Paso
A ticketing platform built from a design handoff, with every screen measured against its mock.

Paso is an Argentine ticketing platform for fans, organizers, promoters and door staff. Its promise is trust: every fee shown on its own line, a QR that the door checks without internet, official resale with a price cap, and promoters paid for the sales they bring. The design handoff had 66 artboards and 98 screens. Building them was half the job. Keeping them true to the design while the product changed underneath was the other half.
Three decisions that shaped it.
- 01
The design handoff as a test, not a reference
Why. A script cuts every artboard into standalone panels. A manifest maps each panel to the route and state that implements it, with query strings that pin things like a running timer. `pnpm visual` shoots the mock and the real route at the artboard's width, runs pixelmatch and writes mock, implementation and diff images. Under 0.5% different, the screen counts as verified. A screen with no route shows up as pending, so the checklist cannot drift.
Trade-off. Pixel diffs are strict about things users never notice. A breakpoint set just above an artboard's width changed four screens by 5% to 8%. When the product deliberately departs from the mock, the screen is marked as decided, with the reason written down, and still measured.
- 02
Fee rules written twice, held together by golden vectors
Why. The service fee is 4% per ticket, capped at $400. The screen computes it in a pure TypeScript package. The Go API computes what is actually charged. A script generates golden vectors from the TypeScript rules, including the exact point where the cap takes over, and the Go tests read the same file.
Trade-off. Two implementations of the same arithmetic. The vectors catch a disagreement only for the cases they list, so every new rule needs new vectors.
- 03
A QR the door can verify without a server
Why. Venues lose signal right when the line is longest. Each ticket carries an Ed25519 signature and rotates every 30 seconds, so the door app checks it on the phone. Scanned tickets are stored in IndexedDB and shared between tabs over BroadcastChannel. Phones with signal exchange their scans every 20 seconds.
Trade-off. Two doors with no signal at all can each accept the same ticket once. Closing that gap needs Bluetooth between phones, which is not built yet.




Paso
A ticketing platform built from a design handoff, with every screen measured against its mock.
- Role
- Frontend architecture and full-stack development
- Stack
- Next.js + React, pnpm + Turborepo, Go, Postgres + Drizzle, Valkey, Playwright + Vitest

Paso is an Argentine ticketing platform for fans, organizers, promoters and door staff. Its promise is trust: every fee shown on its own line, a QR that the door checks without internet, official resale with a price cap, and promoters paid for the sales they bring. The design handoff had 66 artboards and 98 screens. Building them was half the job. Keeping them true to the design while the product changed underneath was the other half.
Three decisions that shaped it.
The design handoff as a test, not a reference
Why. A script cuts every artboard into standalone panels. A manifest maps each panel to the route and state that implements it, with query strings that pin things like a running timer. `pnpm visual` shoots the mock and the real route at the artboard's width, runs pixelmatch and writes mock, implementation and diff images. Under 0.5% different, the screen counts as verified. A screen with no route shows up as pending, so the checklist cannot drift.
Trade-off. Pixel diffs are strict about things users never notice. A breakpoint set just above an artboard's width changed four screens by 5% to 8%. When the product deliberately departs from the mock, the screen is marked as decided, with the reason written down, and still measured.
Fee rules written twice, held together by golden vectors
Why. The service fee is 4% per ticket, capped at $400. The screen computes it in a pure TypeScript package. The Go API computes what is actually charged. A script generates golden vectors from the TypeScript rules, including the exact point where the cap takes over, and the Go tests read the same file.
Trade-off. Two implementations of the same arithmetic. The vectors catch a disagreement only for the cases they list, so every new rule needs new vectors.
A QR the door can verify without a server
Why. Venues lose signal right when the line is longest. Each ticket carries an Ed25519 signature and rotates every 30 seconds, so the door app checks it on the phone. Scanned tickets are stored in IndexedDB and shared between tabs over BroadcastChannel. Phones with signal exchange their scans every 20 seconds.
Trade-off. Two doors with no signal at all can each accept the same ticket once. Closing that gap needs Bluetooth between phones, which is not built yet.



