Skip to content

Development and CI

Lef edited this page Oct 4, 2026 · 3 revisions

Development and CI

CI (GitHub Actions)

.github/workflows/ci.yml runs on pushes to main and on pull requests, but only when code changes (backend, frontend, monitoring, scripts, tests, compose). Docs-only pushes skip it. You can also start it by hand from the Actions tab:

Job What it checks
Python compileall on all Python, plus ruff limited to real errors (syntax errors, undefined names). No style rules
PostgreSQL schema Loads backend/init_postgresql_schema.sql into Postgres 16 and runs migrate_db() twice. Catches a missing or broken schema
Backend unit tests ~390 pytest tests in backend/tests/unit (dice engines, dice pools, auth, chat actions, Laya evaluation, classifier, prompt budget, live events...)
Frontend Node 22: npm ci, the Jest tests (~470), npm run lint (fails on any warning) and a Vite production build

The frontend moved from Create React App to Vite in 0.10.0. Jest runs on its own (frontend/jest.config.js) and ESLint 9 uses a flat config.

Running the same checks locally

# frontend tests (inside the frontend image, nothing to install on the host)
./scripts/run-frontend-tests.sh
# after a dependency change, rebuild the image first: docker compose --profile dev build frontend

# python errors
docker run --rm -v "$PWD":/src:ro -w /src python:3.12-slim \
  sh -c 'pip install -q ruff && ruff check --no-cache --select E9,F63,F7,F82 backend monitoring books scripts tests'

The Python tests in tests/ and backend/tests/ are integration tests. They need the running stack (and some need LM Studio), so CI doesn't run them.

Security

  • CodeQL scans Python and JavaScript when code changes on main or in a PR (.github/workflows/codeql.yml). Results are in the Security tab
  • Dependabot opens update PRs monthly for pip, npm, Docker base images and Actions (.github/dependabot.yml), and security fix PRs right away when an alert comes in
  • All of this is free here: Actions minutes on public repos with GitHub-hosted runners don't count against any plan
  • Secret scanning with push protection is on
  • How to report a vulnerability: SECURITY.md

Things to keep in mind

  • The backend's DB rows are dicts (RealDictCursor). Read by column name
  • The JWT identity is a string. Use int(get_jwt_identity()) before comparing with ids from the database
  • PostgreSQL booleans: use TRUE/FALSE, not 1/0
  • When you add a table or column, add it to init_postgresql_schema.sql too, not only to an ensure_* helper

Clone this wiki locally