R-02 PRE-BRIEF NOTES — THE TILL¶
Stripe + Checkout + Entitlement¶
Locked 18 March 2026 — write brief when R-01 closes¶
Architecture Decisions (Locked)¶
Stripe is the ledger. We surface it, we don't duplicate it. - All financial data lives in Stripe - We query Stripe API to display in L1/L2/L3/L4 panels - Never store card details, invoice PDFs, or replicate Stripe data - Stripe Customer Portal handles self-service billing for L3/L4
Legal entity on all invoices: United Central Colleges of Australia Pty Ltd ABN 59 168 872 535 Trading as: RTOpacks
Currency: AUD GST: Enable Stripe Tax — auto-calculates and remits 10% GST for Australian buyers. Zero code.
Stripe account structure: - Org: RTO Packs (Stripe Connect) - Trading account: RTOPacks.com.au (live keys, AUD, settles to Pty Ltd bank) - Parent entity: United Central Colleges of Australia Pty Ltd
The Dual Auth Gate (Locked)¶
You can browse anonymously. You cannot buy anonymously.
Before checkout: 1. Enter email + mobile 2. Verify both (same dual auth flow as R-01 — Auth0 email OTP + Twilio Verify SMS) 3. Account created or existing account recognised 4. Proceed to Stripe checkout as identified user
Session: 30-day verified session cookie. Verify once, buy multiple times within 30 days without re-verifying.
If already L3 tenant: Skip gate, go straight to checkout.
Every successful purchase: - Creates L4 account if one doesn't exist (JIT provisioning) - Sends confirmation to email + SMS - Entitlement record created in engine-db - Lands in L4 dashboard
Finance Tab Per Layer (Locked)¶
L1 — Platform view (Tim) Total revenue across all tenants. MRR, total processed, by tenant. Stripe Connect org level. Engine P&L.
L2 — UCCA staff Read-only. Total dollars through gateway. No tenant granularity. Health check, not accounting.
L3 — RTO admin Their purchases, invoices, billing history. Stripe Customer Portal link — self-service. We surface it, Stripe hosts it.
L4 — Learner / direct buyer Their purchase history. What they bought, when, download/access link. Stripe Customer Portal link for receipt download.
Verification Gate Copy (Locked)¶
Headline: "Your content is built to your specification. We verify who you are so it stays yours."
Context: - Appears on the dual auth gate screen before checkout - Does NOT say "security" or "verification" or "identity" - Positions verification as IP protection, not a barrier - No legal language, no alarm bells - Communicates that content is customised = higher perceived value
Supporting copy (draft): "The training context, learner descriptors, and organisational details you provide are your IP. We take that seriously."
Purchases Table — engine-db (Locked)¶
CREATE TABLE IF NOT EXISTS purchases (
id TEXT PRIMARY KEY,
tenant_id TEXT REFERENCES tenants(id), -- NULL for guest (shouldn't happen post-R-02)
user_id TEXT REFERENCES users(id),
stripe_customer_id TEXT NOT NULL,
stripe_payment_intent_id TEXT UNIQUE NOT NULL,
stripe_invoice_id TEXT,
product_id TEXT NOT NULL,
price_id TEXT NOT NULL,
amount_aud INTEGER NOT NULL, -- in cents
gst_aud INTEGER NOT NULL DEFAULT 0, -- in cents
status TEXT NOT NULL CHECK (status IN ('pending','paid','refunded','disputed')),
entitlement_json TEXT NOT NULL DEFAULT '{}', -- what they get
delivery_status TEXT NOT NULL DEFAULT 'pending', -- stub for now
created_at INTEGER NOT NULL DEFAULT (unixepoch()),
paid_at INTEGER,
refunded_at INTEGER
);
CREATE INDEX IF NOT EXISTS idx_purchases_tenant ON purchases(tenant_id);
CREATE INDEX IF NOT EXISTS idx_purchases_user ON purchases(user_id);
CREATE INDEX IF NOT EXISTS idx_purchases_stripe_pi ON purchases(stripe_payment_intent_id);
CREATE INDEX IF NOT EXISTS idx_purchases_status ON purchases(status);
Migration from ops-db (Locked)¶
Current state: - Stripe webhook writes to ops-db (old architecture) - Checkout route on ops-v2 (ops.ucca.online) - Keys on ucca-ops Worker secrets
R-02 migration: - Webhook stays at ops.ucca.online/api/stripe/webhook but writes to engine-db purchases table - Checkout flow wired to L4 user session from R-01 dual auth gate - Stripe Tax enabled on RTOPacks.com.au account - ops-db Stripe tables deprecated (not deleted, just no longer written to)
Blockers — None¶
R-02 is fully scoped. Write brief when Alex confirms R-01 closed.
R-02 PRE-BRIEF · UCCA Inc · 18 March 2026 "You can browse anonymously. You cannot buy anonymously."