Baustein 5: Praxisaufgaben mit Anhaengen und Abnahme

- Status offen / in Arbeit / zur Abnahme / abgenommen, mit Zeitstempeln
- Notizfeld fuer den Azubi, Dateianhaenge bis 25 MB
- Speicherpfad nur aus selbst erzeugter UUID, nie aus dem Dateinamen
- Auslieferung ueber /anhaenge/<kennung> mit Rechtepruefung bei jedem Abruf,
  CSP sandbox und nosniff; SVG ausdruecklich nicht erlaubt
- Anhaenge haengen an Aufgabe UND Azubi
- Ausbilder hakt Kriterien einzeln ab, Note und Rueckmeldung, Abnahme sperrt
- Zurueckgeben zur Nacharbeit
- "Was auf dich wartet" zeigt offene Abnahmen
- Abgenommene Aufgaben zaehlen im Wochenfortschritt mit

Behoben: Next.js deckelt Serveraktionen ab Werk bei 1 MB - damit waere kein
Handyfoto durchgekommen. bodySizeLimit jetzt 30 MB, Vorabpruefung im Browser,
client_max_body_size im Proxy-Beispiel auf 30m.

Geaendert: Seiten verweigern fremde Daten mit 404 statt mit einem Fehler.
Eigene Seiten fuer "Nicht gefunden" und Stoerfaelle.

24 neue Tests, insgesamt 157.

Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com>
This commit is contained in:
Florian Wilde
2026-09-10 12:18:54 +02:00
co-authored by Claude Opus 5
parent bb592ad2bd
commit ffbca01bdc
44 changed files with 1925 additions and 26 deletions
+44
View File
@@ -164,3 +164,47 @@ kommen zuletzt, damit zuerst der Rückstand abgebaut wird.
Fach 4 heißt: Abstand über drei Tage, also mindestens dreimal in Folge gekonnt.
Das ist die Schwelle, ab der die Karte im Wochenfortschritt als erledigt zählt.
Wer sie einmal richtig hatte, hat sie noch nicht gelernt.
## E18 · Anhänge: Pfad aus UUID, Auslieferung nur über eine geprüfte Route
Drei Regeln, die zusammengehören:
1. Der **Speicherpfad** ist `<jahr>/<uuid><endung>`. Der übermittelte Dateiname
landet nur als Anzeigename in der Datenbank und wird nie zum Bilden eines
Pfades benutzt. `speicherpfad()` wirft, wenn die Kennung keine UUID ist.
2. **Ausgeliefert** wird ausschließlich über `/anhaenge/<kennung>`. Es gibt
keinen Weg, über die Adresse eine beliebige Datei anzufordern, und die
Berechtigung wird bei jedem Abruf neu geprüft – nicht nur beim Hochladen.
3. Der Antwortkopf trägt `Content-Security-Policy: sandbox` und
`X-Content-Type-Options: nosniff`. Anhänge sind Daten, kein Programm.
SVG ist trotz `image/` **nicht** erlaubt: Es ist XML und kann Skripte enthalten.
## E19 · Anhänge hängen an Aufgabe **und** Azubi
Der Bezug lautet `<aufgabeId>::<azubiId>`. Beim ersten Entwurf hing er nur an
der Aufgabe – bei zwei Azubis hätte der zweite die Fotos des ersten gesehen.
## E20 · Kriterien werden über ihre Position gespeichert
`kriterien_erfuellt` ist eine JSON-Liste der Positionen in der Aufgabendatei,
etwa `[0,2,3]`. Wird die Reihenfolge der Kriterien nachträglich geändert,
verschiebt sich die Zuordnung. Neue Kriterien gehören deshalb ans Ende –
dieselbe Regel wie bei den Merkkarten (siehe E11).
## E21 · Fehlende Berechtigung ist ein 404, kein 403
Seiten rufen `erfordereSichtAufAzubi()` auf, das mit „nicht gefunden" endet.
Ein 403 würde bestätigen, dass es die angefragten Daten gibt. Serveraktionen
brechen weiterhin mit einem Fehler ab – dort wäre eine Weiterleitung sinnlos.
Nebeneffekt: Next.js schwärzt Fehlermeldungen im Produktionsbetrieb. Eine eigene
„Kein Zugriff"-Seite ließe sich anhand des Fehlertextes gar nicht erkennen.
## E22 · Der Deckel für Serveraktionen liegt über der eigenen Grenze
`serverActions.bodySizeLimit` steht auf 30 MB, die eigene Prüfung auf 25 MB.
Der Abstand ist Absicht: Eine zu große Datei soll die **eigene**, verständliche
Meldung bekommen und nicht den Rumpfgrößenfehler des Gerüsts, der nur im
Serverprotokoll auftaucht. Zusätzlich prüft der Browser vorab, damit am
Mobilfunk nicht erst 30 MB übertragen und dann abgelehnt werden.