Documentation
Everything you need to understand, set up, and deploy StormGecko — a complete, multi-tenant booking & appointments SaaS.
Overview
StormGecko is a real, production-ready SaaS — not a front-end template. Each business is its own tenant with authentication, isolated data, a public booking page, payments, emails, and a team. It runs on Next.js 14, Supabase, and Stripe, and deploys to Vercel.
It ships with a zero-config demo mode: run it with no environment variables and the whole app renders with sample data and no login — perfect for evaluating before you configure anything.
Features
Self-service booking
A public booking page per business — customers pick a service, date & time (from real availability, slot intervals, capacity, buffer times, min notice) and book themselves.
Links & embed widget
Share a direct link, a per-service link, or drop an <iframe> booking widget straight into any website (Squarespace, Wix, WordPress).
Locations & Zoom
Each service can be in-person, an external URL, or Zoom — with auto-generated meeting links (unique per 1-on-1, shared for groups).
Client timezones
Visitors see slots in their own timezone alongside the business's — no more missed cross-timezone bookings.
Payments (Stripe Connect)
Set a price per service; each business connects their own Stripe account and is paid directly. The platform routes the payment.
Automatic emails
Branded confirmations, cancellations, and next-day reminders via Resend + Vercel Cron.
Real teams & roles
Invite teammates by email; they get their own login. Four built-in roles plus a custom role builder — permissions enforced server-side and at the database.
Reviews, branding, CRM
Customer ratings on the booking page, per-business logo + accent color, and a client book with visits, tags, and history.
Owner dashboard
Today/upcoming schedule, a monthly calendar, revenue & service-mix charts, live notifications, and a platform admin panel.
Tech stack
Quick start
Create a Supabase project
Sign up at supabase.com → New project. In the SQL Editor, paste the entire supabase/schema.sql and run it — this creates every table, Row Level Security policy, the auto-onboarding trigger, and the storage bucket.
Add environment variables
Copy .env.local.example → .env.local and fill in your three Supabase keys, NEXT_PUBLIC_SITE_URL, and ADMIN_EMAILS. Email, payments, and Zoom are optional and can be added anytime.
Run it
npm install then npm run dev, and open localhost:3000. Create your account — your business and booking page are generated automatically.
Deploy to Vercel
Import the repo (or use the Vercel CLI), add the same env vars, and deploy. Then set your Supabase Auth Site URL + /auth/callback redirect to your live URL.
The full step-by-step guide (with every click) ships in SETUP.md.
Integrations
Every integration is optional and independent — the app degrades gracefully without any of them.
Email — Resend
Add RESEND_API_KEY + EMAIL_FROM. For real delivery, verify your domain in Resend. Powers confirmations, reminders, and team invites.
Payments — Stripe
Enable Connect ("you collect payments and pay recipients"), add your secret + webhook keys. Optionally create a monthly Pro price for the platform subscription.
Video — Zoom
Create a Server-to-Server OAuth app with the meeting:write:admin scope; add the three ZOOM_* keys to auto-generate meeting links.
Reminders — Vercel Cron
A daily job (vercel.json) emails tomorrow’s customers. Set CRON_SECRET in Vercel to secure it.
Environment variables
| Variable | Required |
|---|---|
| NEXT_PUBLIC_SUPABASE_URL | Required |
| NEXT_PUBLIC_SUPABASE_ANON_KEY | Required |
| SUPABASE_SERVICE_ROLE_KEY | Required |
| NEXT_PUBLIC_SITE_URL | Required |
| ADMIN_EMAILS | Required |
| RESEND_API_KEY / EMAIL_FROM | Optional |
| STRIPE_SECRET_KEY / STRIPE_WEBHOOK_SECRET | Optional |
| STRIPE_PRO_PRICE_ID | Optional |
| ZOOM_ACCOUNT_ID / CLIENT_ID / CLIENT_SECRET | Optional |
| CRON_SECRET | Optional |
Security & architecture
Multi-tenant isolation
Every row is scoped to a business via Postgres Row Level Security — one business can never read or write another’s data. The public booking page reads/writes through the server (service-role) so customers never touch other tenants’ data.
Server-enforced permissions
Team roles are enforced both in the UI and on the server: every mutating action checks the member’s permission, and the database restricts direct writes to owners — so a limited member can’t escalate via the API.
Hardened surface
Cryptographically-random booking tokens, HTML-escaped email templates, owner-gated billing, a secret rotatable calendar-feed token, and fail-closed cron — all reviewed in a dedicated security audit.
Going live
- Turn "Confirm email" back ON in Supabase Auth.
- Verify your sending domain in Resend and point EMAIL_FROM at it.
- Activate Stripe, switch to live keys, and create a live-mode webhook.
- Re-create the Pro price in live mode (if you use subscriptions).
- Set CRON_SECRET in Vercel for reminders, and NEXT_PUBLIC_SITE_URL to your domain, then redeploy.
Troubleshooting
Everything shows sample data / no login
You’re in demo mode — the Supabase env variables aren’t set. Add them to switch to the real app.
Signup says "check your email"
Turn OFF "Confirm email" in Supabase Auth for testing, or ensure your Redirect URLs include /auth/callback.
Emails not arriving
On the shared Resend sender you can only email your own account address — verify a domain to reach anyone. New domains may land in spam at first; check Resend → Logs.
Payment button doesn’t appear
The service price is 0, the business hasn’t connected Stripe, or STRIPE_SECRET_KEY is unset. Priced services fall back to free until Stripe is connected.
column ... does not exist
The schema didn’t fully run — re-run supabase/schema.sql (safe on a fresh project).