Install CentraKit, start the local Supabase stack and the apps with or without Portless, and sign in with the seeded personas.
package.json.pnpm supabase:start runs the local Supabase stack on the CLI's native runtime, so no container engine is needed..env.local. With the repository linked to Vercel, pnpm env:pull writes .env.local (development) and .env.production.local (production). Without a link, copy .env.example to .env.local and fill in the required values.Install dependencies from the repository root:
pnpm installEvery app reads the root env files through loadMonorepoEnv, so there are no per-app .env files. See Environment variables.
Keep local-only values in .env.development.local. pnpm env:pull rewrites .env.local but leaves this file alone.
pnpm dev:hosted starts the SaaS app and the API against the hosted development project instead of the local stack: values in .env.local take precedence over .env.development.local. pnpm env:local rewrites the local Supabase values in .env.development.local without restarting the stack.
pnpm supabase:start writes the Supabase values into this file for the local project it started: NEXT_PUBLIC_SUPABASE_URL, NEXT_PUBLIC_SUPABASE_PUBLISHABLE_KEY, SUPABASE_SECRET_KEY, POSTGRES_URL (direct Postgres for the API's idempotency keys, rate limits and scheduled jobs), and SMTP_HOST and SMTP_PORT for Mailpit. It replaces those keys in place and keeps every other line. Run pnpm --filter @workspace/supabase-runtime supabase:env to write them again without restarting.
# Leave NEXT_PUBLIC_SITE_URL unset, or set it to https://localhost,
# so the default brand resolves to https://app.localhost.
# NEXT_PUBLIC_SITE_URL=https://localhostStart the local stack, then apply the schema and seeds:
pnpm supabase:start
pnpm supabase:syncpnpm supabase:start generates a local JWT signing key if needed, starts the local Supabase project and writes its URLs and keys to .env.development.local. pnpm supabase:sync pushes pending migrations and seeds to the local database, falls back to a full reset when the push fails, and then seeds the Storage buckets.
Use pnpm supabase:reset only when you want a clean database. It drops all local data and replays every migration and seed. After a reset, sign in again, because existing browser sessions refer to the previous auth database.
The local stack runs Postgres, Auth, Storage, Realtime and imgproxy, so Storage /render/image URLs behave like hosted image transforms. The pooler service is intentionally stopped. The project runs on the Supabase CLI stack engine ([experimental] stack = true in supabase/config.toml): Postgres starts right away and every other service starts on its first request and stops again when idle. Each git worktree and branch gets its own project with its own ports and data. More detail is in Supabase local dev.
| Command | Starts |
|---|---|
pnpm dev:portless | SaaS and API on https://app.localhost and https://api.localhost. |
pnpm dev | SaaS and API with plain next dev on localhost ports. |
pnpm dev:api:portless | Only the API, on https://api.localhost. |
pnpm dev:api | Only the API, with plain next dev. |
pnpm dev:docs:portless | The API and the docs site on https://docs.localhost/docs. |
pnpm dev:marketing:portless | The API and the marketing site. |
pnpm dev:showcase:portless | Only the showcase. |
pnpm dev:all:portless | Every app that has a dev:portless task. |
Use the Portless commands for browser testing. The SaaS app calls the API for chat, inbox, AI suggestions and other features, which is why pnpm dev and pnpm dev:portless always start both. The plain next dev commands are useful in cloud and container environments where Portless is not available. Each of the docs, marketing and showcase commands also has a variant without :portless.
The docs app is mounted at /docs through basePath, the same path it has on the app host in production, so open https://docs.localhost/docs when you run it on its own.
In production the API, the MCP server and the docs are the /api, /mcp and /docs paths on each brand's app host, and so is the OAuth protected resource metadata at /.well-known/oauth-protected-resource. Locally there are no vercel.json rewrites, so the SaaS server forwards the same paths to https://api.localhost and https://docs.localhost. https://app.localhost/api/v1/health and https://app.localhost/.well-known/oauth-protected-resource reach the API, and https://app.localhost/docs works while the docs server runs. Set LOCAL_API_ORIGIN when the API runs somewhere else, as the E2E suite does with http://127.0.0.1:3101. The marketing and showcase apps are not deployed; their commands remain for local work.
One SaaS server serves every brand, and the brand comes from the request host. pnpm dev:portless registers eight Portless aliases that point at the SaaS port, so the local brand hosts are:
| Brand | Local host |
|---|---|
| CentraKit | https://app.localhost |
| MechUp | https://mechup.localhost |
| StableDock | https://stabledock.localhost |
| Caresly | https://caresly.localhost |
| PropDock | https://propdock.localhost |
| MarryDuck | https://marryduck.localhost |
| SignalDock | https://signaldock.localhost |
| Spacelio | https://spacelio.localhost |
| LegalDock | https://legaldock.localhost |
The aliases are re-registered each time the SaaS server starts, so they always follow its current port. Cookies are host-only, so sign in on each brand host separately. Each organization belongs to one brand. The CentraKit host lists and opens every organization, and each product brand host only its own. The local Auth redirect allow list in supabase/config.toml accepts every brand host.
Domain events such as a sent quote or invoice go through the outbox and the background job queues, which Vercel Cron drains every minute in production. In development the API calls the same /api/v1/internal/jobs/drain route every minute itself, so workflow emails reach Mailpit and webhooks go out about a minute after the action. When CRON_SECRET is not set, the API generates one for the running process.
pnpm dev:oauth starts the SaaS app on a localtest.me host for testing Google sign-in. See Authentication.
Every seeded user has the password Password123!, except the PropDock owner propdock@example.com, who uses PropDock123!, the MarryDuck owner marryduck@example.com, who uses MarryDuck123!, the SignalDock owner signaldock@example.com, who uses SignalDock123!, the Spacelio owner spacelio@example.com, who uses Spacelio123!, and the LegalDock owner legaldock@example.com, who uses LegalDock123!. test@example.com (Lieke Hofstra) is the central test account. It owns the four shop organizations and the Caresly care organization, and it is an admin of the PropDock, MarryDuck, SignalDock, Spacelio and LegalDock organizations, which each have their own owner and staff. Each organization covers its own industry:
| Organization | Brand | Business |
|---|---|---|
tractor-service | MechUp | Tractor and garden machinery repair. The deepest seed, with every domain state. |
auto-garage | MechUp | Car garage with APK inspections, tyre storage and courtesy cars. |
bike-scooter-shop | CentraKit | Bicycle and scooter shop with retail sales, repairs and a webshop. |
equestrian-center | StableDock | Riding school and livery stable with boarders, lessons and farrier visits. |
elderly-care | Caresly | Dutch elderly care organization (Zorggroep De Lindehof) with a nursing home location and a district nursing team: client records, daily reports, rosters, care tasks and a family inbox. |
property-management | PropDock | Amsterdam property manager (Canalside Property Management) with long-term rooms and apartments and short-stay studios: 26 customers across owners, tenants, applicants and guests, units as assets, maintenance work orders, rent and deposit invoices, turnovers and a WhatsApp inbox. |
wedding-planning | MarryDuck | Vienna wedding planner (Alpine Vows Wedding Planning) with full-service, partial and day-of planning and destination weddings: 24 customers across couples in every planning stage, prospects, past and cancelled weddings and a corporate gala, weddings with their venue bookings and room blocks as assets, vendor tasks, deposit and balance invoices and a couples WhatsApp inbox. |
event-services | SignalDock | Utrecht event services company (Northpoint Event Services) that supplies event security, crowd control, temporary wifi and access gates and finds work from signals: 24 accounts across the sales funnel, scored permit, tender and business register signals as assets, follow-up tasks, quotes, crew invoices, a signal desk WhatsApp inbox and a Brabant partner on the portal. |
accounting-firm | Spacelio | Rotterdam accounting firm (Harbourline Accountants) with annual accounts, tax returns, payroll and deal work: 24 customers across business and private clients, prospects and an archived client, engagement files as assets with document checklists, a data room for a company sale, engagement letters, invoices with the HLI number prefix, client document requests and a client WhatsApp inbox. |
law-firm | LegalDock | Hague law firm (Lindenberg Advocaten) in employment, corporate, family and real estate law: 24 clients across prospects with a conflict check, active, on hold and archived matters, matter files as assets, procedural deadlines, engagement letters as quotes, hourly, fixed-fee and subscription invoices with trust money deposits, and a client WhatsApp inbox. |
| Access | |
|---|---|
test@example.com | Owner of all four shop organizations and elderly-care, admin of property-management, wedding-planning, event-services, accounting-firm and law-firm, the seeded system admin, and a portal contact of De Haan Landscaping. |
test1@example.com | Member of tractor-service, set up in People as a field service mechanic (Jeroen Bakker). |
test2@example.com | Viewer in bike-scooter-shop (Sanne Visser). |
test3@example.com | Portal-only private customer of both tractor-service and auto-garage (Pieter Brouwer). |
test4@example.com | Portal-only contact for the business customer Green Acre Farms BV in tractor-service (Hendrik van Laar). |
test5@example.com | Portal-only boarder at equestrian-center (Charlotte Veenstra). |
test6@example.com | Portal-only family member of client 7001 in elderly-care (Ellen Kleinjan, daughter of Johanna de Vries). |
propdock@example.com | Owner of property-management (Hannah Whitfield), with the password PropDock123!. Sign in on https://propdock.localhost. |
prop.tenant@example.com | Portal-only tenant of Room 2 at Prinsengracht 412 in property-management (Emma Clarke). |
prop.owner@example.com | Portal-only owner of Prinsengracht 412 in property-management (Richard Hale). |
marryduck@example.com | Owner of wedding-planning (Eleanor Ashdown), with the password MarryDuck123!. Sign in on https://marryduck.localhost. |
wed.couple@example.com | Portal-only bride of customer 9001 in wedding-planning (Amelia Sinclair). |
wed.parent@example.com | Portal-only mother of the bride of customer 9001 in wedding-planning (Diane Whitcombe). |
signaldock@example.com | Owner of event-services (Harriet Langford), with the password SignalDock123!. Sign in on https://signaldock.localhost. |
sig.client@example.com | Portal-only contact of the festival client 10001 in event-services (Freya Lockhart). |
sig.partner@example.com | Portal-only contact of the Brabant partner 10002 in event-services (Gavin Stroud), who sees the leads offered to the partner. |
spacelio@example.com | Owner of accounting-firm (Philippa Grantham), with the password Spacelio123!. Sign in on https://spacelio.localhost. |
space.client@example.com | Portal-only director of client 11001 Bakker Holding in accounting-firm (Cordelia Ashcombe). |
space.buyer@example.com | Portal-only buyer-side adviser of client 11005 Noordzee Capital Partners in accounting-firm (Dominic Brewster), with access to the data room. |
legaldock@example.com | Owner and managing partner of law-firm (Margaret Hollingsworth), with the password LegalDock123!. Sign in on https://legaldock.localhost. |
law.client@example.com | Portal-only general counsel of client 12001 Brightwater Foods BV in law-firm (Geoffrey Talbot). |
law.private@example.com | Portal-only private client 12002 with a family law matter in law-firm (Lavinia Ellison). |
The seed also creates role-specific accounts for permission testing:
| Access | |
|---|---|
support@example.com | The system-support system role, with no organization membership. |
owner@example.com | Finance and settings role in all four shop organizations and elderly-care. |
operator@example.com | Admin in tractor-service and auto-garage. |
team.lead@example.com | Service planner in tractor-service and auto-garage. |
crm.editor@example.com | Sales advisor in tractor-service and bike-scooter-shop. |
assets.editor@example.com | Parts manager in tractor-service and bike-scooter-shop. |
viewer@example.com | Read-only custom role in tractor-service. |
bike.mechanic@example.com | Mechanic in bike-scooter-shop. |
bike.retail@example.com | Sales advisor in bike-scooter-shop. |
garage.apk@example.com | Mechanic and APK inspector in auto-garage. |
garage.advisor@example.com | Service advisor in auto-garage. |
stable.manager@example.com | Admin in equestrian-center. |
stable.instructor@example.com | Instructor with the service planner role in equestrian-center. |
stable.viewer@example.com | Read-only custom role in equestrian-center. |
care.manager@example.com | Admin (location manager) in elderly-care (Marjolein Brugman). |
care.evv@example.com | Primary carer (EVV'er) with the seed-care-evv custom role in elderly-care (Anouk Rietdijk): clients, notes, tasks, inbox approval and agenda. |
care.nurse@example.com | District nurse (level 5) with the seed-care-professional custom role in elderly-care (Samira Bouzid). |
care.carer@example.com | Certified carer (level 3, mostly night shifts) with the seed-care-professional custom role in elderly-care (Daan Lubbers). |
care.planner@example.com | Planner with the seed-care-planner custom role in elderly-care (Renske Veltman). |
prop.manager@example.com | Admin in property-management who runs finance and owner relations (Daniel Fairbanks). |
prop.leasing@example.com | Leasing coordinator with the seed-prop-leasing custom role in property-management (Priya Raman): waiting list, viewings, screening and leases. |
prop.host@example.com | Guest operations lead with the seed-prop-host custom role in property-management (Lucas Moreau): guest inbox, bookings and turnovers. |
prop.maintenance@example.com | Maintenance coordinator with the seed-prop-maintenance custom role in property-management (Tom Gallagher): work orders, suppliers and materials. |
prop.cleaner@example.com | Housekeeping lead with the seed-prop-cleaner custom role in property-management (Ana Ferreira): assigned turnovers only. |
wed.manager@example.com | Admin in wedding-planning who runs finance and the business (Oliver Kingsley). |
wed.planner@example.com | Lead planner with the seed-wed-planner custom role in wedding-planning (Grace Whitlock): couples, tasks, the agenda, quotes and the inbox. |
wed.coordinator@example.com | Day-of coordinator with the seed-wed-coordinator custom role in wedding-planning (Rosie Calder): wedding day timelines and assigned weddings. |
wed.vendors@example.com | Vendor manager with the seed-wed-vendors custom role in wedding-planning (Samuel Rowntree): suppliers, purchase orders and vendor contracts. |
wed.assistant@example.com | Planning assistant with the seed-wed-assistant custom role in wedding-planning (Lily Fenwick): RSVPs, stationery and checklists on assigned weddings. |
sig.manager@example.com | Admin in event-services who runs operations, finance and the business (Callum Pemberton). |
sig.bizdev@example.com | Business developer with the seed-sig-bizdev custom role in event-services (Nadia Hollis): opportunities, meetings, quotes and the inbox. |
sig.analyst@example.com | Signal analyst with the seed-sig-analyst custom role in event-services (Felix Marlowe): reviews and scores incoming signals. |
sig.ops@example.com | Event operations lead with the seed-sig-ops custom role in event-services (Owen Treadwell): crews, site surveys, kit and the event agenda. |
sig.assistant@example.com | Office and planning assistant with the seed-sig-assistant custom role in event-services (Ivy Redfern): account preparation, follow-up tasks and the meeting agenda. |
space.manager@example.com | Admin in accounting-firm who runs the office and payroll (Martin Elsworth). |
space.accountant@example.com | Senior accountant with the seed-space-accountant custom role in accounting-firm (Naomi Pritchard): clients, engagement files, tasks, documents, engagement letters and invoices. |
space.tax@example.com | Tax adviser with the seed-space-tax custom role in accounting-firm (Laurence Thackeray): tax returns, tasks, documents and the knowledge base. |
space.deals@example.com | Deal adviser with the seed-space-deals custom role in accounting-firm (Julian Hartigan): deal clients and the data room only. |
space.assistant@example.com | Junior assistant with the seed-space-assistant custom role in accounting-firm (Zoe Marchbank): document requests, reminders and checklists. |
law.manager@example.com | Admin in law-firm who runs the office and finance (Nathan Cresswell). |
law.lawyer@example.com | Senior associate in employment law with the seed-law-lawyer custom role in law-firm (Edward Blackwood): clients, matter files, tasks, the agenda, documents, engagement letters and time. |
law.paralegal@example.com | Paralegal with the seed-law-paralegal custom role in law-firm (Imogen Radcliffe): conflict checks, documents, tasks and deadlines, without finance. |
law.billing@example.com | Legal secretary with the seed-law-billing custom role in law-firm (Felicity Wainwright): invoices, time review and trust money deposits. |
law.trainee@example.com | Trainee lawyer with the seed-law-trainee custom role in law-firm (Rupert Langley): assigned matters, documents and own time. |
disabled@example.com | A mechanic in tractor-service whose account is disabled, so signing in is refused. |
external@example.com | Owner of harbor-marine-service and of cedar-hvac-rental, which is disabled. No access to the shop organizations. |
Each shop organization has customers, contacts, customer assets, products and inventory, tasks, agenda items, quotes, invoices and orders in every status, plus files, inbox threads, chat history, notifications, employees, time, expenses, hiring, workflows, audit logs and billing data. Seed files live in supabase/seeds/, and each one starts with a -- Covers: comment that lists the scenarios it seeds.
pnpm supabase:sync warns about unset Google OAuth variables. Google sign-in is optional locally, so the warning is safe to ignore..env.local are placeholders, so billing flows do not work locally. Everything else does./api, /mcp, /.well-known/oauth-protected-resource and /docs to https://api.localhost and https://docs.localhost. LOCAL_API_ORIGIN overrides the API target.postinstall outside CI. Run pnpm exec lefthook install --force to refresh them..localhost hosts and sign in again.https://my-branch.app.localhost. The brand aliases have no worktree prefix, so https://mechup.localhost, https://stabledock.localhost, https://caresly.localhost, https://propdock.localhost, https://marryduck.localhost, https://signaldock.localhost, https://spacelio.localhost and https://legaldock.localhost point at whichever SaaS server started last. The local Auth redirect allow list in supabase/config.toml accepts https://*.app.localhost/**, so sign-up confirmation, magic link and password reset emails link back to that host. A running stack keeps the list it started with, so run pnpm supabase:stop and pnpm supabase:start after changing it. For a host that is not on the list, Auth falls back to site_url.content_path. The link verifies through Auth and lands on /auth/confirm with a PKCE code, so open it in the browser where you signed up. Hosted projects keep the token_hash template from [remotes.*] in supabase/config.toml.pnpm supabase:start and pnpm supabase:sync on the new branch. pnpm exec supabase stack list shows every local project, and pnpm --filter @workspace/supabase-runtime supabase:destroy deletes the current one and its data.Last updated on