Skip to content

Quickstart

The setup guide is QUICKSTART.md at the root of the repository, the one copy kept up to date. It takes a fresh clone to a running app in about ten minutes, then covers the first administrator, documents and AI jobs, the accounts and keys you need next, deployment and the launch checklist. This page is its outline; where the two differ, QUICKSTART.md is right.

You need Bun 1.4 or newer, and Docker with Compose and a running daemon for the local Postgres, or an existing Postgres 17 with pgvector instead of Docker. Python 3.13 and uv are only for the AI service, Rust only for the Tauri shells. Node.js is optional, but if it is installed it must be 22.17 or newer: Vite runs under it.

Start from a release, not from the kit’s main: UPGRADING.md’s first block checks out the release you name (name the newest: git tag -l "kit/*" --sort=-v:refname lists them) and files the kit’s tags under kit/, which later upgrades merge from. Then:

Terminal window
bun install
bun run setup # every .env from its template, with generated secrets
bun run doctor # read-only: prerequisites and configuration
bun run db:up # Postgres 17 in Docker on 127.0.0.1:5433
bun run db:migrate
bun run dev:app # API on :3000, app on http://localhost:5173

On Windows, run them in PowerShell; QUICKSTART.md, Step 0, says what to do once in a clone checked out with CRLF line endings, and how stopping the API differs there.

Without Docker, point DATABASE_URL in the root .env at a development database on your own Postgres, run bun run doctor -- --database=external instead of bun run doctor, and skip db:up. The doctor then skips its Docker checks; it does not install or configure Postgres. Create that database with createdb -T template0 --locale=C <name>. Homebrew’s postgresql@17 is keg-only, so on a Mac createdb and psql are not on your PATH until you run brew link --force postgresql@17 or add $(brew --prefix postgresql@17)/bin to it. Every id is text, and under a language collation, the default a Homebrew or distribution Postgres gives a new database, an index probe on a text key costs about 7 µs against 0.7 µs under C. C sorts by byte value, so a list users see sorted by name names an ICU collation in its query (order by name collate "und-x-icu"). Once the database answers, the doctor prints its collation and warns when it is not C. A Docker database db:up creates from this release on is in the builtin C.UTF-8 locale; a volume created before keeps en_US.utf8, and gets that warning. Give the database’s role CREATEDB (createuser --createdb <role>, or ALTER ROLE <role> CREATEDB): the database suites and test:e2e:full create scratch databases beside yours, and doctor warns without it.

Rename the kit before setup if you already have a product name, on the branch UPGRADING.md names so later releases merge cleanly (QUICKSTART.md, Step 1, item 2). setup never replaces a value you set, so it is safe to run again. It also gives the marketing site and the docs their local SITE_URL, so bun run build works on a fresh clone.

The AI service that runs document jobs starts in its own terminal, with the SERVICE_TOKEN setup shared between it and the API:

Terminal window
cd services/ai && uv sync && uv run uvicorn ai.main:app --reload --port 8000

Configuration explains every variable, and Commands lists every command. When you add your first feature, follow the worked feature example.

For data that belongs to one organization’s workspace, follow Your first tenant-scoped feature.

  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. /app offers it in one click, already named after you, until you have one. New sessions start in your first organization. The organization’s menu at the top of the sidebar changes it and opens its settings.
  3. Invite people from Members in the settings dialog (/app/organization/members). 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. Promote the account you created during signup, then manage others from /admin/users:

Terminal window
bun run admin:create -- --email you@example.com --name 'You' --yes

--yes confirms promotion of the existing account and leaves its password unchanged. For a new email, the script creates the account and reads its password from ADMIN_PASSWORD or an interactive prompt. The password is never read from a command-line argument, 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. The documents’ files go to storage the way an upload does, so they download, and Extract, Summarize and Index run on them.

A deploy publishes your product, so check what it still says about the kit before the first one:

  • The marketing site. Its copy and its OG images are the kit’s until you rewrite them. The changelog and the blog start with one draft sample each (draft: true), which bun run dev:site shows and no build publishes; write your own entries in apps/site/src/content/changelog and blog. The kit’s own release notes are CHANGELOG.md and never reach your site.
  • The legal pages are templates. A production build for a real origin refuses them while a **[placeholder]** or the “review with counsel” note is left, and names each file; ALLOW_LEGAL_PLACEHOLDERS=1 publishes them anyway, for a staging deployment.
  • The docs. A docs build serves your product’s documentation by default, apps/docs/src/content/product: a two-page start and the interactive API reference. This manual is apps/docs/src/content/docs; bun run dev:manual serves it locally, and no build includes it unless it sets DOCS_CONTENT=kit.

bun run rename prints the full list as the end of its checklist.

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: your product's docs, and this manual (`bun run dev:manual`)
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:.