# Entwicklungstagebuch Neuester Eintrag oben. Die Dauer je Sitzung stammt aus `devlog/zeiten.csv`, die Übersicht aus `scripts/zeit.sh summe`. ## Zeit je Meilenstein | Meilenstein | Art | Minuten | Stunden | | ----------- | ------ | ----------------------------------- | ------- | | M1 | claude | _(wird beim Abschluss eingetragen)_ | | --- ## 2026-09-10 – M1: Fundament **Ziel der Sitzung:** Das Projekt von Grund auf aufsetzen: Gerüst, Datenbank, Anmeldung, Rollen, Audit, Instanzsteuerung, Betrieb und Dokumentation. ### Erledigt - Projektgerüst mit Next 16, React 19, TypeScript strict, Tailwind 4, alle Versionen exakt gepinnt - `npm run pruefen` als Sammelprüfung: Prettier, ESLint, `tsc`, Vitest, ShellCheck - Datenmodell und erste Migration: Benutzer mit Rolle, OIDC-Konten, Passkeys, WebAuthn-Herausforderungen, Bereiche, Audit - Anmeldung über OIDC, Passkey und Passwort, je Instanz zuschaltbar - Rollenprüfung in Seite **und** Server Action, Audit je Schreibaktion - Instanzsteuerung mit 404 statt Hinweis - Bereiche verwalten, Protokollseite, Startseite, Einstellungen - `/api/health`, Dockerfile, Compose-Stapel mit Migrationsdienst - `backup.sh`, `update.sh`, `scripts/release.sh`, `scripts/zeit.sh` - Unit-, Integrations-, Migrations- und E2E-Tests - Screenshot-Kette mit eigener Wegwerf-Instanz - README, Schnellstart, Handbuch, ROADMAP, CHANGELOG ### Entscheidungen mit Begründung **Prisma 7.10.0 statt der notierten Fassung 6.** Fassung 6 ist überholt, Fassung 8 liegt nur als RC auf `latest`. Prisma 7 nimmt die Verbindung nicht mehr im Schema entgegen — sie steht in `prisma.config.ts`, der Client bekommt den pg-Treiberadapter. **TypeScript 6.0.3 statt 7.0.2.** TS 7 ist zwar `latest`, aber `typescript-eslint@8.70` verlangt `typescript >=4.8.4 <6.1.0`. Mit TS 7 wäre die Lint-Kette kaputt gewesen. **ESLint 9.39.5 statt 10.** Das in `eslint-config-next@16` gebündelte `eslint-plugin-react` ruft noch `context.getFilename()`, das ESLint 10 entfernt hat. Der Lint-Lauf brach reproduzierbar ab. **Eigener Auth.js-Adapter.** Der mitgelieferte `@auth/prisma-adapter` greift fest auf `prisma.user` und `prisma.account` zu; unsere Modelle heißen `Benutzer` und `Konto`. Der Adapter ist schmal und ersparte es, die Fachbegriffe der Konvention zu opfern. **Passkeys direkt über SimpleWebAuthn 14.** Der WebAuthn-Provider von Auth.js ist als experimentell markiert und auf SimpleWebAuthn 9 festgelegt. Direkt angebunden bleibt die Fassung aktuell und der Ablauf nachvollziehbar. Für die npm-Auflösung brauchte es `overrides`, weil next-auth die älteren Fassungen als optionale Peers deklariert. **Sitzungen als JWT, Rolle trotzdem aus der Datenbank.** Credentials- Provider verlangen JWT. Damit eine Sperre nicht bis zum Ablauf des Tokens wirkungslos bleibt, liest der `session`-Callback Rolle und Status bei jeder Anfrage frisch. Die Tabellen `sitzung` und `verifizierungs_token` wären damit tot und wurden wieder entfernt, solange es nur eine einzige Migration gab. **Migrationen als eigener Compose-Dienst.** Der Versuch, nur die Prisma-CLI ins schlanke Laufzeitabbild zu kopieren, scheiterte an ihren transitiven Modulen (`effect` über `@prisma/config`). Alle mitzunehmen hätte das Abbild aufgebläht. Ein Einmaldienst aus der Bau-Stufe läuft vor der App und muss sauber durchlaufen. **Aufgabe, Zeitblock und Kalenderkonto bewusst nicht modelliert.** Sie kommen mit M2, M4 und M3 — dann mit den Feldern, die der jeweilige Provider wirklich braucht, statt heute geraten. ### Probleme und Lösungen | Problem | Lösung | | ------------------------------------------------------------------- | ------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- | | `prisma validate` lehnte `url` im Schema ab | Prisma 7 erwartet die Verbindung in `prisma.config.ts` und einen Treiberadapter im Client. | | Integrationstest brach nach der ersten erwarteten Verletzung ab | In PostgreSQL bricht ein fehlgeschlagener Befehl die ganze Transaktion ab. Der Test läuft jetzt ohne Sammeltransaktion; alle Testdaten tragen eine Kennung und werden am Ende entfernt. | | `prisma migrate diff` kannte `--from-url` nicht | In Prisma 7 heißen die Flaggen anders. Der Test vergleicht jetzt die eingespielte Wegwerf-Datenbank über `--from-config-datasource` gegen das Schema — und braucht damit keine Schattendatenbank. | | Nach der Anmeldung ging es nicht zum ursprünglichen Ziel zurück | Das Layout leitet um, bevor die Seite drankommt, und kennt seinen Pfad nicht. Ein schlanker Proxy reicht ihn als Kopfzeile durch — ohne Anmeldelogik, weil er im Edge-Umfeld läuft. | | Der Docker-Bau brach beim Sammeln der Seitendaten ab | Prisma-Client und Auth.js-Konfiguration wurden beim Laden des Moduls ausgewertet und brauchten Umgebungsvariablen, die es zur Bauzeit nicht gibt. Beide entstehen jetzt faul. | | Ein Typfehler in `scripts/screenshots.ts` blockierte den Abbild-Bau | Entwicklungsskripte gehören nicht in den Docker-Kontext. `.dockerignore` schließt sie aus; geprüft werden sie von `npm run pruefen`. | | ESLint beanstandete `setState` im Effekt | Der Hydratations-Trick im Farbschema-Knopf war unnötig: `next-themes` setzt die `dark`-Klasse vor der Hydratation, das erledigt CSS ohne Zustand. | ### Eigene Fehler, die ich korrigiert habe - Die ersten vier Commits lagen direkt auf `main` statt auf einem Meilenstein-Zweig und ohne Attributionszeile. Historie umgebaut: `main` trägt nur noch einen leeren Wurzel-Commit, die Arbeit liegt auf `m1-fundament`. - Ein `git add -A` zog die Proxy-Umbenennung in den Doku-Commit. Wieder getrennt. - `scripts/screenshots.ts` wurde geschrieben, ohne danach `npm run pruefen` laufen zu lassen; der Typfehler fiel erst im Docker-Bau auf. ### Offene Punkte - Die `origin`-URL fehlt noch. Push und Merge stehen ohnehin erst nach der Freigabe an. - Der Schnellstart endet beim Passkey statt beim ersten Kalenderkonto und der ersten Aufgabe — beides gibt es erst mit M3 und M2. - Der Demo-Seed enthält noch keine erfundenen Termine; einen Demo-Kalenderprovider gibt es erst mit M3. - Lokal weichen die Ports ab (Datenbank 5435, App 3001), weil 5432 und 3000 auf diesem Rechner belegt sind. In `.env.example` stehen die üblichen Werte. ### Commits Siehe `git log --oneline main..m1-fundament`.