# 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) - Versionierte Vorlagen: „Bearbeiten“ erzeugt eine tiefe Kopie der zuletzt veröffentlichten Version als Entwurf, je Vorlage gibt es höchstens einen. Veröffentlichen hält Zeitpunkt, Urheber und Änderungsnotiz fest (#009) - Vorlagen duplizieren und archivieren statt löschen (#009) - JSON-Export und -Import für Vorlagen, Format dokumentiert in `docs/vorlagen-format.md` (#009) - Zwei Redakteure am selben Entwurf treten sich nicht mehr auf die Füße: wer auf einem überholten Stand speichert, wird abgewiesen statt die Arbeit des anderen spurlos zu überschreiben (#009) - Vorlagenliste mit Suche, Filter nach Kategorie und Schlagwort und dem Kennzeichen „Entwurf vorhanden“; eine Vorlage lässt sich anlegen, duplizieren, archivieren und als JSON ein- und ausspielen (#010) - Vorlagen-Editor: Abschnitte, Schritte und Variablen anlegen, bearbeiten, löschen und sortieren — mit dem Finger, der Maus, der Tastatur oder zwei Knöpfen an jeder Zeile (#010) - Typabhängige Felder je Schritt: Auswahloptionen, Zahlenbereich mit Einheit, mehrzeiliger Text, Shell und Befehlstext; Hilfetexte als Markdown, dazu ein Doku-Link (#010) - Warnung im Editor, wenn ein Platzhalter zu keiner Variablen und zu keinem eingebauten Wert gehört — sie blockiert nichts, sie zeigt den Tippfehler, bevor der Techniker ihn im Lauf findet (#010) - Vorschau der Vorlage mit Beispielwerten, so wie ein Lauf sie zeigen wird (#010) - Versionsgeschichte je Vorlage: wer wann mit welcher Notiz veröffentlicht hat und wie viele Läufe an einer Version hängen (#010) ### 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 — `//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) - Eine veröffentlichte Vorlagen-Version ist unveränderlich: jeder Schreibversuch wird abgewiesen, und ein bestehender Lauf zeigt auch nach neuen Veröffentlichungen genau die Schritte, mit denen er gestartet wurde (#009) - Die Unveränderlichkeit setzt zusätzlich die Datenbank durch, damit auch Migrationen, `psql` und spätere Connectoren nicht daran vorbeischreiben können; der Rückweg nach Entwurf ist versperrt (#009) - Vorlagen eines fremden Kunden bleiben auch bei Suche und Filtern verborgen, und Historie wie Aufbau einer Version geben nichts heraus, was der Benutzer nicht sehen darf (#009) - Der Doku-Link eines Schritts nimmt nur `http` und `https` an; über eine importierte Datei wäre ein `javascript:`-Link sonst fremder Code im Browser des Technikers (#009) - Hilfetexte werden als Markdown ohne rohes HTML gerendert — ein Skript im Hilfetext einer eingespielten Vorlage bleibt sichtbarer Text (#010) - Der Doku-Link eines Schritts wird auch in der Vorschau nur dann verlinkt, wenn er `http` oder `https` ist — dort hat ihn das Schema noch nicht gesehen (#010) - Die Content-Security-Policy lockert `unsafe-eval` und WebSocket-Verbindungen **nur** im Entwicklungsmodus; ein Test prüft die Entscheidung im Proxy selbst und nicht bloß die Funktion darunter (#010) - Eine abgelaufene Anmeldung beendet den Vorgang mit einer Meldung, statt die Seite auszuhängen — im Editor wäre sonst jede ungespeicherte Arbeit verloren gewesen (#010) - Eine archivierte Kundenzuordnung bleibt beim Speichern der Kopfdaten erhalten, statt sich stillschweigend in „für alle Kunden“ zu verwandeln (#010)