# Wardrobe — Module Plan ## Status (2026-04-23) Greenfield. Das Fundament (meImages + reference-based image generation) ist komplett verfügbar — siehe `docs/plans/me-images-and-reference-generation.md` Stand M1-M5. Dieses Modul konsumiert es. ## Ziel Ein Nutzer pflegt seinen **digitalen Kleiderschrank**: einzelne Kleidungsstücke und Accessoires (Hemd, Hose, Schuhe, Brille, Uhr) mit Foto + Metadaten. Er kombiniert sie zu **Outfits** und nutzt KI, um sich selbst in dem Outfit zu visualisieren — als Anprobe ohne Spiegel oder als Vorschau vor dem Kauf. Kernfragen, die dieser Plan beantwortet: 1. Wie bilden wir Kleidungsstücke + Outfits im Datenmodell ab? 2. Wie fließen sie in die KI-Generierung (me-images plus garment-photos)? 3. Welche Mindest-UI braucht es, damit das Feature tragfähig ist? 4. Wie machen wir Wardrobe-AI (Outfit-Vorschläge auf Basis von Kontext) möglich, ohne das Modul zu überladen? ## Abgrenzung - **Kein generisches Fashion-Catalog / Shopping**: Dieses Modul verwaltet, was dem Nutzer *gehört*, nicht was er kaufen könnte. Wishlist lebt weiter in `wishes`. - **Kein Ersatz für `inventory`**: `inventory` ist für physische Gegenstände mit Seriennummer/Garantie (Elektronik, Möbel). Kleidung hat eigene Primitive (Größe, Farbe, Kategorie, Tragevorschriften) — und eigene Use-Cases (Outfit-Komposition, Try-On). Ein Nutzer könnte seine 300€-Jacke in beiden führen — Wardrobe für Outfit-Zwecke, Inventory für Versicherungs-Zwecke. Wir doppeln den Datensatz bewusst nicht zusammen. - **Kein Stylist-Coaching / Body-Shaming**: Die AI schlägt Kombinationen basierend auf *des Nutzers eigenem Kleiderschrank* vor, nicht auf abstraktem Stil-Urteil. Kein "Du solltest…". - **Kein Online-Kauf**: Wishlist→Affiliate ist ein separater Track. Wardrobe ist Besitz. - **Cross-Link zu `picture`**: Try-On-Ergebnisse landen in der Picture-Galerie (`picture.images`) wie jede andere Generierung. `LocalOutfit.lastTryOnImageId` pointet dorthin. - **Cross-Link zu `me-images`**: Wardrobe liest `useImageByPrimary('face-ref')` + `useImageByPrimary('body-ref')` um den Nutzer zu visualisieren. Ohne primary face+body → Try-On nicht verfügbar. ## Entscheidungen ### 1. Ein Modul, zwei Tabellen Das Repo hat Präzedenz für ein einzelnes Modul mit mehreren Tabellen (siehe `library` mit kind-discriminator, `invoices` mit clients/settings). Wardrobe ist dasselbe Muster: - **`wardrobeGarments`** — einzelne Kleidungsstücke / Accessoires - **`wardrobeOutfits`** — Zusammenstellungen (referenzieren garmentIds) Kein separates `wardrobeTryOns`-Table: Try-On-Ergebnisse sind normale `picture.images` mit `generationMode='reference'` und einer Rück-Referenz `outfitId`. Warum kein drittes Table? Ein Try-On ist ein "snapshot of an outfit at a moment" — die einzigen neuen Daten sind `outfitId`-Rückreferenz + Pose-/Prompt-Kontext. Das passt als optionale Felder auf `LocalImage` (pattern wie `referenceImageIds`). ### 2. Garment = Foto + Kategorie, nicht Produkt-DB Ein Garment ist für uns im MVP: - ein Foto (mana-media-Upload, wie alles andere) - eine Kategorie aus geschlossener Liste (top/bottom/shoes/accessory/…) - paar freie Text-Felder (Name, Marke, Farbe, Notizen) Wir bauen **keine Produkt-Datenbank**, keine Barcode-Scanning, keinen Marken-Katalog, kein EAN-Lookup. Das sind alles interessante Features, die das Modul nicht *tragen* muss, um nützlich zu sein. Eine einfache handy-gemachte Foto + Name-Tipperei reicht für den 80%-Fall. ### 3. Try-On ist ein Picture-Modul-Ergebnis Ein Try-On-Call geht über den vorhandenen `POST /api/v1/picture/generate-with-reference`-Endpoint (M3 des me-images-Plans), mit einer erweiterten Referenz-Liste: ``` referenceMediaIds = [primaryFaceMediaId, primaryBodyMediaId, ...outfit.garmentIds.map(g => g.primaryMediaId)] prompt = "Porträt von mir in diesem Outfit, realistisch, freundliches Lächeln" ``` Problem: M3 cappt bei 4 Referenzen. Ein Outfit mit 3 Kleidungsstücken + Face + Body = 5 Refs. Wardrobe M1 muss den Cap im Endpoint anheben (→ 8). OpenAI erlaubt bis 16, 8 ist ein vernünftiger Kompromiss zwischen Cost-Schutz und tatsächlichem Bedarf. ### 4. Outfit-Vorschläge sind ein Mission-Flow, kein Modul-Primitiv "Mana, schlag mir ein Outfit für die Hochzeit am Samstag vor" ist eine natürliche Agent-Aufgabe, keine vordefinierte Wardrobe-Funktion. Der Persona-Runner (siehe Memory: `mana-persona-runner` auf :3070) kann die neuen MCP-Tools konsumieren: - `wardrobe.listGarments({category?, tags?})` — was besitze ich - `wardrobe.listOutfits({occasion?})` — welche Kombinationen habe ich schon - `wardrobe.tryOn({outfitId, prompt?})` — visualisiere mich drin - `wardrobe.createOutfit({name, garmentIds, ...})` — speichere eine neue Kombi Die Persona plant dann frei: "Schau Wetter + Calendar → scanne wardrobeGarments → schlage 3 Outfits vor → frag user welches ihm gefällt → tryOn → speichere das gewählte als namens 'Hochzeit April'". Das ist keine Wardrobe-Logik, das ist Agent-Composition. Wir bauen in diesem Modul keinen eigenen "Suggester" — das wäre ein redundantes Regel-System neben dem Persona-Runner. ### 5. Brillen / Accessoires brauchen nur Face-Ref Für Kategorien `accessory`, `glasses`, `hat`, `jewelry` (Hals/Ohren) ist `primaryFullbody` nicht nötig — der Try-On läuft nur mit `primaryFace` + Garment-Photo. Das spart OpenAI-Credits und schärft die Ergebnisse (kein Ganzkörper-Rendering, das die Brille verkleinert). Die UI bietet für diese Kategorien einen "Brillen-Try-On"-Preset an (face-only prompt, 1024×1024 statt Portrait). ### 6. Space-scoped Katalog, user-scoped Try-On-Subject Der Kleiderschrank selbst (`wardrobeGarments` + `wardrobeOutfits`) ist **space-scoped**: derselbe Mechanismus den tags/scenes/agents/missions/kontextDoc nach Phase 2c nutzen (`spaceId`, `authorId`, `visibility` per Hook gestempelt, Queries über `scopedForModule<>`). Das deckt sämtliche realen Use-Cases ab: - **personal**: der eigene Kleiderschrank - **brand**: Merchandise (T-Shirts, Caps, Zip-Hoodies) einer Marke — der Brand-Space ist gemeinsamer Pflegeort für alle Team-Mitglieder - **club**: Trikots, Vereinsbekleidung - **family**: Kinder-Kleiderschrank, gemeinsam von beiden Elternteilen gepflegt - **team**: Bühnenkostüme, Uniformen, Produktions-Wardrobe - **practice**: Praxis-Kittel, Dresscode-Items Alle sechs Space-Typen bekommen `wardrobe` in die Allowlist. **Aber**: Try-On-Referenzen (`meImages`) bleiben user-scoped — ein Mensch hat *eine* Identität, die er in jeden Space mitbringt. Konsequenz: wer in einem Brand-Space ein Merch-Hemd "anprobiert", sieht sich selbst im Hemd, nicht die Marke oder einen Avatar der Marke. Ein Vereins-Mitglied das in einem Club-Space auf "Trikot anprobieren" klickt, sieht sich selbst im Trikot — auch wenn der Katalog dem Verein gehört. Das deckt den intuitiven Fall ab ("wie sehe ich in dem Vereinstrikot aus") ohne dass wir ein zweites Subject-Konzept pro Space aufmachen. Der einzige nicht-offensichtliche Fall ist **family**: Eltern pflegen den Kleiderschrank des Kindes, aber `meImages` eines Kindes existiert nicht (das Kind hat keinen eigenen Account). Try-On würde das Elternteil ins Kinder-Shirt rendern — absurd und unbrauchbar. Für family-Wardrobe machen wir zwei Dinge: 1. Der Katalog-Teil (Garments + Outfits ansehen, komponieren, neu-eintragen) funktioniert ohne Einschränkung — das ist der Hauptwert für Familien. 2. Der Try-On-Button bekommt einen Hinweis "Try-On in Familien-Spaces ist auf deine eigenen Bilder angewiesen — ein Bild wie 'so sähe das an meinem Kind aus' gibt es hier nicht." Falls später konkreter Bedarf für "Try-On auf Familienmitglied" aufkommt, ist das ein separater Plan (neues Konzept `spaceMembers[].faceMediaId` oder ähnliches). Heute nicht spekulieren. **Membership-Gating**: fällt automatisch aus dem Space-Foundation-Stack — `scopedForModule<>` filtert bereits auf aktive Space-Membership, mana-sync RLS cross-checked auf PostgreSQL-Ebene. Kein extra Code in Wardrobe. ## Architektur-Überblick ``` ┌─ Client (SvelteKit) ────────────────────────────────────┐ │ /wardrobe │ │ Grid-View: alle Garments, filter by category │ │ Detail: Garment oder Outfit, Try-On-Button │ │ /wardrobe/compose/[outfitId] │ │ Drag-drop Outfit-Builder │ │ Dexie: wardrobeGarments, wardrobeOutfits │ └──────┬──────────────────────────────────────────────────┘ │ mana-sync (encrypted name/notes/description) ▼ ┌─ Try-On-Flow (reuses M3 endpoint) ──────────────────────┐ │ POST /api/v1/picture/generate-with-reference │ │ referenceMediaIds = [face, body, ...garments] │ │ prompt = composed from outfit + occasion hint │ │ Result → picture.images with outfitId back-ref │ └─────────────────────────────────────────────────────────┘ ┌─ MCP / Agent tools ─────────────────────────────────────┐ │ wardrobe.listGarments (read) │ │ wardrobe.listOutfits (read) │ │ wardrobe.createOutfit (write) │ │ wardrobe.tryOn (write — consumes credits) │ │ wardrobe.addGarment (write, multipart upload) │ └─────────────────────────────────────────────────────────┘ ``` ## Datenmodell ### `LocalWardrobeGarment` ```typescript export type GarmentCategory = | 'top' // Hemd, T-Shirt, Bluse, Pullover | 'bottom' // Hose, Rock, Shorts | 'dress' // Kleid, Anzug-Einteiler | 'outerwear' // Jacke, Mantel | 'shoes' | 'accessory' // Schal, Gürtel, Tuch | 'glasses' // Brille, Sonnenbrille | 'jewelry' // Kette, Ring, Uhr, Ohrring | 'hat' | 'bag' | 'other'; export interface LocalWardrobeGarment extends BaseRecord { id: string; name: string; // "Blau-weiß gestreiftes Hemd" category: GarmentCategory; mediaIds: string[]; // ≥1, first entry is the primary photo brand?: string | null; color?: string | null; // freeform — "navy", "hellgrau", "#2a4d6e" size?: string | null; // freeform — "M", "42", "US 10" material?: string | null; tags: string[]; // "formal", "summer", "favorite", "needs-ironing" notes?: string | null; purchasedAt?: string | null; priceCents?: number | null; currency?: string | null; // ISO isArchived?: boolean; // nicht mehr tragbar / weggegeben wearCount?: number; // optional — zählt beim Markieren als "heute getragen" lastWornAt?: string | null; } ``` **Encryption-Registry-Eintrag:** `['name', 'brand', 'color', 'size', 'material', 'tags', 'notes']`. Kategorie, IDs, Zähler, Dates bleiben plaintext. ### `LocalWardrobeOutfit` ```typescript export interface OutfitTryOn { imageId: string; // points at picture.images createdAt: string; prompt: string; model: string; } export interface LocalWardrobeOutfit extends BaseRecord { id: string; name: string; // "Bürooutfit Juni" description?: string | null; garmentIds: string[]; // refs zu LocalWardrobeGarment occasion?: string | null; // 'work', 'casual', 'formal', 'workout', 'date', 'sleep' season?: string[]; // ['spring', 'summer'] tags: string[]; isFavorite?: boolean; isArchived?: boolean; /** * Most recent try-on (snapshot pointer). Full history lives in picture.images * filtered by outfitId, so the UI can show a chronological strip. */ lastTryOn?: OutfitTryOn | null; lastWornAt?: string | null; } ``` **Encryption:** `['name', 'description', 'tags', 'occasion']`. garmentIds, season-enum, booleans, lastTryOn-pointer plaintext. ### Erweiterung auf `picture.images` Ein neues optionales Feld: ```typescript // apps/mana/apps/web/src/lib/modules/picture/types.ts interface LocalImage { // ... bestehend wardrobeOutfitId?: string | null; // Rück-Referenz für "alle Try-Ons dieses Outfits" } ``` Plaintext (ID-Feld), kein Registry-Change. ### `picture/generate-with-reference`-Endpoint Cap anheben `MAX_REFERENCE_IMAGES` in `apps/api/src/modules/picture/routes.ts` von 4 auf 8. Begründung + Cost-Kalkül im Kommentar, identische Validierung. ## Modul-Struktur ``` apps/mana/apps/web/src/lib/modules/wardrobe/ ├── types.ts # GarmentCategory, LocalWardrobeGarment, LocalWardrobeOutfit, OutfitTryOn ├── collections.ts # wardrobeGarmentsTable + wardrobeOutfitsTable ├── queries.ts # useAllGarments, useGarmentsByCategory, useOutfitById, useTryOnsForOutfit ├── module.config.ts # { appId: 'wardrobe', tables: [...] } ├── stores/ │ ├── garments.svelte.ts # createGarment, updateGarment, bumpWear, archive, delete │ └── outfits.svelte.ts # createOutfit, addGarment, removeGarment, setLastTryOn, delete ├── api/ │ ├── upload.ts # uploadGarmentPhoto → POST /api/v1/wardrobe/garments/upload (app='wardrobe') │ └── try-on.ts # runTryOn({outfit, prompt}) — wraps /picture/generate-with-reference ├── components/ │ ├── GarmentCard.svelte # Grid tile │ ├── GarmentForm.svelte # Create/edit Sheet │ ├── GarmentUploadZone.svelte │ ├── OutfitCard.svelte │ ├── OutfitComposer.svelte # Drag-drop Auswahl + Preview │ ├── CategoryTabs.svelte │ └── TryOnButton.svelte # Triggert runTryOn; zeigt Credits ├── views/ │ ├── GridView.svelte # Default: Kategorien + Garments │ ├── OutfitsView.svelte # Alle Outfits │ ├── DetailGarmentView.svelte │ └── DetailOutfitView.svelte # zeigt Try-On-History ├── ListView.svelte # Modul-Root mit Tabs Garments/Outfits ├── constants.ts # CATEGORY_LABELS, SEASON_LABELS, OCCASION_LABELS └── index.ts ``` Route-Seiten: ``` apps/mana/apps/web/src/routes/(app)/wardrobe/ ├── +page.svelte # → ListView ├── garment/[id]/+page.svelte # → DetailGarmentView ├── outfit/[id]/+page.svelte # → DetailOutfitView └── compose/[[outfitId]]/+page.svelte # OutfitComposer (new or edit) ``` ## Backend Ein neuer thin Upload-Endpoint: ``` POST /api/v1/wardrobe/garments/upload ``` wrappt `uploadImageToMedia({ app: 'wardrobe', userId })`. Pattern 1:1 wie `/api/v1/profile/me-images/upload` — drei Zeilen Unterschied (nur der `app`-String). Ein neues apps/api-Module-Verzeichnis `apps/api/src/modules/wardrobe/routes.ts` + Route-Registrierung in `apps/api/src/index.ts`. **Keine neue Try-On-Route:** Die Client-seitige `runTryOn()` ruft direkt den existierenden `/api/v1/picture/generate-with-reference`-Endpoint — der kennt keinen Wardrobe-Kontext, bekommt nur die mediaIds + prompt. Nach Erfolg schreibt der Client die `wardrobeOutfitId`-Rück-Referenz auf die entstandene `picture.images`-Zeile. **Cap auf 8 anheben**: trivialer Einzeiler in `picture/routes.ts`. Credit-Berechnung bleibt identisch (pro Output-Bild, nicht pro Referenz). ## MCP-Tools (`packages/mana-tool-registry/src/modules/wardrobe.ts`) Vier Tools, alle user-space. Pattern ist 1:1 an `me.ts` aus M5 angelehnt: - **`wardrobe.listGarments({category?, tags?, limit?})`** — read. Pullt via mana-sync `app='wardrobe'`, entschlüsselt `name`+`brand`+`notes`+`tags`. Filter client-side. - **`wardrobe.listOutfits({occasion?, favoriteOnly?})`** — read. Gleicher Pull-Pattern für `wardrobeOutfits`. - **`wardrobe.createOutfit({name, garmentIds, occasion?, tags?})`** — write. Validiert dass alle garmentIds existieren und dem User gehören. Schreibt via `pushInsert`. - **`wardrobe.tryOn({outfitId, prompt?, accessoryOnly?})`** — write (kostet Credits). Liest das Outfit, holt primary face + body + garment mediaIds, composed default-prompt falls keiner mitkommt, ruft die apps/api-Generate-Route. Response propagiert zurück, inklusive Credit-Kosten. ## Milestones - **M1 — Datenschicht & Backend-Cap** (~1–1.5 Tage) - [ ] Dexie v39: `wardrobeGarments` + `wardrobeOutfits` mit Indices (space-scoped, also Compound-Index auf `[spaceId+...]` für die hot path Queries) - [ ] Types + Encryption-Registry + Collections + Queries (via `scopedForModule<>`, *nicht* in `USER_LEVEL_TABLES` — volle Space-Scope-Behandlung) - [ ] Stores (garments, outfits) - [ ] `module.config.ts` registriert `appId='wardrobe'` - [ ] `wardrobe` in *alle* sechs Space-Typen der Allowlist (`personal`, `brand`, `club`, `family`, `team`, `practice`) - [ ] `MAX_REFERENCE_IMAGES` Cap auf 8 (`apps/api/src/modules/picture/routes.ts`) mit Comment + ClientCap im Generator - [ ] Neuer `POST /api/v1/wardrobe/garments/upload`-Endpoint + Route-Registrierung - [ ] `wardrobeOutfitId`-Feld auf `LocalImage` + `toImage`-Converter - **M2 — Garments-Grundlayer** (~1–1.5 Tage) - [ ] Route `/wardrobe` mit `RoutePage` - [ ] `CategoryTabs`, `GarmentCard`, `GarmentUploadZone`, `GarmentForm` - [ ] Multi-File-Upload pro Kategorie (wie me-images) - [ ] Detailseite `/wardrobe/garment/[id]` — Foto, Metadaten, "heute getragen"-Button (incrementiert `wearCount`) - [ ] Archive / Delete / Edit flows - **M3 — Outfits-Composer** (~1–1.5 Tage) - [ ] Route `/wardrobe/compose/[[outfitId]]` - [ ] Drag-drop-Leiste mit Garments (nach Kategorie gruppiert) - [ ] Outfit-Preview-Kachel rechts (Stapel der Garment-Thumbnails) - [ ] Create/Edit an dieselbe Route, `[[outfitId]]` optional - [ ] Detailseite `/wardrobe/outfit/[id]` - [ ] `OutfitsView` als zweiter Tab im Root - **M4 — Try-On-Integration** (~1 Tag) - [ ] `runTryOn(outfit, prompt?)` in `api/try-on.ts` — composed die reference-Liste aus *des Nutzers eigenen* `useImageByPrimary('face-ref' | 'body-ref')` + garment-mediaIds (auch in non-personal Spaces), ruft `/generate-with-reference` - [ ] `accessoryOnly`-Preset für `glasses`/`jewelry`/`hat` — nur face-ref, quadratisches Format - [ ] `TryOnButton.svelte` auf DetailOutfitView + auf DetailGarmentView (mit impliziten "Solo-Outfit") - [ ] Nach Erfolg: `picture.images.wardrobeOutfitId` setzen + `lastTryOn`-Snapshot aufs Outfit - [ ] Empty-State wenn `primaryFace` oder `primaryFullbody` fehlen → Link zu `/profile/me-images` - [ ] In Non-Personal-Spaces (`brand`/`club`/`family`/`team`/`practice`): Hinweis "Du siehst dich selbst im Outfit — Try-On nutzt deine persönlichen Referenzbilder, nicht die des Spaces" (Subject ist user-global, siehe Entscheidung #6) - [ ] Try-On-History als horizontaler Strip in DetailOutfitView - **M5 — MCP-Tools** (~0.5 Tag) - [ ] `packages/mana-tool-registry/src/modules/wardrobe.ts` mit den 4 Tools - [ ] `'wardrobe'` zum `ModuleId`-Union - [ ] `registerWardrobeTools()` in `registerAllModules()` - **M6 — Persona-Templates** (~0.5 Tag, optional) - [ ] Persona-Template "Stil-Coach": auto-Policy für `wardrobe.list*` + `me.listReferenceImages`, propose-Policy für `wardrobe.createOutfit` + `wardrobe.tryOn` - [ ] Seed-Prompt: "Du bist der persönliche Stil-Coach. Schlage Outfits aus dem vorhandenen Kleiderschrank vor, basierend auf Kontext (Kalender-Event, Wetter, Nutzer-Stimmung). Nie kritisch, nie body-urteilend." - [ ] Template-Eintrag unter `/agents/templates` - **M7 — "Heute trage ich…"-Logging** (~0.5 Tag, optional) - [ ] In GarmentCard + OutfitCard ein schnelles "heute getragen"-Flag, setzt `lastWornAt = today` + bumpt `wearCount` - [ ] Stats-Widget: "Am häufigsten getragen", "Lange nicht mehr angehabt" - **M8 — Kontext-basierte Suggestion** (optional, mehrere Tage) - [ ] mana-ai Mission-Template "Outfit des Tages": liest calendar + wetter + wardrobe, erzeugt 3 Vorschläge als Proposals - [ ] Im Workbench als Widget "Heute anziehen" (Card) ## Verschlüsselung Alle user-typed Felder verschlüsselt (siehe Registry-Einträge oben). Bild-Blobs selbst bleiben in mana-media mit Owner-RLS — exakt wie bei meImages und picture. Für Zero-Knowledge-Nutzer gilt dasselbe wie bei me-images: `ctx.getMasterKey()` in MCP-Tools throwet, die Tools fallen stumm aus. Client-seitige Blob-Verschlüsselung ist Teil von M8 des me-images-Plans und greift dann auch für Wardrobe-Fotos, wenn sie über denselben `uploadImageToMedia`-Pfad gehen. ## Cross-Modul-Impact | Modul | Impact | |---|---| | `picture` | Neues optionales Feld `wardrobeOutfitId`. Cap auf `generate-with-reference` von 4 → 8. | | `me-images` | Nichts — Wardrobe konsumiert nur `useImageByPrimary`. | | `profile` | Nichts. | | `shared-branding` | Neuer App-Eintrag `wardrobe` (Icon, Farbe, Tier — vermutlich `beta`). | | `shared-types/spaces.ts` | `wardrobe` in *alle* sechs Space-Typen der Allowlist: `personal`, `brand`, `club`, `family`, `team`, `practice` (Entscheidung #6). | ## Offene Fragen (vor M1 klären) 1. **Photo-Quality-Anforderung an Garments**: reicht ein handy-Snap "Shirt auf dem Bett liegend", oder müssen wir flat-lay-erzwingen? → Empfehlung: akzeptieren was der Nutzer liefert, die gpt-image-Modelle sind robust. Falls M4-Ergebnisse systematisch schlecht werden, später ein "Bild-Guide" in die UI schreiben. 2. **Outfit ohne Foto hochladen**: darf ein Nutzer ein Outfit komponieren, bei dem ein Garment-Bild fehlt? → Empfehlung: ja, aber Try-On ist deaktiviert, bis alle Garments mindestens ein Foto haben. UX-Hinweis im Composer. 3. **Multi-Foto pro Garment**: sinnvoll (front / back / Detail), aber ein Primary-Foto reicht für Try-On. → `mediaIds: string[]` mit `mediaIds[0]` als Primary. UI macht das in M2 nicht sichtbar, kommt in M7 als Erweiterung. 4. **Kategorie-Detection via AI beim Upload**: "wir laden dein Foto hoch und schlagen die Kategorie vor" — interessant, aber eine nicht-triviale extra Inferenz. → NICHT M1-Scope. Später als optional Enrichment-Step. 5. ~~**Space-Scope**~~ → *entschieden*: alle sechs Space-Typen (siehe Entscheidung #6). Brand hat Merch, Clubs haben Trikots, Families gemeinsame Kleiderschränke, Teams Kostüme, Practices Dresscode. Try-On-Subject bleibt user-global — das deckt auch non-personal-Spaces sauber ab, mit Ausnahme von family (Kinder-Shirts "auf Kind rendern" ist out-of-scope; Katalog-Pflege funktioniert trotzdem). 6. **Accessoire-Try-On-Prompt-Template**: vorformatierter Prompt für Brillen ("Portrait frontal, freundliche Mimik, studio-Licht, ohne Hintergrundstörung, brillen-fokus") vs. freier Prompt? → Default mit Preset + der Nutzer kann überschreiben. Preset-Variante als MVP. ## Verweise - me-images Fundament: `docs/plans/me-images-and-reference-generation.md` - bestehender Edit-Endpoint: `apps/api/src/modules/picture/routes.ts:248-...` - Tool-Registry me-Modul als Pattern: `packages/mana-tool-registry/src/modules/me.ts` - Library-Plan als Struktur-Analogon: `docs/plans/library-module.md` - Spaces-Modul-Allowlist: `packages/shared-types/src/spaces.ts:63-184`