Under offer2026

Confexio

An event platform I took from first commit to a live three-day conference in 24 days, now running in production with live payments.

Status
Under offer
Live since June 2026
Built in
24 days
To the first live event, April 2026
Stack
Next.jsExpo / React NativeSupabasePayload CMSStripe ConnectVercel WorkflowVercel AI SDK

01 / 06

Communications

Reminders, follow-ups and surveys scheduled around the event, beside the attendee app.

The problem

Event teams run their year on a ticketing page, a spreadsheet and a WhatsApp group.

Teams that run regular events sell on Eventbrite or Luma, keep the guest list in a spreadsheet and talk to attendees in group chats, so every event starts from scratch and people drift away between them. Conferences that want more pay Bizzabo or Accelevents $27–65k a year for a web app nobody opens. I wanted one native app that attendees would actually keep on their phone, with tickets, messages and check-in built in.

How it works

Organisers build the event on the web; attendees carry it in their pocket.

An organiser describes their event, or pastes a flyer or a link, and an AI assistant drafts the programme, tickets and emails next to them. They publish, sell tickets in four currencies with deposits and discounts, and send designed emails with delivery tracking. Attendees get a QR ticket with an Apple Wallet pass, the agenda and a list of who’s going. On the day, the team scans people in at the door.

Building it

It’s a monorepo of four apps: a Next.js backend and organiser dashboard, an Expo app for attendees, a Payload CMS for event sites and emails, and an internal ops app, each with its own database and deploy. Supabase Postgres sits under the product, with row-level security doing the access control. AI coding agents wrote most of the code, so a lot of the engineering went into the system around them: plans, review, a seeded QA world and recorded evidence before anything ships.

API routes
500+
Test files
2,500+
Database migrations
329
Releases in four months
97

Under the hood

Release pipeline

Every pull request gets its own Vercel preview, an Expo over-the-air build on its own channel with a QR code posted to the PR, and its own Supabase database branch if it touches the schema. Merging to main ships web, CMS and mobile to staging. release-please turns conventional commits into a versioned changelog, and every two weeks I QA everything on the train, mark each issue qa-passed, and cut the tag that ships it all to production. That’s 25 GitHub Actions workflows and 97 releases from v1.1.0 to v2.73.0.

  • The problem

    Releases made by the bot triggered nothing. Pushes made with GitHub’s default token don’t start other workflows, so release PRs hung and tags would have deployed nothing.

    The fix

    release-please runs as its own GitHub App, so its PRs and tags start the downstream deploy workflows like any human push.

  • The problem

    Choosing between an over-the-air update and a new native build. Diffing git missed runtime-version bumps made mid-cycle and builds that had failed earlier.

    The fix

    On each tag, the pipeline asks EAS directly whether a production build exists for that runtime version. If one does, it ships an OTA update; if not, it builds and submits to the App Store. This is the third version of that logic.

  • The problem

    A production migration that had never run on staging, or a bad web build going straight to the live domain.

    The fix

    Migrations are additive-only, and a parity guard checks through the Supabase Management API that every pending one is already in staging’s history. Web builds deploy with --skip-domain, get smoke-tested on that URL, and only then are promoted.

  • The problem

    A workflow that failed by succeeding: release-please ran green for months without cutting a tag, so no failure alert ever fired.

    The fix

    Daily heartbeats whose absence pages my phone, alongside failure alerts on every workflow.

Communications engine

Every message is three independent choices: a type (what’s sent; 32 are built in), a style (the event’s brand; 7 presets) and a workflow (when: a graph of trigger → delay → send, across 16 trigger types). An instant reaction is just a workflow with no delays, so one enrolment path, one executor and one send function serve everything. Workflows run durably on Vercel Workflow, email goes out through Resend, and delivery status comes back through signed webhooks into a per-event history. The comms code alone has 1,337 tests, run on every PR and again every night.

  • The problem

    Durable workflows replay from a log, so any side effect in the workflow body would send the same email twice.

    The fix

    Every read, write and send lives in its own step. Delays sleep in chunks of at most a day and re-read the event date when they wake, so moving an event corrects reminders that are already in flight.

  • The problem

    Late sign-ups: someone who registers 20 hours before an event would get every reminder they’d missed, all at once.

    The fix

    Steps are skipped by comparing against the person’s fixed enrolment time, not the clock, so the decision stays the same when the workflow replays.

  • The problem

    Delivery webhooks arriving out of order, twice, or before the send had even been logged.

    The fix

    Status only moves forward by rank (sent, delivered, bounced, complained). A webhook for an unknown send writes a placeholder that the real log row later merges into, and the event id is claimed in the same transaction, so a failed apply rolls back cleanly and Resend retries.

  • The problem

    Sending the same thing twice, or flooding attendees when an organiser makes several edits in a row.

    The fix

    Idempotency keys at enrolment (a unique constraint) and on every Resend call, a 10-minute coalescing guard on automated event-wide notices, a per-person weekly cap and a global bounce list.

Site builder on Payload CMS

