Case study
Ghost Lifestyle: fixing a loyalty program that couldn't keep up with launch day
Ghost sells supplements and apparel to a genuinely loyal community. Drops, raffles, streaks, badges, the whole thing. The loyalty program behind it kept buckling whenever a raffle got popular, so I rebuilt it to actually hold up.
01
Swapped out the databaseThe old loyalty system ran on MongoDB, and it just wasn't a great fit for points, tiers, and redemptions. Moved the whole thing to PostgreSQL.
02
Closed a fraud holeFound a gap in how rewards got checked before they could be redeemed, and rebuilt that validation so it actually holds up.
03
Built it to survive traffic spikesA raffle across four storefronts can pull thousands of entries in minutes. Cloud Functions and Pub/Sub let the system scale up on its own instead of falling over.
04
Gave the team their own toolsRaffles, earning bonuses, badges, tiers. All of it configurable by the Ghost team directly, no engineer needed every time they want to run a drop.
What members see
Loyalty dashboard, customer view (recreated)
KR
Kieran ReynoldsMember since 2024
Recreated for this page. Balances are blurred, but the real badge system alone runs more than 40 distinct badges.
What the Ghost team sees
Raffles admin, internal tool (recreated)
| Name | Status | Entries | Winners | Subscribed |
|---|---|---|---|---|
| Raffle name goes here | active | 12,345 | 1,234 | 1,234 |
| Raffle name goes here | past | 12,345 | 1,234 | 1,234 |
| Raffle name goes here | past | 12,345 | 1,234 | 1,234 |
| Raffle name goes here | draft | 12,345 | 1,234 | 1,234 |
Same columns as the real tool, names and numbers blurred out. This gets genuinely dense in production: entries, winners, and subscriptions tracked per raffle, per region.
The real win wasn't adding a loyalty program. It was giving the Ghost team tools they could run themselves, no engineer required.