Dans101 — A Multi-Tenant SaaS Platform with an AI Concierge
Executive Summary
I designed, built and run Dans101: a white-label booking, payments and CRM platform for dance teachers and studios, with a discovery marketplace on top and an AI agent inside it. It is live in production, moves real money through Stripe Connect, enforces tenant isolation at the application layer, and is covered by roughly 3,200 automated tests across four codebases. It is the system I point at when someone asks whether I have built production AI infrastructure or only advised on it.
Problem
Independent teachers and small studios run their businesses across a booking tool, a payment link, a spreadsheet of students and a WhatsApp thread. Nothing talks to anything else, so the admin grows faster than the business does. The obvious fix — one platform — creates harder problems: every studio needs its own brand and its own bank account, one studio must never see another's data, and an AI assistant that touches bookings or money has to be trustworthy enough to hand to a non-technical owner.
Solution
I designed and built the platform end to end:
- Multi-tenancy with isolation as a build rule, not a review step: Every table carries a tenant id and is registered in a single source of truth that the migration tooling reads, so the schema and the isolation list cannot drift apart. Tenant scoping is enforced in the application and has been live in production since July 2026. Platform-level tables — identities, devices, inbound webhooks — are deliberately excluded and documented as such, because a misplaced tenant id is as wrong as a missing one.
- Plan entitlements defined in code, not in the database: Paid features gate through a single entitlement check against a tier map that lives in the codebase, so changing a tier instantly changes what is unlocked with nothing to sync. The database stores only deliberate per-tenant overrides — comps, pilots, grandfathering. The UI reads the same map, so an ungranted feature is absent from the navigation rather than advertised and then refused.
- An AI concierge built to be trusted by a non-technical owner: The agent runs a tool loop over the host's own data with four rules carried from a previous production assistant: nothing that creates, sends or spends happens without a confirmation a human clicks; every factual claim is grounded in a retrieved source, and "I don't have that" is a correct answer; write access is granted per tool and per use case rather than by default; and cheap models handle background classification while a strong model handles the live conversation, because letting premium models leak into the cheap path is how per-message cost quietly triples.
- Two separate payment systems, because they solve different problems: Stripe Connect moves class payments into each host's own connected account — the money is theirs and never sits with the platform. Stripe Billing, entirely separate, handles what hosts pay for their plan. Transactional revenue rides on the same rails: featured placement, and a flat commission on corporate bookings taken as a destination charge.
- Compliance-grade handling of children's data: Youth programmes are off by default and unlock only when a studio supplies four attestations together — a safeguarding policy, a named lead, a contact for that lead, and confirmation of background checks. Consent is an append-only ledger: withdrawing an answer stamps the old row and writes a new one, so what was agreed and when it stopped being agreed is still readable years later. Attendance is recorded per child rather than per booking, with its own append-only change log, and every read of a child's medical notes is logged — which makes "who has seen my child's information" an answerable question rather than a reassuring guess.
- A security review of my own product, and what it found: I audited the platform and found and closed several real issues: an account-takeover path in a social sign-in route that trusted an email address alone, a privilege-escalation route through token claims, exposure of demo-tenant data to live surfaces, and unguarded public endpoints. Sensitive values are now masked before an in-app issue report ever reaches a human. Finding these in your own system is uncomfortable; shipping without looking is worse.
- Graduation — making the white-label promise real: A teacher who builds inside a larger studio's tenant can be moved into their own, carrying their classes, sessions, bookings, payment history, media, automations and saved segments in a single transaction — with segment tag references rewritten so their smart lists still match real people on the other side. What does not move is documented just as carefully, and a host is told before the move rather than after.
What it demonstrates
- A live, multi-tenant, revenue-capable product — not a prototype. Web, mobile (Flutter, on TestFlight), an admin console and a Node/Express backend, deployed and running.
- Roughly 3,200 automated tests across backend, web, mobile and database, with anything touching SQL verified against real Postgres because mocked tests had already missed real type bugs.
- AI features that a non-technical owner can actually be given the keys to, because the guardrails are architectural rather than instructions in a prompt.
- A compliance story that survives a hard question — append-only consent, per-child attendance, and an audit trail on access to medical notes.
- Evidence that I ship the unglamorous parts: tenancy, entitlements, payment separation, migrations that are safe to run on every deploy, and a security audit of my own work.
Stack
Node/Express · Next.js · Flutter · PostgreSQL (Supabase) · Postgres full-text search & trigram · Stripe Connect & Stripe Billing · a provider-agnostic LLM layer (Claude, GPT and any OpenAI-compatible endpoint, selected by config) · Slack (Bolt) · n8n · Vercel · Hetzner