Baustein 1: Grundgeruest, Datenbank, Anmeldung, zwei Rollen
Legt das Fundament der Lern-Bar an: - Next.js 15 (App Router), React 19, TypeScript, ESLint, Vitest - SQLite ueber Drizzle hinter einer Repository-Schicht - Eigener Migrationslauf mit Pruefsummen, beim Start angewendet - Argon2id, serverseitige Sitzungen, HttpOnly-Cookie, SameSite=Lax - Rollen Ausbilder und Azubi, Rechteregeln als reine Funktionen - Verwaltung: Azubikonto und Ausbildung anlegen, Passwort, Sperren - Gestaltung Petrol/Bernstein, helle und dunkle Darstellung - Dockerfile, docker-compose, Lebenszeichen, update.sh mit Rueckfall - Sicherung und Wiederherstellung als Shell-Skripte - 29 Tests fuer Rechte, Zeitrechnung und Migrationslauf Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com>
This commit is contained in:
@@ -0,0 +1,84 @@
|
||||
# Entscheidungen
|
||||
|
||||
Kurze Notizen zu Festlegungen, die im Auftrag offen waren. Jede Notiz nennt
|
||||
die Lage, die Wahl und den Grund.
|
||||
|
||||
---
|
||||
|
||||
## E1 · Stack: Next.js 15 mit App Router
|
||||
|
||||
Der Auftrag verweist auf eine Stackvorgabe im „Kopf des Prompts", die nicht
|
||||
mitgeliefert wurde. Auf Rückfrage: **Next.js 15 (App Router), React 19,
|
||||
TypeScript**. Datenzugriff über Drizzle ORM auf better-sqlite3.
|
||||
|
||||
Serveraktionen ersetzen eine eigene REST-Schicht. Das hält die Rechteprüfung
|
||||
dort, wo die Daten geholt werden, statt sie über eine API zu verteilen.
|
||||
|
||||
## E2 · Zeitstempel als ISO-8601 in UTC
|
||||
|
||||
Der Auftrag verlangt „alle Zeitstempel mit Zeitzone". Gespeichert wird
|
||||
`2026-09-10T07:15:00.000Z`, also ein eindeutiger Zeitpunkt in UTC. Angezeigt
|
||||
wird durchgehend in Europe/Berlin.
|
||||
|
||||
Grund: UTC-Strings sortieren sich lexikografisch richtig, was bei SQLite ohne
|
||||
echten Zeitstempeltyp entscheidend ist. Ein gespeicherter Ortsversatz
|
||||
(`+02:00`) würde beim Wechsel zwischen Sommer- und Winterzeit falsch sortieren.
|
||||
|
||||
Reine Kalenderdaten – Berichtszeitraum, Tagesnotiz, Ausbildungsbeginn – sind
|
||||
`YYYY-MM-DD` ohne Uhrzeit, weil sie auch keine haben.
|
||||
|
||||
## E3 · Eigener Migrationslauf statt drizzle-kit
|
||||
|
||||
Migrationen sind handgeschriebene SQL-Dateien unter
|
||||
`src/lib/db/migrationen/`, die beim Start der Reihe nach genau einmal
|
||||
angewendet und mit SHA-256-Prüfsumme vermerkt werden.
|
||||
|
||||
Grund: volle Kontrolle über Indizes und `CHECK`-Bedingungen (Statuswerte sind
|
||||
Aufzählungen, keine freien Zeichenketten), und beim Start ist im Protokoll
|
||||
sichtbar, was passiert ist. Wird eine bereits angewendete Datei nachträglich
|
||||
verändert, bricht der Start mit klarer Meldung ab.
|
||||
|
||||
Der Preis: das Drizzle-Schema muss von Hand zu den SQL-Dateien passen. Dagegen
|
||||
läuft ein Test, der die migrierte Datenbank gegen das Schema abgleicht.
|
||||
|
||||
## E4 · Schlüssel sind UUIDs, keine laufenden Nummern
|
||||
|
||||
Textspalten mit `crypto.randomUUID()`. Läuft auf SQLite und PostgreSQL
|
||||
gleichermaßen, und beim Zurückspielen einer Sicherung gibt es keine Kollisionen
|
||||
mit zwischenzeitlich vergebenen Nummern.
|
||||
|
||||
## E5 · Debian-slim als Grundlage des Abbilds, nicht Alpine
|
||||
|
||||
`better-sqlite3` und `@node-rs/argon2` bringen für glibc fertige Binärdateien
|
||||
mit, für musl nicht. Auf Alpine müsste im Abbild übersetzt werden – längerer
|
||||
Bau, größere Bauschicht, mehr Fehlerquellen. Der Größenunterschied im
|
||||
Laufzeitabbild ist bei einem selbst gehosteten Dienst ohne Belang.
|
||||
|
||||
## E6 · Passwortprüfung mit gleichbleibender Antwortzeit
|
||||
|
||||
Bei unbekannter E-Mail-Adresse wird trotzdem einmal gegen einen festen
|
||||
Argon2-Wert gerechnet. Sonst verrät die Antwortzeit, welche Adressen es gibt.
|
||||
Die Fehlermeldung ist in beiden Fällen dieselbe.
|
||||
|
||||
## E7 · Anhänge liegen im Dateisystem, nicht in der Datenbank
|
||||
|
||||
Unter `<daten>/anhaenge/`, in der Datenbank steht nur der Verweis. Hält die
|
||||
Datenbankdatei klein und die Sicherung schnell; das Archiv nimmt beides mit.
|
||||
|
||||
## E8 · Sicherung als Shell-Skript, nicht als Node-Werkzeug
|
||||
|
||||
`scripts/im-container/sicherung.sh` läuft im Laufzeitabbild, das kein
|
||||
TypeScript kennt, und auf dem Entwicklungsrechner unter Git Bash. Eine zweite
|
||||
Fassung in TypeScript wäre eine zweite Fehlerquelle. Die konsistente Kopie der
|
||||
Datenbank entsteht über die Sicherungsschnittstelle von SQLite – ein `cp` wäre
|
||||
bei aktivem WAL-Modus nicht verlässlich.
|
||||
|
||||
## E9 · Kein `main`-Zweig ohne Freigabe
|
||||
|
||||
Die verbindliche Arbeitsweise verbietet Commits direkt auf `main`. Die
|
||||
Erstfassung entsteht deshalb vollständig auf `feat/lernbar-erstfassung`.
|
||||
`main` bleibt leer, bis eine Freigabe erfolgt.
|
||||
|
||||
---
|
||||
|
||||
<!-- Weitere Entscheidungen werden unten angefügt und fortlaufend nummeriert. -->
|
||||
Reference in New Issue
Block a user