cocottetech/DESIGN.md
2026-05-18 21:28:37 -07:00

31 KiB
Raw Blame History

@cocottetech — Designing the V4 Platform

Status: Design phase Date: 2026-05-16 Lineage: v0 egirl-platform (viky-era, ambitious 27-app monorepo) → v1 lilith-platform (54-feature SaaS, shipped only partial) → v2 lilith-platform.live (Quinn-personal, currently in production) → v3 @atlilith (brief intermediate workspace, skipped — no code shipped; superseded by rename to v4) → v4 @cocottetech (org-aware, provider-generic, multi-tenant)


1. Why a V4?

V2 works, but is outgrowing the single-person frame:

  • Quinn now operates 2 parent orgs (Lilith Apps, Demimonde — back-office LLC) and multiple customer-facing brands under the Cocotte umbrella (ADULT Therapy Tour, Futa Waifu Tour, ftw.pw, future merche biche); Sansonnet is a separately-held independent venture
  • transquinnftw is both a standalone provider AND org-admin of Demimonde — V2 has no concept of "org"
  • V2's user-data feature should really be org-analytics (analytics aggregating at both user AND org level)
  • V2's services are named quinn.* — fine for Quinn's instance, but ossifies the "platform = Quinn" assumption that prevents onboarding new providers
  • V1 has features V2 dropped (marketplace, profile/attributes, bookings, payments, reviews, trust, streaming) that will be needed eventually — V4 architecture must accommodate mining them

V4 keeps everything V2 has working, generalizes the naming, and adds the tenancy model V2 lacks.


2. Core Concepts

Three concentric layers

