Zum Inhalt

Changelog

Changelog

All notable changes to this project will be documented in this file.

The format is based on Keep a Changelog and this project adheres to Semantic Versioning.

[1.4.0]

Changed

  • ext_emconf.php entfernt, Metadaten in die composer.json verlagert. TYPO3 14.3 verwirft ext_emconf.php und erwartet stattdessen extra."typo3/cms".version sowie extra."typo3/cms".Package.providesPackages. Ohne beides meldet der PackageManager eine Deprecation, sobald die Extension in einem TYPO3-14.3-Projekt installiert ist — was jede Testsuite mit failOnDeprecation rot macht. Die Version steht bewusst im extra-Block und nicht auf oberster Ebene, weil das Paket über Git-Tags ausgeliefert wird.

Added

  • Öffentliche API zum Ansteuern eines bestimmten Anbieters. Netthinks\NtAi\Provider\AiProviderLocatorInterface (@api, public: true) liefert über get('openai') einen Anbieter, der fest an diesen Bezeichner gebunden bleibt. Bisher löste die öffentliche Schnittstelle immer den konfigurierten Standardanbieter auf — richtig für den Normalfall, aber damit ließ sich keine Fallback-Kette bauen: Eine externe Extension, die erst OpenAI und bei Fehler Anthropic versuchen will, konnte den zweiten Anbieter nicht benennen und hätte auf die Interna (ProviderRegistry) zugreifen müssen. Zusätzlich liefert getAvailableProviders() die registrierten und konfigurierten Anbieter, sodass eine Kette unkonfigurierte Anbieter überspringen kann. Die zurückgegebenen Objekte implementieren dasselbe AiProviderInterface — aufrufender Code bleibt unverändert.

Changed

  • ProviderAdapter bildet Anfragen und Antworten nicht mehr selbst ab, sondern delegiert an den Locator. Verhalten unverändert: Der Standardanbieter wird weiterhin bei jedem Aufruf neu aufgelöst, damit Konfigurationsänderungen ohne Container-Neubau greifen.

Fixed

  • Entwicklerdokumentation nannte für eigene Anbieter das falsche Interface. docs/developer.de.md und docs/developer.en.md verwiesen auf das öffentliche Netthinks\NtAi\Provider\AiProviderInterface, zeigten aber die Methoden des internen Netthinks\NtAi\Service\Provider\AiProviderInterface und als Rückgabetyp AiResult statt AiResponse. Wer dem Beispiel folgte, bekam eine Klasse, die sich nicht als Anbieter taggen ließ. Die RST-Fassung war bereits korrekt.

[1.3.6]

Fixed

  • Barrierefreiheits-Fenster ragte auf flachen Bildschirmen oben heraus. Die Hoehe des Panels war mit min(80vh, 640px) an die Fensterhoehe gebunden, nicht an den Platz, der ueber dem Knopf tatsaechlich frei ist. Auf einem iPad im Querformat (695 px sichtbare Hoehe) standen Ueberschrift und Schliessen-Knopf ausserhalb des Bildes. Die Hoehe rechnet jetzt mit dem eingestellten Randabstand, der Knopfgroesse und etwas Luft; dvh beruecksichtigt zusaetzlich die ein- und ausfahrenden Leisten mobiler Browser. Gemessen bei 1024x695, 1024x600, 768x1024 und 390x664: das Panel bleibt vollstaendig im Bild.

[1.3.5]

Fixed

  • Score-Alarm-Mails schlugen unter TYPO3 v14 fehl: AlertService verschickte über MailMessage::send(). Diese Methode wurde in TYPO3 v14 entfernt — MailMessage erbt von Symfonys Email, und die kennt kein send(). Sobald ein Schwellenwert tatsächlich gerissen wäre, hätte der Versand mit einem Fatal Error abgebrochen. Der Versand läuft jetzt über MailerInterface; der Systemabsender wird dabei wie zuvor automatisch ergänzt.

[1.3.4]

Changed

  • A11y-/TTS-Init-Skript CSP-nonce-fähig ausliefern: Das Inline-Skript, das die data-nt-*-Konfiguration früh am <html>-Tag setzt (u. a. Dark-Mode vor dem ersten Paint), wird nicht mehr als roher <script> über page.headerData, sondern über page.jsInline (PageRenderer) ausgegeben. Dadurch erhält es bei aktiver Content-Security-Policy automatisch die Request-Nonce (script-src 'nonce-…') und wird nicht mehr blockiert. Es läuft weiterhin synchron im <head> (kein Dark-Mode-Flash). Voraussetzung, um im Sitepackage auf eine erzwingende Frontend-CSP umzustellen.

[1.3.3]

Fixed

  • Reiter „Erklärung" auch im Seitendetail sichtbar: Der Tab erschien bisher nur in der Site-Übersicht und in Lighthouse, nicht in der Seitendetail-Ansicht. Er wird jetzt (wie der Lighthouse-Tab) in allen Audit-Ansichten angezeigt.

[1.3.2]

Changed

  • Barrierefreiheitserklärung ohne interne Werkzeugnamen: Der Entwurf sprach von „automatisierter Prüfung durch nt-ai" — für Leser nichtssagend. Formuliert jetzt neutral („Selbstbewertung mittels automatisierter Prüfwerkzeuge für Barrierefreiheit sowie ergänzender manueller Kontrolle"); auch die Maßnahmen-Texte nennen keine Produktnamen (nt-ai/nt-lingua) mehr. Der Prompt weist die KI zusätzlich an, keine Softwareprodukte zu benennen.

[1.3.1]

