docs(review): Deep-Code-Review 2026-04-18
All checks were successful
Build & Publish Docker Image / build-and-push (push) Successful in 31s

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>
This commit is contained in:
hsiegeln
2026-04-18 21:55:41 +02:00
parent 5283ab9b51
commit 10c43c4d4a
5 changed files with 519 additions and 0 deletions

View File

@@ -0,0 +1,140 @@
# 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:
1. **Ein echter Doku-Bug:** `docs/ARCHITECTURE.md:55` sagt `recipe_ingredient` + `recipe_step` — die Tabellen heißen in Wirklichkeit `ingredient` / `step` (siehe `001_init.sql`). 5-Minuten-Fix.
2. **API-Handler duplizieren `parseId`** neunmal. Kandidat #1 für einen `src/lib/server/api-helpers.ts`.
3. **Page-Komponenten sind groß** geworden (`+page.svelte` 808 Zeilen, `recipes/[id]/+page.svelte` 757 Zeilen). Solange du allein dran arbeitest: akzeptabel. Sobald jemand mitprogrammiert: refactor.
4. **`yauzl` / `@types/yauzl` sind 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, 12 Std)
Extrahiere `src/lib/server/api-helpers.ts` mit:
- `parsePositiveIntParam(raw: string, field: string): number` — wirft via SvelteKit `error(400, …)`
- `validateBody<T>(body: unknown, schema: ZodSchema<T>): T` — ersetzt die `safeParse()`-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 3050 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, 23 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`) und `ManifestDiff` (`src/lib/sw/diff-manifest.ts:4`) sind exportiert, aber nur intern benutzt — `export` weg 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 in `RecipeEditor` dupliziert Logik aus `parseIngredient` — könnte über `src/lib/shared/` geteilt werden
- Profile-Guard (`if (!profile.active) alert(…)`) 4× identisch in `recipes/[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.ts` gibt zusätzlich `{issues}` aus (Zod-Details). Festschreiben.
- Store-Init-Races: `profile.svelte.ts` und `search-filter.svelte.ts` laden bei erstem Zugriff. Komponenten sehen ggf. Leer-State vor Fetch. Optional `loading`-Flag.
- Konsolen-Logs: 6 Stück in Prod-Build (`service-worker.ts` 2×, `searxng.ts` 3×, `sw-register.ts` 1×). Vermutlich Absicht; als Dok-Kommentar festhalten oder in `if (DEV)`-Guards packen.
- Svelte-5-Runes-Stores sind konsistent, keine God-Stores.
- TypeScript: `strict` an, 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:** 001011 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
1. Heute (10 min): Quick-Wins 1 + 2 (ARCHITECTURE-Tabellen, OPERATIONS-ENV).
2. Nächste Session (2 h): `api-helpers.ts` + `parseId`-Consolidation + Tests (Refactor A).
3. Bei Zeit: Search-State-Store (Refactor B) — bringt beim nächsten Feature sofort Dividende.
4. Phase-5b: `yauzl` einsetzen ODER Deps entfernen.
---
## Teilreports
Die vollständigen Agent-Befunde liegen daneben:
- `docs/superpowers/review/dead-code.md`
- `docs/superpowers/review/redundancy.md`
- `docs/superpowers/review/structure.md`
- `docs/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).