managarten/apps/api
Till JS 6432ef7e6b feat(comic): M4 — AI-Storyboard aus Cross-Modul-Text
User wählt einen bestehenden Text (Tagebuch-Eintrag, Notiz oder
Bibliotheks-Review), das Modell schlägt eine geordnete
Panel-Sequenz vor (prompt + optional caption + dialogue pro Panel),
der User prüft/editiert und feuert Batch-Gen mit sourceInput-
Tagging — damit wird `useStoriesByInput` später cross-referenzieren
können ("Welche Comics sind aus diesem Journal-Eintrag entstanden?").

Backend:
- POST /api/v1/comic/storyboard (Hono route) nimmt style +
  sourceText + panelCount (+ optional storyContext / sourceModule)
  und ruft llmJson() mit einem response_format=json_object-Prompt
  an mana-llm. System-Prompt instruiert das Modell auf eine exakte
  {panels: [{prompt, caption?, dialogue?}]}-Shape, Rules wie
  "keine Style-Instruktionen" (kommen aus dem Story-Prefix
  downstream) und "kein Panel-Nummerieren".
- Defense-in-depth Coerce auf der Response: Panel ohne prompt
  wird gefiltert, Strings werden gecappt (caption/dialogue 200,
  prompt 800), Zahl der Panels auf panelCount geclampt.
- Model via COMIC_STORYBOARD_MODEL env var überschreibbar;
  Default ollama/gemma3:4b wie writing (lokal + billig).
- Beide Erfolgs- und Fehler-Pfade mit logger.info /
  logger.error + userId + sourceModule für Observability.
- Route registriert in apps/api/src/index.ts als /api/v1/comic.

Client:
- api/storyboard.ts: suggestPanels({style, sourceText, panelCount,
  storyContext?, sourceModule?}) — thin fetch-Wrapper + Error-Messaging
  für 402 / 502 / no-panels-Responses.
- ReferenceInputPicker: Tabs über Journal / Notizen / Bibliothek
  (die drei inhalts-dichtesten Quellen), pro Tab Live-Query +
  Suche + Entry-Liste. Click emittiert {module, entryId, label,
  sourceText} — label ist der Display-Name für die
  "Gequellt aus…"-Chip, sourceText ist bereits decrypted (Queries
  liefern plaintext zurück). Bibliotheks-Einträge ohne Review
  sind disabled (kein Text = nichts zu rendern).
- StoryboardSuggester: 4-Schritt-Flow (pick-source →
  generating-plan → review-plan → rendering). Schritt 3 ist der
  eigentliche Editor: jede Claude-Zeile ist editierbar (Prompt,
  Caption, Dialog) mit Trash-Button; Quality + Format-Toggle
  teilen sich M3-Batch-Style. "Generieren" ruft parallel
  runPanelGenerate() via Promise.allSettled mit
  sourceInput={module, entryId} im panelMeta, alle Panels gehen
  durch den identischen M2-HTTP-Pfad.
- DetailView bekommt einen dritten Editor-Modus "ai" neben
  "single" und "batch" — eine Sparkle-Button-CTA öffnet den
  Suggester.

Kein Writing-Draft / Calendar-Event-Input in dieser Runde —
Drafts brauchen Version-Chain-Resolve, Events sind meist zu dünn
an Prosa. Follow-up wenn gewünscht (rein additiv: Tab + Hook).

Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
2026-04-24 16:06:03 +02:00
..
drizzle fix(website): publish failed with uuid type error on Better-Auth ids 2026-04-23 21:43:57 +02:00
scripts feat(wardrobe): module foundation — garments + outfits space-scoped data layer (M1) 2026-04-23 18:27:37 +02:00
src feat(comic): M4 — AI-Storyboard aus Cross-Modul-Text 2026-04-24 16:06:03 +02:00
Dockerfile fix(infra): include shared-ai + shared-rss in mana-api Dockerfile installer 2026-04-23 02:34:22 +02:00
drizzle.config.ts feat(webapp): wire isParallelSafe in Companion chat + Mission runner 2026-04-23 14:11:24 +02:00
drizzle.presi.config.ts fix(presi): wire up db:push for presi schema via @mana/api 2026-04-12 14:32:44 +02:00
package.json feat(wardrobe): module foundation — garments + outfits space-scoped data layer (M1) 2026-04-23 18:27:37 +02:00
tsconfig.json fix(api): unblock tsc by dropping rootDir and allowing .ts imports 2026-04-15 18:51:26 +02:00