# Contributing Thank you for your interest in librenotes. This document covers the developer workflow: setup, conventions, commit messages, and how to land a pull request. ## Code of conduct Participation in this project is governed by the [Contributor Covenant 2.1](./CODE_OF_CONDUCT.md). Please read it before opening issues or PRs. ## Development setup The fastest path is the Nix flake. The `dev` shell drops you into a working Go toolchain without any sandbox wrapping: ```sh git clone ssh://tengo@git.librete.ch:41240/public/librenotes.git cd librenotes nix develop .#dev make build && make test ``` If you don't use Nix: - Install Go 1.22 or later. - Install `make`, `git`. - Optional: `staticcheck` (Go), `sqlite3` (for backup tooling). A Docker-based dev environment also exists: ```sh docker build -f Dockerfile.dev -t librenotes-dev . docker run --rm -it -v "$PWD:/workspace" librenotes-dev ``` See the [README](./README.md) for the full layout. In short: ``` cmd/librenotes/ Binary entry + serve cmd + frontend assets internal/auth/ Magic-link auth + JWT internal/storage/ SQLite + user model internal/tenant/ Per-user filesystem sandbox internal/httpapi/ Routes, middleware, notes CRUD internal/notesium/ Forked Notesium core (notes engine) docs/ User-facing docs (this guide, ops, api, ...) scripts/ Backup, prune, restore tools ``` ## Coding standards - Match the existing style. We don't have a custom linter beyond `go vet`; `gofmt` and `goimports` are enforced via the toolchain. Run `make lint` before pushing. - Keep packages focused. Cross-package dependencies should flow one way: `httpapi -> auth/storage/tenant`, never the reverse. - Tests live next to the code they exercise (`*_test.go`). Aim for table-driven tests for input parsing and behavioural tests with `httptest.NewRecorder` for handlers. - New runtime configuration goes through `LIBRENOTES_*` env vars with a corresponding `--flag` on `librenotes serve`. - All filesystem operations on tenant data must go through `internal/tenant`. Never `os.Open` a path containing a user ID. ## Branch naming - `feat/` for new features - `fix/` for bug fixes - `docs/` for documentation - `chore/` for tooling, CI, refactors - `phase-N/` for issues belonging to a roadmap phase ## Commit messages Imperative mood, present tense. First line ≤72 characters. Body explains the *why*, references the issue with `Closes #N` or `Refs #N` so Gitea can auto-link. Example: ``` Add tenant-scoped notes REST API Backed by tenant.FS so all reads/writes go through the per-user sandbox. ?base= drives optimistic-locking conflict detection for PUT/DELETE. Closes #11. ``` ## Pull request process 1. Open an issue first for anything non-trivial. Reference it from the PR. 2. Branch off `main`, push, open a PR against `main`. 3. CI must pass (`make lint && make test`). Failed CI blocks review. 4. Fill out the PR template — at minimum: what changed, why, how it was tested. 5. Squash on merge unless the history is genuinely useful. ## Reporting issues Use the bug-report or feature-request templates from the *New issue* page on Gitea. The templates ask for the right things; filling them out gets faster responses. For security issues please **do not** open a public issue. Email `security@librete.ch` with details. ## Releases Tagged releases follow [SemVer](https://semver.org). The maintainer creates the tag and the deploy workflow handles the build and registry push automatically. Individual contributors are not expected to tag releases.