Files
AfiS-Aktensystem/web/lib/i18n/admin.ts
T
HarlekinandClaude Opus 5 3466215e2c
Prüfung / Lint, Typen, Tests (push) Canceled after 0s
Prüfung / Images bauen (pdf) (push) Canceled after 0s
Prüfung / Images bauen (web) (push) Canceled after 0s
Prüfung / Images bauen (worker) (push) Canceled after 0s
Images / bauen (pdf, docker/pdf.Dockerfile) (push) Canceled after 0s
Images / bauen (web, docker/web.Dockerfile) (push) Canceled after 0s
Images / bauen (worker, docker/worker.Dockerfile) (push) Canceled after 0s
Phase 9 abgeschlossen: Übersicht, Beobachtungsliste, helles Thema, Messung
Die Übersicht beantwortet vier Fragen, die man morgens hat: woran arbeite ich,
was ist fällig, wo hat jemand geschrieben, was hat sich getan. Jede Liste
läuft durch visibleCaseWhere — das ist der Ort, an dem eine unachtsame
Abfrage am ehesten eine Akte verrät. Ein Test prüft jede einzeln gegen eine zu
hoch eingestufte Akte. Der bisherige Inhalt ("Dein Zugang") steht jetzt unter
/zugang.

Beobachten ist eine Merkliste, kein Recht: nur was sichtbar ist, lässt sich
merken, und steigt eine Akte später über die eigene Stufe, verschwindet sie
aus der Liste, ohne dass jemand aufräumt.

Das helle Thema tauscht nur die semantische Ebene; die Grundpalette bleibt.
Die Klassifizierungsfarben sind für hellen Grund eine Spur dunkler, im Farbton
aber dieselben — eine Stufe muss in beiden Themen wiedererkennbar sein. Drei
Zustände, "wie das System" ist der Auslieferungszustand, und ein Skript im
Kopf setzt die Wahl, bevor das erste Mal gemalt wird.

Die Messung misst nicht den Nutzer. web-vitals schickt Zahlen und das
Routenmuster, keine Kennung und keinen konkreten Pfad: wer wann welche Akte
geöffnet hat, steht im Zugriffsprotokoll, und eine zweite Spur daneben wäre
eine Überwachungsfunktion ohne Auftrag. Ausgewertet wird Median und 75.
Perzentil, nicht der Mittelwert.

Mobil: die breiten Tabellen scrollen in sich, statt die Seite breiter zu
machen. Ein e2e-Test hält fest, dass keine Seite waagerecht überläuft.

scripts/restore-test.sh spielt eine Sicherung in eine Wegwerf-Datenbank und
prüft ausdrücklich, dass Regeln und Trigger mitkommen: eine Wiederherstellung
ohne entry_no_delete wäre eine Datenbank ohne die Zusicherung, um derentwillen
das System gebaut wird. Einmal durchgespielt, alles angekommen.

186 Tests im Web-Paket, 17 in der Datenbank, 7 im Worker, 54 e2e.
Grösste Route 116,2 von 120 kB.

Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
2026-09-03 10:28:50 +02:00

109 lines
4.3 KiB
TypeScript

