Inspiration
Every student at Bath has been burned by ticket scams. Tickets for example, Loca Thursdays or Skint Monday get sold over WhatsApp and Snapchat by anonymous accounts, you send the money, and half the time the "seller" disappears. There's no verification, no recourse, and no trust layer. We wanted to build something that makes that problem structurally impossible, not just harder.
What does it do
UniTix is a ticket resale platform exclusively for UK university students. Sellers upload a photo of their ticket, the app scans the QR code directly in the browser, hashes it, and checks it against every listing ever made to prevent duplicates. The QR image is stored securely on the server and is completely invisible to buyers until payment completes. Once a transaction goes through, the buyer gets a dedicated ticket screen with the QR code ready to show at the door. Every user is verified via their .ac.uk email with a one-time code, no passwords, no anonymous accounts.
How we built it
- Next.js 16 (App Router) for the full-stack web app
- Prisma 6 + SQLite for the database, with a custom generated client path
- Tailwind CSS v4 + shadcn/ui for the UI
- Resend for passwordless OTP email delivery
- JWT in httpOnly cookies for session management
- jsQR for in-browser QR code decoding from uploaded ticket images
- ESP32 + SSD1306 OLED for a live hardware dashboard showing real-time signups and listings
- Claude code was used to aid with development
Challenges we ran into
- Next.js 16 breaking changes - the framework renamed middleware.ts to proxy.ts and introduced Turbopack by default. Several routing and config conventions changed from what we knew.
- Prisma + SQLite path resolution - Prisma's engine binary resolves DATABASE_URL relative to its own location, not process.cwd(), which silently broke the database connection until we tracked it down.
- Secure cookie on localhost - our production URL (https://unitix.store) caused the session cookie to be set with Secure: true, which browsers refuse to send over plain HTTP. Debugging why login appeared to work but auth was silently failing took longer than expected.
- QR duplicate prevention - hashing the decoded QR content client-side before sending to the server, while also handling dark-background tickets and low-res photos, required multiple fallback decode strategies.
Accomplishments that we're proud of
- The core anti-scam mechanic works end-to-end - a seller cannot scam a buyer because the QR is never transmitted until payment is confirmed, and can't be listed twice
- Fully passwordless auth with real .ac.uk email verification
- A live hardware dashboard on an ESP32 that polls the platform and shows real-time stats and notifications on an OLED screen
- Went from zero to a deployed, working product at https://unitix.store within the 24 hour hackathon window
- Custom logo and colour theme made with Photopea
What we learned
- How to work with Next.js 16's new conventions and Turbopack quirks under time pressure
- The subtleties of cookie security attributes and how they interact with HTTP vs HTTPS environments
- How to decode QR codes entirely client-side using canvas - no server round-trip needed
- How to wire an ESP32 to a live web API over HTTPS with JWT-secured endpoints
What's next for UniTix
- Stripe integration - real payment processing with escrow, so money only releases to the seller after the buyer confirms the ticket worked at the door
- Mobile app - a React Native client so buyers can show tickets directly from their phone (although it still works at the website at the moment)
- Event partnerships - work directly with venues to verify event QR code formats and provide official resale infrastructure
- Deploy using Vercel - Currently the server is being hosted on a laptop using npm with a Cloudflared tunnel.
Built With
- arduino
- esp32
- json-web-tokens
- jsqr
- next.js
- node.js
- prisma
- resend
- shadcn/ui
- sqlite
- tailwind-css
- typescript
Log in or sign up for Devpost to join the conversation.