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.phpentfernt, Metadaten in diecomposer.jsonverlagert. TYPO3 14.3 verwirftext_emconf.phpund erwartet stattdessenextra."typo3/cms".versionsowieextra."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 mitfailOnDeprecationrot macht. Die Version steht bewusst imextra-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 überget('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 liefertgetAvailableProviders()die registrierten und konfigurierten Anbieter, sodass eine Kette unkonfigurierte Anbieter überspringen kann. Die zurückgegebenen Objekte implementieren dasselbeAiProviderInterface— aufrufender Code bleibt unverändert.
Changed¶
ProviderAdapterbildet 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.mdunddocs/developer.en.mdverwiesen auf das öffentlicheNetthinks\NtAi\Provider\AiProviderInterface, zeigten aber die Methoden des internenNetthinks\NtAi\Service\Provider\AiProviderInterfaceund als RückgabetypAiResultstattAiResponse. 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;dvhberuecksichtigt 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:
AlertServiceverschickte überMailMessage::send(). Diese Methode wurde in TYPO3 v14 entfernt —MailMessageerbt von SymfonysEmail, und die kennt keinsend(). Sobald ein Schwellenwert tatsächlich gerissen wäre, hätte der Versand mit einem Fatal Error abgebrochen. Der Versand läuft jetzt überMailerInterface; 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>überpage.headerData, sondern überpage.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
FAILUREzurü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 auflighthouse.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-Limitunter „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 insys_registrygemerkt.- 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
errornach 5 s aus — underror-Severity ist keine Option, weil sie die Upload-Antwort aufhasErrors=truekippt und die gespeicherte Datei fälschlich als „fehlgeschlagen" markiert würde. Neuespdf-upload-notice.jswird überAfterBackendPageRenderEventeinmal 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-Upload —pdf.uploadGate=off(Standard) /warn(Datei wird gespeichert, FlashMessage mit Befunden) /block(Upload wird mit Meldung inkl. konkreter Befunde abgelehnt; die Temp-Datei wird bereits inBeforeFileAddedEventanalysiert, es entsteht kein FAL-Eintrag). Schwellwertpdf.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 demExtendedFileUtilityeinen 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.xlfergä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/:PdfAnalyzerextrahiert 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|warningfür CI). Neue Tabelletx_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-focusablewerden 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 Themeoutlineglobal 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 jetzttranslate="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 imAbstractHttpProvider, implementiert für den OpenAI-Provider). Konsumenten (z. B. nt_lingua) prüfeninstanceofund fallen sonst auf sequentiellecomplete()-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). Neuerhtml[data-nt-theme="dark"]-Block ina11y-widget.cssspiegelt sie, sodass Overlay und Player auch bei per Widget aktiviertem Dark-Mode dunkel erscheinen (inkl.!importantgegen die Hover-Härtung). - Kein weißes Aufblitzen beim Seitenwechsel im Dark-Mode. Das Inline-Config-Script
des Sets liest jetzt
localStorage.ntA11yPrefsvor dem ersten Paint und setztdata-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äfixntai.*), Asset-Includes (a11y-widget.js/.css,tts.js) und das Inline-Config-Script (data-nt-*am<html>). Kundensysteme binden nur noch eine Dependencynetthinks/nt-aiin ihre Site-Konfiguration ein — kein manuelles Pflegen vonsettings.definitions.yamlmehr. Site-spezifisches Theming (Dark-Theme-Farben, Tweaks, Vorlesen-Button im Template) bleibt im jeweiligen Sitepackage. - Setting-Präfix von
netthinks.*aufntai.*migriert;TtsMiddlewareliest entsprechendntai.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
AbortErrorbeim 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!importanterzwungen (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 seitenweitenprefers-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 perdata-nt-fontscale(statt Inline-Style), Index-Logik korrigiert (Stufe 0 = neutral). - Widget-Chrome dezenter (Icon-Launcher, Text optional) und in
px/emstattrem, 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.cssim Sitepackage; Markenorange bleibt Akzent). Erste Fassung — Feintuning einzelner Sektionen folgt. prefers-contrast: morewird 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) —zoomauf<body>, reflow-freundlich. - Positions-Einstellung als Dropdown (Site-Settings
enum+labels.xlf/de.labels.xlfmit deutschen Labels) statt Freitext. - Zoom wirkt jetzt auf
#maincontentstatt<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,
Escschließ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
#maincontentblockweise 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-PartialReadAloud(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/ttsviaTtsMiddleware. 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-115,tts-1-hd30,gpt-4o-mini-tts12). 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 mitRetry-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(Routent_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 optionalensuggestionLanguageCode;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, Routent_ai_audit_report_overview); berücksichtigt nur zugängliche Seiten.
[1.0.14]¶
Added¶
- Druckoptimierte CSS für beide BFSG-Berichte:
print-color-adjust: exacterhä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 demfindings-Key (die Spalte speichertReport::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-reportexistiert 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, Routent_ai_audit_report), als eigenständiges HTML zum Drucken/als-PDF-Speichern. - Lighthouse: der von PageSpeed Insights gerenderte Screenshot
(
fullPageScreenshot, sonstfinal-screenshot) wird jetzt gespeichert (neue Spaltetx_ntai_lighthouse_report.screenshot) und als visueller Beleg im Bericht angezeigt.
[1.0.11]¶
Added¶
Publishing Quality Gate
- New
QualityGateHook(DataHandlerprocessDatamapClass): warns about or blocks publishing a page while its last accessibility audit still has findings at or above the configured severity.blockmode vetoeshidden=0in the pre-hook and forces the page to stay unpublished;warnmode 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 — keepaudit.autoOnSaveon 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).
PageFetcherappends 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
pagescolumn via DataHandler. - Inline "KI" buttons in page properties on
pages.seo_title,pages.descriptionandpages.tx_ntai_focus_keyphrase(in addition to the page teaser).AiTextElementnow renders both single-line inputs and textareas; supported fields and prompts live in the sharedPageAiFieldProvider. - Inline image-description button on
sys_file_metadata.description(vision-based caption, complementary to the alt-text button). - Inline teaser button on
pages.abstractthat 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_scoreis now append-only (addedtstampcolumn, removeddeletefromPageScoreRepository::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 withcrdateandscoresper run.PageScoreRepository::getAverageScores()andgetScoreDistribution()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 viaGROUP BYinstead of total rows.ScoreAnalysisAjaxController::latestAction()returns ahistoryarray (last 8 runs).inline-audit.js—renderScorePanel()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 toLighthouseRepository. 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, mirrorsnt_ai:analyze-pagesin 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 nightlynt_ai:analyze-pagesandnt_ai:lighthouseruns. - New extension settings tab Alerting:
alerting.enabled,alerting.recipient(comma- separated),alerting.thresholdGeo/Performance/Semantics/Keywords/Accessibilityfor AI scores andalerting.thresholdLighthousePerformance/Accessibility/BestPractices/Seofor Lighthouse. Zero = disabled for that category. ConfigurationService::isAlertingEnabled(),getAlertRecipients(),getScoreThresholds(),getLighthouseThresholds().
AI Content Quality Scoring (Seiten-Score)
- New subsystem
Score/withPageScoreService,PageScoreRepository,ScoreRangeenum. - 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) andnt_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)
PageLayoutAuditListenernow 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
DoughnutChartWidgetinstances (one per category): display the average score across all analysed pages as a gauge ring — e.g.85 / 100filled 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()andcountAnalyzedPages()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 likegpt-4o-mini-2024-07-18resolve correctly. - New
CostEstimationService— calculates(input_tokens / 1M × input_price) + (output_tokens / 1M × output_price)in USD; converts to EUR on request; formats as~$0.19or~0,18 €. - Three new extension settings:
tokenTracking.currency—USDorEUR(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).TokenUsageWidgetshows 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.TokenUsagePerUserWidgetgains a "ca. Kosten" column (per-user × per-model aggregation with separate input/output token queries).
New AI providers (4 added)
- Google Gemini —
GeminiProvider(gemini-2.0-flashdefault). Vision supported. - DeepSeek —
DeepSeekProvider(deepseek-chatdefault). No vision. - Mistral AI —
MistralProvider(mistral-small-latestdefault). Vision onpixtral-large-latest. - Groq —
GroqProvider(llama-3.3-70b-versatiledefault). 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.
GenerateAltTextOnUploadListenerwrapped only the AI call (generateSafe) but left DB operations (language overlayinsert/update) andgetForLocalProcessing()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-leveltry/catchin__invoke(); errors are logged and the upload always completes. - Dashboard score widgets showed ~100% for one colour.
ScoreDistributionDataProviderreturned 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 gauge —data = [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 genericnt_ai_generateandnt_ai_summarizeAJAX endpoints remain as the shared backend API; the unusednt_ai_translateendpoint was removed.
Interne Vor-Release-Historie (Mai 2026, Schema
1.0.0→1.2.0) — vor dem öffentlichen Git-Releasev1.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
webwas renamed tocontent(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 usesAfterDatabaseOperationsEventwith status filtering, so it fires on every backend page save. It also resolvesNEW...placeholder UIDs viaDataHandler::substNEWwithIDsso 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:auditCLI 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
$optionOverridesargument onAiService::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
AiServiceAPI withgenerate,translate,summarize,generateAltText,describeImage. - Backend module "AI Tools" with playground UI.
- AJAX endpoints for backend JavaScript integration.
- CLI command
nt_ai:generate-alt-textsfor 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.