Fixed

  • Lighthouse-Scheduler meldete weiterhin einen Fehler: Der Befehl gab FAILURE zurück, sobald EINE Seite scheiterte — ohne PSI-API-Key läuft ein Lauf über alle Seiten aber zwangsläufig in Googles Rate-Limit (429), sodass einzelne Seiten scheitern und der Scheduler den ganzen Task als fehlgeschlagen markierte. Ein Monitoring-Lauf gilt jetzt nur noch bei Totalausfall (keine einzige Seite erfolgreich) als Fehler; Teil-Fehler sind Warnungen. Zusätzlich ein Hinweis auf lighthouse.apiKey, wenn ohne Key Fehler auftreten.
  • Barrierefreiheitserklärung: Der Hinweis-Kasten im Modul lief über mehrere Spalten, weil der Flex-Container jedes Inline-Element (Icon, <strong>) als eigene Spalte anordnete. Der Text liegt jetzt in einem eigenen Block — der Hinweis fließt wieder normal einzeilig um das Icon.

[1.3.0]

Added

  • KI-Alt-Texte für PDF-Dokumente: PDFs können jetzt ebenfalls einen Alt-Text erhalten (relevant, wenn ein PDF als Vorschaubild mit Link zum Dokument eingebunden ist). Da ein PDF nicht an die Vision-KI geht, wird sein Textinhalt extrahiert (PdfTextExtractor) und per Text-KI zu einem prägnanten Alt-Text zusammengefasst.
  • Wirkt an derselben Schaltfläche „Alt-Text generieren" im Datei-Metadaten- Formular (erkennt PDF automatisch) sowie am generischen AJAX-Endpunkt.
  • Neuer CLI-Schalter nt_ai:generate-alt-texts --include-pdf (opt-in; ohne ihn bleibt es bei Bildern, damit bestehende Cron-Läufe unverändert bleiben).
  • Gescannte PDFs ohne Textebene werden mit klarer Meldung übersprungen.

Changed

  • Extension-Konfiguration übersichtlicher: Die sieben einzelnen Anbieter- Reiter (Anthropic, OpenAI, Gemini, DeepSeek, Mistral, Groq, Ollama) sind zu einem Reiter „KI-Anbieter" zusammengefasst (Labels mit Anbieter-Präfix), Rate-Limit unter „Allgemein", der Reiter „Barrierefreiheitserklärung" gekürzt zu „Erklärung" — 16 Reiter → 9, damit die Tab-Leiste ins Fenster passt. Nur Kategorien/Labels geändert, keine Schlüssel — bestehende Werte bleiben.

Fixed

  • Barrierefreiheitserklärung: „Leichte Sprache" wird nicht mehr pauschal als Maßnahme genannt. Die Vereinfachungssprache ist jetzt konfigurierbar (Standard: nur „Einfache Sprache"), sodass „Leichte Sprache" nur erscheint, wenn tatsächlich aktiviert. Mehrsprachigkeit (nt-lingua) wird weiterhin automatisch ergänzt.

[1.2.0]

