Skip to main content

Contributing

Guidelines for contributing to Lumio.

Getting Started

  1. Clone the repository (access required — Lumio is a closed-source project)
  2. Set up the dev stack: just stack-up
  3. Run the API: just dev-api
  4. Run the web app: just dev-web

Code Style

  • Rust — Follow rustfmt.toml conventions (just fmt), pass clippy with -D warnings
  • TypeScript — ESLint + double quotes
  • Commits — Conventional commits format

Before you push

CommandWhat it covers
just verify-allverify-rust + lint-ts + typecheck-ts — the fast inner loop
just lint-allclippy (-D warnings) + ESLint
just test-alltest-rust + test-v8 + test-ts
just verify-releaseverify-all plus OpenAPI / GraphQL schema and Bazel vendor drift — run before a version-bump or crate-update change
just bazel-build / just bazel-testthe Bazel gates CI runs for Rust — required for any Rust change
pnpm --filter @lumio/<app> buildthe 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/**" buildthe 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 next and open the pull request into next, 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 draftedjust verify-all and just test-all, plus just bazel-build / just bazel-test for a Rust change and just verify-release for 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 Done aggregate 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.