# Contributing to JellyTau Thanks for looking. This file is the short version of how the project is built and what has to be true before a change lands. The long version lives in [CLAUDE.md](CLAUDE.md) and [docs/architecture/](docs/architecture/README.md), which are maintained rather than decorative — read them before a structural change. ## Getting set up Package manager is **bun**. You will also need a Rust toolchain (the exact version is pinned in [src-tauri/rust-toolchain.toml](src-tauri/rust-toolchain.toml) — rustup honours it automatically) and the Tauri Linux dependencies. ```bash bun install bun run hooks:install # do this once: it enables the pre-commit gates bun run tauri dev ``` `hooks:install` points `core.hooksPath` at [scripts/hooks/](scripts/hooks/), so hook updates arrive with a `git pull` instead of needing a re-install. ## What has to pass Everything below runs in CI, and the fast half runs in the pre-commit hook. None of it is advisory: ```bash bun run check # svelte-check — 0 errors bun run test # vitest bun run format:check # prettier bun run lint # eslint — 0 errors; the warning count is a ratchet bun run check:boundary # no Jellyfin taxonomy in the frontend bun run test:rust # cargo test cd src-tauri && cargo fmt --all && cargo clippy --all-targets -- -D warnings cd src-tauri && cargo deny check # advisories, licences, bans, sources ``` `bun run test:all` runs the whole set. Several of these are **ratchets** — a number that only ever moves in the improving direction: | Ratchet | Where | Rule | |---|---|---| | eslint `--max-warnings` | [.gitea/workflows/build-and-test.yml](.gitea/workflows/build-and-test.yml) | only goes down | | Coverage thresholds | [vitest.config.ts](vitest.config.ts) | only go up | | Traceability coverage | [.gitea/workflows/traceability-check.yml](.gitea/workflows/traceability-check.yml) | only goes up | Never relax one to make a build pass. Fix the thing it caught. ## The two rules that surprise people **1. Bug fixes start with a failing test.** Write a test that reproduces the bug and *watch it fail* before you touch the fix. A test written against already-fixed code can pass for the wrong reason and guards nothing. If the logic is trapped in a component, extract the pure part into a plain `.ts` module and test that — see `episodeStrip.ts` or `TrackList.logic.ts` for the pattern. **2. Domain vocabulary lives in Rust.** The frontend is presentation-only. It must not encode Jellyfin's *taxonomy* — for example, the set of item types that makes up a category like "Music". Send an opaque scope across the IPC boundary and let the backend expand it. `bun run check:boundary` is a tripwire, not a proof: it only flags item-type array literals, so a green run does not mean you are clear. [docs/specs/scoped-search-boundary.md](docs/specs/scoped-search-boundary.md) describes the leak that made this a rule. ## Traceability Code that implements a requirement carries a `TRACES:` comment naming the requirement IDs, and a tool builds the matrix from those comments: ```rust /// TRACES: UR-005 | DR-001 ``` Every ID must exist as a row in [docs/requirements.md](docs/requirements.md) — `bun run traces:validate` fails on a typo or a stale rename. Internal helpers and requirement-less code stay untraced; do not sprinkle IDs to raise the number. If you add a requirement, add its row. If you implement one, tag the code. ## Commits and pull requests - Conventional-commit subjects: `fix(player): …`, `feat(updater): …`, `ci: …`. - Explain **why** in the body, not what the diff already shows. The commit log is the main record of why things are the way they are here, and it is used to draft release notes. - One concern per commit. A formatting sweep and a behaviour change in the same commit is unreviewable. - Rebase rather than merge-commit onto `master`. ## Specs New features start from [docs/specs/SPEC-TEMPLATE.md](docs/specs/SPEC-TEMPLATE.md). Its "Layer assignment" section is the point: each piece of logic gets placed in Rust or the frontend *with a reason*. Review against [docs/specs/SPEC-REVIEW-CHECKLIST.md](docs/specs/SPEC-REVIEW-CHECKLIST.md). Do not frame a spec around "no Rust changes required" — correct placement is the goal, not minimal backend churn. ## CI CI is **Gitea Actions** (`.gitea/workflows/`), not GitHub. 🔴 **CI installs no system tools.** Every build, test and packaging tool must already be in the Docker builder image. If a job needs a tool the image lacks, add it to [Dockerfile.builder](Dockerfile.builder), rebuild and push the image, and pin the new tag — do not `apt-get` it at job time. Details in [docs/build/ci-operations.md](docs/build/ci-operations.md). Fetching the project's own declared dependencies (`bun install`, cargo crates, an advisory database) is not a toolchain install and is fine. ## Reporting bugs Use the issue templates. For anything involving playback, include what the platform was, whether the media was streaming or downloaded, and whether it was transcoding — those three answers determine which of several code paths you were actually on. Security issues go to [SECURITY.md](SECURITY.md), not the tracker.