Monetization productization · execution status

Lissin Monetization — Execution Plan & Build Status

One-paragraph summary (updated 2026-07-20)

The full program is now built out across six PRs (59 commits), all observe-only / additive / flag-gated — nothing blocks a user until you flip a flag, so all are safe to merge. Backend: the entitlement + quota + enforcement foundation (#514) and grandfathering for both filtered cohorts and hand-picked users + audit (#515). iOS: the plan-contract base (#309), the offer-stage rescue ladder (#311), and Phase 4 — gates, trial banner, nudges, live balances (#312). Admin: grants + user multi-select bulk grandfather + audit (#163). Every code-review comment is fixed & pushed; the full iOS stack compiles + 356 tests pass (Xcode 26.5). The only remaining step is the App Store / RevenueCat catalog (yours). This report is a per-session snapshot brought current on 2026-07-20; the Master report carries the full commit-by-commit detail.

Where we are

Backend 2 PRs open

#514 + #515 → dev

✅ Contract → ledger → quota → access API → trial → enforcement (dark)

✅ Grandfather cohorts + hand-picked users + audit

✅ nest build clean · 29/29 grandfather + billing tests

✅ All review P1/P2 fixed & pushed

iOS 3 PRs open

#309 → #311 → #312 → develop (stacked)

✅ Plan contract + offer-stage rescue ladder

✅ Phase 4: gates, trial banner, nudges, live balances

✅ Full stack compiles + 356 tests (Xcode 26.5)

✅ All review P1/P2 fixed; re-reviews green

Admin PR open

#163 → dev (admin.dev)

✅ Grants / revoke / access snapshot

✅ Cohort grandfathering UI (builder → preview → apply)

✅ User multi-select → bulk grandfather + audit page

✅ tsc + next build clean

The execution plan

The PRD is a full program (Free/Plus/Pro + 3-day trial, credit quotas, rescue-offer ladder, server enforcement, grandfathering, expanded iOS, store config). The PRD's hard sequencing rule — never enable client gates before backend enforcement + grandfathering exist — sets the order. We're executing it phase by phase with dev as the base branch in every repo:

Phase 0 — Product lock. Confirmed numbers adopted; pending values use PRD defaults, flagged for sign-off. (numbers are versioned config, changeable without a deploy)
Backend foundation (this session). Versioned plan contract, dashboard-editable plan_versions, usage ledger, quota service, expanded access API — all observe-only. shipped · PR #514
iOS contract alignment. Client decodes the expanded access response and aligns its fallback plan to the contract. shipped · PR #309
Wire & enforce. Trial phase projected from the webhook, meters wired into generation/upload/playback (observe-only), enforcement engine behind per-capability flags with structured 402 denials (off by default). shipped · PR #514
iOS Phase 4. Entitlement gates (transcript/speed/soundscape/Explore-time/files), the offer-stage rescue ladder, trial countdown banner, Plan & Billing on live balances, usage nudges. shipped · PR #311 + #312
Admin grandfathering. Cohort preview → apply, plus hand-picked user multi-select → bulk apply, + a campaigns audit view. shipped · PR #515 + #163
Store/RevenueCat catalog (trial + save50/save65 rescue offerings, once prices/durations sign off) → QA & ramp. your part — the only remaining step

What shipped this session

Two PRs, ten focused commits, both built against one agreed interface — the backend and iOS work ran in parallel and meet at the expanded /billing/access contract.

Backend — PR #514dev

CommitWhat it does
2c8591eVersioned credit-based plan contract — the PRD's Free/Plus/Pro + plus_trial numbers as one typed source of truth. Confirmed numbers locked by tests.
8edc016`plan_versions` table + seeder — makes the DB the runtime source of truth for plan numbers, so they become dashboard-editable later with no deploy.
f4adc3f`usage_accounts` + immutable `usage_ledger` — the meters substrate (RESERVE → CONSUME/RELEASE) replacing placeholder-zero usage.
8a6e08bUTC-anchored window math — weekly (ISO Monday), rolling-3-day (tumbling), billing-month, trial. Fully unit-tested.
f546ffcQuota service — balances + reserve/consume/release + rollover, idempotent, unlimited meters short-circuit. Not yet wired to create/upload/playback.
17b250aAccess phase + trial fields on billing_access (phase, planVersion, trial dates, product/offer, environment).
c9caf70Expanded `GET /billing/access` — phase, planVersion, serverTime, per-meter balances (read-only peek), trial. All additive.

Verification: nest build clean after every commit; 46/46 billing unit tests pass. Migrations authored per repo convention (manual SQL + migrate deploy, never migrate dev).

iOS — PR #309develop

CommitWhat it does
772daf4eDecode the expanded contract — optional phase/planVersion/serverTime/balances/trial on AccessSnapshot + new wire types; extended PlanLimits.
d8d93c06Align local fallback plan to the confirmed Phase-0 numbers + a plusTrial variant.
7dd7e34bDecode tests — response with and without the new fields both decode cleanly.

Verification: Xcode 26.5 build succeeds (app + test targets); 3/3 decode tests pass. Robustness: phase and MeterBalance.window decode as raw strings so an unknown future value can't fail the snapshot; new composite fields fail open. No paywall placement, capability, or gate trigger changed. It added a new fileMaxBytes field rather than tightening the legacy documentMaxBytes, so no current Pro user is newly blocked.

The shared contract — expanded GET /billing/access

Both PRs were built to this interface, so they line up when merged. Every new field is optional / backward-compatible — old clients and old server responses keep working.

{
  ...existing AccessSnapshot fields (tier, capabilities, limits, usage, ...),
  "phase":        "free|trial|paid|grace|billingRetry|promotional|complimentary|expired",
  "planVersion":  "plan_contract_v1",
  "serverTime":   "2026-07-18T..Z",           // authoritative clock
  "trial":        { "startsAt": "..", "endsAt": ".." } | null,
  "balances": {
    "recurringGeneration": MeterBalance,
    "oneTimeGeneration":   MeterBalance,
    "explorePlayback":     MeterBalance,       // unit: SECONDS
    "fileUploads":         MeterBalance
  }
}
MeterBalance = { limit|null, remaining|null, used, reserved,
                 rolloverBalance, resetAt|null, window }

Branch strategy — dev as base

RepoBase branchThis session's branch → PR
backenddevfeat/billing-quota-foundation#514; feat/billing-grandfather-cohort#515
iOSdevelopfeat/billing-plan-contract#309feat/billing-offer-ladder#311feat/billing-phase4#312 (stacked)
admindevfeat/billing-grants-admin#163

Why this is safe to merge now

What's next

All the engineering phases above are shipped (webhook trial projection, meter wiring, dark enforcement, iOS Phase 4, and grandfathering are all in the six PRs). What remains is mostly yours:

  1. Review & merge the six PRs — backend #514 + #515 → dev (one at a time); admin #163 → dev; iOS in stack order #309 → #311 → #312develop.
  2. RevenueCat / App Store catalog — create the default, save50, and save65 offerings (the ladder loads save50/save65 for its downsells; the client falls back gracefully until they exist), trial intro offer, placements, prod webhook.
  3. Sign off pending product numbers (prices, 50/65 discount duration, rollover caps) — versioned config, a data edit, no deploy.
  4. Flip enforcement per capability when ready (BILLING_ENFORCE_CAPABILITIES=true first, then FILES + GENERATION), then QA → cohort → % ramp.

Nice-to-have engineering follow-ups (non-blocking): auto-present a paywall on a live 402; a DEBUG -billingScenario trial/lowBalance to screenshot the trial banner/nudges/live balances; wire pro_sources once a Pro-sources feature exists; grandfathering hardening (two-person approval, expiry dashboard).

Open items & decisions

ItemStatus / needed
Apply migrations on devaction Docker was off locally, so the two migrations weren't applied here. Start docker + npx prisma migrate deploy + npm run seed:plan-versions — or they apply on dev-deploy when #514 merges.
Product sign-offspending Prices, 50%/65% discount duration, one-time weekly rollover caps (default 2x base: Free 4 / Plus 20 / Pro 100) & Pro files (25/wk @25MB) normalization. Using PRD defaults; flagged in plan-contract.ts. Blocks store config only.
Weekly-window anchoringdecided UTC ISO-week for now (per your call); signup-weekday anchoring is a later refinement.
Dashboard editing UIdeferred Architecture is in place (plan_versions); the admin editing screen is a later admin task.
Admin repodeferred Base dev; env being stood up separately.

All six PRs are pushed and open; commits are small and focused; nothing is merged yet — they await your review. Every code-review comment is fixed and re-reviews are green. The only remaining step is the App Store / RevenueCat catalog (yours). See the Master report for the full commit-by-commit detail and action items.