From 04827a489d65450ec80e13ef7f4946bb9ead6840 Mon Sep 17 00:00:00 2001 From: Schalli Date: Mon, 7 Sep 2026 13:35:58 +0200 Subject: [PATCH] docs(quick-260907-ipz): Plan fuer einheitliche Anrede und richtige Einzahl MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Zwei Wortlaut-Maengel, beide am Code verifiziert: vier deutsche Texte duzen statt zu siezen, und der Gruppen-Loeschdialog setzt zwei Zahlen in fest formulierte Mehrzahl-Woerter ("1 Mitglieder"). Beim Planen nachgeprueft: der Mock-Uebersetzer in groups-page.test.tsx kann kein ICU-Plural — die Umstellung wuerde die beiden bestehenden Loeschdialog-Tests brechen. Der Plan loest das ueber dieselbe Regex-Technik, mit der grants-matrix.test.tsx bereits ICU-select aufloest, und nagelt den Einzahl-Fall mit einem neuen Test fest. Co-Authored-By: Claude Opus 5 (1M context) Claude-Session: https://claude.ai/code/session_01K5jtbGzC5Sf9npJ3JCjKhq --- .../260907-ipz-PLAN.md | 322 ++++++++++++++++++ 1 file changed, 322 insertions(+) create mode 100644 .planning/quick/260907-ipz-anrede-vereinheitlichen-duzen-auf-siezen/260907-ipz-PLAN.md diff --git a/.planning/quick/260907-ipz-anrede-vereinheitlichen-duzen-auf-siezen/260907-ipz-PLAN.md b/.planning/quick/260907-ipz-anrede-vereinheitlichen-duzen-auf-siezen/260907-ipz-PLAN.md new file mode 100644 index 0000000..1217829 --- /dev/null +++ b/.planning/quick/260907-ipz-anrede-vereinheitlichen-duzen-auf-siezen/260907-ipz-PLAN.md @@ -0,0 +1,322 @@ +--- +quick_id: 260907-ipz +title: Anrede vereinheitlichen (Duzen auf Siezen) und Einzahl korrigieren +type: execute +wave: 1 +depends_on: [] +autonomous: false +files_modified: + - apps/web/src/messages/de.json + - apps/web/src/messages/en.json + - apps/web/src/app/(portal)/admin/groups/groups-page.test.tsx + - apps/web/src/app/(portal)/admin/modules/grants/grants-matrix.test.tsx + - apps/web/src/components/modules/module-access-gate.test.tsx + +estimate: + tokens: 22000 + raw_tokens: 22000 + tasks: 2 + confidence: low + +must_haves: + truths: + - "Die vier bisher duzenden deutschen Texte siezen: leere Gruppenliste, Modul-Aktivierungsdialog, Modul-Sperrseite und Marktplatz-Hinweis." + - "Kein Wert in de.json enthaelt mehr eine Du-Form (du, dich, dir, dein*)." + - "Der Loeschdialog einer Gruppe mit genau einem Mitglied und einer Freigabe schreibt '1 Mitglied' und '1 Modul-Freigabe' — nicht '1 Mitglieder'." + - "Dasselbe gilt auf Englisch: '1 member' und '1 module grant'." + - "Ab zwei zeigt derselbe Text weiterhin die Mehrzahl." + - "de.json und en.json tragen weiterhin denselben Schluesselsatz." + - "Alle Tests, die diese Texte festnageln, laufen gruen — keiner wurde geloescht." + artifacts: + - apps/web/src/messages/de.json + - apps/web/src/messages/en.json + key_links: + - "Die Mock-Uebersetzer in den Tests spiegeln die Texte aus de.json — jede Textaenderung muss dort mitgezogen werden, sonst pinnen die Tests eine Fassung, die es nicht mehr gibt." + - "Der Mock-Uebersetzer in groups-page.test.tsx kann heute KEIN ICU-Plural — ohne Erweiterung bricht der Loeschdialog-Test durch die Plural-Umstellung." +--- + + +Zwei Wortlaut-Maengel in der deutschen Oberflaeche, beide vom Nutzer beauftragt und beide am +Code verifiziert: + +1. **Die Anrede springt.** Die Oberflaeche siezt ueberall — an genau vier Stellen duzt sie. +2. **Die Einzahl ist falsch.** Der Loeschdialog einer Gruppe schreibt "1 Mitglieder und + 1 Modul-Freigaben", weil zwei Zahlen in fest formulierte Mehrzahl-Woerter eingesetzt + werden. Live beobachtet an der Gruppe "Vertrieb Innendienst". + +Purpose: Ein Produkt, das an externe Kunden verkauft werden soll, redet seine Nutzer nicht +mal so und mal so an und zaehlt nicht falsch. + +Output: Vier korrigierte deutsche Texte, ein Loeschdialog-Text mit echter Ein-/Mehrzahl in +beiden Sprachen, mitgezogene Tests und ein neuer Test, der genau den Einzahl-Fall festnagelt. + +Ausdruecklich NICHT Teil dieses Plans: jede andere Umformulierung. Es werden ausschliesslich +die fuenf hier namentlich genannten Schluessel angefasst. Englisch ist von Defekt 1 nicht +betroffen — Englisch kennt den Unterschied nicht und ist bereits richtig formuliert. + + + +@~/.claude/gsd-core/workflows/execute-plan.md + + + +@CLAUDE.md +@apps/web/src/app/(portal)/admin/groups/components/DeleteGroupDialog.tsx +@apps/web/src/app/(portal)/admin/modules/grants/grants-matrix.test.tsx + + + +Alles Folgende wurde beim Planen am Code nachgeprueft und erspart dem Executor die Suche. + +**1. Die vier Du-Stellen sind vollstaendig — es gibt keine fuenfte.** +Ein Wortgrenzen-Grep ueber `de.json` nach `du|dich|dir|dein*` trifft heute exakt vier +Zeilen (400, 464, 492, 630) und nichts sonst. Die Erhebung im Auftrag ist damit +bestaetigt und abgeschlossen. + +| Schluessel | Zeile | heute | +|---|---|---| +| `admin.groups.noGroupsBody` | 400 | "Lege deine erste Gruppe an, um Modulzugriff gezielt zu vergeben." | +| `adminModules.activationDialog.body` | 464 | "… oder moechtest du die Freigaben separat konfigurieren?" | +| `modules.accessDenied.body` | 492 | "Du hast fuer dieses Modul keine Freigabe. Wende dich an deinen Administrator." | +| `marketplace.toastNoAccess` | 630 | "Kein Zugriff auf dieses Modul — wende dich an deinen Administrator." | + +`marketplace.toastNoAccess` liegt tatsaechlich unter `marketplace` (Zeile 630, direkt vor +`certManager`) — nicht unter `domaincheck`, obwohl die Nachbarzeilen im Ausschnitt so +wirken. Genutzt wird er in `app/(portal)/marketplace/page.tsx:178`. + +**2. Derselbe Grep trifft in den drei Testdateien exakt vier Zeilen** — allesamt die oben +gelisteten Texte. Es gibt keine weitere Stelle im `src`-Baum, die diese Texte kopiert. + +**3. ICU-Plural ist im Projekt bereits etabliert.** `admin.ldap.…resultSummary` +(de.json Zeile 365) nutzt `{errors, plural, =0 {} other {, # Fehler}}`. next-intl 4.13 +kann das produktiv ohne jede Zusatzarbeit — es braucht kein neues Mittel, nur dieselbe +Schreibweise. + +**4. Der Loeschdialog uebergibt beide Zahlen bereits als Parameter.** +`DeleteGroupDialog.tsx:102` ruft `t('deleteConfirm.body', { memberCount, grantCount })`. +Es ist also nichts am Aufrufer zu aendern — nur am Text. + +**5. Der Mock-Uebersetzer in `groups-page.test.tsx` versteht KEIN ICU.** +Nachgelesen in `resolve()` (Zeile 66–80): er ersetzt stur `{k}` durch den Wert. Sobald +`deleteConfirm.body` auf Plural-Schreibweise umgestellt wird, findet er `{memberCount}` +nicht mehr, gibt den ICU-Rohtext aus, und die bestehenden Zusicherungen `/4 Mitglieder/` +(Zeile 475) und `/2 Modul-Freigaben/` (Zeile 477) schlagen fehl. +**Das ist keine Nebenwirkung, die man in Kauf nimmt — Task 2 loest es ausdruecklich.** + +**6. Fuer die Loesung gibt es im Projekt bereits ein Vorbild.** +`grants-matrix.test.tsx` (Zeile 48–53) hat genau dieses Problem fuer `select` geloest: ein +winziger Regex-Ersatz im Mock, der die eine benutzte ICU-Form aufloest. Task 2 spiegelt +dieses Vorgehen fuer `plural`. Damit bleibt die Mock-Nachricht wortgleich mit `de.json` — +was der Sinn dieser Mocks ist. + +**7. Der Umlaut-Waechter schlaegt bei keiner der neuen Formulierungen an.** +`umlaut-guard.spec.ts` meldet jedes neue Token mit `ae`/`oe`/`ue`/`ss`, das nicht auf der +Positivliste steht. Die geplanten Formulierungen wurden gegen genau diese Regel geprueft: +kein einziges verdaechtiges Token. Es ist also **kein** Eintrag in `umlaut-dictionary.ts` +noetig. + +**8. de.json und en.json haben heute identische Schluesselsaetze** (maschinell verglichen, +beide Richtungen leer). Dieser Plan aendert ausschliesslich Werte, niemals Schluessel. + + + +**Ja, der Einzahl-Test wird angelegt.** Begruendung, weil der Auftrag sie verlangt: + +Der Fehler war ueber Monate im Code und kein Test hat ihn bemerkt — weil beide bestehenden +Loeschdialog-Tests mit `memberCount: 4, grantCount: 2` laufen, also nur im Mehrzahl-Fall. +Genau die eine Zahl, bei der der Text falsch wird, war nie abgedeckt. Ein Test, der nach +der Korrektur nur die Mehrzahl prueft, wuerde denselben Rueckfall wieder durchlassen. + +Der Aufwand ist zudem praktisch null: `buildRouterFetchMock` nimmt `impact` bereits als +Parameter entgegen (Zeile 393/412), der neue Fall ist ein Aufruf mit `{ memberCount: 1, +grantCount: 1 }` und zwei Zusicherungen. Und der Test hat einen zweiten Nutzen: er ist der +Beweis, dass die Mock-Erweiterung aus Task 2 das ICU-Plural wirklich auswertet — ohne ihn +koennte der Mock stillschweigend falsch bleiben, solange nur mit 4 und 2 geprueft wird. + + + +Keine der fuenf bestehenden Test-Fundstellen wird entfernt. Sie werden **mitgezogen**: die +Mock-Nachrichten und die Zusicherungen tragen danach den neuen Wortlaut. Ein Test, der +eine Formulierung festnagelt, ist nach einer Formulierungsaenderung nicht wertlos, sondern +schuetzt die neue Fassung. + + + + + + Task 1: Anrede auf Siezen vereinheitlichen (Defekt 1) + apps/web/src/messages/de.json, apps/web/src/app/(portal)/admin/groups/groups-page.test.tsx, apps/web/src/app/(portal)/admin/modules/grants/grants-matrix.test.tsx, apps/web/src/components/modules/module-access-gate.test.tsx + +Setze in `apps/web/src/messages/de.json` genau vier Werte auf die Sie-Form. Ausschliesslich +diese vier Schluessel werden angefasst, kein weiterer Text in der Datei wird umformuliert. + +- `admin.groups.noGroupsBody` (Zeile 400) wird zu: + Legen Sie Ihre erste Gruppe an, um Modulzugriff gezielt zu vergeben. +- `adminModules.activationDialog.body` (Zeile 464) wird zu: + Soll die Standardgruppe sofort Zugriff auf dieses Modul erhalten, oder moechten Sie die + Freigaben separat konfigurieren? — mit korrektem Umlaut in "moechten" geschrieben. +- `modules.accessDenied.body` (Zeile 492) wird zu: + Sie haben fuer dieses Modul keine Freigabe. Wenden Sie sich an Ihren Administrator. — + mit korrekten Umlauten in "fuer". +- `marketplace.toastNoAccess` (Zeile 630) wird zu: + Kein Zugriff auf dieses Modul — wenden Sie sich an Ihren Administrator. — der + Geviertstrich bleibt unveraendert erhalten. + +Alle vier Werte werden mit echten Umlauten geschrieben (`ü`, `ö`); die Ersatzschreibweisen +in dieser Aufgabenbeschreibung sind nur der Klartext dieses Plans. + +`en.json` wird in dieser Aufgabe NICHT angefasst — Englisch kennt die Unterscheidung nicht +und ist bereits richtig formuliert. Es werden keine Schluessel hinzugefuegt, umbenannt oder +entfernt. + +Ziehe anschliessend die drei Testdateien nach, damit ihre Mock-Nachrichten und +Zusicherungen wieder wortgleich zu `de.json` sind. Kein Test wird geloescht oder +uebersprungen — nur der Wortlaut wird aktualisiert: + +- `grants-matrix.test.tsx` Zeile 27 — Mock-Nachricht `adminModules.activationDialog.body`. +- `groups-page.test.tsx` Zeile 15 — Mock-Nachricht `admin.groups.noGroupsBody`. +- `groups-page.test.tsx` Zeile 185 — die Zusicherung, die denselben Text im Leerzustand + sucht. Sie muss buchstabengleich zur Mock-Nachricht aus Zeile 15 bleiben. +- `module-access-gate.test.tsx` Zeile 27 — Eintrag `accessDenied.body` in der + handgepflegten Uebersetzungstabelle. + + + cd /home/vicolab/projects/tessera-ctl && ! grep -nE '\b([Dd]u|dich|dir|dein(e|en|er|em|es)?)\b' apps/web/src/messages/de.json 'apps/web/src/app/(portal)/admin/groups/groups-page.test.tsx' 'apps/web/src/app/(portal)/admin/modules/grants/grants-matrix.test.tsx' apps/web/src/components/modules/module-access-gate.test.tsx && grep -q 'Wenden Sie sich an Ihren Administrator' apps/web/src/messages/de.json + cd /home/vicolab/projects/tessera-ctl && pnpm --dir apps/web test -- groups-page.test.tsx grants-matrix.test.tsx module-access-gate.test.tsx umlaut-guard.spec.ts + + +`de.json` enthaelt in keinem Wert mehr eine Du-Form; dieselbe Pruefung ueber die drei +Testdateien ist ebenfalls leer. Die vier Texte lauten auf Sie/Ihr. `en.json` ist +unveraendert. Alle vier genannten Testdateien laufen gruen, keiner der fuenf bisherigen +Pruefpunkte wurde entfernt. + + + + + Task 2: Ein-/Mehrzahl im Loeschdialog korrigieren (Defekt 2) + apps/web/src/messages/de.json, apps/web/src/messages/en.json, apps/web/src/app/(portal)/admin/groups/groups-page.test.tsx + + - Bei einem Mitglied und einer Freigabe lautet der deutsche Text "… hat 1 Mitglied und + 1 Modul-Freigabe. …"; die Zeichenfolge "1 Mitglieder" kommt nicht vor. + - Bei vier Mitgliedern und zwei Freigaben lautet er weiterhin "… hat 4 Mitglieder und + 2 Modul-Freigaben. …" (die beiden bestehenden Tests bleiben gruen). + - Auf Englisch gilt dasselbe: "1 member" / "1 module grant" gegen "4 members" / + "2 module grants". + - Der Rest des Satzes (Folgen des Loeschens, Unwiderruflichkeit) bleibt in beiden + Sprachen unveraendert. + + +Schreibe zuerst die Mock-Erweiterung und den neuen Einzahl-Test, dann die Textaenderung — +der neue Test muss vor der Textaenderung rot sein. + +Schritt A — `resolve()` in `groups-page.test.tsx` (Zeile 66–80) um eine ICU-Plural-Aufloesung +erweitern, nach demselben Muster, mit dem `grants-matrix.test.tsx` (Zeile 48–53) bereits +`select` aufloest. Vor der bestehenden Schleife, die schlichte `{k}`-Platzhalter ersetzt, +laeuft ein globaler Ersatz mit dem Muster +`/\{(\w+),\s*plural,\s*one\s*\{([^}]*)\}\s*other\s*\{([^}]*)\}\}/g`. +Fuer jeden Treffer wird der Zweig `one` gewaehlt, wenn `Number(params[name]) === 1`, sonst +der Zweig `other`; im gewaehlten Zweig wird danach jedes `#` durch `String(params[name])` +ersetzt. Die bestehende schlichte Ersetzungsschleife bleibt unveraendert dahinter stehen — +sie greift weiterhin fuer alle anderen Schluessel wie `adDnLabel`. Aktualisiere den +Kopfkommentar der Datei so, dass er die nun ebenfalls aufgeloeste Plural-Form erwaehnt. + +Schritt B — neuer Test im Block `DeleteGroupDialog (via AdminGroupsPage)`, direkt nach dem +bestehenden Test, der beide Zahlen prueft. Er nutzt `buildRouterFetchMock` mit +`impact: { memberCount: 1, grantCount: 1 }`, oeffnet den Loeschdialog ueber denselben Weg +wie der Nachbartest (letzte Loeschen-Schaltflaeche) und sichert zu, dass der Dialogtext +`/hat 1 Mitglied und 1 Modul-Freigabe\./` enthaelt. Zusaetzlich eine Gegenprobe: die +Mehrzahlform mit vorangestellter Eins darf nicht im Dokument sein +(`queryByText(/1 Mitglieder/)` ist `null`). Der Test muss an dieser Stelle fehlschlagen — +das ist der Nachweis, dass er den Defekt wirklich trifft. + +Schritt C — `admin.groups.deleteConfirm.body` in beiden Sprachdateien auf ICU-Plural +umstellen, in derselben Schreibweise wie das bestehende `admin.ldap.…resultSummary`. +Beide Zahlen bekommen je ein eigenes `plural`-Argument mit den Zweigen `one` und `other`, +die Zahl selbst wird im Zweig als `#` gesetzt: + +- `de.json` Zeile 433: erstes Argument `memberCount` mit den Zweigen Mitglied / Mitglieder, + zweites Argument `grantCount` mit den Zweigen Modul-Freigabe / Modul-Freigaben. Der + Satzanfang "Diese Gruppe hat" und die beiden Folgesaetze bleiben Wort fuer Wort stehen. +- `en.json` Zeile 433: dieselbe Struktur mit member / members und module grant / + module grants. "This group has" und die beiden Folgesaetze bleiben unveraendert. + +Ziehe abschliessend die Mock-Nachricht in `groups-page.test.tsx` Zeile 49–50 nach, sodass +sie buchstabengleich zum neuen Wert aus `de.json` ist — die Erweiterung aus Schritt A wertet +sie dann korrekt aus. Es werden keine Schluessel hinzugefuegt oder entfernt; beide +Sprachdateien behalten denselben Schluesselsatz. + + + cd /home/vicolab/projects/tessera-ctl && test "$(grep -c 'memberCount, plural' apps/web/src/messages/de.json)" = "1" && test "$(grep -c 'memberCount, plural' apps/web/src/messages/en.json)" = "1" && test "$(grep -c 'grantCount, plural' apps/web/src/messages/de.json)" = "1" && test "$(grep -c 'grantCount, plural' apps/web/src/messages/en.json)" = "1" + cd /home/vicolab/projects/tessera-ctl && node -e "const a=require('./apps/web/src/messages/de.json'),b=require('./apps/web/src/messages/en.json');const f=(o,p='')=>Object.entries(o).flatMap(([k,v])=>typeof v==='object'&&v?f(v,p+k+'.'):[p+k]);const A=f(a).sort().join('|'),B=f(b).sort().join('|');if(A!==B){console.error('key sets differ');process.exit(1)}console.log('key parity ok:',f(a).length)" + cd /home/vicolab/projects/tessera-ctl && pnpm --dir apps/web test -- groups-page.test.tsx + + +Beide Sprachdateien tragen fuer `memberCount` und `grantCount` je ein `plural`-Argument. +Der Schluesselsatz beider Dateien ist weiterhin identisch (787). In `groups-page.test.tsx` +laufen alle Loeschdialog-Tests gruen: die beiden bestehenden mit 4/2 und der neue mit 1/1, +der ohne die Textkorrektur rot war. Der Mock-Uebersetzer loest das Plural-Argument auf, +statt den Rohtext auszugeben. + + + + + + +**Maschinell** (laeuft in beiden Aufgaben, hier nochmal als Gesamtlauf): + +- `pnpm --dir apps/web test` — die gesamte Web-Testsuite, nicht nur die vier beruehrten + Dateien. Es soll auffallen, falls eine bisher unbekannte Stelle einen der Texte spiegelt. +- `pnpm --dir apps/web run type-check` + +**Sichtpruefung im Browser** — vom Orchestrator auszufuehren, nicht vom Planer. +Vorher noetig: `docker compose build web && docker compose up -d --force-recreate web`. +Anschliessend `http://localhost:3000`. + + +Alle Bildschirme in **deutscher** Oberflaeche pruefen. Gesucht wird jeweils die Sie-Form — +kein "du", "dich", "dein". + +1. **Modul-Aktivierungsdialog** — als `admin`/`admin123` anmelden, dann + Administration → Module, bei einem noch nicht aktivierten Modul auf Aktivieren klicken. + Der Dialogtext muss siezen ("… oder möchten Sie die Freigaben separat konfigurieren?"). + +2. **Löschdialog einer Gruppe, Einzahl** — als `admin` unter Administration → Gruppen die + Gruppe **"Vertrieb Innendienst"** loeschen (Dialog nur oeffnen, NICHT bestaetigen). + Der Text muss "1 Mitglied und 1 Modul-Freigabe" lauten — nicht "1 Mitglieder und + 1 Modul-Freigaben". Zur Gegenprobe eine Gruppe mit mehreren Mitgliedern oeffnen: dort + muss weiterhin die Mehrzahl stehen. Beide Dialoge mit Abbrechen schliessen. + +3. **Modul-Sperrseite** — abmelden, als `nutzer2`/`Test1234!` anmelden (dieser Benutzer hat + KEINE Freigabe fuer tender-radar) und die Modulseite von tender-radar direkt aufrufen. + Die 403-Seite muss "Sie haben für dieses Modul keine Freigabe. Wenden Sie sich an Ihren + Administrator." zeigen. + +4. **Marktplatz-Hinweis** — als `nutzer2` im Marktplatz auf die Kachel eines aktiven Moduls + ohne Freigabe klicken. Die eingeblendete Meldung muss "… wenden Sie sich an Ihren + Administrator." lauten. + +5. **Englische Fassung des Löschdialogs** — Sprache auf Englisch umstellen und Punkt 2 + wiederholen: "1 member and 1 module grant". + +**Nicht im Browser pruefbar:** der Leerzustand der Gruppenliste +(`admin.groups.noGroupsBody`) erscheint nur, wenn gar keine Gruppe existiert — im +Testsystem gibt es Gruppen. Dieser Text ist durch den Test in `groups-page.test.tsx` +(Zeile 185) abgedeckt und darf im Browser uebersprungen werden. + + + + +- Die vier bisher duzenden deutschen Texte siezen; `de.json` enthaelt keine Du-Form mehr. +- Der Loeschdialog schreibt bei genau einem Mitglied und einer Freigabe die Einzahl, ab + zwei weiterhin die Mehrzahl — in beiden Sprachen. +- `en.json` wurde nur fuer den Loeschdialog angefasst; die Schluesselsaetze beider + Sprachdateien sind weiterhin identisch (787). +- Kein bestehender Test wurde geloescht; alle fuenf bisherigen Fundstellen wurden auf den + neuen Wortlaut nachgezogen. +- Ein neuer Test nagelt den Einzahl-Fall fest und war vor der Korrektur rot. +- Kein anderer Text der Oberflaeche wurde umformuliert. + + + +Nach Abschluss `.planning/quick/260907-ipz-anrede-vereinheitlichen-duzen-auf-siezen/260907-ipz-SUMMARY.md` anlegen. + \ No newline at end of file