Lissin Monetization — Execution Plan & Build Status
2026-07-18, brought current 2026-07-20 · from the PRD set in lo/lissin-monetization-plan/ · base branch = dev everywhere · focused commits, build + tests green
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:
plan_versions, usage ledger, quota service, expanded access API — all observe-only. shipped · PR #514save50/save65 rescue offerings, once prices/durations sign off) → QA & ramp. your part — the only remaining stepWhat 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 #514 → dev
| Commit | What it does |
|---|---|
2c8591e | Versioned 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. |
8a6e08b | UTC-anchored window math — weekly (ISO Monday), rolling-3-day (tumbling), billing-month, trial. Fully unit-tested. |
f546ffc | Quota service — balances + reserve/consume/release + rollover, idempotent, unlimited meters short-circuit. Not yet wired to create/upload/playback. |
17b250a | Access phase + trial fields on billing_access (phase, planVersion, trial dates, product/offer, environment). |
c9caf70 | Expanded `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 #309 → develop
| Commit | What it does |
|---|---|
772daf4e | Decode the expanded contract — optional phase/planVersion/serverTime/balances/trial on AccessSnapshot + new wire types; extended PlanLimits. |
d8d93c06 | Align local fallback plan to the confirmed Phase-0 numbers + a plusTrial variant. |
7dd7e34b | Decode 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
| Repo | Base branch | This session's branch → PR |
|---|---|---|
| backend | dev | feat/billing-quota-foundation → #514; feat/billing-grandfather-cohort → #515 |
| iOS | develop | feat/billing-plan-contract → #309 → feat/billing-offer-ladder → #311 → feat/billing-phase4 → #312 (stacked) |
| admin | dev | feat/billing-grants-admin → #163 |
Why this is safe to merge now
- Observe-only. The quota service exists but is not wired into generation, upload, or playback — nothing reserves or denies yet.
- Additive. Every new field on the access response is optional; the expanded balances are computed read-only (a non-fatal add-on that never breaks the response).
- No client behavior change. iOS only decodes new fields and updates fallback copy; no gate, placement, or capability was touched.
- Dashboard-ready by design. Plan numbers live in the
plan_versionstable (seeded from code), so they can be edited from admin later without a deploy — the answer to "make each value configurable from the dashboard."
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:
- Review & merge the six PRs — backend #514 + #515 →
dev(one at a time); admin #163 →dev; iOS in stack order #309 → #311 → #312 →develop. - RevenueCat / App Store catalog — create the
default,save50, andsave65offerings (the ladder loads save50/save65 for its downsells; the client falls back gracefully until they exist), trial intro offer, placements, prod webhook. - Sign off pending product numbers (prices, 50/65 discount duration, rollover caps) — versioned config, a data edit, no deploy.
- Flip enforcement per capability when ready (
BILLING_ENFORCE_CAPABILITIES=truefirst, 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
| Item | Status / needed |
|---|---|
| Apply migrations on dev | action 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-offs | pending 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 anchoring | decided UTC ISO-week for now (per your call); signup-weekday anchoring is a later refinement. |
| Dashboard editing UI | deferred Architecture is in place (plan_versions); the admin editing screen is a later admin task. |
| Admin repo | deferred 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.