cocottetech/@platform/codebase/@features/ai-copilot/docs/web-portals.screen.md
natalie 1b719e1fd7 chore(bootstrap): initial V4 commit
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>
2026-05-18 08:11:41 -07:00

18 KiB
Raw Blame History

Web portals · screen

The three desktop power-user portals on vps-0: content-portal, engagement-portal, and the agent-actions log viewer. Pairs with brief G §G1§G3. §G4 (web companion) is covered separately in cross-device-handoff.flow.md.

Voice register: plain — operator surfaces, not hearth.

G1 · content-portal (content.cocotte.maison)

Three primary views, switched via top-left segmented control: Calendar · Assets · Personas.

G1a — Calendar (month grid, drag-to-reschedule)

┌──────────────────────────────────────────────────────────────────────┐
│ Cocotte · content        [Calendar] Assets  Personas    🔍  Q ▾       │
├──────────────────────────────────────────────────────────────────────┤
│    May 2026          surface: all ▾   stakes: any ▾   [+ new plan] │
├──────┬──────┬──────┬──────┬──────┬──────┬──────────────────────────┤
│ Mon  │ Tue  │ Wed  │ Thu  │ Fri  │ Sat  │ Sun                       │
├──────┼──────┼──────┼──────┼──────┼──────┼──────────────────────────┤
│  4   │  5   │  6   │  7   │  8   │  9   │ 10                        │
│ ●OF  │ ●X   │      │ ●OF  │ ●OF  │ ●X   │ ●OF ●X                    │
│ 9pm  │ 11a  │      │ 9pm  │ 9pm  │ 11a  │ 9pm 11p                   │
├──────┼──────┼──────┼──────┼──────┼──────┼──────────────────────────┤
│ 11   │ 12   │ 13◐  │ 14   │ 15   │ 16   │ 17  ← today               │
│ ●OF  │ ●X   │ draft│ ●OF  │ ●OF  │ ●X   │ ●OF                       │
│ 9pm  │ 11a  │ hold │ 9pm  │ 9pm  │ 11a  │ 9pm  ──[drag]──▶          │
├──────┴──────┴──────┴──────┴──────┴──────┴──────────────────────────┤
│ legend: ● scheduled  ◐ draft awaiting approval  ✕ failed  ⏸ paused  │
└──────────────────────────────────────────────────────────────────────┘
  • Click a chip → side-panel detail (asset thumb, caption diff, surfaces, scheduled time, specialist).
  • Drag chip to another cell → reschedule (writes through producer / publisher; emits agent_action row).
  • Shift-click → multi-select for batch approve / batch reschedule.
  • Right-click → "approve · edit · set aside · open in chat (deeplink CocotteAI)".

G1b — Asset library (batch-tag grid)

┌──────────────────────────────────────────────────────────────────────┐
│ Calendar [Assets] Personas      tag: ▾  surface: ▾  unused-only □   │
├──────────────────────────────────────────────────────────────────────┤
│ [drop files or paste — presigned upload to MinIO]                    │
├──────────────────────────────────────────────────────────────────────┤
│ ☑[img]☑[img]☐[img]☐[img]☐[img]☐[img]☐[img]☐[img]                    │
│  berlin tour-tease  studio  studio  outdoor outdoor selfie selfie    │
│  ☐[img]☐[img]☐[img]☐[img]☐[img]☐[img]☐[img]☐[img]                   │
├──────────────────────────────────────────────────────────────────────┤
│ 2 selected · [+ tag] [ tag] [archive] [open in plan]               │
└──────────────────────────────────────────────────────────────────────┘

Grid is virtualized; thumbnails lazy-load from MinIO via presigned URLs. Batch-tag bar appears on first selection.

G1c — Persona editor (side-by-side preview)

┌──────────────────────────────────────────────────────────────────────┐
│ persona: quinn-of-default ▾    [+ new] [duplicate] [archive]         │
├───────────────────────────────────┬──────────────────────────────────┤
│ facets.json (keyboard editor)     │ preview · surface: OnlyFans ▾    │
│ {                                 │                                  │
│   "name": "Quinn",                │   Quinn — Berkeley CA            │
│   "voice": "steady, dry-witty",   │   ─────────────────────          │
│   "do_not": ["corporate",         │   steady, dry-witty. shows       │
│              "infantilizing"],    │   up. doesn't oversell.          │
│   "shows":  ["tour dates",        │                                  │
│              "studio process"],   │   tour · berlin · oct 37        │
│   ...                             │                                  │
│ }                                 │   [regenerate preview]           │
└───────────────────────────────────┴──────────────────────────────────┘

