--- quick_id: 260907-hyi title: Umlaute in der deutschen Oberflaeche korrigieren status: complete tech-stack: patterns: - "Explizite Ersetzungs-/Positivliste statt Zeichenregel fuer Umlaut-Korrektur" key-files: created: - apps/web/src/messages/umlaut-dictionary.ts - apps/web/src/messages/umlaut-guard.spec.ts modified: - apps/web/src/messages/de.json - apps/api/src/mail/mail.service.ts - apps/api/src/domaincheck/domaincheck.seed.ts decisions: - "ss/ß-Faelle (Groesse, Schliessen, ausschliessen, Gruessen) wurden mitkorrigiert statt ausgeklammert, da derselbe Defekt." - "Fehlende Woerterbuch-Eintraege, die der neue Waechter selbst aufdeckte, wurden inline nachgezogen (Rule 1 - Bug)." actuals: tokens: 9975 tasks: 3 commits: 3 plan_head_before: bec0530a2b2638b47fbc91dc9017cda148f5c37f metrics: duration: "~25 min" completed: 2026-09-07 --- # Quick-Task 260907-hyi: Umlaute in der deutschen Oberflaeche korrigieren Summary Deutsche Oberflaechentexte, Passwort-/Willkommens-Mail und Marktplatz-Modulbeschreibung schrieben Umlaute als Buchstabenpaare aus; jetzt schreiben sie echte Umlaute, per expliziter Token-Liste korrigiert und mit einem Vitest-Waechter gegen Rueckfall abgesichert. ## Ausgefuehrte Tasks 1. **Woerterbuch anlegen und de.json korrigieren** — `umlaut-dictionary.ts` angelegt (`UMLAUT_REPLACEMENTS`, `UMLAUT_ALLOWLIST`), 68 falsche Tokens (140 Fundstellen inkl. der in Task 2 entdeckten Ergaenzung) in `de.json` per Ganzwort-Ersetzung korrigiert. Commit `3d351c6`. 2. **Regressionswaechter als Vitest-Spec** — `umlaut-guard.spec.ts` angelegt, liest ausschliesslich das geparste JSON, prueft drei Dinge (keine bekannten Ersatzschreibweisen mehr, kein neues ae/oe/ue/ss-Token ausserhalb der Positivliste, de/en-Schluesselparitaet). Commit `caa4827`. 3. **API-Texte — Passwort-Mail und Modul-Beschreibung** — `mail.service.ts` (Betreff, Reset-Fliesstext, Willkommens-Mail) und `domaincheck.seed.ts` korrigiert. Commit `d9f1422`. 4. **Sichtpruefung im Browser und in der Datenbank** — `checkpoint:human-verify`, absichtlich nicht ausgefuehrt. Der Orchestrator fuehrt Docker-Rebuild und die visuelle Pruefung durch. ## Deviations from Plan ### Auto-fixed Issues **1. [Rule 1 - Bug] Fehlender Grossschreibungs-Eintrag `Bestaetigen` → `Bestätigen`** - **Found during:** Task 2, beim ersten Lauf des neuen Waechters. - **Issue:** Die Plan-Wortliste fuehrte nur `bestaetigen→bestätigen` (klein), aber `common.confirm` in `de.json` nutzt die Grossschreibung `"Bestaetigen"` (Schaltflaechen-Text) — blieb nach Task 1 faelschlich unkorrigiert. - **Fix:** `Bestaetigen: 'Bestätigen'` zu `UMLAUT_REPLACEMENTS` ergaenzt, `de.json`-Wert direkt korrigiert. - **Files modified:** `apps/web/src/messages/umlaut-dictionary.ts`, `apps/web/src/messages/de.json` - **Commit:** `caa4827` **2. [Rule 1 - Bug] Fehlende Positivlisten-Eintraege fuer nach der Korrektur entstandene, aber weiterhin ae/oe/ue/ss-haltige korrekte Woerter** - **Found during:** Task 2, gleicher Waechter-Lauf. - **Issue:** Die Korrektur von `Passwoerter`, `vertrauenswuerdigen`, `ausschliessen`, `entschluesselt` ergibt korrektes Deutsch (`Passwörter`, `vertrauenswürdigen`, `ausschließen`, `entschlüsselt`), das aber weiterhin die Zeichenfolge `ss`/`ue` enthaelt (z. B. `üssel`, `au` + `e` in `trauen`, `uss` in `ausschließen`) und deshalb vom zweiten Waechter-Test als "neues Wort" markiert wurde. - **Fix:** Die vier Woerter zu `UMLAUT_ALLOWLIST` ergaenzt. - **Files modified:** `apps/web/src/messages/umlaut-dictionary.ts` - **Commit:** `caa4827` Beide Punkte wurden inline behoben, nicht als separate Commits — sie sind Teil der Fertigstellung des in Task 1/2 beschriebenen Woerterbuchs, keine architektonische Aenderung. ## Test-/Build-Ergebnisse (real, nicht simuliert) - `pnpm --filter @tessera/web test`: **38 Testdateien, 225 Tests — alle gruen** (inkl. neuem `umlaut-guard.spec.ts` und bestehender `tenderRadar-parity.spec.ts`). - `pnpm --filter @tessera/web run type-check`: sauber, keine Ausgabe. - `pnpm --filter @tessera/api run build`: sauber, keine Ausgabe. - `pnpm --filter @tessera/api run type-check`: sauber, keine Ausgabe. - `pnpm --filter @tessera/api run test`: **46 Testdateien, 642 Tests — alle gruen** (mehrere erwartete `ERROR`/`WARN`-Log-Zeilen in der Ausgabe stammen von absichtlich simulierten Fehlerpfaden in bestehenden Tests, kein neuer Testfehler). - Manuelle Waechter-Probe (Task 2 `done`-Kriterium): ein probeweise eingefuegtes `fuer` liess die Spec mit exakt der geforderten Meldung fehlschlagen (`"für"` + Schluesselpfad `common.edit`), danach zurueckgenommen — `git diff --stat` bestaetigt keine Restspur. ## Wieviele Strings geaendert wurden - **68 verschiedene Tokens** in `UMLAUT_REPLACEMENTS` (67 aus dem Plan + 1 selbst gefunden: `Bestaetigen`), **140 Ersetzungs-Treffer** in `de.json`-Werten insgesamt. - **65 Tokens** auf `UMLAUT_ALLOWLIST` (61 aus dem Plan + 4 selbst ergaenzt). - **6 Zeichenketten** in `apps/api/src/mail/mail.service.ts` (Betreff + 5 Fliesstext-/ Template-Literal-Stellen in beiden Mails). - **1 Zeichenkette** in `apps/api/src/domaincheck/domaincheck.seed.ts`. ## Was bewusst unangetastet blieb - `empfaenger@example.com` (Schluessel `testToPlaceholder`) — Platzhalter-Adresse, per `@`-Regel uebersprungen, wie im Plan gefordert. - Alle 65 Positivlisten-Woerter (`Passwort`, `Adresse`, `Quelle`, `manuell`, `Ausschreibung`, `Erzeugnisse`, `zuerst`, `neue`, ...) — unveraendert, keine einzige Ersetzung darauf angewendet. - Deutsche Code-Kommentare (z. B. in `tessera-logo.tsx`) — laut Plan ausdruecklich nicht Teil dieses Tasks, nicht angefasst. - Wortlaut jeder Zeichenkette — nur Schreibweise korrigiert, keine Umformulierung. - Schluessel und Reihenfolge in `de.json`/`en.json` — strukturell identisch geblieben (787 Schluessel, geprueft per Skript vor und nach der Aenderung). - Die beiden Backlog-Punkte aus dem Plan (`1 Mitglieder` statt `1 Mitglied`; Duzen im Aktivierungsdialog) — ausdruecklich nicht Teil dieses Plans, bereits im Backlog unter `.planning/phases/15-modul-berechtigungen-gruppen-user-grants/15-UAT-2026-09-07.md` vermerkt. - Task 4 (Sichtpruefung, Docker-Rebuild) — `checkpoint:human-verify`, dem Orchestrator ueberlassen. ## Self-Check: PASSED - `apps/web/src/messages/umlaut-dictionary.ts` — FOUND - `apps/web/src/messages/umlaut-guard.spec.ts` — FOUND - Commit `3d351c6` — FOUND (`git log --oneline --all`) - Commit `caa4827` — FOUND - Commit `d9f1422` — FOUND ## Task 4 — Abnahme am 2026-09-07, mit Nachbesserung Der Orchestrator hat Web und API neu gebaut und die Oberflaeche im Browser geprueft. Die Abnahme hat **drei uebersehene Stellen** gefunden, darunter zwei gut sichtbare Schaltflaechen: | falsch | richtig | Ort | |---|---|---| | `Aenderungen speichern` | Änderungen speichern | Dashboard-Bearbeitungsleiste | | `Oeffnen` | Öffnen | Modul oeffnen | | `Eine Aenderung ist hier nicht moeglich` | Eine Änderung … | LDAP-Hinweis im Konto | ### Warum der Waechter sie durchgelassen hat Sein Verdachtsmuster war `/(ae|oe|ue|ss)/` — **case-sensitiv**. "Aenderungen" beginnt mit "Ae", nicht mit "ae", und konnte deshalb gar nicht anschlagen. Derselbe Fehler war auch in der ersten Analyse des Orchestrators und hat dort zunaechst zu einem falschen Entwarnungssignal gefuehrt. Behoben in Commit `85d2d77`: - Muster auf `/(ae|oe|ue|ss)/i` umgestellt — erfasst jetzt auch grossgeschriebene Formen. - `Aenderung`, `Aenderungen`, `Oeffnen` ins Woerterbuch aufgenommen und in `de.json` korrigiert (4 Fundstellen). - Durch die schaerfere Pruefung melden sich neu die Abkuerzungen `RSS`, `RSSGenerator` und `SSL`. Sie tragen ein doppeltes S ohne Umlaut-Bezug und stehen jetzt auf der Positivliste. ### Zwei weitere Nutzertexte, die der erste Durchgang nicht als solche erkannt hatte `ldap.service.ts` schreibt zwei Meldungen in `result.errors`. Das ist kein Protokoll, sondern die Fehlerliste, die dem Administrator auf der LDAP-Seite angezeigt wird (`admin/ldap/page.tsx:1028`). Beide korrigiert: "ungueltiger ldapObjectGuid-Wert" und "Base-DN-Konfiguration pruefen. Nicht geloescht." Drei Tests pinnen diese Texte bewusst und wurden mitgezogen. **Bewusst nicht angefasst:** die Warnung in `crypto.service.ts`. Sie geht ueber `logger.warn` ins Protokoll und nicht an einen Nutzer. ### Gegenproben | Pruefung | Ergebnis | |---|---| | Unabhaengige Analyse aller Tokens in `de.json` mit ae/oe/ue | keine Ersatzschreibung mehr; die 26 verbleibenden Treffer sind korrektes Deutsch (Quelle, manuell, Aktuell, neue, dauerhaft …) | | Schluesselsatz de/en | 787 / 787, identisch | | Modulbeschreibung in der **bestehenden** Datenbank nach API-Neustart | `Domain-Verfügbarkeit prüfen` — der Seed-Upsert hat die Altzeile mitgezogen, ohne Migration | | Browser, echte Navigation | "Änderungen speichern", "Widget hinzufügen", "hinzuzufügen", "Verfügbar", "Domain-Verfügbarkeit prüfen" korrekt | | Testlaeufe | 642 API-Tests, 225 Web-Tests, beide Typpruefungen gruen | ### Nachtrag zur Belastbarkeit der Messmethode Eine erste Sichtpruefung per `fetch()` aus der laufenden Seite heraus meldete alle Seiten als sauber. Dieselbe Methode hatte in dieser Sitzung schon einmal ein falsches Ergebnis geliefert, weil sie die Sitzung nicht wie eine echte Navigation mitfuehrt. Die oben berichteten Ergebnisse stammen deshalb aus echten Seitenaufrufen.