Building Gachasik
Written by Gustama Dimas
Gacha sellers run their sales on spreadsheets. A column of items, a column of odds, and a hope that nobody asks how the number got picked.
That's the whole reason Gachasik exists. Not to make gacha — people were already doing that — but to make the draw something you can show.
The one thing that had to be true
Everything else is a feature. This is the product:
- The random pick runs on the server, from a cryptographic source — not on the buyer's phone.
- The odds are printed on the page, before the pull.
- Every pull produces exactly one item and a public receipt.
- The selection code is open source, linked from the site.
That last point took the longest to decide. It's easy to write "provably fair" in a footer. It's harder to publish the actual function that does the picking, so a stranger can read it and check. I did the harder thing, because a fairness claim you can't verify is just marketing.
The rules the product can't break
Two constraints shaped almost every screen.
The platform serves sellers, not buyers. Buyer and seller settle money between themselves, off-platform. The platform owns the draw; it never sits in the middle of a payment. That's a smaller and safer product, and it's the honest one.
It isn't money. Credits are called kredit. There is no cash-out and no transfer. The interface keeps a hard word list, and an automated test scans every screen so the framing never slips into betting language. Even the disclaimer can't use the word. If you have to explain why something isn't a wager, you've already lost the framing.
One day, then a week
The first commit landed at 04:47 on 30 September — a scaffold and a frozen build plan. By 12:58 the same day, the whole thing was standing: pools and odds, the draw engine, the QRIS credit ledger, referrals, the public storefront, a margin calculator, and the deploy bundle. Thirty-six commits in one day.
Then it kept going. Reveal animations. Nested pools — an item can continue into another of the seller's pools, up to three stages under a single charge. A no-login demo on the landing page that runs the real selection code against sample items, so you can pull before you trust it. Kiosk mode for a booth screen.
Final count: 114 commits, 75 test files, 12,367 lines of tests against 10,989 lines of application Python. The schema went from v1 to v16 — every migration additive except one, which needed a real table rebuild to drop a template the CHECK constraint no longer allowed.
What broke
Two things nearly shipped broken, and both are worth naming.
The deploy image was missing two files. draw.js and share.js weren't in the built wheel — the animations would simply have died in production, with no error and no log line. A test now guards the whole app/static directory, so the image can't quietly drop an asset again.
Nginx Proxy Manager's "Force SSL" nearly took the site down. The tunnel hands NPM plain HTTP, so Force SSL redirects that HTTP to the same HTTPS URL — a loop. The fix is to use Cloudflare's "Always Use HTTPS" and leave Force SSL off. It's the kind of setting that looks correct and is exactly wrong.
There was also a stretch where three subagents failed in a row on the nested-pool feature — one crash-looping, one only doing reconnaissance. The main session built it directly. Delegation is not automatically faster than doing it yourself.
What's still open
I'd rather write this down than pretend otherwise:
- The legal pages are real copy but not final — they say, on the page itself, that they're pending a lawyer's review.
- The local repo is one commit ahead of origin.
- There's no pricing for B2B or event work yet — only a contact page.
Why it's a picker, not a game
The name on the box is "a recorded, customizable random picker — not a wager." That's not a euphemism. It's the specification.
A picker is a tool. It does what it's told, shows its work, and keeps a record. Everything in the build followed from that: the server-side draw, the printed odds, the receipt, the published algorithm.
If the draw is fair and you can check it, you don't need to trust the seller. That's the whole product.