Problem
Card games live on scarcity and trust: a pack must hold exactly the cards it promises, a minted card can never change, and coins can't appear from nowhere. With 2.6 million possible cards, none of that can depend on careful application code alone.
Solution
I moved the guarantees into PostgreSQL: triggers freeze each card at mint, reject incomplete packs and check every wallet against its ledger. On top sits a responsive Next.js app (packs, collection, market, trades, duels) and a background worker that settles auctions and nightly upkeep.