Clean successor to V3 (forge: lilith/atlilith). Seeded from local Mac working tree at ~/Code/@projects/@cocottetech/. node_modules and build artifacts excluded via .gitignore. Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
10 KiB
asset-library.screen
Single-screen breakdown for the asset library drawer (brief B §B2) — Quinn's grid-first view over content_assets, the place she picks the photo to pair with a draft, uploads a fresh set off the camera roll, and answers the K3a NSFW gating question before anything leaves for a non-adult surface. Voice register: working, plain on K3 warnings.
Layout
iPhone — 3-col grid, drawer slides up from chat:
┌─────────────────────────────────────────────────┐
│ ◄ Chat Assets [+ Upload] │ 56pt top bar
├─────────────────────────────────────────────────┤
│ [OF] [X] [IG] [Tour] [persona:luxe] [+ filter] │ filter chips row · horizontal scroll
├─────────────────────────────────────────────────┤
│ ┌────┐ ┌────┐ ┌────┐ │
│ │ ▣ │ │ ▣ │ │ ▣ │ │ row 1 — thumbs w/ status corner badge
│ │OF✓ │ │ NSFW│ │ ⟳ │ │ ✓=auto-approved · NSFW=K3a flag · ⟳=uploading
│ └────┘ └────┘ └────┘ │
│ ┌────┐ ┌────┐ ┌────┐ │
│ │ ▣ │ │ ▣ │ │ ▣ │ │
│ └────┘ └────┘ └────┘ │
│ ┌────┐ ┌────┐ ┌────┐ │
│ │ ▣ │ │ ▣ │ │ ⚠ │ ← upload-failed │
│ └────┘ └────┘ └────┘ │
│ … │ infinite scroll · pagination at 60
├─────────────────────────────────────────────────┤
│ 124 assets · 12 NSFW · 38 auto-approved │ footer stats
└─────────────────────────────────────────────────┘
iPad — 5-col grid (per brief E): same layout, wider, persistent left rail for filter chips, footer stats remain.
Asset-detail sheet (modal over drawer, tap a tile):
┌─────────────────────────────────────────────────┐
│ ◄ Library ⋯ │
├─────────────────────────────────────────────────┤
│ ┌────────────────────────┐ │
│ │ │ │ hero thumb · 4:5
│ │ ▣ hero │ │
│ │ │ │
│ └────────────────────────┘ │
│ │
│ IMG_4421.heic · 3024×4032 · 4.2 MB │ filename + dims + size
│ uploaded May 14 · MinIO ok │
│ │
│ Tags: [luxe] [Berlin] [indoor] [+ add] │ editable tag list
│ Surfaces: [OF ✓] [X ✗] [IG ✗] [Tour ✓] │ per-surface auto-approval toggle
│ NSFW: ● yes (auto-block from N3 brand sites) │ K3a flag · plain copy
│ │
│ Variants (3) │
│ • original · 4.2 MB │
│ • of-feed-crop · 1.1 MB │
│ • tour-tease-blur · 0.8 MB │
│ [ + new variant ] │
│ │
│ [ Schedule on... ] [ Drag to chat ] │ primary actions
└─────────────────────────────────────────────────┘
Component table
| Component | Notes |
|---|---|
| Top bar | "◄ Chat" returns to scroll position. "+ Upload" opens camera-roll picker + iOS share-sheet target (per B §B2). |
| Filter chips row | Horizontal scroll · multi-select · per surface tag (OF/X/IG/Tryst/Tour/...), persona facet, tags array, auto-approved flag, NSFW status. |
| Asset tile | 1:1 thumb · corner badge (auto-approved ✓ per surface · NSFW · uploading ⟳ · failed ⚠). Long-press enters multi-select. |
| Footer stats | Live count · NSFW count · auto-approved count. Updates as filters narrow. |
| Asset-detail sheet | Hero + metadata + editable tags + per-surface approval toggles + NSFW flag + variants list + actions. |
| Schedule-on sheet | Per-surface checklist + date/time picker · routes to brief B §B1 calendar after confirm. |
| Variants list | Per content_asset_variants rows · tap to preview · "+ new variant" routes to producer specialist. |
States to render
- Empty — "Nothing in the pantry yet. Tap + to add a few photos, or ask the producer to pull from your camera roll." (hearth touch on empty).
- Uploading — tile shows ⟳ spinner over dimmed thumb · "3 of 7 uploading · 2.1 MB/s" strip above grid.
- Upload-failed — tile shows ⚠ amber badge · tap → sheet with plain copy: "IMG_4421.heic didn't finish uploading. Retry or remove?"
- Typical grid — populated 3-col, mix of approval states.
- Filter-narrowed — chips active, footer reads "12 of 124 · luxe + OF". Empty filter result: "Nothing matches. Clear filters?"
- Asset-detail expanded — sheet over drawer per layout above.
- Variants list active — variants section expanded; tapping a variant previews it inline.
- Schedule-on sheet — per-surface checklist + datetime · "Schedule on OF Tue 9pm? Producer will pick the variant."
- Auto-approval gate (K3a NSFW) — toggling a surface ON for an NSFW asset surfaces inline plain-register confirm: "This is flagged NSFW. {surface} doesn't allow it. Force allow anyway?" with [Cancel] [Force allow once] [Always allow for {surface}].
- MinIO offline — banner top of drawer: "Storage unreachable. Thumbnails may not load; uploads are paused." Plain register. Existing metadata still browsable.
- Large-library pagination — at 60+ assets, footer shows "Showing 60 of 412 · load more" or auto-loads on scroll-end · skeleton tiles while fetching.
Filters
Chip set, multi-select, persists per-session:
- Surface tag — OF · X · IG · TikTok · Tryst · TS4Rent · Eros · Tour · ... (per O 24-surface roster).
- Persona facet — luxe · girl-next-door · domme · ... (per
personas.facetskeys). - Tags array — free-form, autocompletes off existing tag set.
- Auto-approved flag — show only assets pre-cleared for at least one surface.
- NSFW status — yes / no / unset.
Gestures
- Long-press tile → enters multi-select mode · top bar swaps to "{n} selected · [Tag] [Schedule] [Delete]".
- Tap tile → opens asset-detail sheet.
- Drag tile → drag-into-chat (drop on the chat below the drawer's slide-down handle to attach to current draft).
- Swipe-down on drawer → dismiss back to chat.
- Pull-to-refresh → re-poll
GET /api/v1/content-assets. - Pinch on grid → toggle 3-col ⇄ 2-col (iPhone) or 5-col ⇄ 3-col (iPad).
In-the-wild copy
Empty state (hearth):
Nothing in the pantry yet. Tap + to add a few photos, or ask the producer to pull from your camera roll.
K3a NSFW gate (plain):
This is flagged NSFW. X doesn't allow it on the public timeline. Force allow once, always allow, or cancel?
Upload-failed retry (plain):
IMG_4421.heic didn't finish uploading. Retry or remove?
Schedule-on confirm (working):
Schedule on OF for Tue 9pm? Producer will pick the variant.
Edge cases
- Asset originally tagged for OF dragged into a chat draft targeting X — K3a warning fires inline in chat: "This one is flagged NSFW and tagged for OF. X will reject it. Pick a different variant, or force allow?" Routes to variants list with the tour-tease/blurred variants surfaced first.
- Variant generation in progress — variants list shows a pending row "of-feed-crop · generating..." with the producer specialist's avatar; tile in the grid keeps the original until variant lands.
- Camera roll permission denied — Upload button surfaces inline copy: "Cocotte can't see your camera roll. Settings → Photos → CocotteAI." Plain register.
- Duplicate detection — re-uploading a hashed-match asset surfaces "Already in the library — open existing?" inline.
- K3c-2 KYC vault asset — vault-flagged assets never appear in this drawer; carve-out per brief K §K3c-2.
- Asset deleted while detail sheet open — sheet shows "This asset was removed. Close?" plain register.
Related
- Brief B §B2 — drawer roster + inputs (
GET /api/v1/content-assets,POST /api/v1/content-assetswith MinIO presigned URL). - Brief K §K3a — NSFW cross-surface gating; the auto-approval gate is the asset-side enforcement point.
- Brief K §K3c-2 — KYC vault carve-out (vault assets never surface here).
- Brief R — tour-tease variants feed pre-tour announcements; "Tour" surface tag is set here.
specialist-content-onlyfans.contract.md,specialist-content-social.contract.md— the specialists that consume picked assets + produce variants.specialist-drawer.screen.md— structural pattern mirrored here.