Skip to content

Quickstart

  • Bun 1.4 or newer: runtime, package manager and test runner for the whole repository.
  • Docker: runs the local Postgres.
  • Python 3.13 + uv: only for services/ai.
  • Rust toolchain: only for apps/native (the Tauri shells).

Every command below is the same in bash and in PowerShell.

  1. Install dependencies and copy the env templates:
Terminal window
bun install
cp .env.example .env # API, db tooling, compose
cp apps/web/.env.example apps/web/.env
  1. Generate BETTER_AUTH_SECRET. It ships empty, and the API refuses to boot without it. Put the output in .env:
Terminal window
bun -e "console.log(require('crypto').randomBytes(32).toString('hex'))"
  1. Start Postgres, apply the migrations and run the app:
Terminal window
bun run db:up # Postgres 17 in Docker (127.0.0.1:5433 by default)
bun run db:migrate # applies packages/db/drizzle/*.sql (exits 1 if any stay pending)
bun run dev:app # api on :3000 + web on :5173

Then open http://localhost:5173. The defaults in .env.example are enough for local development: emails print to the API terminal, billing and social sign-in stay off, and nothing is capped. See Configuration for what each variable switches on.

Command What
bun run dev every app with a dev script (api, web, site :4321, docs :4322)
bun run dev:desktop Tauri desktop shell around the dev server (needs Rust)
bun run verify lint, typecheck and tests, in CI’s order. Run it before every push
bun run check · bun run test · bun run lint · bun run build the same steps one at a time, plus the build. test runs Svelte components in a real browser and installs Playwright’s Chromium on first run
bun run test:e2e Playwright against a production preview of apps/web
bun run admin:create -- --email … [--name …] create the first platform administrator. The password comes from ADMIN_PASSWORD or a prompt
bun run seed demo organization, workspaces, documents and jobs
cd services/ai && uv sync && uv run uvicorn ai.main:app --reload the Python service on :8000

The full list is in Commands.

  1. Sign up at /signup with email and password. In development the verification email prints to the API terminal. REQUIRE_EMAIL_VERIFICATION decides whether a session is issued before the address is verified (default: only in production).
  2. Create an organization. It is the tenant and billing entity that owns members, invitations and teams. New sessions start in your first organization. The sidebar switcher changes it.
  3. Invite people from /app/team. Invitations are emailed as links that expire after 7 days. Give each person the owner, admin or member role.
  4. Create a workspace from /app. Workspaces hold the product data. Each one belongs to the organization and optionally to a team.

Platform administrators are users whose role is admin. This role is independent of organization roles. Create the first one from the command line, then promote others from /admin/users:

Terminal window
ADMIN_PASSWORD='' bun run admin:create -- --email you@example.com --name 'You'
# add --yes to promote an account that already exists

With ADMIN_PASSWORD unset the script prompts for one. The password is never read from the command line, because arguments stay in shell history and are visible in ps.

bun run seed fills a fresh database with a demo organization: a team, two workspaces, three documents, six finished jobs with their credit-ledger rows and an audit trail. The owner is demo@example.com / demo-password-1234 (SEED_PASSWORD overrides the password). The script is idempotent and refuses to run with NODE_ENV=production. It writes no storage objects, so a seeded document can be read and searched but not downloaded.

apps/
web/ SvelteKit application: auth, orgs/teams, workspaces, billing, admin (thin client)
api/ Hono on Bun: Better Auth, oRPC router (RPC + REST/OpenAPI), webhooks
site/ Astro: marketing, pricing, blog, SEO
docs/ Astro Starlight: this documentation
native/ Tauri 2: desktop + mobile shells around apps/web's static build (no IPC)
packages/
api-contract/ oRPC + Zod contract: the API's single source of truth
api-client/ typed client for the contract (browser, SSR, Tauri, Bun scripts)
auth/ Better Auth server instance (API) and Svelte client factory (frontends)
db/ Drizzle schema (generated auth tables + ours), migrations, Bun.SQL client
billing/ plan catalog + Stripe client
email/ provider abstraction (Resend / console) + templates
env/ validated server environment (t3-env + Zod)
storage/ document bytes: local disk with signed URLs, or S3/R2/MinIO
ui/ shared Svelte 5 components (shadcn-svelte/bits-ui + thin form wrappers) + Tailwind tokens
tsconfig/ shared TypeScript configs
services/
ai/ FastAPI service (uv): internal, called by the API only
infra/
compose.yml self-hosted stack: postgres · api · web · ai · caddy
compose.dev.yml Postgres for local development
caddy/ subdomains.Caddyfile (public) · single-origin.Caddyfile (tailnet/LAN)
docker/ Dockerfile.static (Astro sites → Caddy)

Internal packages are consumed from source. There is no build step. Shared dependency versions are pinned once in the root package.json catalog and referenced with catalog:.