Skip to content

Getting started

This guide walks through a local full stack: Postgres in Docker, the Rust gateway, and the Mithril file-explorer UI.

Prerequisites

  • Rust (see rust-toolchain.toml; 1.88+)
  • Node.js and npm (for Nx, Vite, Orval)
  • Docker (for local Postgres)

If you use VS Code or Cursor with the Dev Containers extension, you can open this repo in the devcontainer defined in .devcontainer/devcontainer.json at the repository root.

What you get:

  • A Linux environment with Rust, Node.js, Docker-in-Docker, lld/clang, and sccache pre-wired for fast builds.
  • On attach, the devcontainer runs npm run dev, which starts the full Compose gateway profile (docker compose --profile gateway up -d --build).
  • Port forwarding exposes 8080 (nginx edge — UI + /api), not Vite :14200. Open the file explorer at http://127.0.0.1:8080 on your host.

If you do not already have a root .env, create it from the template (the gateway profile requires POSTGRES_PASSWORD, ATCR_*, and OAuth variables described below). This only copies when .env is missing:

bash
test -f .env || cp .env.example .env

The devcontainer postCreateCommand runs the same step so a fresh container gets .env automatically when absent.

Environment

The gateway does not embed defaults: every variable below must be set (usually via a root .env loaded by dotenvy).

  • Copy the template if you do not already have .env:
bash
test -f .env || cp .env.example .env
  • Adjust values if needed. The file includes:

  • Gateway (required): DATABASE_URL, PUBLIC_BASE_URL, HOST, PORT, CORS_ALLOWED_ORIGINS

  • RLS (local / Compose): DATABASE_ADMIN_URL (superuser substratum), DATABASE_URL (login substratum_gateway), and POSTGRES_PASSWORD so bootstrap can create the gateway role — see .env.example

  • Docker Postgres: POSTGRES_USER, POSTGRES_PASSWORD (required; no default in docker-compose.yml), POSTGRES_DB — must match the bootstrap URL and substratum_gateway password

docker compose reads the same .env for variable substitution. Do not define Postgres variables in two files: use the root .env.example only (there is no separate Docker env template with duplicate keys).

Note: The database password is fixed the first time the data volume is created. If you change POSTGRES_PASSWORD or DATABASE_URL later, see Troubleshooting.

1. Start Postgres

From the repository root:

bash
docker compose up -d

Postgres listens on host port 15432 (see docker-compose.yml).

Docker Compose: Postgres + gateway + file-explorer + edge (local OAuth)

The gateway Compose profile is the primary local stack for OAuth against a loopback PDS (http://localhost:3000). It starts Postgres, the gateway, the file-explorer Vite dev server, and an nginx edge reverse proxy:

  • edge serves / → Vite and /api + /.well-known → gateway on a single origin (http://127.0.0.1:8080).
  • Vite listens on :14200 inside the Compose network only (nginx upstream); do not open that port on the host.
  • The PDS runs on the host at http://localhost:3000 (not proxied through edge). Set PDS_PUBLIC_URL, PDS_OAUTH_ISSUER_ORIGIN, and PDS_HANDLE_DOMAIN=test in .env (see MODE B in .env.example). Handles look like alice.test.
bash
docker compose --profile gateway up -d --build
# or: npm run dev

Open http://127.0.0.1:8080 for the app and OAuth. Use 127.0.0.1, not localhost, so authorize navigations stay cross-site with the PDS at http://localhost:3000. Gateway DATABASE_URL is set automatically in Compose.

For production topology and OAuth / PDS origin rules, see Operations — Production deployment and OAuth and PDS origins.

2. Run the gateway (host / without Compose)

bash
cargo run -p substratum-gateway

The gateway listens on HOST:PORT from .env (MODE A uses 0.0.0.0:18080). Use this when Postgres is in Docker and you run the binary locally with npm run dev:ui. Set VITE_PUBLIC_APP_ORIGIN=http://127.0.0.1:18080 in apps/file-explorer/.env.development.local so Login redirects off Vite :14200 before OAuth. Loopback PDS OAuth works with PDS_PUBLIC_URL=http://localhost:3000 and the Compose gateway profile at http://127.0.0.1:8080.

3. Regenerate the TypeScript API client (when routes change)

bash
cargo run -p substratum-gateway --bin dump-openapi
npm run api-client:generate

4. Run the file-explorer UI

Recommended (Compose + edge): from the repository root:

bash
npm install
npm run dev

Then open http://127.0.0.1:8080. The devcontainer forwards 8080 only; Vite :14200 is internal to Compose.

Advanced (MODE A — host gateway + Vite on the host): run the gateway with cargo run -p substratum-gateway, then:

bash
npm run dev:ui

Set VITE_PUBLIC_APP_ORIGIN in apps/file-explorer/.env.development.local to your gateway origin (see .env.development.local.example). OAuth still requires the browser origin to match PUBLIC_BASE_URL.

Nx shortcuts

If cargo is on your PATH:

  • npx nx run gateway:serve — same as cargo run -p substratum-gateway
  • npm run dev:stack — Docker only: docker compose --profile gateway up -d --build
  • npm run openapi:dump — run the OpenAPI dump target

CORS

CORS_ALLOWED_ORIGINS is required (comma-separated).

  • MODE B (Compose edge): include http://127.0.0.1:8080 (and http://localhost:8080 if you use that alias). See commented values in .env.example.
  • MODE A (host Vite): include the Vite origin, e.g. http://127.0.0.1:14200 and http://localhost:14200, when running npm run dev:ui against a host gateway.

Optional: logging

By default the gateway prints human-readable log lines. For JSON (e.g. log aggregators), set SUBSTRATUM_LOG_JSON=1 or true in .env.

Uncomment or set in .env:

bash
RUST_LOG=info,sqlx=warn

Documentation site (this site)

To work on these docs locally:

bash
npm run docs:dev

The project uses VitePress 2 alpha so the docs toolchain stays on a patched Vite 7 line (npm audit clean). When VitePress stable depends on a fixed Vite 7.x, consider pinning a non-alpha release.

Troubleshooting

password authentication failed for user "substratum"

The Docker volume was likely created with an older password (for example when both user and password were substratum). POSTGRES_PASSWORD in Compose only applies on first init.

Option A — reset dev data (simplest)

bash
docker compose down -v
docker compose up -d
cargo run -p substratum-gateway

Option B — keep data

Set POSTGRES_PASSWORD and the password in DATABASE_URL to the password the existing volume was created with.