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>
80 lines
5.1 KiB
Markdown
80 lines
5.1 KiB
Markdown
# Changelog
|
||
|
||
Alle nennenswerten Änderungen an Laufzettel werden in dieser Datei dokumentiert.
|
||
|
||
Das Format basiert auf [Keep a Changelog](https://keepachangelog.com/de/1.1.0/),
|
||
und dieses Projekt folgt [Semantic Versioning](https://semver.org/lang/de/).
|
||
|
||
## [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 `tagCode`s 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)
|