Ein Schritt nimmt jetzt Bilder (JPEG, PNG, WebP, HEIC) und PDF auf, am
Handy direkt aus der Kamera. Die Dateien liegen im Dateisystem unter
ANHAENGE_PFAD, nach Kunde und Lauf gegliedert; in der Datenbank stehen
nur Name, Typ, Groesse und Pruefsumme. Der Pfad entsteht aus der
Kennung, nie aus dem Dateinamen vom Browser.
Jeder Abruf prueft Recht und Mandantengrenze — auch der des Bildes
selbst: der Route Handler ruft rechtErforderlich() selbst, weil die
Huelle unter (app) Route Handler nicht abdeckt. Hochgeladen wird ueber
eine Server Action statt ueber einen zweiten Endpunkt; der
Archiv-Schreibschutz haengt an derselben einen Stelle wie alles andere
am Lauf. Kein SVG: ein SVG ist ein Dokument, das Skripte ausfuehrt.
In der Datenbank halten zwei CHECK-Bedingungen und zwei
zusammengesetzte Fremdschluessel fest, was auch gilt, wenn jemand an
der Service-Schicht vorbei schreibt — ein Anhang kann strukturell nicht
an einem Schritt eines anderen Laufs oder bei einem fremden Kunden
haengen.
docs/betrieb/sicherung.md ist neu geschrieben: dort stand "Kein
Upload-Verzeichnis, keine erzeugten Dateien", und eine Sicherung nach
der alten Anleitung haette ab hier still Daten verloren. Sicherung und
Ruecksicherung sind einmal wirklich gefahren, mit Pruefsummenvergleich.
Gefunden in der Klickprobe am gebauten Stand und nur dort: zwei Felder
"datei" in einem Formular, und FormData.get nahm das leere. Wer "Datei"
waehlte, bekam "Keine Datei gewaehlt", waehrend "Foto" ging. Die Regel
liegt jetzt als reine Funktion in src/lib, und tests/e2e/anhaenge.spec.ts
laedt bewusst ueber den zweiten Knopf hoch.
Closes#52
Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com>
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
Nummer 38.
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