Modern POS and club management UI built with SvelteKit 5 runes, Supabase, Tailwind CSS v4, and a11y‑first UI primitives.
- Auth & Users: Supabase Auth with
users
profile table and roles:admin
,staff
,secretary
. - Products & Categories: CRUD, low‑stock indicators, hierarchical categories.
- Registers & Orders: Register sessions, orders, order items, discounts/treats, daily summaries.
- Secretary tools: Birthdays/appointments, football field bookings.
- Admin: Manage users, products, categories, registers, and orders.
- Internationalization:
src/lib/i18n.ts
witht()
/tt()
utilities anden
/el
locales. - Beautiful UI: Shadcn‑inspired Svelte components exported via barrels under
src/lib/components/ui/*
. - Strict typing & linting: TypeScript strictest options, Biome (Ultracite), Knip, svelte-check, Vitest.
- SvelteKit 2, Svelte 5 runes (
$state
,$derived
,$bindable
) - Supabase (Auth, Database, Storage)
- Tailwind CSS v4 + Tailwind Variants + tailwind-merge
- Tooling: Biome (Ultracite rules), Knip, Vitest
Prerequisites: Bun 1.1+ (or Node 20+), Supabase CLI, Git.
- Clone and install
git clone https://github.com/dacrab/clubOS-svelte.git
cd clubOS-svelte
bun install
- Environment Copy example env and edit:
cp .env.example .env.local
Keys used by the app: PUBLIC_SUPABASE_URL
, PUBLIC_SUPABASE_PUBLISHABLE_KEY
(or legacy PUBLIC_SUPABASE_PUBLISHABLE_DEFAULT_KEY
). Local-only: SUPABASE_SERVICE_ROLE_KEY
(for bun run db:seed
).
- Optional: local Supabase
supabase start
supabase db reset # loads schema from supabase/migrations
bun run db:seed # seeds demo tenant, users, categories, products, orders
- Run the app
bun run dev
- Quality & tests
bun run check # svelte-check + biome + knip
bun run test # vitest
bun run dev # start dev server
bun run build # production build
bun run preview # preview production build
bun run check # typecheck + svelte-check + biome + knip
bun run check:watch # watch mode (svelte-check + ultracite fix)
bun run test # run unit tests (vitest)
bun run db:seed # seed database (requires service role key locally)
bun run db:reset # supabase db reset + seed
bun run db:restart # supabase stop && supabase start
src/lib/supabase-client.ts
– Supabase client (browser) via$env/dynamic/public
.src/lib/user.ts
– current user store and profile/tenant loader.src/lib/i18n.ts
– i18n utilities and translations (en
,el
).src/lib/components/ui/**
– reusable UI; import from barrels.src/routes/**
– SvelteKit routes (pages + endpoints):admin/*
,staff/*
,secretary/*
,reset/*
,api/*
.scripts/seed.ts
– idempotent database seeding (service role key, local only).supabase/**
– CLI config and migrations.- Config:
svelte.config.js
,vite.config.ts
,biome.jsonc
,knip.json
,tsconfig.json
.
- Runes: Use
$state
for local mutable state,$derived
for pure computed values,$bindable
for two‑way bindable props. - UI barrels: Prefer barrel imports for shared UI:
import { Card, CardContent, CardHeader, CardTitle } from "$lib/components/ui/card";
import { Button } from "$lib/components/ui/button";
import { Table, TableBody, TableCell, TableHead, TableHeader, TableRow } from "$lib/components/ui/table";
- Aliases:
$lib/*
,$app/*
,$env/*
(seeknip.json
). Avoid namespace imports. - Accessibility: Follow Ultracite a11y rules (SVG
title
, buttontype
, valid ARIA only, no positivetabIndex
). - TypeScript: Strictest settings enabled (
noUncheckedIndexedAccess
,exactOptionalPropertyTypes
,verbatimModuleSyntax
, etc.). Useimport type
for types.
- Runtime (client):
PUBLIC_SUPABASE_URL
and one ofPUBLIC_SUPABASE_PUBLISHABLE_KEY
orPUBLIC_SUPABASE_PUBLISHABLE_DEFAULT_KEY
are required. The app throws if missing. - Server/admin: use
SUPABASE_SERVICE_ROLE_KEY
. On hosted projects, prefer ansb_secret_...
key. For local Supabase CLI, you must use the legacy JWTservice_role
key (thesb_secret_...
key is not supported by the local Auth server for admin endpoints). - Local tooling only:
SUPABASE_SERVICE_ROLE_KEY
is used byscripts/seed.ts
to bypass RLS for seeding. Never expose this key to browsers or deploy hosts. - SvelteKit CSP: production CSP is strict (
script-src 'self'
,style-src 'self'
). Add hosts explicitly if you embed external resources.
- Core tables:
users
,categories
,products
,register_sessions
,orders
,order_items
,tenant_members
,facilities
,appointments
,football_bookings
,tenant_settings
,user_preferences
. - RLS: default authenticated access; admin‑level writes where appropriate.
- Seeding: creates a demo tenant/facility, admin/staff/secretary users, categories/products, an open register session, sample order, appointments, and football bookings.
- Unit tests with Vitest:
bun run test
. - Example test setup files:
vitest-env-public.ts
,vitest-setup-client.ts
.
Workflows in .github/workflows
:
ci.yml
– install, typecheck, lint, tests.codeql.yml
– code scanning.dependabot.yml
– dependency updates (Actions + npm).
Recommended repository secrets:
GITGUARDIAN_API_KEY
(if using a secrets scan workflow)
- Adapter:
@sveltejs/adapter-vercel
. - Set
PUBLIC_SUPABASE_URL
andPUBLIC_SUPABASE_PUBLISHABLE_DEFAULT_KEY
on the host. - Ensure CSP allows any required external resources.
- Scheduled keep‑alive:
vercel.json
defines a cron to hit/api/keep-alive
every 6 days at 03:17 UTC.
- "Missing PUBLIC_SUPABASE_URL or PUBLIC_SUPABASE_PUBLISHABLE_DEFAULT_KEY": set both in
.env.local
(dev) or host env (prod). - CSP blocks fonts/scripts in production: update
svelte.config.js
CSP directives. - Local Supabase ports: dev CSP already allows
127.0.0.1:54321
and Vite HMR; ensure CLI is running.
This repository enforces strict a11y and code quality via Ultracite + Biome and strict TypeScript. Prefer barrel imports and typed-only imports for a clean, tree‑shakable surface.