feat(betrieb): native Installation, Proxmox-Einzeiler und Abnahme
Zwei Wege in den Betrieb, beide so weit gefahren, wie es hier moeglich war. deploy/install.sh richtet Debian 13 in neun Schritten ein: PostgreSQL 17 hoert nur am Unix-Socket, der Dienstnutzer hat kein Login, die Geheimnisse entstehen im Zielsystem und liegen 0600 bei root. Die Umgebungsdatei wird nie ueberschrieben -- auch nicht beim Aktualisieren, sonst enden alle Sitzungen und die verschluesselten Bind-Passwoerter waeren unlesbar. deploy/proxmox/laufzettel.sh legt den Container an und ruft install.sh darin auf. Der pct-Teil ist ungetestet, weil kein PVE-Host zur Verfuegung stand; die Gegenprobe steht als Pruefliste in docs/betrieb/proxmox.md, das Folge-Issue ist #024. Die Abnahme gegen alle 61 Kriterien hat drei Zusagen ohne Deckung gefunden, alle behoben: der Healthcheck des Webdienstes konnte nie bestehen (busybox loest localhost nach ::1 auf, Next lauscht nur auf IPv4), die CI-Pipeline konnte in keinem Job gruen werden (kein LDAP-Dienst, kein gestarteter Server, kein shellcheck), und der README nannte fuer die Entwicklungsdatenbank den falschen Port. Closes #19
This commit is contained in:
+143
-2
@@ -21,11 +21,12 @@ als Unterpunkte mit Aufgabe und Dauer.
|
||||
| #016 | M11 – Verzeichnis und LDAP-Abgleich | 3 h 25 min |
|
||||
| #017 | M12 – Seed der sieben Vorlagen | 1 h 30 min |
|
||||
| #018 | M13 – E2E-Tests, Anleitung, PDF | 2 h 15 min |
|
||||
| | **Summe** | **29 h 55 min** |
|
||||
| #019 | M14 – Betriebswege und Release v0.1.0 | 5 h 25 min |
|
||||
| | **Summe** | **35 h 20 min** |
|
||||
|
||||
| Meilenstein | Tatsächlich | Status |
|
||||
|---|---|---|
|
||||
| v0.1.0 | 29 h 55 min | in Arbeit |
|
||||
| v0.1.0 | 35 h 20 min | veröffentlicht |
|
||||
|
||||
---
|
||||
|
||||
@@ -899,3 +900,143 @@ als Unterpunkte mit Aufgabe und Dauer.
|
||||
|
||||
- #019 Betriebswege und Release `v0.1.0` — `deploy/install.sh`, der Proxmox-One-Liner, die
|
||||
Betriebsdokumentation und der Tag mit Release-Notes.
|
||||
|
||||
---
|
||||
|
||||
## 2026-09-26 · Sitzung 15 · 10:50–16:15
|
||||
|
||||
**Issue:** #019 (M14)
|
||||
**Version:** 0.1.0
|
||||
|
||||
### Erledigt
|
||||
|
||||
- **`deploy/install.sh`** (1058 Zeilen): neun Schritte von den Voraussetzungen bis zum gestarteten
|
||||
Dienst, PostgreSQL 17 nur am Unix-Socket (`listen_addresses = ''`), Dienstnutzer ohne Login,
|
||||
Geheimnisse im Zielsystem erzeugt, systemd-Unit im Skript, `--test` als Selbstprüfung
|
||||
- **`deploy/proxmox/laufzettel.sh`** (963 Zeilen): der Einzeiler im Stil der Helper-Scripts, Dialog
|
||||
Standard gegen Erweitert, Trockenlauf, Erkennung eines vorhandenen Containers, `--aktualisieren`
|
||||
- **`docs/betrieb/`**: Inbetriebnahme, Proxmox, Reverse Proxy, Sicherung und eine Übersicht — dazu
|
||||
eine Prüfliste für den Teil, den hier niemand ausführen konnte
|
||||
- **Der gehärtete Compose-Stand einmal wirklich gefahren**, nicht nur gelesen: Migrationen laufen von
|
||||
selbst, der Seed bleibt ein Handgriff, `5432` ist vom Host dicht und aus `web` erreichbar
|
||||
- **Abnahme gegen alle 61 Kriterien** durch einen Agenten, der den Code nicht geschrieben hat:
|
||||
57 erfüllt, drei Befunde noch vor dem Tag behoben, drei Folge-Issues (#024–#026)
|
||||
- **Release `v0.1.0`**: Changelog-Abschnitt, Tag, Gitea-Release mit dem Anleitungs-PDF
|
||||
|
||||
### Entscheidungen
|
||||
|
||||
- **Die Umgebungsdatei wird nie überschrieben, auch nicht beim Aktualisieren.** Sonst würde ein
|
||||
Aktualisierungslauf das `APP_SECRET` neu erzeugen: alle Sitzungen enden, und die verschlüsselten
|
||||
LDAP-Bind-Passwörter wären unlesbar. Wer Schalter mitgibt, die deshalb nicht mehr wirken, bekommt
|
||||
eine Warnung statt stillen Gehorsams.
|
||||
- **Das Erstpasswort reist über eine Leihgabe, nicht über die Ausgabe.** Der Proxmox-Weg kann die
|
||||
Ausgabe von `install.sh` hinter `pct exec` nicht mitlesen. Sie mitzuschneiden und zu durchsuchen
|
||||
hätte das Passwort durch Pipes und Protokolldateien geschleift und von Formulierungen abgehangen.
|
||||
Stattdessen legt `install.sh` es auf Wunsch in eine Datei (0600, root), der Aufrufer liest sie
|
||||
einmal und löscht sie sofort — gelesen oder nicht.
|
||||
- **shellcheck läuft in CI im Container**, nicht aus dem Paketverzeichnis des Runners. So prüft die
|
||||
Pipeline genau die Fassung, die hier lokal geprüft wurde, und der Runner muss nichts mitbringen.
|
||||
- **Kriterium 4 bleibt offen statt „im Grunde erfüllt“.** Der `pct`-Teil ist nie gelaufen; hier stand
|
||||
kein Proxmox-Host. Abgehakt wird er, wenn ihn ein Mensch einmal gefahren hat — Prüfliste und
|
||||
Folge-Issue #024 stehen dafür bereit.
|
||||
|
||||
### Probleme
|
||||
|
||||
- **Der dokumentierte Weg startete nicht.** Der Compose-Stand las `DATABASE_URL` aus der `.env` —
|
||||
dort steht die Entwicklungsadresse mit `localhost`, die im Container ins Leere zeigt. Und der
|
||||
Einmal-Dienst für die Migration bekam kein `APP_SECRET`, weshalb der dokumentierte Seed-Befehl
|
||||
mitten im Lauf abbrach, nachdem die Vorlagen schon angelegt waren. Beides fiel erst auf, als der
|
||||
Stand zum ersten Mal wirklich gefahren wurde — die Suite war die ganze Zeit grün. **Ein Fehler im
|
||||
dokumentierten Weg eines Dritten ist für eine Testsuite unsichtbar.**
|
||||
- **Ein Healthcheck, der nie bestehen konnte.** busybox löst `localhost` im Container zuerst nach
|
||||
`::1` auf, Next lauscht nur auf IPv4. `docker compose ps` zeigte `web` dauerhaft als `unhealthy`,
|
||||
während die App einwandfrei antwortete. Jedes `docker compose up --wait` wäre in den Zeitablauf
|
||||
gelaufen. Wieder eine Zusage ohne Deckung — jetzt hält ein Test die Adresse fest.
|
||||
- **Die CI-Pipeline konnte in keinem Job grün werden.** Dem Prüf-Job fehlte das LDAP-Testverzeichnis,
|
||||
das `pnpm test` dort ausdrücklich verlangt; dem E2E-Job fehlte ein gestarteter Server, weshalb die
|
||||
Vorabprüfung aus #018 sofort abgebrochen hätte; und `shellcheck` wurde aufgerufen, ohne installiert
|
||||
zu sein. „Qualitätsschranken“ galt damit nur lokal. Gefunden hat das die Abnahme, nicht die Arbeit
|
||||
daran.
|
||||
- **Ich habe „shellcheck ohne Befund“ gemeldet, ohne es zu sein.** Der Satz kam aus einem `echo`, das
|
||||
unabhängig vom Ergebnis lief, während shellcheck vier SC1111-Warnungen ausgab. Das ist derselbe
|
||||
Fehler, den dieser Devlog seit #010 als teuersten beschreibt, nur diesmal in meiner eigenen
|
||||
Berichterstattung. Richtiggestellt, dann behoben — und seither wird jede Behauptung über ein
|
||||
Prüfergebnis am Exit-Status gemessen.
|
||||
- **Zwei Skripte, eine Naht.** `laufzettel.sh` übergibt seine Werte als Umgebungsvariablen, weil
|
||||
`pct exec` keine Befehlszeile durchreicht; `install.sh` las zunächst nur Schalter. Der Dienst wäre
|
||||
auf `127.0.0.1` gebunden geblieben, während der Abschlussbildschirm `http://<ip>:3000` versprach.
|
||||
Nahtstellen zwischen zwei Skripten prüft keine Suite — nur das Lesen beider Seiten.
|
||||
- **Der README nannte Port 5433, die Entwicklungsdatenbank hört auf 5434.** Wer dem README folgte,
|
||||
landete auf der Datenbank eines anderen Projekts. Der Hinweis darauf heißt „0 Treffer“ — genau die
|
||||
Meldung, die in #016 und #018 schon je einen halben Abend gekostet hat.
|
||||
|
||||
### Nächster Schritt
|
||||
|
||||
- Phase 1 ist abgeschlossen und veröffentlicht. Offen für `v0.2.0`: #020–#026, darunter der echte
|
||||
Proxmox-Lauf (#024), der die letzte offene Zeile der Abnahme schließt.
|
||||
|
||||
---
|
||||
|
||||
## Phase 1 abgeschlossen: was aus dem Plan wurde
|
||||
|
||||
**35 h 20 min** über vierzehn Meilensteine, geschätzt waren **148 h**. Der Faktor ist kein Verdienst,
|
||||
sondern eine Eigenschaft der Arbeitsweise: parallele Sub-Agenten an Stellen, wo die Schnittstelle
|
||||
vorher feststand, und ein Mensch, der nur an den Nahtstellen eingreift. Die Schätzung war für
|
||||
Menschenarbeit gedacht und bleibt als Maßstab stehen, weil sie den **Umfang** beschreibt.
|
||||
|
||||
### Was entstanden ist
|
||||
|
||||
| | |
|
||||
|---|---|
|
||||
| Quelltext | rund 30.000 Zeilen unter `src/` (ohne erzeugten Prisma-Client) |
|
||||
| Datenmodell | 20 Tabellen, 9 Aufzählungen, 2 Migrationen |
|
||||
| Tests | 1131 Vitest-Tests, 101 Ende-zu-Ende-Abläufe (`INTERN`), 97 (`DIENSTLEISTUNG`) |
|
||||
| Vorlagen | 7 Abläufe mit 155 Schritten, als veröffentlichte Version 1 im Seed |
|
||||
| Dokumentation | Anleitung in neun Kapiteln (72 Seiten PDF), Architektur, Betrieb, 14 Issue-Dateien |
|
||||
|
||||
### Wo die Zeit hinging
|
||||
|
||||
Der teuerste Meilenstein war **#019 Betriebswege** (5 h 25) — und zwar nicht wegen der beiden
|
||||
Skripte, sondern weil dort zum ersten Mal der **dokumentierte Weg eines Dritten** gefahren wurde:
|
||||
Compose-Stand hochziehen, Seed nach Anleitung, Installation in einem leeren Debian. Vier Fehler lagen
|
||||
genau dort, wo keine Suite hinsieht, und die Suite war die ganze Zeit grün.
|
||||
|
||||
Dahinter **#014 QR-Tags** (3 h 35), **#016 Verzeichnis** (3 h 25) und **#013 Läufe** (3 h 05) — alle
|
||||
drei nicht wegen des Umfangs, sondern wegen der Randfälle: ein Scanner, der die native Schnittstelle
|
||||
nie benutzte; ein Abgleich, der bei einem Tippfehler die ganze Firma abgeschaltet hätte; ein Passwort,
|
||||
das zweimal verschieden erzeugt wurde. Keiner dieser Fehler fiel beim Bauen auf. Alle drei fand der
|
||||
unabhängige Review.
|
||||
|
||||
### Was sich als richtig erwiesen hat
|
||||
|
||||
- **Ein Review-Agent je Meilenstein, der den Code nicht geschrieben hat.** In **jedem** der vierzehn
|
||||
fand er etwas, in neun davon etwas Ernstes. Die teuersten Funde waren nie Tippfehler, sondern
|
||||
Zusagen ohne Deckung: ein Kommentar, eine Oberflächenmeldung oder ein Testname, der etwas behauptet,
|
||||
das der Code nicht tut. Das ist der häufigste Fehlertyp dieses Projekts — vor Logikfehlern, weit
|
||||
vor Tippfehlern.
|
||||
- **Regeln in der Datenbank, nicht nur im Dienst.** Zwölf CHECK-Bedingungen, zwei partielle
|
||||
Eindeutigkeitsindizes, vier zusammengesetzte Fremdschlüssel und die Trigger auf veröffentlichten
|
||||
Versionen haben mehrfach Fehler abgefangen, die durch die Service-Schicht gekommen wären — zuletzt
|
||||
in #017, als der Seed eine veröffentlichte Version füllen wollte.
|
||||
- **Gegen den gebauten Stand prüfen.** `next dev` hydriert in dieser Umgebung nicht; ein Screenshot
|
||||
beweist nichts über Bedienbarkeit. Die Regel steht seit #010 in `CLAUDE.md` und hat sich in jedem
|
||||
Oberflächen-Meilenstein bewährt.
|
||||
|
||||
### Was ich anders machen würde
|
||||
|
||||
- **Zweimal gegen einen veralteten Server geprüft** (#016, #018), beide Male eine halbe Stunde. Die
|
||||
Konsequenz steht jetzt in der Arbeitsweise: erst `ps -eo lstart` gegen `.next/BUILD_ID` halten,
|
||||
dann der Seite glauben.
|
||||
- **Einmal in die falsche Datenbank geschrieben** (#017): Testprozess und Server zeigten
|
||||
woandershin, und die Meldung hieß „0 Treffer". Seit #018 prüft das ein `global-setup` vorab.
|
||||
- **Zwei eigene Tests konnten nicht scheitern** (#017, #018). Seitdem gehört die Gegenprobe zum
|
||||
Schreiben eines Tests: einmal absichtlich verletzen und sehen, ob er rot wird.
|
||||
- **Parallele Agenten im selben Verzeichnis** haben sich einmal gegenseitig eine Datei überschrieben
|
||||
(#018). Die Trennung muss an Dateien verlaufen, nicht an Themen.
|
||||
|
||||
### Was bewusst offen bleibt
|
||||
|
||||
Sechs Folge-Issues für `v0.2.0`: Vorgesetzter für von Hand angelegte Personen (#020), stabiler
|
||||
Schlüssel für Seed-Vorlagen (#021), Schnellstart je Gerätetyp pflegen (#022), Protokollansicht
|
||||
(#023). Dazu die Punkte, die der Abnahme-Review aufwirft. Nichts davon blockiert den Betrieb; alles
|
||||
davon steht geschrieben, statt verschwiegen zu werden.
|
||||
|
||||
Reference in New Issue
Block a user