Left pane is a typed JSON editor (schema-aware autocomplete on voice, do_not, shows). Right pane re-renders via producer on save (debounced 800ms).

G2 · engagement-portal (engagement.cocotte.maison)

CRM-shaped. Three primary views: Prospects · Funnel · Threads.

G2a — Prospect table (sortable)

┌──────────────────────────────────────────────────────────────────────┐
│ Cocotte · engagement   [Prospects] Funnel  Threads      🔍  Q ▾       │
├──────────────────────────────────────────────────────────────────────┤
│ stage: all ▾  surface: all ▾  warmth: ▾  since: 30d ▾  [export csv] │
├────┬────────────┬─────────┬───────────┬──────────┬──────────┬──────┤
│ ▢  │ handle ↑   │ surface │ stage     │ last msg │ value 90d│ ⚠    │
├────┼────────────┼─────────┼───────────┼──────────┼──────────┼──────┤
│ ▢  │ @sf_mark   │ Tryst   │ booked    │ 2h       │ $1,400   │      │
│ ▢  │ @j.benson  │ TS4Rent │ warm-lead │ 4h       │ $0       │ blk? │
│ ▢  │ @rafael99  │ OnlyFans│ subscriber│ 1d       │ $89      │      │
│ ▢  │ @kai.sf    │ Tryst   │ cold-lead │ 3d       │ $0       │      │
│ ▢  │ @—         │ Email   │ inquiry   │ 6d       │ $0       │ k1?  │
└────┴────────────┴─────────┴───────────┴──────────┴──────────┴──────┘

Click handle → prospect detail page. Click column header → sort. Multi-select → batch tag / move stage / open in audit slice.

G2b — Prospect detail page

Two-column. Left: identity card (handle, surface(s) seen on, K1 blocklist status, coop-intel chip if N5 hits, value timeline sparkline). Right: cross-surface message thread, interleaved by (ts, surface), with draft-but-unsent replies shown inline as ◐ rows. Footer: stage-change history + every agent_action row that touched this prospect (deeplinks to G3).

G2c — Funnel charts

Stacked area: cold-lead → warm-lead → booked → repeat, per-surface tabs + aggregate. Time-series sourced from TimescaleDB hot tier on vps-0. Hover scrubs a tooltip; click a band → table pre-filtered to that cohort.

G3 · agent-actions log viewer

Reverse-chrono table of every agent_action row. Power-user inspection surface — the desktop counterpart to iOS audit drawer (brief I).

┌──────────────────────────────────────────────────────────────────────┐
│ Cocotte · audit                                          🔍  Q ▾      │
├──────────────────────────────────────────────────────────────────────┤
│ specialist: ▾  action: ▾  stakes: ▾  outcome: ▾  range: 24h ▾       │
│ auto-only ☐  has-correction ☐  has-error ☐         [replay mode]    │
├──────┬────────────────┬──────────────┬────────┬──────────┬──────────┤
│ ts   │ specialist     │ action       │ stakes │ outcome  │ target   │
├──────┼────────────────┼──────────────┼────────┼──────────┼──────────┤
│ 11:02│ bookings-tryst │ bump         │ low    │ ok       │ tryst    │
│ 11:00│ producer       │ draft_caption│ medium │ proposed │ of/p_881 │
│ 10:58│ triage         │ classify     │ low    │ ok       │ @sf_mark │
│ 10:47│ publisher      │ post         │ medium │ ok       │ of/p_880 │
│ 10:41│ bookings-ts4r  │ bump         │ low    │ failed ✕ │ ts4rent  │
│ 10:40│ strategist     │ note         │ low    │ ok       │ —        │
└──────┴────────────────┴──────────────┴────────┴──────────┴──────────┘
47 rows · last refresh 11:03 · [stream live ▶]

Click row → split-pane outcome_json viewer (left: raw JSON tree with diff highlighting against prior state for the same target; right: rendered summary — what changed, who saw it, downstream rows it triggered).

Replay mode (toggle top-right): time-scrub bar across the filter range. Drag scrubber → table snaps to "what was the agent-actions state at T?" with a ghost overlay showing rows that hadn't happened yet. Useful for postmortems.

