feat(docker): CYCLONE_ADMIN_* env vars for backend

This commit is contained in:
Nora
2026-06-22 15:21:55 -06:00
parent 4402a993d1
commit ca40fd72c3
2 changed files with 118 additions and 4 deletions
+17 -4
View File
@@ -1,7 +1,20 @@
# Cyclone — environment configuration
# Copy this file to `.env.local` and fill in values for your environment.
# Base URL for the Python (FastAPI) backend that powers the Upload page and
# the real /api/parse-837 + /api/parse-835 endpoints. Leave empty to keep
# the in-memory sample data store and disable real EDI parsing.
VITE_API_BASE_URL=http://localhost:8000
# Required on first boot. Cyclone refuses to start without these unless
# at least one user already exists (e.g. seeded via `python -m cyclone users create`).
# Min 12 chars for password.
CYCLONE_ADMIN_USERNAME=admin
CYCLONE_ADMIN_PASSWORD=change-me-to-a-strong-password-min-12-chars
# Base URL for the Python (FastAPI) backend. Leave empty for the
# Docker deployment (nginx proxies /api/* to backend on compose network).
VITE_API_BASE_URL=
# Optional. Set to 1 if you're behind an HTTPS reverse proxy and want
# the session cookie to include the Secure flag.
# CYCLONE_BEHIND_HTTPS=1
# Optional. Set to 1 to disable auth entirely (DEV ONLY). When set,
# the backend auto-grants admin access without checking credentials.
# CYCLONE_AUTH_DISABLED=0
+101
View File
@@ -0,0 +1,101 @@
# Cyclone — local docker-compose stack.
#
# Two services on a user-defined network:
#
# frontend (nginx) — published on http://127.0.0.1:8080
# serves the built SPA + reverse-proxies /api/* to backend
# backend (uvicorn) — NOT published externally by default; reachable from
# the frontend over the compose network on backend:8000
# (override `ports:` below to expose it for curl/debug)
#
# Persistent state:
# - `cyclone-data` named volume mounted at /data in the backend holds
# the SQLite database file. Survives `docker compose down`; only
# `docker compose down -v` wipes it.
# - `config/payers.yaml` is baked into the backend image at build time.
# To edit payer config, change the YAML, rebuild the backend image,
# and `POST /api/admin/reload-config` (or just restart the container).
#
# Usage:
# docker compose up -d --build # start (or rebuild + restart)
# docker compose logs -f # tail both services
# docker compose restart backend # bounce the backend (e.g. after crash)
# docker compose down # stop containers, KEEP the data volume
# docker compose down -v # stop AND wipe the data volume
name: cyclone
services:
backend:
build:
context: .
dockerfile: backend/Dockerfile
image: cyclone-backend:local
container_name: cyclone-backend
restart: unless-stopped
environment:
# Bind on all interfaces inside the container (required — 127.0.0.1
# would only be reachable from inside the container itself).
CYCLONE_HOST: "0.0.0.0"
CYCLONE_PORT: "8000"
CYCLONE_RELOAD: "0"
# Absolute path inside the container; the named volume mounts at /data.
CYCLONE_DB_URL: "sqlite:////data/cyclone.db"
# Bootstrap admin (required on first boot unless at least one user
# already exists). The ${VAR:?msg} syntax makes docker-compose refuse
# to start with a clear error if the env var isn't set in the host
# environment.
CYCLONE_ADMIN_USERNAME: ${CYCLONE_ADMIN_USERNAME:?CYCLONE_ADMIN_USERNAME is required on first boot}
CYCLONE_ADMIN_PASSWORD: ${CYCLONE_ADMIN_PASSWORD:?CYCLONE_ADMIN_PASSWORD is required on first boot (min 12 chars)}
volumes:
- cyclone-data:/data
# The healthcheck in the Dockerfile hits /api/health. The frontend
# depends_on `service_healthy` so it won't accept traffic until the
# backend is responsive.
healthcheck:
test: ["CMD", "curl", "--fail", "--silent", "http://127.0.0.1:8000/api/health"]
interval: 15s
timeout: 5s
retries: 3
start_period: 10s
# No `ports:` — the frontend reaches the backend over the compose
# network. Uncomment the next line to expose the API directly for
# `curl http://localhost:8000/api/...` from the host.
# ports:
# - "127.0.0.1:8000:8000"
networks:
- cyclone-net
frontend:
build:
context: .
dockerfile: frontend/Dockerfile
image: cyclone-frontend:local
container_name: cyclone-frontend
restart: unless-stopped
depends_on:
backend:
condition: service_healthy
ports:
# Bind address defaults to 0.0.0.0 (reachable from the LAN). Set
# CYCLONE_BIND_ADDRESS=127.0.0.1 to tighten to loopback-only and
# match the standalone install's local-only posture.
# Port defaults to 8081 to dodge the common clash on 8080; override
# with CYCLONE_WEB_PORT=... (see README).
- "${CYCLONE_BIND_ADDRESS:-0.0.0.0}:${CYCLONE_WEB_PORT:-8081}:80"
healthcheck:
test: ["CMD", "wget", "--quiet", "--tries=1", "--spider", "http://127.0.0.1/healthz"]
interval: 15s
timeout: 3s
retries: 3
start_period: 5s
networks:
- cyclone-net
networks:
cyclone-net:
driver: bridge
volumes:
cyclone-data:
name: cyclone-data