Everything you don't want to spend time on when prototyping or building an MVP — already done.
adapter-static and client-side routing fallback$state, $derived, $effect) for modern reactive stateuser_profiles)This project includes Cursor rules, skills, and MCP server integrations that keep AI-assisted development aligned with the project's conventions and security requirements.
.cursor/rules/)sveltekit-spa.mdc — Primary project rules covering SvelteKit conventions, runes, TypeScript, Supabase auth/database patterns, shadcn-svelte usage, form handling, onboarding flow, accessibility, error handling, and code style. Always applied.engineering-patterns.mdc — Classic engineering patterns (Factory, Repository, Service Layer, Singleton, Strategy, Observer, Adapter) adapted for a SvelteKit SPA with Supabase. Applied on demand when structuring new features..cursor/skills/)security-review — Security review and hardening guidance for the SvelteKit SPA + Supabase stack. Covers RLS policies, auth flows, XSS prevention, input validation, open redirect prevention, session management, and a deployment checklist. Invoke with /security-review to scan for vulnerabilities.list-sections -> get-documentation (all relevant sections) -> svelte-autofixer until no issues remain.src/routes/
├── +layout.svelte
├── +layout.ts # SPA config (ssr = false)
├── (public)/
│ ├── +page.svelte
│ └── (auth)/
│ ├── login/+page.svelte
│ ├── signup/+page.svelte
│ ├── verify-email/+page.svelte
│ ├── reset-password/+page.svelte
│ ├── set-new-password/+page.svelte
│ └── account-deleted/+page.svelte
└── (protected)/
└── app/
├── +page.svelte
├── account/+page.svelte
└── onboarding/ # optional (feature-flagged)
├── +page.svelte
├── step-1/+page.svelte
└── step-2/+page.svelte
src/lib/
├── auth/
│ ├── state.svelte.ts # reactive auth state + Supabase listener
│ ├── actions.ts # login/signup/reset/account actions
│ ├── guards.ts # protected route guard helpers
│ ├── errors.ts # auth error message mapping
│ └── types.ts
├── config/
│ └── features.ts # feature flags + onboarding step config
├── helpers/
│ ├── name-helpers.ts # display name formatting
│ └── redirect-helpers.ts # safe redirect validation (open redirect prevention)
├── services/
│ └── onboarding-service.ts # onboarding business logic (Result-based)
├── supabase/
│ ├── client.ts # browser Supabase client
│ └── profiles.ts # user_profiles helpers + RPCs
└── components/
├── auth/
├── account/
├── onboarding/ # optional (feature-flagged)
│ ├── onboarding-shell.svelte
│ └── onboarding-schemas.ts
└── ui/
npm install
Create a .env file in the project root:
PUBLIC_SUPABASE_URL=https://your-project-ref.supabase.co
PUBLIC_SUPABASE_PUBLISHABLE_KEY=your_publishable_anon_key
Notes:
PUBLIC_ prefix intentionally exposes these values to browser code.In Supabase dashboard:
window.location.origin, so both local and production origins must be allowlisted.Recommended configuration:
https://your-domain.devhttp://localhost:5173/verify-email/http://localhost:5173/set-new-password/http://localhost:5173/reset-password/https://your-domain.dev/verify-email/https://your-domain.dev/set-new-password/https://your-domain.dev/reset-password/https://www.your-domain.dev/verify-email/https://www.your-domain.dev/set-new-password/https://www.your-domain.dev/reset-password/Apply the migration in supabase/migrations/ via the Supabase SQL editor or the CLI:
npx supabase link --project-ref <your-project-ref>
npx supabase db push
The single migration sets up the user_profiles table with RLS policies, CHECK constraints, delete_current_user and complete_onboarding security definer RPCs, and a trigger protecting onboarding_completed_at from direct writes.
npm run dev
This boilerplate includes an optional multi-step onboarding flow that guides new users through profile setup before they can access the app. It is controlled by a single feature flag.
src/lib/config/features.ts via featureFlags.enableOnboarding. When disabled, users go straight to the app after login.onboardingSteps (same file). Add, remove, or reorder steps without touching route files.src/routes/(protected)/app/+layout.svelte) redirects users who haven't completed onboarding to the correct step. No per-page guard logic needed.user_profiles via helpers in src/lib/supabase/profiles.ts. Users can resume where they left off.enableOnboarding: true in src/lib/config/features.ts (this is the default).enableOnboarding: false in src/lib/config/features.ts.Edit the onboardingSteps array in src/lib/config/features.ts to change questions, labels, or field keys. For each field you add or change, update:
OnboardingFieldKey type (same file)src/lib/components/onboarding/onboarding-schemas.tsuser_profiles columns in the onboarding migrationThe browser is untrusted. Supabase (Postgres RLS + Auth) is the only enforcement point. Client-side checks (auth guards, Zod schemas, route gating) improve UX but provide zero security.
PUBLIC_SUPABASE_PUBLISHABLE_KEY is safe to expose — it can only do what RLS allowsauth.uid()security definer RPCs assert auth.uid() IS NOT NULL and are restricted to the authenticated roleBEFORE UPDATE trigger protects onboarding_completed_at from direct writes — only the complete_onboarding RPC (security definer) can set itCHECK constraints enforce string length limits at the database level, matching client-side Zod max() limitsnext= query parameter) are validated with getSafeRedirect() to prevent open redirectsservice_role key is never used in frontend codeUse /security-review in Cursor to scan for vulnerabilities against the full checklist.
Useful policy audit query:
select tablename, policyname, cmd, roles, qual, with_check
from pg_policies
where schemaname = 'public'
order by tablename, policyname;
| Command | Description |
|---|---|
npm run dev |
Start dev server |
npm run build |
Build for production |
npm run preview |
Preview production build |
npm run check |
Svelte + TypeScript checks |
npm run lint |
ESLint + Prettier checks |
npm run format |
Format code |
This repository includes a GitHub Pages workflow at .github/workflows/deploy-pages.yml that:
npm run buildbuild directory as a Pages artifactactions/deploy-pagesAdd these in Repository -> Settings -> Secrets and variables -> Actions:
PUBLIC_SUPABASE_URLPUBLIC_SUPABASE_PUBLISHABLE_KEYThese are injected during CI build in the Pages workflow.
your-domain.dev)In Repository -> Settings -> Pages:
your-domain.devDNS records should include:
A records to GitHub Pages IPs (185.199.108.153, .109.153, .110.153, .111.153)AAAA records to GitHub Pages IPv6 endpointswww CNAME to YOUR-GITHUB-USERNAME.github.io