Files below fileadmin/placeholders/ (or named "...placeholder...") are grey
dummies. PageCheckService and ProductCheckService now report them:
- image cells carry `placeholder` = number of placeholder files (only when > 0);
`ok` is unchanged (something is attached)
- summary.filled counts only cells without placeholders, new summary.placeholder
counts the cells that have one
- detail images carry `placeholder: true|false`
- cards: `placeholder` = cards whose icon/image is a placeholder; record: the
record image
Additive change to the JSON contract; frontend rendering follows (ticket).
Requested by Harry 2026-11-13.
Co-Authored-By: Claude Fable 5.1 <noreply@anthropic.com>
Sibling of the product check (decision Harry 2026-11-13): new content element vitec_pagecheck with a FlexForm scope (markets | solutions) and PageCheckService/PageCheckJsonRenderer. Overview = one row per page of the tree (11 markets + 24 sub-markets, 8 solution groups + 39 sub-solutions) with 18 checks taken from the page elements (hero image and subline, lead, intro text/image/CTA, cards with visuals, testimonials, products, insights text/cover/CTA, logos, CTA banner), the page properties (meta description, OG image, page media) and the market/solution record behind the page; columns a page type does not have come as ok null. ?check=<pageUid> delivers the page detail (elements in page order with texts, links, images, FlexForm settings; SEO, media, record, children). Always USER_INT, check is cHash-excluded already. New command vitec:pagecheck-pages created /markets/market-check (608) and /solutions/solution-check (609) from the product-check page properties; both live on DEV, rendering is front end work.
Co-Authored-By: Claude Fable 5.1 <noreply@anthropic.com>
New command vitec:markets-figma-elements (dry-run by default, --apply writes) for the 11 main market pages: numbered placeholder image placeholders/pages/<uid>-02.png and learnmore_target /contact on vitec_marketintro, the hidden Trusted-by and Case-studies shells of the 2026-10-23 page import unhidden (logos with the home page settings, case studies as testimonials with the empty selection = all stories, like the sub-market pages), the lead paragraph in the hero slot hidden (decision aehm 12.11., not deleted). Sub-market pages: vitec_marketinsights CTA /success-stories -> /insights/news with the label Explore our insights. Applied on DEV 2026-11-12: 11 images, 11 targets, 11 logo bands, 11 sliders, 11 hidden leads, 24 CTAs, 0 warnings; protocol in migrations/markets_figma_apply_20261112.txt.
Co-Authored-By: Claude Fable 5.1 <noreply@anthropic.com>
Deliverability check (e.g. mail-tester.com) with the same sender, mailer and plain-text format as a real alert. Optional address; without one the configured alert recipients get it. No health sample is taken.
Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
Decision Harry 2026-11-12 for the third level of the products panel: an overview page with exactly one product is presented as that product. items[].link becomes the product detail page and items[].image the product picture (productimage, else heroimage, else the page media as before); new additive fields items[].linkType (product | overview) and items[].overviewLink (always the overview page). The product uid is resolved from the card link via the product slug; one extra query per build. Applies today to Avedia, EZ TV, X-Player End-Points, ChannelLink IP Gateway and ActiveSQX and switches back automatically once an editor adds a second card. Removing the sub-product line and the shortcut pill/subline is front end work (ticket 0121-BE).
Co-Authored-By: Claude Fable 5.1 <noreply@anthropic.com>
The frontend reads the main navigation from the headless initial-data type (?type=834, field navigation) in both SSR and SPA mode, has no language switch and keeps its favicons static, so the three page-level fields were dead weight (about 15 kB per page for mainNavigation alone). Removed from page.10.fields; lib.mainNavigation dropped, FaviconsJsonRenderer stays in the code base unused. Verified on DEV: page JSON of /, /product/aligo and /products/appliances without the three keys, footerMenu/metaMenu unchanged, /_json/?type=834 still delivers the 7 top-level items.
Co-Authored-By: Claude Fable 5.1 <noreply@anthropic.com>
SsrPurgeTargetResolver finds the paths of a saved VITEC or news record: its detail URL, the pages that select it (sys_refindex), product lists by category or all products, list plugins of its type and the records embedding it one level deep. URL, visibility and timing changes, the newest news, events, unknown tables and more than 150 paths still purge everything. Megamenu records and the megamenu element now purge everything (before: only its storage page). New read-only command vitec:ssr-purge-targets shows what a save would purge. Reference index rebuilt (117 updates).
Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
The big response time number is labelled last check. ClientErrorClassifier tells smoke and curl test reports and bot reports apart; tests are counted separately and left out of the tile, the hourly bars, the list and the dashboard tile, bots keep a label.
Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
The product audit of public/product-check/ becomes data for the React frontend: new content element vitec_productcheck (plugin registration, wizard entry, TypoScript USER func) delivers under content.productcheck either the overview (every product with one {ok,count} check per field - hero, photos, og, video, teaser, subtitle, description, description2, highlights, capabilities, applications, features incl. icon count, resources, datasheets, solutions - plus per-field summary) or, with ?check=<uid>, the detail of one product (texts as stored HTML, images with original URL and 480px thumbnail, videos, feature cards with icons, resources, datasheets, solutions). ProductCheckService ports the PDO queries of the standalone page to Doctrine; the renderer is always USER_INT so the audit is never served from the page cache; check is excluded from the cHash. Migration adds the element to page 607 (/products/product-check). The standalone page stays untouched. Verified on DEV: overview 85 products in 0.13 s warm, detail 0.2-0.9 s, thumbnails resolve.
Co-Authored-By: Claude Fable 5.1 <noreply@anthropic.com>
New command vitec:scheduler-setup creates the scheduler group VITEC with the tasks vitec:ssr-health every 5 minutes and vitec:client-error-cleanup daily at 04:23, safe to run again; --disabled creates them switched off, --enable switches them on after the old crontab lines are gone.
Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
New site setting vitec.ssr.alertEmails (Site Management, Settings, VITEC; one address per entry). vitec:ssr-health reads the recipients from there, invalid entries are skipped and logged, SSR_ALERT_EMAIL in the env file stays as fallback. The cockpit shows the recipients in the live band. Pre-filled with the address that was in the env file.
Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
Every tile of the module and the three SSR dashboard widgets has a round question mark button top right. Hovering it or focusing it with the keyboard shows a tooltip that explains what the tile shows. Pure CSS, anchored to the card so it never leaves the tile.
Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
The three SSR widgets render dark VITEC tiles like the cockpit module: status with pulse, cache ring and last purge, statistics with the 24 h availability strip and number tiles, errors with hit rate ring and split bar. Shared markup in CockpitHtml, styles in dashboard-ssr.css loaded per widget.
Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
Live band with 24 h availability strip, gauges for hit rate, response time, cache fill and client errors, traffic chart 24 h / 7 days from the health log counter deltas drawn with the core Chart.js of EXT:dashboard, warm progress ring with live polling, purge activity timeline, client error cards, link to the site settings. ssr-cockpit.js replaces ssr-warm-progress.js, whose deletion went into a9923e1.
Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
Mit dem selbstreferenzierenden Canonical (07f74e3) zaehlten
/insights/news?page=2 und ?category=... als eigene Seiten mit dem
Titel von Seite 1 (Seobility: 3 doppelte Titel, 2x Duplicate Content).
VitecMetaHandler haengt jetzt ' - Page N' bzw. die Kategorie an Titel
und Description.
Co-Authored-By: Claude Fable 5.1 <noreply@anthropic.com>
Ticket 0096-FE (aehm): the module now uses the core Module layout (DocHeader with reload and shortcut, module-body spacing), a Status card as description list with one badge style, an Actions card with core buttons and icons, help texts below the buttons and TYPO3 modal confirmations (ssr-module.js) instead of window.confirm, and three protocol cards. Purge protocol rows show a one-line time, the trigger as badge plus user, paths as count + first two + disclosure, result and duration right-aligned, with 30/100/500 row switches. Status shows the last health sample with relative age and the cache limit (new optional SSR_CACHE_LIMIT_MB in var/vitec-ssr-purge.env, SsrPurgeService::getCacheLimitMb). ssr-warm-progress.js now also disables the Warm button with a spinner while a run is active. backend-ssr.css holds only layout glue with core CSS variables (dark mode safe). Verified in the backend: layout, modal, running progress bar, protocol tables.
Co-Authored-By: Claude Fable 5.1 <noreply@anthropic.com>
VitecMetaHandler: /insights/news?page=2 (und ?category=) bekommt einen
selbstreferenzierenden Canonical statt Seite 1 (0100-FE 5.1).
PageJsonLdRenderer: auf Produkt-, News- und Story-Detailseiten ersetzt
der Datensatz (Titel + URL) die Shell-Seite als letztes Breadcrumb-
Element (0108-FE F11). UsecaseListJsonRenderer: cardImage.crops aus den
Listen-Karten entfernt, ~20 kB pro Seite mit Testimonial-Band
(0102-FE 5). Migration fe_answers_fixes_20261111 (angewendet):
Platzhalter 'H1 Header' (/solutions) und 'Featured Product' (Startseite,
Lorem ipsum, CTA auf /product) versteckt; Karte 'Government' auf
/markets/government; Button in #699 'Explore our solutions'; Story CDC
h4 'Product Highlight' -> h3 (0104-FE 4.1).
Co-Authored-By: Claude Fable 5.1 <noreply@anthropic.com>
Der erste Lauf (5bm) legte die neuen Why-VITEC-Baender auf 9 Uebersichts-
seiten als text_only an - das Frontend baut das Icon-Band nur aus icon_card.
Importer legt neue Band-Karten jetzt als icon_card (ohne Icon) an und stellt
vorhandene Band-Karten beim Re-Run um; 36 Karten repariert, Seiten gepurgt.
Co-Authored-By: Claude Fable 5.1 <noreply@anthropic.com>
The Cache warming row of the VITEC SSR module now shows a Bootstrap progress bar with a running counter instead of asking for a reload. New ajax route vitec_ssr_health (SsrController::healthJson) returns the node /__health JSON; ssr-warm-progress.js polls it every 2 s while a warm run is active and every 15 s otherwise (pauses in background tabs) and also refreshes the Cache: N pages / M MB line. The health fetch moved into SsrController::fetchHealth, shared by indexAction and the ajax route; its error text is English now. Verified live in the backend: bar, counter and cache line advance during a run.
Co-Authored-By: Claude Fable 5.1 <noreply@anthropic.com>
Migration crawl2_fixes_20261110 (angewendet): sechs Karten-Buttons
zeigten auf versteckte/geloeschte Produkt-URLs (ArtioSign/ArtioView ->
/products/aetria, Redirects folgen; X-View-Selbstlink entfernt;
Chassis-Karte auf das verbliebene Produkt). Drei weitere News trugen
noch den InfoComm-Importplatzhalter und doppelten echte Artikel
(JODDB, Bluefin, NAB 2026) -> geloescht + 301; EKOM-Artikel bekommt
seinen Text von der alten /en/news-Seite; byte-identische Datapath-
Kopie (#551) -> 301. Drei Tippfehler. Tote vitec.com-Links in 14
Datensaetzen auf interne Ziele (/markets, /insights/sustainability,
Story Northwestern, /product/fx4, 'vitec.com./' und ' '-Links).
SEO-Titel fuer sieben Hauptseiten, Descriptions fuer neun
Kategorieseiten mit < 60 Zeichen.
VitecMetaHandler: Titel-Kontext ueberspringt Ordner-/Shortcut-Ebenen
('End-Points | Products | VITEC' statt 'End-Points | VITEC'); kurze
Story-Titel bekommen '| Success Story'; Meta-Description auf 155
Zeichen gekappt, auch redaktionelle (Seobility: 527 'zu lang').
Co-Authored-By: Claude Fable 5.1 <noreply@anthropic.com>
13 Pressemeldungen tragen denselben Text wie eine Success Story
(Seobility: doppelter Inhalt). Neues Feld am News-Datensatz (Tab
'VITEC SEO', Auswahl der Story); VitecMetaHandler ersetzt damit den
Canonical-Link durch /success-stories/<slug>. Die Meldung bleibt in der
Liste, Suchmaschinen werten die Story als Original. Migration
news_story_canonical_20261110 setzt die 13 Zuordnungen (angewendet).
Co-Authored-By: Claude Fable 5.1 <noreply@anthropic.com>
Bisher gab es den Aufklapper nur bei Meldungen mit Stack. Jetzt hat jede
Zeile "details" mit Zeit, Release, voller URL, kompletter Meldung,
Stack (oder Hinweis "no stack transmitted"), vollem User-Agent und
anonymisierter IP, damit sich jeder Fehler bewerten laesst (Wunsch Harry).
Co-Authored-By: Claude Fable 5.1 <noreply@anthropic.com>
Die Kategorieseiten tragen seo_title = '<Titel> | VITEC' (Import), was
die Kontext-Vorlage als gepflegten SEO-Titel las. Der Brand-Suffix wird
vor dem Vergleich abgestreift; die Vorlage baut den Titel aus Seitentitel
+ Elternseite neu auf, der Brand-Suffix folgt wie bisher.
Die Rootline ist root-first; der Helfer las bisher Index 1 (oberste
Ebene, 'Products') statt der direkten Elternseite ('AVoIP & KVM').
Co-Authored-By: Claude Fable 5.1 <noreply@anthropic.com>
Der Import hatte bei fast allen Seiten den Seitentitel 1:1 als seo_title
gespeichert, dadurch griff die Kontext-Vorlage fuer kurze Titel nie. Ein
seo_title, der dem Seitentitel entspricht, gilt jetzt als nicht gepflegt
('Aligo | AV over IP & KVM | VITEC'). Dazu die Meta-Description der
Solutions-Uebersicht (war bis heute der TCA-Platzhaltertext).
Co-Authored-By: Claude Fable 5.1 <noreply@anthropic.com>
Crawl nach dem Footer-Fix: 1.094 Seiten (vorher 9). Backend-Anteil:
- Migration seo_report_fixes_20261110: Platzhalter-SEO-Titel auf /solutions
geleert; News mit verdoppeltem Titel/Slug und Slugs mit Slash bereinigt
(+Redirects); 8 Tippfehler; zweite Welle toter Alt-Links (datapath.co.uk-
Absolutlinks, utm-Varianten, /resource-center, /services, /contact-sales,
/aetria-use-cases, /video-wall-solutions ...) in 48 News ersetzt + 101
Redirects; Record-Shells /product, /news/article, /success-stories/story
leiten auf ihre Uebersichten; Meta-Description /datasheets; WordPress-
Reste in den 17 SEO-Artikeln entfernt; 53 News-Zeiger-Records (type=1
auf alte /en/news-Seiten, ohne eigenen Text) bekommen den Seiteninhalt
(Text + Bilder) in den Record und werden normale Artikel - die alten
Seiten leiten per 301 auf die Artikel.
- VitecMetaHandler: kurze Seitentitel ohne SEO-Titel erhalten ihren
Bereich als Kontext ('Aligo | AV over IP & KVM | VITEC').
- ProcessedFileReferenceToArray: Alt-Text-Fallback (Referenz-Titel, dann
Dateititel) fuer Content-Block-Bilder.
- UsecaseListJsonRenderer: Testimonial-Baender liefern nur noch Stories
mit Zitat, aktueller Markt zuerst, max. 12 (vorher alle 70 = 226 kB auf
jeder Markt-/Solution-Unterseite, identische Bloecke auf ~90 Seiten).
- NewsJsonRenderer: paginierte Listen-Payloads 15 Min. im hash-Cache
(USER_INT rendert sonst jede Variante neu; 50 langsame URLs im Report).
- robots.txt host-abhaengig: dev bekommt robots-dev.txt mit der dev-Sitemap
(Seobility fand '0 Sitemaps', weil die Sitemap-Zeile auf www zeigte).
Co-Authored-By: Claude Fable 5.1 <noreply@anthropic.com>
Neue PSR-15-Middleware ClientErrorMiddleware: nimmt Browser-Fehler des
React-Frontends als JSON {url, message, stack, release, userAgent}
entgegen und antwortet 204 ohne Body. Schutz: 30 Meldungen pro Minute
und IP (Sliding Window ueber TYPO3-RateLimiter, 429 + Retry-After),
8-KB-Body-Limit (413, Content-Length und tatsaechliche Bytes), kein
JSON-Objekt oder leere message = 400, GET = 405. Keine Session, keine
Cookies; der /_json-Praefix funktioniert ebenfalls.
Speicherung in der neuen Tabelle tx_vitec_clienterrorlog mit
anonymisierter IP (IPv4 letztes Oktett 0, IPv6 /48). Sichtbar als
Tabelle "Client errors (last 24 h)" im Modul VITEC SSR (mit Stack als
Aufklapper) und als Zeile "Client errors reported (24 h / 7 d)" in der
Dashboard-Kachel VITEC: SSR statistics.
CLI vitec:client-error-cleanup [--days=30] loescht Eintraege aelter als
30 Tage (taeglich per Cron).
Co-Authored-By: Claude Fable 5.1 <noreply@anthropic.com>
Die SEO-Artikel trugen (a) eine FAQ-Sektion als nackte <p>-Paare im
Bodytext und (b) ~150 Links auf die alte datapath.com-Struktur
(/datapath-products/..., alte /markets/...-Namen, /video-wall-solutions)
- alles 404 auf der neuen Seite.
- NewsJsonRenderer (Detail-Modus): extractFaqBand() schneidet die
'Frequently asked questions'-Sektion aus dem Bodytext und liefert sie
strukturiert als faq {heading, items[{question, answer(HTML)}]} fuers
Frontend-Accordion (fail-safe: unter 2 sauberen Paaren bleibt alles
unveraendert); collectMentionedProducts() liefert bis zu 6 Karten
(title, text, image, link) fuer im Text verlinkte Produkt- und
Kategorieseiten. Beide Felder additiv; Listen unveraendert.
- Migration fix_datapath_links_20261110: 148 News-Records auf die neuen
Ziele umgeschrieben (Mapping alte Datapath-IA -> /product/<slug> bzw.
/products/<slug>/Markets/Solutions, Ziele gegen DB verifiziert) und
113 sys_redirects 301 angelegt (alte Pfade mit und ohne Slash - greift
fuer externe Backlinks, sobald datapath.com hierher zeigt).
Live verifiziert: Beispielartikel liefert faq (8 Fragen, Antworten mit
funktionierenden Links), 4 Karten, Bodytext ohne FAQ-Absaetze und ohne
Datapath-Links; normale News unveraendert (faq null); Redirects 301 ok.
Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
17 SEO-Artikel tragen ein rohes FAQPage-JSON-Objekt in einem
abschliessenden Absatz ihres Bodytexts - das Frontend renderte es als
sichtbaren Text, Google sah es nie als strukturierte Daten.
Neue Klasse Seo\EmbeddedJsonLd trennt solche schema.org-Bloecke aus dem
RTE-HTML (fail-safe: was nicht sauber dekodiert, bleibt stehen):
- NewsJsonRenderer: Detail-bodytext und Listen-Exzerpt ohne die Bloecke
- PageJsonLdRenderer: die dekodierten Nodes wandern in den @graph der
Seite (FAQPage landet damit als <script type=application/ld+json> im
Head, den das Frontend bereits injiziert)
- VitecMetaHandler: Description-Fallback aus dem Bodytext ohne JSON-Muell
Verifiziert an 3 Artikeln: @graph mit NewsArticle + FAQPage (8-9 Fragen),
kein FAQPage-Rest im Textkoerper, kein sichtbarer JSON-Absatz im HTML.
Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
Die Uebersichtsliste (news_newsliststicky/news_pi1 ohne limit und ohne
Auswahl, d.h. genau /insights/news) liefert jetzt pro Request nur die
Karten der angefragten Seite: ?page=<n>&category=<slug>, Antwort additiv
mit pagination {page,pages,itemsPerPage,total}, categories[] mit
Gesamt-Zaehlern und activeCategory. page klemmt auf die letzte Seite,
unbekannte category faellt auf alle zurueck, Sortierung serverseitig
datetime DESC, itemsPerPage aus settings.list.paginate (Default 12).
Caching: page/category stehen in cacheHash.excludedParameters, der
TYPO3-Seitencache unterscheidet die Varianten also nicht - das Element
konvertiert sich deshalb im paginierten Fall per
convertToUserIntObject() zu USER_INT (EXT:headless wrappt den
INT-Marker selbst); ETag/304 je Query-Variante verifiziert, der
SSR-Cache haelt eine Variante pro Pfad+Query.
Karten im paginierten Modus in schlanker Form (Felderliste aus
0070-FE); media[] traegt jetzt ueberall alternative (Alt-Text-Fallback
B5). Teaser-Listen mit limit und Selected-/Search-Listen unveraendert;
ohne pagination-Feld bleibt das Frontend beim bisherigen Verhalten.
JSON der Liste: 700 kB -> ~100 kB pro Seite.
Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
Ticket 0068-FE: ProductFeatureJsonRenderer returned json_encode(null), which headless passes on as the STRING null (it only decodes object/array-looking strings) and crashed the front end. It now returns an empty string and the TypoScript field sets ifEmptyReturnNull = 1, giving a real JSON null. No other renderer used the pattern. Ticket 0066-FE: SsrPurgeService::warm() posts to the node /__warm endpoint (derived from SSR_PURGE_ENDPOINT, same secret), exposed as a Warm cache button with confirmation in the VITEC SSR module, a Cache warming progress row fed by /__health, and the CLI vitec:ssr-warm [paths]. Warm runs are deliberately not written to the purge log. Verified: two-path run 2/2 done, affected page delivers productfeature null.
Co-Authored-By: Claude Fable 5.2 <noreply@anthropic.com>
The backend context menu appends .js itself when importing the callback module; with the extension already in the attribute the browser requested ssr-context-menu.js.js and the click died silently. Confirmed working in the backend after the fix.
Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
SsrPurgeItemProvider adds the item behind Clear cache for real pages (doktype < 199) whenever the purge endpoint is configured. The callback module posts the page uid to the new vitec_ssr_purge_page ajax route, which resolves the page path through the site router, purges it via SsrPurgeService (trigger contextmenu:username, logged as usual) and reports back as a toast notification.
Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
Widgets, backend module template and flash messages now match the rest of the backend, which is English.
Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
The group identifier comes from EXT:dashboard DashboardWidgetGroups.php; with an unknown group the widgets never appeared in the add-widget dialog.
Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
Package 1: SsrPurgeService posts to the node /__purge (endpoint+secret in var/vitec-ssr-purge.env, outside git) and logs every attempt to tx_vitec_ssrpurgelog. DataHandler hooks queue per request and flush once: pages with nav-relevant field changes and all tx_news_/tx_vitec_ records purge everything, other page/content edits purge the hosting page path. Gated by the routing flag and the new Site Set switch vitec.ssr.autoPurge. Flipping the SSR switch ON purges everything once. CLI: vitec:ssr-purge, vitec:ssr-health (samples /__health into tx_vitec_ssrhealthlog, 14 days kept, scheduler-ready). Package 2: dashboard widgets vitecSsrStatus (live health, release, switch, last purge) and vitecSsrStats (purge counts, failures, uptime, response time). Package 3: backend module web_vitecssr with manual purge (paths or everything) and both protocols. Tested end to end against the running node (purge single/all 200, health sample logged).
Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
Ticket 0054-FE section 5: (1) with the SSR flag on, /_frontend/assets/* is now proxied to the VPS release as well, deliberately without a file-exists guard so stale local SPA hashes cannot shadow the release; the proxy rules tag requests with env SSRPROXY and mod_headers adds X-Forwarded-Proto: https. (3) If-None-Match comparison in JsonCacheHeaders accepts the -gzip suffix that mod_deflate appends, so browser 304s work through compression. (4) X-TYPO3-Cache-Tags*/-Debug-Cache/-Cache-Lifetime/-Parsetime are stripped from responses (onsuccess and always tables - they leak record ids and overflowed the SSR node 16 KB header limit on news pages).
Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
New JsonCacheHeaders middleware (outer, frontend stack): GET/HEAD 200 responses under /_json get a single Cache-Control: no-cache, Expires: 0 and a content md5 ETag; If-None-Match answers as empty 304. Logged-in visitors (fe_typo_user) keep TYPO3 headers. Expires: 0 is deliberate so mod_expires leaves the response alone. .htaccess: the global Header unset ETag now skips /_json (KEEP_ETAG env, carried across the mod_rewrite internal redirect as REDIRECT_KEEP_ETAG). Fulfils tickets 0011-FE point 3 and 0055-BE question 6; asset immutable headers were already live.
Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
All seo.* settings now carry real values (sources: vitec.com footer + privacy policy, KBIS for the legal name VITEC SA): canonical base, org name/legalName, address Chatillon, phone, sameAs LinkedIn/YouTube, logo at fileadmin/vitec-brand/vitec-logo.png (served 200, verified in the home jsonLd as absolute www.vitec.com URL). Email left empty - no public address exists. Removed the my.vitec.setting / my.seoRelevantSetting scaffold examples from the set definition and the my.example.setting value.
Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
- Site set Vitecset: new bool setting vitec.ssr.enabled (default off,
backend switch under Site Management > Settings > VITEC Settings)
- SsrFlagService derives var/vitec-ssr-on.flag from the setting;
SyncSsrFlag middleware (frontend + backend) re-syncs per request
because TYPO3 v14 fires no event on site settings save;
vitec:ssr-flag CLI command for status/--sync
- public/.htaccess: flag-gated block proxies page requests [P] to
https://vitec-ssr.evomedien.de (mod_proxy incl. https target verified
on this host 2026-11-09), same exclusions as the SPA fallback block;
completely inert while the flag file is absent
- Emergency off without TYPO3: delete var/vitec-ssr-on.flag
- Tested end to end: flag on -> pages proxied to VPS Caddy (502 while
the SSR node is not deployed yet), /_json untouched; flag off ->
SPA shell exactly as before
Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
The 2026-11-02 menu build created the 3 categories and 9 sub-categories
as sysfolders (labels); every level must be a clickable page.
- build-product-overviews: six sub-categories adopt the 2026-10 category
pages (Joe's workbooks; content, slug and SEO kept, sitemap name as
nav_title), the remaining folders become pages with generated content,
Capture & Graphics gets the main column of Graphics & Multi-Display and
Video Capture copied in. Pages move/convert by direct UPDATE (the
redirects slug hook would rewrite the flat child slugs); three 2026-10
pages leave the menus but stay reachable. Warns about a sys_redirect
on a target slug.
- ProvideProductCatalog: categories[].link and groups[].link (additive),
menu title = nav_title when set, only filled groups/categories count.
The menu search reads both levels as pages too.
- build-why-vitec-bands: band at the top of the main column; on pages
with an existing "Why VITEC?" section the context's icons go onto the
cards whose title matches the icon theme (16 icons on 4 pages).
- No browser cache headers on the page JSON: headless enables
sendCacheHeaders and TYPO3 14 caches pages for a year by default, so
every /_json/ response carried max-age=~31536000.
- Spec v1.32.
Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
- Megamenu entries with the catalog or spotlight layout get two editor
fields, "Data source folders" (source_pages) and "Data source
categories" (source_categories); the extension stores them, the site
package's listener reads them from the entry row.
- ProvideInsightsSpotlight reads its news from those folders (empty =
11 + 442; the newer posts live in 442, the query only read 11) and,
when set, only from those categories (Insights: Blog Post + Press
Release). Newest datetime first, three cards.
- Pages carrying the menu are tagged with the news and event tables, so
saving such a record refreshes the menu without a cache flush.
- VITEC field descriptions via a TCA override; spec v1.31, README.
Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
- token-containment pass: theme words inside the card title
(ManagementFoundation -> "Aetria management foundation")
- last-pair rule: a complete set (#icons == #cards) with exactly one
icon and one card left over pairs them (FlexibleConnection,
EndToEndEncryption, HighPerformance, 4KSourcetoDisplays, AVoverIP)
- genuine mismatches (aligo-workstation, EZ-TV Platform, AvediaPlatform
Artio icons) still stay unmatched for the editors
Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
- new inline table tx_vitec_product_feature (title, cardtext, FAL icon)
+ `features` field on the product record; ProductShowJsonRenderer
emits product.features {heading, items[{title, text, icon}]} and null
while a product has no cards, so the front end keeps its
applications-HTML fallback
- new vitec:seed-product-features: seeds the cards from the
applications <p><strong> pairs and matches the staged agency icons by
normalised title (camelCase split, stop words, Levenshtein <= 3 typo
tolerance); products with existing cards are never touched
- new vitec:build-why-vitec-bands: "Why VITEC?" intro + icon_card band
on the 7 overview pages with a staged icon set (the contract's
"centered" variant does not exist - documented in ticket 0039-BE);
vision/visionav sub-group sets stay unassigned
- product-check page: sortable title column and an Open Product button
- new migration fix_colombia_quote.php: stray quote element #12037
removed, quote_role set (ticket 0038-FE)
Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
The vitec/herosection content block has prefixFields - the real column
and sys_file_reference fieldname is vitec_hero_bgimage; the JSON merely
strips the prefix. The first apply wrote the 20 references with the bare
name, so they existed but never rendered (no herosection anywhere had an
image, so there was no working example to catch it against).
- BuildProductOverviews: attach/backfill/skip-check now use
vitec_hero_bgimage
- new migration fix_overview_hero_refs.php: renames the existing 20
references in place (no re-attach) and sets the counter column
Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>