Full-Stack Web Application
Berryessa TNT
A membership and tournament registration platform for a bass fishing tournament series on Lake Berryessa, California.
Visit Site- Next.js
- React
- TypeScript
- Supabase
- Stripe API
- Resend
- Sentry
- Cloudflare Turnstile
- Tailwind CSS

The Challenge
The organizers ran a yearly, two-series bass fishing tournament by hand, which made memberships, registrations, and event logistics slow to manage. They needed one platform where anglers could buy a membership and register for tournaments themselves, and where admins could manage users, oversee registrations, and handle logistics like the boat launch order.
What I Built
I designed and built a full-stack web application with a member-facing site and an admin dashboard. Anglers create an account, purchase a membership, and register a team for each tournament, paying online through Stripe. Each member has a profile and a page listing the tournaments they have entered.
- Event management: admins create and edit tournaments, upload event images, and set entry prices and membership requirements.
- Member management: a user list with controls for memberships and admin access.
- Blast off: a randomized boat launch order for each event, generated with a cryptographically fair shuffle.


Payments
Memberships and tournament entries are sold through Stripe Checkout. Entry prices are read from the database on the server when a session is created, never taken from the browser, and membership requirements are enforced before checkout begins.
A webhook verifies each event's Stripe signature and then records the membership or registration in Supabase. The writes are upserts, so Stripe's automatic retries are safe to process more than once. If processing fails, the error is captured in Sentry and an alert email goes out.

Accounts and Security
Authentication runs on Supabase with cookie-based sessions that are refreshed on the server. The sign-up, login, and password reset forms are protected with Cloudflare Turnstile, and admin API routes confirm the caller's session and admin role on the server before making any change.
Outcome
The client went from managing everything manually to a purpose-built platform that handles the full tournament lifecycle. Administrative overhead dropped, and members have a self-service path from sign-up to tournament day.
