Orbit documentation

Installation

How to run Orbit locally for development, with Docker Compose, and on Dokploy.

Components

Service Tech Default port Role
api Hono (Node 22) 8000 REST API /v1; runs migrations at start-up; bootstraps the first superadmin
worker Node 22 – Background jobs: imports, reminders, report schedules, cleanup
web Next.js 3100 (3000 in container) Tenant dashboard and public portal; proxies /v1 to the API
overseer Next.js 3101 (3000 in container) Superadmin console
docs Node 22 3102 (3000 in container) This documentation as a website
postgres PostgreSQL 16 5462 → 5432 Data. Schema-per-tenant
seaweedfs SeaweedFS S3 8334 → 8333 File storage (any S3-compatible store works)
createbucket aws-cli – One-off: creates the bucket

Local development

Requirements: Node 22, pnpm 11, Docker.

cp .env.example .env
pnpm install
pnpm infra:up                                  # postgres (:5462) + SeaweedFS S3 (:8334) + bucket
pnpm migrate                                   # public + all tenant schemas
pnpm --filter @orbit/api dev:setup acme medium # tenant "acme" with demo data and admin@acme.test
pnpm dev                                       # api :8000, worker, web :3100, overseer :3101

With SMTP_HOST empty, emails (sign-in codes, confirmation links, password resets) are written to the API log instead of being sent:

[mail:disabled] to=someone@example.org subject="Orbit: confirm your application"
Please confirm your application within 72 hours:
http://localhost:3100/confirm/acme/…

Full stack in Docker

cp .env.example .env                       # edit secrets first
docker compose up -d --build               # postgres, seaweedfs, api, worker, web, overseer, docs
docker compose run --rm setup acme medium  # optional demo tenant
  • Every app container reads .env. Compose overrides only what differs inside its network: DATABASE_URL, S3_ENDPOINT_URL, the API URL that web and overseer use on the server side, and PORT.
  • NEXT_PUBLIC_* values are baked into the web and overseer bundles at build time. Rebuild (--build) after changing them.
  • Host ports are defined only in docker-compose.override.yml, which docker compose loads automatically locally.
  • Data lives in the pgdata and s3data volumes.

Dokploy (hosted / QA)

  1. Create a Compose service (type Docker Compose, not Stack) pointing at the repository and docker-compose.yml.
  2. Paste a customised .env.example into the Environment tab; Dokploy writes it to .env.
  3. Add domains for web (port 3000) and overseer (port 3000). The API doesn't need a public domain: browsers reach it through web's /v1 proxy.
  4. Dokploy doesn't load docker-compose.override.yml, so no host ports are published.

Production checklist

  • [ ] Strong JWT_SIGNING_KEY (long random string), unique per environment.
  • [ ] Strong POSTGRES_PASSWORD and S3 keys.
  • [ ] SUPERADMIN_PASSWORD changed after first sign-in; REQUIRE_SUPERADMIN_MFA=true.
  • [ ] APP_BASE_URL and PUBLIC_PORTAL_BASE_URL set to the public HTTPS address (they're used in email links).
  • [ ] SMTP configured, then a test password reset sent.
  • [ ] cors_origin restricted to your domains; debug_mode=false.
  • [ ] HTTPS terminated at the proxy.
  • [ ] Backups of Postgres and the S3 bucket.
  • [ ] The worker container is running (imports, reminders, schedules depend on it).

Documentation website

This documentation can be served as a searchable website with navigation and dark mode. It runs as the docs service in Compose: docker compose up -d --build docs, then open http://localhost:3102. To run the image on its own:

docker build -f infra/Dockerfile.docs -t orbit-docs .
docker run --rm -p 3000:3000 orbit-docs

Open http://localhost:3000. To preview Markdown edits without rebuilding, mount the folder: add -v "$PWD/documentation:/docs:ro" to docker run. Without Docker, run npm install && npm start in infra/docs-site/. With the site running, npm run check reports broken links and anchors.