docs: Bauprotokoll mit Zeiten, Aufwand und gefundenen Fehlern

Aufstellung, wann was entstanden ist und was es gekostet hat - zur
Nachvollziehbarkeit und zur Kostenrechnung.

Die reine Commit-Rechnung taugt hier nur bedingt: Die Etappen 2 bis 7
sind parallel entstanden, erst drei, dann fuenf Agenten gleichzeitig.
Aus der Historie sieht es aus, als haette Etappe 3 dreissig Minuten
gedauert - tatsaechlich lief sie knapp eine Stunde und gleichzeitig mit
vier anderen. Deshalb steht neben der automatischen Auswertung eine
Tabelle mit den tatsaechlichen Laufzeiten und den Ausgabe-Token je
Agent; daran bemessen sich die Kosten.

Ebenfalls festgehalten: die gut drei Stunden erzwungener Pause am
Sitzungslimit, die in der kalendarischen Spanne stecken, aber keine
Bauzeit sind. Reine Bauzeit rund zwei Stunden 45 Minuten.

Und die sechs Fehler, die waehrend des Baus aufgefallen sind - von der
Server/Client-Grenze bis zur Doppelzaehlung bei den Heimkosten. Die
stehen dort, weil sie zeigen, wo bei dieser Art Anwendung die
Fallstricke liegen.