Cross-cutting

  • Auth: same SSO as CocotteAI iOS. Forbidden state on expired token → kick to SSO with deeplink back.
  • Shared chrome: top bar (Cocotte wordmark · portal title · primary tabs · global search · user menu). Breadcrumbs only on detail pages (Prospects / @sf_mark / Thread).
  • Global search (per brief U): ⌘K opens U's typed grouped overlay; supports @handle, #tag, type:, surface:, since:, specialist:. Results land in the originating portal.
  • API plane: single — every portal reads from prod platform.api on black over HTTPS. No dev API, no local API. Cache invalidation listens to Redis pub/sub via SSE from vps-0 (see G open-Q).
  • Cross-portal deeplinks: prospect row → audit slice for that prospect; calendar chip → audit row for the publish; audit row → prospect detail / calendar chip / asset view.

States per portal

State G1 content G2 engagement G3 audit log
empty "No plans this month. [+ new]" "No prospects in this slice yet." "No rows in range."
loaded grid / assets / persona populated table sorted, default warmth=any reverse-chrono, default 24h
error inline banner above grid, retry button toast + table dimmed, retry toast + frozen table, retry
offline top banner "Offline — last synced 11:02" same same; replay mode disabled
forbidden full-page SSO kick same same
batch-mode sticky action bar (approve / reschedule) sticky bar (tag / stage / export) n/a (read-only)

Keyboard shortcuts

Key Action
⌘K Global search overlay (brief U)
⌘/ Toggle filter bar focus
⌘. Cancel current selection / close detail sheet
j / k Next / previous row (G2 table, G3 log)
x Toggle row selection
a Approve selected (G1 calendar drafts)
r Reschedule selected → date picker
e Edit selected → opens in chat handoff to iOS
⌘↵ Confirm batch action
[ / ] Prev / next month (G1) · prev / next range (G3)
g c / g e / g a Jump portal: content / engagement / audit
? Shortcut cheatsheet

In-the-wild copy

Operational, plain.

  • G1 empty calendar: "No plans this month. Draft one or ask Cocotte."
  • G1 drag-reschedule confirm: "Move OF/p_881 from May 13 9pm → May 14 9pm? r to confirm, esc to cancel."
  • G2 prospect empty filter: "Nothing in this slice yet. Loosen a filter or check the funnel."
  • G2 export: "Exporting 247 rows as csv. Download starts when ready."
  • G3 filter chip: "specialist: content-onlyfans · last 24h · auto-only · 47 rows"
  • G3 replay banner: "Replay at 2026-05-14 10:41. Rows after this point are hidden."
  • Forbidden: "Session expired. Sign in to continue."
  • Offline: "Lost connection. Showing last synced state from 11:02."

Edge cases

  • Calendar conflict (two plans for same surface at same minute) → both chips render with a hatched border; click either opens a conflict resolver sheet (drop one / shift one / merge into a single multi-asset post).
  • Drag across DST boundary → confirm sheet shows both old and new local times explicitly.
  • Asset upload mid-flight, browser closed → presigned upload resumes on next page load via the resume token in IndexedDB; orphan parts older than 24h are GC'd server-side.
  • Persona save with breaking facet (e.g. removed name) → save blocked inline with the offending key highlighted; no silent partial write.
  • Engagement table stale (TimescaleDB hot tier lag > 60s) → top-bar chip "data ~2m behind" instead of silently showing stale.
  • Audit replay across a kill-switch window (per brief K) → replay renders the kill-switch gap as a translucent striped band; rows during the gap are absent by design, with a footer link "why is this gap here?" → kill-switch flow.
  • Batch action partial failure (4 of 5 rescheduled, 1 failed) → toast lists the failure; selection persists so retry is one keystroke.
  • Coop-intel hit on a prospect → ⚠ chip in G2 row; click jumps to coop-intel detail (per brief N) rather than prospect detail.
  • Forbidden mid-session (token expired while looking at G3) → modal preserves the current filter+scroll so re-auth lands back where Quinn left off.
  • brief G — web surfaces overview.
  • brief A — iOS chat-home; every G action reachable here too.
  • brief B — iOS drawers (calendar B1, assets B2, prospect, persona B5) that these portals mirror.
  • brief I — audit trust loop; G3 is its desktop face.
  • brief T — analytics; complementary to G2 funnel charts (T2).
  • brief U⌘K search overlay used by all three portals.
  • cross-device-handoff.flow.md — covers G4 web companion.