adapter-node limitiert Request-Bodies per Default auf 512 KB.
Unsere Rezept-Fotos sind bis 8 MB gross -- der Upload scheitert
sonst vor dem Endpoint-Check mit "Multipart body erwartet", weil
SvelteKit den Body frueher abweist.
Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
Der vorige Versuch mit ssr.external in vite.config.ts war ein No-op:
adapter-node macht einen eigenen Rollup-Bundle-Schritt nach Vite und
ignoriert ssr.external komplett. Ergebnis: sharp's dynamic-require
fuer die native .node-Binary landet kaputt im Server-Bundle (332KB
Bundle-Chunk, 297 sharp-Referenzen).
Dynamic import mit /* @vite-ignore */ verhindert, dass Rollup sharp
aufloest — die Require geht stattdessen zur Laufzeit regulaer an
Node und findet @img/sharp-linuxmusl-arm64 in node_modules.
Ergebnis lokal: Server-Chunk von 332KB auf 14KB geschrumpft, nur noch
2 Referenzen auf den Paketnamen (der Import-String selbst).
Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
Der Server-Bundle-Schritt (Rollup via adapter-node) kann sharp's
dynamic-require fuer die native Plattform-.node-Binary nicht aufloesen
und bundelt kaputten Code ins Image. ssr.external sorgt dafuer, dass
sharp zur Laufzeit regulaer aus node_modules geladen wird, wo der
Docker-Build die @img/sharp-linuxmusl-arm64-Binary korrekt abgelegt hat.
Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
Finaler Anlauf gegen den arm64-Build-Fehler. Bisher scheiterte
npm daran, @img/sharp-linuxmusl-arm64 unter Docker-Buildx-QEMU zu
installieren, trotz --include=optional. Mehrschichtiger Fix:
1. --cpu=arm64 --os=linux --libc=musl auf npm install: umgeht QEMU-
bezogene Detection-Bugs (sharp's offiziell empfohlener Fix).
2. Expliziter Zusatz-Install von @img/sharp-linuxmusl-arm64 und
@img/sharp-libvips-linuxmusl-arm64: zwingt die Prebuilts auf Disk,
unabhaengig von der Lockfile-Resolution.
3. --ignore-scripts beim Install + npm rebuild danach: loest den Race,
wo sharp's postinstall laeuft bevor der Prebuilt-Tarball fertig ist.
4. node-addon-api + node-gyp als Runtime-Deps: from-source-Build-
Fallback falls alle Prebuilt-Pfade scheitern.
Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
Drei Schichten Absicherung gegen den arm64-Build-Fehler:
- --ignore-scripts beim npm install verhindert, dass sharp's postinstall
check.js laeuft, bevor das @img/sharp-linuxmusl-arm64-Paket entpackt
ist (Race in parallelem Install).
- npm rebuild danach: alle Deps sind jetzt auf Disk, Postinstalls laufen
sauber in Dependency-Reihenfolge.
- node-addon-api als Runtime-Dep: falls die Prebuilt-Binary im npm-Tree
nicht landet, kann sharp from-source bauen (vips-dev + python3 + make
+ g++ sind im Dockerfile bereits installiert).
Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
Der vorige Fix (ignore-scripts + rebuild, plus Fresh-ci im Builder) hat
den sharp-Prebuilt trotzdem nicht installiert. Ursache: der Windows-
generierte Lockfile markiert @img/sharp-linuxmusl-arm64 als "dev": true,
sodass npm ci die Prebuilt-Binary konsistent auslaesst — egal ob mit
--include=optional. npm install dagegen resolvt Optional-Deps frisch fuer
die Build-Plattform (linux-arm64-musl im Docker) und findet die Prebuilts.
Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
Zwei Fixes gegen den arm64-Build-Fehler:
1. npm ci mit --ignore-scripts + npm rebuild danach — vermeidet
eine Race, bei der sharp's postinstall check.js laeuft bevor die
Plattform-Prebuilt-Binary vollstaendig entpackt ist.
2. Statt npm prune --omit=dev ein Fresh-Install via npm ci
--omit=dev. Grund: Der Lockfile wird auf Windows generiert und
markiert die linux-musl-arm64-Prebuilts als "dev": true, obwohl
sie fuer's Runtime gebraucht werden. Prune wuerde sie kappen.
Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
15 bite-sized tasks mit TDD-Struktur, von deps+env ueber
Gemini-Client, API-Endpoints bis UI und Release.
Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
Random-Auswahl server-seitig nach AI-Call; description steht
nicht im Gemini-Schema, keine Halluzinationsflaeche.
Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
Design-Spec fuer Gemini-basierten Foto->Rezept-Import:
Kamera-Icon im Header, Extraktion auf Server, Editor-Prefill
ohne DB-Record, Foto wird nicht persistiert.
Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
npm run format hat zuletzt 18k Zeilen HTML-Fixture und alle
Markdown-Plaene angefasst. Ignore-Liste deckt jetzt ab:
- tests/fixtures (byte-exakte HTML-Captures fuer Parser-Tests)
- *.md (hand-aligned Tabellen, historische Plan-Artefakte)
- searxng/settings.yml (Template mit VAR-Platzhaltern)
- data/, build/, .svelte-kit, node_modules, Lockfile
Damit bleibt npm run format auf Code beschraenkt.
Liest KOCHWAS_TAG via +layout.server.ts aus $env/dynamic/private
und zeigt den Tag als kleine graue Zeile unter dem Brand-Text auf
der Startseite. Fallback "dev" wenn nicht gesetzt. Auf engen
Screens mit ausgeblendetem Brand verschwindet auch die Version.
docker-compose.prod.yml reicht die Host-Env-Variable jetzt in den
Container durch (vorher nur fuers Image-Tag-Binding interpoliert).
SWR lieferte bei jedem Cache-Hit sofort die alte Antwort und
aktualisierte das Cache nur fuer den naechsten Request. Folge:
UI zeigte stale Daten, frische Daten erst nach Refresh.
Neu: network-first mit 3 s Timeout-Fallback. Netz gewinnt bei
frischer Antwort; Timeout oder Netzwerk-Fehler fallen auf Cache
zurueck. Pre-Cache-Logik (runSync) bleibt unveraendert, Shell
und Bilder bleiben cache-first.
- IngredientRow: Sektion-entfernen-Button nutzt Trash2 (konsistent
mit dem Zutat-Entfernen-Button daneben)
- RecipeView: section-heading von 1rem/600 auf 1.2rem/700, mehr
vertikaler Abstand fuer deutlichere optische Trennung
- E2E-Spec: type-inference-Trick durch APIRequestContext-Import
ersetzt (svelte-check stolperte bei typeof test mit TestDetails-
Overload)
- Plan-Datei der Feature-Session mitcommitet
Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
- Migration 012: ingredient.section_heading TEXT NULL
- Editor: Inline-Abschnitt-hinzufuegen-Button (fade-in on hover) vor
jeder Zeile; Heading-Input + X-Entfernen-Button wenn gesetzt
- View: <li class="section-heading"> vor erster Zutat jeder Sektion
- Scaler preserviert section_heading via Spread
- E2E-Suite: 4 neue Tests mit CRUD gegen kochwas-dev (46/46 gruen)
Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
INSERT/SELECT in insertRecipe, replaceIngredients und getRecipeById
um section_heading ergänzt. IngredientSchema im PATCH-Endpoint sowie
Ingredient-Fixtures in search-local-, scaler- und repository-Tests
auf das neue Pflichtfeld aktualisiert.
Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
Fuegt das nullable Feld section_heading zur ingredient-Tabelle hinzu
(Migration 012), erweitert den Ingredient-Typ und aktualisiert alle drei
Return-Stellen in parseIngredient. Downstream-Sites (repository, Editor,
Tests) bleiben rot – werden in Task 2+ behoben.
Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
Die Remote-Suite hatte `serviceWorkers: allow` gesetzt, jeder Test
registriert einen frischen SW im neuen Context. Nach 20-30 Specs
akkumuliert das im Single-Worker-Run genug Browser-State, dass
Chromium mitten in der Suite crasht — alle folgenden Tests fallen
dann mit "browser.newContext closed" als Cascade.
'block' entfernt den SW komplett. Diese Suite testet nur Live-API-
Verhalten gegen den Server, keine PWA-Features (dafuer ist
offline.spec.ts lokal zustaendig). Full-Run jetzt stabil 42/42,
Laufzeit zusaetzlich ~3s schneller.
Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
timeSummary-Formatierung in eine wiederverwendbare Component
gezogen. RecipeView liefert nur noch die drei Werte — zukuenftige
Call-Sites (Preview, Hover-Cards) koennen dieselbe Logik reusen.
Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
Zubereitungs-Liste mit Add + Remove als Sub-Component. Parent steuert
nur noch den Wrapper und reicht steps + die zwei Callbacks rein.
Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
IngredientRow rendert eine einzelne editierbare Zutat-Zeile. DraftIng
und DraftStep sind jetzt in recipe-editor-types.ts, damit Parent und
Sub-Components auf dieselbe Form referenzieren.
Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
Isoliert den Bild-Upload-Flow (File-Input, Preview, Entfernen-Dialog)
aus dem RecipeEditor. Parent haelt nur noch den <section>-Wrapper und
reicht recipe.id + image_path rein, kriegt Aenderungen per onchange
callback zurueck.
Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
SearchStore extrahiert aus +page.svelte (808→645) und +layout.svelte
(681→569). 12 neue Unit-Tests (196 total), 40/42 E2E grün (1 Flake,
1 Skip). Keine Regression in UAT auf kochwas-dev.
Enter waehrend Debounce-Fenster feuerte bislang eine zweite Fetch
fuer dieselbe Query. Race-Guard greift nicht, weil q identisch ist.
runSearch clearTimeout am Anfang behebt's, neuer Unit-Test sichert es.
Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
Entfernt die duplizierten $state-Felder, runSearch, loadMore und
beide Debounce-Effekte. URL-Sync, Snapshot und Filter-Re-Search
bleiben hier — delegieren aber an den Store. All-Recipes-Infinite-
Scroll unberuehrt (separate UI-Concern).
Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>