Commit Graph

14 Commits

Author SHA1 Message Date
hsiegeln
7c8edb9b92 feat(pwa): Cache-Manifest-Diff-Funktion + Tests
All checks were successful
Build & Publish Docker Image / build-and-push (push) Successful in 1m19s
Pure Funktion diffManifest(current, cached) → {toAdd, toRemove}.
Vom SW beim Update-Sync genutzt: neue Rezept-IDs nachladen,
gelöschte aus dem Cache räumen. 5 Tests decken add/remove/
beides/unchanged/empty-cache ab.

Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
2026-04-18 16:34:39 +02:00
hsiegeln
d38992661c feat(pwa): Cache-Strategy-Entscheider + Unit-Tests
All checks were successful
Build & Publish Docker Image / build-and-push (push) Successful in 1m18s
Reine TS-Funktion resolveStrategy({url, method}) → 'shell' | 'swr'
| 'images' | 'network-only'. Kernregel:
  - Schreib-Methoden + import/preview/search/web → network-only
  - /images/* → images (cache-first)
  - /_app/, manifest, Icons, favicon, robots → shell (cache-first)
  - Alles andere same-origin-GET → swr
7 Tests decken alle Buckets ab. Wird vom SW in Task 8 aufgerufen.

Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
2026-04-18 16:32:30 +02:00
hsiegeln
d08cefa5c9 feat(pwa): Sync-Status-Store mit localStorage-Persistierung
All checks were successful
Build & Publish Docker Image / build-and-push (push) Successful in 1m18s
Spiegelt SW-Messages (sync-start/progress/done/error) in einen
Svelte-State. lastSynced wird in localStorage persistiert, damit
der User nach einem Reload sieht, wann zuletzt synchronisiert
wurde. Wird vom SyncIndicator und der Admin-App-Tab konsumiert.

Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
2026-04-18 16:25:35 +02:00
hsiegeln
0c66bd677e feat(pwa): Toast-Store + Renderer
All checks were successful
Build & Publish Docker Image / build-and-push (push) Successful in 1m19s
Toast-Queue als $state-Store mit Auto-Dismiss nach 3 s und manuellem
dismiss(id). Drei Kinds: info/error/success (Farbe). Renderer als
<Toast /> im Root-Layout, fix-positioniert oben mittig. Wird
vom Offline-Check der Schreib-Aktionen genutzt und später auch für
Sync-Abschluss-Meldungen.

Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
2026-04-18 16:21:14 +02:00
hsiegeln
04641355df feat(pwa): Online-Status-Store
All checks were successful
Build & Publish Docker Image / build-and-push (push) Successful in 1m31s
Reaktiver Store basierend auf navigator.onLine und den window-
Events online/offline. Kein aktives Heuristik-Probing — für
unseren Offline-PWA-Use-Case reicht der Browser-Status. Wird von
SyncIndicator und require-online-Helper konsumiert.

Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
2026-04-18 16:17:11 +02:00
hsiegeln
3e3afc0102 fix(importer): Microdata-Steps bei HowToSection + mehrfach-Schritten
All checks were successful
Build & Publish Docker Image / build-and-push (push) Successful in 1m19s
Rezeptwelt lieferte Zubereitungs-Steps immer als einen einzigen Treffer,
oft mit vermischtem Icon-alt-Text. Zwei Ursachen, beide in der
generischen Microdata-Logik — kein rezeptwelt-spezifischer Parser nötig.

1. HowToSection wrappt HowToSteps als itemListElement, unser Parser sah
   nur das erste. Jetzt: recipeInstructions-Container mit itemtype=
   HowToSection werden abgestiegen, jedes itemListElement wird ein Step.

2. Ein einzelner HowToStep kann intern "1. …<br>2. …<br>3. …" enthalten.
   Neuer textWithLineBreaks(el) konvertiert <br>/Block-Grenzen zu \n und
   ignoriert <img>/<script>/<style>. splitStepText(raw) erkennt
   nummerierte Zeilen und erzeugt einen eigenen Step pro Nummer; Fort-
   setzungszeilen ohne Nummer hängen an den aktuellen Step an.

3 neue Tests: HowToSection-Kette, inline-nummerierter Multi-Step,
<img>-alt-Unterdrückung.

Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
2026-04-18 09:03:50 +02:00
hsiegeln
aad3ad689d feat(importer): Microdata-Fallback für Seiten ohne JSON-LD
All checks were successful
Build & Publish Docker Image / build-and-push (push) Successful in 1m17s
Bisher scheiterte der Import auf Seiten wie rezeptwelt.de mit „Diese Seite
enthält kein Rezept", obwohl unser Such-Filter die Treffer durchließ
(Microdata wird seit dem vorherigen Commit erkannt). Jetzt kann der
Importer die Daten auch tatsächlich extrahieren:

- extractRecipeFromMicrodata(html): parst [itemtype=schema.org/Recipe]-
  Scopes per linkedom, sammelt itemprop-Werte unter Beachtung der
  verschachtelten itemscope-Grenzen (HowToStep-Texts landen nicht im
  Haupt-Scope).
- Übernimmt Content-Attribute auf <meta>/<time> (z.B. prepTime="PT20M"),
  src auf <img>, textContent als Fallback — die Standard-Microdata-
  Value-Regeln.
- Behandelt HowToStep-Items UND einfache <li>/<ol>-Listen als
  recipeInstructions.
- extractRecipeFromHtml ruft JSON-LD zuerst, fällt nur bei null auf
  Microdata zurück — damit bleibt bestehendes Verhalten stabil.

Tests: Königsberger-Klopse-Fixture mit HowToSteps, einfache ol/li-
Variante und Priorität-JSON-LD-über-Microdata-Check.

Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
2026-04-18 08:52:00 +02:00
hsiegeln
2e196b4834 feat(search): Microdata-Fallback erkennt rezeptwelt & Co.
All checks were successful
Build & Publish Docker Image / build-and-push (push) Successful in 1m15s
Aus dem Log (q="Königsberger klopse"): 11 rezeptwelt-Treffer kamen durch
alle URL-Filter, wurden aber von hasRecipeJsonLd als non-recipe gedroppt.
Ursache: rezeptwelt.de nutzt Microdata (itemtype=schema.org/Recipe) statt
application/ld+json.

- hasRecipeJsonLd → hasRecipeMarkup: prüft jetzt zusätzlich per Regex
  auf itemtype=(https?://)schema.org/Recipe. Alter Export bleibt als
  Deprecated-Weiterleitung erhalten.
- Log zeigt jetzt auch die ersten 3 gedropten URLs als dropped samples,
  damit neue Problem-Domains einfach zu diagnostizieren sind.
- Migration 010 räumt alle thumbnail_cache-Einträge mit has_recipe=0 aus
  — die waren mit dem alten Check falsch-negativ und müssen neu
  klassifiziert werden.

Tests: 4 neue Cases für hasRecipeMarkup (JSON-LD, http/https Microdata,
Negativ-Fall).

Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
2026-04-18 08:32:18 +02:00
0f9aabe76b refactor: move scaler out of $lib/server so it can run in browser
RecipeView needs scaleIngredients on the client for live portion scaling.
Moved scaler.ts from $lib/server/recipes/ to $lib/recipes/.

Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
2026-04-17 15:41:20 +02:00
2f3248c9a3 feat(parser): add JSON-LD schema.org/Recipe extractor
Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
2026-04-17 15:04:05 +02:00
789af122f4 feat(scaler): add ingredient scaling with sensible rounding
Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
2026-04-17 15:02:09 +02:00
ae774e377d feat(parser): add ingredient parser
Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
2026-04-17 15:02:09 +02:00
c56201c5f3 feat(parser): add ISO8601 duration parser
Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
2026-04-17 15:02:08 +02:00
5b714919a0 test(infra): add vitest smoke test
Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
2026-04-17 15:02:08 +02:00