- ARCHITECTURE.md: ingredient/step (waren faelschlich recipe_*) - OPERATIONS.md: IMAGE_DIR (statt IMAGES_PATH) - session-handoff: /api/recipes/[id]/image POST/DELETE ergaenzt Findings aus REVIEW-2026-04-18.md / docs-vs-code.md
154 lines
6.5 KiB
Markdown
154 lines
6.5 KiB
Markdown
# Review-Fixes 2026-04-18 — Implementation Plan
|
||
|
||
> **Quelle:** `docs/superpowers/review/REVIEW-2026-04-18.md` + Sub-Reports.
|
||
> **Branch:** `review-fixes-2026-04-18`
|
||
> **Goal:** Alle HIGH/MEDIUM Findings aus dem Code-Review adressieren, bewusst verschobene Items dokumentieren.
|
||
> **Architecture:** Inkrementelle Refactors, jeder atomar committed + gepusht, Tests nach jedem Wave grün.
|
||
> **Tech-Stack:** SvelteKit, TypeScript-strict, Zod, Vitest, better-sqlite3, Service-Worker.
|
||
|
||
---
|
||
|
||
## Was wird angegangen (must-do)
|
||
|
||
| # | Wave | Zeit | Begründung |
|
||
|---|------|------|------------|
|
||
| 1 | Doku-Fixes (ARCHITECTURE/OPERATIONS/handoff) | 5 min | Hoher Wert, trivialer Aufwand |
|
||
| 2 | constants.ts + Image-Endpoint EN + interne Types | 30 min | Alle "Quick-Wins" aus REVIEW |
|
||
| 3 | api-helpers.ts (parsePositiveIntParam + validateBody) | 1-2 h | Refactor A — 9+11 Call-Sites |
|
||
| 4 | requireProfile() + asyncFetch Wrapper | 1 h | Profile-Guard 4× + fetch-Pattern 5× |
|
||
| 5 | Cleanup (yauzl-Doku, baseRecipe-Fixture, Console-Logs) | 30 min | Restliche LOW-Findings |
|
||
| 6 | Ingredient-Parser Edge-Cases (Refactor D) | 2-3 h | Locale-Komma, Unicode-Brüche, Bounds |
|
||
| 7 | Verifikation (test/check/build, Docker-Smoke) | 30 min | Baseline gegen Regressionen |
|
||
| 8 | Re-Review + OPEN-ISSUES-NEXT.md | 1 h | Beweis + Ausblick |
|
||
|
||
## Was bewusst NICHT angegangen wird (Begründung in OPEN-ISSUES-NEXT.md)
|
||
|
||
- **Refactor B** (Search-State-Store, halber Tag): Touch von 808-Zeilen-Page + 678-Zeilen-Layout, bricht riskant Frontend ohne UAT. Eigene Phase planen.
|
||
- **Refactor C** (RecipeEditor zerlegen): Review sagt explizit "keine Eile, solange niemand sonst drin arbeitet".
|
||
- **SearXNG Rate-Limit Recovery**: Größeres Feature, eigene Phase.
|
||
- **SW-Zombie-Cleanup Unit-Tests**: Bereits 6 pwa-store-Tests vorhanden, Erweiterung wäre Bonus.
|
||
- **JSON-LD Parser Edge-Cases** (Locales): Weniger Käse als Ingredient-Parser-Issues, eigene Iteration.
|
||
|
||
---
|
||
|
||
## Wave 1 — Doku-Fixes
|
||
|
||
**Files:** `docs/ARCHITECTURE.md:55`, `docs/OPERATIONS.md:135`, `docs/superpowers/session-handoff-2026-04-17.md:46`
|
||
|
||
- [ ] ARCHITECTURE.md: `recipe_ingredient` + `recipe_step` → `ingredient` + `step`
|
||
- [ ] OPERATIONS.md: `IMAGES_PATH` → `IMAGE_DIR`
|
||
- [ ] session-handoff: `/api/recipes/[id]/image` (POST/DELETE) ergänzen
|
||
- [ ] Commit `docs(review): Doku-Mismatches korrigiert`
|
||
|
||
## Wave 2 — Konstanten + Cleanup
|
||
|
||
**Files:** `src/lib/constants.ts` (neu), `src/routes/+page.svelte`, `src/lib/client/pwa.svelte.ts`, `src/routes/api/recipes/[id]/image/+server.ts`, `src/lib/sw/cache-strategy.ts`, `src/lib/sw/diff-manifest.ts`
|
||
|
||
- [ ] `src/lib/constants.ts` mit `SW_VERSION_QUERY_TIMEOUT_MS = 1500`, `SW_UPDATE_POLL_INTERVAL_MS = 30 * 60_000`
|
||
- [ ] Image-Endpoint: deutsche Fehlermeldungen → englisch (Konsistenz)
|
||
- [ ] `RequestShape` / `ManifestDiff`: `export` weg wenn rein intern
|
||
- [ ] Test + check, Commit
|
||
|
||
## Wave 3 — api-helpers.ts (TDD)
|
||
|
||
**Files:** `src/lib/server/api-helpers.ts` (neu), `tests/unit/api-helpers.test.ts` (neu), `src/lib/types.ts` (ErrorResponse)
|
||
|
||
### 3a Helper bauen
|
||
- [ ] Test: `parsePositiveIntParam("42", "id")` → 42
|
||
- [ ] Test: `parsePositiveIntParam("0", "id")` wirft 400
|
||
- [ ] Test: `parsePositiveIntParam("abc", "id")` wirft 400
|
||
- [ ] Test: `parsePositiveIntParam(null, "id")` wirft 400
|
||
- [ ] Test: `validateBody(invalid, schema)` wirft 400 mit issues
|
||
- [ ] Test: `validateBody(valid, schema)` returns parsed
|
||
- [ ] Implement helpers
|
||
- [ ] Tests grün, Commit
|
||
|
||
### 3b Migration parseId → parsePositiveIntParam (9 Sites)
|
||
Files (jeder Endpoint):
|
||
- `src/routes/api/recipes/[id]/+server.ts`
|
||
- `src/routes/api/recipes/[id]/favorite/+server.ts`
|
||
- `src/routes/api/recipes/[id]/rating/+server.ts`
|
||
- `src/routes/api/recipes/[id]/cooked/+server.ts`
|
||
- `src/routes/api/recipes/[id]/comments/+server.ts`
|
||
- `src/routes/api/recipes/[id]/image/+server.ts`
|
||
- `src/routes/api/profiles/[id]/+server.ts`
|
||
- `src/routes/api/domains/[id]/+server.ts`
|
||
- `src/routes/api/wishlist/[recipe_id]/+server.ts`
|
||
|
||
- [ ] Pro Endpoint: lokales parseId entfernen, Helper importieren
|
||
- [ ] Tests grün
|
||
- [ ] Commit
|
||
|
||
### 3c Migration safeParse → validateBody
|
||
Files: alle `+server.ts` mit `safeParse`. ErrorResponse-Shape standardisieren.
|
||
|
||
- [ ] Pro Endpoint umstellen
|
||
- [ ] Tests grün
|
||
- [ ] Commit
|
||
|
||
## Wave 4 — Client-Helpers
|
||
|
||
### 4a requireProfile()
|
||
- [ ] Helper in `src/lib/client/profile.svelte.ts` ergänzen
|
||
- [ ] 4 Sites in `src/routes/recipes/[id]/+page.svelte` ersetzen
|
||
- [ ] Test + Commit
|
||
|
||
### 4b asyncFetch Wrapper
|
||
- [ ] `src/lib/client/api-fetch-wrapper.ts` mit `asyncFetch(url, init, actionTitle)`
|
||
- [ ] 5 Sites umstellen: `recipes/[id]/+page.svelte` (2×), `admin/domains/+page.svelte` (2×), `admin/profiles/+page.svelte`
|
||
- [ ] Test + Commit
|
||
|
||
## Wave 5 — Cleanup
|
||
|
||
- [ ] yauzl: Inline-Kommentar in package.json: "Reserved for Phase 5b ZIP-Backup-Import"
|
||
- [ ] baseRecipe Fixture nach `tests/fixtures/recipe.ts` (wenn dupliziert)
|
||
- [ ] Console-Logs: per `if (import.meta.env.DEV)` wrappen oder absichtlich-Kommentar
|
||
- [ ] Commit
|
||
|
||
## Wave 6 — Ingredient-Parser Edge-Cases
|
||
|
||
**Files:** `src/lib/server/parsers/ingredient.ts`, `tests/unit/ingredient.test.ts`
|
||
|
||
### Tests zuerst (red)
|
||
- [ ] Locale-Komma: `"1,5 kg Mehl"` → qty 1.5
|
||
- [ ] Unicode-½: `"½ TL Salz"` → qty 0.5
|
||
- [ ] Unicode-⅓: `"⅓ Tasse Wasser"` → qty 1/3
|
||
- [ ] Unicode-¼: `"¼ kg Zucker"` → qty 0.25
|
||
- [ ] Negativ: `"-1 EL Öl"` → wirft / qty=null
|
||
- [ ] Null: `"0 g Mehl"` → wirft / qty=null
|
||
- [ ] Führende Null: `"0.5 kg"` → 0.5
|
||
- [ ] Wissenschaftliche Notation: `"1e3 g"` → wirft / qty=null
|
||
|
||
### Parser fixen
|
||
- [ ] Unicode-Brüche-Map
|
||
- [ ] Locale-Komma-Handling (sicher: "1,5" wenn nur 1 Komma + Ziffern drumrum)
|
||
- [ ] Bounds: 0 < qty <= 10000 (Zod refinement oder Pre-Check)
|
||
- [ ] Tests grün, Commit
|
||
|
||
## Wave 7 — Verifikation
|
||
|
||
- [ ] `npm test` — 158+ Tests grün
|
||
- [ ] `npm run check` — 0 Errors
|
||
- [ ] `npm run build` — erfolgreich
|
||
- [ ] Optional: Docker-Smoke `docker compose -f docker-compose.prod.yml up --build`
|
||
- [ ] Push aller Commits
|
||
|
||
## Wave 8 — Re-Review + OPEN-ISSUES-NEXT.md
|
||
|
||
- [ ] Parallele Explore-Agenten: dead-code, redundancy, structure, docs-vs-code
|
||
- [ ] Befunde in `docs/superpowers/review/OPEN-ISSUES-NEXT.md`
|
||
- [ ] Bewusst verschobene Items mit Begründung
|
||
- [ ] Neue Findings (falls vorhanden)
|
||
- [ ] Commit + Push
|
||
|
||
---
|
||
|
||
## Erfolgs-Kriterien
|
||
|
||
1. Tests grün (158+)
|
||
2. svelte-check: 0 Errors, 0 Warnings (oder ≤ Baseline)
|
||
3. Build erfolgreich
|
||
4. Alle 8 Quick-Wins + Refactor A + Refactor D umgesetzt
|
||
5. OPEN-ISSUES-NEXT.md vorhanden mit klarer Trennung "verschoben (warum)" vs "neu entdeckt"
|
||
6. Branch ready zum Mergen / PR
|