Redpoint Engine — Build Plan (9 phases, one at a time)
Each phase ends at an acceptance gate: the operator tests, sets env vars, and explicitly says "go" before the next phase. Claude Code must state, at the end of each phase, exactly (a) what to test and (b) what to configure.
Phase 1 — Foundation (scaffolded — review, install, run)
Tenant-aware schema (0001_init.sql), seed (Wakecut tenant, dummy packages, brief template), Next.js app with Supabase SSR auth, tenant-resolution middleware, login.
Gate: operator can run migration + seed on a fresh Supabase project, sign up as client/editor/admin, and RLS holds — client sees only own-tenant packages, editor sees nothing unassigned, admin sees all. Tenant resolves from host (or ?tenant=wakecut in dev).
Phase 2 — Upload pipeline (highest risk — do early)
Uppy + presigned multipart R2 upload, resumable, browser-direct. files metadata written on completion. Signed-URL download endpoint gated by RLS-equivalent checks.
Gate: multi-GB file uploads on a throttled connection with pause/resume; lands in R2 with correct DB row; participant-only download works; non-participant 403s. Test hard before calling done.
Phase 2b — Remote ingest (insertable any time after Phase 2 — see docs/INGEST-SPEC.md)
Pull footage from cloud services and transfer links server-side into R2: Tier 1 official APIs via self-hosted Uppy Companion (Dropbox, Google Drive, Google Photos, OneDrive, Box, direct URL); Tier 2 feature-flagged link resolvers (WeTransfer, SwissTransfer, iCloud shared albums — unofficial endpoints, degrade gracefully); Tier 3 manual ops-assisted queue for anything else. Migration 0003_ingest.sql (done). Runs on a small always-on ingest service (EU), not Vercel functions.
Gate: per INGEST-SPEC §6 — picker + pasted-link ingests land multi-GB originals with correct rows; bad links fail into queued_manual; SSRF probes rejected; source URLs redacted for clients.
Phase 3 — Catalogue, checkout, billing abstraction
Tenant-branded package page → Stripe Checkout (manual capture) → verified webhook creates NEW job with brief. Implement billing_config dispatch: one_off fully; retainer/credits as entitlement tables + debit path (Stripe subscription wiring can stub until a retainer client exists). Rush surcharge flag. VAT data capture.
Gate: test-mode payment authorizes (not captures) and a NEW job appears with brief data; cancelling voids the authorization.
Phase 4 — Ops console (the operator's most important screen)
All jobs across tenants, filter by tenant/status/SLA; assign editor + internal deadline; QC approve/reject with notes; SLA countdown + breach highlighting; refund/cancel actions. All transitions via transitionJob().
Gate: NEW→ASSIGNED→…→IN_REVIEW→QC pass/fail loop works; every change appears in events.
Phase 5 — Editor workspace
Assigned jobs only; brief view; originals download (Phase 2 reuse); draft upload; mark submitted → IN_REVIEW. Pseudonym display. Concurrent-job cap enforced. Gate: editor completes the loop and can see nothing beyond assigned jobs.
Phase 6 — Client review, approval, delivery, payout
Client review page (preview files); approve → capture + Connect transfer of editor_payout + finals released; request revision → REVISION with per-package cap enforced; over-cap prompts paid-revision or admin.
Gate: full happy path NEW→DELIVERED end-to-end in Stripe test mode, including editor payout transfer and finals only downloadable post-approval.
Phase 6b — Pool pushback: 3-strike demand repricing (insertable once the reconciliation train — PRs #30/#31, supplemental-payment rails — has merged; full scope + operator decisions D1–D6 in docs/design/SCOPE-POOL-PUSHBACK.md)
Reasoned editor passes become a demand signal: at N distinct reasoned passes (default 3, tenant config) on an unclaimed pool job, ops gets an attention card and releases a client prompt with three levers — adjust scope, extend deadline (free), or boost pay (supplemental checkout on the paid-revision rails; boost majority to editor payout; job repools with a boosted badge). v1 is ops-gated, managed-dispatch jobs exempt, strikes reset on any accepted intervention. Three PRs: (1) dismissal reasons + strike detection + ops queue; (2) client intervention + boost payment + repool (money path — falsification runs); (3) marketing-language/config pass (all copy tenant-config, no invented numbers). Entry condition: operator has answered D1–D6 (or confirmed the scope doc's recommendations). Gate: three editors reason-pass → attention state + ops card (plain passes never trigger); ops release → client card renders config-bound (sentinel test); deadline-extend and boost paths both repool with strikes cleared; boost flows checkout → verified webhook → ledger + payout uplift → boosted badge; client never sees dismissal counts/identities; non-participants 404.
Phase 7 — Notifications + SLA machinery
Resend emails on key transitions, per-tenant sender + templates; internal SLA-breach alerts to admin; post-delivery retainer nudge to client. Gate: each transition fires the right branded email exactly once (idempotent on webhook retries).
Phase 8 — Headless surface (tenant API + webhooks + theming)
/api/v1/*: create order/session, job status, upload-URL issuance, approve/revise. Tenant API keys (hashed) + HMAC-signed outbound webhooks with retry. Theme tokens applied across engine-hosted pages. Versioned partner reference: docs/PARTNER-API.md. Proof: a third dummy tenant — "expocut", expo/events vertical, PURE-API (operator direction supersedes the original "propcut/real-estate" example) — seeded with its own brief/packages runs the full order→delivery loop over /api/v1 + webhooks only, untouched by code changes.
Gate: dummy tenant end-to-end via API only; Wakecut unaffected. Evidence: migration 0027_expocut_tenant.sql (+ seed mirror); acceptance e2e tests/e2e/expocut-api.spec.ts (drives NEW→DELIVERED via the API + engine-side editor sim, asserts every expected webhook is delivered/HMAC-verified/redacted, dedupe holds); partner integration reference + runbook in examples/expo-seat/; the "zero code forks on tenant slug" invariant in tests/expocut-src-purity.test.ts.
Phase 9 — Media + compliance automation
ffmpeg preview/watermark worker (decide runtime here); retention cron (delete originals retention_days post-DELIVERED); right-to-erasure admin action (job + R2 + event anonymisation); editor quality counters (qc-pass/revision/on-time) feeding the ops console.
Gate: watermarked previews auto-generate; retention deletes only what it should (dry-run mode first); erasure verified against R2 listing.
Later (explicitly not now)
Curated-pool self-serve onboarding + auto-match (schema ready); platform analytics console across tenants; timestamped review player; show-day rapid dispatch mode (surge-capacity variant of Phase 4); adjacent-vertical tenant launches.
Phases 10+ — detailed plan (seat-business ordered): docs/ROADMAP-PHASE-10-PLUS.md.