Why this one
Every SaaS starts the same way: three weeks of plumbing before you write a line that's actually yours. TanBase Web is that plumbing, finished — and it's multi-tenant from the first commit, which is the part most starters leave you to retrofit.
- Organisations, not just users. Workspaces, role-based access control across Owner / Admin / Member, and Slack-style magic-link invites with a pending-invite dashboard. Retrofitting tenancy onto a single-user starter is a rewrite; this begins there.
- Billing that handles the tax. Paddle as merchant of record, so VAT, sales tax and compliance are their problem. Plans render from your Paddle catalogue, and the subscription lifecycle — overlay checkout, plan switching with proration, the customer portal, invoices — is wired and webhook-driven into Postgres.
- Typed to the edges. TanStack Start on React 19 and Vite, with file-based routing and server functions. The client and server share types, so a renamed column surfaces as a compile error rather than a runtime
undefined. - Security migrations, not security intentions. Row-level security on every table, plus two dedicated hardening migrations that close the gaps a first pass leaves behind.
What's included
Auth and organisations — magic-link and OAuth sign-in through Supabase, multi-tenant workspaces, role-based access control, an onboarding flow for new accounts, and session handling that works with server functions.
Invites — magic-link team invitations, a pending-invite management view, automatic role assignment on acceptance, and the email templates to go with them.
Billing — Paddle Billing as merchant of record. Monthly and yearly plans read from your catalogue, overlay checkout, proration on plan changes, a customer portal session, invoice download scoped so a user can only fetch their own, and a webhook route that verifies the raw body before touching the database.
Realtime notifications — live in-app notifications over Supabase Realtime, toasts for immediate feedback, and a notification centre with read and unread states.
Email and marketing — transactional email through Resend with React Email templates you can preview locally, a waitlist with its own landing page, and an MDX-powered blog for content pages.
Theming and SEO — dark and light with system detection, brand colours as theme variables, dynamic OG images, and the full complement of meta tags, sitemap, robots.txt and web manifest.
Analytics and monitoring — PostHog for privacy-first product analytics with custom event tracking, and Sentry for error tracking, instrumented on the server too.
Backend — nine Supabase migrations covering the schema, row-level security, organisation enrichment and Paddle billing, two of them dedicated to security hardening. Local stack via the Supabase CLI, with type generation after every schema change.
Stack
| Layer | Choice |
|---|---|
| Framework | TanStack Start — React 19, Vite, file-based routing, server functions |
| Database, auth | Supabase — Postgres, RLS, Realtime |
| Payments | Paddle, merchant of record |
| Styling | Tailwind CSS v4 + shadcn/ui |
| Resend + React Email | |
| Analytics | PostHog · Monitoring Sentry |
| Deployment | Cloudflare Workers via Wrangler |
| Type safety | TypeScript strict + Zod · Lint Biome |
What's not included, on purpose
There is no admin dashboard, no API rate limiting and no i18n — all three are on the roadmap rather than in the box. There's no mobile client: if you need one against the same backend, that's TanBase Universal. Analytics and monitoring are optional, so the app runs without PostHog or Sentry keys.
Getting it running
Clone it, copy env.example to .env.local, and fill in Supabase, Resend and Paddle credentials. pnpm supabase:start brings up the local stack and applies all nine migrations; pnpm dev serves it on port 3000. Paddle's sandbox is enough for development — you don't need a live merchant account to see checkout work end to end.
Deployment is pnpm deploy, which builds and ships to Cloudflare Workers through Wrangler, with production secrets set via wrangler secret put.