Commit Graph
56 Commits
Author SHA1 Message Date
orascheandClaude Fable 5 8adbe8cc90 Market record taxonomy aligned with the agency structure
- new vitec:align-market-records: the visible /markets page tree is the
  target (it implements the agreed agency taxonomy). RENAME_MAP carries
  16 records - story relations included - onto the new names, exact
  matches get their detail_page wired, 10 records are created (CNI,
  Government, Public Safety and seven sub-markets). Records the agency
  dropped are never touched: they are reported with their attached
  stories as the editorial decision list - which turned out empty, all
  nine carried zero stories
- INDUSTRY_TO_MARKET of the story importer moved to the new names. The
  old combined defense market split cleanly: the Government industry now
  maps to its own market, Military stays on Defense and Security, so the
  --markets-only re-run redistributed those stories by their original
  industry. Healthcare deliberately lost its target (market dropped) and
  surfaces as unresolved from now on
- re-run applied: 48/48 stories relinked, badges verified live (no old
  names left), Solr reindex queued - the market facet now speaks the new
  taxonomy

Open: Overlake Medical Center still points at the dropped Healthcare
record (title-match fallback), the nine orphaned old records await
deletion, Public Safety has no stories yet.

Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
2026-10-26 10:40:42 +01:00
orascheandClaude Fable 5 6b0b2a3511 Engagament rename; redirects installed, CLI-queued and backfilled
- new generic vitec:rename-page --page=<uid|slug> --title="...": renames
  a page, recalculates its own slug from the parent slug plus the new
  title and cascades every descendant slug - the gap a backend rename
  leaves open. Used to fix the "Engagament" page (#465): title, own
  slug and five child slugs in one run, verified live (zero occurrences
  left in the JSON)
- SubsolutionWorkbookImporter::norm() tolerates the engagament spelling:
  the 39 delivered workbook metas carry the old page title, re-imports
  keep matching (verified)
- typo3/cms-redirects installed - it had NEVER been installed, so every
  "redirect follows" of the 10-23 renames was wishful thinking and all
  old URLs answered 404. Backend slug changes now auto-create redirects
- EXT:redirects' auto-creation does not fire for CLI DataHandler runs,
  so vitec:rename-page, vitec:normalize-slugs and
  vitec:align-market-pages now queue their 301 sys_redirect rows
  themselves in the same DataHandler run
- new one-off vitec:backfill-redirects: the 28 paths vacated on
  2026-10-23/26, reconstructed from the command protocols, guarded
  against existing redirects and live slugs; applied and verified.
  Note the headless semantics: a redirect arrives as the JSON envelope
  {"redirectUrl": ..., "statusCode": 301} with HTTP 200 - the front end
  must act on redirectUrl (briefing updated)

Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
2026-10-26 10:19:16 +01:00
orascheandClaude Fable 5 cbe46cdba2 Megamenu page-tree panels; generic slug normaliser
- evo_megamenu_json: new entry layout "pagetree" - the panel columns
  mirror the live subtree of the page the entry links to (one child per
  column, grandchildren as items, getMenu() restrictions apply), so the
  menu can never age against the page structure again. The stale
  9-market panel after the markets realign was the trigger. Curated
  columns are ignored on this layout; teasers and the featured slot
  stay editorial. Same columns shape in the payload - front ends need
  no change beyond knowing the new layout string
- new vitec:normalize-slugs --root=<slug> [--style=plain|and]:
  recursively realigns every slug below a root to
  <parent-slug>/<slugified-title>, cascading, with a sibling-collision
  warning; EXT:redirects covers the old URLs. TYPO3's slug generator
  keeps slashes from page titles (third hit: rtcc-/-rtic), this sweeps
  a whole tree. Run on /solutions: four fixes, including the
  long-standing passenger page and solution page 467. The misspelled
  "engagament" slug stays deliberately - it follows the page title and
  is fixed in the coordinated typo task

Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
2026-10-23 14:10:57 +02:00
orascheandClaude Fable 5 303defe24d Markets branch: 11-market tree, sub-market import, hero pipeline
Structure per the agency agreement (Joe/Christina, confirmed 2026-10-23):
/markets -> eleven market hero pages -> their sub-market pages; the
use-case level stays sections on the sub-market pages.

- new vitec:align-market-pages: renames 8 main market pages onto the
  agency names (slug change -> EXT:redirects), creates the 3 new markets,
  hides the dropped "Security & Surveillance" (records/stories
  untouched), reports unknown children. A child-slug pass realigns every
  child to <parent-slug>/<slugified-title> (DataHandler does not cascade
  slug changes; this also repaired the third embedded-slash slug,
  rtcc-/-rtic). --publish unhides the tree (dev convenience; element
  shells stay hidden)
- sub-market import: all 24 agency workbooks applied (4 existing pages,
  20 created) - their Meta sheets were clones of Corporate Environments
  (record_uid 32) and were repaired beforehand (market/sub-market set,
  record_uid 0; the record taxonomy alignment is a separate step)
- SubmarketWorkbookImporter: page-properties parity (og/twitter titles
  and descriptions, canonical, abstract from the intro copy) and a
  placeholder upgrade pass - pages created in the same run only get the
  generic grey (their uid is still NEW), the re-run swaps it for the
  numbered per-page placeholder
- new market hero pipeline: frontend layout 23 "Market Hero Page"
  (zones hero=colPos1, main=colPos0), Import\MarketHeroPageImporter +
  vitec:import-market-hero-workbooks (inbox migrations/markethero_xlsx_in,
  gitignored). Hero H1 travels on the introparagraph header (markethero
  has no headline field), the hero CTA anchors #submarkets, sub-market
  cards link their child page via t3://page, customerlogos and
  usecaselist ship hidden until filled editorially, prefooter ctabanner;
  full page-properties set with 11 curated keyword sets
- applied end to end and live-verified (layout 23 heroes with linked
  cards, layout 21 sub pages with all six colPos groups, clean slugs)
- spec v1.25

Open: market RECORD taxonomy (story badges / Solr facets still use the
old 9 mains), featured product "ISR Video Mission Commander" has no
record, the /markets main page workbook (template 2) is a separate flow.

Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
2026-10-23 13:52:43 +02:00
orascheandClaude Fable 5 115952a132 Product banners and photos: vitec:import-product-images
- new command attaching the agency asset delivery (one Dropbox folder
  per product) to the product records: files containing "banner" go to
  heroimage (first reference reused/swapped), every other jpg/png -
  carousel subfolders included - is APPENDED to productimage with the
  full reference list, so the live-site images from 2026-09-04 stay
- folder -> record matching: normalised title, title without the
  parenthetical, slug, then IMAGE_ALIASES (Joe's "+1" Vision folder
  names map onto the existing records - their banner files still carry
  the old product names; 95-Series -> avedia-end-points)
- uploads land in fileadmin/product_import/<slug>/ with REPLACE, so
  re-runs are idempotent; inbox migrations/product_images_in/ gitignored
- applied: 39 banners + 14 photos across 42 products, 0 errors,
  live-verified (srcset/webp processing included)
- the "MGW Diamond (SDI encoder)" Dropbox folder held the OG blade's
  banner (image inspected): moved to the OG product in the inbox, the
  appliance deliberately keeps no hero; the Dropbox source still has it
  in the wrong folder
- still without records: MGW Diamond/Pico/Pico+ TOUGH and X-View - their
  assets wait in the inbox, a re-run attaches them once records exist

Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
2026-10-23 13:05:32 +02:00
orascheandClaude Fable 5 3e2ebf3823 Solution group pages: layout 22 + Template-06 workbook import
- new frontend layout 22 "Solution Group Page" (provider LAYOUT_MAP,
  TCA layout item, locallang_pages.xlf; zones hero=colPos1, main=colPos0
  like layout 5 so the front end reuses its components)
- new pipeline Import\SolutionGroupPageImporter +
  vitec:import-solution-group-workbooks (inbox
  migrations/solutiongroups_xlsx_in/, gitignored): reads the agency
  "Template 06" group workbooks by column-A label scan, resolves the
  group via "Hero H1" -> is_group record -> detail_page (pages must
  exist), cursor-based slotNext() allows repeated CTypes per column
- element plan per page: markethero (+#capabilities CTA anchor) + hero
  intro paragraph; intro + supporting 50/50; challenges header + 4
  text_only cards; capabilities header + 4 alternating horizontal cards
  (bullets as <ul>); usecaselist shipped HIDDEN (an empty selection
  would list ALL stories - editors pick, then unhide); marketinsights;
  prefooter ctabanner. Page properties as on the sub-solution pages,
  8 curated keyword sets
- 56 numbered grey placeholders for pages 459-466 (7 slots per page)
- applied to all 8 group pages, live-verified on 459/465; the solutions
  branch is now content-complete (groups + 39 details)
- spec v1.24 (revision row, head/footer)

Found on the way: the "Engagament" typo lives in page 465's title AND
slug; the record is spelled correctly. Fix needs coordination with the
sub-solution workbook metas - own task, not done here.

Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
2026-10-23 12:19:05 +02:00
orascheandClaude Fable 5 d115ffb144 Sub-solutions filled from Joe's 39 workbooks; dummy assets wired
- Joe's 39 "- Completed" workbooks applied to all 39 sub-solution pages
  (#467-#515); both workbook inboxes are now gitignored and the tracked
  test workbooks untracked - filled deliveries live in the Nextcloud
- new Import\ProductFamilyAliases: the workbooks reference product
  FAMILIES in the product slots; 11 labels map to a representative
  product, consulted by BOTH importers after the exact title match and
  reported as "-> family alias"
- flip-card icons: dummy SVGs fileadmin/icons/flow/<name>.svg for Joe's
  10-name vocabulary, attached by the new attachIconFile() through the
  shared idempotent attachFalFile() (extracted from attachUrlFile);
  real icons later REPLACE those files in the Filelist (same sys_file
  uid), every card follows without a re-import
- image slots: numbered grey placeholders per page and slot
  (fileadmin/placeholders/pages/<pid>-NN.png, the id rendered into the
  image; generic grey as fallback). An existing reference is never
  overwritten; a real URL on re-import swaps the placeholder away
- page properties per sub-solution: og/twitter title + description
  mirror the SEO fields, canonical_link points at the page itself,
  abstract derived from the intro copy (~300 chars, word boundary),
  keywords from the curated PAGE_KEYWORDS set
- spec head-matter fix rides along (version table was stuck at 1.21,
  real state 1.23)

Open afterwards: 3 missing Datapath stories + re-apply, quotes on 16
story records (list to Joe), slug slash on page 467.

Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
2026-10-19 18:51:21 +02:00
orasche 887caed2aa Products megamenu as a data-driven catalog with a Solr product type-ahead
- evo_megamenu_json stays project-neutral: new panel layout "catalog";
  for such entries the MenuBuilder dispatches the new PSR-14 event
  BuildCatalogEvent and emits whatever a listener sets as `catalog`
  (null without a listener). The entry's teaser cards serve as the
  featured tiles; the teaser inline field now also shows for "catalog",
  and the entry form reloads when the layout changes. README section
  "Layout catalog"
- VITEC listener ProvideProductCatalog fills it, modelled on the Ross
  Video products menu: main categories below the "Product" root, their
  subcategories as groups, products with a plain-text one-line teaser;
  same visibility rules as the product list, Product Finder links
  (/products?cat=&subcat=), empty categories and groups left out, three
  queries for the whole catalog
- Product type-ahead GET /_json/?type=7385&q= (USER_INT page type,
  ProductMenuSearchJsonRenderer): Solr restricted to products, last term
  completed as a prefix, up to six product cards plus their titles as
  autocomplete suggestions; endpoint announced in catalog.search
- Spec v1.23 (clause 7.16: product type-ahead)
2026-10-09 13:40:23 +02:00
orasche 91ad5e6596 Search cards above the results, detail-page fallback for market/solution documents
- New record type tx_vitec_domain_model_searchcard ("best bets"):
  keyword list, priority, optional referenced record (page, product,
  story, solution, market, news) and overridable title/teaser/image/link;
  hidden/start/end time allow timed campaigns
- SearchCardService delivers content.search.cards on page 1: max. 3,
  priority-ordered, deduplicated by URL, independent of filter, facets
  and result count. Keywords match as whole words/phrases, case- and
  punctuation-insensitive, including one level of the Solr managed
  synonyms in both directions (cached for an hour, fail-soft). Record
  cards read the record's indexed Solr document, so a card always
  matches the record's own search result
- Index fallback for markets and solutions: when the record carries no
  image or text, the document takes the intro image (then the hero
  background) and the hero subline, intro headline and intro text from
  the content blocks of its detail page - selected by CType, so it works
  for layout 21 and layout 5 alike; improves results and cards
- Fix: a search request without q returned an empty body instead of the
  documented empty shape (stdClass resolved inside the renderer namespace)
- migrations/check_solution_fields.php: shows live/workspace versions of
  solution records
- Spec v1.22 (clause 7.16: cards)
2026-10-09 12:59:12 +02:00
orasche 9b1ad202a9 Extend Solr search: content coverage, 14.0.2, news recency, result images
- Index the text columns of the market/solution Content Blocks and the
  vitec_items/vitec_faq_items collection children; story documents now
  include their body (inline tt_content children via
  tx_vitec_usecase_content, same per-element extraction as pages) -
  stories were indexed with subtitle and teaser only until now
- Upgrade EXT:solr 14.0.0-RC1 -> 14.0.2 final (the Solr image moved to a
  fresh volume because the configset changed; synonyms restored via REST)
- News decay with age by publication date: crdate is the import date, so
  news map datetime to created; boost function gated to news only
- Results carry `image`: processed 640px tile image per type,
  root-relative, null for pages and downloads
- Spec v1.21: 7.16 states the /_json prefix and lists `solution` in the
  type vocabulary; footer had been stuck at v1.19
- suggest-demo.html fetches through /_json after the URL swap
2026-10-07 16:22:50 +02:00
orasche 8e67f5db23 Sub-solution workbook pipeline on layout 5, fix element order in both importers
- New, deliberately separate pipeline for sub-solutions (markets and
  solutions must never break each other): generator
  vitec:generate-subsolution-workbooks (list from the page tree below
  /solutions, 39 workbooks, every sub-solution matched to its record),
  SubsolutionWorkbookImporter + CLI vitec:import-subsolution-workbooks,
  and a "Sub-Solutions" tab in the VITEC Import module with its own
  inbox migrations/subsolutions_xlsx_in/
- Targets the existing template 5 "Solution Detail" without changing
  it: hero element in colPos 1, the remaining sections in fixed order in
  colPos 0, found again by CType on re-import; existing empty sub-solution
  pages are switched to layout 5, missing ones created hidden;
  detail_page set on the solution record
- Workbook per the Figma "07 Solution Detail page": hero without video
  teaser, intro with headline and without learn-more/portfolio, extended
  icon list, own page-layout reference image
- Shared content elements: market hero/intro/insights relabelled
  "Market/Solution", market intro gains the optional intro_headline
  field (new column, requires extension:setup)
- Fix: DataHandler puts every NEW record with a positive pid at the top
  of its column, so pages built in one run came out reversed. Both
  importers now track the page order per colPos and write
  tt_content.sorting explicitly after the DataHandler run; re-applying
  repairs pages imported earlier (verified on the control-room
  sub-solution and sub-market page 443)
- migrations/fill_test_subsolution.php: realistic test content from
  vitec.com copy and images for the control-room sub-solution
- Docs section 5z
2026-10-07 15:39:18 +02:00
orasche 3d5459b8d2 Sub-market workbook import as a backend module tab
- Extract the complete import logic (label-scan reading, page
  find-or-create, slot filling, content-idempotent image attach) from
  ImportSubmarketWorkbooksCommand into the shared service
  SubmarketWorkbookImporter; the CLI command and the new controller are
  thin shells around importFile(), so both entry points cannot drift.
  CLI regression verified: identical dry-run report for the reference
  workbook (12 elements, page 443)
- New "Sub-Markets" tab in the VITEC Import module
  (SubmarketImportController + Import/Submarkets.html): upload multiple
  filled workbooks into the SAME inbox the CLI uses
  (migrations/submarkets_xlsx_in/), per-file checkboxes, dry-run and
  apply buttons, result cards with the familiar report and a direct
  link into the page module; backend dry-run verified against the CLI
- Submitted filenames are whitelisted against the actual directory
  listing (no path traversal); uploads restricted to sanitized .xlsx
  basenames
- Routes submarkets/submarket_upload/submarket_process in Modules.php,
  Sub-Markets tab link in the sibling module views, ok/danger badge
  colors in backend-import.css
- Docs section 5y (incl. operations note: apply in small batches in the
  module, mass runs via CLI - image downloads run inside the web
  request)
2026-10-05 15:35:40 +02:00
orasche 78af83d2e3 - The three market Content Blocks preview as compact collapsible rows:
thumbnail of the actual image (hero background, intro image, insights
  cover), key copy in the summary line, full details expanded; card and
  intro-paragraph previews are wrapped in the same mechanism
- New SubmarketPluginPreview for vitec_usecaselist / vitec_productfeature /
  vitec_productlist: instead of bare standard boxes they now list the
  selected story titles (flagging stories that still lack a quote), the
  featured product and the hand-picked products in order
- Container-style collapse for whole page-module COLUMNS: a chevron at the
  right of every column header folds a section down to its title row,
  state kept per page and colPos in localStorage - the slot view of a
  sub-market page folds to six slim bands
- Previews sit under the page module's pointer-events lock and its
  click-to-edit layer: pointer events are re-enabled inside the collapse
  markup and the toggle runs on pointerdown in the capture phase
- Two more v14 removals fixed on the way, both latent in the OLDER preview
  classes too (Usecaseshow, Modelcard would have crashed the page module):
  GridColumnItem::getRecord() now returns a Domain\Record object, and
  StandaloneView is gone - previews normalize the record via a shared
  helper and render through the ViewFactory
2026-10-02 15:00:05 +02:00
orasche 8b175211ea vitec:generate-submarket-workbooks builds one protected customer workbook
per sub-market (25, grouped by the 9 main markets): VITEC-styled Read me,
a Page-layout sheet embedding the Figma design with section markers,
DB-live dropdowns, soft character limits, a hidden Meta sheet and named
input cells. Names must NOT start with a cell-reference token - Excel
silently strips s1_-style names as repairs.

vitec:import-submarket-workbooks (dry-run default, idempotent) finds or
creates the page below its main market (hidden, layout 21), fills the six
colPos slots updating in place and never deleting, links detail_page on
the market record, downloads asset URLs into fileadmin/submarket_import/
for editorial review and writes the flexforms as DataHandler arrays.
Reading is three-layered after a bruising day of real-world Excel: named
ranges first, then a label scan over the locked column A with section
tracking - a customer save stripped ALL defined names and shifted rows,
so fixed addresses are not a contract.

Learned and fixed along the way: DuplicationBehavior moved to
Resource\Enum in v14; sys_file_reference rows via DataHandler need
pid/tablenames/uid_foreign or are dropped silently; handing DataHandler a
fresh NEW reference per run STACKS live references on re-import (caught
by a double-run test), so attachments are now content-idempotent - the
existing live reference is reused or retargeted and surplus duplicates
are deleted via cmdmap; RequestFactory replaces GeneralUtility::getUrl so
download failures carry their reason - which surfaced that the dev basic
auth blocked the server itself (server IP + loopback now allowlisted,
which a future SSR needs anyway) and that the core resource-consistency
check rightly rejects HTML masquerading as PNG.

Verified end to end on Broadcast & Media from a clean slate, twice in a
row: 12 elements in colPos 110-160, layout-21 payload, both images
attached exactly once with publicUrl in the JSON; second run reports
nothing but unchanged.
2026-10-02 13:24:54 +02:00
orasche 90ae6803a4 Backend of the sub-market template (spec agreed section by section with
the customer workflow in mind: the customer fills one XLSX per sub-market,
an importer builds the page).

- Frontend layout 21 'Sub-Market Page' in the existing
  BackendLayoutDataProvider: six zones, one per Figma section, emitted as
  colPos110..colPos160 - the JSON groups plus appearance.layout are the
  front-end contract (spec clause 7.17). A first attempt via page-TSconfig
  BackendLayouts was the wrong mechanism next to the provider and was
  removed again
- New Content Blocks vitec_markethero, vitec_marketintro,
  vitec_marketinsights (field bags, serialized unprefixed under data);
  the workflow section reuses intro-paragraph + vitec_card flip cards
- Stories gained quote/quote_person/quote_role (Testimonial tab),
  maintained once per story, emitted on every story card; usecaselist
  gained the layout value 'testimonials'
- New plugin vitec_productfeature: one referenced product as a full
  product card, serialisation shared with the product list (cObj made
  protected for the subclass)
- vitec_productlist gained hand-picked product selection: exactly the
  chosen products in the editor's order, category filter ignored,
  visibility filters kept - closes the long-standing single-select gap
- New CLI vitec:generate-submarket-workbooks: one protected customer
  XLSX per sub-market (9 main markets, 25 sub-markets from the Market
  category tree) - dropdowns filled live from the database, named ranges
  as the importer contract, hidden Meta sheet pinning submarket/group/
  record uid, soft character-limit warnings, asset URL fields

Verified end to end on Broadcast & Media: layout-21 payload with colPos110
carrying the hero element and its subline. Spec raised to v1.20.
2026-10-02 10:18:36 +02:00
orasche f0b0694842 - New extension fe_comment (Evomedien, framework-agnostic): floating page
feedback widget served from /api/fe-comment/widget.js, note pad in
  localStorage, submissions mailed via /api/fe-comment/submit with
  recipients from the extension configuration; classic sites get the
  script injected via AssetCollector when the jsonOutput setting is off.
  An enabled master switch serves the widget EMPTY when off (no 404, no
  console errors) and rejects submissions - the go-live kill switch, no
  front-end build change needed
- URL swap finished: /_json prefix middleware, SPA fallback live with a
  dedicated root rule (REQUEST_FILENAME of / is a directory) and a
  query-string exception for the TYPO3 v14 install tool entry
  (?__typo3_install on the site root - the backend Settings/Environment
  modules depend on it); /api/ as a whole stays with TYPO3
- MailMessage::send() no longer exists in v14: fe_comment and the form
  EmailDelivery (latently broken since the core upgrade) now send through
  the Mailer service. Mail transport moved to SMTP against the local exim
  so delivery errors surface instead of bouncing into the blackhole -
  exim verifies the envelope sender, which therefore must be a routable
  existing address (transport config lives in the untracked settings.php)
- Related-product card texts editable on the product record (table rebuilt
  with uid/pid, TCA + inline field, one-time migration script); shared
  RteCompare for the module badge and the CLI comparison - batch dry-run
  now reports 0 writes instead of flagging every richtext field
- Workbook clarification cases executed: VisionIO-SD14, VisionSC-SD14 and
  both Diamond OG records imported (40 fields, live-verified); ArtioSign
  and ArtioView created hidden (uid 109/110) via
  create_artio_records.php - the product table has no sorting column;
  WallControl_10 mapping REVERTED and parked: the dry run revealed
  aetria-wallcontrol already carries its own agency workbook, which
  WallControl_10 would have overwritten. Manifest now 75 product /
  24 family / 1 open
2026-09-30 13:59:55 +02:00
orascheandClaude Fable 5 6961254e57 Workbook import phase 1: manifest-driven batch command
Implements the 18.09. strategy's phase 1 on top of the existing single
importer (which stays the one write path):

- new vitec:import-product-workbooks: runs vitec:import-product-workbook
  per manifest entry (in-process sub-command), aggregates a per-file
  report (writes/unchanged/na, URL-mismatch and error flags, details on
  -v or failure) plus a summary; without --apply every run is a dry
  run; --only filters
- migrations/products_xlsx/ now holds working copies of all 100 agency
  workbooks in their category folders (git-ignored) plus the TRACKED
  manifest.json: workbook path -> product slug, family entries mark the
  K-level landing pages (never imported), product null = unresolved.
  Generated from the 18.09. analysis + sitemap column K:
  68 product / 17 family / 15 open
- --init-manifest resolves open entries against the full product table
  (hidden records included): URL segment/filename vs slug, normalized
  title, unique slug prefix; only unambiguous hits are written back
- single command compare is now tolerant of the RTE storage transform
  (whitespace collapse + <p>-wrap simulation), fixing the known
  every-run-WRITE false positive on re-imports

Post-dry-run hardening, applied the same day (69 products, 785 field
writes across two runs, zero errors, verified against the live JSON):

- PROTECTED_FIELDS title/urltitle in the single command: the stored
  module mapping would have overwritten six canonical sitemap-V2
  product titles
- the stored mapping predated the 18.09. defaults and silently dropped
  `highlights` on every product; the single command now merges
  DEFAULT_MAPPING under the stored mapping (defaults as base, stored
  as per-field override)
- known limitation for phase 2: the g: composed fields report WRITE on
  every run (RTE transform alters ul/strong markup beyond the p-wrap
  normalisation) - the change watch must compare against stored
  imported values, not the database

Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
2026-09-24 15:50:16 +02:00
orascheandClaude Fable 5 6811463343 Product texts: mapping completed; product model: solutions + resources
Two work packages, one deploy.

Workbook field mapping completed (2026-09-18)
- highlights <- g:Technical Highlight (new spec-row component of the
  full agency delivery; composeGroup() is generic, no change needed)
- applications <- g:Why Choose Card (benefit cards as one block)
- seometa <- new composed source x:seometa (Introduction body trimmed
  at a word boundary to ~155 chars - the SEO sheet ships no meta
  description, a trimmed intro beats an empty tag)
- teaser stays the hero one-liner, settling the varchar(255) question
- fix: "Save mapping" now merges over the stored mapping instead of
  overwriting it - an empty dropdown no longer wipes a stored selector

Product model: solutions relation and Resources tab (2026-09-24)
- closes the gaps the full workbook walkthrough exposed (rows the
  import deliberately skips because the model had no place for them)
- solutions: MM multi select to tx_vitec_domain_model_solution
  (tx_vitec_product_solution_mm, relatedprodukt pattern), emitted by
  both product renderers as solution cards in the shared shape
- Resources tab: inline child table tx_vitec_product_resource - per
  entry a type (documentation/support), an editable card title/text,
  an icon (free text with a value-picker seed set) and one link
  (page/url/file/record via the link wizard). Deliberately no Extbase
  model: only the UserFunc path reads the rows.
- datasheets: own MM selection of download records below the resource
  list (tx_vitec_product_datasheet_mm); emitted into the SAME
  resources envelope as ready-made type=datasheet cards (title/teaser/
  icon from the record, url = the public /download/<slug> route, uid
  fallback - private/hidden downloads 404 as everywhere)
- JSON `resources` (detail payload only, like heroimage): list envelope
  {layout, items[]}; a hand-written card whose link is empty or
  unresolvable is not emitted; layout switches to carousel above three
  cards in total
- solutions hybrid (same day, after analysing all 100 workbooks: their
  Solution Cards reference the 8 GROUPS in 98% of cases): new is_group
  flag on the solution model, new idempotent CLI
  vitec:create-solution-groups (8 group records; title source is
  AlignSolutionsCommand::TARGET - now public -, category = the group's
  own category, detail_page = the /solutions group page with -N
  disambiguation). Group records are invisible to the solution list
  and to vitec:align-solutions and only selectable in the product
  relation; product solution cards carry isGroup
- spec raised to v1.18 (7.15 member table, 7.13.3 note, revision row;
  the footer had been stuck at v1.15 since 1.16/1.17)

Requires on the server:
    vendor/bin/typo3 database:updateschema "*.add,*.change"
    vendor/bin/typo3 cache:flush

Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
2026-09-24 14:47:04 +02:00
orascheandClaude Fable 5 3df66b1353 Product texts: mapping completed; product model: solutions + resources
Two work packages, one deploy.

Workbook field mapping completed (2026-09-18)
- highlights <- g:Technical Highlight (new spec-row component of the
  full agency delivery; composeGroup() is generic, no change needed)
- applications <- g:Why Choose Card (benefit cards as one block)
- seometa <- new composed source x:seometa (Introduction body trimmed
  at a word boundary to ~155 chars - the SEO sheet ships no meta
  description, a trimmed intro beats an empty tag)
- teaser stays the hero one-liner, settling the varchar(255) question
- fix: "Save mapping" now merges over the stored mapping instead of
  overwriting it - an empty dropdown no longer wipes a stored selector

Product model: solutions relation and Resources tab (2026-09-24)
- closes the gaps the full workbook walkthrough exposed (rows the
  import deliberately skips because the model had no place for them)
- solutions: MM multi select to tx_vitec_domain_model_solution
  (tx_vitec_product_solution_mm, relatedprodukt pattern), emitted by
  both product renderers as solution cards in the shared shape
- Resources tab: inline child table tx_vitec_product_resource - per
  entry a type (documentation/support/datasheet), editable card title
  and text, an icon (free text with a value-picker seed set) and one
  link (page/url/file/record via the link wizard, so the Download tab
  works too). Deliberately no Extbase model: only the UserFunc path
  reads the rows.
- JSON `resources` (detail payload only, like heroimage): list envelope
  {layout, items[]}; a card whose link is empty or unresolvable is not
  emitted; layout switches to carousel above three cards
- spec raised to v1.18 (7.15 member table, revision row; the footer had
  been stuck at v1.15 since 1.16/1.17)

Requires on the server:
    vendor/bin/typo3 database:updateschema "*.add,*.change"
    vendor/bin/typo3 cache:flush

Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
2026-09-24 14:15:43 +02:00
orascheandClaude Fable 5 4a7ea387a0 Product list: success stories on the all-products element
The big product list on /products (all products, no category context)
deliberately delivered the empty successStories envelope; the front end
now renders story cards there too and filters them client-side, so the
element aggregates over the WHOLE product category tree instead:

- new allProductCategoryUids(): root category 'Product' (same detection
  as ProductFinderJsonRenderer), children plus descendants depth-first,
  fed through the existing successStoriesFor()
- per-category elements are untouched; forCategories keeps carrying the
  category uids a story is attached to, so the ?cat=/?subcat= filter
  behaves identically on both element kinds
- layout rule unchanged: first contributing category in tree order

Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
2026-09-16 14:43:00 +02:00
orasche 55f7f82a42 Show success stories below the product lists, linked on the category
sys_category gains a story selection and a layout (Options tab, alongside
the images field EXT:news puts there), so one editorial decision serves
every product list that renders the category. ProductListJsonRenderer emits
them beside the products in the 7.3 list envelope; each card carries
forCategories - the product categories it came from - so the front end hides
it with the same ?cat=/?subcat= filter it applies to the products. Stories
are collected over the category and its descendants and deduplicated.

Story links follow the existing rule (detail page's parent path plus slug,
which SuccessStoryPathRewrite maps back), taking the page from the element's
FlexForm or the new site setting vitec.storyDetailPid.

Spec raised to 1.17 with clause 7.15.2.1; the header had been left at 1.12
although entries up to 1.15 already existed, so today's two entries were
renumbered to 1.16 and 1.17.
2026-09-11 15:28:32 +02:00
orasche 8c881d153c Index PDF and Office file contents via Apache Tika
Solr 10 dropped the ExtractingRequestHandler, so a dedicated Tika
container on the Solr VPS (Caddy route /tika/*, own basic-auth
credential; Tika itself has no auth) extracts file text during
indexing: TikaDownloadContentIndexer listens on
BeforeDocumentIsProcessedForIndexingEvent, resolves the file through
the existing DownloadFileResolver and appends the text (mime
whitelist, 30 MB cap, 100k chars, fail-soft) to the document's content
field. Extractions are cached in var/tika-cache keyed on
path+size+mtime - a full re-index of 177 downloads drops from 2:12 min
to 27 s, replacing a file re-extracts naturally. Datasheet
specifications ("625i", "genlock") are now searchable. Spec v1.15.
2026-09-11 13:15:05 +02:00
orasche 5bb4e374b4 Add evo_megamenu_json extension and seed the megamenu
- new project-neutral extension evo_megamenu_json (Evomedien): a Megamenu
  plugin holding entries, columns, items, teaser cards and a featured slot
  as nested records; presentation settings travel with the payload so the
  front end reads behaviour instead of hard-coding it; published as
  page.10.fields.megaMenu, driven by the site settings megamenu.contentUid
  and megamenu.storagePid
- vitec:seed-megamenu fills one element from the live structure: 5 entries,
  26 columns, 95 items, 4 story cards; items without a page yet are flagged
  pending so the front end falls back to the column link
- vitec:debug-sets prints the resolved site set order
- read-only diagnostics: check_megamenu_schema.php, check_typoscript_templates.php
- docs: schema updates run via extension:setup (database:updateschema no
  longer exists in v14), and a JSON Accept header activates headless-mixed,
  which strips every set-added page field
2026-09-11 11:44:20 +02:00
orasche e9eaa62d89 Align solutions to the sitemap's 39 Generic Solutions; map detail pages
- vitec:align-solutions: declarative target = the 39 Generic Solutions in 8
  group categories under the Solution root (sheet is binding, group typo
  Engagament->Engagement fixed). Two legacy records renamed onto their sheet
  names instead of deleted (keeps the only editorial teaser/description),
  slugs generated for all, market categories stripped from solutions, the
  ~82 market-specific records soft-deleted (markets link editorially)
- vitec:map-solution-pages: writes matching page uids into detail_page
  (unique matches, fill-only); disambiguates the duplicated page branches
  by slug suffix and prunes the 10 empty duplicate pages
- read-only diagnostics: check_solutions.php, check_dup_solution_pages.php
2026-09-04 15:30:27 +02:00
orasche c91063d6f3 Import product photos from live sites; link downloads and SEO meta to products
- vitec:import-product-images: attach staged photos (fileadmin/user_upload/
  products/<slug>/, 116 files harvested from vitec.com and datapath.co.uk
  carousels) to image-less products via FAL/DataHandler; fill-up only.
  fix_image_reference_fieldname.php repairs the first run's references
  (TCA field is productimage, not the JSON key images)
- vitec:link-product-downloads: match the download records imported on
  2026-08-06 to products by title (doc-type/brand/role suffix stripping,
  alias table for live-site naming deviations, series rules for g45xx/e38xx/
  chassis docs); 55 unique-match links added, add-only, idempotent
- SEO meta: seo_meta_vitec.json + apply_seo_meta.php fill empty seotitle/
  seometa from the live vitec.com product pages (11 products, fill-up only)"
2026-09-04 14:34:38 +02:00
orasche 5aad13e635 Keep hidden headers (header_layout 100) out of the JSON
Applied on all three render paths: stdWrap.if rule on
lib.contentElementWithHeader (before the plugin copies), the same rule in
the container element definitions, and a HiddenHeaderProcessor behind the
nb content-blocks data processor. headerLayout itself stays in the payload
so the front end can tell why the header is empty.
2026-09-04 13:21:50 +02:00
orasche 5499ca54af Align product records with sitemap V2; product family model; CLI workbook import
- vitec:migrate-product-structure: exact V2 titles, Milestone typo fix (incl.
  slug), QTX100 stray VSN category removed, Aligo record moved to its own
  category with slug /product/aligo, new Aligo Workstation record takes over
  /product/aligo-workstation
- product families (sitemap column K) are ordinary content pages now:
  vitec:remove-family-records deletes the interim landing records again,
  reset_subproduct_flags.php clears the misused subproduct flag (the list
  renderer has always excluded subproduct=1)
- vitec:import-product-workbook: non-interactive counterpart of the module
  import (same reader, mapping and DataHandler path); Arqa imported, Aligo
  re-applied with the corrected capabilities markup
- ProductXlsxReader: new :copy cell selector (Body Copy with CTA fallback)
  absorbs the agency's column drift; default teaser mapping uses it
- ProductListJsonRenderer: selected categories now match their whole subtree,
  results ordered by category tree position, sheet order within a category
- read-only diagnostics: check_product_structure.php, check_productlist_ces.php
2026-09-04 12:59:17 +02:00
orasche 7833e1b668 Product import 2026-08-28 13:57:54 +02:00
orasche 7442d10e68 SEO record links; story markets repair; story page titles
Kev's keyword CSV and TYPO3 hold the same solutions under slightly
different names, so the structure check filed them as missing/extra.
Matching is now slug -> normalized title -> record alias, using the
per-model alias store the import tabs got on 2026-08-18
(tx_vitec_import_mapping.record_aliases, key = lowercased CSV name).
One link therefore serves the import union list, the structure check
and vitec:create-markets (same service - linked rows are no longer
proposed as new records).

- every "Missing in TYPO3" row carries a select of all records the
  direct match did not claim; "Save record links" persists per model
- alias-matched rows show under "Both" with a "linked" badge and the
  same select; option 0 removes the link
- SeoResearchService::recordsCheck() additionally returns `linkable`
  (the select options) and flags alias matches with via=link
- new backend POST route seo_aliases

Success stories: --markets-only repair mode
- /success-stories emitted empty `markets` for all 48 stories - a data
  problem (code and TCA untouched since 17.08.); read-only diagnosis
  script migrations/check_usecase_markets.php added
- vitec:import-success-stories --markets-only re-derives each story's
  industries from the export exactly like the full import and rewrites
  ONLY the markets MM relation of the existing record via DataHandler;
  nothing else is touched, no usecase created or deleted, unresolved
  stories keep their current relations
- decision: industries are translated onto the nine main markets of
  the current taxonomy (INDUSTRY_TO_MARKET) instead of recreating the
  seven deleted industry markets; the repair mode never creates
  market records (root cause: those industry markets were deleted
  after the 07.08. taxonomy import, orphaning all story relations)
- ensureMarkets() gained a $create flag for reuse by the full import

Story detail pages: real page title
- every story page answered with the generic page title "Story"; same
  defect and same fix as the product pages on 21.08.: new
  UsecasePageTitleProvider (singleton), registered as vitecUsecase in
  config.pageTitleProviders, fed from UsecaseShowJsonRenderer with
  seo_title falling back to title

Requires on the server:
    vendor/bin/typo3 cache:flush
2026-08-26 19:48:43 +02:00
orascheandClaude Fable 5 083f0937e2 Add type filter and facet counts to the search endpoint
The search JSON gains tab support: the new `filter` GET parameter
restricts results to one document type (product, news, download, story,
page, market); the response carries `filter` (active value or null) and
`facets.type` with per-type counts and active flags. Counts stay
complete while a filter is active (keepAllFacetsOnSelection), so tabs
never collapse - except on an empty filtered result, documented in spec
v1.12 clause 7.16.

The parameter is named `filter` because `type` is TYPO3's reserved
page-type parameter and crashes page resolution; like q and page it is
excluded from cHash validation. Facets come from EXT:solr's native
faceting, serialized generically by SearchJsonRenderer - a future
category facet only needs TypoScript.

Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
2026-08-24 15:51:26 +02:00
orasche cf7a04ea15 Added Downloads to search index. 2026-08-21 15:44:03 +02:00
orasche 710f95794c Add Solr search: EXT:solr 14 integration and JSON search endpoint
Apache Solr 10 runs on a dedicated VPS behind a Caddy HTTPS proxy
(vitecsolr.evomedien.de) because the managed webserver only allows
outgoing standard ports. Credentials stay out of git: the site config
carries %env()% placeholders resolved via putenv() in the git-ignored
config/system/additional.php.

- composer: apache-solr-for-typo3/solr 14.0.0-RC1 (the only line
  compatible with TYPO3 14; final 14.0.0 will arrive via composer update)
- config.yaml: read connection https/443, core_en per language,
  env placeholder credentials; .gitignore covers additional.php
- setup.typoscript: config.index_enable = 1 (page indexing silently
  refuses without it), solr_pi_results JSON renderer registration,
  results highlighting, and content field extraction from tt_content
  rows - the headless JSON output has no TYPO3SEARCH markers, so the
  default page content extraction indexed an empty content field
- SearchJsonRenderer (renderer #27): JSON output for the search plugin
  on /search. GET q/page in; { query, page, resultsPerPage, numFound,
  totalPages, results[], suggestions } out. Disables the page cache per
  request: config.no_cache is gone in TYPO3 v14, and q/page are
  excluded from cHash, so cached variants would collide
- ext_localconf.php: q and page added to cacheHash excludedParameters
- SolrIndexCommand (vitec:solr-index): works the index queue from the
  CLI with connection diagnostics and a --debug single-step mode -
  EXT:solr 14 ships no console commands and the backend button indexes
  one item per click
2026-08-21 14:43:44 +02:00
orasche 7bd1161abf Product text import from agency XLSX workbooks
VITEC Import module: Products tab is now a searchable/sortable product
overview. "Edit Product" opens an XLSX upload with per-field source
mapping (component + cell), old/new preview and checkbox apply via
DataHandler; the mapping and manual matches are persisted and preselect
the next workbook. Category workbooks are detected and rejected.

- new: ProductXlsxReader (PhpSpreadsheet), ProductTextImportController,
  Products/ProductTexts templates, 4 module routes
- related products: per-pair card text in new side table
  tx_vitec_product_related_text (survives MM rewrites), emitted as
  `cardtext` in the product JSON; missing MM relations added add-only
- card copy read from Body Copy (D) with fallback to CTA/Card Copy (E) -
  the workbooks fill either depending on row type
- product detail page <title> now uses seotitle with title fallback
  (provider made singleton and fed from the JSON renderer)
- per-user recent-search badges; last loaded workbook stored per product
  (tx_vitec_product_workbook), Edit Product reopens on it
- composer: add phpoffice/phpspreadsheet ^5.9
- diagnostics: migrations/check_workbook.php
2026-08-21 11:00:45 +02:00
orascheandClaude Opus 5 12eb40614b Unify list plugins, add solution list and per-story detail page
- vitec_usecaselist: layout + record selection like marketlist
- new plugin vitec_solutionlist (spec 7.13.3, key "solutions")
- tx_vitec_domain_model_usecase: detail_page -> resolved detailUrl
  (also gives story cards in vitec_modelcard a link for the first time)
- "Show Toolbar" checkbox on product/market/solution/usecase lists
- spec bumped to v1.9

BREAKING: vitec_productlist and vitec_usecaselist now emit an object
instead of a bare array. Consumers must read products.products and
usecases.usecases. Also found: productlist had a configurable layout
that was never serialised; it is emitted now, but keeps its own 0-3
vocabulary instead of grid/list/carousel.

Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com>
2026-08-17 16:29:06 +02:00
orasche 4ef3ad0026 Backend Modul Worpress Import added 2026-08-14 13:26:40 +02:00
orasche 58990ebe8d Add BG offset 2026-08-14 10:59:22 +02:00
orasche c720696781 Add Container Options 2026-08-14 10:36:36 +02:00
orasche f515de54ad News und News-Pages Importer 2026-08-13 17:00:53 +02:00
orasche 8d3ac08a37 Updates 2026-08-13 12:49:10 +02:00
orasche 48da8bccd8 Solution detail page and a single LinkResolver
Closes two annex items that turned out to be the same defect seen from two
sides: markets could link to a detail page, solutions could not, and the code
that turns a page uid into a URL existed four times over.

detail_page for Solution (B-11)
- ext_tables.sql, TCA (group on pages, maxitems 1, in showitem behind slug)
  and Domain\Model\Solution mirror the Market field exactly
- SolutionShowJsonRenderer emits detailUrl
- ModelcardJsonRenderer serialized no detailUrl at all: its shared
  market|solution branch never carried the field. Market modelcards therefore
  gain a link here too, not just solutions.

Service\LinkResolver (B-12)
- one implementation replaces four private copies (Market list/show, Usecase
  list/show). The copies had drifted: Market returned null on failure, Usecase
  an empty string. The contract is now explicit -- null means "no link".
- Usecase keeps a thin resolvePageUrl() wrapper appending ?? '', because it
  concatenates paths and a null would tear the strings apart.
- LocationsJsonRenderer and NewsJsonRenderer stay out on purpose: they resolve
  a full parameter construct resp. slug paths plus canonical, which is not
  page-uid-to-URL and does not fit the same contract.

Requires on the server, the column exists in code only:
    vendor/bin/typo3 database:updateschema "*.add,*.change"
    vendor/bin/typo3 cache:flush
2026-08-10 15:27:16 +02:00
orasche 1011162bb1 Backend module: CSV import for the VITEC domain models
New "VITEC Import" module under Web: one import page per domain model
(v1: Market, Solution, Product - registry-driven, adding a model is one
config entry). Workflow: upload a CSV (delimiter and encoding are
auto-detected, including German-Excel semicolon/Windows-1252), map CSV
columns to DB fields, persist the mapping per model together with the
identity field used for matching (new table tx_vitec_import_mapping,
no TCA - pure tool configuration), review a unified list of CSV rows
matched against the DB records (new / update with differing fields /
unchanged / db-only), then apply the checked rows through DataHandler.

Each importable row carries an editable JSON payload textarea - what
is written is the textarea content, not the raw CSV, so editors can
fix values right in the review step. The parsed CSV travels through
the form as a hidden JSON field: no session state, no temp files.
Importable fields are derived from TCA at runtime (scalar types only;
files, categories and other relations are excluded - a flat CSV
cannot carry them). Payloads are whitelisted against that field list
on apply; new records require a storage pid (prefilled from existing
records). BE user permissions apply via DataHandler.

The module ships its own CSS (backend-import.css, loaded only by
this module) using the frontend button palette from _vitec.scss:
orange #f47937 for primary actions, navy #26358c for secondary
actions and structure. The stray <h2>Hi</h2> debug leftover in the
shared backend layout is removed (also affects the OG Image module).

A fourth tab "SEO Research" handles the recurring keyword-research
CSV. It is deliberately not an import mask - the file carries research
only (no meta title/description yet). Each upload is persisted as a
delivery (tx_vitec_seo_research, never deleted) and evaluated: diff
against the previous delivery keyed by URL, a structure check of the
CSV tree against TYPO3 (pages by slug path; market/solution/product
rows against the domain tables, matched by slug then normalized
title), and the three work lists from the SEO flags (quick wins by
GSC impressions, shared terms grouped by keyword, already ranking).
CsvReader now deduplicates repeated header names, which that CSV has.

New CLI command vitec:create-markets: creates the market records the
structure check reports as missing, sourced from the stored delivery
and matched through the same SeoResearchService - what the module
lists is what the command creates. Each market gets a sys_category of
the same title, found anywhere under the auto-detected market category
root or created; sub-market categories are created under the parent
market's category, so the category tree carries the hierarchy the
flat market model cannot. Idempotent, dry-run first.

New CLI commands vitec:create-markets and vitec:market-dummy-image.
create-markets creates the market records the structure check reports
as missing (root detection three-staged: option, auto-detect, find or
create a "Markets" category). market-dummy-image assigns a shared
placeholder (white logo on brand navy, fileadmin/placeholders/) to
every market without an image - one sys_file for all, replacing the
file restyles every placeholder at once. Both idempotent.

Deliberately out of v1: import log with three-way compare (protection
against overwriting manual edits), images/relations, multiple saved
mappings per model.
2026-08-10 14:56:19 +02:00
orascheandClaude Opus 5 5e3be3ec42 Backend module: CSV import for the VITEC domain models
New "VITEC Import" module under Web: one import page per domain model
(v1: Market, Solution, Product - registry-driven, adding a model is one
config entry). Workflow: upload a CSV (delimiter and encoding are
auto-detected, including German-Excel semicolon/Windows-1252), map CSV
columns to DB fields, persist the mapping per model together with the
identity field used for matching (new table tx_vitec_import_mapping,
no TCA - pure tool configuration), review a unified list of CSV rows
matched against the DB records (new / update with differing fields /
unchanged / db-only), then apply the checked rows through DataHandler.

Each importable row carries an editable JSON payload textarea - what
is written is the textarea content, not the raw CSV, so editors can
fix values right in the review step. The parsed CSV travels through
the form as a hidden JSON field: no session state, no temp files.
Importable fields are derived from TCA at runtime (scalar types only;
files, categories and other relations are excluded - a flat CSV
cannot carry them). Payloads are whitelisted against that field list
on apply; new records require a storage pid (prefilled from existing
records). BE user permissions apply via DataHandler.

The module ships its own CSS (backend-import.css, loaded only by
this module) using the frontend button palette from _vitec.scss:
orange #f47937 for primary actions, navy #26358c for secondary
actions and structure. The stray <h2>Hi</h2> debug leftover in the
shared backend layout is removed (also affects the OG Image module).

Deliberately out of v1: import log with three-way compare (protection
against overwriting manual edits), images/relations, multiple saved
mappings per model.

Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
2026-08-07 12:59:49 +02:00
orascheandClaude Opus 5 10c0328bf2 Backend module: CSV import for the VITEC domain models
New "VITEC Import" module under Web: one import page per domain model
(v1: Market, Solution, Product - registry-driven, adding a model is one
config entry). Workflow: upload a CSV (delimiter and encoding are
auto-detected, including German-Excel semicolon/Windows-1252), map CSV
columns to DB fields, persist the mapping per model together with the
identity field used for matching (new table tx_vitec_import_mapping,
no TCA - pure tool configuration), review a unified list of CSV rows
matched against the DB records (new / update with differing fields /
unchanged / db-only), then apply the checked rows through DataHandler.

Each importable row carries an editable JSON payload textarea - what
is written is the textarea content, not the raw CSV, so editors can
fix values right in the review step. The parsed CSV travels through
the form as a hidden JSON field: no session state, no temp files.
Importable fields are derived from TCA at runtime (scalar types only;
files, categories and other relations are excluded - a flat CSV
cannot carry them). Payloads are whitelisted against that field list
on apply; new records require a storage pid (prefilled from existing
records). BE user permissions apply via DataHandler.

Deliberately out of v1: import log with three-way compare (protection
against overwriting manual edits), images/relations, multiple saved
mappings per model.

Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
2026-08-07 12:53:21 +02:00
orascheandClaude Opus 5 baa0fdd331 Import old-site downloads and add a type taxonomy
New CLI command vitec:import-downloads: reads the JSON export of the
old site (www.vitec.com/import), cuts it out of the surrounding page
template by brace counting, and imports the downloads idempotently by
slug. Scope is deliberately narrow: only files under
/fileadmin/downloads/Collateral/, records without title or file are
skipped, records sharing one file_url are merged. Files are fetched
resumably into fileadmin/downloads/Collateral/ and stored on pid 29.

Legacy filenames are normalized on fetch so every imported file
matches the <prefix>__<filetype>__<NN>-<letter> version convention:
__NN_A -> __NN-A, ___NN -> __NN, __NNA -> __NN-A, and a bare __NN
gets -A appended as its initial revision. Verified against the full
export: all 179 names match afterwards, none of the already-correct
ones change.

tx_vitec_domain_model_download gains a second category field "type"
(display taxonomy: Datasheet, Success Story, Brochure, Software) next
to the filename-driven filetype categories. No SQL change needed -
the core generates columns for category fields. The three download
renderers emit the field as a string analogous to filetype; MM rows
are distinguished by fieldname, existing queries filter on it and
remain unaffected.

Import values are matched via the custom columns sys_category.filetype
and .type (falling back to title); missing categories are created
(filetype under --category-parent, default 4; type under a "Download
Type" parent).

getDownloadFile() in the three download renderers gains a filepath
fallback (FAL -> convention -> filepath) as a safety net for any
future filename that escapes the convention - previously such records
emitted file: null.

Architecture spec bumped to v1.7.

Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
2026-08-07 12:08:48 +02:00
orasche 27cc22dc69 Markets List and Detail Plugin 2026-08-05 16:53:02 +02:00
orasche a739dd8fe3 Formular-Infrastruktur: Contact/Demo/Helpdesk mit E-Mail- und Salesforce-Delivery, JSON-Renderer-Erweiterungen, Crop-Variants
Build-Artefakte in public/_frontend/assets nicht enthalten.
2026-07-30 13:12:45 +02:00
khaccountandClaude Fable 5 eae40f4286 Success-story migration + new plugins + JSON/UX polish
- Success Stories: full migration from old site (48/48, audited),
  markets n:n, quotation content block, columns content block,
  pretty SEO detail URLs via SuccessStoryPathRewrite middleware,
  list/detail split (list page 4 / story page), detailUrl/backUrl
- New plugins: VITEC Locations (grid/list/map + RTE map text),
  VITEC Customer Logos (color/bw logic, only-show-selected),
  VITEC Card (one plugin for product/story/market/solution
  with reloading FlexForm + custom backend preview renderer)
- Eventlist: layout dropdown (list/grid/teaserbar) in settings
- Hero section CB: Images/Video tabs, background video + overlay
- Product JSON: full category rootline (parents), fixed missing
  ConnectionPool import (all-products crash), category tree map
- Backend preview CSS: container-query responsive (narrow columns)
- Docs: ISO architecture spec, root + extension READMEs

Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
2026-07-24 09:53:33 +02:00
khaccount de8e3f55df Dev Commit 2026-07-09 10:10:05 +02:00
o-rascheandClaude Opus 4.8 bb7c03235d Checkpoint: headless JSON architecture documented + cleanup (Stufe 1+2)
Restore point before Stufe 3 (central resolver-service refactoring).

Includes this session's work:
- Success Story (usecase) rebuild: new fields/tabs, UsecaseSerializer,
  thin List/Show renderers, MM relations, inline content elements.
- vitec_columns content block (two-column layout with per-item content)
  incl. unified header section; special-cased JSON resolution.
- Container per-column flex (items[].config align/justify) + gap on parent.
- Unified header section across CEs/plugins/containers; header fields in JSON.
- ISO-style architecture spec: Documentation/Headless-JSON-Architecture.md.
- Cleanup: removed local scratch + verified .bak backups.
- Fixes: B-6 (undefined thumbnail variable in Downloadcardcollection image
  resolver), B-7 (unsatisfiable legacy CType OR branch in Downloadcard/Datasheets).

Rollback: git reset --hard snapshot-2026-07-09-pre-stufe3

Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
2026-07-09 10:01:56 +02:00
khaccount c6759186cb DEV CommiDEV Committ 2026-07-01 10:34:48 +02:00