Commit Graph
135 Commits
Author SHA1 Message Date
orascheandClaude Fable 5.1 f4f18e913a Produkt-Uebersichtsseiten: Agentur-Texte aus den "Enriched"-Workbooks importiert
- neues CLI vitec:import-product-overview-workbooks (Dropbox-Lieferung 09.11.,
  15 Workbooks): Hero-Subline/CTA, Intro + Use Case, Why-VITEC-Band (Text-
  karten bzw. Text auf passende Icon-Karten), Range-Intro, Solution-Karten
  mit Link auf die Gruppenseite, CTA-Banner, SEO-Meta; Produktkarten bleiben
  (Record-Teaser), Vergleichstabelle nur mit --comparison
- vitec:seed-product-features --attach-icons: gestagte Icons an vorhandene
  Karten ohne Icon haengen (PRISM 5/5, SFF PRISM 4/5 angehaengt)
- Diagnose-Skripte check_overview_pages_20261110 / check_banners_20261110
- .gitignore: migrations/product_overviews_xlsx_in, product_images_pending

Co-Authored-By: Claude Fable 5.1 <noreply@anthropic.com>
2026-11-10 19:37:15 +01:00
orascheandClaude Fable 5.1 2aa8865b23 Tote Partner-Links in alten News entlinkt (22 Links, 10 Artikel)
Entscheidung Harry: Link entfernen, Text behalten. Hosts: Queen's
Awards Magazine, Sam Minton, EET Group, Tecnomultimedia, Sentry Video
Walls, Exertis, InfoComm SEA, SurveyMonkey, Exterity, Eureka Network.
Migration unlink_dead_external_20261110 (angewendet).

Co-Authored-By: Claude Fable 5.1 <noreply@anthropic.com>
2026-11-10 19:17:11 +01:00
orascheandClaude Fable 5.1 e357f42b81 Seobility-Crawl 2: Karten-Links, Platzhalter-News, Titel-Kontext ueber Ordner, Descriptions 155 Zeichen
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 '&nbsp;'-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>
2026-11-10 19:08:34 +01:00
orascheandClaude Fable 5.1 4b6731786d News: Canonical auf Success Story (Feld vitec_canonical_usecase), 13 Paare gesetzt
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>
2026-11-10 18:20:03 +01:00
orascheandClaude Fable 5.1 f7b1eacecb Dubletten-Bereinigung nach Seobility: Produkt-Kopie, 10 News, Slugs, /about, Story-Texte
Migration dedupe_20261110 (angewendet): leere Chassis-Kopie geloescht;
bei InfoComm/LG/PRISM/ISE trugen die -1-Kopien den Text, die Basis war
Platzhalter oder leer - Kopien uebernehmen den sauberen Slug; identische
Kopien (Datapath-Uebernahme, Remote-Work-Blog) weg; Records ohne Inhalt
(Global Events, DSEI-2023-Zeiger) weg; WallControl-Award und die beiden
Jahresbotschaften mit sprechenden Slugs; /about (nur Standortliste)
versteckt und auf /insights/who-we-are umgeleitet, Links umgehaengt;
drei Story-Teaser/-Descriptions, die von fremden Stories kopiert waren,
neu gesetzt. Alle alten Adressen leiten per 301, bestehende Redirects
zeigen direkt auf die neuen Ziele (keine Ketten).

