Useful Commands

A practical command reference for application developers working on (or deploying) the Headless Auth Platform. It assumes you have checked out this repository and have a terminal open at its root.

Who this is for. This page is for people building and shipping this application. It does not cover standing up the WBSP platform itself (that is the platform operator's job). Where a command talks to the platform, it uses the wbsp-app CLI, which your platform team provides.

Where things live. All application code is under target/. Run the Python/dev commands below from inside target/. The deployment manifests (wbsp.yaml, wbsp.Docker) live at the repository root.


1. Local development (run the app on your machine)

Everything here runs from the target/ directory and uses uv (a fast Python package manager). The app needs a PostgreSQL and a Redis to talk to — the quickest way to get both is Docker Compose (see §3).

cd target

# Install dependencies (including dev tools) into a local .venv
uv sync --extra dev

# Copy the example environment file and adjust as needed (never commit a real .env)
cp .env.example .env

# Apply database migrations, then start the API with hot reload on http://localhost:8000
uv run alembic upgrade head
uv run uvicorn hap.main:app --reload --port 8000

# Quick health checks (in another terminal)
curl -s localhost:8000/healthz   # liveness  → {"status":"ok"}
curl -s localhost:8000/readyz    # readiness → checks the DB and Redis

The server emits structured JSON logs to stdout (one line per event, mapped to the OpenTelemetry Logs Data Model). To read them comfortably while developing, pipe through a JSON pretty-printer, e.g. uv run uvicorn hap.main:app --reload | jq.

Configuration (environment variables)

The app is configured entirely from the environment (12-factor). Locally these come from target/.env; see .env.example for the full list. The most important ones:

VariablePurpose
HAP_DATABASE_URLSQLAlchemy/asyncpg URL for Postgres
HAP_REDIS_URLRedis URL (rate limits, OTP/challenge state, JWKS cache)
HAP_MASTER_ENCRYPTION_KEYbase64 32-byte key for at-rest encryption (secret)
HAP_ADMIN_API_KEYbootstrap admin key for the management API (secret)
HAP_ISSUER_BASE_URLpublic issuer base URL used in tokens/discovery
HAP_ENVIRONMENTdev | staging | prod

On the WBSP platform you do not set HAP_DATABASE_URL / HAP_REDIS_URL directly. When you enable the platform datastores in wbsp.yaml (§5), the platform injects DATABASE_HOST/_PORT/_NAME/_USER/_PASSWORD/_SSL and REDIS_HOST/_PORT (+ REDIS_NAMESPACE); the app builds the connection URLs — and applies the Redis key prefix — automatically.


2. Tests and quality gates

These are the same checks CI runs; all must pass before merge. Run from target/.

# Full test suite — unit + integration. Spins up real ephemeral Postgres & Redis via
# testcontainers (Docker must be running), so no manual DB setup is needed.
uv run pytest

# Style: lint + format check
uv run ruff check .
uv run ruff format --check .

# Static types (strict)
uv run mypy --strict src/hap

# Migrations apply cleanly up and back down
uv run alembic upgrade head && uv run alembic downgrade base

# Regenerate the published OpenAPI document from the code
uv run python scripts/export_openapi.py

Smoke-test a running server end to end

scripts/demo_flow.py drives the whole OAuth2/OIDC journey against a live server (provision tenant → register app → register + log in a user → PKCE authorize → token exchange → userinfo) and exits non-zero if any step fails — handy as a post-deploy check. Start a server first (see §1), then:

uv run python scripts/demo_flow.py                       # against http://localhost:8000
HAP_DEMO_BASE_URL=https://auth.wbsp.ai \
  HAP_ADMIN_API_KEY=… uv run python scripts/demo_flow.py # against a deployed instance

Migrations:

uv run alembic revision --autogenerate -m "describe the change"   # create a migration
uv run alembic upgrade head                                       # apply
uv run alembic downgrade -1                                       # roll back one step

3. Local containers (Docker Compose)

target/docker-compose.yml brings up Postgres, Redis, and the app together — the closest local mirror of a real deployment. Run from target/.

docker compose up --build          # build the image and start postgres + redis + app
docker compose up -d postgres redis # just the datastores (then run the app via uv, §1)
docker compose ps                  # what's running
docker compose logs -f app         # follow the app's logs
docker compose down                # stop everything
docker compose down -v             # stop and delete the data volumes (fresh start)

# Open a psql shell inside the database container
docker compose exec postgres psql -U hap -d hap

4. Deploying on WBSP (wbsp-app)

Deploys are driven by the root wbsp.yaml, which points at wbsp.Docker for the build and enables a platform-managed Postgres + Redis (database.enabled / redis.enabled). The container listens on port 8080 (the platform's ingress contract). A deploy selects a placement with --destination <name> (reading the matching .env.<destination>); the lifecycle commands (list/status/logs/stop/remove) scope by --provider / --tenant instead. This project declares these destinations: local (type: dev), and wbsp / stage / twist / aws (type: aws).

# Deploy / redeploy to a placement (the destination's type selects where it lands)
wbsp-app deploy --config wbsp.yaml --destination aws       # EKS (aws)
wbsp-app deploy --config wbsp.yaml --destination wbsp      # EKS (aws), wbsp enclave/tenant

# List apps and check status / health (list scopes by --provider; aws status needs --tenant)
wbsp-app list --provider aws
wbsp-app list --provider aws --health
wbsp-app status headless-auth --tenant test

# Stream logs (structured JSON; the platform's LogWatch also ingests these)
wbsp-app logs headless-auth --tenant test --follow
wbsp-app logs headless-auth --tenant test --lines 500

# Stop (keep the database + Redis) / remove (tear down and DELETE the data)
wbsp-app stop   headless-auth --tenant test
wbsp-app remove headless-auth --tenant test

For the local inner loop, use the local (type: dev) destination: the deploy brings up Postgres/Redis in containers and writes a .env beside the app; you then run HAP yourself from your IDE (there is no wbsp-app dev command in the v2 CLI):

wbsp-app deploy --config wbsp.yaml --destination local   # brings up DB/Redis, writes .env
source .env && uv run uvicorn hap.main:app --reload      # run HAP yourself (from target/)
wbsp-app stop headless-auth --tenant test                # stop the data services (keeps data)

Verify the image runs before an aws deploy: docker build -f wbsp.Docker -t headless-auth:dev . then docker run -p 8080:8080 --env-file target/.env headless-auth:dev, and open http://localhost:8080/healthz.


5. Backing services: Postgres and Redis

Both datastores this app needs are first-class platform resources — you just enable them in wbsp.yaml and the platform provisions and injects them:

database:
  enabled: true        # platform-managed PostgreSQL (RDS); injects DATABASE_*
redis:
  enabled: true        # platform-managed Redis; injects REDIS_* + REDIS_NAMESPACE
  durable: false       # true → a persistent store rather than a cache

You do not stand these up yourself or wire them through a Parallel Namespace. On deploy the platform injects DATABASE_* and REDIS_* (including REDIS_NAMESPACE, the key prefix this app must stay within); hap.config builds the connection URLs and hap.core.redis applies the key prefix automatically, so nothing is hard-coded.

Parallel Namespaces are for other backing services — e.g. Forgejo, ClickHouse — not Postgres/Redis. If you ever need one of those, define a wbsp-services.yaml and run wbsp-app services up --config wbsp-services.yaml; see the platform's parallel-services-guide.md.


6. Accessing the database on-platform

Day-to-day, prefer the application's own admin API and migrations over hand-editing data. When you genuinely need a shell against the platform database (e.g. to inspect a production issue), follow the platform's accessing-the-database.md — it explains how to obtain credentials and tunnel in. The platform sets DATABASE_SSL=true on managed (RDS) databases; the app enables TLS automatically when it sees that.


Quick reference

I want to…Command
Run the app locallyuv run uvicorn hap.main:app --reload (from target/)
Run all testsuv run pytest
Smoke-test a running serveruv run python scripts/demo_flow.py
Lint + typesuv run ruff check . && uv run mypy --strict src/hap
New migrationuv run alembic revision --autogenerate -m "..."
Regenerate OpenAPIuv run python scripts/export_openapi.py
Everything in containersdocker compose up --build (from target/)
Deploy to the cloudwbsp-app deploy --config wbsp.yaml --destination aws
Tail deployed logswbsp-app logs headless-auth --tenant test --follow
Enable Postgres + Redisset database.enabled / redis.enabled in wbsp.yaml