UAT — client workflow (Phase 6–10 acceptance)
Test account: dorian@redpoint-vision.com (client, Wakecut, magic-link —
no password). Site: https://wakecut.com
Stripe test card: 4242 4242 4242 4242, any future expiry, any CVC.
Role handoffs: steps marked ⚙️ need the editor/ops walkthrough running in
parallel (another browser profile or private window).
The one promise this whole flow must keep: your card is authorized at booking but only charged when you approve — and finals stay locked until then.
🧱 Phase-10 migration prerequisite. The new sections below (voice notes §2b, specify-editor add-on §1b, rate-your-edit §4b) depend on migrations
0034–0039. The shared dev/prod DB was last verified at0033, so until the operator applies these each surface probe-and-skips (stays dark) — that is by design, not a bug. Confirm the live level first (CLAUDE.md rule 8: probe the object over REST with the service-role key, don't trust docs). If a section's surface never appears, check the migration is applied before logging a fail.
📧 Email prerequisite (Phase 7). Steps marked 📧 verify the transactional emails that now fire on each transition. They only send once the operator has set
RESEND_API_KEY(rotate the two keys that transited chat during SMTP setup FIRST) in the Vercel prod env; migration0020_notificationsis already applied live. Sender ishello@wakecut.com(verified domain). If the key isn't set yet, the flow still passes — the email just doesn't send and afailed/absentnotificationsrow is expected; skip the 📧 cells and note it.dorian@redpoint-vision.comis a real inbox, so client emails are directly checkable here.
1 · Landing & order
| # | Do | Expect |
|---|---|---|
| 1.1 | Open / logged out (phone width too) |
Marketing home: hero, 3 steps, real package cards with prices, trust strip, FAQ opens on tap. No yacht clichés, no lorem ipsum |
| 1.1a | In the FAQ, open "What if no editor picks up my job?" | New Phase-6b entry: honest framing — editors choose their work; a job that needs a tweak gets more time / lighter brief / better pay and you hold the levers. NEVER "rejected"/"failed"; no invented numbers |
| 1.2 | "Start an order" → login with dorian@redpoint-vision.com |
Magic-link email arrives; link returns you to the site logged in |
| 1.3 | Revisit / while logged in |
Hero CTA becomes "My jobs" + welcome-back line |
| 1.4 | /order: pick a package, fill the brief, continue to payment |
Stripe Checkout opens; the hold is explained BEFORE you pay ("authorized now, charged only when you approve") |
| 1.5 | Pay with the test card | Success page → job visible at /jobs as "Order received" |
| 1.5📧 | Check dorian@…'s inbox |
Receipt email "Wakecut — order received (…)" from hello@wakecut.com. Line items match the order; total only, NO VAT line (Wakecut is unregistered — billing_config.vat unset). Editor never named |
| 1.6 | In Stripe dashboard (test mode): find the payment | Status "Uncaptured" — authorized, NOT charged |
1b · Specify your editor — paid add-on (0038)
Precondition (operator setup): the client must have a prior
APPROVED/DELIVERED job with an editor — run the §1–§4 spine once first, or use
an existing delivered job for dorian@…. Needs migration 0038 live and
the tenant's package_extras row key='specify_editor' priced in GBP (live on
wakecut at £10 — the repo seed carries only a dummy price, so read the live
figure; never assert an invented number). The add-on offers the same
pool-hold continuity as set_preferred_editor but as a paid, refund-on-miss
upsell. Copy + price are tenant config (rule 5).
| # | Do | Expect |
|---|---|---|
| 1b.1 | As dorian@… (who has a prior delivered edit), start a fresh /order in GBP |
The add-on "Work with your previous editor again" appears with the live price (£10 on wakecut) and a pseudonym picker of the editors who delivered for you before. Under it: "If they can't take this one, this add-on is refunded automatically." Only pseudonyms — never a real editor name |
| 1b.2 | As a first-order client (no delivered job yet — a fresh account, or before your first delivery) | The add-on is ABSENT — hidden entirely for anyone with no prior delivered editor |
| 1b.3 | Switch the order currency to EUR (if the tenant offers it) | The add-on is ABSENT for EUR buyers unless the tenant set a EUR price — wakecut's specify_editor has no EUR price, so it is hidden and never charged |
| 1b.4 | Pick your previous editor's pseudonym and pay | Order placed; the job holds for that editor on the claim board for the hold window (tenant billing_config.specify_editor_hold_hours, code default 48h). The editor still has to claim — it is never auto-assigned |
| 1b.5 | ⚙️ If the requested editor claims within the window | The add-on is honoured; nothing is refunded. Job proceeds normally |
| 1b.6 | ⚙️ If the requested editor does NOT claim before the window ends (a "miss"), and the base payment has been captured, the specify-editor cron sweeps | The job opens to the wider pool automatically; the extra (only) auto-refunds to your original card — the base charge, editor payout and job status are untouched |
| 1b.6📧 | Check dorian@…'s inbox after a miss-refund |
Email "Wakecut — add-on refunded (…)" — "…we've refunded that add-on — £X goes back to your original payment method" + "Your project continues as normal with our wider editor team; everything else about your order is unchanged." CTA "View your project". No editor named |
Manual-capture timing. The extra can only be refunded once the base payment is captured (that happens at approval, §4). A miss on a job that is still pre-approval / uncaptured stays
pending(reported as deferred by the sweep) and refunds on the first sweep after capture — design the UAT timing around that, don't expect an instant refund on an unapproved order.
2 · Footage
| # | Do | Expect |
|---|---|---|
| 2.1 | Open the job → upload page | Drag-drop is the obvious primary path |
| 2.2 | Upload a real video file (any mp4) | Progress, resumable, lands in the file list |
| 2.3 | (Optional) paste a WeTransfer/URL link instead | Import chip shows progress → done |
2b · Voice notes for your editor (0034)
Precondition: migration 0034 live; the job in an early state
(NEW/ASSIGNED/IN_PROGRESS — i.e. before review). dorian@… owns the job.
Voice notes are a brief-intake / early-edit tool — client-authored only (an
editor can never record one). What the editor sees is covered in the editor
sheet §3b.
| # | Do | Expect |
|---|---|---|
| 2b.1 | On the job page while the edit is being prepared, find "Voice notes for your editor" | Section shows with helper "Optional — record a quick note telling your editor what you want. You can add more later." and a "Record a voice note" button |
| 2b.2 | Record a short note; watch the meter, then "Stop & save" | Live "Recording m:ss / 5:00" counter while recording; then "Saving your voice note…"; the note then appears with its own audio player + a timestamp |
| 2b.3 | Record again | The button now reads "Add another note"; the new note APPENDS — the earlier one is KEPT (full history, newest first). Nothing is replaced |
| 2b.4 | Cap checks | Recording auto-stops at 5:00 (5-minute cap). An oversized upload (over 15MB) is refused: "That recording is too large — please record a shorter note." |
| 2b.5 | Once the job reaches review/approval and beyond | The recorder is no longer offered (recording is limited to the early window); notes already recorded stay listed and playable |
The assigned editor plays your latest note prominently (older ones kept under an "Earlier notes" disclosure) and gets a "New brief voice note" email + push on each new note — cross-check editor §3b.
3 · Waiting states (⚙️ editor claims + works the job, ops QC-passes)
| # | Do | Expect |
|---|---|---|
| 3.1 | Watch the job page as the job progresses | Client-friendly labels only: "In production", "Quality check" — NEVER raw enums like IN_PROGRESS/QC_REJECTED, never the editor's identity or deadline |
| 3.2 | Open /jobs/[id]/review too early |
Calm "Not ready yet" guard — no player, no error |
4 · Review & approve (the money moment)
| # | Do | Expect |
|---|---|---|
| 4.1 | When status = "Ready for your review": open the job | Loud CTA to the review page |
| 4.1📧 | Check dorian@…'s inbox |
Email "Wakecut — your edit is ready to review (…)" with a review CTA. Editor never named |
| 4.2 | Review page | Watermarked preview plays in a framed player, labelled "watermarked preview — your final files are clean"; "N of M revisions left" chip; NO finals visible anywhere |
| 4.3 | Try "Request changes" with an empty note, then spaces only | Button stays disabled until real text |
| 4.4 | Request a change with a note | Status → "Revisions under way"; your note echoed back; ⚙️ editor sees the note, re-submits; ops QC-passes again |
| 4.5 | Back in review: count decremented ("N−1 of M") | Correct arithmetic |
| 4.6 | Approve → confirmation modal | Designed modal (not a browser popup): "Approving releases your payment and your final files." Escape closes it; nothing charged yet |
| 4.7 | Confirm approve | Page flips to "Approved — your final files are ready"; finals section appears; downloads work and are CLEAN (no watermark) |
| 4.7📧 | Check dorian@…'s inbox |
Delivery email "Wakecut — your files are ready (…)". Exactly ONE arrives even though delivery is automatic on approval (auto + manual paths share one dedupe key) |
| 4.8 | Stripe dashboard | Payment now captured (charged); ⚙️ editor's payout appears in their workspace |
| 4.9 | Log in as rp.client2@example.com (non-participant) and try the same job/review URLs |
404 — never someone else's job |
4b · Rate your edit (0037) + the high-rating tie-in (#79)
Precondition: the job is APPROVED or DELIVERED (post §4), an editor is
set, migration 0037 live. The rating is one per job, immutable, and
pseudonym-only — a client never sees the editor's real name.
| # | Do | Expect |
|---|---|---|
| 4b.1 | On the delivered job page find "How was your edit?" | Prompt "Rate your experience with {pseudonym}. Optional — you can skip this anytime." — 5 stars + an optional comment ("Add a comment (optional)", capped at 2000 chars). Only the editor's pseudonym shown |
| 4b.2 | Skip it (just navigate away without rating) | Nothing blocks you — rating is skippable by design; approval/delivery already stand |
| 4b.3 | Pick stars ("Submit rating" stays disabled until a star is chosen), optionally comment, submit | Button shows "Sending…", then flips to the done view: "Thanks for rating your edit." with your stars read-only and "You rated {pseudonym} N out of five" + your comment quoted back |
| 4b.4 | Reload / revisit the job | The rating is IMMUTABLE — the already-rated view shows your own stars; you cannot re-rate. A forced re-submit is rejected ("You've already rated this edit.") |
| 4b.5 | Rate 4 or 5 stars (on a job whose editor you could re-request) | The done view shows the tie-in: "Want {pseudonym} on your next edit? Request them again when you order (+£X)" linking to /order (the specify-editor add-on, §1b) |
| 4b.6 | Rate 1–3 stars (on another delivered job) | NO tie-in — the "work with them again" offer is absent on a low rating |
The 4-5★ tie-in only renders when the tenant actually sells the
specify_editorextra (priced above zero in the order currency) and you are eligible to re-request that editor — otherwise the done view has no offer even after a 5★ rating. The(+£X)figure is the live tenant price, not an invented number.
5 · Edge checks (optional but valuable)
- Cancel before approval: on a second cheap order, cancel while pre-review → Stripe authorization voided (dashboard shows canceled), never charged.
- Over-cap: burn all included revisions → the decision block becomes a calm "you've used your included revisions" state with a contact path; approving remains possible and free. No paid-revision price shown (not configured).
- Finals gating: before approving, copy a final file's download URL path (if visible in ops) and try it as the client → 403 until approved.
5b · Pushback intervention copy (Phase 6b — ⚙️ needs ops)
Only appears when a pool job stalls and ops releases the prompt. To see it:
⚙️ on a fresh unclaimed order, have editors pass it (or ops opens
/ops → the job → "release pushback prompt"), then reload the client job page.
| # | Do | Expect |
|---|---|---|
| 5b.1 | Open the job showing the intervention card | Headline "A small change could get this picked up faster"; honest body ("editors choose the jobs they take on… we're telling you straight"). NEVER "rejected"/"no one wants it"; NO editor identity, NO count of who passed or why |
| 5b.2 | Read the three levers | Give it more time / Adjust the brief / Boost the pay — boost only shows if ops set an amount, and its button reads "Boost by £X" with the real amount (no invented number) |
| 5b.3 | Pick a lever (e.g. extend) | Job goes straight back to the pool; calm confirmation, no blame framing |
6 · iOS app (installable client app — 2026-07-11)
Prerequisite (once, before this section): the Supabase magic-link email
template must contain {{ .Token }} (Dashboard → Auth → Email Templates),
otherwise sign-in emails carry no code and step 6.4 cannot pass.
Device: a real iPhone, Safari.
| # | Do | Expect |
|---|---|---|
| 6.1 | Safari → the site root, logged out | Dismissible hint appears: install via Share → Add to Home Screen (it must NOT appear on desktop) |
| 6.2 | Share → Add to Home Screen from any client page | App named "Wakecut" with the engine icon; opens full-screen (no Safari chrome), status bar/notch area looks intentional, nothing clipped |
| 6.3 | Dismiss the install hint in Safari, reload | Hint stays gone (per-app dismissal) |
| 6.4 | In the INSTALLED app: sign in as dorian@… — request the magic link, then use "enter the code from the email" with the code (8 digits) from the same email |
Signed in INSIDE the app, landed per your role. (Tapping the emailed link instead opens Safari, not the app — that's exactly why the code path exists) |
| 6.5 | Re-run the spine in the app: /order → pay (Stripe Checkout) → upload an mp4 → job list |
Checkout completes and returns into the app; drag-drop upload path degrades to the photo picker; keyboard never hides inputs |
| 6.6 | Kill the app, reopen | Still signed in (session survives) |
Pass bar (§6): the app installs with the right identity, the code path signs you in without ever leaving it, and the §1–§4 promises hold identically inside standalone mode.
Pass bar: every promise in §4 holds, no raw enum/editor identity ever visible, payment state in Stripe matches the UI story at every step, and each lifecycle email (§1.5📧/§4.1📧/§4.7📧) arrives exactly once, correctly branded, naming no editor.
Phase-10 pass bar (§1b/§2b/§4b): the specify-editor add-on shows only for a returning client (hidden first-order and for unpriced-EUR), and a miss refunds only the extra with the base charge untouched; voice notes append (never replace) and stay under the early-window/15MB/5-min caps; the rating is one-per-job immutable and pseudonym-only, with the re-request tie-in present on 4-5★ and absent on ≤3★. Every one of these surfaces names no editor and shows no invented price — all money/label copy is the live tenant config.