Development setup
With Docker
Section titled “With Docker”cp .env.example .env # then set SECRET_KEY and DATA_ENCRYPTION_KEYdocker compose up --buildThe frontend is on http://localhost:5173, the API on http://localhost:8000, and PostgreSQL on port 5432. Source is mounted, so changes reload. The backend migrates the database when it starts.
To generate the encryption key:
openssl rand -base64 32 | tr '+/' '-_'Demo data
Section titled “Demo data”This creates a demo organization, with an exercise ready to conduct:
docker compose exec backend python -m scripts.seed_demo--reset rebuilds it, --codes prints the current two-factor codes, and --extras adds polls, rooms and an instance administrator.
Without Docker
Section titled “Without Docker”You need Python 3.12, Node.js 22 and PostgreSQL 16.
cd backendpython3.12 -m venv .venvsource .venv/bin/activatepip install -r requirements.txt -r requirements-dev.txtalembic upgrade headuvicorn app.main:app --reloadcd frontendnpm installnpm run devChecks
Section titled “Checks”These are what CI runs.
ruff check . && ruff format --check .alembic upgrade head && alembic checkpytest
# frontend/npm run lint && npm run format:check && npm run build && npm test
# docs/site/npm run buildRun one test at a time against that database: concurrent runs deadlock.
Browser tests run on their own stack:
cd frontendnpm run e2enpm run e2e:downDatabase changes
Section titled “Database changes”After changing a model, generate a migration. CI fails if a model changed without one.
docker compose exec backend alembic revision --autogenerate -m "message"API changes
Section titled “API changes”A changed route needs the API description regenerated, or CI fails:
docker compose exec -T backend python -m scripts.export_openapi > docs/site/schemas/openapi.jsonEvery operation needs a docstring, which becomes its description in the API reference. A new route must also be classified as PUBLIC or INTERNAL_ONLY in backend/app/api/exposure.py.