From e0b03ea33679578a64fad81d790932a63878257b Mon Sep 17 00:00:00 2001 From: Harlekin Date: Fri, 4 Sep 2026 08:54:52 +0200 Subject: [PATCH] Gedankenstriche durch Bindestriche ersetzt 375 Vorkommen in 210 Dateien. Betrifft Kommentare, Oberflaechentexte und die README; an keiner Stelle Bedeutung, nur Zeichensetzung. --- .env.example | 2 +- README.md | 6 ++--- compose.yaml | 2 +- .../migration.sql | 2 +- .../20260903140000_suche/migration.sql | 2 +- .../20260903200000_messwerte/migration.sql | 2 +- .../migration.sql | 2 +- .../migration.sql | 2 +- .../migration.sql | 2 +- .../20260904100000_abteilungen/migration.sql | 10 ++++---- .../migration.sql | 4 ++-- packages/db/prisma/schema.prisma | 24 +++++++++---------- packages/db/prisma/seed.ts | 8 +++---- packages/db/scripts/prepare-test-db.mjs | 6 ++--- packages/db/src/testDatabase.ts | 2 +- .../db/tests/auslieferungszustand.test.ts | 2 +- packages/db/tests/regeln.test.ts | 2 +- packages/db/tests/schema-drift.test.ts | 2 +- scripts/restore-test.sh | 2 +- start.sh | 2 +- web/app/(app)/abteilungen/[key]/loading.tsx | 2 +- web/app/(app)/abteilungen/[key]/page.tsx | 2 +- web/app/(app)/abteilungen/page.tsx | 2 +- .../admin/abteilungen/DepartmentForm.tsx | 2 +- web/app/(app)/admin/abteilungen/loading.tsx | 2 +- web/app/(app)/admin/layout.tsx | 2 +- web/app/(app)/admin/loading.tsx | 2 +- web/app/(app)/admin/page.tsx | 2 +- web/app/(app)/admin/protokoll/loading.tsx | 2 +- web/app/(app)/admin/richtlinie/actions.ts | 2 +- web/app/(app)/admin/richtlinie/loading.tsx | 2 +- web/app/(app)/admin/rollen/loading.tsx | 2 +- web/app/(app)/admin/rollen/page.tsx | 2 +- web/app/(app)/admin/sections.ts | 2 +- web/app/(app)/admin/system/loading.tsx | 2 +- web/app/(app)/admin/system/page.tsx | 2 +- web/app/(app)/admin/vorlagen/loading.tsx | 2 +- web/app/(app)/dateien/actions.ts | 2 +- .../[documentNumber]/DocumentActions.tsx | 2 +- .../[documentNumber]/export/loading.tsx | 2 +- web/app/(app)/einstellungen/actions.ts | 2 +- web/app/(app)/einstellungen/loading.tsx | 2 +- web/app/(app)/export/actions.ts | 2 +- .../(app)/faelle/[caseNumber]/CaseActions.tsx | 2 +- .../faelle/[caseNumber]/Participants.tsx | 2 +- .../(app)/faelle/[caseNumber]/WatchToggle.tsx | 2 +- .../[caseNumber]/aenderungen/loading.tsx | 2 +- .../faelle/[caseNumber]/aenderungen/page.tsx | 2 +- .../[caseNumber]/beteiligte/loading.tsx | 2 +- .../faelle/[caseNumber]/dokumente/loading.tsx | 2 +- .../faelle/[caseNumber]/export/loading.tsx | 2 +- web/app/(app)/faelle/[caseNumber]/layout.tsx | 4 ++-- web/app/(app)/faelle/[caseNumber]/page.tsx | 2 +- .../faelle/[caseNumber]/sectionActions.ts | 2 +- web/app/(app)/faelle/actions.ts | 4 ++-- web/app/(app)/faelle/neu/NewCaseForm.tsx | 4 ++-- web/app/(app)/faelle/neu/loading.tsx | 2 +- web/app/(app)/faelle/page.tsx | 2 +- web/app/(app)/layout.tsx | 4 ++-- .../(app)/personalakten/[id]/Assignments.tsx | 4 ++-- web/app/(app)/personalakten/[id]/LinkCase.tsx | 2 +- .../personalakten/[id]/PersonnelHead.tsx | 4 ++-- web/app/(app)/personalakten/[id]/page.tsx | 2 +- web/app/(app)/personalakten/actions.ts | 2 +- .../personalakten/neu/NewPersonnelForm.tsx | 4 ++-- web/app/(app)/personalakten/neu/loading.tsx | 2 +- web/app/(app)/personalakten/page.tsx | 2 +- web/app/(app)/suche/SavedViews.tsx | 2 +- web/app/(app)/suche/SearchBox.tsx | 2 +- web/app/(app)/suche/loading.tsx | 2 +- web/app/(app)/suche/page.tsx | 10 ++++---- web/app/(app)/uebersicht/loading.tsx | 2 +- web/app/(app)/uebersicht/page.tsx | 6 ++--- web/app/(app)/zugang/loading.tsx | 2 +- web/app/(print)/NotAvailable.tsx | 2 +- web/app/(print)/PrintBar.tsx | 4 ++-- .../dokumente/[documentNumber]/druck/page.tsx | 4 ++-- .../faelle/[caseNumber]/druck/page.tsx | 8 +++---- web/app/(print)/layout.tsx | 4 ++-- web/app/api/admin/export/route.ts | 2 +- web/app/api/exports/[id]/route.ts | 2 +- web/app/api/files/[id]/route.ts | 2 +- web/app/api/files/route.ts | 2 +- web/app/api/search/quick/route.ts | 4 ++-- web/app/api/stream/route.ts | 6 ++--- web/app/api/vitals/route.ts | 2 +- web/app/globals.css | 14 +++++------ web/app/layout.tsx | 4 ++-- web/auth.ts | 4 ++-- web/components/AddPanel.tsx | 4 ++-- web/components/Avatar.tsx | 2 +- web/components/NavLinks.tsx | 2 +- web/components/Pending.tsx | 4 ++-- web/components/PieChart.tsx | 4 ++-- web/components/ProfileMenu.tsx | 2 +- web/components/SearchBar.tsx | 2 +- web/components/StampMark.tsx | 4 ++-- web/components/StatusTags.tsx | 2 +- web/components/Tabs.tsx | 2 +- web/components/ThemeToggle.tsx | 2 +- web/components/Vitals.tsx | 2 +- web/components/chat/Chat.tsx | 10 ++++---- web/components/chat/ChatLazy.tsx | 2 +- web/components/documents/DocumentList.tsx | 2 +- web/components/documents/NewDocument.tsx | 2 +- web/components/documents/Sheet.tsx | 6 ++--- web/components/documents/SheetSwitch.tsx | 2 +- web/components/export/ExportPanel.tsx | 2 +- web/components/palette/CommandPalette.tsx | 2 +- web/components/palette/PaletteTrigger.tsx | 2 +- web/components/realtime/useStream.ts | 4 ++-- web/components/sections/SectionEditor.tsx | 8 +++---- web/components/sections/Sections.tsx | 6 ++--- web/components/sections/SectionsForm.tsx | 2 +- web/components/sections/types.ts | 2 +- web/e2e/smoke.spec.ts | 4 ++-- web/lib/access/attachmentFilter.ts | 2 +- web/lib/access/caseFilter.ts | 4 ++-- web/lib/access/caseWrite.ts | 4 ++-- web/lib/access/chatFilter.ts | 2 +- web/lib/access/departmentFilter.ts | 2 +- web/lib/access/documentWrite.ts | 2 +- web/lib/access/personnelFilter.ts | 4 ++-- web/lib/audit/query.ts | 6 ++--- web/lib/auth/current.ts | 4 ++-- web/lib/cases/entryService.ts | 2 +- web/lib/cases/links.ts | 2 +- web/lib/cases/participants.ts | 6 ++--- web/lib/cases/service.ts | 6 ++--- web/lib/cases/terms.ts | 4 ++-- web/lib/cases/watch.ts | 2 +- web/lib/chat/mentions.ts | 2 +- web/lib/chat/preview.ts | 2 +- web/lib/chat/service.ts | 10 ++++---- web/lib/chat/terms.ts | 2 +- web/lib/chat/view.ts | 2 +- web/lib/dashboard/load.ts | 4 ++-- web/lib/departments/entries.ts | 4 ++-- web/lib/departments/service.ts | 22 ++++++++--------- web/lib/documents/service.ts | 4 ++-- web/lib/errors.ts | 2 +- web/lib/export/cacheKey.ts | 2 +- web/lib/export/database.ts | 2 +- web/lib/export/printAccess.ts | 2 +- web/lib/export/renderAccess.ts | 2 +- web/lib/export/service.ts | 8 +++---- web/lib/export/token.ts | 2 +- web/lib/export/zip.ts | 2 +- web/lib/files/clamav.ts | 2 +- web/lib/files/limits.ts | 2 +- web/lib/files/magic.ts | 8 +++---- web/lib/files/paths.ts | 2 +- web/lib/files/process.ts | 6 ++--- web/lib/files/reencode.ts | 4 ++-- web/lib/files/service.ts | 10 ++++---- web/lib/files/view.ts | 2 +- web/lib/i18n/admin.ts | 4 ++-- web/lib/i18n/cases.ts | 4 ++-- web/lib/i18n/chat.ts | 2 +- web/lib/i18n/common.ts | 4 ++-- web/lib/i18n/de.ts | 2 +- web/lib/i18n/departments.ts | 2 +- web/lib/i18n/documents.ts | 2 +- web/lib/i18n/export.ts | 2 +- web/lib/i18n/people.ts | 2 +- web/lib/i18n/shell.ts | 6 ++--- web/lib/notify/enqueue.ts | 6 ++--- web/lib/personnel/service.ts | 4 ++-- web/lib/personnel/terms.ts | 2 +- web/lib/recent/service.ts | 12 +++++----- web/lib/recent/track.ts | 2 +- web/lib/redaction.ts | 4 ++-- web/lib/search/query.ts | 2 +- web/lib/search/service.ts | 18 +++++++------- web/lib/search/views.ts | 4 ++-- web/lib/sections/render.ts | 2 +- web/lib/templates/fields.ts | 12 +++++----- web/lib/templates/schema.ts | 2 +- web/lib/uuidv7.ts | 2 +- web/tests/abteilungen.test.ts | 2 +- web/tests/aktenblatt.test.ts | 2 +- web/tests/anhaenge.test.ts | 4 ++-- web/tests/benachrichtigungen.test.ts | 2 +- web/tests/beteiligte-anlegen.test.ts | 4 ++-- web/tests/chat.test.ts | 6 ++--- web/tests/dateitypen.test.ts | 6 ++--- web/tests/design-tokens.test.ts | 2 +- web/tests/dokumente.test.ts | 2 +- web/tests/einschleusen.test.ts | 6 ++--- web/tests/eintragsaenderung.test.ts | 2 +- web/tests/entzug.test.ts | 2 +- web/tests/export.test.ts | 2 +- web/tests/neukodierung.test.ts | 2 +- web/tests/personalakte.test.ts | 6 ++--- web/tests/protokoll.test.ts | 4 ++-- web/tests/schreibgrenzen.test.ts | 2 +- web/tests/schwaerzung-sql.test.ts | 2 +- web/tests/suche.test.ts | 4 ++-- web/tests/thema-vorab.test.ts | 4 ++-- web/tests/thema.test.ts | 4 ++-- web/tests/uebersicht.test.ts | 2 +- web/tests/uuidv7.test.ts | 2 +- web/tests/verknuepfungen.test.ts | 2 +- web/tests/zugriff.test.ts | 2 +- web/tests/zuletzt-geoeffnet.test.ts | 4 ++-- worker/src/env.ts | 2 +- worker/src/notify.ts | 6 ++--- worker/src/sync.ts | 6 ++--- worker/tests/mitgliedschaft.test.ts | 2 +- worker/tests/nachricht.test.ts | 2 +- 210 files changed, 368 insertions(+), 368 deletions(-) diff --git a/.env.example b/.env.example index 6879553..c4fe942 100644 --- a/.env.example +++ b/.env.example @@ -1,4 +1,4 @@ -# AfiS-Aktensystem — Vorlage für den .env-Reiter in Dockge. +# AfiS-Aktensystem - Vorlage für den .env-Reiter in Dockge. # Diese Datei enthält nur Platzhalter. Die echten Werte gehören nach # /opt/stacks/afis/.env und niemals ins Repository. Siehe docs/11-betrieb.md. diff --git a/README.md b/README.md index 424c54f..795d976 100644 --- a/README.md +++ b/README.md @@ -22,14 +22,14 @@ gehostet. Keine Mandantentrennung, keine öffentliche Registrierung. ## Zusicherungen Acht Regeln, die im Code und wo möglich in der Datenbank durchgesetzt sind. Sie sind der -Grund, warum das System so gebaut ist, wie es gebaut ist — Codekommentare verweisen unter +Grund, warum das System so gebaut ist, wie es gebaut ist - Codekommentare verweisen unter ihrer Nummer hierher. 1. **Berechtigungsprüfung immer serverseitig und immer in der Datenbankabfrage.** Niemals alle Datensätze laden und danach filtern. 2. **Verlaufseinträge dürfen nachträglich geändert werden, aber niemals unsichtbar.** Jede Änderung erzeugt eine Version, jede Zurücknahme lässt einen Grabstein stehen, beides ist - für alle sichtbar, die den Eintrag sehen dürfen. Es gibt kein `DELETE` — das steht als + für alle sichtbar, die den Eintrag sehen dürfen. Es gibt kein `DELETE` - das steht als Regel in der Datenbank, nicht nur in der Anwendung. 3. **Jede schreibende Aktion und jeder Lesezugriff ab Stufe 3 erzeugt einen Protokolleintrag.** @@ -64,7 +64,7 @@ Container. ## Einrichten Discord-Application anlegen, Bot auf den Server einladen und **Server Members Intent -aktivieren** — ohne das liefert der Bot keine Rollen. +aktivieren** - ohne das liefert der Bot keine Rollen. ## Lokal entwickeln diff --git a/compose.yaml b/compose.yaml index 7492cfc..afea50a 100644 --- a/compose.yaml +++ b/compose.yaml @@ -1,4 +1,4 @@ -# AfiS-Aktensystem — ein einziger Dockge-Stack. +# AfiS-Aktensystem - ein einziger Dockge-Stack. # Ablage: /opt/stacks/afis/compose.yaml, .env im eigenen Dockge-Reiter. # Begründung der Entscheidungen in docs/11-betrieb.md: # - keine Einmal- und keine Init-Container, Dockge zeigt beendete Container nicht diff --git a/packages/db/prisma/migrations/20260902160000_personalakten_und_dokumente/migration.sql b/packages/db/prisma/migrations/20260902160000_personalakten_und_dokumente/migration.sql index 0853df6..34056d1 100644 --- a/packages/db/prisma/migrations/20260902160000_personalakten_und_dokumente/migration.sql +++ b/packages/db/prisma/migrations/20260902160000_personalakten_und_dokumente/migration.sql @@ -211,7 +211,7 @@ $$ LANGUAGE sql STABLE; -- Wie bei case_refresh_search_vector: mit IF verzweigt, nicht mit einem -- CASE-Ausdruck. Der würde auch im nicht genommenen Zweig verlangen, dass --- NEW."documentId" existiert — auf "Document" gibt es das Feld nicht. +-- NEW."documentId" existiert - auf "Document" gibt es das Feld nicht. CREATE OR REPLACE FUNCTION document_refresh_search_vector() RETURNS trigger AS $$ DECLARE target text; diff --git a/packages/db/prisma/migrations/20260903140000_suche/migration.sql b/packages/db/prisma/migrations/20260903140000_suche/migration.sql index 7a5f80b..c68acb8 100644 --- a/packages/db/prisma/migrations/20260903140000_suche/migration.sql +++ b/packages/db/prisma/migrations/20260903140000_suche/migration.sql @@ -41,7 +41,7 @@ ALTER TABLE "SavedView" ADD CONSTRAINT "SavedView_userId_fkey" -- Schwärzungen stufenweise auflösen -- -- `strip_redactions` entfernt jede markierte Stelle. Für den Vektor einer --- Stufe muss aber stehen bleiben, was diese Stufe lesen darf — sonst findet +-- Stufe muss aber stehen bleiben, was diese Stufe lesen darf - sonst findet -- ein Leser der Stufe 4 einen Namen nicht, den er auf der Seite sieht. -- =========================================================================== diff --git a/packages/db/prisma/migrations/20260903200000_messwerte/migration.sql b/packages/db/prisma/migrations/20260903200000_messwerte/migration.sql index 7b2ec7d..0050125 100644 --- a/packages/db/prisma/migrations/20260903200000_messwerte/migration.sql +++ b/packages/db/prisma/migrations/20260903200000_messwerte/migration.sql @@ -1,6 +1,6 @@ -- Phase 9: Ladewerte messen. -- --- Nur Zahlen und das Routenmuster. Keine Kennungen, keine konkreten Pfade — +-- Nur Zahlen und das Routenmuster. Keine Kennungen, keine konkreten Pfade - -- die Messung soll sagen, ob die Anwendung schnell ist, nicht wer wann welche -- Akte geöffnet hat. Siehe docs/09-performance-und-ux.md. diff --git a/packages/db/prisma/migrations/20260903220000_zuletzt_geoeffnet/migration.sql b/packages/db/prisma/migrations/20260903220000_zuletzt_geoeffnet/migration.sql index 27732af..daa162c 100644 --- a/packages/db/prisma/migrations/20260903220000_zuletzt_geoeffnet/migration.sql +++ b/packages/db/prisma/migrations/20260903220000_zuletzt_geoeffnet/migration.sql @@ -2,7 +2,7 @@ -- -- Eine persönliche Sprungliste, kein Verlauf: je Nutzer und Datensatz genau -- eine Zeile, die beim nächsten Öffnen überschrieben wird. Der Primärschlüssel --- erzwingt das — es gibt keine Form, in der diese Tabelle sagen könnte, wie oft +-- erzwingt das - es gibt keine Form, in der diese Tabelle sagen könnte, wie oft -- oder in welcher Reihenfolge jemand etwas geöffnet hat. -- -- Wer wann was gelesen hat, beantwortet weiterhin allein das Zugriffsprotokoll diff --git a/packages/db/prisma/migrations/20260903230000_chat_in_der_akte/migration.sql b/packages/db/prisma/migrations/20260903230000_chat_in_der_akte/migration.sql index 2602af8..4ccced5 100644 --- a/packages/db/prisma/migrations/20260903230000_chat_in_der_akte/migration.sql +++ b/packages/db/prisma/migrations/20260903230000_chat_in_der_akte/migration.sql @@ -9,7 +9,7 @@ -- Zeitpunkt dieser Migration stand in keinem Kanal eine Nachricht. -- Die Nachrichtentabelle ist gegen DELETE gesperrt. Für das einmalige --- Aufräumen wird die Regel abgenommen und danach wieder gesetzt — sie ist die +-- Aufräumen wird die Regel abgenommen und danach wieder gesetzt - sie ist die -- Zusicherung, dass niemand im Betrieb Nachrichten verschwinden lässt. DROP RULE chat_no_delete ON "ChatMessage"; diff --git a/packages/db/prisma/migrations/20260904090000_taeter_und_mittaeter/migration.sql b/packages/db/prisma/migrations/20260904090000_taeter_und_mittaeter/migration.sql index 902c26b..5835fa3 100644 --- a/packages/db/prisma/migrations/20260904090000_taeter_und_mittaeter/migration.sql +++ b/packages/db/prisma/migrations/20260904090000_taeter_und_mittaeter/migration.sql @@ -2,7 +2,7 @@ -- -- Damit wird eine Lücke sichtbar, die es schon vorher gab: ein Beteiligter darf -- die Akte lesen, gleich in welcher Rolle. Bei „Betroffener" fiel das nicht auf, --- bei „Täter" wäre es offensichtlich falsch — der Beschuldigte läse die +-- bei „Täter" wäre es offensichtlich falsch - der Beschuldigte läse die -- Ermittlung gegen sich selbst mit. -- -- Die Prüfung in lib/access/caseFilter.ts unterscheidet deshalb ab jetzt diff --git a/packages/db/prisma/migrations/20260904100000_abteilungen/migration.sql b/packages/db/prisma/migrations/20260904100000_abteilungen/migration.sql index f68b2eb..70d8779 100644 --- a/packages/db/prisma/migrations/20260904100000_abteilungen/migration.sql +++ b/packages/db/prisma/migrations/20260904100000_abteilungen/migration.sql @@ -1,7 +1,7 @@ -- Abteilungen: die Ebene über der Personalakte. -- -- Bisher stand die Abteilung als Freitext in der Personalakte. Damit liess sich --- niemand fragen, was es zu einer Abteilung insgesamt gibt — jede Schreibweise +-- niemand fragen, was es zu einer Abteilung insgesamt gibt - jede Schreibweise -- war eine eigene Abteilung. Als eigenes Modell ist sie verwaltbar, und die -- Zuordnung einer Fallakte ergibt sich aus ihren Beteiligten und deren -- Personalakten. Eine Fallakte trägt deshalb **keine** Abteilung: die @@ -28,7 +28,7 @@ CREATE INDEX "Department_isArchived_name_idx" ON "Department"("isArchived", "nam ALTER TABLE "PersonnelFile" ADD COLUMN "departmentId" TEXT; -- Was schon als Freitext dastand, wird zur Abteilung. Der Schlüssel ist der --- getrimmte Text in Grossbuchstaben, der Name der Text selbst — beides lässt +-- getrimmte Text in Grossbuchstaben, der Name der Text selbst - beides lässt -- sich im Adminbereich nachziehen. INSERT INTO "Department" ("id", "key", "name", "updatedAt") SELECT gen_random_uuid()::text, @@ -125,7 +125,7 @@ CREATE INDEX "PersonnelFile_departmentId_idx" ON "PersonnelFile"("departmentId") -- Abteilung als dritter Besitzer wäre eine halbe Sache: die Vorlagen kennen -- über TemplateUse nur die beiden Orte, und ein Feld, das nichts füllen kann, -- ist schlimmer als keins. Was zu einer Abteilung an Dokumenten gehört, wird --- wie alles andere abgeleitet — über ihre Mitglieder und deren Fälle. +-- wie alles andere abgeleitet - über ihre Mitglieder und deren Fälle. -- Der Chat bekommt einen dritten Ort. Der CHECK aus der vorigen Migration wird -- entsprechend erweitert: genau einer, weiterhin. @@ -161,7 +161,7 @@ $$ LANGUAGE plpgsql; -- Dieselben Zusicherungen wie beim Verlauf einer Akte (harte Regel 2): kein -- DELETE, jede Änderung erzeugt eine Version, jede Zurücknahme lässt einen -- Grabstein stehen. Die Regeln stehen in der Datenbank und nicht nur in der --- Anwendung — die Anwendung kann man umgehen. +-- Anwendung - die Anwendung kann man umgehen. -- =========================================================================== CREATE TABLE "DepartmentEntry" ( @@ -216,7 +216,7 @@ CREATE RULE dept_entry_version_no_delete AS ON DELETE TO "DepartmentEntryVersion" DO INSTEAD NOTHING; -- Autor, Entstehungszeit und Abteilung sind unantastbar. Wer etwas anderes --- sagen will, zieht zurück und schreibt neu — und genau das ist dann sichtbar. +-- sagen will, zieht zurück und schreibt neu - und genau das ist dann sichtbar. CREATE OR REPLACE FUNCTION dept_entry_immutable_guard() RETURNS trigger AS $$ BEGIN IF NEW."authorId" IS DISTINCT FROM OLD."authorId" diff --git a/packages/db/prisma/migrations/20260904120000_beteiligte_in_der_suche/migration.sql b/packages/db/prisma/migrations/20260904120000_beteiligte_in_der_suche/migration.sql index a27d514..d385f14 100644 --- a/packages/db/prisma/migrations/20260904120000_beteiligte_in_der_suche/migration.sql +++ b/packages/db/prisma/migrations/20260904120000_beteiligte_in_der_suche/migration.sql @@ -1,7 +1,7 @@ -- Beteiligte in den Suchindex der Fallakte. -- -- Wer nach einem Namen sucht, will die Akten finden, in denen die Person --- vorkommt — auch dann, wenn sie weder im Titel steht noch im Text erwähnt +-- vorkommt - auch dann, wenn sie weder im Titel steht noch im Text erwähnt -- wird, sondern nur als Zeuge oder Betroffener eingetragen ist. -- -- Das verrät nichts Neues: der Name eines Beteiligten steht ohnehin in der @@ -74,7 +74,7 @@ END; $$ LANGUAGE plpgsql; -- Der Verteiler kennt zwei neue Anlässe: eine geänderte Beteiligung, und einen --- geänderten Namen. Beim Namen sind alle Akten der Person betroffen — sonst +-- geänderten Namen. Beim Namen sind alle Akten der Person betroffen - sonst -- fände die Suche nach einer Umbenennung weiter den alten Namen. CREATE OR REPLACE FUNCTION search_index_trigger() RETURNS trigger AS $$ DECLARE diff --git a/packages/db/prisma/schema.prisma b/packages/db/prisma/schema.prisma index b5ef069..82886e4 100644 --- a/packages/db/prisma/schema.prisma +++ b/packages/db/prisma/schema.prisma @@ -1,4 +1,4 @@ -// AfiS-Aktensystem — Datenmodell +// AfiS-Aktensystem - Datenmodell // Fachliche Grundlage: docs/04-datenmodell.md // // Konventionen: @@ -113,7 +113,7 @@ model RoleMapping { } enum RoleCategory { - /// "AfiS", "Personalabteilung" — regelt, wer sich anmelden darf + /// "AfiS", "Personalabteilung" - regelt, wer sich anmelden darf MEMBERSHIP /// Dienstgrade, regeln die Rechte RANK @@ -202,9 +202,9 @@ enum TemplateUse { /// Bauform des Dokuments, siehe docs/13-entscheidungen.md. enum DocumentLayout { - /// beschriftete Felder, ausgefuellt — der Vorfallsbericht + /// beschriftete Felder, ausgefuellt - der Vorfallsbericht FORM - /// fester Wortlaut mit Platzhaltern, mehrseitig — der Sonderarbeitsvertrag + /// fester Wortlaut mit Platzhaltern, mehrseitig - der Sonderarbeitsvertrag PROSE /// ein einzelnes Freitextfeld, dargestellt wie ein Vermerk NOTE @@ -415,7 +415,7 @@ model CaseParticipant { /// Zwei Gruppen, und der Unterschied entscheidet ueber den Zugriff: LEAD, /// INVESTIGATOR und OBSERVER **arbeiten** an der Akte und duerfen sie deshalb /// lesen. WITNESS, SUBJECT, SUSPECT und ACCOMPLICE sind Angaben **ueber** den -/// Fall und verschaffen keinen Zugang — sonst laese der Beschuldigte die +/// Fall und verschaffen keinen Zugang - sonst laese der Beschuldigte die /// Ermittlung gegen sich selbst mit. Siehe lib/cases/terms.ts. enum ParticipantRole { LEAD @@ -467,8 +467,8 @@ enum LinkKind { // Personalakten // --------------------------------------------------------------------------- -/// Akte zu einer Person. Ueberwiegend zu **Externen** — Sicherheitsdienst, -/// Zeugen, Vertragspartner — die kein Discord-Konto haben. `userId` bleibt +/// Akte zu einer Person. Ueberwiegend zu **Externen** - Sicherheitsdienst, +/// Zeugen, Vertragspartner - die kein Discord-Konto haben. `userId` bleibt /// deshalb der Ausnahmefall, nicht die Regel. model PersonnelFile { id String @id @default(uuid(7)) @@ -512,7 +512,7 @@ model PersonnelFile { } /// Auswahl der Status-Etiketten, im Adminbereich pflegbar. Die Namen sind -/// Daten, keine Oberflaechentexte — siehe die Sprachkonvention: Code englisch, Oberflaeche deutsch. +/// Daten, keine Oberflaechentexte - siehe die Sprachkonvention: Code englisch, Oberflaeche deutsch. model PersonnelStatusTag { key String @id // "tot", "gekuendigt" name String // "Tot", "Gekuendigt" @@ -554,7 +554,7 @@ enum AssignmentRole { } /// Die Freigabestufen der Foundation, wie sie im Kopf eines Dokuments stehen. -/// **Sie steuern keinen Zugriff** — das tut allein ClearanceLevelConfig. +/// **Sie steuern keinen Zugriff** - das tut allein ClearanceLevelConfig. /// Siehe docs/13-entscheidungen.md, "Zwei Freigaben im Kopf". model FoundationClearance { level Int @id // 1..5 @@ -849,7 +849,7 @@ model NotificationOutbox { /// /// Fast jede Person gehoert einer an, und die Abteilung ist die Ebene ueber /// der Personalakte: was zu ihr aktenkundig ist, ergibt sich aus ihren -/// Mitgliedern. Deshalb traegt eine Fallakte **keine** Abteilung — die +/// Mitgliedern. Deshalb traegt eine Fallakte **keine** Abteilung - die /// Zuordnung entsteht ueber die Beteiligten und deren Personalakten und ist /// damit immer aktuell. Siehe docs/13-entscheidungen.md. model Department { @@ -881,7 +881,7 @@ model Department { /// Dieselbe Zusicherung wie beim Verlauf einer Akte, in schmalerer Form: es /// gibt kein DELETE, jede Aenderung erzeugt eine Version, jede Zuruecknahme /// laesst einen Grabstein stehen. Was fehlt, sind die Teile, die nur eine -/// Ermittlung braucht — Korrekturkette, Anhaenge, Karenzzeit. Ein +/// Ermittlung braucht - Korrekturkette, Anhaenge, Karenzzeit. Ein /// Abteilungsvermerk ist ein laufendes Protokoll, kein Beweismittel. model DepartmentEntry { id String @id // clientseitig erzeugt, UUIDv7 @@ -926,7 +926,7 @@ model DepartmentEntryVersion { /// Der Vektor zur Stufe N enthaelt alles, was ein Leser dieser Stufe sehen /// darf: Kopfdaten, Abschnitte und Eintraege bis einschliesslich N, und aus /// dem Fliesstext die geschwaerzten Stellen bis N. Eine Suche nimmt genau -/// eine Zeile — die zur Stufe des Suchenden — und kann deshalb nichts finden, +/// eine Zeile - die zur Stufe des Suchenden - und kann deshalb nichts finden, /// was er nicht lesen darf. /// /// Der Vorgaenger war ein einziger Vektor mit nur dem, was jeder sehen darf. diff --git a/packages/db/prisma/seed.ts b/packages/db/prisma/seed.ts index c6ce4e2..70dd725 100644 --- a/packages/db/prisma/seed.ts +++ b/packages/db/prisma/seed.ts @@ -29,7 +29,7 @@ const CLEARANCE_LEVELS = [ /** * Startvorlagen nach docs/05-akten-und-vorlagen.md. Die Feldschlüssel sind - * stabil und werden nie geändert — eine Akte merkt sich ihre Vorlage über + * stabil und werden nie geändert - eine Akte merkt sich ihre Vorlage über * `templateId`, und eine neue Vorlagenversion lässt bestehende Akten unberührt. * * Der Zuschnitt der Felder ist bewusst schmal gehalten: den Vorlagen-Editor @@ -75,7 +75,7 @@ const TEMPLATES: Vorlage[] = [ const TEMPLATE_FIELDS = [ // Nachgebaut nach dem Vorfallsbericht der Abteilung. Die Foundation-Freigabe - // steht im Kopf des Dokuments, steuert aber keinen Zugriff — das tut allein + // steht im Kopf des Dokuments, steuert aber keinen Zugriff - das tut allein // die interne Freigabe. Siehe docs/13-entscheidungen.md. { key: 'foundation_freigabe', @@ -200,7 +200,7 @@ const PERSONALAKTE_FIELDS = [ /** * Dokumentarten. Sie hängen an einer Fallakte, an einer Personalakte oder an - * nichts — was davon, steht in `uses`. Eine weitere Art anzulegen ist ein + * nichts - was davon, steht in `uses`. Eine weitere Art anzulegen ist ein * Datensatz, kein Deployment: der Vorlagen-Editor reicht. * Siehe docs/13-entscheidungen.md. */ @@ -367,7 +367,7 @@ async function main(): Promise { isActive: true, }, // Version 1 gehört dem Seed und wird von ihm aktuell gehalten. Ändert - // der Leiter eine Vorlage im Editor, entsteht Version 2 — die fasst der + // der Leiter eine Vorlage im Editor, entsteht Version 2 - die fasst der // Seed nie an, und bestehende Akten behalten ohnehin ihre Version. update: { name: template.name, diff --git a/packages/db/scripts/prepare-test-db.mjs b/packages/db/scripts/prepare-test-db.mjs index 11f0f1b..dd7f9de 100644 --- a/packages/db/scripts/prepare-test-db.mjs +++ b/packages/db/scripts/prepare-test-db.mjs @@ -10,7 +10,7 @@ import { resolveTestDatabaseUrl } from '../dist/testDatabase.js' * Wird von `pnpm test` vorgeschaltet. * * **Neu aufsetzen, nicht nur anlegen.** Verlaufseinträge, Akten und - * Protokollzeilen sind nach Zusicherung 2 der README nicht löschbar — was + * Protokollzeilen sind nach Zusicherung 2 der README nicht löschbar - was * ein Testlauf anlegt, bleibt für immer stehen. Nach einigen Dutzend Läufen * standen 2487 Akten in der Datenbank, und Tests, die eine auf zehn Einträge * begrenzte Liste prüfen, fanden ihre eigene Akte nicht mehr darin. Solche @@ -45,7 +45,7 @@ try { const behalten = process.env.KEEP_TEST_DB === '1' if (rowCount > 0 && !behalten) { - // Offene Verbindungen verhindern das Verwerfen — etwa ein Prisma Studio + // Offene Verbindungen verhindern das Verwerfen - etwa ein Prisma Studio // oder ein abgebrochener Testlauf. await client.query( `SELECT pg_terminate_backend(pid) FROM pg_stat_activity @@ -87,7 +87,7 @@ execFileSync(process.execPath, [tsxCli, 'prisma/seed.ts'], { // Die Änderungsrichtlinie ist eine einzige Zeile für die ganze Anwendung. Der // Seed lässt sie bewusst in Ruhe, damit er die Einstellung des Leiters nicht -// überschreibt — in der Testdatenbank soll sie aber bei jedem Lauf im +// überschreibt - in der Testdatenbank soll sie aber bei jedem Lauf im // Auslieferungszustand starten, sonst hängt das Ergebnis davon ab, was der // vorige Lauf hinterlassen hat. const reset = new pg.Client({ connectionString: testUrl }) diff --git a/packages/db/src/testDatabase.ts b/packages/db/src/testDatabase.ts index ea0de39..4a3736d 100644 --- a/packages/db/src/testDatabase.ts +++ b/packages/db/src/testDatabase.ts @@ -33,7 +33,7 @@ export function resolveTestDatabaseUrl(source = process.env.DATABASE_URL): strin /** * Setzt die Umgebung eines Testlaufs auf die Testdatenbank um. Muss laufen, - * bevor irgendein Modul einen Prisma-Client baut — deshalb gehört der Aufruf + * bevor irgendein Modul einen Prisma-Client baut - deshalb gehört der Aufruf * in die `setupFiles` von Vitest, nicht in eine einzelne Testdatei. */ export function switchToTestDatabase(): string { diff --git a/packages/db/tests/auslieferungszustand.test.ts b/packages/db/tests/auslieferungszustand.test.ts index 979ee7a..b87dd1a 100644 --- a/packages/db/tests/auslieferungszustand.test.ts +++ b/packages/db/tests/auslieferungszustand.test.ts @@ -48,7 +48,7 @@ suite('Auslieferungszustand', () => { // Der Seed vergibt keine Rechte. Rollen kommen ausschliesslich aus dem // Abgleich des Workers und werden im Adminbereich zugeordnet. // Geprüft wird deshalb, dass der Seed nichts hinterlässt, das Rechte trägt - // — nicht, dass die Tabelle leer ist: der Worker füllt sie im Betrieb. + // - nicht, dass die Tabelle leer ist: der Worker füllt sie im Betrieb. const mitRechten = await db.roleMapping.findMany({ where: { permissions: { isEmpty: false } }, select: { label: true, permissions: true }, diff --git a/packages/db/tests/regeln.test.ts b/packages/db/tests/regeln.test.ts index f5dfb05..0024adb 100644 --- a/packages/db/tests/regeln.test.ts +++ b/packages/db/tests/regeln.test.ts @@ -240,7 +240,7 @@ suite('Datenbankregeln', () => { }) it('löst Schwärzungen im Suchindex stufenweise auf', async () => { - // Der Vektor zur Stufe N muss enthalten, was diese Stufe lesen darf — und + // Der Vektor zur Stufe N muss enthalten, was diese Stufe lesen darf - und // nichts darüber. Sonst findet ein Leser der Stufe 4 einen Namen nicht, // den er auf der Seite sieht, oder ein Leser der Stufe 1 einen, den er // dort nur als Balken sieht. diff --git a/packages/db/tests/schema-drift.test.ts b/packages/db/tests/schema-drift.test.ts index 87d4fad..e2d8e94 100644 --- a/packages/db/tests/schema-drift.test.ts +++ b/packages/db/tests/schema-drift.test.ts @@ -8,7 +8,7 @@ import path from 'node:path' * Der Anlass war handfest: ein von Hand angelegter GIN-Index über den * Suchvektor stand in der Migration, aber nicht in `schema.prisma`. Prisma * hielt das für einen Rückstand und fragte bei jedem `migrate dev` nach einem - * Namen für eine neue Migration — deren Inhalt gewesen wäre, **den Suchindex + * Namen für eine neue Migration - deren Inhalt gewesen wäre, **den Suchindex * zu löschen**. Wer die Frage in Eile beantwortet, verliert die gestufte * Volltextsuche und merkt es erst, wenn die Suche leer bleibt. * diff --git a/scripts/restore-test.sh b/scripts/restore-test.sh index d68af46..bc58024 100755 --- a/scripts/restore-test.sh +++ b/scripts/restore-test.sh @@ -1,6 +1,6 @@ #!/usr/bin/env bash # Spielt eine Sicherung in eine Wegwerf-Datenbank ein und prüft, ob alles -# angekommen ist. Ein ungetestetes Backup ist keins — siehe docs/11-betrieb.md. +# angekommen ist. Ein ungetestetes Backup ist keins - siehe docs/11-betrieb.md. # # scripts/restore-test.sh [container] [quelldatenbank] # diff --git a/start.sh b/start.sh index 1357e1b..4ca91ce 100755 --- a/start.sh +++ b/start.sh @@ -98,7 +98,7 @@ mkdir -p "${FILES_DIR_LOKAL}/quarantine" "${FILES_DIR_LOKAL}/store" info "Dateiablage unter ${FILES_DIR_LOKAL}" # Die Prüfkette braucht beides. Fehlt eines, bleiben die betroffenen Uploads in -# der Quarantäne — sie gehen nicht ungeprüft durch. Siehe docs/07. +# der Quarantäne - sie gehen nicht ungeprüft durch. Siehe docs/07. CLAMAV_SOCKET_LOKAL="$(grep -E '^CLAMAV_SOCKET=' .env 2>/dev/null | cut -d= -f2- || true)" [ -S "${CLAMAV_SOCKET_LOKAL:-/var/run/clamav/clamd.sock}" ] \ || warn "Kein clamd erreichbar: Uploads landen auf 'Prüfung unvollständig' und brauchen die Freigabe von Hand" diff --git a/web/app/(app)/abteilungen/[key]/loading.tsx b/web/app/(app)/abteilungen/[key]/loading.tsx index 5ad90b9..805617a 100644 --- a/web/app/(app)/abteilungen/[key]/loading.tsx +++ b/web/app/(app)/abteilungen/[key]/loading.tsx @@ -2,7 +2,7 @@ import { Skeleton, SkeletonLine } from '@/components/Skeleton' /** * Skelett statt Spinner: die Struktur steht sofort, die Daten fallen hinein. - * Ohne diese Grenze wartet die Navigation stumm, bis der Server fertig ist — + * Ohne diese Grenze wartet die Navigation stumm, bis der Server fertig ist - * man klickt und es passiert scheinbar nichts. Siehe docs/09-performance-und-ux.md. */ export default function Loading() { diff --git a/web/app/(app)/abteilungen/[key]/page.tsx b/web/app/(app)/abteilungen/[key]/page.tsx index 2c1e960..6398c7e 100644 --- a/web/app/(app)/abteilungen/[key]/page.tsx +++ b/web/app/(app)/abteilungen/[key]/page.tsx @@ -39,7 +39,7 @@ export async function generateMetadata({ * * Dasselbe Bild wie eine Personalakte, eine Stufe höher: wer gehört dazu, was * ist dazu aktenkundig, was ist dazu vermerkt, und worüber wird geredet. Der - * Unterschied ist, dass hier **nichts eingetragen** wird — die Fälle ergeben + * Unterschied ist, dass hier **nichts eingetragen** wird - die Fälle ergeben * sich aus den Beteiligten und deren Personalakten. */ export default async function DepartmentPage({ params }: { params: Promise<{ key: string }> }) { diff --git a/web/app/(app)/abteilungen/page.tsx b/web/app/(app)/abteilungen/page.tsx index eb0a356..a0e3fa4 100644 --- a/web/app/(app)/abteilungen/page.tsx +++ b/web/app/(app)/abteilungen/page.tsx @@ -14,7 +14,7 @@ export const dynamic = 'force-dynamic' * * Das Diagramm beantwortet die Frage, mit der man auf diese Seite kommt: zu * welcher Abteilung gibt es die meisten Fälle. Gezählt wird nur, was der - * Fragende auch sehen darf — eine Zahl, die mehr zählt als seine Liste + * Fragende auch sehen darf - eine Zahl, die mehr zählt als seine Liste * hergibt, wäre selbst eine Auskunft. */ export default async function DepartmentsPage() { diff --git a/web/app/(app)/admin/abteilungen/DepartmentForm.tsx b/web/app/(app)/admin/abteilungen/DepartmentForm.tsx index 33b6278..82089c9 100644 --- a/web/app/(app)/admin/abteilungen/DepartmentForm.tsx +++ b/web/app/(app)/admin/abteilungen/DepartmentForm.tsx @@ -23,7 +23,7 @@ type Existing = { * * Das Kürzel steht nach dem Anlegen fest: es steckt in der Adresse jeder * Abteilungsseite, und ein wandernder Bezeichner macht geteilte Links wertlos. - * Wer sich vertan hat, legt neu an und archiviert die alte — archivieren + * Wer sich vertan hat, legt neu an und archiviert die alte - archivieren * statt löschen, weil an einer Abteilung Vermerke und Zuordnungen hängen. */ export function DepartmentForm({ diff --git a/web/app/(app)/admin/abteilungen/loading.tsx b/web/app/(app)/admin/abteilungen/loading.tsx index 76c3dba..529e7dd 100644 --- a/web/app/(app)/admin/abteilungen/loading.tsx +++ b/web/app/(app)/admin/abteilungen/loading.tsx @@ -2,7 +2,7 @@ import { Skeleton, SkeletonLine } from '@/components/Skeleton' /** * Skelett statt Spinner: die Struktur steht sofort, die Daten fallen hinein. - * Ohne diese Grenze wartet die Navigation stumm, bis der Server fertig ist — + * Ohne diese Grenze wartet die Navigation stumm, bis der Server fertig ist - * man klickt und es passiert scheinbar nichts. Siehe docs/09-performance-und-ux.md. */ export default function Loading() { diff --git a/web/app/(app)/admin/layout.tsx b/web/app/(app)/admin/layout.tsx index e3c1ff0..7f2b0e9 100644 --- a/web/app/(app)/admin/layout.tsx +++ b/web/app/(app)/admin/layout.tsx @@ -12,7 +12,7 @@ export const dynamic = 'force-dynamic' * * Wie bei der Fallakte sind die Bereiche **eigene Seiten** unter einem * gemeinsamen Layout, keine umgeschalteten Blöcke. Wer gar keinen Bereich - * sehen darf, bekommt 404 — die Verwaltung ist für ihn nicht vorhanden. + * sehen darf, bekommt 404 - die Verwaltung ist für ihn nicht vorhanden. */ export default async function AdminLayout({ children }: { children: ReactNode }) { const user = await requireUser() diff --git a/web/app/(app)/admin/loading.tsx b/web/app/(app)/admin/loading.tsx index 76c3dba..529e7dd 100644 --- a/web/app/(app)/admin/loading.tsx +++ b/web/app/(app)/admin/loading.tsx @@ -2,7 +2,7 @@ import { Skeleton, SkeletonLine } from '@/components/Skeleton' /** * Skelett statt Spinner: die Struktur steht sofort, die Daten fallen hinein. - * Ohne diese Grenze wartet die Navigation stumm, bis der Server fertig ist — + * Ohne diese Grenze wartet die Navigation stumm, bis der Server fertig ist - * man klickt und es passiert scheinbar nichts. Siehe docs/09-performance-und-ux.md. */ export default function Loading() { diff --git a/web/app/(app)/admin/page.tsx b/web/app/(app)/admin/page.tsx index 8bf6985..a1f6132 100644 --- a/web/app/(app)/admin/page.tsx +++ b/web/app/(app)/admin/page.tsx @@ -11,7 +11,7 @@ export const dynamic = 'force-dynamic' * Die Startseite der Verwaltung: was es gibt und wofür es da ist. * * Kein Weiterleiten auf den ersten Bereich. Wer die Verwaltung öffnet, weiss - * nicht immer, wo das Gesuchte liegt — eine Liste mit einem Satz je Bereich + * nicht immer, wo das Gesuchte liegt - eine Liste mit einem Satz je Bereich * beantwortet das schneller als das Durchklicken der Leiste. */ export default async function AdminIndexPage() { diff --git a/web/app/(app)/admin/protokoll/loading.tsx b/web/app/(app)/admin/protokoll/loading.tsx index 76c3dba..529e7dd 100644 --- a/web/app/(app)/admin/protokoll/loading.tsx +++ b/web/app/(app)/admin/protokoll/loading.tsx @@ -2,7 +2,7 @@ import { Skeleton, SkeletonLine } from '@/components/Skeleton' /** * Skelett statt Spinner: die Struktur steht sofort, die Daten fallen hinein. - * Ohne diese Grenze wartet die Navigation stumm, bis der Server fertig ist — + * Ohne diese Grenze wartet die Navigation stumm, bis der Server fertig ist - * man klickt und es passiert scheinbar nichts. Siehe docs/09-performance-und-ux.md. */ export default function Loading() { diff --git a/web/app/(app)/admin/richtlinie/actions.ts b/web/app/(app)/admin/richtlinie/actions.ts index 86a78e6..663a738 100644 --- a/web/app/(app)/admin/richtlinie/actions.ts +++ b/web/app/(app)/admin/richtlinie/actions.ts @@ -18,7 +18,7 @@ export type PolicyResult = { ok: true } | { ok: false; error: string } /** * Die Änderungsrichtlinie gilt für die ganze Abteilung und wird serverseitig * gelesen, nie aus dem Request. Deshalb ist das hier die einzige Stelle, an - * der sie sich ändern lässt — mit Recht `admin` und mit Protokolleintrag. + * der sie sich ändern lässt - mit Recht `admin` und mit Protokolleintrag. */ export async function savePolicy(input: unknown): Promise { const user = await requirePermissionForAction('admin') diff --git a/web/app/(app)/admin/richtlinie/loading.tsx b/web/app/(app)/admin/richtlinie/loading.tsx index c42fe2f..6d8e7b2 100644 --- a/web/app/(app)/admin/richtlinie/loading.tsx +++ b/web/app/(app)/admin/richtlinie/loading.tsx @@ -2,7 +2,7 @@ import { Skeleton, SkeletonLine } from '@/components/Skeleton' /** * Skelett statt Spinner: die Struktur steht sofort, die Daten fallen hinein. - * Ohne diese Grenze wartet die Navigation stumm, bis der Server fertig ist — + * Ohne diese Grenze wartet die Navigation stumm, bis der Server fertig ist - * man klickt und es passiert scheinbar nichts. Siehe docs/09-performance-und-ux.md. */ export default function Loading() { diff --git a/web/app/(app)/admin/rollen/loading.tsx b/web/app/(app)/admin/rollen/loading.tsx index 76c3dba..529e7dd 100644 --- a/web/app/(app)/admin/rollen/loading.tsx +++ b/web/app/(app)/admin/rollen/loading.tsx @@ -2,7 +2,7 @@ import { Skeleton, SkeletonLine } from '@/components/Skeleton' /** * Skelett statt Spinner: die Struktur steht sofort, die Daten fallen hinein. - * Ohne diese Grenze wartet die Navigation stumm, bis der Server fertig ist — + * Ohne diese Grenze wartet die Navigation stumm, bis der Server fertig ist - * man klickt und es passiert scheinbar nichts. Siehe docs/09-performance-und-ux.md. */ export default function Loading() { diff --git a/web/app/(app)/admin/rollen/page.tsx b/web/app/(app)/admin/rollen/page.tsx index aa10c9a..1182e2d 100644 --- a/web/app/(app)/admin/rollen/page.tsx +++ b/web/app/(app)/admin/rollen/page.tsx @@ -10,7 +10,7 @@ export const dynamic = 'force-dynamic' /** * Reihenfolge der Abschnitte: erst die Ränge, dann die Zugehörigkeit, dann die - * Zugangsrollen — so, wie die Abteilung sie selbst aufzählt. Innerhalb eines + * Zugangsrollen - so, wie die Abteilung sie selbst aufzählt. Innerhalb eines * Abschnitts entscheidet die Position der Rolle auf dem Discord-Server, oben * die höchste. Damit steht die Hierarchie an einer Stelle, die ohnehin gepflegt * wird, statt in einer zweiten Sortierung in dieser Anwendung. diff --git a/web/app/(app)/admin/sections.ts b/web/app/(app)/admin/sections.ts index ec320c9..b079383 100644 --- a/web/app/(app)/admin/sections.ts +++ b/web/app/(app)/admin/sections.ts @@ -5,7 +5,7 @@ import { de } from '@/lib/i18n/de' * Die Bereiche der Verwaltung, an einer Stelle. * * Vorher standen Rollenverwaltung, Vorlagen und Änderungsrichtlinie als drei - * eigene Einträge in der Kopfzeile — drei Einträge für etwas, das man selten + * eigene Einträge in der Kopfzeile - drei Einträge für etwas, das man selten * und dann meist zusammenhängend braucht. Jetzt ist es ein Eintrag mit einer * Leiste darunter. * diff --git a/web/app/(app)/admin/system/loading.tsx b/web/app/(app)/admin/system/loading.tsx index 76c3dba..529e7dd 100644 --- a/web/app/(app)/admin/system/loading.tsx +++ b/web/app/(app)/admin/system/loading.tsx @@ -2,7 +2,7 @@ import { Skeleton, SkeletonLine } from '@/components/Skeleton' /** * Skelett statt Spinner: die Struktur steht sofort, die Daten fallen hinein. - * Ohne diese Grenze wartet die Navigation stumm, bis der Server fertig ist — + * Ohne diese Grenze wartet die Navigation stumm, bis der Server fertig ist - * man klickt und es passiert scheinbar nichts. Siehe docs/09-performance-und-ux.md. */ export default function Loading() { diff --git a/web/app/(app)/admin/system/page.tsx b/web/app/(app)/admin/system/page.tsx index 080bdf5..18abb32 100644 --- a/web/app/(app)/admin/system/page.tsx +++ b/web/app/(app)/admin/system/page.tsx @@ -97,7 +97,7 @@ export default async function SystemPage() { /** * Die Ladewerte der letzten sieben Tage. Median und 75. Perzentil, kein - * Mittelwert — ein Ausreisser auf einem alten Laptop soll die Zahl nicht + * Mittelwert - ein Ausreisser auf einem alten Laptop soll die Zahl nicht * bestimmen. */ async function VitalsTable() { diff --git a/web/app/(app)/admin/vorlagen/loading.tsx b/web/app/(app)/admin/vorlagen/loading.tsx index 76c3dba..529e7dd 100644 --- a/web/app/(app)/admin/vorlagen/loading.tsx +++ b/web/app/(app)/admin/vorlagen/loading.tsx @@ -2,7 +2,7 @@ import { Skeleton, SkeletonLine } from '@/components/Skeleton' /** * Skelett statt Spinner: die Struktur steht sofort, die Daten fallen hinein. - * Ohne diese Grenze wartet die Navigation stumm, bis der Server fertig ist — + * Ohne diese Grenze wartet die Navigation stumm, bis der Server fertig ist - * man klickt und es passiert scheinbar nichts. Siehe docs/09-performance-und-ux.md. */ export default function Loading() { diff --git a/web/app/(app)/dateien/actions.ts b/web/app/(app)/dateien/actions.ts index a7054d7..676924b 100644 --- a/web/app/(app)/dateien/actions.ts +++ b/web/app/(app)/dateien/actions.ts @@ -13,7 +13,7 @@ const schema = z.object({ id: z.string().min(1) }) /** * Freigabe einer Datei, deren Prüfung nicht abgeschlossen werden konnte. - * Nur mit Recht `admin`, geprüft im Dienst — nicht hier. + * Nur mit Recht `admin`, geprüft im Dienst - nicht hier. */ export async function releaseAttachmentAction(input: unknown): Promise { const user = await requireUser() diff --git a/web/app/(app)/dokumente/[documentNumber]/DocumentActions.tsx b/web/app/(app)/dokumente/[documentNumber]/DocumentActions.tsx index 6be5409..febdcd2 100644 --- a/web/app/(app)/dokumente/[documentNumber]/DocumentActions.tsx +++ b/web/app/(app)/dokumente/[documentNumber]/DocumentActions.tsx @@ -14,7 +14,7 @@ import { * Ausfertigen, Zurückziehen, Umklassifizieren. * * Wie beim Fall bewusst **nicht** optimistisch: alle drei sind folgenreich. - * Das Ausfertigen fragt nach, das Zurückziehen verlangt eine Begründung — es + * Das Ausfertigen fragt nach, das Zurückziehen verlangt eine Begründung - es * gibt kein Löschen, der Grabstein bleibt stehen. */ export function DocumentActions({ diff --git a/web/app/(app)/dokumente/[documentNumber]/export/loading.tsx b/web/app/(app)/dokumente/[documentNumber]/export/loading.tsx index c42fe2f..6d8e7b2 100644 --- a/web/app/(app)/dokumente/[documentNumber]/export/loading.tsx +++ b/web/app/(app)/dokumente/[documentNumber]/export/loading.tsx @@ -2,7 +2,7 @@ import { Skeleton, SkeletonLine } from '@/components/Skeleton' /** * Skelett statt Spinner: die Struktur steht sofort, die Daten fallen hinein. - * Ohne diese Grenze wartet die Navigation stumm, bis der Server fertig ist — + * Ohne diese Grenze wartet die Navigation stumm, bis der Server fertig ist - * man klickt und es passiert scheinbar nichts. Siehe docs/09-performance-und-ux.md. */ export default function Loading() { diff --git a/web/app/(app)/einstellungen/actions.ts b/web/app/(app)/einstellungen/actions.ts index 4bac63a..f637cac 100644 --- a/web/app/(app)/einstellungen/actions.ts +++ b/web/app/(app)/einstellungen/actions.ts @@ -10,7 +10,7 @@ export type ActionResult = { ok: true } | { ok: false; error: string } const schema = z.object({ notifyMode: z.enum(['ALL', 'OWN_CASES', 'MENTIONS', 'OFF']) }) -/** Jeder stellt nur für sich selbst ein — die Kennung kommt aus der Sitzung. */ +/** Jeder stellt nur für sich selbst ein - die Kennung kommt aus der Sitzung. */ export async function saveNotifyModeAction( _prev: ActionResult | null, formData: FormData, diff --git a/web/app/(app)/einstellungen/loading.tsx b/web/app/(app)/einstellungen/loading.tsx index 5be3f4d..ac4fa81 100644 --- a/web/app/(app)/einstellungen/loading.tsx +++ b/web/app/(app)/einstellungen/loading.tsx @@ -2,7 +2,7 @@ import { Skeleton } from '@/components/Skeleton' /** * Skelett statt Spinner: die Struktur steht sofort, die Daten fallen hinein. - * Ohne diese Grenze wartet die Navigation stumm, bis der Server fertig ist — + * Ohne diese Grenze wartet die Navigation stumm, bis der Server fertig ist - * man klickt und es passiert scheinbar nichts. Siehe docs/09-performance-und-ux.md. */ export default function Loading() { diff --git a/web/app/(app)/export/actions.ts b/web/app/(app)/export/actions.ts index d056ce1..6a82d29 100644 --- a/web/app/(app)/export/actions.ts +++ b/web/app/(app)/export/actions.ts @@ -28,7 +28,7 @@ const requestSchema = z.union([ /** * Export anfordern. * - * Der Auftrag läuft im Hintergrund weiter, nachdem die Antwort raus ist — das + * Der Auftrag läuft im Hintergrund weiter, nachdem die Antwort raus ist - das * Rendern dauert, und niemand soll auf einen Fortschrittsbalken starren, der * auf Playwright wartet. Siehe docs/09-performance-und-ux.md. */ diff --git a/web/app/(app)/faelle/[caseNumber]/CaseActions.tsx b/web/app/(app)/faelle/[caseNumber]/CaseActions.tsx index 5b446eb..697e1af 100644 --- a/web/app/(app)/faelle/[caseNumber]/CaseActions.tsx +++ b/web/app/(app)/faelle/[caseNumber]/CaseActions.tsx @@ -90,7 +90,7 @@ export function CaseActions({ {/* Welche Zustände von hier aus erreichbar sind, ergibt sich aus dem - Lebenszyklus — aus einem Entwurf führt nur „Offen" heraus. Ohne + Lebenszyklus - aus einem Entwurf führt nur „Offen" heraus. Ohne diesen Satz sieht die kurze Auswahl aus wie ein Fehler. */}

