7.1 KiB
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 to contribute through issues as well as patches that
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 tracks what's next; 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. That has two practical implications:
- 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.
- 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.modis the source of truth) make- For the front-end CSS bundle: nothing extra —
make builddownloads a pinnedtailwindcssstandalone binary intobin/. - For the docs site: nothing extra —
make docsdoes the same trick withmdbook. - For end-to-end tests: Docker + Docker Compose, plus
npxfor Playwright.
One-time setup
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 is the path of least resistance:
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
gofumptfor formatting;goimportsfor import grouping. Both run via the pre-commit hook in this repo.golangci-lintwith.golangci.ymldefaults; 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.
slogfor structured logs. Never log secrets — and especially never the merged-creds rest-server URL (seeCLAUDE.md).
File and package layout
cmd/serverandcmd/agentare 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 andinternal/agent/...for the agent. web/templates/are HTML templates rendered with the standard library; embedded viaweb.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.NewServeragainst the real router; seeinternal/server/http/auth_test.gofor the canonical fixture pattern. - End-to-end tests live in
e2e/and run against a Docker Compose stack. Seedocs/e2e.md.
Database migrations
- Migrations are hand-rolled SQL in
internal/store/migrations/and embedded viaembed.FS. - Prefer column-level
ALTER TABLEover rebuilds — seeCLAUDE.md"Migrations" section for the FK-cascade trap that bit migration 0007's first draft.
Workflow
Opening an issue
Issues are contributions too. Use them to report a bug, suggest a feature, improve the documentation, or start a design discussion even if you do not plan to submit a patch.
Before opening one, search the existing issues and check tasks.md to
see whether the topic is already tracked. Then choose the closest issue
template:
- Bug report for behaviour that does not match the documentation or expected operation.
- Feature request for a new capability or a change to existing behaviour.
Give the issue a specific title, keep it to one problem or proposal, and complete the relevant template fields. If no template is an exact fit, open a regular issue and explain the context, desired outcome, and any alternatives you have considered. Maintainers may ask follow-up questions or close requests that duplicate existing work or fall outside the project's scope.
Security-sensitive reports are the exception: follow the SECURITY.md disclosure process and do not open a public issue.
Before opening a PR
- Open an issue first for non-trivial changes. The design is still moving; an issue lets us agree on direction cheaply.
- Run
make lint testlocally — both must pass. - Match existing code style (see above).
- Keep commits focused: one logical change per commit. Imperative subject lines, body explaining why if it isn't obvious.
- Don't add
Co-Authored-Bytrailers — 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
Use the bug report issue template and include:
- 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).
For security-sensitive bugs, use the private disclosure process noted above.
Suggesting features
Use the feature request issue template and describe 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. 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.