/**
* Der Adminbereich: Rollen, Vorlagen, Einstellungen.
*
* Nach Bereichen getrennt, weil eine **Client-Komponente die ganze Datei ins
* Bündel zieht**, in der ihr Text steht. Lägen alle Texte in einer, trüge jede
* Ansicht die der ganzen Anwendung mit sich herum — das Budget aus
* docs/09-performance-und-ux.md wäre nach wenigen Phasen aufgebraucht.
*
* Serverkomponenten nehmen weiter `de` aus `lib/i18n/de.ts`: was dorthin
* gezogen wird, verlässt den Server nicht.
*/
export const roleAdminText = {
heading: 'Rollenverwaltung',
intro:
'Jede Rolle des Discord-Servers steht hier. Zugangsrollen bestimmen die Freigabestufe, Rangrollen die Rechte, und eine Zugehörigkeitsrolle entscheidet, wer sich überhaupt anmelden darf.',
empty:
'Noch keine Rollen eingelesen. Der Worker spiegelt sie, sobald er am Discord-Gateway hängt.',
role: 'Rolle',
category: 'Sorte',
clearance: 'Freigabestufe',
grantsMembership: 'Darf sich anmelden',
permissions: 'Rechte',
missingFromGuild: 'Auf dem Server nicht mehr vorhanden',
save: 'Zuordnung speichern',
invalidInput: 'Eingabe nicht gültig',
roleGone: 'Rolle nicht gefunden, sie wurde zwischenzeitlich gelöscht',
saving: 'Wird gespeichert',
saved: 'Zuordnung gespeichert',
confirm: 'Rollen-Mapping ändern? Das wirkt sofort für alle angemeldeten Personen.',
categories: {
MEMBERSHIP: 'Zugehörigkeit',
RANK: 'Rang',
CLEARANCE: 'Zugang',
UNSORTED: 'Nicht eingeordnet',
} as Record<string, string>,
optIn:
'Dieses Recht ist im Auslieferungszustand keiner Rolle zugeordnet. Vergib es bewusst.',
preview: {
heading: 'Vorschau',
intro: 'Was jemand mit dieser Stufe sieht, wenn er keine weiteren Rollen hat.',
level: 'Stufe',
sees: 'Sieht Akten bis einschliesslich',
hidden: 'Höhere Akten sind unsichtbar',
lockedOnly: 'Höhere Akten sind sichtbar, aber gesperrt',
nobody: 'Keine Rolle führt zu dieser Stufe',
viaRoles: 'Erreichbar über',
},
} as const
export const templateAdminText = {
heading: 'Vorlagen',
intro:
'Eine Vorlage bestimmt, aus welchen Bausteinen eine Fallart besteht. Speichern legt eine neue Version an; bestehende Akten behalten die Version, mit der sie angelegt wurden.',
empty: 'Noch keine Vorlage.',
version: (v: number) => `Version ${v}`,
fieldsLabel: 'Bausteine als JSON',
fieldsHelp:
'Liste von Bausteinen. Eingabefelder: shorttext, longtext, select, multiselect, date, person, number, checklist, table. Feste Bausteine: heading, paragraph, signature, pagebreak.',
numberPrefix: 'Präfix des Aktenzeichens',
numberPadding: 'Stellen der laufenden Nummer',
save: 'Als neue Version speichern',
saved: (v: number) => `Gespeichert als Version ${v}`,
preview: 'Vorschau',
previewIntro: 'So sieht eine neue Akte mit dieser Vorlage aus.',
invalid: 'Die Bausteine sind kein gültiges JSON.',
fieldsInvalid: 'Die Bausteine sind nicht gültig.',
inputField: 'Eingabe',
staticBlock: 'Fester Baustein',
} as const
export const settingsText = {
heading: 'Änderungsrichtlinie',
intro:
'Regelt, ob und wie lange Verlaufseinträge nachträglich geändert werden dürfen. Gilt für die ganze Abteilung.',
policy: 'Richtlinie',
graceMinutes: 'Karenzzeit in Minuten',
markGrace: 'Auch Änderungen in der Karenzzeit sichtbar markieren',
save: 'Richtlinie speichern',
saved: 'Richtlinie gespeichert',
confirm: 'Änderungsrichtlinie ändern? Das gilt sofort für alle Akten.',
policies: {
APPEND_ONLY: 'Keine Änderung möglich, nur Korrektureinträge',
GRACE_WINDOW: 'Eigene Einträge in der Karenzzeit frei änderbar, danach nur mit Recht',
OPEN: 'Jederzeit änderbar, sofern das Recht vorliegt',
} as Record<string, string>,
} as const
export const vitalsText = {
heading: 'Ladewerte',
intro:
'Gemessen in den Browsern der Nutzer, letzte sieben Tage. Nur Zahlen und das Routenmuster — wer wann welche Akte geöffnet hat, steht im Zugriffsprotokoll.',
empty: 'Noch nichts gemessen.',
metric: 'Wert',
median: 'Median',
p75: '75. Perzentil',
count: 'Messungen',
target: 'Ziel',
worstRoutes: 'Langsamste Routen',
route: 'Route',
targets: {
LCP: 'unter 1,5 s',
INP: 'unter 200 ms',
CLS: 'unter 0,05',
TTFB: 'unter 500 ms',
FCP: 'unter 1,0 s',
} as Record<string, string>,
} as const