Added

  • Barrierefreiheitserklärung-Generator (neuer Reiter „Erklärung" im Audit-Modul): erzeugt aus den vorhandenen Audit-Daten den Entwurf einer Erklärung zur Barrierefreiheit (nach BITV-Mustertext / BFSG § 14, EU 2016/2102) und veröffentlicht ihn nach redaktioneller Freigabe auf der Barrierefreiheits-Seite.
  • DeclarationDataService: aggregiert Konformitätsstatus, betroffene WCAG-Barrieren (identische Gruppierung wie der BFSG-Gesamtbericht), PDF-Ergebnisse, Maßnahmen (Konfig + automatisch erkanntes nt-lingua/nt-ai-Audit) und das Prüfdatum.
  • DeclarationGenerator: KI-Entwurf de/en, nur aus den übergebenen Fakten, fehlende Pflichtangaben als „[bitte ergänzen]".
  • DeclarationPublisher: Veröffentlichung per DataHandler (versioniert, zugriffsgeprüft). Beim ersten Mal wird das vorhandene Erklärungs-Element adoptiert und aktualisiert (kein Duplikat); der verwaltete Datensatz wird je Seite/Sprache in sys_registry gemerkt.
  • Neuer Extension-Settings-Tab „Barrierefreiheitserklärung" (declaration.*): Zielseite, Organisation, Feedback-Kontakt, Durchsetzungsstelle, Maßnahmen.
  • AJAX-Routen nt_ai_declaration_generate / nt_ai_declaration_publish.

[1.0.34]

Fixed

  • Lighthouse-Scheduler-Task schlug fehl („Task failed to execute successfully", Task-Typ nt_ai:lighthouse): Der Scheduler übergibt alle Optionen — eine nicht gesetzte Strategie kam als leerer String an und ging ungeprüft in den PSI-Request (strategy=""). Leere/ungültige Werte fallen jetzt auf den konfigurierten Standard (lighthouse.strategy) zurück.

[1.0.33]

Added

  • PDF-Barrierefreiheit Phase 3a: Dashboard-Widget für PDF-Ergebnisse und ein eigener Abschnitt „Dokumente" im BFSG-Gesamtbericht (BFSG deckt auch Dokumente ab).

[1.0.32]

Changed

  • Doku: PDF-Barrierefreiheit vollständig dokumentiert (Benutzerhandbuch + Konfiguration).

[1.0.31]

Fixed

  • Upload-Gate-Warnung verschwand nach 5 Sekunden. TYPO3 blendet Notifications ohne explizite Client-Dauer für alle Schweregrade außer error nach 5 s aus — und error-Severity ist keine Option, weil sie die Upload-Antwort auf hasErrors=true kippt und die gespeicherte Datei fälschlich als „fehlgeschlagen" markiert würde. Neues pdf-upload-notice.js wird über AfterBackendPageRenderEvent einmal in den Backend-Hauptrahmen geladen (dort rendern alle Notifications, egal aus welchem Modul-iframe) und setzt für die Gate-Meldungen die Dauer auf 0 — sie bleiben stehen, bis der Redakteur sie aktiv schließt. Nur aktiv, wenn das Gate eingeschaltet ist.

[1.0.30]

Changed

  • Upload-Gate: Standard-Schweregrad ist jetzt warning (pdf.uploadGateSeverity) — das Gate greift damit standardmäßig auch bei Warnungen (z. B. fehlender Dokumenttitel), nicht nur bei Fehlern.

[1.0.29]

Added

PDF-Barrierefreiheit Phase 2: Upload-Gate

  • Neuer PdfUploadGateListener (PSR-14): prüft PDFs beim Backend-Uploadpdf.uploadGate = off (Standard) / warn (Datei wird gespeichert, FlashMessage mit Befunden) / block (Upload wird mit Meldung inkl. konkreter Befunde abgelehnt; die Temp-Datei wird bereits in BeforeFileAddedEvent analysiert, es entsteht kein FAL-Eintrag). Schwellwert pdf.uploadGateSeverity (error/warning), pdf.uploadGateAdminBypass (Admins erhalten statt Blockade nur die Warnung). Frontend-Formular-Uploads sind ausgenommen.
  • Block-Meldung nutzt ResultException/ResultMessage — der einzige Weg, auf dem ExtendedFileUtility einen eigenen Meldungstext im Upload-Dialog rendert (eine RuntimeException wird zur generischen „Schreibrechte"-Meldung verschluckt).
  • Jeder Backend-PDF-Upload persistiert automatisch einen Bericht (triggered_by=upload) — das Modul bleibt ohne manuelle Läufe aktuell.

[1.0.28]

Fixed

  • PDF-Modul: „Befunde"/„Prüfen" luden das Backend verschachtelt im Content-Frame. Die Links waren relative ?detail=…-URLs ohne Modul-Route/Token — TYPO3 leitete auf das Backend-Root um. Alle Modul-Links werden jetzt über den Backend-Router (UriBuilder::buildUriFromRoute) erzeugt.
  • Deutsches Modul-Label: de.locallang_pdf_mod.xlf ergänzt — das Modul heißt im deutschen Backend jetzt „PDF-Barrierefreiheit" statt „PDF Accessibility".

[1.0.27]

Added

PDF-Barrierefreiheit (Phase 1: Bestandsprüfung)

  • Neues Subsystem Pdf/: PdfAnalyzer extrahiert in einem Parse-Durchlauf (smalot/pdfparser, reines PHP — läuft ohne Java/Binaries auch auf Shared Hosting) die barrierefreiheits-relevanten Fakten; 9 Regeln prüfen sie nach Matterhorn/PDF-UA: getaggtes PDF, gescannte Seiten ohne Textebene, Dokumentsprache, Dokumenttitel (+ DisplayDocTitle), Figure-Alternativtexte, Verschlüsselung, Schrifteinbettung, Lesezeichen, PDF/UA-Kennzeichnung. Wiederverwendet die Audit-DTOs (Finding/Severity/Report) → konsistente Scores und Schweregrade.
  • Backend-Modul „PDF Accessibility" (Medien): alle FAL-PDFs mit Ampel-Status/Score, Befundliste je Datei mit Handlungsempfehlung und WCAG-/PDF-UA-Referenz, Einzel- und Sammelprüfung („neue & geänderte").
  • CLI/Scheduler nt_ai:pdf-audit (--limit, --force, --fail-on=error|warning für CI). Neue Tabelle tx_ntai_pdf_report (ein Bericht je Datei, Upsert); unveränderte Dateien (gleicher SHA1) werden übersprungen — geplante Läufe sind praktisch kostenlos.
  • Geplant (Phase 2): Upload-Gate (warn/block analog Publishing Quality Gate); Phase 3: KI-Regeln, veraPDF-Anbindung, Dashboard-Widget, BFSG-Abschnitt.

[1.0.26]

Added

  • Seitenweite Tastatur-Guards (WCAG 2.4.1 / 2.4.7) in a11y-widget.css: Skip-Links mit .visually-hidden-focusable werden bei Tastaturfokus sichtbar eingeblendet (viele Themes liefern die auflösende :focus-Regel nicht — der Link blieb für sehende Tastaturnutzer 1×1 px unsichtbar), und ein :focus-visible-Sicherheitsnetz erzwingt eine sichtbare Fokus-Umrandung, auch wenn das Theme outline global unterdrückt (nur Tastatur; Maus-Fokus bleibt Theme-gestaltet). Beide Guards mit Dark-Mode-Variante.

[1.0.25]

Fixed

  • Barrierefreiheits-Widget und TTS-Player als translate="no" markiert. Die UI hat eigene i18n; DOM-Übersetzer (nt_lingua) sammelten und übersetzten ihre Labels bisher mit (erschienen z. B. als „Deficienza di colore" im Cache). Container tragen jetzt translate="no" / data-nt-notranslate.

[1.0.24]

Added

  • Nebenläufige Completions (ConcurrentAiProviderInterface). Neue optionale Public-Capability: completeMany() führt mehrere unabhängige Text-Completions gleichzeitig aus (curl_multi im AbstractHttpProvider, implementiert für den OpenAI-Provider). Konsumenten (z. B. nt_lingua) prüfen instanceof und fallen sonst auf sequentielle complete()-Aufrufe zurück. Beschleunigt große, in Chunks zerlegte Batches erheblich (N-fach-seriell → ~ein Roundtrip).

[1.0.23]

Added

  • Einstellung ntai.a11yWidget.scaleTarget (CSS-Selektor, Default #maincontent): legt fest, auf welches Element Schriftvergrößerung und Farbfilter wirken. So kann ein Kunden-Theme mit abweichendem Content-Wrapper das Ziel selbst setzen, ohne dass fixe Elemente (Sticky-Header, Zurück-nach-oben, Widget) mitskaliert/gefiltert werden.

Fixed

  • Farbschwäche-Filter wirkt jetzt. Der SVG-url()-Farbmatrix-Filter lag auf <html>, wo Blink/WebKit ihn stillschweigend ignorieren → keine sichtbare Wirkung (Kontrast/Sättigung als Funktions-Filter wirkten dagegen). Textgröße (Zoom) und Farbfilter werden nun per JS als Inline-Style auf ein konfigurierbares Content-Element gelegt (statt auf <html>).
  • Farbschwäche-Modi sind jetzt Korrektur statt Simulation. Die Matrizen (Rot-/Grün-/Blausehschwäche) daltonisieren — sie trennen verwechselbare Farben auf, statt die Sehschwäche nachzustellen; passend zum Einstellungstext.

[1.0.22]

Fixed

  • Barrierefreiheits-Overlay & TTS-Player im manuellen Dark-Mode dunkel. Die Widget-Chrome-Dark-Farben galten bisher nur bei OS-Dark (@media prefers-color-scheme: dark). Neuer html[data-nt-theme="dark"]-Block in a11y-widget.css spiegelt sie, sodass Overlay und Player auch bei per Widget aktiviertem Dark-Mode dunkel erscheinen (inkl. !important gegen die Hover-Härtung).
  • Kein weißes Aufblitzen beim Seitenwechsel im Dark-Mode. Das Inline-Config-Script des Sets liest jetzt localStorage.ntA11yPrefs vor dem ersten Paint und setzt data-nt-theme="dark" sofort — kein FOUC mehr.

[1.0.21]

Added

Wiederverwendbares Site Set netthinks/nt-ai

  • nt-ai bringt jetzt ein eigenes Site Set (Configuration/Sets/NtAiFrontend) mit: Settings-Definitionen (Kategorien Barrierefreiheit / Vorlesen, Präfix ntai.*), Asset-Includes (a11y-widget.js/.css, tts.js) und das Inline-Config-Script (data-nt-* am <html>). Kundensysteme binden nur noch eine Dependency netthinks/nt-ai in ihre Site-Konfiguration ein — kein manuelles Pflegen von settings.definitions.yaml mehr. Site-spezifisches Theming (Dark-Theme-Farben, Tweaks, Vorlesen-Button im Template) bleibt im jeweiligen Sitepackage.
  • Setting-Präfix von netthinks.* auf ntai.* migriert; TtsMiddleware liest entsprechend ntai.tts.*.

[1.0.20]

Added

Vorlesen: Player-Steuerung + Klicken-und-vorlesen

  • Player-Leiste erweitert: Zurück/Vor (Absatz-Navigation) sowie Regler für Lautstärke und Tempo (Cloud live über playbackRate/volume, Web Speech ab nächstem Absatz bzw. beim Loslassen). Ergänzt Pause/Stopp.
  • Klicken und vorlesen als Widget-Modus: aktivieren und einen Absatz anklicken, um ab dort vorzulesen (window.ntTts.setClickMode).

Fixed

  • Spul-Fix: Vor-/Zurückspulen las nicht mehr zwei Absätze parallel — der AbortError beim Abbrechen der Cloud-Wiedergabe löst keinen Web-Speech-Fallback mehr aus.

[1.0.19]

Added

  • TTS-Aussprache-Ersetzungen. Neue Site-Einstellung, um Begriffe vor der Sprachausgabe zu ersetzen (Format Begriff=Aussprache, mehrere durch |), z. B. TYPO3=Typo drei. Nur die Sprachausgabe ändert sich, der sichtbare Seitentext bleibt.

[1.0.18]

Added

  • „Vorlesen"-Icon in der Navbar (neben der Sprachwahl) als frei platzierbarer Auslöser der Vorlesefunktion.

Fixed

  • Widget-Härtung gegen Theme-Bleed: generische button:hover/a:hover-Regeln des Themes (weiße Schrift, ::after-Effekte, Letter-Spacing) machten Icon/Optionen bei Hover unlesbar und verursachten Zeilensprünge. Farben/Metrik jetzt per !important erzwungen (Hover = dunkel, nie weiß), dekorative Pseudo-Elemente neutralisiert.

[1.0.17]

Added

Barrierefreiheits-Widget (Frontend, Stufe 1)

  • Neues Frontend-Personalisierungs-Widget (bewusst kein Accessibility-Overlay): Textgröße, Textabstand (WCAG 1.4.12), Kontrast, Dunkelmodus, Animationen reduzieren, Links hervorheben, leichter lesbare Schrift, Lesehilfe (Lineal), Bilder ausblenden. Einstellungen lokal in localStorage, kein Tracking.
  • Kein DOM-/ARIA-Rewriting: die Präferenzen wirken über data-nt-*-Attribute auf <html> und reine CSS-Feature-Layer. Das Widget selbst ist voll tastatur-/ AT-bedienbar (aria-expanded/aria-pressed, Esc, Fokus-Rückgabe, keine Fokusfalle) und respektiert Systemeinstellungen (prefers-reduced-motion/-contrast/-color-scheme).
  • Buildfreie Auslieferung: a11y-widget.css + a11y-widget.js (klassisches Script). Enthält zusätzlich einen seitenweiten prefers-reduced-motion-Schutz für die Theme-Scroll-Animationen (.animate-box) und Fokus-Sichtbarkeit im Windows-Kontrastmodus (forced-colors).
  • Backend-konfigurierbar über die Site-Einstellungen (Barrierefreiheit): Widget an/aus, Position (4 Ecken), Beschriftung an/aus. Standard: dezentes Symbol unten rechts (überdeckt den Cookie-Button nicht). Config erreicht das Frontend als data-nt-a11y-*-Attribute am <html>-Tag (Inline-Script im <head>; das Sitepackage-Set liefert Assets + Attribute).
  • Schriftgrößen-Skalierung robuster über !important-CSS-Regel per data-nt-fontscale (statt Inline-Style), Index-Logik korrigiert (Stufe 0 = neutral).
  • Widget-Chrome dezenter (Icon-Launcher, Text optional) und in px/em statt rem, damit es von der Schriftskalierung nicht selbst mitwächst.
  • Symbolgröße und Rand-Abstände (horizontal/vertikal) über die Site-Einstellungen konfigurierbar (--nt-a11y-size/-offset-x/-offset-y).
  • Nativer Dunkelmodus statt Invert-Filter: der Widget-Dunkelmodus schaltet jetzt html[data-nt-theme="dark"] und damit ein echtes dunkles Theme (nt-dark-theme.css im Sitepackage; Markenorange bleibt Akzent). Erste Fassung — Feintuning einzelner Sektionen folgt.
  • prefers-contrast: more wird jetzt seitenweit berücksichtigt (Links unterstrichen, stärkere Fokus-/Rahmen-Darstellung); forced-colors-Support erweitert.
  • Schriftgröße via Page-Zoom statt Root-font-size (das Theme sizt px-basiert, daher war die Skalierung wirkungslos) — zoom auf <body>, reflow-freundlich.
  • Positions-Einstellung als Dropdown (Site-Settings enum + labels.xlf/de.labels.xlf mit deutschen Labels) statt Freitext.
  • Zoom wirkt jetzt auf #maincontent statt <body> — sonst wurden fixe Elemente (Launcher, Back-to-top) verschoben und Hero-Überschriften (Startseite/Unterseiten) mitvergrößert.
  • Launcher sitzt über der Bottom-Ecke frei (Abstand zu Back-to-top/Cookie-Badge).
  • „Bilder ausblenden" lässt Logo, Navigation, Hero und Footer unangetastet.
  • „Alles zurücksetzen" zusätzlich als Symbol (↺) oben im Panel neben dem Schließen-X.
  • Erklär-Tooltip am Launcher (Hover/Fokus) mit Kurzbeschreibung + Shortcut-Hinweis — wichtig, wenn nur das Symbol (ohne Beschriftung) angezeigt wird.
  • Einmaliger Erst-Besuch-Hinweis: der Tooltip erscheint beim ersten Besuch automatisch und wird gemerkt (localStorage), auf Folgeseiten nicht mehr.
  • Tastatur-Shortcut Alt + 1 öffnet/schließt das Panel; alle Merkmale sind per Tastatur bedienbar (echte Buttons, Fokus wandert ins Panel, Esc schließt mit Fokus-Rückgabe).
  • Neue Funktionen (EyeAble-Parität): Blaulichtfilter (warmer Overlay, Intensitäts-Regler), Farbschwäche-Filter (Rot-/Grün-/Blausehschwäche via SVG-Farbmatrix), Farbsättigung/ Graustufen (Regler), Größerer Mauszeiger, Ton stummschalten (inkl. später geladener Medien), Fokus-Hervorhebung. Kontrast erhält einen Intensitäts-Regler. Filter (Kontrast/Sättigung/Farbschwäche) werden als eine --nt-filter-Kette auf <html> komponiert; Blaulicht als separater Overlay.
  • Erklärtext je Menüpunkt: beim Hover/Fokus erscheint eine Kurzbeschreibung seitlich am Panel.

Vorlesefunktion (Text-to-Speech) — ReadSpeaker-Ersatz

  • Selbstgehostete Vorlesefunktion, hybrid und admin-umschaltbar: Web Speech API (browsereigene Stimmen, kostenlos, lokal) oder Cloud-TTS (Premium-Stimmen, aktuell OpenAI). Liest #maincontent blockweise mit Hervorhebung des gesprochenen Absatzes, Player-Leiste (Pause/Stopp), vollständig tastaturbedienbar.
  • Nutzbar im Widget („Webseite vorlesen") und frei im Template platzierbar über [data-nt-tts]-Buttons bzw. das Fluid-Partial ReadAloud (z. B. neben dem Klickpfad).
  • Cloud-Audio wird serverseitig gecacht (TtsService + ntai_tts-Cache), Key bleibt am Server; Client fällt bei Cloud-Fehlern automatisch auf Web Speech zurück. FE-Endpoint /nt-ai/tts via TtsMiddleware. Config: Site-Settings (Engine/Rate/Scope) + nt-ai-Ext-Config (Cloud-Provider/Voice/Model).
  • Fix: Pause im Player war unzuverlässig (speechSynthesis.pause() browserabhängig) → jetzt Cancel + Neustart des aktuellen Absatzes bei „Weiter", mit Guard gegen Race.
  • Fix: ovale Pause/Stopp-Buttons (Theme-button-Styles) gehärtet.
  • Cloud-TTS im Token-/Kosten-Dashboard: jede echte Cloud-Generierung (Cache-Miss) wird erfasst (TokenUsageService::trackTts, Kontext „tts", Zeichenzahl im input-Feld). Preistabelle um TTS ergänzt (USD pro 1M Zeichen: tts-1 15, tts-1-hd 30, gpt-4o-mini-tts 12). Das Widget „Token-Verbrauch" zeigt die Zeile „Vorlesen (TTS, Zeichen)" samt geschätzter Kosten; Cache-Treffer kosten nichts.
  • Cloud-TTS-Endpoint abgesichert: antwortet nur bei Site-Engine cloud, weist Cross-Site-Anfragen ab (Sec-Fetch-Site), Rate-Limit pro IP (tts.rateLimit, Standard 30/Min., HTTP 429 mit Retry-After), X-Robots-Tag: noindex. Cache-Treffer zählen nicht zum Limit.
  • Doku umfassend nachgezogen: alle Widget-Funktionen (Blaulicht/Farbschwäche/Sättigung/ Cursor/Ton/Fokus, Regler, Erklärtexte), Symbol-Auswahl, Vorlesefunktion inkl. Schutz & Kosten (user-guide + configuration, de/en).

Launcher-Symbol wählbar

  • Acht als Vektor nachgebaute Barrierefreiheits-Symbole (Person im Doppelkreis, Person im Kreis, Person mit Armen, Person auf Linie, Person im gefüllten Kreis, Rollstuhl, aktiver Rollstuhl, Hand mit Person) — in den Site-Einstellungen wählbar (data-nt-a11y-icon), alle einfarbig (currentColor).

[1.0.16]

Added

Lighthouse im Seitenlayout

  • Das KI-Assistent-Panel im Seitenlayout-Modul zeigt eine neue Spalte „Lighthouse" mit den vier Messringen der zuletzt gespeicherten Messung der Seite (read-only, Link ins Modul). Neuer Endpoint LighthouseAjaxController::latestAction (Route nt_ai_lighthouse_latest).

Changed

  • Seiten-Score-Tipps in Backend-Sprache. Die Verbesserungsvorschläge des KI-Inhaltsqualitäts-Scores werden nun in der UI-Sprache des Backend-Nutzers erzeugt statt in der Sprache der geprüften Seite (ein deutsches Backend liefert auch bei englischen Seiten deutsche Tipps). PageScoreService::analyzePage() erhält einen optionalen suggestionLanguageCode; ScoreAnalysisAjaxController übergibt die Backend-Sprache.

[1.0.15]

Added

  • Gesamtbericht (seitenübergreifend): neuer druckbarer BFSG-Bericht über alle auditierten Seiten — aggregiertes Konformitäts-Verdict, Kennzahlen inkl. Durchschnitts-Score, Seitenübersicht (schlechteste zuerst) und häufigste WCAG-Barrieren mit Vorkommen + betroffenen Seiten. Button „Gesamtbericht (BFSG)" in der Site-Übersicht (BfsgReporter::renderOverview, Route nt_ai_audit_report_overview); berücksichtigt nur zugängliche Seiten.

[1.0.14]

Added

  • Druckoptimierte CSS für beide BFSG-Berichte: print-color-adjust: exact erhält die Schweregrad-/Verdict-Farben im PDF, Screenshot und Snippets werden begrenzt, saubere Seitenumbrüche. Eigener CSP-Header, damit der „Drucken"-Button trotz Backend-CSP funktioniert.

[1.0.13]

Fixed

  • BFSG-Bericht: Befunde erschienen ohne Text. Der Reporter iterierte die Top-Level-Keys der findings-Spalte statt der eigentlichen Befundliste unter dem findings-Key (die Spalte speichert Report::toArray()). Jetzt werden Meldung, Schweregrad, WCAG-Gruppe, Empfehlung und Snippet korrekt angezeigt.
  • BFSG-Bericht: „Drucken / als PDF speichern" ohne Funktion. Die Backend-CSP blockierte das Inline-Script; die Report-Antwort setzt jetzt einen eigenen CSP-Header (den die CSP-Middleware respektiert).
  • Bericht-Button zeigte ein gebrochenes Icon (actions-file-report existiert nicht) → actions-file-pdf.

[1.0.12]

Added

BFSG-Report & Screenshots

  • Neuer druckbarer Barrierefreiheits-Bericht (BFSG / EN 301 549 / WCAG 2.2): Befunde nach WCAG-Kriterium gruppiert, Konformitäts-Aussage, Score + Lighthouse-A11y, Screenshot-Beleg und Disclaimer. Button „Bericht (BFSG)" im Audit-Modul (BfsgReporter, Route nt_ai_audit_report), als eigenständiges HTML zum Drucken/als-PDF-Speichern.
  • Lighthouse: der von PageSpeed Insights gerenderte Screenshot (fullPageScreenshot, sonst final-screenshot) wird jetzt gespeichert (neue Spalte tx_ntai_lighthouse_report.screenshot) und als visueller Beleg im Bericht angezeigt.

[1.0.11]

Added

Publishing Quality Gate

  • New QualityGateHook (DataHandler processDatamapClass): warns about or blocks publishing a page while its last accessibility audit still has findings at or above the configured severity. block mode vetoes hidden=0 in the pre-hook and forces the page to stay unpublished; warn mode shows a flash message after save.
  • Extension configuration (Audit tab): audit.qualityGate (off/warn/block), audit.qualityGateSeverity (error/warning), audit.qualityGateScope (onPublish/onSave), audit.qualityGateAdminBypass. Uses the latest stored report — keep audit.autoOnSave on so it stays current (fix → save → re-audit → publish passes).
  • nt_ai:audit --fail-on=error|warning — non-zero exit code for CI/CD quality gates.

Audit not-yet-published pages (preview fetch)

  • The audit can now render and check pages that are not publicly reachable yet — future start date, hidden, or expired — so issues are caught before go-live (which is the whole point of the quality gate). PageFetcher appends a short-lived, HMAC-signed preview token (AuditPreviewToken); a new frontend middleware (AuditPreviewMiddleware) verifies it and relaxes time/visibility for that single render only. Signed with the site encryption key, so only this installation can mint a valid token; the preview render is not cached.
  • Module audits and on-save audits use it automatically; CLI: nt_ai:audit --preview.
  • The audit module now reports the real reason when a page can't be reached (e.g. "not published yet / hidden") instead of a generic "Audit fehlgeschlagen".

[1.0.2] - 2026-07-09

Changed

  • SEO-KI: Sprachanweisung im Prompt verstärkt — konsistentere Zielsprache bei generierten SEO-Feldern.

[1.0.1] - 2026-07-09

Added

SEO editing

  • SEO field assistant in the SEO panel of the Page Layout module. Generate → preview → apply buttons for the SEO title, meta description and focus keyphrase, each derived from the rendered page content and saved to the matching pages column via DataHandler.
  • Inline "KI" buttons in page properties on pages.seo_title, pages.description and pages.tx_ntai_focus_keyphrase (in addition to the page teaser). AiTextElement now renders both single-line inputs and textareas; supported fields and prompts live in the shared PageAiFieldProvider.
  • Inline image-description button on sys_file_metadata.description (vision-based caption, complementary to the alt-text button).
  • Inline teaser button on pages.abstract that generates a teaser from the rendered page content.

[1.0.0] - 2026-07-09

Erster öffentlicher Git-Release (Composer). Bündelt die zuvor intern entwickelten Funktionen (siehe interne Historie unten) plus die folgenden neuen Subsysteme.

Added

Score history and sparkline

  • tx_ntai_page_score is now append-only (added tstamp column, removed delete from PageScoreRepository::save()). Every analysis run creates a new row so historical data is preserved.
  • PageScoreRepository::getScoreHistory(pageUid, languageUid, limit) — returns the last N runs in chronological order with crdate and scores per run.
  • PageScoreRepository::getAverageScores() and getScoreDistribution() fixed to consider only the latest row per (pid, sys_language_uid) pair (PHP deduplication on uid DESC); with multiple history rows per page the averages were otherwise counted multiple times.
  • PageScoreRepository::countAnalyzedPages() now counts distinct (pid, sys_language_uid) combinations via GROUP BY instead of total rows.
  • ScoreAnalysisAjaxController::latestAction() returns a history array (last 8 runs).
  • inline-audit.jsrenderScorePanel() shows a row of coloured sparkline dots (green/amber/red by average score) when ≥ 2 historical runs are available.

Lighthouse monitoring (Google PageSpeed Insights)

  • New DB table tx_ntai_lighthouse_report — stores Lighthouse category scores (Performance, Accessibility, Best Practices, SEO, 0–100) and Core Web Vitals (LCP, CLS × 1 000, INP, FCP, TTFB) per page + language + strategy (mobile/desktop).
  • New Lighthouse/LighthouseService — calls the PSI v5 API, parses the JSON response, saves to LighthouseRepository. Requires the analysed URL to be publicly reachable.
  • New Lighthouse/LighthouseRepository — save, findLatest, findHistory, getAverageScores, countAnalyzedPages, findAllLatest.
  • CLI command nt_ai:lighthouse [pageId] [recursion] [--strategy=mobile|desktop|both] — schedulable, mirrors nt_ai:analyze-pages in structure.
  • New Dashboard/Widget/LighthouseWidget — four gauge rings (Performance, Accessibility, Best Practices, SEO) showing averages across analysed pages; shows strategy label and page count.
  • New extension settings tab Lighthouse: lighthouse.apiKey, lighthouse.strategy.
  • Dashboard widget nt_ai_lighthouse (large, dashboard.widget.nt_ai_lighthouse).
  • ConfigurationService::getLighthouseApiKey(), getLighthouseStrategy().

Email alerts (score threshold monitoring)

  • New Service/AlertService — compares latest AI content scores and latest Lighthouse scores against configurable thresholds; sends one summary HTML email per run listing all violating pages. No per-page spam; one mail covers all violations.
  • CLI command nt_ai:alert-check — schedulable; designed to run daily after the nightly nt_ai:analyze-pages and nt_ai:lighthouse runs.
  • New extension settings tab Alerting: alerting.enabled, alerting.recipient (comma- separated), alerting.thresholdGeo/Performance/Semantics/Keywords/Accessibility for AI scores and alerting.thresholdLighthousePerformance/Accessibility/BestPractices/Seo for Lighthouse. Zero = disabled for that category.
  • ConfigurationService::isAlertingEnabled(), getAlertRecipients(), getScoreThresholds(), getLighthouseThresholds().

AI Content Quality Scoring (Seiten-Score)

  • New subsystem Score/ with PageScoreService, PageScoreRepository, ScoreRange enum.
  • DB table tx_ntai_page_score — append-only history (see Score history above). Stores JSON scores for five categories and JSON suggestions list.
  • Five score categories analysed per page via LLM (rendered HTML as input): geo (GEO/SEO), performance (page structure), semantics (HTML5/ARIA), keywords (focus keyword density), accessibility (WCAG signals). Scale: 0–100 each.
  • Focus keyword read from pages.tx_ntai_focus_keyphrase — the existing SEO field is re-used so no extra editor input is required.
  • Score thresholds: High ≥ 75 (green), Medium ≥ 50 (amber), Low < 50 (red).
  • Suggestions are LLM-written, language-aware (language of the analysed page), max 120 chars each, max 2 per category, only when score < 80.
  • AJAX routes nt_ai_score_analyze (POST) and nt_ai_score_latest (GET) for the inline panel.
  • CLI command nt_ai:analyze-pages [pageId] [recursion] — bulk analysis, supports all configured site languages per page; registered as schedulable Scheduler command.

Page Layout module — Seiten-Score panel (3rd inline column)

  • PageLayoutAuditListener now renders a third column "Seiten-Score" beside the Barrierefreiheits-Audit and SEO panels.
  • Displays five SVG gauge rings (52×52 px, colour-coded) with the scores and the improvement suggestions list below.
  • "Neu analysieren" button triggers analysis on demand and refreshes the panel.
  • Language resolved from the module URL (?languages[0]=…) for correct per-language results when editors switch language view.

Dashboard — Score widgets

  • Five DoughnutChartWidget instances (one per category): display the average score across all analysed pages as a gauge ring — e.g. 85 / 100 filled 85 % in the category colour. Legend hidden; score is shown in the chart label.
  • New PageScoreOverviewWidget (large widget): renders five mini rings with their average scores plus the total count of analysed pages, all in one widget.
  • PageScoreRepository::getAverageScores() and countAnalyzedPages() power both.

Token usage — Cost estimation

  • New Configuration/ModelPricing.php — built-in USD price table for 35+ models across all supported providers (OpenAI, Anthropic, Gemini, DeepSeek, Mistral, Groq). Keys are model-name prefixes; longest prefix wins, so versioned names like gpt-4o-mini-2024-07-18 resolve correctly.
  • New CostEstimationService — calculates (input_tokens / 1M × input_price) + (output_tokens / 1M × output_price) in USD; converts to EUR on request; formats as ~$0.19 or ~0,18 €.
  • Three new extension settings:
  • tokenTracking.currencyUSD or EUR (default: USD).
  • tokenTracking.eurRate — conversion rate (default: 0.92).
  • tokenTracking.customPricing — JSON object to override or extend the built-in price table (e.g. private/fine-tuned models).
  • TokenUsageWidget shows a blue "ca. Kosten" box below the token total. When a model is not in the pricing table a warning with the model name is shown.
  • TokenUsagePerUserWidget gains a "ca. Kosten" column (per-user × per-model aggregation with separate input/output token queries).

New AI providers (4 added)

  • Google GeminiGeminiProvider (gemini-2.0-flash default). Vision supported.
  • DeepSeekDeepSeekProvider (deepseek-chat default). No vision.
  • Mistral AIMistralProvider (mistral-small-latest default). Vision on pixtral-large-latest.
  • GroqGroqProvider (llama-3.3-70b-versatile default). No vision.

All four providers are configurable via separate Extension Configuration tabs.

New audit rules (15 added since v1.1.0)

Deterministic rules:

Rule WCAG Severity
IframeTitleRule 4.1.2 Error
ButtonTextRule 2.4.4 Warning
DuplicateIdRule 4.1.1 Error
DocumentLandmarkRule 1.3.1 / 2.4.1 Warning
TableHeaderRule 1.3.1 Warning
FocusOutlineRule 2.4.7 Warning
AriaHiddenFocusRule 4.1.2 Error
VideoCaptionsRule 1.2.2 Error
MetaRefreshRule 2.2.1 Error
ReadabilitySentenceLengthRule 3.1.5 AAA Notice
ReadabilityParagraphLengthRule 3.1.5 AAA Notice
ReadabilitySubheadingRule 3.1.5 AAA Notice
SeoTitleLengthRule 2.4.2 (SEO) Warning
SeoMetaDescriptionLengthRule SEO Warning
SeoKeyphraseRule SEO Error/Warning/Notice

AI-powered rules:

Rule What AI checks
AiAltTextQualityRule Quality of existing alt texts (generic, filename-based, nonsensical) — up to 20 images
AiHeadingQualityRule Descriptiveness of headings — up to 15 headings
AiMetaDescriptionRule Accuracy and clickability of meta description

Total: 26 audit rules (9 deterministic + 3 AI in v1.1.0 → 23 deterministic + 5 AI now counted as two batches; 3 AI rules in this release).

Fixed

  • Upload error message suppressed correctly. GenerateAltTextOnUploadListener wrapped only the AI call (generateSafe) but left DB operations (language overlay insert/update) and getForLocalProcessing() uncovered. Any exception from these paths surfaced as "Upload fehlgeschlagen" in the backend even though the file was stored successfully. The entire processing logic is now wrapped in a top-level try/catch in __invoke(); errors are logged and the upload always completes.
  • Dashboard score widgets showed ~100% for one colour. ScoreDistributionDataProvider returned page-count distributions (how many pages fall into each quality tier). With only a few analysed pages all falling in one tier, the ring appeared 100 % one colour. Changed to return the average score as a gaugedata = [avgScore, 100 − avgScore] with colour matching the score value.

Removed

  • "AI Tools" backend module (web_ntai) and its playground UI. The AI services are now integrated directly into the editing forms and the SEO panel where they are actually used. The generic nt_ai_generate and nt_ai_summarize AJAX endpoints remain as the shared backend API; the unused nt_ai_translate endpoint was removed.

Interne Vor-Release-Historie (Mai 2026, Schema 1.0.01.2.0) — vor dem öffentlichen Git-Release v1.0.0 (Juli 2026), das den obigen Funktionsumfang gebündelt ausgeliefert hat. Zur Nachvollziehbarkeit erhalten.

[1.2.0] - 2026-05-24 (intern)

Added

  • TYPO3 v14 LTS compatibility. Tested against TYPO3 v14.0 (released April 2026). CI matrix now covers v12.4, v13.4 and v14.0 against PHP 8.1-8.4.

Changed

  • Backend module parent auto-detected. In v14, the toplevel module web was renamed to content (Core feature #107628). The extension detects the running TYPO3 major version and picks the correct parent automatically — no manual change required when upgrading.
  • Composer constraints widened: typo3/cms-core: ^14.0, phpunit/phpunit: ^11.0 || ^12.0, typo3/testing-framework: ^10.0.

Fixed

  • Auto-audit-on-save now actually triggers on regular saves. Previously the listener was bound to AfterRecordPublishedEvent, which only fires when records are published from a workspace. The feature never worked in workspace-less installations. The listener now uses AfterDatabaseOperationsEvent with status filtering, so it fires on every backend page save. It also resolves NEW... placeholder UIDs via DataHandler::substNEWwithIDs so newly created pages get audited correctly.

[1.1.0] - 2026-05-24 (intern)

Added

  • Accessibility audit module. New backend module "Web -> Accessibility Audit" with score (0-100), severity-grouped findings, WCAG references, AI-generated fix suggestions, CSV export, and history.
  • 9 built-in WCAG rules: image alt, heading hierarchy, link text, lang attribute, form labels, page title, inline contrast, AI link suggestions, AI readability check.
  • Three audit triggers: manual button, auto-on-save event listener (with cooldown), nt_ai:audit CLI command (CI-friendly via --min-score).
  • Configurable alt-text generation: style (concise/descriptive/detailed), max length, tone, brand context, custom multi-line instructions, "no image-of prefix" enforcement, detected-text transcription toggle.
  • Per-call alt-text overrides via $optionOverrides argument on AiService::generateAltText().
  • Defensive post-processing strips quote-wrapping, "Image of"/"Bild von" prefixes, and enforces the length cap on AI output.
  • TYPO3-standard documentation in Documentation/ (reST/Sphinx) with introduction, installation, configuration reference, user manual, developer guide, known problems, changelog.

Changed

  • AiService::generateAltText() now accepts a fourth argument $optionOverrides (BC-compatible default []).
  • README rewritten for the expanded feature set.

Tests

  • 56 unit tests, 144 assertions, all green.
  • New tests for AltTextOptions, ContrastCalculator, ImageAltRule, LinkTextRule, Report.

[1.0.0] - 2026-05-23 (intern)

Added

  • Initial release.
  • AI providers: Anthropic Claude, OpenAI, Ollama.
  • High-level AiService API with generate, translate, summarize, generateAltText, describeImage.
  • Backend module "AI Tools" with playground UI.
  • AJAX endpoints for backend JavaScript integration.
  • CLI command nt_ai:generate-alt-texts for batch alt-text generation.
  • TYPO3 12.4 and 13.4 compatibility.
  • Unit tests for ConfigurationService, PromptBuilder, ProviderRegistry.
  • GitHub Actions CI for PHP 8.1-8.4 across TYPO3 12/13.
  • GPL-2.0-or-later.