# Contributing to restic-manager Thanks for your interest in restic-manager. This document covers how to set up a development environment, the conventions the project follows, and how patches make it from your machine into `main`. ## Project status and scope restic-manager is in pre-1.0. Core functionality (Phases 0–4) is landed; OSS-readiness polish is in progress. The top of [`tasks.md`](./tasks.md) tracks what's next; [`spec.md`](./spec.md) is the canonical design doc and the source of truth for any "why is it built this way" question. The project is **single-maintainer, hobbyist-scale, and licensed under [PolyForm Noncommercial 1.0.0](./LICENSE)**. That has two practical implications: 1. Big PRs without prior discussion may be declined for fit reasons even when they're correct — opening an issue first lets us check alignment cheaply. 2. Commercial use is not permitted by the license. Bug reports and patches from operators of personal/community deployments are very welcome. ## Getting started ### Prerequisites - Go 1.25 or newer (`go.mod` is the source of truth) - `make` - For the front-end CSS bundle: nothing extra — `make build` downloads a pinned `tailwindcss` standalone binary into `bin/`. - For the docs site: nothing extra — `make docs` does the same trick with `mdbook`. - For end-to-end tests: Docker + Docker Compose, plus `npx` for Playwright. ### One-time setup ```sh git clone https://gitea.dcglab.co.uk/steve/restic-manager.git cd restic-manager make build # compiles bin/restic-manager-{server,agent} make test # full unit + integration test sweep make lint # gofumpt + goimports + golangci-lint ``` ### Running locally For most development, the [smoke environment](./docs/e2e-smoke.md) is the path of least resistance: ```sh make smoke-restart # rebuilds, launches as a systemd --user unit make smoke-logs # tail of the server log ``` Then point a browser at `http://127.0.0.1:8080`. The first run prints a one-time bootstrap token to the log; use it to create the admin user. ## Code conventions ### Style - `gofumpt` for formatting; `goimports` for import grouping. Both run via the pre-commit hook in this repo. - `golangci-lint` with `.golangci.yml` defaults; CI rejects on lint errors. - UK English in identifiers, comments, log messages, and UI strings (the misspell linter is configured for the UK locale — see P3-X5 for the original sweep). - Comments explain **why**, not what; avoid restating the code. A surprising invariant or an external constraint is worth writing down. "Adds 1 to x" is not. - `slog` for structured logs. Never log secrets — and especially never the merged-creds rest-server URL (see [`CLAUDE.md`](./CLAUDE.md)). ### File and package layout - `cmd/server` and `cmd/agent` are the two binary entry points. - `internal/` holds everything that's not part of the public Go API (which is none of it — restic-manager isn't a library). - Per-feature packages live under `internal/server/...` for the control plane and `internal/agent/...` for the agent. - `web/templates/` are HTML templates rendered with the standard library; embedded via `web.FS`. ### Tests - Unit tests live alongside the code as `*_test.go`. Use the in-process sqlite store (`store.Open(":memory:")`) when you need state — there is no test mock layer to maintain. - HTTP handlers test through `httptest.NewServer` against the real router; see `internal/server/http/auth_test.go` for the canonical fixture pattern. - End-to-end tests live in `e2e/` and run against a Docker Compose stack. See [`docs/e2e.md`](./docs/e2e.md). ### Database migrations - Migrations are hand-rolled SQL in `internal/store/migrations/` and embedded via `embed.FS`. - Prefer column-level `ALTER TABLE` over rebuilds — see [`CLAUDE.md`](./CLAUDE.md) "Migrations" section for the FK-cascade trap that bit migration 0007's first draft. ## Workflow ### Before opening a PR 1. **Open an issue first** for non-trivial changes. The design is still moving; an issue lets us agree on direction cheaply. 2. Run `make lint test` locally — both must pass. 3. Match existing code style (see above). 4. Keep commits focused: one logical change per commit. Imperative subject lines, body explaining why if it isn't obvious. 5. Don't add `Co-Authored-By` trailers — repo policy. If you used AI assistance in writing the patch, that's fine; we just don't pollute every commit message with attribution boilerplate. ### Pull requests PRs target `main`. CI runs lint + tests on Linux amd64/arm64 and Windows amd64; all three must be green to merge. Squash-merge is the default; the PR title becomes the merge-commit subject, so keep it short and informative. The PR template asks for: - A short description of what changed and why. - A test plan (commands run, scenarios verified). - Anything reviewers need to know to assess the change (related issue, follow-up work, deferred concerns). ### Reporting bugs Open an issue with: - restic-manager version (`server --version`) and agent version. - restic version on the affected host. - Steps to reproduce. - Server and agent logs (sanitise any tokens before pasting). Security-sensitive bugs go through the [SECURITY.md](./SECURITY.md) disclosure path instead — please don't open a public issue for them. ### Suggesting features Open an issue describing the use case (not just the proposed solution). The roadmap in `tasks.md` shows where the project is heading; if the suggestion fits a future phase we'll wire it in there. If it falls outside the project's scope (multi-tenancy, SaaS, non-restic backends — see `spec.md` §2 non-goals) we'll say so early to save your time. ## Code of conduct Project participation is governed by [CODE_OF_CONDUCT.md](./CODE_OF_CONDUCT.md). The short version: be civil; assume good faith; harassment is not tolerated. ## License By contributing you agree that your contributions are licensed under the [PolyForm Noncommercial 1.0.0](./LICENSE) license.