Files
HamHam/docs/DEVELOPMENT.md
T

5.4 KiB

Architektur und Entwicklung

Stack

Next.js App Router, React, TypeScript, PostgreSQL, Drizzle, Zod, decimal.js, Motion, Lucide, Sharp und @node-rs/argon2. Konkrete kompatible Versionen sind in package-lock.json fixiert. Das UI nutzt bewusst eigenständiges CSS mit Designvariablen statt eines generischen Dashboard-Themes. Lokale DM Sans und Fraunces werden über Fontsource gebündelt.

Verantwortlichkeiten

Pfad Verantwortung
src/lib/recipe.ts Gemeinsames Datenmodell, Validierung, Referenzintegrität
src/lib/calculator.ts Reine präzise Skalierung, Einheiten, Anzeige und Einkaufsliste
src/lib/import.ts JSON/XML-Dekodierung und verlustfreier Metadatenexport
src/lib/cooking.ts Testbare Zeitstempel-Timer
src/lib/server.ts Sessions, CSRF, Größenlimits, Rate Limit, Fehlerabbildung
src/lib/repository.ts Rezeptpersistenz, Sichtbarkeit, Versionskonflikte
src/db/ Drizzle-Mappings und PostgreSQL-Pool
src/app/api/[...path]/route.ts Dünne HTTP-Operationen mit Validierung/Autorisierung
src/components/ Bibliothek, Detail, Kochmodus, Editor, Administration
migrations/ Versionierte SQL-Migrationen
scripts/ Migration, Admin-Bootstrap, Schema/Beispielgenerierung

Die Rezeptstruktur liegt als validiertes JSONB-Dokument vor, ergänzt um relationale ID, Titel, normalisierten eindeutigen Titel, Veröffentlichungsstatus und Zeitstempel. Damit werden Zutaten/Schritte atomar geändert und beim Import nicht auseinandergerissen. Sessions, Administratoren, Limits und Medien sind getrennte relationale Tabellen. Öffentliche Leseoperationen filtern serverseitig auf published=true.

API

Alle Fehler: { "error": "Verständliche Meldung" }. Statuscodes: 400 Syntax, 401 Anmeldung, 403 Origin, 404 fehlt, 409 Duplikat/Versionskonflikt, 413 Größe, 415 Dateityp, 422 Datenvalidierung, 428 fehlende Bearbeitungsversion, 429 Loginlimit, 500 unerwarteter Serverfehler. Unerwartete Fehler werden serverseitig geloggt, ohne interne Details an Clients auszugeben.

  • GET /api/recipes: veröffentlichte Rezepte; ?admin=1 nur mit gültiger Session erweitert.
  • GET /api/recipes/:id: öffentlich nur veröffentlicht, sonst autorisierter Admin.
  • POST /api/recipes, PUT /api/recipes/:id, DELETE /api/recipes/:id: Admin, Origin erforderlich. PUT benötigt den letzten updatedAt-Wert.
  • POST /api/auth/login, POST /api/auth/logout, GET /api/auth/me, POST /api/auth/password.
  • POST /api/import: {raw, format: "json"|"xml", preview: boolean}.
  • GET /api/export?format=json|xml&id=UUID: ID optional, sonst gesamte Sammlung.
  • GET/PUT /api/settings: Kategorien-/Tag-Auswahllisten und Sammlungsname.
  • GET/POST/DELETE /api/media: Rohbild-Upload mit Content-Type JPEG/PNG/WebP, Löschung per {name}. Bilder werden serverseitig dekodiert und als WebP neu kodiert (max. 40 MP, 10 MB Eingabe, 2400 px Kantenlänge). EXIF wird entfernt.
  • GET /api/health: Datenbankverbindung + Anwendung.

Alle Admin-Operationen prüfen die Session auf dem Server. Passwörter werden mit Argon2id (64 MiB, 3 Iterationen) gehasht. CSRF-Schutz nutzt den verpflichtenden exakten Origin-Vergleich plus SameSite-Strict-Cookies. Automatisierte API-Clients müssen die konfigurierte Origin explizit setzen. Es gibt keine Token in Local Storage.

Rechner und Referenzen

Faktoren bleiben als hochpräzise Dezimalstrings erhalten. Neue Zielmengen werden stets durch die unveränderte Originalmenge geteilt; Originalzutaten werden nie mutiert. Runden erfolgt nur zur Anzeige. Übliche Viertel-/Halbbrüche werden typografisch dargestellt, kleine Mengen mit bis zu sechs Nachkommastellen. Nährwerte sind pro Originalportion, Gesamtzeit wird nicht skaliert.

Editor und lokale Speicherung

Änderungen werden lokal im Browser gesichert, ohne das veröffentlichte Rezept zu verändern. „Rezept speichern“ validiert und überträgt ausdrücklich auf den Server. Der Browser warnt beim Verlassen mit noch nicht auf den Server übertragenen Änderungen. Konflikte mit einer zwischenzeitlich geänderten Fassung werden als 409 zurückgegeben. Lokale Entwürfe bleiben dann erhalten.

Zutaten und Schritte lassen sich per Drag-Handle sowie per Auf/Ab-Buttons sortieren. So ist die Funktion auch ohne Maus bedienbar. Bilder werden sofort in die lokale Medienablage hochgeladen und können dort später entfernt werden, solange kein Rezept sie verwendet.

Tests

Unit: npm test. E2E: npm run build && npm run test:e2e. Tests verwenden echte PostgreSQL-Persistenz, echte HTTP-Authentifizierung und Chromium ohne gemockte Produktfunktionen. Die E2E-Datenbank muss auf _test enden und wird zurückgesetzt. Playwright erzeugt Screenshots für Desktop (1440 px), Smartphone (390 px) und Tablet (768 px).

Bei Schemaänderungen npm run schema:generate ausführen und generierte Dokumente mitcommitten. Entwicklungsserver und Produktionsbuild teilen dieselbe Datenbankkonfiguration. Next-Telemetrie im Container ist deaktiviert; lokal bei Bedarf NEXT_TELEMETRY_DISABLED=1 setzen.