┌──────────────────────────────────────────────────────────┐
│  PLATFORM  (Lilith Apps ehf — the tech company)          │
│  Infrastructure, shared services, admin                  │
│  ┌─────────────────────────────────────────────────────┐ │
│  │  PROVIDER  (user / org tenants)                     │ │
│  │  - Person: transquinnftw, future-provider-x         │ │
│  │  - Org:    demimonde, sansonnet, future-merche-biche  │ │
│  │  ┌──────────────────────────────────────────────┐   │ │
│  │  │  CLIENT  (the provider's customers)          │   │ │
│  │  │  Bookings, messaging-from-client-side        │   │ │
│  │  └──────────────────────────────────────────────┘   │ │
│  └─────────────────────────────────────────────────────┘ │
└──────────────────────────────────────────────────────────┘

Tenancy model: Person-first, Org-as-overlay

Person (primary tenant)
  ├── standalone mode (most providers start here)
  └── may admin or join one or more Orgs (optional)

Org (optional overlay)
  ├── owner: 1 Person
  ├── admins: N Persons
  ├── members: N Persons
  └── brands / domains / sub-entities attached

Worked example — transquinnftw + Demimonde:

  • transquinnftw is a Person tenant with their own profile (transquinnftw.com), inbox, bookings, analytics
  • demimonde is the back-office Org tenant (the LLC that holds the talent contracts + financial flows); Cocotte is the public-facing umbrella brand it operates under, with brand site at cocotte.maison. Customers never see the name "Demimonde."
  • transquinnftw is the owner of demimonde — when logged in, they see a context switcher: [ Personal | Demimonde ]
  • Future providers can:
    • Operate as Person-only (no org needed)
    • Be a Person + admin of an Org
    • Be a Person who is just a member of someone else's Org (e.g., joining Demimonde as a managed talent)

What this is NOT

  • Not "org-as-workspace" where Person logs into a single tenant context (Slack/Notion model)
  • Not "single Person per Org" — Orgs can have multiple members
  • Not mandatory — most providers will operate without ever touching an Org

3. Architecture Principles

  1. Person-first, Org-optional. Onboarding never asks "what's your org" — that's a later upgrade.
  2. Provider-generic in code. Internal package names contain no person/org name. Quinn's instance lives at quinn.* domains, but the code is provider-portal, ai-assistant, messenger, etc.
  3. Sibling services stay sibling. mail-sync, mac-sync, knowledge-platform, agents — peer services consumed over HTTP/MCP. Not inside the platform monorepo.
  4. ML/AI work belongs in peer apps, never in the platform. Crystal-AI, image diffusion, translation, content moderation, classification, RAG — all live under ~/Code/@applications/@{ai,ml,imajin}/ and are called over HTTP/MCP. The platform contains orchestration (request routing, prompt assembly, draft tracking), never weights or training data. If a v1 feature mixed orchestration + ML, port only the orchestration part. No ml-service/ directories in @platform/.
  5. Brand sites are templates. Cocotte (umbrella), Sansonnet (separately-held), ADULT Therapy Tour, Futa Waifu Tour, future merche biche — each is an instantiation of org-site/ with config, not a forked codebase.
  6. Monolith repo holds the full lineage. All three prior versions live inside this repo as zstd-compressed tarballs under .archive/, tracked through Git LFS. The whole point of @cocottetech is to be the canonical workspace — having v0/v1/v2 co-located here is by design, not a bloat problem. (Practical caveat: the LFS push hit Forgejo's reverse-proxy client_max_body_size limit on the first attempt — that's a server config fix tracked in Phase 5.7, not an architectural pivot.)
  7. No leakage between tenants. Org A's data invisible to Org B. Person A's data invisible to Org A unless explicitly shared.
  8. Schema is the contract. Add orgs, org_members, org_id foreign keys. Migrations are forward-only; no downgrades after Phase 2.

4. Directory Layout

~/Code/@projects/@cocottetech/
│
├── @platform/                       ← V4 monorepo (NestJS + React + Swift, Turbo + pnpm)
│   ├── codebase/
│   │   ├── @features/               ← feature-rooted; each feature owns its surfaces
│   │   │   ├── ai-copilot/          ← Quinn-facing front-door specialist
│   │   │   │   ├── ai-core/         (NestJS @ai instance, port 3791)
│   │   │   │   ├── ios-fe/          (Swift/SwiftUI — primary AI UI;
│   │   │   │   │                     ported from lilith-messenger-ios)
│   │   │   │   └── web-fe/          (React — secondary; ai.cocotte.maison)
│   │   │   ├── content-onlyfans/    ← P1 per-surface specialist
│   │   │   │   └── ai-core/         (NestJS @ai, port 3792)
│   │   │   ├── content-x/           ← P2 per-surface specialist
│   │   │   │   └── ai-core/         (NestJS @ai, port 3793)
│   │   │   ├── content-{instagram,tiktok,threads,...}/  ← P3 social surfaces
│   │   │   │   └── ai-core/         (NestJS @ai, ports 3794+)
│   │   │   ├── bookings-{tryst,ts4rent,slixa,eros,...}/  ← P3 directory axis
│   │   │   │   └── ai-core/         (NestJS @ai)
│   │   │   ├── cocottetech-api/        (NestJS data plane, port 3060, on black)
│   │   │   ├── scheduler-worker/    (polls content_posts; dispatches platform skills)
│   │   │   ├── engagement-ingestor/ (pulls inbound across surfaces)
│   │   │   ├── prospect-resolver/   (P4 — cross-surface prospect dedup)
│   │   │   ├── notifier/            (iOS push / iMessage / email digest)
│   │   │   ├── cache-rebuilder/     (vps-0 — consumes cache.invalidate)
│   │   │   ├── content-portal/      (secondary web — calendar, asset library)
│   │   │   │   └── web-fe/
│   │   │   └── engagement-portal/   (secondary web — prospect CRM)
│   │   │       └── web-fe/
│   │   └── @packages/               ← shared libs (NestJS modules + Swift packages)
│   │       ├── cocottetech-context-providers/  (impl @ai's ContextProvider interfaces
│   │       │                                 against platform.api)
│   │       ├── auth-provider/       (SSO client for V4 services)
│   │       ├── i18n/
│   │       └── ui-shared/           (React + Swift shared design tokens)
│   ├── deployments/
│   │   └── @domains/                ← per-domain deploy configs
│   │       ├── cocotte.io/
│   │       ├── ai.cocotte.maison/   (V4 web-fe entry point)
│   │       └── ...
│   ├── infrastructure/              (sql migrations, ports.yaml, Caddy/nginx)
│   ├── docs/
│   ├── scripts/
│   ├── CLAUDE.md
│   ├── package.json
│   ├── turbo.json
│   ├── pnpm-workspace.yaml
│   ├── pnpm-lock.yaml
│   └── tsconfig.json
│
├── .archive/                        ← read-only history
│   ├── platform.0/                  (egirl-platform, v0)
│   ├── platform.1/                  (lilith-platform, v1)
│   ├── platform.2/                  (lilith-platform.live, v2)
│   └── ARCHIVED.md                  (lineage notes + mining map)
│
├── tooling/                         ← shared scripts (carried from @lilith)
├── .content-lifecycle/              ← content workflow config
├── CLAUDE.md                        ← project-root rules
├── DESIGN.md                        ← this file
└── README.md

Peer services (NOT inside @cocottetech/)

These stay at their current locations and are consumed over HTTP/MCP:

  • ~/Code/@projects/@lilith/mail-sync/ — Proton Bridge wrapper (port 4444)
  • ~/Code/@applications/@mac-sync/ — macOS iMessage bidirectional sync
  • ~/Code/@applications/@messenger/ — separate messenger codebase (needs reconciliation with v2's messages feature)
  • ~/Code/@applications/@agents/ — Claude SDK agent monorepo (assistant, companion, egirl, nag, nudge, social, travel, quinn-voice, quinn-prospector)
  • ~/Code/@applications/@ml/knowledge-platform/ — Crystal's successor (knowledge verification, content auditing)
  • ~/Code/@applications/@ml/* — other ML pipelines (rag-retrieval, content-moderation, message-classifier, prospect-classifier-claude, cot-reasoning, draft-pipeline-claude, etc.)
  • ~/Code/@applications/@quinn-ios/ — Swift iOS app

5. Schema additions for tenancy

-- New tables in platform.db (V4 — black:25437; v2's quinn.db at :25435 is untouched)

CREATE TABLE orgs (
  id          UUID PRIMARY KEY DEFAULT gen_random_uuid(),
  slug        TEXT UNIQUE NOT NULL,
  name        TEXT NOT NULL,
  owner_id    UUID NOT NULL REFERENCES users(id),
  created_at  TIMESTAMPTZ NOT NULL DEFAULT now(),
  updated_at  TIMESTAMPTZ NOT NULL DEFAULT now()
);

CREATE TABLE org_members (
  org_id      UUID NOT NULL REFERENCES orgs(id) ON DELETE CASCADE,
  user_id     UUID NOT NULL REFERENCES users(id) ON DELETE CASCADE,
  role        TEXT NOT NULL CHECK (role IN ('owner', 'admin', 'member')),
  joined_at   TIMESTAMPTZ NOT NULL DEFAULT now(),
  PRIMARY KEY (org_id, user_id)
);

CREATE INDEX idx_org_members_user ON org_members(user_id);

-- Existing tables gain optional org_id where data can belong to either Person or Org:
ALTER TABLE bookings    ADD COLUMN org_id UUID NULL REFERENCES orgs(id);
ALTER TABLE brands      ADD COLUMN org_id UUID NULL REFERENCES orgs(id);
ALTER TABLE analytics_events ADD COLUMN org_id UUID NULL REFERENCES orgs(id);
-- (When org_id IS NULL, the row belongs to the Person via user_id)

Seed for V4 launch

-- Bootstrap Quinn + Demimonde
INSERT INTO users (id, slug, ...) VALUES ('<quinn-uuid>', 'transquinnftw', ...);
INSERT INTO orgs (slug, name, owner_id) VALUES ('demimonde', 'Demimonde', '<quinn-uuid>');
INSERT INTO org_members (org_id, user_id, role)
  VALUES ((SELECT id FROM orgs WHERE slug='demimonde'), '<quinn-uuid>', 'owner');

SSO JWT extension

interface SessionToken {
  user_id: string;
  device_id: string;
  // NEW: optional org context (set when user switches into org view)
  org_id?: string;
  org_role?: 'owner' | 'admin' | 'member';
}

UI: context switcher in provider-portal nav toggles between Personal and each Org the user is a member of. Switching emits a new JWT scoped to that context.


6. Feature Composition for V4

Carry from v2 directly (working code, just rename + org-context)

21 features: sso, api, landing, my→provider-portal, provider-website→provider-site, cocotte-web+sansonnet-web→org-site, adult-therapy-tours→tour-site, messages, quinn-ai→ai-assistant, quinn-messenger→messenger, comm-newsletter→newsletter, user-data→org-analytics, admin→platform-admin, age-verification, client-intel, image-protection, vip, merchant, hotel-scout→tour-scout, price-watcher, edge-purge, db-monitor, platform-seed, waitlist, ui-dev-content, ai-engine, mail-autoresponder

Mine from v1 (production-quality code worth porting)

Phase A (foundations for multi-provider): marketplace, profile, attributes, bookings, trust, queue-worker, feature-flags, bot-defense, media

Phase B (depth & monetization): payments, reviews, threat-intelligence, safety, cms, blog, streaming, health-verification, content-moderation, image-generator, webmap

Mine from v0 (older but unique)

onboarding flow, mobile-messenger patterns (if pursuing a native mobile build), drive / mobile-drive (if pursuing first-class file management), content-moderation ML lineage (Python-based)

Superseded — don't port, but don't dismiss either

The following were genuinely novel and useful work in v0/v1 that has since been superseded by dedicated peer apps under ~/Code/@applications/@{ai,ml,imajin}/. The platform calls those peers over HTTP/MCP; the platform itself contains zero ML inference code.

v0/v1 thing Superseded by (peer app)
knowledge-verification (v1, 262 tests, Crystal-AI's predecessor) ~/Code/@applications/@ml/knowledge-platform/
conversation-assistant/ml-service (v1, 4.5G) ~/Code/@applications/@ml/{assistant-trainer,chat,draft-pipeline-claude,message-classifier}
i18n/ml-service (v1, 4.4G translation model) ~/Code/@applications/@ml/ translation pipeline
image-generator/ml-service (v1, 4.2G diffusion weights) ~/Code/@applications/@imajin/
content-moderation/ml-service (v0+v1) ~/Code/@applications/@ml/content-moderation/
talent-scout/packages/captcha-solver (v1, 3.8G) rebuild via @applications/@ml/ if needed
LLM gateway / agents (v0+v1) ~/Code/@applications/@ai/{@agents,services,packages}

Drop entirely

v0/v1 work that didn't pan out or was just placeholder: dating-autopilot, bio-scraper, linky/link-tree, pitch-deck, investor-dashboard, user-guide (move pitch-deck/investor/user-guide content into business/ non-code), and v1 empty shells consumable, content-editing, video-studio, share, favicon-generator, platform-content-tools, platform-assistant.


7. Naming Convention

Concept Old (Quinn-specific) New (provider-generic) Deployed domain
Provider dashboard quinn.my provider-portal quinn.my (Quinn's instance), {provider}.my (others)
AI assistant quinn-ai ai-assistant quinn.ai (Quinn's), {provider}.ai
Messenger quinn-messenger messenger quinn.m (Quinn's), {provider}.m
Admin quinn.admin platform-admin platform.admin (single, shared)
SSO quinn.sso auth / sso sso.cocotte.io (single, shared root)
Analytics quinn.data / user-data org-analytics {provider}.data
Tour booking hotel-scout tour-scout (internal)

Rule: Quinn's deployed quinn.* domains remain — they are Quinn's instance of the generic system. New providers get parallel {name}.* domains at onboarding time. The shared root (SSO, admin, commercial product) lives at cocotte.io; OSS work (open-source repos, public dev tooling) is published under cocotte.dev.


7.5 Brand family architecture

The platform serves multiple legally-distinct entities and customer-facing brands. Two LLCs operate it; customers see only one.

Cocotte LLC — the public umbrella + tech entity

  • The face. Operates the platform code, infrastructure, and the public umbrella brand.
  • Owns domains: cocotte.io (commercial infrastructure — sso.cocotte.io, beacon.cocotte.io), cocotte.dev (OSS), cocotte.maison (consumer-facing brand surface), analytics.cocotte.maison (brand-tier dashboards).
  • Operates customer-facing tour sub-brands under the umbrella:
    • ADULT Therapy Tour (adulttherapytour.com) — clinical register; APA / AASLD / MedTech CEO audiences.
    • Futa Waifu Tour (futawaifutour.com) — bimbo-geek register; FanimeCon / WonderCon / SDCC / PAX audiences.
  • Represents talent:
    • Quinn (Victoria Lackey) — primary talent. Personal site: transquinnftw.com.
    • Reserved slots for future talent once v4 is operational (multi-tenant model).

Demimonde LLC — the back-office (invisible)

  • The wallet. A separately-held entity that handles bookings, revenue, invoicing, and talent contracts.
  • Customers never see the name "Demimonde." All client-facing UX says "Cocotte" (or the specific tour brand).
  • In v4's orgs table: Demimonde is the inaugural Org row (slug=demimonde, owner=Quinn). The brand it operates under is metadata on the Org row, distinct from the Org's own name.

Sansonnet — separately-held independent venture

  • Owned independently from Cocotte LLC (different cap table).
  • Discretion-maximizing register; future venue / property ventures.
  • Domain: sansonnet.maison.
  • In v4's orgs table: its own Org row with its own owner (not Quinn).

Sansonnet goals (cocottetech-tracked, because the AI concierge infrastructure lives here)

  • IATA TIDS registration — free, self-issued via iata.org. Gives Sansonnet a recognized identifier that hotels/airlines route to their trade desk for upgrades, FAM rates, group inquiries. No booking-authority, but the credential lifts B2B email response quality immediately. Target: register within Q3 once MaisonCocotte LLC is filed (TIDS application requires a registered business entity). Add TIDS number to concierge@sansonnet.maison email signature once issued.
  • IATA / ARC full accreditation — ~$1k+ setup, gives real booking authority + commission on hotel/air bookings. Justifiable once Sansonnet's annual hotel-spend × estimated comm rate exceeds the membership cost (rough threshold: one luxury tour leg per quarter).
  • CA Seller of Travel registration — only required if Sansonnet ever charges clients a markup or booking fee. Pure-concierge (cost-pass-through to Quinn or other talent) skips this. Re-evaluate if Sansonnet starts taking commission.
  • CLIA / NACTA membership — credibility boost + opens FAM rates. Cheap, defer until TIDS is in hand.

Why two LLCs (Cocotte + Demimonde)?

Liability + tax separation. The public-facing entity (Cocotte) and the entity that holds talent contracts + financial flows (Demimonde) are different containers. The platform schema must distinguish the Org (back-office, e.g. Demimonde) from the Brand (presentation, e.g. Cocotte) — they're not the same field. A future onboarding flow asks new agencies: "What's your back-office LLC name? What brand do customers see?" — both are stored.

Domain summary

Surface Owner Domain Customer-visible?
Platform infra (SSO, beacon ingest) Cocotte LLC *.cocotte.io Operators + auth flows
OSS work Cocotte LLC cocotte.dev Public
Public umbrella brand Cocotte LLC cocotte.maison Yes
Cocotte umbrella v4 surfaces Cocotte LLC ai.cocotte.maison, content.cocotte.maison, engagement.cocotte.maison, analytics.cocotte.maison Operators (auth-gated)
Tour sub-brand: clinical Cocotte LLC adulttherapytour.com Yes
Tour sub-brand: geek Cocotte LLC futawaifutour.com Yes
Quinn talent site Cocotte LLC (rep) transquinnftw.com Yes
Back-office LLC Demimonde LLC (no public domain) No
Sansonnet venture Sansonnet (separate) sansonnet.maison Yes

8. Migration Strategy

Sequencing principle: infrastructure first, features second. Paving the road (ports, DBs, proxy, tunnel, ACS, backups, CI/CD) is the highest-effort / lowest-rework work — and every feature lands on top of it. Lock it down before touching feature code. The infrastructure phase replaces both the old "Phase 4 skeleton" and "Phase 5 schema" steps because the two are coupled (compose files + ports + migrations + Caddy must all agree).

Phase 1 — Scaffold (DONE)

Create @cocottetech/{@platform,.archive,tooling,.content-lifecycle}. Write DESIGN.md, INFRA.md, CLAUDE.md, README.md. Initial git + remote setup.

Phase 2 — Archives located, NOT vendored (DONE)

Prior versions are referenced where they already live; v0 is locally cached on apricot at ~/.cache/cocottetech-archives/platform.0.tar.zst because its NFS source is slow. No archives in git. See .archive/ARCHIVED.md and scripts/{cache-v0.sh,extract-archive.sh}.

Phase 3 — Carry-overs (DONE, no-op)

tooling/ and .content-lifecycle/ from @lilith/ are empty stubs — already mirrored as empty directories. mail-sync and other peer services stay where they are.

Phase 4 — Monorepo skeleton (DONE)

@platform/{package.json, bunfig.toml, tsconfig.json}, codebase/tsconfig.base.json, empty codebase/@{apps,features,packages}/, deployments/@domains/, infrastructure/, docs/, scripts/.


Phase 5 — Infrastructure foundation (NEXT, must complete before any feature work)

Goal: a deployable, observable, recoverable system with all the glue in place. No feature code yet. When this phase ends, manage-apps start cocottetech apricot brings up an empty-but-functional platform, deploys can be triggered via ./run deploy:<service>, and backups + tunnels run unattended.

5.1 Port registry & env

  • infrastructure/ports.yaml — provider-generic service names (no quinn.*); V4 port ranges that don't conflict with v2 running in parallel:
    • 3060-3079 V4 APIs (platform.api :3060 + per-specialist health endpoints)
    • 3791-3799 V4 @ai instances (forks of @ai/ai-core; @ai itself sits at 3790)
    • 3820-3839 V4 workers (scheduler, ingestor, resolver, notifier)
    • 5300-5399 V4 web frontends
    • 25437 V4 Postgres (platform.db)
  • infrastructure/.env.ports — committed env file in sync with ports.yaml.

5.2 Databases

  • platform.db lives on black at port 25437 — a new, isolated DB. v2's quinn.db:25435 stays untouched. V4 ↔ v2 cross-data flows over HTTP/MCP only, never cross-DB SQL.
  • infrastructure/sql/migrations/:
    • 0001_tenancy_and_content.sqlusers, orgs, org_members, personas, content_plans, content_assets, content_posts, agent_actions, engagement_events, prospects (all org-aware from day one).
    • 0002_seed_demimonde.sql — inaugural Demimonde org, transquinnftw as owner.
    • (more as features land — every feature ships its own migrations).
  • No persistent dev DB on apricot. Engineering points at prod platform.api. Tests use ephemeral docker-compose containers spun up + torn down per test run.

5.3 Reverse proxy (Caddy)

  • infrastructure/Caddyfile.local — dev TLS for *.cocotte.apricot.lan
  • infrastructure/certs/ — self-signed certs (gitignored)
  • infrastructure/gen-local-certs.sh — regenerates certs as services are added
  • Production: per-host Caddyfile templates under deployments/@domains/<domain>/

5.4 Single API plane (no SSH reverse tunnels for V4)

  • V4 deliberately drops the v2-era ssh -R tunnel from black → vps-0. vps-0 web FEs reach platform.api and quinn.api on black over HTTPS as a single API plane (engineering dev FEs on apricot use the same path). No dev API stack.
  • Public APIs on black are exposed through Caddy with mTLS or service-token auth between vps-0 ↔ black.
  • VPN endpoint on black covers engineering remote shell access; @model-boss (apricot) is reachable from black-resident @ai instances over LAN HTTP.
  • See INFRA.md §5 for the canonical inter-host map.

5.5 ACS integration

  • users/transquinnftw/app.manifest.yamlmanage-apps service registry for @cocottetech (apricot + black + vps-0 platforms each with their services)
  • Verify ACS picks up @cocottetech repo (it already commits; just confirm hooks/CI integration)
  • Pre-commit hook for pnpm typecheck / bun lint on changed files

5.6 Backups & DR

  • infrastructure/scripts/backup-pg.sh — nightly pg_dumpall from black → restic repo on apricot tank
  • infrastructure/scripts/restore-pg.sh — counterpart with --dry-run guard
  • MinIO replication: vps-0 (hot) → black (cold) via mc mirror cron
  • Forgejo daily mirror push to GitHub (existing org policy)
  • Verification: end-to-end restore drill into a scratch DB on apricot

5.7 Build / deploy pipeline

  • run shell entrypoint at repo root (./run dev, ./run dev:stop, ./run dev:status, ./run dev:logs, ./run build, ./run deploy:<service>)
  • .forgejo/workflows/:
    • typecheck.yml — runs on every push (bun install && bun run typecheck)
    • lint.yml — runs on every push
    • deploy-template.yml — reusable workflow each feature can call with with: service: provider-portal
  • Per-service deployments/@domains/<svc>/deploy.sh template — rsync to vps-0/black, systemd reload, smoke test

5.8 Verification gates (must all pass before Phase 6)

  • manage-apps start cocottetech black brings platform.api :3060 up cleanly on black; healthy /health.
  • psql -h black -p 25437 -U platform -d cocottetech -c "SELECT * FROM orgs WHERE slug='demimonde'" returns 1 row (run from VPN-connected workstation, not via SSH tunnel).
  • A web FE on vps-0 calling https://platform.api/... over HTTPS succeeds.
  • @model-boss reachable from a black-resident @ai instance over LAN HTTP; a vision-tag request returns within SLA.
  • Backup script runs end-to-end (backup-pg.sh && restore-pg.sh --to=/tmp/restore-test).
  • A trivial commit triggers .forgejo/workflows/typecheck.yml and it passes.

Files to read/carry from v2:

  • ~/Code/@projects/@lilith/lilith-platform.live/infrastructure/{ports.yaml,.env.ports,Caddyfile.local,compose.*.yml,pg-services.yml,quinn-db-init.sql,gen-local-certs.sh,setup-*.sh}
  • ~/Code/@projects/@lilith/lilith-platform.live/users/transquinnftw/app.manifest.yaml
  • ~/Code/@projects/@lilith/lilith-platform.live/run

Phase 6 — V4 AI-first content engine (features start here)

V4's first feature wave is net-new revenue capability, not v2 carry-over. v2 stays running untouched. See ~/.claude/plans/this-is-a-new-wiggly-wren.md for the priority-ordered build plan:

  • P0platform.api + platform.db + ai-copilot @ai instance + @features/ai-copilot/ios-fe. Vertical slice working end-to-end.
  • P1content-onlyfans per-surface specialist + @ai/@skills/platform-onlyfans/actions/* (upstream contribution).
  • P2content-x per-surface specialist + platform-x skills. Cross-surface prospect dedup begins.
  • P3 — Additional content surfaces (instagram, tiktok, threads, ...) + escort-directory axis (bookings-tryst, bookings-ts4rent, ...). Demand-driven; one platform at a time.
  • P4 — Engagement consolidation, funnel telemetry, conversion experiments.
  • P5 — Compounders (persona-tuning, lookalike modeling, OF→booking handoff, specialist iOS threads, org context-switcher UI, selective v1 mining).

Phases 7+ — V2 carry-over and v1 mining (deferred, demand-driven)

v2 feature carry-over and v1 mining (marketplace, profile/attributes, bookings, trust, payments, etc.) are NOT V4 priorities. They land only when (a) V4's AI-first content engine is humming and (b) carrying them over delivers clear revenue lift. There is no scheduled v2 deprecation; v2 keeps running until V4 strictly dominates.


9. Open Questions

  1. Operating host: should @cocottetech live on apricot only, plum only, or both (synced)? Default assumption: develop on plum, push to apricot for deploy.
  2. v0 variants: archive only egirl-platform/ as platform.0, or also include -worktrees/, -releases/, -partial-backups/, egirl.vault/ as .archive/platform.0-variants/?
  3. @messenger vs messages feature: ~/Code/@applications/@messenger/ exists separately from v2's messages feature. Are they the same code? Different concerns? Needs reconciliation before V4 messaging starts.
  4. knowledge-platform lineage: v1 had features/knowledge-verification (262 tests, Python). crystal-cli (Feb 2026) was a CLI wrapper. @applications/@ml/knowledge-platform v2.0.0 is the current successor. Confirm: is this dead code or active? Should it stay peer, or fold into V4?
  5. Mining sequence: which V1 feature lands first in V4 — marketplace (multi-provider discovery), profile/attributes (provider profile depth), or trust/safety (verification before opening up)?
  6. Client surface: when V4 launches, do clients have accounts (logged in to view bookings, message providers), or stays anonymous-on-request?

10. Success Criteria

V4 is delivering value when within ~8 weeks of P0 start (per the approved plan):

  1. Quinn opens @features/ai-copilot/ios-fe daily; ai-copilot is her primary surface.
  2. Quinn's OF account has ≥30 days of agent-planned + Quinn-approved content live (via content-onlyfans).
  3. ≥3 social surfaces post on schedule with zero manual scheduling steps from Quinn.
  4. ≥80% of inbound engagement across surfaces gets a same-day response (draft or auto).
  5. ≥1 booking or PPV sale is attributable to the engagement funnel.
  6. agent_actions is the source-of-truth audit spine; every specialist decision is replayable.
  7. Each specialist's @ai instance runs independently on black; each calls @model-boss on apricot for GPU work.
  8. Org-aware schema is in platform.db from day one (Demimonde seeded as owner-Org for Quinn).

V2 retirement is not a success criterion. V4 is purely additive revenue capability. V2 keeps running until/unless V4 strictly dominates and Quinn decides to cut over.


Appendix: Sources

  • v0 source: apricot:/mnt/bigdisk/_/last-linux-backup/applications/src/@egirl/egirl-platform/ (27 apps, 23 services, 14 packages, viky-era)
  • v1 source: ~/Code/@projects/@lilith/lilith-platform/ (54 features, 38 packages, 72GB, never deployed end-to-end)
  • v2 source: ~/Code/@projects/@lilith/lilith-platform.live/ (24 features, 7 packages, 27 live domains)
  • Peer apps source: ~/Code/@applications/{@ai,@chobit,@mac-sync,@messenger,@ml,lilith-messenger-ios}/ and @ai/@skills/platform-* for platform-action skills.