kreynolds

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
Points balance
50,302
Lifetime earned
53,302
Tier
Member

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)
NameStatusEntriesWinnersSubscribed
Raffle name goes hereactive12,3451,2341,234
Raffle name goes herepast12,3451,2341,234
Raffle name goes herepast12,3451,2341,234
Raffle name goes heredraft12,3451,2341,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.