Bericht: Teilverbrauch & Fly-Animationen (07.06.2026 nachts, Welle 6)
Executive Summary
Die zwei Top-Punkte aus dem Design-Doc Mitteilungen & Vorrat sind umgesetzt und live (ADR-48): 🪸 Teilverbrauch sichtbar (#24) und ✨ Verbrauchs-Animationen à la YNAB (#25). Beides kam ohne Schema-Umbau und ohne IPA-Rebuild aus — reine Frontend-Deploys plus zwei kleine Backend-Anpassungen. Beifang: der „Verbrauchen"-Button im Vorrats-Sheet war seit jeher serverseitig kaputt (Argument-Shift → stiller 500); das Log bewies es mit null verbraucht-Einträgen. Gefixt und per API-Test verifiziert.
In einfachen Worten
Bisher tat der Vorrat so, als gäbe es nur ganze Packungen — „1×" konnte alles zwischen krümelig-leer und originalverschlossen heißen. Jetzt zeigt jeder Packungs-Artikel einen Füllbalken: isst man die halbe Packung Hack, steht da „angebrochen, ~200 g von 400 g", und der Balken steht auf halb. Wird's knapp, färbt er sich bernstein. Das Minus im Stepper fragt jetzt nach (¼ · ½ · Rest · ganz · freie Gramm), statt heimlich eine ganze Packung verschwinden zu lassen.
Und: Werte fliegen jetzt sichtbar dorthin, wo sie wirken — wie bei YNAB das Geld. Essen eintragen lässt einen „+358 kcal"-Chip in den Tagesring segeln, der Ring pulst und die Zahl tickt runter statt zu springen. Bewusst dosiert: genau vier Stellen, eine halbe Sekunde, und wer in iOS „Bewegung reduzieren" anhat, bekommt gar keine Flüge.
Geliefert
🪸 Teilverbrauch sichtbar (#24)
- Füllbalken je Packungs-Artikel (Stück-Einheit + gepflegtes Packungsgewicht). Modell: eine offene Packung pro Artikel — der Nachkommaanteil von
inventory.qtyist ihr Füllstand. Klartext daneben: „2 × à 400 g" · „~200 g von 400 g" · „~200 g offen + 1 voll". - „angebrochen"-Badge (bernstein) sobald eine Packung offen ist; Balken wird bernstein, wenn insgesamt weniger als ¼ Packung übrig ist. Die Tilde ist ehrlich — es sind Schätzwerte aus den Log-Abzügen.
- Stepper „−" fragt nach: ¼ Pck · ½ Pck · Rest (~X g, nur bei angebrochener Packung) · ganz · freie Gramm. Abzüge landen als
entnommenim Journal (Journal-Gründe jetzt mit Klartext-Labels). kg-Artikel bleiben unverändert (−0,1 kg, kein Balken). - Kein Schema-Umbau —
inventory.qty(float) undfoods.packaging_weight_gexistierten; es fehlte nur Darstellung + Abzugslogik. Genau wie im Design-Doc geschätzt.
✨ Fly-Animationen (#25)
- Neuer Helfer
lib/fly.js: Ziele registrieren sich per Svelte-Actionuse:flyTarget={'name'};flyValue(quelle, ziel, label, {color})fliegt einen Chip per WAAPI (450 ms, Haus-Kurvecubic-bezier(.22,1,.36,1), leichter Bogen) und pulst das Ziel beim Einschlag. Fehlt das Ziel oder ist „Bewegung reduzieren" an → No-Op, der Toast bleibt immer die Quittung. - Genau vier Flüsse (Dosierung ist Teil des Designs):
1. Essen loggen →
+kcal-Chip vom Eintragen-Button in den Tagesring; Ring pulst, „übrig" tickt animiert (svelte/motiontweened) 2. Vorrats-Abzug (Verbrauchen-Sheet + Schnellabzug) → roter−g-Chip zur Artikel-Zeile, Füllbalken sinkt sanft mit 3. Einkaufsliste abhaken → ✓-Chip zum „offen"-Zähler („Einkauf kommt an") 4. Aktivität buchen → grüner+kcal-Chip zum Ring, Budget wächst fühlbar - Ring-Zählrichtung wie im Design-Doc vorgeschlagen umgesetzt: Chip zeigt das + (was passiert ist), die Ring-Zahl bleibt „übrig" und tickt runter — konsistent mit dem Budget-Mental-Modell. Falls sich das am Gerät falsch anfühlt: melden, war der offene Diskussionspunkt (§5).
- Toast beim 🪸-Abzug zeigt jetzt die echte Menge („Eingetragen ✓ · 🪸 −200 g") statt pauschal „Vorrat angepasst".
🐛 Beifang: consume-Endpoint war tot
POST /api/inventory/consume rief add_inventory() mit verschobenen Argumenten auf — "verbraucht" rutschte in den unit-Parameter, reason wurde None → NOT-NULL-Verletzung → 500. Exakt dieselbe Falle, die beim Stepper schon einmal gefixt worden war. Das Vorrats-Journal bewies es: 0 × verbraucht seit Bestehen. Gefixt (Unit kommt jetzt aus der Inventory-Zeile), per API-Test verifiziert, Testbestände zurückgedreht.
Abweichungen vom Design-Doc
- „Bon → Vorrat füllt Balken grün auf": Der Gegen-Fluss ist da, wo er sichtbar ist — die Balken animieren jede Bestandsänderung weich (width-Transition). Ein eigener Flug auf der Einkäufe-Seite hätte kein sichtbares Ziel (kein Balken im Viewport) und hätte die Vier-Flüsse-Dosierung aufgeweicht. Stattdessen fliegt beim Listen-Abhaken das ✓ zum „offen"-Zähler.
- Mockup zeigte die Restmenge groß im Stepper; umgesetzt ist sie als Klartext neben dem Balken — der Stepper behält die ×-Zählung (weniger Layout-Risiko, gleiche Information).
Verifikation
- Build + Deploy live;
GET /api/inventory200 hinter Auth. - API-Tests:
adjustmitreason=entnommen✓ ·consume(vorher 500) ✓ · Journal-Einträge korrekt · Testdaten zurückgedreht. - Playwright-Screenshots (mobil, hell + dunkel): Füllbalken, Badge, Schnellabzug-Sheet, Heute-Ring — Optik deckt sich mit den Mockups.
- Gerätetest steht aus → Testplan Welle 6 (hinter Login) (18 Punkte).
Nächste Kandidaten (unverändert aus der Prio-Liste)
- Notification-Center (#21) — höchster Alltagswert pro Aufwand (Design steht)
- „Was koch ich draus?" (#23) — baut auf dem Teilverbrauch auf (Korb zeigt angebrochene Mengen)
- Ad-hoc-Umstieg mit dem neuen Dev-Account (macht den 14.06.-SideStore-Check obsolet)
- Home-Screen-Quick-Actions (¼ Tag + IPA) · Live Activities (jetzt entsperrt, braucht WidgetKit-Extension)
Bezug: Design-Doc #24/#25 · ADR-48 in app/ARCHITEKTUR.md · Testplan: Welle 6