Ctrl K
ComunidadGuías…

CONTRIBUTING.md

Rama main · réplica de lectura del repositorio original.

Archivo original ↗Preguntar a KiBot
# Contributing

Thanks for taking an interest. Bug reports and small focused PRs are the most
useful things you can send.

## Before you write code

- **Bug fix** — just open a PR. Link the issue if there is one.
- **New feature** — open an issue first so we can agree on the shape before you
  spend an evening on it. Check [the roadmap](docs/wiki/Roadmap.md); the
  built-in player is already planned, and a half-built version of a planned
  feature is harder to merge than nothing.
- **Issues are labelled automatically** — a type and an `area/*` label, plus
  `needs-info` or `possible-duplicate` when they fit. A maintainer reads every
  issue and corrects the labels where needed.
- **New integration** (indexer, download client, media server) — welcome. Copy
  the shape of an existing one in `internal/indexer/`, `internal/download/`
  (e.g. `deluge.go`) or `internal/mediaserver/`.

## Setup

Requires Go >= 1.27.3 (the `go` directive in `go.mod`), Node >= 24.22.2,
[pnpm](https://pnpm.io) 12 (the `packageManager` in `package.json`) and
[Task](https://taskfile.dev). Nix users get all of it, at exactly those
versions, from the flake devshell (`nix develop`, or direnv).

```bash
git clone https://github.com/datahearth/streamline.git
cd streamline
pnpm install --frozen-lockfile
task                    # builds frontend assets + the binary
```

The frontend is `//go:embed`-ed into the binary, so `task build:go` depends on
`task build:js` and `task build:css`. Always build through Task — raw
`go build` / `go test` / `pnpm exec` skips steps that CI does not.

For development:

```bash
streamline config init --output ./tmp/config.yaml    # or ./streamline config init …
task dev                # live reload via air, serves http://localhost:8080
```

## The loop

```bash
task lint               # golangci-lint + biome + svelte-check
task fmt                # golangci-lint fmt + biome format --write + nixfmt
task test               # all suites
task test:unit -- ./internal/metadata/...   # one package
```

CI runs `task test` and all three linters: `task lint:go`, `task lint:frontend`
and `task lint:ts` (svelte-check, with warnings counted as failures, since
nothing else type-checks the Svelte app). If `task lint` and `task test` pass
locally, the PR should be green.

## Code generation

Generated files are committed. Regenerate and include the result when you
change an input:

| Changed                        | Run                                          |
| ------------------------------ | -------------------------------------------- |
| `api/openapi.yaml`             | `go tool oapi-codegen --config api/oapi-codegen.yaml api/openapi.yaml` |
| `ent/schema/`                  | `go generate ./ent`, then `task migrate:diff -- <name>` |
| a mocked interface             | `go tool mockery`                            |
| any of the above               | `task generate` does all three               |

`api/openapi.yaml` is the source of truth for the REST API — write the spec
first, then implement the generated handler interface.

## README screenshots

The screenshots in `docs/assets/` come from one command:

```bash
task docs:screenshots                       # all twenty
task docs:screenshots -- -only movies,books # some of them
task docs:screenshots -- -keep              # leave the instance up afterwards
```

It boots a throwaway instance under `$TMPDIR/streamline-demo`, adds a demo
library of public-domain films, television and books and Creative Commons
music, grabs it through a fake indexer and a fake qBittorrent, imports the
finished releases from files ffmpeg makes, files the requests and a library
import, and shoots each page. It needs `ffmpeg`, a Chromium (`CHROME_PATH` or
on `PATH`) and the TMDB, TVDB and Hardcover keys as
`STREAMLINE_METADATA__TMDB_API_KEY`, `STREAMLINE_METADATA__TVDB_API_KEY` and
`STREAMLINE_METADATA__HARDCOVER_API_KEY`. A run takes about fifteen minutes,
most of it MusicBrainz's one request a second; the first also encodes the
video clips it reuses. Retake them when a change shows on any of the pages,
and read every image before committing them. What the demo holds and the two
values it stages are described in `e2e/demoshots/main.go`.

## Conventions

The full house style lives in [CLAUDE.md](CLAUDE.md) — it is written for AI
agents but it is an accurate description of how the codebase is put together
(logging, observability, config-backed resources, auth, frontend). Worth
skimming before a larger change. The short version:

- **Go**: tabs, `slog.XContext(ctx, …)` for logging (no logger plumbing), a
  span per service operation via the package `tracer`, no named returns, no
  ignored errors.
- **Tests**: Ginkgo + Gomega. One `_test.go` per source file, in the same
  package. Every top-level `Describe` needs a
  `Label("unit"|"integration"|"e2e")`, or `task test:unit`,
  `test:integration` and `test:e2e` silently skip it.
- **Frontend**: Svelte 5 + TypeScript (`<script lang="ts">` everywhere),
  TailwindCSS v4, TanStack Query/Form, valibot. A section's wrapping layout is
  `_module.svelte` — `_layout.svelte` renders as a sibling route instead.
- **Comments**: only where the code cannot explain itself. No restatements, no
  section banners, no changelog notes in the source.
- **Config-backed resources**: indexers, download clients, media servers and
  quality profiles (video, music and book) live in the YAML config, not in
  SQLite. New config keys must
  be added to `config.defaults()` and `api/config.schema.json` — two tests
  guard that.

## AI-assisted contributions

Streamline is built with heavy AI assistance — that's what [CLAUDE.md](CLAUDE.md)
is for. So this is not a "no AI" project, and you don't need to hide that you
used a coding agent. There is one rule:

**You are the author. The model is a tool.**

In practice:

- **Understand every line you submit.** If a reviewer asks why a function is
  shaped that way and the honest answer is "the model wrote it", the PR isn't
  ready. Read the diff before you open it.
- **Run `task lint` and `task test` yourself.** An agent claiming the tests pass
  is not evidence that they pass. Paste real output if a change is subtle.
- **Verify the code against reality, not plausibility.** Agents invent config
  keys, ent methods, and API endpoints that look exactly right and don't exist.
  Build it.
- **Mention it in the PR description.** One line — "written with Claude Code" —
  so a reviewer knows which failure modes to look for. No stigma attached.
- **Point your agent at `CLAUDE.md`.** It is the house style and it is kept
  current; a PR that follows it needs far less review.

What gets closed without much discussion:

- Large unreviewed diffs the submitter can't explain, or PRs that clearly
  weren't run
- Agent-generated refactors, "modernisations", or comment/docstring sweeps nobody
  asked for
- Scanner or agent output filed as a bug report or security report with no
  reproduction — see [SECURITY.md](SECURITY.md) for what a real report looks like

Reviewer time is the scarce resource here. A small PR you fully understand is
worth more than a large one you don't.

## Commits and PRs

Conventional Commits, subject line only unless the body earns its place:

```
fix(library): scope import decision writes to their scan
feat(indexer): support Jackett
```

`type(scope): msg`, scope optional. The changelog is generated from these by
git-cliff, so don't hand-edit `CHANGELOG.md`.

Keep the PR to one topic. Rebase on `main` rather than merging it in. Fill in
the PR template checklist.

A PR from a branch of this repository is published as an image,
`ghcr.io/datahearth/streamline-pr:pr-<number>` (`-vaapi` for the VAAPI
flavor), so you and a reviewer can try it on a real deployment. The tags are
deleted when the PR closes. A PR from a fork gets no image: its workflow token
cannot push. See
[Trying a pull request](https://github.com/datahearth/streamline/wiki/Installation#trying-a-pull-request).

**A UI/UX change needs screenshots or a video in the PR.** That covers
anything that changes what a page looks like or how it behaves: a new page or
component, a layout, style or copy change, an interaction. Show before and
after at desktop, tablet and phone width (around 1440, 820 and 390 px). The
app has three layouts: the full sidebar from `lg`, an icon rail with swipeable
tabs from `md` to `lg`, and bottom navigation, sheets and a search page below
`md`. Attach a short video or GIF for anything that moves. Drag the files into
the PR description and GitHub hosts them. A UI PR without them is sent back before review: a reviewer cannot judge
a visual change from the diff alone.

## License

Contributions are licensed under [GPL-3.0-or-later](LICENSE), same as the
project.