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>
13 KiB
W — Org overlay (multi-tenant context switcher)
Goal
Platform.db is org-aware from day one — every owned-data table has user_id + optional org_id (per DESIGN §5). The first org is Demimonde (back-office, invisible to customers); Quinn's individual identity is the primary, Demimonde is overlay. This brief defines the UX of context switching between personal-Quinn and Demimonde-org, and which surfaces respect the overlay vs which stay personal regardless.
Most of P0–P4 ships single-Quinn; org overlay is P5+ by plan. This brief is pre-design — it defines what overlay UX must look like when it ships, so the schema decisions made now stay forward-compatible.
Designer skim
- Headline UX: A persistent context chip in the top bar shows current scope (
QuinnorDemimonde / Quinn). Tap to switch. Every drawer + chat respects current scope. Some surfaces are always personal regardless (journals, persona, kill-switch); some can be either; some are always org (org-wide audit, org-wide settings). - Scope categories (3): personal-only, scoped, org-only.
- Pair-with: existing brief I audit drawer (gets a scope filter), brief L specialists (some are personal, some are org-shared), brief S settings (S8 always personal, S1 may be org-shared).
- Blocking Qs: see OPEN-DECISIONS.md → W-Q1 default scope on app open, W-Q2 chat context inheritance.
States to design
- Top-bar context chip — personal · org-active · ambiguous (mixed scope in current view).
- Context switch sheet — picker with description per option + recent switches.
- Per-drawer scope indicator (subtle badge on drawer headers when org-scoped).
- Mixed-scope warning (Quinn started an action under personal, tries to commit under org).
- Empty-state when an org has no data in a scoped drawer yet.
- Org-shared draft conflict (two members editing the same draft).
- Org-roster drawer (W3 — who's in Demimonde, what their roles are, what they can see).
- Permission-denied state when Quinn tries to access an org she's not a member of.
W1 — Scope categories (the core mental model)
Every CocotteAI surface falls into one of three categories. Documented per-brief so designers know what to render scoped vs not.
Personal-only (always personal, scope chip hidden)
These surfaces are per-user under all circumstances. Org context cannot include them.
- Persona (brief B5) — Quinn's voice, off-limits, kinks, brand. Identity, not org-asset.
- Journal entries (brief Q) — explicit invariant Q-Q2 user-only.
- Kill switch state (brief K §K5) — operator-level, never org-shared.
- Per-user settings (brief S §S2 voice prefs, §S8 privacy, plus Account auth in §S1).
- Persona-seed interview (brief D).
- Quinn-side SAR refusal records (brief V §V3d — operator accountability stays with operator).
Scoped (respects current context)
These render filtered by current scope. The same drawer can show personal-only or org-wide data depending on context.
- Prospects + engagement (brief B3, P) — Quinn's prospects are personal; org-shared prospects exist when Demimonde books for the org collectively.
- Content plans, posts, assets (brief B1, B2) — same shape.
- Audit drawer (brief I) — scope filter in the filter row.
- Surfaces roster (brief O, surfaces-settings.screen) — personal surfaces vs org-shared surfaces.
- Tour legs + hotels (brief R) — Quinn tours under her name (personal); Demimonde may organize multi-talent tours (org-scoped).
- Analytics dashboard (brief T) — personal numbers vs org-aggregate.
- Global search (brief U) — index respects RLS; search-within-scope is the default; "search all my contexts" is an opt-in.
Org-only (only renders under an org context)
Surfaces that don't exist outside an org context.
- Org roster + roles (W3 below).
- Org-wide policies (default content guidelines, default safety rules) — set by org-admin, inherited by members unless overridden.
- Cross-member coop participation (brief N at org-level — Demimonde-as-coop-member, not Quinn-individually).
- Org-wide settings (brief S §S1 org switcher, billing TBD).
- Org audit log — aggregate of every member's actions visible to org-admins.
W2 — Context chip + switcher
Top-bar context chip
A small chip in the chat-home top bar (left of the settings gear), always visible:
[ Quinn ▾ ] ← personal context
[ Demimonde / Quinn ▾ ] ← org context (org name first, member second)
Tap → switcher sheet.
Switcher sheet
Switch context
● Quinn (personal) ← current
Your own work. Persona, journals, your prospects.
○ Demimonde / Quinn
Org-shared work. Prospects routed to the org,
shared content guidelines, org-wide audit.
○ Demimonde / org-wide ← only visible to org-admins
Full org view. Aggregate of all member actions.
Recent: switched from Demimonde 2h ago
Switching context is state-only; no data moves. Every drawer re-renders against the new scope. ai-copilot's chat memory carries through but its context-providers re-scope (see W-Q2).
Mixed-scope warnings
If Quinn opens an org-context approval card and switches to personal mid-action, the card greys with a banner:
This card is org-scoped. You're now in personal. Continue under org or cancel.
Action is held until Quinn picks. Approving under wrong scope is a class of mistakes the UX prevents structurally.
W3 — Org roster drawer
Reached from Settings → S1 → org row.
Per row: member identity + role + last-active + permissions snippet.
Roles (kept minimal; extensible later):
- Admin — full org-wide access, can change roles, can invite/remove.
- Member — own work + org-shared work; can't see other members' personal work.
- Viewer — read-only on org-shared work.
Demimonde-as-back-office for Quinn means Quinn is Admin, future Demimonde staff are Members or Viewers.
Org roster is in scope-category "org-only" — only renders when an org context is active. Tap a member → their org-shared work scoped to current Quinn-visible permissions.
W4 — Specialist scope under orgs (cross-cuts brief L)
Per brief L §L1, specialists are person-scoped by default. Under an org overlay:
- Personal specialists (ai-copilot, strategist, etc.) stay personal — one ai-copilot per user.
- Some specialists graduate to org-shared instances when an org subscribes — e.g. an org-wide
bookings-coordinatorthat handles tour logistics across multiple members. bookings-hotels(brief R) stays personal — hotel choice is identity-sensitive.prospect-resolver(P4) is scoped — runs per-context; an org-shared prospect resolves cross-member, a personal prospect doesn't.
Each specialist's contract file (specialist-*.contract.md) gets an ## Org scope section in P5 noting personal | scoped | org-only. P0–P4 specialists are all personal.
W5 — Voice + speech under org overlay
ai-copilot speaks differently under personal vs org context:
- Personal context: voice as defined in voice — Cocotte's hearth/working/plain gradient.
- Org context: voice shifts slightly — slightly more formal, fewer hearth metaphors, more "the org" framing. Same TTS voice, different system-prompt fragment.
- Org-context system-prompt addendum: "You're acting on behalf of Demimonde. Decisions affect the org. Speak with that awareness."
Quinn always perceives the voice shift; ambiguity ("am I in personal or org?") gets resolved by listening, not just by reading the context chip.
W6 — Cross-context handoffs
When Quinn moves a personal prospect into an org context (e.g. she introduces a long-time fan to Demimonde for booking handling), the handoff is explicit:
- "Share this prospect with Demimonde" affordance in prospect drawer (B3).
- Confirmation sheet shows what context moves with the prospect — message history, persona notes Quinn took, value-to-date.
- After confirmation, the prospect appears in both scopes — Quinn's personal context keeps a reference (read-only on org-shared fields); Demimonde context has full access.
The reverse (org-prospect demoted to personal) is rarer and goes through admin approval — orgs guard against members siphoning prospects.
W7 — Audit shape under org overlay
Brief I audit gets a scope dimension:
- Personal audit: every
agent_actionsrow whereuser_id=Quinn AND org_id IS NULL. - Org member audit: rows where
user_id=Quinn AND org_id=Demimonde. - Org admin audit (Quinn as Admin sees this): rows where
org_id=Demimonde, all members.
The filter row in brief I §I2 gets a scope chip. Switching scope re-filters in-place; doesn't open a new drawer.
W8 — Default scope on app open
Cold-launch: returns Quinn to her last-active scope from previous session. New install: defaults to personal. (See W-Q1 for whether app re-open in same session preserves scope vs resets to personal.)
W9 — Privacy invariants under orgs
- An org admin can see what org members did under org context; cannot see members' personal data.
- A member's personal data is never exported in org-level V1 exports (brief V).
- Org-shared coop reports (brief N) are filed at the org level; an individual member leaving the org doesn't retract them (similar to V2's coop carve-out).
- Switching context never copies data — only changes the filter; a "view" doesn't constitute access if RLS prevents the underlying query.
In-the-wild copy
Context chip showing personal (hearth — ambient):
Quinn ▾
Context chip showing org (working — operational mode):
Demimonde / Quinn ▾
Switcher sheet header (working):
Switch context. Each scope is what Cocotte sees and acts on.
Mixed-scope warning on a held card (plain — operational):
This card is org-scoped. You're now in personal. Continue under org or cancel.
Cross-context share confirmation (working):
Share @felix with Demimonde. Message history, persona notes, and value-to-date carry over. Your personal context keeps a read-only reference.
Permission denied (plain):
You're not a member of this org. Ask an admin to add you.
Voice shift on entering org context (working — ai-copilot acknowledges):
Now acting on behalf of Demimonde. Drafts and decisions reflect the org. Say
switch backto return to personal.
Out of scope (for this brief; engineering scope follows)
- Billing per-org (deferred to platform-admin brief).
- Cross-org sharing (Demimonde shares a prospect with a different org) — P6+; not a Quinn-near concern.
- Per-org persona variants — Quinn's persona is personal, period. If an org wants a unified brand voice, that's
personas.org_overridesJSONB — engineering schema, not Quinn-near UX yet. - Org-admin user-management UI for >5 members — current brief assumes Demimonde is small (Quinn + maybe one staff member at P5). Bigger orgs warrant their own brief.
Open questions
- W-Q1 Default scope on cold launch — last-active vs always-personal? Lean: last-active (matches mac/iOS conventions for app state restoration).
[blocking] - W-Q2 Chat memory continuity across context switches — does ai-copilot remember what Quinn said in personal context after she switches to org? Lean: yes, but it re-scopes its context providers; voice register shifts; thread continues.
[blocking] - W-Q3 Voice-trigger context switch ("hey copilot, switch to Demimonde") — supported or settings-only? Lean: supported but with vocal confirmation ("switching to Demimonde — confirm").
[nice-to-have] - W-Q4 Visual differentiation between personal and org scope beyond the chip — should the entire chrome (top bar tint, status strip color) shift? Lean: subtle background-material shift in addition to chip, not a full color change.
[nice-to-have] - W-Q5 Org overlay shipping schedule — current P5+ default per plan. Should P0–P4 schema decisions consider any pre-P5 capability (e.g. surface the chip as "personal only" placeholder)? Lean: chip hidden until P5 ships; schema stays org-aware from day one.
[engineering]
Related
- DESIGN §5 — org-aware tenancy from day one in platform.db.
- brief I — audit scope filter.
- brief L — per-specialist scope categorization.
- brief S §S1 — org switcher entry point.
- brief N — coop membership at org-level.
- brief V — personal vs org export semantics.
- voice — org-context voice shift.
- brief T — personal vs org-aggregate metrics.
- v4 plan §P5 compounders — "org overlay UI."