Files
Laufzettel/CHANGELOG.md
T
florian.wildeandClaude Opus 5 ecc3c579df
Prüfung / pruefung (push) Canceled after 0s
Prüfung / e2e (push) Canceled after 0s
feat(mandant): Betriebsmodus, Kundenverwaltung und Einstellungen (#22)
Zwei Betriebsmodi, ein Codepfad. src/server/mandant.ts ist die eine Stelle,
an der die Mandantenregel steht.

Der Review fand drei Blocker: die Lesemodelle wandten die Mandantensicht nicht
an, der Protokolleintrag des Moduswechsels stand außerhalb der Transaktion, und
Prüfung und Vollzug lagen so weit auseinander, dass zwei gleichzeitige Wechsel
beide durchliefen. Alle drei geschlossen, der letzte mit einem Advisory Lock.

336 Tests.

Closes #8

Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com>
2026-09-25 05:03:11 +00:00

5.1 KiB
Raw Blame History

Changelog

Alle nennenswerten Änderungen an Laufzettel werden in dieser Datei dokumentiert.

Das Format basiert auf Keep a Changelog, und dieses Projekt folgt Semantic Versioning.

[Unveröffentlicht]

Hinzugefügt

  • Projektgerüst: Next 16 mit App Router und TypeScript strict, Tailwind 4, Vitest 5, Playwright 1.63, ESLint flat config, Prettier, husky mit lint-staged und commitlint (#005)
  • Gestaltung: Design-Token als CSS-Variablen, selbst gehostete Schriften, Wortmarke und Bildmarke [ ✓ ], Versionsanzeige unten links (#005)
  • Betriebsstand mit Docker Compose: die Datenbank ist von außen nicht erreichbar — kein veröffentlichter Port und ein Netz ohne Gateway; Migrationen laufen beim Start in einem eigenen Einmal-Dienst, der Seed bleibt ein bewusster Handgriff (#005)
  • Healthcheck GET /api/gesundheit und Sicherheitskopfzeilen samt CSP-Nonce je Anfrage (#005)
  • shadcn/ui eingerichtet: sein Variablen-Vertrag wird aus den Laufzettel-Token gespeist, damit kopierte Bauteile ohne Nacharbeit passen (#005)
  • pnpm pruefe:doku hält Dokumentation und Code zusammen: Version im Changelog, Issue-Dateien gegen ihre Übersicht, keine Verweise auf fehlende Dateien, keine fehlenden Bilder (#005)
  • pnpm docs:screenshots erzeugt Screenshots reproduzierbar und prüft dabei gleich, dass am Handy nicht horizontal gescrollt wird (#005)
  • Issues, Labels und Meilensteine für alle vier Phasen im Gitea-Tracker (#001–#019)
  • Vollständiges Datenmodell in deutscher Benennung: 20 Tabellen, 9 Aufzählungen, erste Migration, idempotenter Seed für Betriebsmodus, eigene Organisation und Administrator (#006)
  • Erzeugung der tagCodes für die QR-Aufkleber, mit Vergabebuch, aus dem nie gelöscht wird — ein Code kommt auch nach dem Löschen eines Geräts nicht zurück (#006)
  • Verschlüsselung von Geheimnissen mit AES-256-GCM aus APP_SECRET, für das LDAP-Bind-Passwort und später die Zugangsdaten der Connectoren (#006)
  • Anmeldung über einen generischen OIDC-Anbieter mit Discovery, PKCE, state und nonce; unbekannte Benutzer entstehen beim ersten Login, die Rolle kommt bei jeder Anmeldung neu aus den Gruppen (#007)
  • Lokale Anmeldung mit E-Mail und Passwort als Notfallzugang, nur bei AUTH_LOCAL_ENABLED=true (#007)
  • Rechte in einer Tabelle mit vier Rollen; geprüft ausschließlich serverseitig, Rolle und Aktiv-Status pro Anfrage aus der Datenbank (#007)
  • Benutzerverwaltung für Administratoren: Rolle setzen, Konto abschalten, lokales Konto anlegen (#007)
  • Navigation zeigt nur, was die eigene Rolle darf (#007)
  • Betriebsmodus Intern und Dienstleistung, umschaltbar ohne Neustart. Im Modus Intern erscheint die eigene Organisation nirgends; der Wechsel nimmt alle Geräte, Personen, Abteilungen und Läufe mit, weil jede Zeile ohnehin schon eine Kunden-Zuordnung trägt (#008)
  • Bestätigungsdialog für den Moduswechsel, der die Folgen aus derselben Prüfung zeigt, die der Wechsel danach durchsetzt (#008)
  • Kundenverwaltung im Modus Dienstleistung: anlegen, bearbeiten, archivieren statt löschen (#008)
  • Admin → Einstellungen: Betriebsmodus, Name der eigenen Organisation, globale Namensregeln, Sperr-OU und die Anzeige der Adresse, die in den QR-Codes steckt (#008)
  • Navigation und Beschriftungen folgen dem Betriebsmodus — ein Codepfad, nur ein- und ausgeblendete Einträge (#008)

Sicherheit

  • Der Compose-Stand bricht ab, wenn APP_SECRET, POSTGRES_PASSWORD oder APP_URL fehlen, statt mit Standardwerten zu starten (#005)
  • Die Mandantengrenze steht als zusammengesetzter Fremdschlüssel in der Datenbank: ein Lauf kann strukturell kein Gerät, keine Person und keine Abteilung eines fremden Kunden wählen (#006)
  • Ein Bind-Passwort ohne Versionspräfix wird von der Datenbank abgewiesen, ein versehentlich im Klartext geschriebenes fällt damit sofort auf (#006)
  • Ein Lauf nimmt seine Schrittergebnisse und Kommentare beim Löschen nicht mehr mit, und ein Protokolleintrag kann seinen Urheber nicht mehr verlieren (#006)
  • Das Rücksprungziel nach der Anmeldung wird aufgelöst und gegen die eigene Herkunft geprüft, statt nur Präfixe zu vergleichen — /<TAB>/fremd.example wäre sonst eine offene Weiterleitung gewesen (#007)
  • Alle Umleitungen gehen über APP_URL statt über die Herkunft der Anfrage; hinter einem Reverse Proxy zeigten sie sonst auf den internen Host (#007)
  • Eine Anmeldung über den Anbieter verknüpft nur mit einem bestehenden Konto, wenn die Adresse bestätigt ist (#007)
  • Ohne eingerichtete OIDC_GROUP_*-Zuordnung bleibt die Rolle unangetastet, statt jeden auf LESER herabzustufen (#007)
  • Der letzte aktive Administrator kann sich weder herabstufen noch abschalten (#007)
  • Beim Abschalten eines Kontos werden laufende Sitzungen sofort ungültig (#007)
  • Im Modus Intern wird eine vom Client mitgeschickte Kunden-Zuordnung verworfen, nicht bloß abgelehnt — es gibt in diesem Modus keine Kundenwahl (#008)
  • Der Rückweg nach Intern wird abgelehnt, solange mehr als ein nicht archivierter Kunde existiert (#008)
  • Die eigene Organisation lässt sich nicht archivieren (#008)