pinball asylum
A membership and door-entry system for a volunteer-run nonprofit pinball venue: members buy a pass, pull up a signed QR code, and get scanned in at the door.
Visit pinballasylum.netlify.app ↗client
The Pinball Asylum
role
Solo build, from scratch
launched
Public beta, 2026
status
Live

// the problem
The Pinball Asylum is a 501(c)(3) run by volunteers, not a staffed business. They needed a way to sell passes, verify members at the door, and let non-technical board members run all of it without touching a server or a database. Paper passes and manual check-in do not hold up at a busy venue, and there was no online way to pay or to prove that a pass was real.

// what I built
I built the whole thing solo: a public marketing site, member accounts, the pass and QR system, a door-scanning tool for staff, and a role-gated admin portal. Members register, get a pass, and see a QR code that changes every day. Staff open a scanner page and validate a member at the door in one step. Board members connect Square, issue passes, edit site copy, and manage the machine list from the browser. Payments run through Square for both online and in-person sales, and the machine catalog stays current by syncing from Pinside and OPDB on a schedule.

// technical highlights
- ▹Passes render as HMAC-SHA256 signed QR codes bound to a single calendar day and a single-use nonce. The scan endpoint verifies the signature, checks the stored nonce, and marks it used, so a screenshot of yesterday's code (or a second scan of today's) is rejected.
- ▹Square integration covers online hosted checkout plus a webhook (payment.created and payment.updated) with signature verification and an idempotency key, so a retried webhook delivery cannot issue a pass twice.
- ▹The webhook finds or creates a member account by buyer email and grants the matching pass by line item, so a walk-in who pays gets an account and a pass automatically.
- ▹Square credentials are entered from the admin and stored AES-256-GCM encrypted at rest, so board members connect payments with no server access.
- ▹New accounts are passwordless and receive a single-use, expiring set-password link (the same token flow also powers Forgot Password), so no plaintext temporary passwords are ever emailed.
- ▹The machine catalog syncs from Pinside through a scheduled GitHub Actions scraper (Playwright), is stored as snapshots, and is reconciled (adds and retires) with a review step, then linked to OPDB for clean art and metadata. The auto-sync interval is configurable from the admin.
- ▹Access is role-based (member, staff, board, admin, webmaster), enforced in middleware, with an audit log for sensitive actions and rate limiting on login, registration, and the scan endpoint.
- ▹A Playwright end-to-end suite covers the core journeys: public pages, auth, pass issuance, admin gating, and the full QR scan round-trip.


// the impact
In public beta. Cash and in-person passes and door scanning work today. Online card payments turn on when the board connects their own Square account, which they can do from the admin without any developer help.

Have a similar problem?
Let's talk about what to build.