ClubHive
Event booking for community clubs — run clubs, cycling clubs, walking groups. Organisers post events and embed a booking widget on their own website; attendees RSVP with no account needed. The booking is the front door. The community is the value.
The problem
Small clubs run their events through a patchwork of WhatsApp polls, Google Forms, and Facebook events. Nobody knows how many are coming until they turn up. The tools that do solve booking — Eventbrite and friends — are built for one-off ticketed events: heavy, fee-laden, and they keep the attendee relationship for themselves.
I saw this first-hand building a website for a cycling club in my freelance practice. The site looked the part, but the moment someone wanted to actually join a ride, the experience fell off a cliff into a group chat. The club also had no memory: no record of who came back week after week, or who drifted away.
The idea
ClubHive treats every RSVP as the start of a relationship, not a transaction. Each booking builds the club's own attendee ledger — who's new, who's loyal, who's lapsed — and when the next event goes live, the club can reach all of them directly. Organisers get a lightweight CRM they never had to fill in; attendees get a one-tap RSVP and never see a password field.
My role
Solo build — product design, data model, and implementation. The project is also a deliberate exercise in the modern serverless Postgres stack: Neon's database branching for environments, Drizzle for end-to-end type safety, and Better Auth's organisations plugin doing the multi-tenancy heavy lifting.
— Architecture
— Key decisions
The audience is someone deciding on a Tuesday night whether to join Sunday's ride. Any sign-up wall at that moment costs the club the booking — and small clubs can't afford to lose a single one.
RSVP is a name, an email, and a tap. Every booking carries a unique token; the confirmation email includes a cancel link keyed to it. Attendees get full control of their booking without ever seeing a password field.
Clubs are textbook tenants: owned by an organiser, possibly co-administered later, with every event and attendee scoped underneath. Building that scoping by hand is where solo projects leak data.
The organisations plugin maps one-to-one onto clubs, so membership, ownership, and future co-admin invites ride on a maintained auth layer. Tenant scoping lives in one place instead of being re-implemented per query.
A person who rides with two clubs is two different community members. A global attendee profile would leak one club's audience to another and make consent murky — whose mailing list are they on?
One attendee record per person per club, accumulated across bookings. Each club owns its list outright: events attended, first seen, last seen, marketing consent. Privacy boundary and CRM in the same design move.
Clubs already have websites they're proud of — often built by a local freelancer. Asking them to send members to a third-party platform breaks their brand and hands their audience to someone else.
The booking form ships as a single iframe snippet that inherits the club's brand colour and looks native on the host site. The club's website stays the front door; ClubHive is the machinery behind it.
Booking data is exactly the kind of state you don't want to test against in production, but maintaining a separate seeded staging database is busywork for a solo builder.
Every feature branch gets a database branch — production-shaped data, isolated writes, deleted when merged. Schema migrations via Drizzle run against the branch before they ever touch production.
— Technical depth
The embed widget
The widget is the product's distribution strategy. It's a stripped-down route rendered inside an iframe — no nav, no marketing, just the next events and an RSVP form. The club sets a single brand colour at creation, and the widget derives its entire theme from it, so the embed reads as part of the host site rather than a third-party bolt-on. Live spots remaining update by polling — simple and sufficient at this scale, with a clean upgrade path to websockets.
One colour, set once when the club is created. The widget derives its whole theme from it — buttons, capacity bar, confirmation state.
<iframe
src="clubhive.app/embed/sunday-riders"
width="100%" height="480"
/>Paste once — works on any site
↑ live demo — embedded on the club's own site
The attendee ledger
Every booking is written against a per-club attendee record — one row per person per club, accumulated across events. From that single table the club gets its community picture for free: first-timers, regulars worth flagging (3+ events), and lapsed members who haven't been seen in 60 days. When a new event is published, everyone who gave consent hears about it — the attendee effectively subscribed to the club the moment they first booked.
Capacity and the waitlist
Capacity is enforced in the database, not the UI. A booking insert runs in a transaction that counts confirmed bookings with the event row locked — two people grabbing the last spot can't both succeed; the second lands on the waitlist with its own confirmation email. Cancellations promote the head of the waitlist automatically, and the cancel link in every email means the whole lifecycle works without a login.
— Design goals
— Where it goes next
The MVP is deliberately narrow: clubs, events, bookings, emails, embed. The growth direction is the community layer — event announcements to past attendees, engagement insights (which events pull the best turnout, who came once and never returned), and recurring events for the weekly ride. Stripe lands when paid events do; the schema is already shaped for it.
Further out: white-label embeds with custom domains — aimed at freelancers and agencies who want to bundle bookings into the club websites they already build. That loop closing is the long game: the product was born inside a freelance club-site build, and it goes back out through them.