Contributing
Guidelines for contributing to Lumio.
Getting Started
- Clone the repository (access required — Lumio is a closed-source project)
- Set up the dev stack:
just stack-up - Run the API:
just dev-api - Run the web app:
just dev-web
Code Style
- Rust — Follow
rustfmt.tomlconventions (just fmt), passclippywith-D warnings - TypeScript — ESLint + double quotes
- Commits — Conventional commits format
Before you push
| Command | What it covers |
|---|---|
just verify-all | verify-rust + lint-ts + typecheck-ts — the fast inner loop |
just lint-all | clippy (-D warnings) + ESLint |
just test-all | test-rust + test-v8 + test-ts |
just verify-release | verify-all plus OpenAPI / GraphQL schema and Bazel vendor drift — run before a version-bump or crate-update change |
just bazel-build / just bazel-test | the Bazel gates CI runs for Rust — required for any Rust change |
pnpm --filter @lumio/<app> build | the production next build CI runs for web, admin, id and stats — required for any change under apps/{web,admin,id,stats}, shared/ or packages/protocol (build @zaflun/lumio-protocol first for web) |
pnpm -r --filter "./packages/**" build | the tsup build CI runs for the public @zaflun/* packages under packages/ — required for any change under packages/ |
just verify-all does not detect schema or vendor drift; only just verify-release does.
Run these one at a time. Each recipe already uses every core it is given, so a build, a test run, a clippy pass and a format check started in parallel do not finish sooner — they contend for the same CPU and slow each other down (badly so on a shared machine). Run the checks in sequence, cheapest first — fmt-check, then lint, then check / typecheck, then tests, then the Bazel gates — and let each finish before starting the next. The recipes above are already sequential internally; do not background one or start a second alongside it, and leave the job counts they set (test-rust pins CARGO_BUILD_JOBS=2) alone.
Cargo green is not Bazel green. CI builds and tests the Rust workspace with Bazel, which fails on things Cargo never sees — a dependency missing from a hand-written BUILD.bazel, a test that reads a fixture off the filesystem instead of embedding it, or vendor/ drift after a lock change. For any change touching Rust, run just bazel-build and just bazel-test before you push.
Typecheck green is not next build green. tsc never resolves Next.js file conventions, route manifests, server/client boundaries, the React Compiler or prerendering. The Next Build job runs the real production build per affected app — the same build the release image performs — so run pnpm --filter @lumio/<app> build locally for any frontend change. It is path-filtered: an app builds when its own directory changed, and a change under shared/, packages/protocol/, the root manifests or ci.yml builds all four.
Typecheck green is not tsup build green either. The public @zaflun/* packages under packages/ are bundled by tsup (entry resolution, export map, .d.ts rollup) — none of which tsc --noEmit or ESLint exercise, so a broken entry or export only surfaced at npm publish time. The Packages Build job runs pnpm -r --filter "./packages/**" build in dependency order (so cli and sdk get their built dependencies first); run it locally for any change under packages/. It is path-filtered: any packages/ file, a root manifest, or ci.yml arms it.
Pull Requests
- Create a feature branch off
nextand open the pull request intonext, the staging integration branch - Open every pull request as a draft (
gh pr create --draft) and mark it ready for review (gh pr ready) only once the work is finished - Include tests for new functionality
- Update
apps/docs/in the same change — a code change without matching doc updates is incomplete - Ensure CI passes and the change is reviewed before it merges
Why draft first
CI is draft-gated: every job in .github/workflows/ci.yml is skipped while a pull request is a draft, so iterating on a draft costs no GitHub Actions minutes. The full pipeline runs when the pull request is marked ready for review, and on every push after that.
Two consequences worth knowing:
- Verify locally while drafted —
just verify-allandjust test-all, plusjust bazel-build/just bazel-testfor a Rust change andjust verify-releasefor a version bump or crate update. That is what replaces the per-push CI run, so run all of it before marking the pull request ready, and say in the pull request which checks you ran. - A draft's green checks are not evidence. The
CI Doneaggregate treats skipped jobs as passing, so a draft shows green with nothing run. Only a run triggered by marking the pull request ready — or by a push while it is not a draft — proves anything.
See Reporting an Issue for where each kind of report goes and how a fix travels from next to production.
Architecture
See the Developer Guide section for detailed system design documentation.