What it is
Software for people who run event venues — hotels, banquet halls, conference centres. Three things, in the order a venue manager actually needs them:
- Run the operation. Events, spaces, vendors, clients, budgets, proposals and quotes, on a multi-venue model with per-tenant data isolation.
- Pick and manage vendors. A weighted matching engine (reliability 40%, cost fit 30%, experience 20%, on-time history 10%) with post-event reviews feeding the scores back.
- Win the business. A public venue page builder — SEO-friendly pages with galleries, spaces, pricing and an availability calendar — with an embedded AI assistant that answers visitor questions and turns them into tracked leads.
Stack, and why
| Layer | Choice | Reasoning |
|---|---|---|
| App | Next.js 16 (App Router), TypeScript strict | Server components for the public pages (SEO, speed); client components only where interaction demands it |
| Data / auth | Supabase (Postgres, RLS, Auth) | Tenant isolation enforced at the database, not in application code |
| Payments | Stripe subscriptions + customer portal | Plan limits and usage metering enforced in one place |
| Background work | Inngest + 3 Vercel cron jobs | Agent runs, outreach, webhook processing, trial expiry |
| AI | Claude SDK (vendor agent), a cheap model (public-page chat) | Split by job: reasoning-heavy outreach on Claude, high-volume visitor chat on the inexpensive model |
| Documents | pdf-lib | Proposals generated server-side, accepted through public token URLs |
| Tests | Playwright, 167 tests across 28 spec files | Includes multi-tenant isolation checks, not just happy paths |
The three decisions worth talking about
1. Tenant isolation at the database layer
Every table carries row-level security policies. The browser client can only ever see its own rows, and the service-role key never leaves the server. Application code cannot accidentally leak another venue's data because it does not hold the authority to do so. That is the difference between “we remembered to filter by user_id” and “the database refuses.”
2. The vendor agent is a state machine, not a prompt
Outreach moves through explicit states per vendor. Every execution writes an agent_runs row, every
message a vendor_communications row, every reply a vendor_quotes row — so a stalled or
wrong decision is inspectable afterwards instead of invisible. An Inngest monitor plus a six-hourly cron check
agent health. I deliberately did not build one large prompt that does everything.
3. Public pages are first-class citizens of the render path
They live at the site root, with their own dynamic metadata, JSON-LD (EventVenue +
LocalBusiness), a dynamic sitemap and explicit robots rules. Demonstration workspaces are detected,
banner-labelled and excluded from indexing — so sample data can never be mistaken for a real business in search
results. Getting that boundary right was part of shipping the feature, not an afterthought.
What is actually shipped
- Roughly 1,000 files; 167 Playwright end-to-end tests across 28 spec files; database schema with RLS policies in version control.
- Three scheduled jobs (agent monitor, webhook processing, trial expiry) and full Stripe subscription lifecycle: trial → paid → portal → plan limits → usage metering → AppSumo redemption path (built, not launched).
- A seeded demonstration workspace, so the product can be reviewed without creating an account.
What I did not build — and would say so in an interview
- No paying customers. It is a working product, not a business with revenue. I built it to take a multi-tenant AI product end to end by myself, and that is the value I claim from it.
- The agent has no eval harness. Agent behaviour is inspectable but not scored. If I continued, an offline eval set with regression runs would come before any new agent capability. This is the gap I would fix first.
- The companion leads product is not deployed — the public-page engine lives inside the main app.
The 90-second version
“I run an event-tech company, and I wanted to prove to myself that I could design, build, deploy and test a multi-tenant AI product alone. So I built Venue Manager: Next.js with Postgres row-level security for tenant isolation, Stripe for the subscription lifecycle, an Inngest-backed vendor-outreach agent on Claude with a queryable state machine, and public venue pages with an embedded AI assistant that captures leads on the cheap model. 167 Playwright end-to-end tests across 28 spec files, including tenant-isolation checks. It has no customers — that was never the point; the point is that every layer, from the RLS policy to the agent's state transitions, is something I have personally built and operated.”