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>
3.9 KiB
3.9 KiB
G — Web secondary surfaces
Goal
Web FEs (React 19 + Vite, hosted on vps-0) for visual / bulk / replay work that's wrong-shaped for a phone chat. Same auth, same tokens, same component conceptual model as iOS — but desktop-first.
Designer skim
- Headline UX: Desktop is the inspection/power-user surface; iOS is daily-driver. Every web action is also reachable by asking ai-copilot on phone. Same auth + tokens + components conceptually.
- Surfaces (4): G1
content-portal(calendar, asset lib, persona) · G2engagement-portal(CRM prospect table, funnel telemetry) · G3 agent-actions log viewer · G4ai.cocotte.maisonweb companion. - Pair-with:
cross-device-handoff.flow.md. - Blocking Qs: OPEN-DECISIONS.md → G-Q1 companion parity-vs-divergent.
Constraints
- React 19 + Vite; design tokens shared with iOS via brief F.
- Hosted on vps-0; consumed by Quinn at her laptop. Mobile web works but isn't the target.
- Auth via the same SSO that CocotteAI uses.
- Every action exposed in web is also reachable by asking ai-copilot in iOS — web is the inspection / power user surface, not the primary.
Surfaces
G1 — content-portal (content.cocotte.maison)
- Calendar grid: month view, drag-to-reschedule, multi-select for batch approval. Same
content_plansdata as iOS calendar drawer (brief B1). - Asset library: large grid, batch tag editing, drag-upload, presigned URL flow to MinIO. Mirrors iOS asset drawer (B2).
- Persona editor: keyboard-driven JSON-facet editor with side-by-side preview. Mirrors B5.
G2 — engagement-portal (engagement.cocotte.maison)
- Prospect list (CRM-style): sortable table — surface, funnel stage, last contact, value-to-date.
- Prospect detail page: full cross-surface message history, all drafted-but-unsent replies, value timeline.
- Funnel telemetry charts: per-surface, aggregate, time-series. Data source: TimescaleDB hot tier on vps-0.
G3 — agent-actions log viewer
- Reverse-chronological table of every specialist decision. Filter by specialist_id, action_type, stakes, outcome.
- Tap row → full
outcome_jsonviewer with diff highlighting (when target_kind has a before/after state). - Replay mode: scrub timeline by date range, see "what would the cache state look like at T?"
G4 — ai.cocotte.maison (web companion)
- Lightweight web version of CocotteAI's chat surface, used when Quinn is on a laptop and doesn't want to switch to the phone.
- Same chat + approval-card UX as iOS (brief A); rendered with React equivalents of the SwiftUI components.
Constraints per-surface
- Auth-gated; no public reads.
- Reads from prod
platform.apion black via HTTPS (single API plane — no dev API). - Public anonymous reads (e.g. brand sites) live elsewhere (
cocotte.maisonCocotte umbrella,sansonnet.maison, tour brand sites atadulttherapytour.com/futawaifutour.com, talent sitetransquinnftw.com); these portals are operator-only.
States to design (per surface)
- Idle / empty / loaded / error / offline / forbidden (auth expired).
In-the-wild copy
G3 · agent-actions log filter chip (plain — power-user surface):
specialist: content-onlyfans · last 24h · auto-only · 47 rows
G2 · prospect CRM table empty filter (working):
Nothing in this slice yet. Loosen a filter or check the funnel chart.
G4 · web-companion offline notice (plain):
Lost connection. Re-sync when you're back.
Out of scope
- Marketing pages (separate
cocottetech.comdesign). - Admin / billing (platform-admin surface — different brief).
Open questions
- Single SPA per portal vs one mega-SPA with internal routing?
- Should web companion (G4) maintain UI/UX parity with iOS, or is desktop allowed to diverge in IA (e.g. side-panel with persistent drawer)?
- Cache invalidation in the browser: do we listen on Redis pub/sub via SSE on vps-0, or poll?