Event sites, email templates and articles are built in Payload 3, which runs as its own app with its own Neon Postgres database, Cloudflare R2 media storage and Vercel project. The product never imports Payload. It talks to it over REST through a proxy that checks permissions against Supabase and passes on the user’s token, which the CMS verifies offline against Supabase’s public keys. Publishing a page revalidates its cached route on the web app, and the public event pages carry structured data for search and generated share images. It has 9 collections, 10 page blocks with 30 layout variants, and 16 email blocks.

  • The problem

    Multi-tenant access was open on create. Payload never checks a create rule against the incoming data, so one organiser could have created a page in another’s workspace.

    The fix

    Every create rule checks the incoming tenant itself, and draft versions declare their own read access instead of inheriting it.

  • The problem

    One block schema with four consumers (the database, the TypeScript types, the AI’s output validation and the React renderer) that must never drift apart.

    The fix

    Types and validators are generated from the schema and checked for drift in CI. Each block is capped at 16 variants, the largest union Anthropic’s structured-output decoder accepts.

  • The problem

    Media uploads: newer AWS SDKs add a checksum header that R2 rejects, and Vercel caps request bodies at 4.5 MB.

    The fix

    Checksums are set to only-when-required, and browsers upload large files straight to R2 with presigned URLs.

Payments and check-in

Ticketing runs on Stripe Connect with direct charges. Every call is made on the organiser’s own Stripe account, so they’re the merchant of record and the money lands with them. Prices, discounts and deposits are worked out on the server from a code or an id, never from a price the browser sends, in USD, EUR, GBP or SEK. Each ticket becomes an Apple Wallet pass, built from the same field-mapping code as the preview the organiser designs it in. At the door, each ticket checks in once per day, and offline scans sync within a bounded time window.

  • The problem

    Stripe webhooks must take effect exactly once but still be safe to retry.

    The fix

    Every event lands in an inbox table keyed on provider and event id, and only rows marked done are skipped. Changes go through idempotent database functions, and each webhook is checked against the stored order’s account, currency and amount before it can mark anything paid.

  • The problem

    Moving the platform to a new Stripe account without breaking organisers’ connected accounts.

    The fix

    Each merchant row is stamped with the platform account it belongs to, so a swap is just a key rotation: rows from the old account stop being used on their own.

AI assistant and MCP server

The organiser’s assistant runs on the Vercel AI SDK through AI Gateway with one tool registry. The user and the event are bound on the server and never appear in a tool’s inputs, and every write tool pauses for an approval card in the chat. AI-first event creation runs the setup steps and a chat side by side over one draft, and can crawl the organiser’s own website (respecting robots.txt) to prefill it. I also built an MCP server with its own OAuth 2.1 so Claude, ChatGPT or Cursor can reach an organiser’s events. It has 19 read tools and 23 that only ever propose changes for the organiser to approve inside Confexio.

  • The problem

    MCP tools had to respect Postgres row-level security without a browser session to borrow it from.

    The fix

    The server mints a five-minute token for that person on every call, flagged as MCP, and it never leaves the server. The public API rejects any token carrying the flag, and no admin database client sits on a tool’s data path.

  • The problem

    An unanswered approval card broke every later turn in the same conversation.

    The fix

    Approval state is stripped from every message except the latest before the history goes back to the model.

Building with agents

A feature starts as a Linear ticket. An exec plan breaks it into milestones and names the flag that switches it on. Each milestone then runs build (failing test first), adversarial review, fix and verify, and the last step films a Playwright walkthrough as evidence. Agents test against a seeded QA world of 16 personas and 14 events, and nothing ships until I’ve watched the evidence. That’s 157 exec plans so far. An internal ops app holds a cockpit for running these agents and an AI sales pipeline with an eight-check compliance gate before anything is sent.

  • The problem

    Several agents working in one checkout kept tangling each other’s changes into the same commits.

    The fix

    One branch and one PR per piece of work, with each agent’s commits restricted to the file paths it owns.

  • The problem

    Realistic test data without real people’s data.

    The fix

    A deterministic sanitiser replaces names and photos on scraped real conferences but keeps the programmes. To reproduce a bug, a pseudonymised slice of production is pulled into the local stack.

  • The problem

    The cockpit spawns Claude Code with write access to the repo, which would be remote code execution if it were ever deployed.

    The fix

    Every cockpit route returns 404 unless it’s running locally, outside production, next to a real .git folder, and a test fails the build if any handler skips that check.

Where it is now

Under offer. Live since June 2026.

Production went live in June 2026, and Stripe has taken real payments since August. The first customer, A Players Club, ran events on it in Stockholm, Amsterdam, Marbella and London before moving on. Since then I’ve renamed it from OBOX to Confexio and refocused it on teams that run events all year: conferences, regular programmes and, next, exhibitions. It has since received a buyout offer for the codebase.

First commit to first live event
24 days
RSVPs at the largest event
146
Commits in six months
2,500+

What I learned

Shipping to a real event in 24 days taught me more than any amount of planning would have. But building around one customer made the product narrower than the market. Next time, I’d put it in front of many teams early, before one customer’s requests fill the roadmap.

Ask about Confexio

The site’s assistant has read this case study. Ask it anything, or start with one of these.

Next projectAppStoreOptimization.ai ›