Files
schalli 04827a489d docs(quick-260907-ipz): Plan fuer einheitliche Anrede und richtige Einzahl
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) <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01K5jtbGzC5Sf9npJ3JCjKhq
2026-09-07 13:35:58 +02:00

18 KiB
Raw Permalink Blame History

quick_id, title, type, wave, depends_on, autonomous, files_modified, estimate, must_haves
quick_id title type wave depends_on autonomous files_modified estimate must_haves
260907-ipz Anrede vereinheitlichen (Duzen auf Siezen) und Einzahl korrigieren execute 1
false
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
tokens raw_tokens tasks confidence
22000 22000 2 low
truths artifacts key_links
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.
apps/web/src/messages/de.json
apps/web/src/messages/en.json
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.

<execution_context> @~/.claude/gsd-core/workflows/execute-plan.md </execution_context>

@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.

<success_criteria>

  • 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. </success_criteria>
Nach Abschluss `.planning/quick/260907-ipz-anrede-vereinheitlichen-duzen-auf-siezen/260907-ipz-SUMMARY.md` anlegen.