Etappe: 8
Phase: Haertung
This commit is contained in:
Florian Wilde
2026-08-22 07:11:47 +02:00
parent dccc34d669
commit c5bd8b53d6
2 changed files with 160 additions and 0 deletions
+154
View File
@@ -0,0 +1,154 @@
# Bauprotokoll
Nachvollziehbare Aufstellung, wann was entstanden ist und was es gekostet
hat. Grundlage sind die Commit-Trailer `Etappe:` und `Phase:` sowie die
Abrechnung der beteiligten Agenten.
**Baubeginn:** 22.08.2026, 01:18 Uhr
**Bauende:** 22.08.2026, 07:10 Uhr
**Kalendarische Spanne:** 5 Stunden 52 Minuten
---
## Warum die reine Commit-Rechnung hier zu wenig sagt
`npm run protokoll` misst die Abstände zwischen Commits. Für eine Person,
die nacheinander arbeitet, ist das ein brauchbares Maß. Hier stimmt es
nicht: Die Etappen 2 bis 7 sind **parallel** entstanden — zuerst drei,
dann fünf Agenten gleichzeitig, jeder mit eigenem Kontext.
Aus der Commit-Historie sieht es deshalb so aus, als wären die Etappen 3
bis 7 in je 30 Minuten entstanden. Tatsächlich liefen sie **gleichzeitig
über rund zweieinhalb Stunden** und wurden am Ende in einem Rutsch
committet. Die ehrliche Aufstellung steht deshalb unten in der zweiten
Tabelle.
---
## Zeitlicher Ablauf
| Uhrzeit | Was |
|---|---|
| 01:18 | Leeres Verzeichnis, `git init` |
| 01:24 | Projektgerüst steht |
| 01:36 | Datenmodell vollständig (24 Entitäten, 2 SQL-Skripte) |
| 01:42 | Feldverschlüsselung, Argon2id, TOTP — 37 Tests |
| 01:46 | Anmeldung mit Pflicht-2FA, Rollen, Audit-Log |
| 01:54 | Oberflächenbausteine, Anwendungsrahmen, Konventionen |
| ~01:58 | **Drei Agenten starten** (Fristen, Vorgänge, Dashboard/Kontakte) |
| 02:16 | Stammdaten, Ersteinrichtung, Zweitfaktor, Protokoll |
| 02:22 | Erster echter Fehler gefunden und behoben (Server/Client-Grenze) |
| 02:24–02:26 | Etappe 2 committet, erste Screenshots |
| ~02:05 | **Fünf weitere Agenten starten** (Etappen 3 bis 7) |
| 02:35 | README, Datenschutztexte, Dockerfile, Sicherungsskripte |
| ~02:47 | Alle laufenden Agenten laufen ins Sitzungslimit |
| ~05:55 | Agenten wieder aufgenommen |
| 06:06 | Typisierung, CSP und Hydration repariert — null Typfehler |
| 06:21–06:22 | Etappen 3 bis 7 committet |
| 06:23 | Erinnerungen, Wartungslauf, erste Playwright-Tests |
| 07:10 | Abnahmekriterien als Tests, 34 End-to-End-Tests grün |
Zwischen 02:47 und 05:55 lag eine erzwungene Pause: Das Sitzungslimit war
erreicht und setzte erst um 06:00 Uhr zurück. Diese gut drei Stunden sind
in der kalendarischen Spanne enthalten, aber es wurde in ihnen nicht
gearbeitet. **Reine Bauzeit: rund 2 Stunden 45 Minuten.**
---
## Aufwand je Etappe
Die Spalte „Agent" nennt die Ausgabe-Token des jeweils zuständigen
Agenten — das ist die Größe, an der sich die Kosten bemessen. Etappe 1
und 8 sind ohne Agenten entstanden.
| Etappe | Phase | Bearbeitung | Laufzeit | Agent-Token | Tests |
|---|---|---|---:|---:|---:|
| 1 | Fundament | selbst, seriell | ~55 min | — | 37 |
| 2a | Fristen & Kalender | Agent | 25 min | 218.183 | 51 |
| 2b | Vorgänge & Genehmigungen | Agent | 25 min | 227.554 | 33 |
| 2c | Dashboard & Kontakte | Agent | 26 min | 273.673 | 25 + 26 |
| 3 | Papier | Agent | ~55 min | 356.318 | 57 |
| 4 | Geld | Agent | ~50 min | 328.065 | 68 |
| 5 | Behörde | Agent | ~53 min | 353.969 | 46 |
| 6 | Substanz | Agent | ~55 min | 369.070 | 74 |
| 7 | Ausgabe | Agent | ~57 min | 357.918 | 41 |
| 8 | Härtung | selbst | ~65 min | — | 34 (E2E) |
| | **Summe** | | | **2.484.750** | **492** |
Die Laufzeiten der Etappen 3 bis 7 setzen sich aus zwei Abschnitten
zusammen (vor und nach dem Sitzungslimit) und überlappen sich vollständig
— nacheinander gebaut hätten sie rund viereinhalb Stunden gedauert, so
waren es knapp eine.
---
## Was dabei entstanden ist
| | |
|---|---:|
| Dateien im Repository | 415 |
| Zeilen TypeScript/TSX | 71.051 |
| Commits | 19 |
| Prisma-Modelle | 24 |
| Unit-Tests (Vitest) | 458 |
| End-to-End-Tests (Playwright) | 34 |
| Seiten in der Anwendung | 46 |
| Hinweiskarten der Wissensbasis | 37 |
| Vorgangs-Vorlagen | 9 |
| TypeScript-Fehler | 0 |
---
## Fehler, die dabei gefunden wurden
Nicht alles lief glatt. Diese sechs Fehler sind während des Baus
aufgefallen und behoben worden — sie stehen hier, weil sie zeigen, wo bei
dieser Art Anwendung die Fallstricke liegen:
1. **Server/Client-Grenze.** Die Navigationsstruktur lag in einer Datei
mit `'use client'` und wurde im Server-Layout benutzt. Dort kommt kein
Wert an, sondern nur ein Verweis — jede Fachseite lief in einen
Serverfehler. Zusätzlich wurden Icons als React-Komponenten über die
Grenze gereicht, was ebenfalls nicht geht.
2. **CSP im Entwicklungsmodus.** `strict-dynamic` schaltet die Freigabe
nach Herkunft ab, also auch `'self'`. Hot-Reload und Fehleranzeige
laden ohne Nonce und wurden blockiert — man sah eine tote Seite statt
der Fehlermeldung.
3. **Nonce beim Hydrieren.** React gibt das `nonce`-Attribut absichtlich
nicht an den Browser weiter. Das Theme-Skript meldete deshalb bei
jedem Seitenaufruf eine Abweichung.
4. **Sperrmeldung kam nicht an.** Auth.js reicht den Fehlercode aus
`authorize()` nicht an die Server Action zurück. Bei gesperrtem Zugang
sah man nur „stimmen nicht" und hätte ratlos weiterprobiert.
5. **Anmeldungen fehlten im Protokoll.** Sie tragen keine `betreuteId` —
die Ansicht filterte danach und ließ ausgerechnet die Frage weg, wer
wann auf die Akte zugegriffen hat.
6. **Doppelzählung bei den Heimkosten.** Der einrichtungseinheitliche
Eigenanteil auf der Heimrechnung ist bereits um die Leistung der
Pflegekasse gekürzt. Wird sie zusätzlich als Deckung erfasst, entsteht
ein Fehler von über tausend Euro im Monat. Gefunden vom
Dashboard-Agenten, gelöst im Sozialhilfe-Modul.
Dazu kam eine Merkwürdigkeit der Werkzeuge: `@react-pdf/renderer` konnte
in diesem Abhängigkeitsbaum keinen einzigen Buchstaben setzen, weil seine
Unterabhängigkeiten weitergewandert sind. Die Krücke dafür steht in
`src/lib/pdf/standardschrift.ts` und baut sich selbst ab, sobald die
Auflösung wieder stimmt.
---
## Protokoll neu erzeugen
```bash
npm run protokoll # Tabelle auf der Konsole
npm run protokoll:md # Markdown
```
Das Skript wertet die Commit-Trailer aus. Für seriell gebaute Abschnitte
ist das genau; für parallel gebaute unterschätzt es den Aufwand — siehe
oben.
+6
View File
@@ -148,6 +148,12 @@ if (alsMarkdown) {
console.log('') console.log('')
console.log('Bauprotokoll') console.log('Bauprotokoll')
console.log('='.repeat(74)) console.log('='.repeat(74))
console.log(
'Hinweis: gemessen werden Commit-Abstaende. Fuer parallel gebaute
' +
'Etappen ist das zu wenig - siehe docs/BAUPROTOKOLL.md.',
)
console.log('-'.repeat(74))
for (const z of zeilen) { for (const z of zeilen) {
console.log( console.log(
`Etappe ${z.etappe.padEnd(4)} ${z.phase.padEnd(16)} ` + `Etappe ${z.etappe.padEnd(4)} ${z.phase.padEnd(16)} ` +