Vier parallele Review-Passes (Dead-Code, Redundanzen, Struktur, Docs-vs-Code) plus konsolidierter Hauptreport. Nur Dokumentation — keine Code-Änderungen. Tests 158/158 grün beim Review-Start. Haupt-Findings: - ARCHITECTURE.md:55 nennt falsche Tabellennamen (recipe_ingredient/recipe_step statt ingredient/step) - parseId in 9 API-Handlern dupliziert - Page-Komponenten teils >750 Zeilen - yauzl installiert aber ungenutzt (für Phase 5b reserviert) Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
8.1 KiB
Deep Code Review — Kochwas
Datum: 2026-04-18
Stand: commit 5283ab9 auf main
Testsuite beim Start: 158/158 grün
Scope: src/ (~97 Dateien), Migrations, Tests, Docker-Setup, alle Docs unter docs/
TL;DR
Der Code ist gesund. Keine toten Pfade, keine broken Features, keine strukturellen Fehlentscheidungen. Die vier auffälligsten Themen sind alle Natural-Growth-Pressure aus der v1.x-Phase, keine Fehler:
- Ein echter Doku-Bug:
docs/ARCHITECTURE.md:55sagtrecipe_ingredient+recipe_step— die Tabellen heißen in Wirklichkeitingredient/step(siehe001_init.sql). 5-Minuten-Fix. - API-Handler duplizieren
parseIdneunmal. Kandidat #1 für einensrc/lib/server/api-helpers.ts. - Page-Komponenten sind groß geworden (
+page.svelte808 Zeilen,recipes/[id]/+page.svelte757 Zeilen). Solange du allein dran arbeitest: akzeptabel. Sobald jemand mitprogrammiert: refactor. yauzl/@types/yauzlsind installiert, aber nicht importiert. Reserviert für den noch fehlenden ZIP-Backup-Import. Entweder im Session-Handoff verankert lassen oder als Phase ziehen.
Keine Sicherheits- oder Performance-Probleme im Code-Review aufgetaucht. Keine Reviewer-Korrekturen an der Architektur-Grundlinie (Server/Client-Trennung, Repository-Pattern, Runes-Stores).
Quick-Wins (≤ 30 min pro Stück)
| # | Titel | Aufwand | Wert |
|---|---|---|---|
| 1 | ARCHITECTURE.md:55 auf ingredient + step korrigieren |
2 min | hoch (sonst debuggt jemand Geisterschema) |
| 2 | OPERATIONS.md:135 IMAGES_PATH → IMAGE_DIR |
2 min | niedrig, aber trivial |
| 3 | parseId zentralisieren (src/lib/server/api-helpers.ts) |
20 min | hoch — 9 Call-Sites |
| 4 | Unit-Test für parseId-Helper |
10 min | hoch — fängt zukünftige Regressionen |
| 5 | requireProfile()-Helper in recipes/[id]/+page.svelte (Zeilen 124/143/166/188 räumen 4×7 Zeilen weg) |
15 min | mittel |
| 6 | Timeout-Magic-Numbers nach src/lib/constants.ts (1500 ms, 30-min SW-Poll) |
10 min | mittel |
| 7 | Deutsche Fehler-Texte in api/recipes/[id]/image/+server.ts englisch ziehen (Konsistenz) |
5 min | kosmetisch |
| 8 | Im Session-Handoff /api/recipes/[id]/image (POST/DELETE) nachtragen |
5 min | niedrig |
Summe: unter 90 Minuten — und du hast den Großteil der Haut-Irritationen unten.
Größere Refactor-Kandidaten
A. API-Endpoints entkoppeln (HIGH, 1–2 Std)
Extrahiere src/lib/server/api-helpers.ts mit:
parsePositiveIntParam(raw: string, field: string): number— wirft via SvelteKiterror(400, …)validateBody<T>(body: unknown, schema: ZodSchema<T>): T— ersetzt diesafeParse()-Loops in 8+ Handlern- gemeinsame
ErrorResponse-Shape (aktuell mal{message}, mal{message, issues})
Nach dem Helper-Refactor sollten die Handler nur noch echtes Business-Logik enthalten und je 30–50 Zeilen kürzer werden.
B. Search-State aus +page.svelte ziehen (HIGH, halber Tag)
+page.svelte trägt 20+ $state-Variablen (query, hits, webHits, searching, webError …) und duplizierte Search-UI in +layout.svelte. Vorschlag: src/lib/client/search.svelte.ts mit search(), loadMore(), clear(). Danach ist das Page-File halbiert und der Layout-Nav-Search nutzt denselben Store.
C. RecipeEditor / RecipeView in Sub-Components zerlegen (MEDIUM, halber Tag)
Kandidaten: IngredientRow.svelte, StepList.svelte, TimeDisplay.svelte, ImageUploadBox.svelte. Vorteile: isoliert testbar, wiederverwendbar in Preview-Seite. Aber: keine Eile, solange niemand sonst drin arbeitet.
D. Ingredient-Parser-Edge-Cases (HIGH, 2–3 Std)
Der Parser (src/lib/server/parsers/ingredient.ts) und seine Tests decken ASCII-Ganzzahlen + Dezimal + Brüche ab. Fehlt:
- Unicode-Brüche (½, ⅓, ¼)
- führende Nullen, wissenschaftliche Notation
- Locale-Kommadezimal (deutsche Rezepte!)
- 0-Portionen, negative Mengen
Parametrisierte Tests anlegen, dann Parser ggf. mit Zod-Refinement absichern.
Einzelbefunde im Detail
Dead Code
- Unused Deps:
yauzl,@types/yauzl(absichtlich für Phase 5b; Entscheidung treffen: behalten oder entfernen bis Phase kommt). RequestShape(src/lib/sw/cache-strategy.ts:3) undManifestDiff(src/lib/sw/diff-manifest.ts:4) sind exportiert, aber nur intern benutzt —exportweg oder im Test importieren.- Alle 97 Source-Files erreichbar, keine orphan-Assets, keine TODO/FIXME/HACK-Marker, keine großen auskommentierten Blöcke.
Redundanzen
parseId/parsePositiveInt— 9 Sites:api/recipes/[id]/,…/favorite,…/rating,…/cooked,…/comments,…/image,api/profiles/[id]/,api/domains/[id]/,api/wishlist/[recipe_id]/- Fetch-try/catch-alert-Pattern in 5 Svelte-Komponenten:
recipes/[id]/+page.svelte(2×),admin/domains/+page.svelte(2×),admin/profiles/+page.svelte - Zod-
safeParse+ gleicher Error-Throw in 12+ Endpoints parseQty+ Zutat-Reassembly inRecipeEditordupliziert Logik ausparseIngredient— könnte übersrc/lib/shared/geteilt werden- Profile-Guard (
if (!profile.active) alert(…)) 4× identisch inrecipes/[id]/+page.svelte
Struktur
- Große Dateien:
+page.svelte(808),recipes/[id]/+page.svelte(757),+layout.svelte(678),RecipeEditor(630),recipes/+page.svelte(539). Keine davon ist kaputt; alle sind Wachstum unter Last. - API-Error-Shape: mehrheitlich
{message},profiles/+server.tsgibt zusätzlich{issues}aus (Zod-Details). Festschreiben. - Store-Init-Races:
profile.svelte.tsundsearch-filter.svelte.tsladen bei erstem Zugriff. Komponenten sehen ggf. Leer-State vor Fetch. Optionalloading-Flag. - Konsolen-Logs: 6 Stück in Prod-Build (
service-worker.ts2×,searxng.ts3×,sw-register.ts1×). Vermutlich Absicht; als Dok-Kommentar festhalten oder inif (DEV)-Guards packen. - Svelte-5-Runes-Stores sind konsistent, keine God-Stores.
- TypeScript:
strictan, 0×any, 0× Server-Import-in-Client — bestätigt die CLAUDE.md-Regel.
Docs-vs-Code-Mismatches
| Fundstelle | Fix |
|---|---|
ARCHITECTURE.md:55 — recipe_ingredient + recipe_step |
ingredient + step |
OPERATIONS.md:135 — IMAGES_PATH |
IMAGE_DIR |
session-handoff-2026-04-17.md:46 — fehlt /api/recipes/[id]/image (POST/DELETE) |
ergänzen |
Alle Gotchas in CLAUDE.md |
✓ verifiziert, stimmen |
| Alle Claims im offline-PWA-Spec | ✓ verifiziert, alle in Code vorhanden |
Was bleibt wie es ist
- Migrationen: 001–011 sind historisch sauber. 008 + 010 löschen beide den Thumbnail-Cache — Feature-Iteration, kein Bug. Keine bestehende Migration anfassen (das ist ohnehin die dokumentierte Regel).
- Service-Worker: Zombie-Cleanup-Logik (
pwa.svelte.ts) ist Kunst, aber funktioniert und ist kommentiert. Unit-Tests decken beide Zweige (Zombie vs alter SW) ab. - Repository-Pattern: Cleane Schichtung. Nicht refactoren.
- Test-Suite: 23 Dateien, 158 Tests, volle Integration inkl. DB/HTTP/Import/SearXNG. Leichte Lücken bei Parser-Edge-Cases (siehe oben).
Ampel
| Dimension | Status |
|---|---|
| Architektur & Schichten | 🟢 gesund |
| Dead Code | 🟢 minimal |
| Redundanzen | 🟡 adressierbar, nicht dringend |
| Datei-/Komponenten-Größen | 🟡 zwei Pages ≥ 750L |
| Tests | 🟢 stark, Edge-Cases ausbaufähig |
| Doku | 🟡 1 inhaltlicher Fehler + 1 ENV-Tippfehler, sonst stabil |
| Sicherheit/Perf | 🟢 keine Funde im statischen Review |
Vorgeschlagene Reihenfolge
- Heute (10 min): Quick-Wins 1 + 2 (ARCHITECTURE-Tabellen, OPERATIONS-ENV).
- Nächste Session (2 h):
api-helpers.ts+parseId-Consolidation + Tests (Refactor A). - Bei Zeit: Search-State-Store (Refactor B) — bringt beim nächsten Feature sofort Dividende.
- Phase-5b:
yauzleinsetzen ODER Deps entfernen.
Teilreports
Die vollständigen Agent-Befunde liegen daneben:
docs/superpowers/review/dead-code.mddocs/superpowers/review/redundancy.mddocs/superpowers/review/structure.mddocs/superpowers/review/docs-vs-code.md
Review-Metadaten: 4 parallele Explore-Agenten, jeweils read-only, Summen manuell gegen Code verifiziert (Line-Counts, Tabellen-Namen, ENV-Namen, parseId-Sites).