Data Model & Rollout
Proposed Prisma schema additions, new ledger types, and the phased shipping plan.
Last updated Thu Jul 16 2026 00:00:00 GMT+0000 (Coordinated Universal Time)
TL;DR -The proposed engineering blueprint for the Creator Program: the new database tables, the new ledger transaction types, the single monthly job that pays everything out, and the five-phase order in which it would ship. All additive -no existing table changes shape.
Who this is for -Engineering & Backend: the whole page. Product & Operations: the rollout-phases table and the open questions at the end.
Status: PROPOSED DESIGN -see the Creator Program overview.
What this page is, in plain terms
This is the build sheet. The other pages describe what each layer does; this one collects the database schema, the money-movement record types, and the scheduled job that computes payouts, then lays out the order to ship them in.
The guiding constraint is that everything is additive. No existing table changes shape (except some new optional metadata fields), so the program can be built and rolled out one phase at a time without risky migrations to the economy that's already live.
Schema additions (Prisma sketch)
Below is the proposed set of new tables -one per program concept (tier state, stream sessions, monthly quota rollups, agencies and their memberships/rebates, PK results, and payout methods). Diamond amounts use the same BigInt-micros convention as the rest of the economy.
Everything is additive -no existing table changes shape except new nullable metadata. Diamond amounts follow the existing BigInt-micros convention.
enum HostTier { RISING BRONZE SILVER GOLD STAR LEGEND }
model HostTierState {
userId String @id
tier HostTier @default(RISING)
multiplierBps Int @default(10000)
monthKey String // evaluation month, e.g. "2026-07"
evaluatedAt DateTime
}
model StreamSession {
id String @id @default(cuid())
userId String
roomId String
startedAt DateTime
endedAt DateTime?
validMinutes Int @default(0) // minutes with >= 3 concurrent viewers
peakViewers Int @default(0)
@@index([userId, startedAt])
}
model HostQuotaMonth {
userId String
monthKey String
track QuotaTrack @default(CASUAL)
validHours Int @default(0)
validDays Int @default(0)
earnedDiamondMicros BigInt @default(0) // settled, paid-coin, pre-split
bonusStatus QuotaBonusStatus @default(PENDING) // PENDING/PAID/MISSED/WITHHELD
@@id([userId, monthKey])
}
enum QuotaTrack { CASUAL REGULAR PROFESSIONAL }
model Agency {
id String @id @default(cuid())
name String
code String @unique // join code
ownerUserId String
status AgencyStatus @default(PENDING) // PENDING/ACTIVE/SUSPENDED/TERMINATED
memberships AgencyMembership[]
}
model AgencyMembership {
id String @id @default(cuid())
agencyId String
userId String
shareBps Int // 0..2000, DB check constraint
status MembershipStatus @default(INVITED) // INVITED/ACTIVE/NOTICE/TERMINATED
acceptedAt DateTime?
endsAt DateTime? // set when notice starts; share applies until here
@@index([userId, status]) // app enforces one ACTIVE/NOTICE per user
}
model AgencyRebate {
agencyId String
monthKey String
rosterDiamondMicros BigInt
rebateBps Int
rebateDiamondMicros BigInt
qualifyingHosts Int
@@id([agencyId, monthKey])
}
model PkBattleResult {
battleId String @id // FK -> existing PkBattle
winnerUserId String? // null = tie
scoreAPaidCoins Int
scoreBPaidCoins Int
bonusDiamondMicros BigInt @default(0)
ladderPointsA Int @default(0)
ladderPointsB Int @default(0)
endedAt DateTime
}
model PayoutMethod {
userId String @id
rail PayoutRail // STRIPE / PAYONEER / LOCAL_BANK
destinationMasked String
verifiedAt DateTime?
changedAt DateTime // drives the 7-day change freeze
}
New ledger transaction types
Every program payout is recorded as a ledger row, just like every other money
movement in the economy. The existing LedgerTransaction table doesn't change
shape -its type enum just gains four new values. The table lists each new
type, which way the money flows, the idempotency-key shape that makes it safe to
retry, and what gets snapshotted into metadata.
The append-only LedgerTransaction model is unchanged; the type enum
grows. Every row keeps the same-$transaction-as-balance-change +
idempotency-key rules from Economy.
| Type | Direction | Idempotency key shape | Metadata snapshot |
|---|---|---|---|
AGENCY_SHARE | agency wallet credit (host-split) | agency_share:<giftLedgerId> | agencyId, shareBps, host id |
AGENCY_REBATE | agency wallet credit (platform) | agency_rebate:<agencyId>:<monthKey> | roster micros, band, qualifying hosts |
QUOTA_BONUS | host credit (platform) | quota_bonus:<userId>:<monthKey> | track, hours, days, base micros, bps |
PK_BONUS | host credit (platform) | pk_bonus:<battleId>[:a|:b] | combined gross, pair-decay step |
Plus one metadata extension: DIAMOND_EARNING rows gain tierAtCredit,
multiplierBps, and (when split) agencyId/shareBps.
Monthly-keyed idempotency keys make the whole monthly job re-runnable: a crashed run resumes safely because every credit it might repeat replays instead of double-paying.
The monthly job
A single scheduled job does all the monthly payouts, in a deliberate order so each stage's output feeds the next. Because every stage is independently idempotent, a crash mid-run can simply be re-run from the top.
One scheduled job (1st of month, 00:10 UTC), ordered so each stage feeds the next, each stage idempotent independently:
- Settle any matured diamonds for affected wallets (reuses lazy settlement logic).
- Tier evaluation →
HostTierStateupserts. - Quota evaluation →
QUOTA_BONUScredits. - Agency rebates →
AGENCY_REBATEcredits. - Season close (every 4th run) → ladder prizes + league reshuffle.
Config
All program numbers live in code, not environment variables -they're economics that belong in code review, not deployment config.
All constants land in creator-program.constants.ts next to
economy.constants.ts, exported as creatorProgramConfig, snapshot into
ledger metadata at credit time. No new env vars -these are economics,
not deployment config, and belong in code review, not .env edits.
Rollout phases
The five layers ship in a fixed order, each chosen so its dependencies are already live. The table gives what each phase ships and why it comes when it does.
| Phase | Ships | Why this order |
|---|---|---|
| 1 -Sessions & tiers | StreamSession tracking (dark), HostTierState, multiplier at gift time, tier badge | Multiplier is the smallest ledger-touching change; sessions must accumulate history before quotas can launch honestly |
| 2 -Quotas | Tracks, progress UI, QUOTA_BONUS | Needs ≥ 1 full month of session data to sanity-check valid-hour rates before money attaches |
| 3 -PK economy | PkBattleResult, winner bonus, ladder | Builds on shipped PK mechanics; needs tier data for league seeding |
| 4 -Agencies | Entities, splits, rebates, admin Agencies page | Highest-complexity money movement; rebate floor needs the quota system live |
| 5 -Payout rails | Finish Stripe Connect, batch clearing, then Payoneer | Independent of 1–4; sequenced last only because current volume clears through manual admin review fine |
Each phase: constants land first behind a flag, admin-portal read views ship before money moves, and the phase's page in this section flips from PROPOSED to normative in the same commit that enables it.
Open questions (decide before Phase 1)
These are the design decisions still unresolved -the ones that need a call before the first phase ships.
- Tier thresholds vs. actual early traffic -the table's numbers assume Poppo-scale spend; likely need a 5–10× reduction for launch and a planned re-rating.
- Do stage guests accrue tier progress on gifts targeted at them (current gifting allows it)? Design says yes (it's their earning), but confirm quota/session attribution UX.
- Regional pricing: coin packages are USD-only today; agency recruiting in SEA/MENA will immediately raise localized-pricing demands -out of scope here, flagged.
Related pages
- Creator Program overview -shared principles and the margin ceiling.
- Host Tiers -the
HostTierStatemodel and multiplier. - Quotas & Bonuses -the
StreamSession/HostQuotaMonthmodels. - Agencies -the
Agencyfamily of models and rebate math. - PK Battle Economy -the
PkBattleResultmodel. - Payout Rails -the
PayoutMethodmodel and phase 5. - Economy -the ledger rules every new type inherits.