{caseText.statusHints[nextStatus] ?? caseText.statusChangeHint} diff --git a/web/app/(app)/faelle/[caseNumber]/Participants.tsx b/web/app/(app)/faelle/[caseNumber]/Participants.tsx index 7114600..1f1bb5b 100644 --- a/web/app/(app)/faelle/[caseNumber]/Participants.tsx +++ b/web/app/(app)/faelle/[caseNumber]/Participants.tsx @@ -113,7 +113,7 @@ export function Participants({ ))} - + {members.map((member) => ( - + {members.map((member) => (

{label}
-
{value || '—'}
+
{value || '-'}
) } diff --git a/web/app/(app)/personalakten/[id]/page.tsx b/web/app/(app)/personalakten/[id]/page.tsx index f071188..c2220c5 100644 --- a/web/app/(app)/personalakten/[id]/page.tsx +++ b/web/app/(app)/personalakten/[id]/page.tsx @@ -171,7 +171,7 @@ async function AssignmentBlock({ * dass das Gespräch bei ihrer Akte steht, war genau das, was vorher auf * Discord passiert ist. Siehe docs/13-entscheidungen.md. * - * Übernehmen als Vermerk gibt es hier nicht — dafür braucht es einen Verlauf, + * Übernehmen als Vermerk gibt es hier nicht - dafür braucht es einen Verlauf, * und den führt nur die Fallakte. */ async function ChatBlock({ diff --git a/web/app/(app)/personalakten/actions.ts b/web/app/(app)/personalakten/actions.ts index 50ee2a1..525afc3 100644 --- a/web/app/(app)/personalakten/actions.ts +++ b/web/app/(app)/personalakten/actions.ts @@ -71,7 +71,7 @@ export async function createPersonnelAction( id = created.id // Das Aktenblatt ist der erste Eintrag zu einer Person und entsteht - // deshalb gleich mit — als Entwurf, mit dem Namen schon eingetragen. + // deshalb gleich mit - als Entwurf, mit dem Namen schon eingetragen. // Fehlt das Recht dafür, bleibt es bei der Akte allein. await erstesAktenblatt(user.permissions, id, parsed.data.displayName) } catch (error) { diff --git a/web/app/(app)/personalakten/neu/NewPersonnelForm.tsx b/web/app/(app)/personalakten/neu/NewPersonnelForm.tsx index 1bd414f..39f5c22 100644 --- a/web/app/(app)/personalakten/neu/NewPersonnelForm.tsx +++ b/web/app/(app)/personalakten/neu/NewPersonnelForm.tsx @@ -8,8 +8,8 @@ import { createPersonnelAction, type ActionResult } from '../actions' /** * Neue Personalakte. * - * Das Discord-Konto ist **optional**. Personen ohne Konto — Zeugen, ehemalige - * Mitarbeiter, Externe — brauchen genauso eine Akte, und ihr Name ist dann das + * Das Discord-Konto ist **optional**. Personen ohne Konto - Zeugen, ehemalige + * Mitarbeiter, Externe - brauchen genauso eine Akte, und ihr Name ist dann das * einzige, was sie identifiziert. */ export function NewPersonnelForm({ diff --git a/web/app/(app)/personalakten/neu/loading.tsx b/web/app/(app)/personalakten/neu/loading.tsx index 5be3f4d..ac4fa81 100644 --- a/web/app/(app)/personalakten/neu/loading.tsx +++ b/web/app/(app)/personalakten/neu/loading.tsx @@ -2,7 +2,7 @@ import { Skeleton } from '@/components/Skeleton' /** * Skelett statt Spinner: die Struktur steht sofort, die Daten fallen hinein. - * Ohne diese Grenze wartet die Navigation stumm, bis der Server fertig ist — + * Ohne diese Grenze wartet die Navigation stumm, bis der Server fertig ist - * man klickt und es passiert scheinbar nichts. Siehe docs/09-performance-und-ux.md. */ export default function Loading() { diff --git a/web/app/(app)/personalakten/page.tsx b/web/app/(app)/personalakten/page.tsx index b47790e..9abd602 100644 --- a/web/app/(app)/personalakten/page.tsx +++ b/web/app/(app)/personalakten/page.tsx @@ -22,7 +22,7 @@ export default async function PersonnelListPage({ }: { searchParams: Promise<{ q?: string; status?: string }> }) { - // Ohne das Recht gibt es die Seite nicht — 404, nicht 403. + // Ohne das Recht gibt es die Seite nicht - 404, nicht 403. const user = await requirePermission('personnel.read') const { q, status } = await searchParams diff --git a/web/app/(app)/suche/SavedViews.tsx b/web/app/(app)/suche/SavedViews.tsx index 2a55e94..950097d 100644 --- a/web/app/(app)/suche/SavedViews.tsx +++ b/web/app/(app)/suche/SavedViews.tsx @@ -9,7 +9,7 @@ import { deleteViewAction, saveViewAction } from './actions' /** * Ansichten: die mitgelieferten und die eigenen. * - * Beide sind dasselbe — eine Suchadresse. Die mitgelieferten stehen im + * Beide sind dasselbe - eine Suchadresse. Die mitgelieferten stehen im * Programm, weil sie von der Gegenwart abhängen („diese Woche"), die eigenen * in der Datenbank. */ diff --git a/web/app/(app)/suche/SearchBox.tsx b/web/app/(app)/suche/SearchBox.tsx index ebddd5e..95f6de0 100644 --- a/web/app/(app)/suche/SearchBox.tsx +++ b/web/app/(app)/suche/SearchBox.tsx @@ -10,7 +10,7 @@ const DEBOUNCE_MS = 250 /** * Das Suchfeld. * - * Tippen schreibt in die Adresse, mit 250 ms Verzögerung — dadurch ist jeder + * Tippen schreibt in die Adresse, mit 250 ms Verzögerung - dadurch ist jeder * Zustand teilbar und der Zurück-Knopf tut das Richtige. Während die neue * Seite lädt, bleiben die alten Treffer stehen und werden gedimmt, statt zu * verschwinden. Siehe docs/09-performance-und-ux.md. diff --git a/web/app/(app)/suche/loading.tsx b/web/app/(app)/suche/loading.tsx index d0243e6..96ac6d4 100644 --- a/web/app/(app)/suche/loading.tsx +++ b/web/app/(app)/suche/loading.tsx @@ -2,7 +2,7 @@ import { Skeleton, SkeletonLine } from '@/components/Skeleton' /** * Skelett statt Spinner: die Struktur steht sofort, die Daten fallen hinein. - * Ohne diese Grenze wartet die Navigation stumm, bis der Server fertig ist — + * Ohne diese Grenze wartet die Navigation stumm, bis der Server fertig ist - * man klickt und es passiert scheinbar nichts. Siehe docs/09-performance-und-ux.md. */ export default function Loading() { diff --git a/web/app/(app)/suche/page.tsx b/web/app/(app)/suche/page.tsx index 4f6c218..ca4fd65 100644 --- a/web/app/(app)/suche/page.tsx +++ b/web/app/(app)/suche/page.tsx @@ -30,7 +30,7 @@ export const dynamic = 'force-dynamic' * Suchseite. * * Alles läuft über Adressparameter: das macht jeden Zustand teilbar, den - * Zurück-Knopf richtig und eine gespeicherte Ansicht zu dem, was sie ist — + * Zurück-Knopf richtig und eine gespeicherte Ansicht zu dem, was sie ist - * ein Lesezeichen. Siehe lib/search/query.ts. */ export default async function SearchPage({ @@ -76,7 +76,7 @@ export default async function SearchPage({ ]) // Bei einer einzelnen Art hängt alles Weitere an ihr: Facetten, Blättern, - // die Trefferzahl in der Kopfzeile. Bei „Alle" gibt es das nicht — dort ist + // die Trefferzahl in der Kopfzeile. Bei „Alle" gibt es das nicht - dort ist // jede Art ein eigener Block mit eigenem Weg in die Vollansicht. const ergebnis = alle ? null : (faelle ?? dokumente ?? personen)! const gesamt = alle @@ -108,7 +108,7 @@ export default async function SearchPage({ {SEARCH_SCOPES.map((kind) => { const anzahl = kind === 'all' ? gesamt : zahlen[kind] // `null` heisst: diese Art gibt es für diesen Nutzer nicht. Dann - // fehlt der Reiter, statt eine Null zu zeigen — auch eine Null wäre + // fehlt der Reiter, statt eine Null zu zeigen - auch eine Null wäre // eine Auskunft. if (anzahl === null) return null @@ -279,7 +279,7 @@ type TrefferView = * * Welche Art es ist, steht an der Form: ein Treffer mit Aktenzeichen ist eine * Fallakte. Das ist kein Trick, sondern der Grund, warum die drei Suchen - * getrennte Rückgaben haben — ein gemeinsamer Typ mit lauter optionalen + * getrennte Rückgaben haben - ein gemeinsamer Typ mit lauter optionalen * Feldern liesse offen, was wirklich dasteht. */ function Treffer({ @@ -371,7 +371,7 @@ async function listStatusTags() { } /** - * Eine Facette. Die Zahlen stammen aus derselben Abfrage wie die Liste — ein + * Eine Facette. Die Zahlen stammen aus derselben Abfrage wie die Liste - ein * Zähler, der mehr zählt als die Liste zeigt, wäre selbst eine Information. */ function Facette({ diff --git a/web/app/(app)/uebersicht/loading.tsx b/web/app/(app)/uebersicht/loading.tsx index 8829491..a054dcf 100644 --- a/web/app/(app)/uebersicht/loading.tsx +++ b/web/app/(app)/uebersicht/loading.tsx @@ -2,7 +2,7 @@ import { Skeleton, SkeletonLine } from '@/components/Skeleton' /** * Skelett statt Spinner: die Struktur steht sofort, die Daten fallen hinein. - * Ohne diese Grenze wartet die Navigation stumm, bis der Server fertig ist — + * Ohne diese Grenze wartet die Navigation stumm, bis der Server fertig ist - * man klickt und es passiert scheinbar nichts. Siehe docs/09-performance-und-ux.md. */ export default function Loading() { diff --git a/web/app/(app)/uebersicht/page.tsx b/web/app/(app)/uebersicht/page.tsx index 44e4ac5..656e9e9 100644 --- a/web/app/(app)/uebersicht/page.tsx +++ b/web/app/(app)/uebersicht/page.tsx @@ -16,7 +16,7 @@ export const dynamic = 'force-dynamic' * * Woran arbeite ich, was ist fällig, wo hat jemand geschrieben, was hat sich * getan. Jede Liste läuft durch dieselbe Sichtbarkeitsprüfung wie die - * Fallliste — das ist der Ort, an dem eine unachtsame Abfrage am ehesten eine + * Fallliste - das ist der Ort, an dem eine unachtsame Abfrage am ehesten eine * Akte verrät, die man nicht sehen darf. */ export default async function DashboardPage() { @@ -206,13 +206,13 @@ function Block({ /** * Eine Zeile der Sprungliste. Sie kann eine Akte, eine Person oder ein - * Dokument sein — deshalb steht die Art nicht dabei, sondern nur das, woran + * Dokument sein - deshalb steht die Art nicht dabei, sondern nur das, woran * man sie erkennt: Aktenzeichen, Name oder Dokumentnummer. * * Eine Akte und ein Dokument tragen eine **Kennung**, eine Person nicht: ihr * Name ist der Titel. Stünde er in der Kennungsspalte, stünde er in Mono, wäre * abgeschnitten, und der Dienstgrad rutschte dorthin, wo sonst der Titel - * steht — untereinander ergäbe das keine Spalte mehr. + * steht - untereinander ergäbe das keine Spalte mehr. * * Ohne Vorabruf, anders als die übrigen Listen: die Seiten dahinter merken * sich, dass sie geöffnet wurden. Der Vorabruf wird zwar serverseitig erkannt diff --git a/web/app/(app)/zugang/loading.tsx b/web/app/(app)/zugang/loading.tsx index 200924e..a37594f 100644 --- a/web/app/(app)/zugang/loading.tsx +++ b/web/app/(app)/zugang/loading.tsx @@ -2,7 +2,7 @@ import { Skeleton, SkeletonLine } from '@/components/Skeleton' /** * Skelett statt Spinner: die Struktur steht sofort, die Daten fallen hinein. - * Ohne diese Grenze wartet die Navigation stumm, bis der Server fertig ist — + * Ohne diese Grenze wartet die Navigation stumm, bis der Server fertig ist - * man klickt und es passiert scheinbar nichts. Siehe docs/09-performance-und-ux.md. */ export default function Loading() { diff --git a/web/app/(print)/NotAvailable.tsx b/web/app/(print)/NotAvailable.tsx index f3bf38a..ec354a4 100644 --- a/web/app/(print)/NotAvailable.tsx +++ b/web/app/(print)/NotAvailable.tsx @@ -5,7 +5,7 @@ import { de } from '@/lib/i18n/de' * * Bewusst **kein `notFound()`**: die Wurzel hat ein `loading.tsx`, und dessen * Skelett bleibt in dieser Gruppe stehen, statt durch die Nicht-gefunden-Seite - * ersetzt zu werden — die Ansicht bliebe leer. Für ein Blatt, das gedruckt + * ersetzt zu werden - die Ansicht bliebe leer. Für ein Blatt, das gedruckt * wird, ist ein leeres Blatt der schlechteste Ausgang: es sieht aus wie ein * Fehler im Papier, nicht wie eine Auskunft. * diff --git a/web/app/(print)/PrintBar.tsx b/web/app/(print)/PrintBar.tsx index 7819f04..b847946 100644 --- a/web/app/(print)/PrintBar.tsx +++ b/web/app/(print)/PrintBar.tsx @@ -7,7 +7,7 @@ import { exportText } from '@/lib/i18n/export' /** * Die Leiste über einer Druckansicht: zurück zur Akte und drucken. * - * Die Druckansichten liegen ausserhalb des angemeldeten Rahmenwerks — der + * Die Druckansichten liegen ausserhalb des angemeldeten Rahmenwerks - der * PDF-Dienst ruft sie mit einem kurzlebigen Zeichen auf und hat keine Sitzung, * also darf dort keine Kopfzeile stehen, die `requireUser()` braucht. Genau * deshalb gab es aber auch keinen Weg zurück: wer die Ansicht im Browser @@ -15,7 +15,7 @@ import { exportText } from '@/lib/i18n/export' * * Das Ziel wird aus dem Pfad abgeleitet und nicht hereingereicht: `/druck` * abschneiden ergibt die Akte, aus der man kommt. Das stimmt auch, wenn jemand - * die Adresse direkt aufruft — `router.back()` täte das nicht. + * die Adresse direkt aufruft - `router.back()` täte das nicht. * * `no-print` blendet die Leiste beim Drucken aus. Auf dem Papier hat ein * Zurück-Knopf nichts verloren. diff --git a/web/app/(print)/dokumente/[documentNumber]/druck/page.tsx b/web/app/(print)/dokumente/[documentNumber]/druck/page.tsx index 73550a9..de52415 100644 --- a/web/app/(print)/dokumente/[documentNumber]/druck/page.tsx +++ b/web/app/(print)/dokumente/[documentNumber]/druck/page.tsx @@ -23,7 +23,7 @@ export async function generateMetadata({ /** * Druckansicht eines einzelnen Dokuments. * - * Kein Verlauf, keine Kopfdatentabelle einer Akte — das Dokument selbst, so + * Kein Verlauf, keine Kopfdatentabelle einer Akte - das Dokument selbst, so * wie seine Vorlage es vorsieht. Ein Aktenblatt kommt als Aktenblatt heraus, * ein Vertrag als Vertrag. Siehe docs/08-suche-und-export.md. */ @@ -169,7 +169,7 @@ export default async function PrintDocumentPage({

) : (

- {String(section.value ?? '—')} + {String(section.value ?? '-')}

)} diff --git a/web/app/(print)/faelle/[caseNumber]/druck/page.tsx b/web/app/(print)/faelle/[caseNumber]/druck/page.tsx index 4de3da0..9dc190d 100644 --- a/web/app/(print)/faelle/[caseNumber]/druck/page.tsx +++ b/web/app/(print)/faelle/[caseNumber]/druck/page.tsx @@ -99,7 +99,7 @@ export default async function PrintCasePage({ /> {anhang.originalName} {anhang.sizeBytes} {/* Der Hash macht nachprüfbar, dass die Datei zum Ausdruck - gehört — deshalb steht er im Verzeichnis. */} + gehört - deshalb steht er im Verzeichnis. */} {anhang.sha256} @@ -188,7 +188,7 @@ function Zeile({ label, value }: { label: string; value: string }) { /** * Die Abschnitte im Druck. Ein gesperrtes Feld wird als Balken ausgegeben, mit - * dem Vermerk, ab welcher Stufe es lesbar wäre — sonst merkt der Empfänger + * dem Vermerk, ab welcher Stufe es lesbar wäre - sonst merkt der Empfänger * nicht, dass er eine gekürzte Fassung in der Hand hält. */ function PrintSections({ @@ -256,7 +256,7 @@ function PrintSections({

) : (

- {String(section.value ?? '—')} + {String(section.value ?? '-')}

)} diff --git a/web/app/(print)/layout.tsx b/web/app/(print)/layout.tsx index c648c37..271bccd 100644 --- a/web/app/(print)/layout.tsx +++ b/web/app/(print)/layout.tsx @@ -10,9 +10,9 @@ export const dynamic = 'force-dynamic' * kurzlebigen Zeichen und ohne Sitzung, und eine Weiterleitung zur Anmeldung * ergäbe ein leeres PDF. Die Prüfung steht in den Seiten selbst. * - * Was er tut, ist zweierlei: er legt den weissen Grund unter das Blatt — sonst + * Was er tut, ist zweierlei: er legt den weissen Grund unter das Blatt - sonst * schwebt ein Ausdruck im dunklen Thema der Anwendung, und man hält die - * Ansicht für kaputt — und er gibt einen Weg zurück. Beides verschwindet beim + * Ansicht für kaputt - und er gibt einen Weg zurück. Beides verschwindet beim * Drucken. */ export default function PrintLayout({ children }: { children: ReactNode }) { diff --git a/web/app/api/admin/export/route.ts b/web/app/api/admin/export/route.ts index 921d91a..5e267af 100644 --- a/web/app/api/admin/export/route.ts +++ b/web/app/api/admin/export/route.ts @@ -18,7 +18,7 @@ export const dynamic = 'force-dynamic' * GET /api/admin/export?kind=bundle ZIP mit den fertigen Exporten * * Beide nur mit Recht `admin`, beide protokolliert. Der JSON-Abzug ist die - * einzige Stelle im System, an der die Klassifizierung nicht greift — deshalb + * einzige Stelle im System, an der die Klassifizierung nicht greift - deshalb * liegt er hinter einem eigenen Endpunkt und nicht hinter einem Knopf an einer * Akte. */ diff --git a/web/app/api/exports/[id]/route.ts b/web/app/api/exports/[id]/route.ts index 6cb8383..e6ecb1d 100644 --- a/web/app/api/exports/[id]/route.ts +++ b/web/app/api/exports/[id]/route.ts @@ -14,7 +14,7 @@ export const dynamic = 'force-dynamic' * Herunterladen eines fertigen Exports. * * Nur der Auftraggeber selbst. Ein Export ist auf **seine** Stufe gekürzt und - * trägt **seinen** Namen im Wasserzeichen — ihn an jemand anderen auszuliefern + * trägt **seinen** Namen im Wasserzeichen - ihn an jemand anderen auszuliefern * hiesse, ein Dokument mit fremdem Namen zu verteilen. */ export async function GET( diff --git a/web/app/api/files/[id]/route.ts b/web/app/api/files/[id]/route.ts index dfda898..92c359e 100644 --- a/web/app/api/files/[id]/route.ts +++ b/web/app/api/files/[id]/route.ts @@ -13,7 +13,7 @@ export const runtime = 'nodejs' export const dynamic = 'force-dynamic' /** - * Auslieferung. **Niemals als statische Datei** — jeder Abruf läuft durch die + * Auslieferung. **Niemals als statische Datei** - jeder Abruf läuft durch die * Sichtbarkeitsprüfung der zugehörigen Akte und wird ab Stufe 3 protokolliert. * Siehe docs/07-dateien-und-sicherheit.md. * diff --git a/web/app/api/files/route.ts b/web/app/api/files/route.ts index a294112..59600b1 100644 --- a/web/app/api/files/route.ts +++ b/web/app/api/files/route.ts @@ -16,7 +16,7 @@ export const dynamic = 'force-dynamic' * Fortschrittsbalken, und 25 MB sind mehr, als eine Server Action annimmt. * * Die Antwort kommt, sobald die Datei in der Quarantäne liegt. Die Prüfkette - * läuft danach weiter und meldet sich über `/api/events` — niemand wartet mit + * läuft danach weiter und meldet sich über `/api/events` - niemand wartet mit * laufendem Balken auf einen Virenscanner. Siehe docs/09. */ export async function POST(request: Request): Promise { diff --git a/web/app/api/search/quick/route.ts b/web/app/api/search/quick/route.ts index 792cce4..4308e14 100644 --- a/web/app/api/search/quick/route.ts +++ b/web/app/api/search/quick/route.ts @@ -18,7 +18,7 @@ const RECENT_IN_PALETTE = 6 * Schnellsuche für die Kommandopalette. * * Bewusst schmal: Aktenzeichen, Titel und Namen, kein Volltext über Inhalte. - * Wer die Palette öffnet, will springen, nicht recherchieren — dafür gibt es + * Wer die Palette öffnet, will springen, nicht recherchieren - dafür gibt es * `/suche`. * * Der Trigram-Index auf `caseNumber` und `displayName` fängt Tippfehler ab, @@ -31,7 +31,7 @@ export async function GET(request: Request): Promise { const params = new URL(request.url).searchParams // Leeres Feld: die eigene Sprungliste. Wer die Palette öffnet, will meistens - // dorthin zurück, wo er eben war — und nicht erst tippen. + // dorthin zurück, wo er eben war - und nicht erst tippen. if (params.get('recent') === '1') { const zuletzt = await listRecent(user.permissions, RECENT_IN_PALETTE) return NextResponse.json({ diff --git a/web/app/api/stream/route.ts b/web/app/api/stream/route.ts index 641798d..f76c0c4 100644 --- a/web/app/api/stream/route.ts +++ b/web/app/api/stream/route.ts @@ -30,7 +30,7 @@ const HEARTBEAT_MS = 25_000 * * Drei Prüfungen, alle nötig: * 1. **Beim Verbinden**: welche der angefragten Themen darf dieser Nutzer - * überhaupt abonnieren. Wer ein fremdes Thema nennt, bekommt es nicht — + * überhaupt abonnieren. Wer ein fremdes Thema nennt, bekommt es nicht - * und erfährt auch nicht, ob es existiert. * 2. **Je Ereignis**: der Inhalt wird mit den Rechten des Empfängers geladen. * Eine Umklassifizierung mitten in einer offenen Verbindung wirkt dadurch @@ -38,7 +38,7 @@ const HEARTBEAT_MS = 25_000 * 3. **Laufend**: Sitzung und Rechte werden neu aufgelöst, nicht einmal beim * Verbinden eingefroren. Eine offene Verbindung ist sonst der eine Ort im * System, an dem ein Entzug nicht ankommt: der Worker löscht die Sitzung, - * jeder Seitenaufruf ist abgemeldet — und der Strom läuft weiter, weil + * jeder Seitenaufruf ist abgemeldet - und der Strom läuft weiter, weil * niemand mehr fragt. Siehe docs/03-auth-und-rechte.md. */ export async function GET(request: Request): Promise { @@ -161,7 +161,7 @@ export async function GET(request: Request): Promise { return } // Rechte geändert: die erlaubten Themen gelten nicht mehr. Sie neu - // zu bestimmen ist wichtiger als die eine Zustellung — ein Ereignis + // zu bestimmen ist wichtiger als die eine Zustellung - ein Ereignis // trägt bei Verlaufseinträgen nur eine Kennung, das Thema ist dort // die **einzige** Schranke. if (abdruck(frisch) !== abdruck(rechte)) { diff --git a/web/app/api/vitals/route.ts b/web/app/api/vitals/route.ts index 0ca1f96..c838033 100644 --- a/web/app/api/vitals/route.ts +++ b/web/app/api/vitals/route.ts @@ -17,7 +17,7 @@ const BEWERTUNGEN = new Set(['good', 'needs-improvement', 'poor']) * Zeichenketten aus dem Browser speichert, ist ein Ablagefach für Fremde. * * Der Nutzer wird **nicht** mitgeschrieben. Wer wann welche Akte geöffnet hat, - * steht im Zugriffsprotokoll — dort gehört es hin, dort ist es geregelt, und + * steht im Zugriffsprotokoll - dort gehört es hin, dort ist es geregelt, und * eine zweite Spur daneben wäre eine Überwachungsfunktion ohne Auftrag. */ export async function POST(request: Request): Promise { diff --git a/web/app/globals.css b/web/app/globals.css index 1aec130..401eaa2 100644 --- a/web/app/globals.css +++ b/web/app/globals.css @@ -56,7 +56,7 @@ /* Struktur: Flaechen bleiben eckig, Bedienelemente sind rund. Eine Akte ist ein Blatt und hat scharfe Kanten. Was man druecken oder - ausfuellen kann, ist rund — daran erkennt man es, bevor man es beruehrt. */ + ausfuellen kann, ist rund - daran erkennt man es, bevor man es beruehrt. */ --radius-none: 0px; --radius-sm: 2px; --radius-DEFAULT: 2px; @@ -87,7 +87,7 @@ * Klassifizierungsfarben: eine Stufe muss in beiden Themen dieselbe Farbe * haben, sonst lernt man sie zweimal. Siehe docs/10-design-system.md. * - * Kein warmes Cremeweiss, sondern ein leicht kühles Papierweiss — dieselbe + * Kein warmes Cremeweiss, sondern ein leicht kühles Papierweiss - dieselbe * Anmutung wie das dunkle Thema, nur andersherum. Die Kontraste sind auf * mindestens 4,5:1 für Fliesstext ausgelegt. */ [data-theme='light'] { @@ -226,7 +226,7 @@ **Und er muss beim Druecken zurueckmelden, dass er getroffen wurde.** Beim Druecken zieht sich der Knopf leicht zusammen und bekommt einen - inneren Ring — er wirkt kurz dicker, ohne dass sich die Rahmenbreite + inneren Ring - er wirkt kurz dicker, ohne dass sich die Rahmenbreite wirklich aendert, sonst wuerde das Umfeld springen. Die Rueckmeldung setzt ohne Verzoegerung ein und klingt langsam ab: ein kurzer Klick bliebe sonst unsichtbar. Siehe docs/10-design-system.md. @@ -318,7 +318,7 @@ Jede Liste in dieser Anwendung zeigt dasselbe Gebilde: eine Kennung, ein Titel, etwas Beiwerk, eine Stempelmarke. Bisher bestimmte **jede Zeile - ihre Spaltenbreiten selbst** — die Kennung war so breit wie ihr Text, und + ihre Spaltenbreiten selbst** - die Kennung war so breit wie ihr Text, und damit fing der Titel in jeder Zeile woanders an. Bei „ETHIK" und „WS" untereinander sieht man das sofort. @@ -350,7 +350,7 @@ } /* Wie die Kennung, aber fuer eine Bezeichnung aus einer festen Liste: - die Rolle eines Beteiligten, die Art eines Auftrags. Kein Mono — es ist + die Rolle eines Beteiligten, die Art eines Auftrags. Kein Mono - es ist Sprache, keine Nummer. */ .record-label { flex: none; @@ -364,7 +364,7 @@ } /* Der Dienstgrad vor einem Namen. In derselben Groesse wie der Name, denn - er gehoert zu ihm — aber in einer eigenen Spalte, sonst faengt jeder Name + er gehoert zu ihm - aber in einer eigenen Spalte, sonst faengt jeder Name woanders an. */ .record-rank { flex: none; @@ -827,7 +827,7 @@ /* Der Grund unter einer Druckansicht. Ohne ihn liegt ein weisses Blatt auf dem dunklen Thema der Anwendung, und die Ansicht sieht kaputt aus, obwohl sie stimmt. Beim Drucken faellt er - weg — Papier bringt seinen eigenen Grund mit. */ + weg - Papier bringt seinen eigenen Grund mit. */ .print-page { min-height: 100dvh; background: #f2f2f0; diff --git a/web/app/layout.tsx b/web/app/layout.tsx index 0b36e3d..3298403 100644 --- a/web/app/layout.tsx +++ b/web/app/layout.tsx @@ -21,7 +21,7 @@ export const viewport: Viewport = { * * Ohne das blitzt beim Laden kurz das falsche Thema auf. Es ist die eine * Stelle mit `dangerouslySetInnerHTML`, und der Inhalt ist eine Konstante aus - * diesem Modul — kein Nutzertext. Das Verbot aus docs/07 gilt Nutzerinhalten. + * diesem Modul - kein Nutzertext. Das Verbot aus docs/07 gilt Nutzerinhalten. */ const THEME_SCRIPT = `try{var t=localStorage.getItem(${JSON.stringify(THEME_KEY)});` + @@ -38,7 +38,7 @@ export default async function RootLayout({ children }: { children: React.ReactNo {/* `suppressHydrationWarning` wegen des Nonce, nicht wegen des Inhalts. Der Browser **leert das Nonce-Attribut**, sobald er das Element - geparst hat — so schreibt es die CSP-Spezifikation vor, damit kein + geparst hat - so schreibt es die CSP-Spezifikation vor, damit kein Skript den Wert über `getAttribute` auslesen und sich selbst nachladen kann. React vergleicht beim Hydrieren aber genau dieses Attribut, liest clientseitig den leeren Wert und meldet einen diff --git a/web/auth.ts b/web/auth.ts index 840b23d..001430c 100644 --- a/web/auth.ts +++ b/web/auth.ts @@ -12,7 +12,7 @@ export { SIGN_IN_ERRORS } /** * Auth.js leitet die Callback-URL **nicht** aus dem Host-Header ab, sondern aus * `AUTH_URL`. Fehlt die Variable, bleibt die `redirect_uri` fest bei - * `http://localhost:3000` — hinter dem Cloudflare Tunnel wäre die Anmeldung + * `http://localhost:3000` - hinter dem Cloudflare Tunnel wäre die Anmeldung * damit kaputt, und zwar mit einer Fehlermeldung von Discord, die nicht auf die * Ursache zeigt. * @@ -38,7 +38,7 @@ type DiscordProfile = { * benutzt: die Rollen holt der Bot mit seinem eigenen Token. * * Die Sitzung selbst steht in der Datenbank. Im Cookie liegt nur ein - * signiertes Wertepaar aus `userId` und `sessionId` — ohne die Zeile in + * signiertes Wertepaar aus `userId` und `sessionId` - ohne die Zeile in * `Session` ist es wertlos. Nur so lässt sich eine Sitzung zurückziehen, * wenn jemand seine Rolle verliert. Siehe docs/03-auth-und-rechte.md. */ diff --git a/web/components/AddPanel.tsx b/web/components/AddPanel.tsx index b777f59..eaa6049 100644 --- a/web/components/AddPanel.tsx +++ b/web/components/AddPanel.tsx @@ -6,13 +6,13 @@ import { commonText } from '@/lib/i18n/common' /** * Ein aufklappbares Formular zum Hinzufügen. * - * Beteiligte, Verknüpfungen, Dokumente, Zuordnungen — überall derselbe Ablauf: + * Beteiligte, Verknüpfungen, Dokumente, Zuordnungen - überall derselbe Ablauf: * ein Knopf, ein kleines Formular, eine Server Action, eine Fehlermeldung an * Ort und Stelle. Das viermal zu wiederholen kostete nicht nur Zeilen, sondern * auch Bündelgrösse auf der Fallakte, die ohnehin die dichteste Seite ist. * * Der Rückruf bekommt `schliessen`, damit das Formular nur nach einem Erfolg - * zugeht — ein Fehler soll die Eingabe nicht wegräumen. + * zugeht - ein Fehler soll die Eingabe nicht wegräumen. */ export function AddPanel({ label, diff --git a/web/components/Avatar.tsx b/web/components/Avatar.tsx index 59205f9..7f0ff53 100644 --- a/web/components/Avatar.tsx +++ b/web/components/Avatar.tsx @@ -6,7 +6,7 @@ * im Stack für ein Bild von 64 Pixeln. Dafür steht `cdn.discordapp.com` in der * Inhaltsrichtlinie, siehe middleware.ts. * - * Ohne Bild — und das ist der Normalfall bei Konten ohne eigenes Profilbild — + * Ohne Bild - und das ist der Normalfall bei Konten ohne eigenes Profilbild - * stehen die Anfangsbuchstaben da. Kein Platzhaltergesicht: ein leerer Kreis * mit Initialen ist ehrlicher und lädt nichts nach. */ diff --git a/web/components/NavLinks.tsx b/web/components/NavLinks.tsx index ddc49cb..0379f25 100644 --- a/web/components/NavLinks.tsx +++ b/web/components/NavLinks.tsx @@ -7,7 +7,7 @@ import { Pending } from '@/components/Pending' /** * Die Bereiche der Anwendung in der Kopfzeile. * - * Sie waren blosse Textlinks — von einem Fliesstextlink nicht zu unterscheiden + * Sie waren blosse Textlinks - von einem Fliesstextlink nicht zu unterscheiden * und ohne Hinweis darauf, wo man gerade ist. Jetzt tragen sie dieselbe * Knopfform wie alles Bedienbare, und der Bereich, in dem man steht, ist * gefüllt. diff --git a/web/components/Pending.tsx b/web/components/Pending.tsx index 7366110..86095e4 100644 --- a/web/components/Pending.tsx +++ b/web/components/Pending.tsx @@ -6,12 +6,12 @@ import { useLinkStatus } from 'next/link' * Der Ladepunkt in einem Link, solange der Wechsel läuft. * * Ein Wechsel kann einen Moment dauern, und ohne Rückmeldung sieht es aus, als - * sei der Klick nicht angekommen — man klickt ein zweites Mal. Der Punkt sitzt + * sei der Klick nicht angekommen - man klickt ein zweites Mal. Der Punkt sitzt * **im geklickten Link**, damit sichtbar bleibt, wohin es geht. * * Das ist kein Blockade-Spinner im Sinn von Zusicherung 5 der README: er ersetzt * keinen Inhalt und hält nichts auf. Die Zielseite bringt ihr Skelett mit, das - * ist die eigentliche Antwort auf das Warten — hier geht es nur darum, den + * ist die eigentliche Antwort auf das Warten - hier geht es nur darum, den * Klick zu quittieren. * * `useLinkStatus` funktioniert nur als Kind eines `next/link`, deshalb die diff --git a/web/components/PieChart.tsx b/web/components/PieChart.tsx index 337842b..1f4d3bf 100644 --- a/web/components/PieChart.tsx +++ b/web/components/PieChart.tsx @@ -27,7 +27,7 @@ export function PieChart({ }: { slices: Slice[] emptyLabel: string - /** „12 Fälle" — steht in der Mitte und sagt, worauf sich die Anteile beziehen. */ + /** „12 Fälle" - steht in der Mitte und sagt, worauf sich die Anteile beziehen. */ totalLabel: (total: number) => string }) { const gesamt = slices.reduce((summe, stueck) => summe + stueck.value, 0) @@ -101,7 +101,7 @@ export function PieChart({ /** * Abstufungen von `--steel`, gleichmässig verteilt. Bei einem einzigen - * Segment die volle Farbe, sonst von kräftig nach blass — so bleibt die + * Segment die volle Farbe, sonst von kräftig nach blass - so bleibt die * Reihenfolge der Liste auch im Kreis ablesbar. */ function farbeFuer(index: number, anzahl: number): string { diff --git a/web/components/ProfileMenu.tsx b/web/components/ProfileMenu.tsx index cc9ced2..8f8381e 100644 --- a/web/components/ProfileMenu.tsx +++ b/web/components/ProfileMenu.tsx @@ -19,7 +19,7 @@ import { ThemeToggle } from '@/components/ThemeToggle' * das Abmelden. In der Kopfzeile standen diese Dinge vorher zwischen den * Aktenbereichen und nahmen dort Platz weg, den die Arbeit braucht. * - * Das Abmelden kommt als Server Action von aussen herein — dieses Fenster darf + * Das Abmelden kommt als Server Action von aussen herein - dieses Fenster darf * die Sitzung nicht selbst beenden können. */ export function ProfileMenu({ diff --git a/web/components/SearchBar.tsx b/web/components/SearchBar.tsx index c1c5cef..439a0b9 100644 --- a/web/components/SearchBar.tsx +++ b/web/components/SearchBar.tsx @@ -3,7 +3,7 @@ import { searchBarText } from '@/lib/i18n/shell' /** * Der Suchbalken in der Kopfzeile. * - * Ein gewöhnliches Formular, das die Anfrage an `/suche` übergibt — kein + * Ein gewöhnliches Formular, das die Anfrage an `/suche` übergibt - kein * Skript, kein Zustand, keine Bytes im Bündel. Die eigentliche Suche mit * Filtern, Facetten und Abbruch laufender Anfragen sitzt auf der Suchseite, * hier steht nur das Eingangstor. diff --git a/web/components/StampMark.tsx b/web/components/StampMark.tsx index b9d99ae..8546e68 100644 --- a/web/components/StampMark.tsx +++ b/web/components/StampMark.tsx @@ -17,7 +17,7 @@ export function stampColor(level: number): string { * `ClearanceLevelConfig.colorToken` und `PersonnelStatusTag.colorToken` sind * Daten und im Adminbereich pflegbar. Sie landen als Name einer CSS-Variablen * in einem `style`-Attribut, und was aus der Datenbank in ein Stilattribut - * geht, wird geprueft — nicht weil es heute jemand setzen koennte, sondern + * geht, wird geprueft - nicht weil es heute jemand setzen koennte, sondern * weil es morgen jemand koennen soll. Ein unbekannter Wert faellt auf die * neutrale Marke zurueck, statt eine Variable zu erfinden, die es nicht gibt. */ @@ -45,7 +45,7 @@ export function colorVariable(token: string | null | undefined): string { * **Feste Breite.** Die Namen der Stufen sind unterschiedlich lang und im * Adminbereich aenderbar; unterschiedlich breite Marken untereinander lesen * sich als Unordnung, nicht als Unterschied. Ein zu langer Name wird gekuerzt, - * die Stufenziffer davor bleibt immer stehen — sie ist die eigentliche + * die Stufenziffer davor bleibt immer stehen - sie ist die eigentliche * Auskunft. * * `name` kommt aus ClearanceLevelConfig und ist im Adminbereich aenderbar, diff --git a/web/components/StatusTags.tsx b/web/components/StatusTags.tsx index e4d5da6..0e0bffe 100644 --- a/web/components/StatusTags.tsx +++ b/web/components/StatusTags.tsx @@ -5,7 +5,7 @@ import { colorVariable } from '@/components/StampMark' * * Mehrere zugleich: „Gekündigt" und „Verhaftet" schließen einander nicht aus. * Die Namen und Farben kommen aus `PersonnelStatusTag` und sind im - * Adminbereich pflegbar — deshalb werden sie hereingereicht und nicht aus + * Adminbereich pflegbar - deshalb werden sie hereingereicht und nicht aus * `lib/i18n/de.ts` gelesen. Siehe die Sprachkonvention: Code englisch, Oberflaeche deutsch. */ export function StatusTags({ diff --git a/web/components/Tabs.tsx b/web/components/Tabs.tsx index 9d1b9da..2757174 100644 --- a/web/components/Tabs.tsx +++ b/web/components/Tabs.tsx @@ -8,7 +8,7 @@ import { Pending } from '@/components/Pending' * Eine Reiterleiste. * * Sie hebt hervor, wo man gerade ist. Vorher taten das weder die Reiter der - * Fallakte noch die der Verwaltung — fünf gleich aussehende Links, und man + * Fallakte noch die der Verwaltung - fünf gleich aussehende Links, und man * musste an der Seite selbst ablesen, welcher davon offen war. * * Der Vergleich läuft über den Pfad, nicht über die vollständige Adresse: diff --git a/web/components/ThemeToggle.tsx b/web/components/ThemeToggle.tsx index 3921c60..63bfe94 100644 --- a/web/components/ThemeToggle.tsx +++ b/web/components/ThemeToggle.tsx @@ -12,7 +12,7 @@ export const THEME_KEY = 'afis:thema' * * Drei Zustände, nicht zwei: „System" ist der Auslieferungszustand und folgt * `prefers-color-scheme`. Wer ausdrücklich wählt, bekommt seine Wahl auf - * diesem Gerät gemerkt — nicht am Konto, denn es ist eine Eigenschaft des + * diesem Gerät gemerkt - nicht am Konto, denn es ist eine Eigenschaft des * Bildschirms, an dem jemand sitzt, nicht der Person. * * Gesetzt wird das Attribut schon vor dem ersten Malen, siehe das Skript im diff --git a/web/components/Vitals.tsx b/web/components/Vitals.tsx index 7d54a5b..05a0c22 100644 --- a/web/components/Vitals.tsx +++ b/web/components/Vitals.tsx @@ -8,7 +8,7 @@ import { usePathname } from 'next/navigation' * * Gesendet wird mit `sendBeacon`: das überlebt den Seitenwechsel, blockiert * nichts und braucht keine offene Verbindung. Die Bibliothek wird erst - * geladen, wenn der Browser Zeit hat — die Messung darf nicht selbst zur + * geladen, wenn der Browser Zeit hat - die Messung darf nicht selbst zur * Ladezeit beitragen. * * Übertragen wird das **Routenmuster**, nicht der konkrete Pfad: eine diff --git a/web/components/chat/Chat.tsx b/web/components/chat/Chat.tsx index 73607a3..ac8bfbc 100644 --- a/web/components/chat/Chat.tsx +++ b/web/components/chat/Chat.tsx @@ -25,16 +25,16 @@ export type ChatScopeView = type Reaktion = { messageId: string; userId: string; key: string } /** - * Der Chat einer Akte — Fallakte oder Personalakte. + * Der Chat einer Akte - Fallakte oder Personalakte. * * Optisch klar vom Verlauf abgesetzt, weil er inhaltlich etwas anderes ist: * formlos, kein Aktenbestandteil. Die Zeitachse des Verlaufs hat eine - * durchgehende Linie, der Chat nicht — der Unterschied muss ohne Beschriftung + * durchgehende Linie, der Chat nicht - der Unterschied muss ohne Beschriftung * erkennbar sein. Siehe docs/10-design-system.md. * * Gesendet wird optimistisch: die Nachricht steht sofort da, mit einer * clientseitig erzeugten UUIDv7 als Kennung. Kommt dieselbe Kennung über den - * Strom zurück, wird der optimistische Eintrag ersetzt statt verdoppelt — und + * Strom zurück, wird der optimistische Eintrag ersetzt statt verdoppelt - und * ein wiederholtes Absenden nach einem Netzfehler erzeugt keine zweite * Nachricht. Siehe docs/09-performance-und-ux.md. */ @@ -194,7 +194,7 @@ export function Chat({ {nachricht.replyToId ? (

- {chatText.replyingTo} {nachId.get(nachricht.replyToId)?.authorName ?? '—'}:{' '} + {chatText.replyingTo} {nachId.get(nachricht.replyToId)?.authorName ?? '-'}:{' '} {(nachId.get(nachricht.replyToId)?.body ?? '').slice(0, 80)}

) : null} @@ -357,7 +357,7 @@ export function Chat({
{antwortAuf ? (

- {chatText.replyingTo} {nachId.get(antwortAuf)?.authorName ?? '—'} + {chatText.replyingTo} {nachId.get(antwortAuf)?.authorName ?? '-'}