The `## [0.3.1]` heading is a reference link with no definition, so it rendered as literal text; `[Unreleased]` still compared from v0.3.0.
3.5 KiB
Contributing to Joulenap
Thanks for your interest in improving Joulenap! This guide covers the local dev setup, how to run the checks CI runs, and the conventions we follow.
By contributing you agree that your contributions are licensed under the project's AGPL-3.0.
Project layout
backend/— Python 3.12 + FastAPI + APScheduler. The app package isbackend/app.frontend/— React + TypeScript SPA (Vite). Built output is served by the backend.docs/— design and setup docs. Start withARCHITECTURE.mdandCONFIG-WIZARD.md.
Dev setup
You need Python 3.12+ and Node 20+.
Backend
cd backend
python -m venv .venv
# Windows: .venv\Scripts\activate | macOS/Linux: source .venv/bin/activate
pip install -e ".[dev]"
ruff check . # lint
pytest # tests
Frontend
cd frontend
npm ci
npm run dev # Vite dev server (proxies /api to the backend on :8080)
npm run build # type-check (tsc --noEmit) + production build
For a running app, copy the config first and start the backend:
cp config.example.yaml config.yaml
cd backend && python -m app.main # serves the API (and the built SPA if you ran `npm run build`)
The example config ships unconfigured, so the app drops you into the first-run registration and setup wizard — no real Proxmox needed to click around the UI.
Frontend without a backend
To work on the UI alone — layout, styling, i18n — you can run the SPA against a built-in stub instead of a real backend and a real Proxmox:
cd frontend
npm run dev -- --mode stub
frontend/src/devStub.ts answers every /api/* request from fixtures (a configured install,
three guests, a few log lines, and enough wizard responses to click through the whole setup
flow) and pins the clock, so the UI renders exactly the same on every run — handy for
screenshots and layout comparisons. It is loaded only when VITE_STUB_API=1, which
frontend/.env.stub sets for the stub mode, and Vite eliminates it from production builds.
Add --host 0.0.0.0 to reach the dev server from a phone on the same network.
Before you open a PR
Run what CI runs (see .github/workflows/ci.yml); all of it must pass:
- Backend:
ruff check .andpytest(CI runs the suite on Python 3.12 and 3.13). - Frontend:
npm run build(this type-checks withtsc --noEmit).
CI also runs dependency (pip-audit / npm audit) and Docker image (Trivy) security scans.
Conventions
- Small, reviewable commits; work on a feature branch and open a PR against
main. - Tests for the connectors and backup-cycle logic — that's where correctness matters most.
- Keep it config-driven — nothing hard-coded (no specific IPs/MACs in code); validate config with pydantic and fail clearly.
- Secrets never get committed.
config.yamlis git-ignored; don't add real hosts/tokens/MACs to code, tests, or docs — use placeholder/192.0.2.x(TEST-NET) values. - i18n: user-facing UI strings go through
t('key')with entries in bothfrontend/src/i18n/en.jsonandfrontend/src/i18n/it.json(English is the source language). Backend-facing strings (errors, notifications) use the server-side dictionary. Never concatenate translated strings — use interpolation.
Reporting bugs and requesting features
Use the issue templates (bug report / feature request). For security vulnerabilities, do not
open a public issue — follow SECURITY.md instead.