← Back to home
SOLO FULLSTACK

Blister64

An auction site for 1:64 diecast collectors in Indonesia. Every bid locks funds in an in-app wallet, and bids in the last two minutes add two minutes, so nobody wins by sniping or backs out after winning. I built it alone, from the Go and PostgreSQL bidding engine to the React app and the AWS deployment, and it runs live with 263 real castings.

  • Go
  • PostgreSQL
  • pgx
  • React
  • TypeScript
  • Vite
  • Tailwind CSS
  • Gemini
  • Docker
  • GitHub Actions
  • AWS EC2
  • Cloudflare Tunnel
Blister64 — screenshot 1
Blister64 — screenshot 2
Blister64 — screenshot 3
Blister64 — screenshot 4
Blister64 — screenshot 5
Blister64 — screenshot 6
Blister64 — screenshot 7
Blister64 — screenshot 8
Blister64 — screenshot 9
Blister64 — screenshot 10
Blister64 — screenshot 11

OVERVIEW

Diecast collectors in Indonesia often auction single cars in Facebook and WhatsApp groups, where a winner can disappear without paying and the last second decides who wins. Blister64 locks a bidder's money in an escrow wallet the moment they bid, returns it automatically when someone bids higher, and adds two minutes whenever a bid lands in the final two minutes. Collectors search in everyday Indonesian, such as "jdm merah di bawah 100rb", which Gemini turns into filters, and the seller and winner arrange shipping in a chat that opens by itself when the lot sells. The site is live with 263 real castings from seven brands plus dioramas; the wallet uses simulated money.

WHAT I DID

  • A bidding engine that cannot corrupt money: each bid is one transaction that locks the auction row first and then the wallets in ascending user order, so two auctions never deadlock. Amounts are whole rupiah in BIGINT columns with CHECK constraints, every movement writes an append-only ledger enforced by a trigger, and tests replay that ledger against the balances.
  • Proven under concurrency: tests run with Go's race detector while many bidders hit the same auctions at once, and deliberate mutations (removing the refund step, the auction lock or the anti-sniping rule) each make a test fail. 82 Go test functions and 27 frontend tests run in CI.
  • Fair closing: a background worker closes expired auctions with FOR UPDATE SKIP LOCKED, moves the winner's locked funds to the seller and opens the buyer-seller chat with a sale notice in the same transaction. An auction that fails to settle is rolled back and skipped, so it cannot block the ones behind it.
  • AI search with guard rails: Gemini answers in a JSON schema with enum fields, the server checks every value against an allowlist and builds parameterized SQL, filters relax step by step when nothing matches, and any model error falls back to keyword search. Prompt injection attempts only produce an empty filter.
  • Run like production on a small budget: one EC2 instance with no inbound ports, visitors through Cloudflare Tunnel, admin access through Session Manager, nightly database backups to S3, per-IP rate limits, and bidder identities that never leave the API. The catalog comes from a Go scraper that reads seven Fandom wikis politely and keeps CC-BY-SA attribution for every item.