Co-Authored-By: Claude Fable 5.1 <noreply@anthropic.com>
2026-11-10 18:12:34 +01:00
orascheandClaude Fable 5.1 37c4c116d0 SSR-Modul: Client errors mit Details-Aufklapper in jeder Zeile
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>
2026-11-10 18:00:58 +01:00
orascheandClaude Fable 5.1 08c02276e5 Titel-Kontext: Import-Muster 'Titel | VITEC' als ungepflegt werten, direkte Elternseite
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>
2026-11-10 17:56:10 +01:00
orascheandClaude Fable 5.1 33bdb8d856 Titel-Kontext auch bei kopiertem SEO-Titel; Description /solutions
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>
2026-11-10 17:49:52 +01:00
orascheandClaude Fable 5.1 8a652063c5 Seobility-Report 2026-11-10: Backend-Befunde umgesetzt
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>
2026-11-10 17:47:55 +01:00
orascheandClaude Fable 5.1 5121eaa000 Client-Error-Endpoint POST /api/vitec/client-error (0072-FE / 0077-BE)
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>
2026-11-10 17:25:23 +01:00
orascheandClaude Fable 5.1 ff6f86b829 Footer-Spalten: Linktexte an die Relaunch-Struktur angeglichen
Die Footer-HTML-Bloecke (pid 19, #132-#135) trugen noch die Benennungen
der alten Website (Venues, Military, Accommodation, VITEC OG, PCIe
Encoder, Interactive TV Portal ...), obwohl die Ziele seit
seo_fixes_20261109 stimmen. Migration fix_footer_link_texts_20261110:
Linktext + title-Attribut = Navigationstitel der Zielseite (Produkt-
Records per Titel), Blatt-Eintraege, die auf dieselbe Seite wie ein
frueherer Eintrag oder ein Eltern-Eintrag zeigen, entfernt, die
Uebersichts-Platzhalter Healthcare (/markets) und Telemetry (/products)
gestrichen, leere Listen bereinigt. Redaktionelle Sonderfaelle: Digital
Signage in der Solutions-Spalte -> Loesungsseite, Fx4 Series -> /product/
fx4, IP/RF Gateways & Transcoders -> /products/gateways-and-transcoding,
HelpDesk-Seite als 'HelpDesk Access' (externer Login-Link steht
darueber). Externe Links, t3://-Links und Ueberschriften unveraendert.

Co-Authored-By: Claude Fable 5.1 <noreply@anthropic.com>
2026-11-10 16:05:05 +01:00
orascheandClaude Fable 5.1 be4bb44c40 Content-Block-Bilder als verarbeitete WebP mit srcset ausliefern
Lighthouse (Mobile) auf der Startseite: Score 40, LCP 25 s, 42 MB. Ursache:
nb-headless-content-blocks serialisiert Bildfelder (hero_bgimage,
intro_image, Karten, Banner) als publicUrl des ORIGINALS - 3,7 und 13,4 MB
JPEGs gingen unveraendert an den Browser, waehrend News-/Produktbilder
laengst durch den ImageService laufen.

- XCLASS Headless\ProcessedFileReferenceToArray (das Paket instanziiert
  seinen Serializer per makeInstance): publicUrl = WebP max. 1920 px mit
  Redaktions-Crop, dazu originalUrl/originalSize, srcset 480-1920
  (Stufen, die aufs Original zurueckfielen, entfallen), width/height,
  mimeType, size. SVG/GIF unveraendert (+Metadaten), Videos/PDFs bekommen
  mimeType/size. Exception-safe: Fallback auf Stock-Payload.
- .htaccess: fileadmin/_processed_/* mit Cache-Control max-age=1 Jahr,
  immutable (Hash im Dateinamen).

Effekt Startseite (gleiche Messbedingungen): LCP 25,1 -> 3,8 s, Bilder
18,7 -> 1,1 MB, gesamt 42 -> 22,6 MB; der Rest ist das 20-MB-Testvideo im
Hero (redaktionell) und Frontend-Themen (Ticket 0085-BE).

Co-Authored-By: Claude Fable 5.1 <noreply@anthropic.com>
2026-11-10 15:53:20 +01:00
orascheandClaude Fable 5 dc9b5fce47 News-Detail: FAQ-Band + Produktkarten, tote Datapath-Links migriert
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>
2026-11-10 12:52:14 +01:00
orascheandClaude Fable 5 5c640d02f7 News: redaktionell eingefuegtes FAQPage-JSON als echtes Schema ausgeben
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>
2026-11-10 11:36:48 +01:00
orascheandClaude Fable 5 c9b00e6f10 News-Liste: serverseitige Pagination (Kontrakt 0070-FE)
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>
2026-11-10 11:11:55 +01:00
orascheandClaude Fable 5 be163a88c2 SSR health alerts: mail texts in English
Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
2026-11-10 11:00:56 +01:00
orascheandClaude Fable 5.2 8f8ae039d4 Real JSON null for empty product feature; SSR warm-cache button and CLI
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>
2026-11-10 10:59:24 +01:00
orascheandClaude Fable 5 cb53ff67ee SSR dashboard: new errors-and-hit-rate tile fed by /__stats samples in vitec:ssr-health (stat_* columns in healthlog)
Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
2026-11-09 22:51:13 +01:00
orascheandClaude Fable 5 bc2e031b0c SSR health: alert mails on ok/down transitions + auto-failover to SPA after N consecutive misses (SSR_ALERT_EMAIL / SSR_FAILOVER_AFTER in var/vitec-ssr-purge.env)
Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
2026-11-09 22:18:06 +01:00
orascheandClaude Fable 5 b9736b9ac7 SEO-Audit 2026-11-09: Meta-Komposition, Sitemap, Redirects, robots.txt
- VitecMetaHandler: Record-Metadaten fuer News-/Produkt-/Story-Details
  (Titel, Description, og:/twitter:-Tags, og:image), '| VITEC'-Suffix,
  Fallback-Description aus Seitenfeldern, twitter:card large_image,
  Story-Canonical auf die oeffentliche Kurz-URL
- PageJsonLdRenderer: Product- und NewsArticle-Nodes auf Detailseiten
  (News-Details hatten <title>article</title> und kein Schema)
- NewsJsonRenderer: Listen ohne Volltext-Body (JSON 2.6 MB -> ~0.6 MB)
- XML-Sitemap: News-Teil konfiguriert (Ordner 11+442, Detailseite 21),
  Record-Sitemaps fuer Produkte und Success Stories (kurze URLs),
  Route-Enhancer fuer alle Teile, Shell-/Altseiten ausgeschlossen
- Migration seo_fixes_20261109: 161 Self-Canonicals geleert (warfen u.a.
  Home, Markets, Solutions, Support aus der Sitemap), noindex fuer
  technische und alte News-Seiten, 71 Redirects Alt-URLs -> neue Ziele,
  51 tote Footer-Links ersetzt
- public/robots.txt mit Sitemap-Verweis

Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
2026-11-09 22:11:01 +01:00
orascheandClaude Fable 5 be519f9bc1 Context menu purge: drop .js from the callback module specifier
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>
2026-11-09 21:14:50 +01:00
orascheandClaude Fable 5 5b524bfce9 Page context menu: Purge from SSR cache
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>
2026-11-09 21:10:30 +01:00
orascheandClaude Fable 5 fa63871da7 SSR control center: English UI strings throughout
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>
2026-11-09 21:03:40 +01:00
orascheandClaude Fable 5 91c2ceb5b1 Dashboard widgets: fix group name (systemInfo, not systemInformation)
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>
2026-11-09 20:59:39 +01:00
orascheandClaude Fable 5 63f950f9db SSR control center: auto-purge webhook, dashboard tiles, backend module
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>
2026-11-09 20:46:16 +01:00
orascheandClaude Fable 5 d52d49974f SSR switch-on fix: proxy the DirectoryIndex homepage detour
First switch-on with a running node: Apache mod_dir turns / into /index.html via the DirectoryIndex subrequest before the per-dir root rule can proxy it; the node then asked for /_json/index.html and rendered a cacheable 404 homepage. New flag-gated rule proxies index.html as / to the node. Companion fix outside git: public/_frontend/.htaccess (build output, gitignored) overrides the root rewrites for /_frontend/*, so release assets only existing on the VPS were answered by its SPA fallback with index.html - HTML served as JS; the flag-gated asset proxy now also sits in that file before the fallback, and the frontend build must adopt it in its .htaccess template (ticket 0059-BE).

Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
2026-11-09 20:20:07 +01:00
orascheandClaude Fable 5 d153cc2eba README: drop the dev basic auth credentials
The vitecdev password has been rotated today (htpasswd on the server, new value distributed via the password manager and set as VITEC_API_AUTH on the SSR VPS). Credentials do not belong in the repository; the leaked value is invalid as of now.

Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
2026-11-09 18:32:29 +01:00
orascheandClaude Fable 5 232aaf2ca8 SSR prep: asset proxy behind flag, forwarded proto, header hygiene
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>
2026-11-09 18:20:21 +01:00
orascheandClaude Fable 5 351349ec1f JSON API: Cache-Control no-cache + ETag/304 revalidation
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>
2026-11-09 17:03:05 +01:00
orascheandClaude Fable 5 dcd713f222 Site settings: fill schema.org organization data, drop scaffold examples
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>
2026-11-09 14:03:54 +01:00
orascheandClaude Fable 5 14623ed4fa gitignore: ignore all of config/system/, not just two files
additional.php.save (editor backup) was untracked and unignored - one git add -A away from pushing config internals. settings.php holds credentials, so the whole directory is off limits.

Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
2026-11-09 13:43:19 +01:00
orascheandClaude Fable 5 2c0da281bd SSR switch: site setting vitec.ssr.enabled gates .htaccess proxy to SSR node
- 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>
2026-11-09 13:35:27 +01:00
orascheandClaude Opus 5.5 bd7a145afa Products: categories and sub-categories become clickable pages
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>
2026-11-05 12:05:04 +01:00
orascheandClaude Opus 5.5 73e4298b75 Insights spotlight: news from folders 11 + 442, source editable in the menu
- 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>
2026-11-05 10:59:56 +01:00
orascheandClaude Fable 5 ad1f3c179c why-vitec band: move it before the "Product range" intro
- new migration fix_why_band_position.php: on the 7 overview pages the
  band (Why VITEC? intro + icon cards) had landed between the "Product
  range" heading and its product cards; reorders the top-level column
  to hero -> band -> Product range -> cards (ticket 0042-FE section 3)

Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
2026-11-04 20:51:42 +01:00
orascheandClaude Fable 5 f525ce3c27 product-check: Features column with icon coverage
- new "Features" column: check with cards-and-icons count per product
  (e.g. "5·4i"), header carries the filled total like the other columns
- detail pane lists every feature card with icon thumbnail (click to
  enlarge), title and text; cards without an icon show a red cross on
  the icon slot - the missing agency icon sets are visible at a glance

Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
2026-11-04 20:17:50 +01:00
orascheandClaude Fable 5 6ff9c3e7a8 seed-product-features: two more icon-matching tiers
- 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>
2026-11-04 20:03:50 +01:00
orascheandClaude Fable 5 46b12d4a58 product.features: Why-choose cards with icons (contract 0036-FE)
- 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>
2026-11-04 19:55:01 +01:00
orascheandClaude Fable 5 3ccb9b149e Stage the 2026-11 product asset dump: ignore migrations/product_images_in2/
The agency "Products Hero page" delivery (banners, product photos) is
staged per product slug under migrations/product_images_in2/ and
imported with the existing vitec:import-product-images command;
the staging directory stays out of the repo like product_images_in/.

Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
2026-11-03 19:32:42 +01:00
orascheandClaude Fable 5 d26c31e6d1 Product content check: live audit page under /product-check/
Standalone PHP page (public/product-check/index.php), deliberately NOT a
plugin so the React front end needs no counterpart. Reads fresh from the
DB on every request (settings.php PDO pattern):

- alphabetical table of all products, header row with 14 field columns
  (hero/photos/og/video, the text fields, resources/datasheets/solutions),
  green check with count / red cross per cell, filled-count per column
- every row expands to a detail pane: all texts rendered, all images as
  thumbnails with a click-to-enlarge lightbox, relations resolved
  (inline resources, datasheet/solution MM), flags, detail page link
- refresh button reloads with a cache buster; noindex + no-store;
  refuses to serve on www.vitec.com

The static badge view (migrations/build_product_audit.php ->
/product-audit/) stays as is.

Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
2026-11-03 19:13:23 +01:00
orascheandClaude Fable 5 ed3ced42b3 Product content check: live audit page under /product-check/
Standalone PHP page (public/product-check/index.php), deliberately NOT a
plugin so the React front end needs no counterpart. Reads fresh from the
DB on every request (settings.php PDO pattern):

- alphabetical table of all products, header row with 14 field columns
  (hero/photos/og/video, the text fields, resources/datasheets/solutions),
  green check with count / red cross per cell, filled-count per column
- every row expands to a detail pane: all texts rendered, all images as
  thumbnails with a click-to-enlarge lightbox, relations resolved
  (inline resources, datasheet/solution MM), flags, detail page link
- refresh button reloads with a cache buster; noindex + no-store;
  refuses to serve on www.vitec.com

The static badge view (migrations/build_product_audit.php ->
/product-audit/) stays as is.

Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
2026-11-03 19:09:23 +01:00
orascheandClaude Fable 5 8e173b1a85 Hero placeholder fieldname: vitec_hero_bgimage (content block prefix)
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>
2026-11-03 18:42:06 +01:00
orascheandClaude Fable 5 77661bf0b6 Datapath stories, grid repairs, menu v2 pure, hero placeholders, fec test
Batch of 2026-10-28/29 plus 2026-11-03:

- NEW vitec:import-datapath-stories: 22 story packages from the agency
  dump (docx + Links/ assets) as usecase records with content, quotes,
  images, customer logos, download cards; --repair-quotes normalizes
  attribution lines; asset backfill for existing stories
- /products grid incident repaired (fix_products_grid, fix_graphics_grid,
  check_grid_page): containers unhidden, 46 duplicate cards soft-deleted,
  section order restored; BuildProductPortfolio and
  ImportProductCategoryPages now GUARD against re-runs on pages that
  already carry vitec_cols_% containers
- &apos; double-encoding fixed: render-pipeline importers write literal
  apostrophes (ENT_NOQUOTES), fix_double_entities literalizes existing rows
- ticket quick wins (ticket_quickwins_20261028), broadcast market page
  cleanup, AttachCardImages market-card handling, SubmarketWorkbook
  META REPAIR, story content/video fixes (fix_story_*)
- ProvideProductCatalog: transitional v1 fields removed (categories
  uid/link, legacyGroupFields, item products teaser) - pure v2 shape
  (ticket 0024-FE); search renderer keeps its teaser
- BuildProductOverviews: heroes get the numbered placeholder background
  (placeholders/pages/<uid>-01.png, wide grey fallback) - backfill on
  existing pages with empty hero_bgimage, attached at creation for new
  pages; existing references always win (ticket 0026-FE); 40 placeholder
  PNGs shipped to fileadmin (not tracked)
- AttachPageMedia: --depth=3 with sysfolders as pass-through parents for
  the overview pages' -08 menu tiles
- NEW migrations/fec_isolation_test.sh: two-user live test proving
  fe_comment ticket isolation (backend verified tight, cross-user
  sighting traced to the FE page-JSON cache, ticket 0027-BE)

Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
2026-11-03 18:29:56 +01:00
orascheandClaude Opus 5.5 9211c8a395 Megamenu: rail display for page trees, cache tags, editorial promo boxes
- Page-tree entries get a "Page tree display" field (columns | rail |
  rail-compact), emitted as display + cardSize: Markets and Solutions
  show their main pages as a list and the sub-pages as image cards on
  hover. Page-tree items carry image (page media) and teaser (abstract)
  from stage 2. Additive; front ends ignoring display render columns.
- vitec:attach-page-media gains --depth=2 and falls back to the page's
  hero background before the grey placeholder; the 39 sub-solution
  pages got their hero image as page media.
- MegamenuJsonRenderer tags every page carrying the menu with the menu
  tables and tt_content_<uid>, so saving menu records refreshes all
  pages instead of waiting for a full flush.
- Products catalog: drop catalog.news; both promo boxes ("Product
  highlight", "Product news") are the entry's editorial teaser cards.
  ProvideInsightsSpotlight back to its previous state.
- Spec v1.29 and v1.30 (header version corrected), README.

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
2026-11-02 17:35:23 +01:00
orascheandClaude Opus 5.5 9fb7f0ca77 Products: 20 overview pages and megamenu catalog v2
Rebuild the product section after the agency sitemap and menu prototype
of 2026-11-02:

- vitec:build-product-overviews builds sysfolder labels (3 categories,
  9 groups) below /products with 20 overview pages /products/<slug>
  (layout 9: hero, intro per group, product cards, contact CTA) and two
  menu shortcuts. Dry-run by default, idempotent, explicit sorting.
- ProvideProductCatalog reads that page tree and emits catalog version 2:
  categories[].groups[].items[] of type page (productCount, products,
  image) or shortcut (target indices), plus viewAll, news and search.
- Transitional v1 fields (groups[].products/link/uid, categories[].uid/
  link, product teaser) keep the deployed front end alive; it read the
  v1 shape and rendered a white page without them. Remove once the
  front end reads items.
- ProvideInsightsSpotlight::latestNews() is public with a count.
- Product type-ahead (type 7385) adds matching overview pages and a
  per-product overview with its menu path.
- Spec v1.28.

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
2026-11-02 16:06:44 +01:00
orascheandClaude Opus 5.5 da2ebdca23 Product detail: resources section layout 3 "Hardware option"
- The Resources Section Layout select gained a third value, hardware
  ("Layout 3 - Hardware option"): Technical Highlights spread over two
  columns, no resource cards
- ProductShowJsonRenderer::resourcesBand() emits the same envelope with
  items: [] for hardware even when cards are maintained, so the cards
  stay on the product and reappear when switching back to layout 1 or 2
- Spec v1.27 (resources.sectionLayout values)

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
2026-11-02 15:11:26 +01:00
orascheandClaude Fable 5 d87e64f73b Success stories: downloads and product sections become real plugins
- comparison report migrations/check_product_downloads.php (kept,
  read-only): download records vs. the delivered product workbooks -
  34 of 74 workbook products have a datasheet, the entire Datapath
  line has none in the pool (import came from vitec.com; queued for
  Joe), ~35 orphan datasheets belong to products without records;
  a vitec:link-product-downloads re-run added seven clean links
  (Artio x2, Diamond-H, the three TOUGH records, X-View)
- RTE resolution fixed at the root: ContentElementResolver and
  ContainerChildrenProcessor passed bodytext RAW into the payload, so
  t3:// links leaked unresolved; both now run RTE columns (bodytext,
  vitec_quote) through RteResolver::html()
- the imported "Download Success Story" RTE buttons carried the wrong
  link identifier (tx_vitec_download -> download, one-time migration
  fix_download_record_links.php) AND old-site uids - missing here or,
  worse, accidentally pointing at foreign PDFs. New
  vitec:convert-story-download-buttons replaces them with real
  vitec_downloadcard plugins: the download is resolved by STORY title
  (manual map for ISR / "Okada Manilla", exact-title fallback for
  suffixless PDFs like "Lord's Cricket Ground"); 29 converted, 4
  stories without a delivered PDF have their button hidden. New
  FlexForm layout "Success Story Download" (story_download) applied
  everywhere; the FE renders it as the previous centered button
- the ADIB "Featured Products" text section (the only one site-wide,
  verified by scan_story_headers.php) is now ONE vitec_productlist
  with hand-picked products via old-name aliases and the new FlexForm
  layout "Success Story Products" (story_products); the four text
  elements are deleted. vitec:convert-story-product-sections stays
  re-runnable for future imports
- the productlist envelope additionally carries "columns" (= number
  of products, capped at 4) so the story grid renders as many columns
  as it has products - additive key, available to every product list;
  and hand-picked lists now ship successStories as an empty array (the
  empty category selection used to aggregate stories over the WHOLE
  tree, leaking story cards into the section)
- the story downloadcards carry header "Downloads" (set on convert
  and backfilled): the front end builds the story anchor nav from
  element headers, so the section now appears there
- diagnosis scripts kept: check_download_record, check_story_elements,
  scan_story_headers; verified live on the ADIB payload (structured
  download object, productlist [5,18,6], texts 10 -> 5)

Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
2026-10-28 14:10:59 +01:00
orascheandClaude Fable 5 80f6da7949 Retire the six old-taxonomy category stubs under /products
- diagnosis first (migrations/check_old_stubs.php, kept): the six
  old-taxonomy pages (#451-454, #456, #458) were completely empty - no
  content elements and NO family child pages (the family workbooks were
  deliberately never imported), so nothing needed moving
- migrations/retire_old_category_stubs.php (dry-run by default, guards
  against children/content) soft-deletes each stub and queues a 301
  sys_redirect onto its new-taxonomy equivalent; existing redirects for
  a path are kept
- applied and verified live: all six old paths answer with the 301
  redirect envelope onto the correct new category page, and the main
  navigation now shows exactly the nine new categories in sitemap order

Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
2026-10-27 15:19:38 +01:00
orascheandClaude Fable 5 b0690c4cdc Cards visible in the FE; /products cards wrapped into 33/33/33 grids
- the freshly attached card images did not show: text_only is the
  explicit no-image variant, so vitec:attach-card-images now flips a
  card to "vertical" whenever it carries (or receives) an image; and
  the new placeholder PNGs sat in the sshfs 770 trap - fix-asset-perms
  covers them, with public/product-audit added to its targets
- new generic vitec:wrap-cards-grid --page=<slug>: wraps a page's cards
  into vitec_cols_33_33_33 containers (b13 columns 221/222/223), three
  per container, section-aware - every top-level intro paragraph starts
  a section, other element types close it, so the category headings on
  /products keep their grids beneath them. Existing grid containers are
  pooled and reused, surplus ones hidden
- the first apply aborted mid-move and left a half state (15 empty
  shells, three cards moved; diagnosis migrations/check_grid_447.php,
  kept) - v2 repairs such states by design: global container pool,
  hard asserts after the create pass, try/catch around the move pass,
  and a final "no card left top-level" verification
- applied on /products and verified live: 38 cards in 15 grids
  (sections 5/7/3/6/2/4/2/6/3 -> 2/3/1/2/1/2/1/2/1 containers), order
  intro -> grids -> banner -> faq intact, children delivered in the
  known items/contentElements shape

Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
2026-10-27 15:10:24 +01:00
orascheandClaude Fable 5 c8d653b39b Card images: product photos plus numbered placeholders on the new cards
- new vitec:attach-card-images (dry-run by default) for the ~145
  vitec_card elements the 2026-10-27 workbook imports created across
  /products, /insights, /support and /contact: a card linking
  /product/<slug> gets the record's first product photo (hero banner
  as fallback), every other card gets the numbered placeholder
  placeholders/pages/<pid>-NN.png counted from slot 10 in card order
  per page (slots 01-04 and 08 are taken by the page conventions; the
  number doubles as the image wish list towards the agency). 110
  placeholder PNGs (640x480) were generated from the live payloads so
  the numbering is deterministic; cards that already carry an image are
  never touched but keep advancing the counter, so re-runs stay stable
- container children are included: the editor had arranged the /support
  cards into a grid container (colPos 221-223/251), which the first
  top-level-only query skipped
- applied and verified live: 42 product photos, 110 numbered
  placeholders, 18 generic grey cards - the grey ones map the records
  without any image at all (ArtioSign, ArtioView, Arqa, the Aetria
  family, Wall Control 10, X-Series; all Datapath software without an
  image delivery, queued for Joe)

Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
2026-10-27 14:26:15 +01:00