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>
141 lines
8.1 KiB
Markdown
141 lines
8.1 KiB
Markdown
# 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, 1–2 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 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`) 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:** 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
|
||
|
||
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).
|