Membership tier
Cambridge TCG has a tiered membership system. Your tier determines several things you feel as a customer: cashback on purchases, your Berries earn multiplier, your trade-in bonus, your commission rate on P2P sales and auctions, and your store discount. Higher tiers get better terms across the board.
Where this lives in code.
- Tier definitions:
tierstable.- User assignment:
users.tier_id+users.tier_source.- Spending recompute:
apps/storefront/src/lib/membership/db.ts+apps/storefront/src/app/api/cron/maintenance.- Subscription flow:
apps/storefront/src/app/api/membership/{subscribe,cancel,resume}/route.ts.
How tiers are assigned
Three paths get a user into a tier. The users.tier_source column records which path applied — substrate-honest about why you're at the tier you're at.
1. Spending (tier_source = 'spending')
The default. Each user has an annual_spend value tracked over a rolling 365-day window. When this number crosses a tier's min_annual_spend, you promote on the next recompute. When it falls below, you demote.
Spend is counted from completed B2C orders. P2P trade volume does not count toward annual_spend (the platform's commission is much smaller, and counting it would create a perverse incentive to wash-trade for tier promotion).
The recompute happens on the maintenance cron every minute. Tier moves are not retroactive — your perks change from the next purchase forward.
2. Subscription (tier_source = 'subscription')
Some tiers are marked is_paid = true. You can pay to be in one of these tiers regardless of your spend. Subscription is via Stripe, monthly or annual. While the subscription is active, you are locked at that tier even if your spend would assign a lower one.
When a subscription is cancelled or fails to renew, tier_source flips back to 'spending' on the next recompute, and you land at whichever tier your actual spend qualifies you for.
3. Manual (tier_source = 'manual')
The operator can manually assign a user to a tier — typically for staff, partners, or retention exceptions. Manual tier assignments are not recomputed against spend or subscription state; they sit until the operator changes them.
What each tier gets
Tier definitions live in the tiers table. Today's roster (subject to change — the operator's admin viewer is authoritative) typically includes:
| Tier | Threshold | Cashback | Berries × | Trade-in bonus | P2P / Auction commission | Store discount |
|---|---|---|---|---|---|---|
| Bronze | £0 | 0% | 1× | 0% | 8% / 10% | 0% |
| Silver | £200 | 1% | 1× | 2% | 7% / 9% | 0% |
| Gold | £500 | 2% | 2× | 5% | 6% / 8% | 2% |
| Platinum | £2,000 | 3% | 3× | 8% | 5% / 7% | 5% |
| OG (paid) | — | 5% | 4× | 10% | 4% / 6% | 8% |
(Illustrative shape — exact numbers are whatever the tiers table currently holds.)
When a tier change happens
- New B2C order completes →
annual_spendincrements; tier may promote on next sweep. - Refund processed →
annual_spenddecrements; tier may demote. - 365-day-old order falls out of the rolling window →
annual_spenddecrements. - Subscription starts → tier set to subscribed tier;
tier_source = 'subscription'. - Subscription cancels / fails →
tier_sourceflips back; tier recomputes. - Operator sets a manual tier →
tier_source = 'manual'; recompute skipped. - Maintenance cron sweep (every minute) — pending recomputes drain.
What you can see
Your current tier and its perks are on /account/membership. The page shows the active tier, your tier_source, your annual spend (with the rolling-window timestamp), and how much further to the next tier.