Ziel, Erledigtes, die Entscheidungen mit Begründung, die Probleme samt Lösung und die offenen Punkte — allen voran, dass auch der Schreibweg nicht gegen die echten APIs geprüft werden konnte. Dauer laut zeiten.csv: 167 Minuten. Gesamt bislang 413 Minuten. Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
397 lines
22 KiB
Markdown
397 lines
22 KiB
Markdown
# 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 | 161 | 2,68 |
|
||
| M2 | claude | 44 | 0,73 |
|
||
| M3 | claude | 41 | 0,68 |
|
||
| M4 | claude | 167 | 2,78 |
|
||
| **Gesamt** | | **413** | **6,88** |
|
||
|
||
---
|
||
|
||
## 2026-09-10 – M4: Wochenplanung und Zeitblöcke
|
||
|
||
**Dauer:** 167 Minuten (20:42–23:29), Art `claude`.
|
||
|
||
**Ziel der Sitzung:** Die Kernidee des Projekts — Aufgaben per Ziehen und
|
||
Ablegen in echte Kalendertermine verwandeln, mit Rückweg.
|
||
|
||
### Erledigt
|
||
|
||
- `Zeitblock` samt Migration und Schleifenschutz (30 Tests)
|
||
- Schreibweg zu Graph und Google mit `If-Match`, Rückweg im Abgleich
|
||
- Rasterlogik für die Wochenansicht (21 Tests)
|
||
- Wochenansicht mit `@dnd-kit/core`: einplanen, verschieben, ausplanen
|
||
- Kapazität und Belegung je Wochentag
|
||
- 3 neue E2E-Tests, Handbuchseite
|
||
|
||
### Entscheidungen mit Begründung
|
||
|
||
**Der Fingerabdruck geht nur über Beginn und Ende.** Titel und Beschreibung
|
||
ändern sich auch aus harmlosen Gründen — etwa weil der Aufgabentitel
|
||
bearbeitet wurde. Für die Planung zählt allein, wann der Block liegt; alles
|
||
andere in den Fingerabdruck zu nehmen hieße, den Anbieter grundlos zu
|
||
behelligen.
|
||
|
||
**Der Kalender gewinnt, ausnahmslos.** Wer im Kalender etwas verschiebt,
|
||
meint es so. Säße der Planer am längeren Hebel, zöge er dem Benutzer den
|
||
Termin wieder weg — und der wüsste nicht, warum. Bei HTTP 412 verwirft der
|
||
Planer sogar seinen eigenen Fingerabdruck, damit der nächste Abgleich die
|
||
fremde Änderung sicher als solche erkennt.
|
||
|
||
**Scheitert das Schreiben, überlebt die Planung.** Der Zeitblock bleibt mit
|
||
vermerktem Fehler stehen. Ihn zu verwerfen hieße, die Planung des Benutzers
|
||
wegen eines Netzproblems zu vergessen; das nächste Verschieben trägt ihn
|
||
nach. Beim Löschen ist es umgekehrt: Da verschwindet der Zeitblock auch bei
|
||
unerreichbarem Kalender, sonst wäre die Planung blockiert.
|
||
|
||
**Die Dauer kommt aus dem geschätzten Aufwand.** Wer schätzt, bekommt die
|
||
passende Blockgröße geschenkt. Das belohnt genau die Gewohnheit, die die
|
||
Planung überhaupt erst tragfähig macht.
|
||
|
||
**Ziehen beginnt erst nach acht Pixeln.** Ohne diese Schwelle löst jeder
|
||
Klick einen Zug aus und die Knöpfe im Block wären nicht mehr bedienbar.
|
||
|
||
**Überbuchte Tage werden rot, aber nicht gesperrt.** Der Planer ist ein
|
||
Werkzeug, kein Aufpasser. Manchmal muss ein Tag überbucht sein.
|
||
|
||
### Probleme und Lösungen
|
||
|
||
| Problem | Lösung |
|
||
| --------------------------------------------------------------------------------------------------------------------- | ------------------------------------------------------------------------------------------------------------ |
|
||
| Ein Zeitblock steht auch im Terminspiegel und erschien doppelt — einmal als eigene Planung, einmal als fremder Termin | Die Wochenabfrage filtert Termine heraus, deren `extId` zu einem Zeitblock gehört. |
|
||
| Ein Build lief 32 Minuten statt Sekunden | Systemlast durch einen gleichzeitigen Docker-Bau. Ein sauberer Neubau danach: 46 Sekunden. Kein Codeproblem. |
|
||
| Sich überschneidende Termine lagen unsichtbar übereinander | `spurenVerteilen` legt sie nebeneinander und gibt eine Spur wieder frei, sobald sie zu Ende ist. |
|
||
|
||
### Offene Punkte
|
||
|
||
- **Der Schreibweg ist nicht gegen die echten APIs geprüft.** Wie in M3
|
||
fehlen die Zugangsdaten. Die Logik ist getestet, der erste echte Schreib-
|
||
und Rückweg ist Florians.
|
||
- Die Dauer lässt sich nicht am Balken ziehen; wer eine andere will, ändert
|
||
den Aufwand der Aufgabe.
|
||
- Ein Zeitblock landet immer im ersten verbundenen Kalender. Das
|
||
Standard-Kalenderkonto je Bereich ist im Datenmodell vorbereitet, aber
|
||
noch nicht in der Oberfläche.
|
||
|
||
### Commits
|
||
|
||
- 5791047 feat(zeitbloecke): Datenmodell und Schleifenschutz
|
||
- 9c1c916 feat(zeitbloecke): Schreibweg in den Kalender und Rückweg zurück
|
||
- bcb4b8e feat(woche): Rasterlogik für die Wochenansicht
|
||
- fada445 feat(woche): Wochenansicht mit Ziehen und Ablegen
|
||
- 5b1e998 test: Wochenansicht und Ausplanen absichern
|
||
- 0974695 docs: Handbuchseite zur Wochenplanung
|
||
|
||
---
|
||
|
||
## 2026-09-10 – M3: Kalender lesen
|
||
|
||
**Dauer:** 41 Minuten (17:48–18:29), Art `claude`.
|
||
|
||
**Ziel der Sitzung:** Termine aus Microsoft 365 und Google lesen, damit der
|
||
Planer weiß, wann überhaupt Platz ist.
|
||
|
||
### Erledigt
|
||
|
||
- `Kalenderkonto` und `Termin` samt Migration; Bereich bekommt sein
|
||
Standard-Kalenderkonto für M4
|
||
- Tokenverschlüsselung mit AES-256-GCM
|
||
- Antworten beider Anbieter mit zod geprüft und in eine gemeinsame Form
|
||
gebracht, geprüft gegen anonymisierte Beispielantworten
|
||
- Belegungsrechnung: Kapazität gegen Termine, freie Fenster für M4
|
||
- OAuth-Verbinden, Tokenerneuerung, seitenweiser Abgleich mit Rückfall auf
|
||
einen vollständigen Durchlauf
|
||
- Seite für die Kalenderkonten, Belegung des Tages auf der Startseite
|
||
- Hintergrundjobs für Abgleich und nächtliches Aufräumen
|
||
- 68 neue Unit-Tests, 10 neue Integrationsprüfungen
|
||
- Handbuchseite und Einrichtungsanleitung für Entra ID und Google
|
||
|
||
### Entscheidungen mit Begründung
|
||
|
||
**Tokens verschlüsselt, Schlüssel aus AUTH_SECRET abgeleitet.** Wer die
|
||
Datenbank oder eine Sicherung bekommt, hätte sonst direkten Zugriff auf
|
||
fremde Kalender — das wiegt schwerer als bei den OIDC-Tokens aus M1, die
|
||
nur die Anmeldung betreffen. Eine eigene Pflichtvariable wäre eine weitere
|
||
Stelle, an der die Einrichtung scheitert; die Ableitung über HKDF kostet
|
||
nichts und hat die richtige Nebenwirkung: wer AUTH_SECRET wechselt, muss
|
||
die Konten neu verbinden — dann sind ohnehin alle Sitzungen ungültig.
|
||
|
||
**Bei fremder Zeitzone abbrechen statt raten.** Graph liefert Datum und
|
||
Zeitzone getrennt, ohne Versatz im Text. Wir fragen ausdrücklich UTC an;
|
||
kommt etwas anderes zurück, wäre jede Umrechnung geraten und würde Termine
|
||
um Stunden verschieben. Ein Abbruch mit klarer Meldung ist besser als ein
|
||
Kalender, der leise falsch liegt.
|
||
|
||
**Unbekanntes showAs zählt als belegt.** Lieber eine Stunde zu viel
|
||
blockiert als eine Doppelbuchung.
|
||
|
||
**Schreibrechte schon jetzt anfragen.** M3 liest nur, aber M4 schreibt.
|
||
Später erneut zuzustimmen ist genau der Schritt, an dem Einrichtung
|
||
scheitert — einmal breiter fragen ist das kleinere Übel.
|
||
|
||
**Ganztägige Termine zählen nicht zur Belegung.** Ein Urlaubstag oder
|
||
Geburtstag blockiert sonst den ganzen Tag, obwohl er keine Arbeitszeit
|
||
kostet.
|
||
|
||
**Alle Kalender zählen gegen jeden Bereich.** Ein Termin blockiert die Zeit
|
||
ohnehin, gleich zu welchem Lebensbereich er gehört.
|
||
|
||
**Kein SDK für Graph und Google.** Es geht um drei Aufrufe je Anbieter, und
|
||
die Antworten werden ohnehin mit zod geprüft. Ein SDK brächte vor allem
|
||
Abhängigkeiten und blinde Flecken.
|
||
|
||
### Probleme und Lösungen
|
||
|
||
| Problem | Lösung |
|
||
| ----------------------------------------------------------------------- | ----------------------------------------------------------------------------------------------------------------------------------------------------- |
|
||
| Prisma lässt in einem zusammengesetzten Unique-Schlüssel kein null zu | `kalenderId` ist nicht optional, sondern trägt den sprechenden Wert `"standard"` für den Standardkalender. |
|
||
| Googles `syncToken` verträgt sich nicht mit `timeMin`/`timeMax` | Folgeabgleiche liefern auch Änderungen außerhalb des Fensters. Was daneben liegt, wird beim Spiegeln verworfen — sonst wüchse der Spiegel unbegrenzt. |
|
||
| Der Verweis für die nächste Runde kann ablaufen (HTTP 410) | Verweis verwerfen, Spiegel leeren, von vorn lesen. Der Ablauf ist so gebaut, dass ein vollständiger Durchlauf jederzeit möglich ist. |
|
||
| Die Shell zerlegte in mehreren Anläufen Template-Literale und Backticks | Auf `node - <<'SKRIPT'` umgestellt; damit geht der Text unverändert durch. |
|
||
|
||
### Offene Punkte
|
||
|
||
- **Nicht gegen die echten APIs getestet.** Ich habe keine Zugangsdaten für
|
||
Entra ID oder Google. Provider und Abgleich sind gegen anonymisierte
|
||
Beispielantworten geprüft; den ersten echten Verbindungsversuch muss
|
||
Florian machen. Die Anleitung dafür steht in der README.
|
||
- Nur der Standardkalender je Konto. Mehrere Kalender desselben Kontos sind
|
||
im Datenmodell vorgesehen, es fehlt die Auswahl in der Oberfläche.
|
||
- Der Abgleich läuft in einer Schleife über alle Konten. Bei vielen Konten
|
||
wäre das nacheinander zu langsam; bei der erwarteten Zahl ist es das
|
||
einfachere Verhalten.
|
||
|
||
### Commits
|
||
|
||
- 79e6c0d feat(kalender): Datenmodell für Kalenderkonten und Termine
|
||
- 6fda2a5 feat(kalender): Antworten von Graph und Google lesen, Belegung rechnen
|
||
- 9946e7c feat(kalender): OAuth und Abgleich für Graph und Google
|
||
- 0c67b73 feat(kalender): Seite für die Kalenderkonten
|
||
- 42c98c8 feat(kalender): Hintergrundjobs für Abgleich und Aufräumen
|
||
- d8d3227 feat(kalender): Belegung des Tages auf der Startseite
|
||
- df50627 test: Verschlüsselung und Kalendermodelle absichern
|
||
- a8b2ff0 docs: Handbuchseite und Einrichtung der Kalenderanbieter
|
||
|
||
---
|
||
|
||
## 2026-09-10 – M2: Aufgaben und Projekte
|
||
|
||
**Dauer:** 44 Minuten (15:57–16:41), Art `claude`.
|
||
|
||
**Ziel der Sitzung:** Erfassen und Wiederfinden — Aufgaben, Inbox, Ideen und
|
||
Projekte. Noch ohne Kalender.
|
||
|
||
### Erledigt
|
||
|
||
- Datenmodell `Aufgabe` und `Projekt` samt Migration
|
||
- Schnellerfassung, Inbox mit Einsortieren, Aufgabenliste mit Filtern
|
||
- Ideen als eigene Ansicht, mit Übernahme in eine Aufgabe
|
||
- Projekte mit Arbeitspaketen, Meilensteinen und Fortschritt
|
||
- Startseite zeigt jetzt, was überfällig oder demnächst fällig ist
|
||
- 53 neue Unit-Tests, 11 neue Integrationsprüfungen, 4 neue E2E-Tests
|
||
- Handbuchseiten zu Aufgaben, Ideen und Projekten; Bilder neu aufgenommen
|
||
|
||
### Entscheidungen mit Begründung
|
||
|
||
**Die Inbox ist kein eigener Zustand.** Eine Aufgabe liegt genau dann in der
|
||
Inbox, wenn sie keinen Bereich hat. Ein zusätzliches Feld „einsortiert"
|
||
hätte mit der Zuordnung auseinanderlaufen können; so ist der Zustand nicht
|
||
darstellbar.
|
||
|
||
**Projekt als eigenes Modell, nicht als Aufgabentyp.** Ein Projekt hat
|
||
selbst weder Aufwand noch Fälligkeit — beides ergibt sich aus dem Inhalt.
|
||
`ARBEITSPAKET` und `MEILENSTEIN` bleiben Typen der Aufgaben _innerhalb_
|
||
eines Projekts.
|
||
|
||
**Verworfene Aufgaben zählen gar nicht in den Fortschritt.** Weder als
|
||
erledigt noch als offen. Sonst sähe ein Projekt fertig aus, weil die Hälfte
|
||
gestrichen wurde — eine Zahl, die lügt, ist schlechter als keine.
|
||
|
||
**Sortiert wird in der Anwendung, nicht in SQL.** Die Reihenfolge ist
|
||
mehrstufig (offen vor abgeschlossen, dann Termin, dann Priorität, dann Titel
|
||
mit deutscher Sortierung). Als geprüfte reine Funktion steht sie an einer
|
||
Stelle; eine zweite Fassung in SQL wäre eine Fehlerquelle. Bei den erwarteten
|
||
Mengen ist das unkritisch — sollte es einmal eng werden, ist der Ort für die
|
||
Änderung klar.
|
||
|
||
**Filter stehen in der Adresse.** Eine gefilterte Liste lässt sich als
|
||
Lesezeichen ablegen, und der Zurück-Knopf tut, was er soll.
|
||
|
||
**Statuswechsel folgen festen Übergängen.** Aus `ERLEDIGT` und `VERWORFEN`
|
||
geht es nur zurück nach `OFFEN`. Wer per Formular etwas anderes einreicht,
|
||
bekommt eine Meldung — nicht einen stillen Zustandssprung.
|
||
|
||
**Fälligkeit in Kalendertagen, nicht in Stunden.** Was heute um 23:00 fällig
|
||
ist, ist heute fällig. Alles andere fühlt sich beim Benutzen falsch an.
|
||
|
||
**Natives `<select>` statt einer eigenen Auswahlkomponente.** Es bedient
|
||
sich auf dem Handy mit dem Systemdialog, ist ohne Zusatzcode
|
||
tastaturbedienbar und braucht kein JavaScript zum Absenden.
|
||
|
||
### Probleme und Lösungen
|
||
|
||
| Problem | Lösung |
|
||
| ----------------------------------------------------------------------- | ------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- |
|
||
| ESLint beanstandete `String(antwort.meldung)` | Ich hatte die Rückmeldung als `Record<string, unknown>` typisiert, statt den vorhandenen `Rueckmeldung`-Typ zu nehmen. Mit dem richtigen Typ entfällt die Umwandlung ganz. |
|
||
| Zwei Stellen rechneten die Tagesgrenze mit einem `toLocaleString`-Trick | `src/lib/zeit.ts` konnte das längst sauber. Beide Stellen nutzen jetzt `tagesBeginn()` beziehungsweise `alsTagesschluessel()`; die Tests belegen gleiche Ergebnisse bei weniger Code. |
|
||
| Typfehler nach der Migration | Der Prisma-Client muss nach jeder Schemaänderung neu erzeugt werden. `npm run pruefen` tut das inzwischen selbst, wenn er fehlt — hier war er nur veraltet. |
|
||
|
||
### Eigene Fehler, die ich korrigiert habe
|
||
|
||
- Im Demo-Seed stand versehentlich ein kyrillisches Wort als Titel eines
|
||
Meilensteins. Ersetzt durch „Seite ist online".
|
||
- Ein Test erwartete, dass 481 Minuten Aufwand erlaubt sind; die Grenze
|
||
liegt bei 480. Der Test war falsch, nicht der Code — jetzt prüft er die
|
||
Grenze selbst und den ersten Wert darüber.
|
||
|
||
### Offene Punkte
|
||
|
||
- Kein Wiederholungsrhythmus für Aufgaben und keine Verknüpfung von Aufgaben
|
||
untereinander. Beides steht bewusst unter „Ideen für später" und wartet
|
||
darauf, ob es im Alltag wirklich fehlt.
|
||
- Die Aufgabenliste lädt bis zu 500 Einträge auf einmal. Für den erwarteten
|
||
Bestand reicht das; eine Blätterfunktion kommt, wenn es eng wird.
|
||
|
||
### Commits
|
||
|
||
- 63c3c15 feat(aufgaben): Datenmodell und Regeln für Aufgaben und Projekte
|
||
- b3ca1c9 feat(aufgaben): Server Actions und Abfrageschicht
|
||
- a4a889f feat(aufgaben): Inbox, Aufgabenliste, Ideen und Projekte
|
||
- 7c8fe10 test: Erfassungsweg und Eindeutigkeit der Quellen absichern
|
||
- 144457b fix(aufgaben): Ideen aus Aufgabenliste und Inbox heraushalten
|
||
- 4d0f83f chore: Demo-Daten für die neuen Seiten erweitern
|
||
- d01c49b docs: Handbuchseiten zu Aufgaben, Ideen und Projekten
|
||
|
||
---
|
||
|
||
## 2026-09-10 – M1: Fundament
|
||
|
||
**Dauer:** 161 Minuten (12:06–14:47), Art `claude`.
|
||
|
||
**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
|
||
|
||
- de1f923 chore: Projektgerüst und Werkzeugkette einrichten
|
||
- 748d032 feat(datenbank): Datenmodell für Anmeldung, Bereiche und Audit
|
||
- e2b00f4 feat(instanz): Instanzsteuerung mit serverseitigem Riegel
|
||
- 19ca082 feat(zeit): Zeitrechnung und Anzeigeformate in Europe/Berlin
|
||
- 4ff67c1 feat(oberflaeche): Grundlayout, Navigation und Farbschema
|
||
- cc013fd feat(anmeldung): OIDC, Passkeys und Passwort mit Auth.js v5
|
||
- e9a2b4b feat(bereiche): Bereiche verwalten mit Rollenprüfung und Audit
|
||
- 1876ae4 feat(betrieb): Health-Endpunkt und Seed für eine frische Datenbank
|
||
- 24a799d chore: tsconfig-Anpassungen von Next 16 übernehmen
|
||
- 126ad93 test: Integrations-, Migrations- und E2E-Tests ergänzen
|
||
- f91d015 feat(betrieb): Abbild, Compose-Stapel und Betriebsskripte
|
||
- 56b5356 docs: README, Schnellstart, Handbuch, Fahrplan und CHANGELOG
|
||
- e3390c8 refactor: middleware in proxy umbenennen
|
||
- a882731 chore: Screenshot-Kette und Demo-Seed
|
||
- cf28ec1 test: Rollentrennung end-to-end absichern
|
||
- 6d04bc2 fix(oberflaeche): Kopfleiste einzeilig halten, Demo-Uhr feststellen
|
||
- 688d9f5 docs: Handbuchbilder aufnehmen
|