The deploy workflow is now a single job that builds, pushes, and
deploys in one runner. Tag computation moved to docker/metadata-action,
the per-deploy .env perl rewrite is gone (host pins LIBRENOTES_IMAGE
once; main pushes update :main rolling, releases pin to :vX.Y.Z by
manual edit), and both jobs run in our bespoke runner image whose
runner user already has socket access via group membership.
ci.yml moves to the same image so go/make/node are all available
without per-step apt installs.
Drops compose.prod.yaml (unused, redundant with compose.netcup.yaml).
The Gitea act_runner already bind-mounts /var/run/docker.sock into job
containers when its own runner container has the socket mounted. The
workflow-level mount duplicated it and act_runner aborted the job with
'Duplicate mount point: /var/run/docker.sock'.
First deploy now works without manual .env priming: the remote step
unconditionally rewrites LIBRENOTES_IMAGE, then runs git pull --ff-only
so the host picks up the renamed compose.* files before pull/up.
- Image base is now ${REGISTRY}/public/librenotes (matches Gitea owner/repo).
- Remote step writes LIBRENOTES_IMAGE on tag pushes via perl, then pulls and
restarts using the new compose.yaml + compose.netcup.yaml stack files.
- Both jobs run inside catthehacker/ubuntu:runner-latest; the default
node:20-bookworm runner image lacks make + docker. The build job
bind-mounts /var/run/docker.sock for build-push-action; the runner config
must whitelist that path under valid_volumes.
Gitea issue templates (.gitea/issue_template/):
- bug.yml: structured form requiring version, environment,
what-happened, repro steps, expected, optional logs. Routes
security reports to security@librete.ch instead of public
issues.
- feature.yml: prompts for the underlying problem before the
proposed solution, plus alternatives and out-of-scope.
Pull request template (.gitea/PULL_REQUEST_TEMPLATE.md):
checklist for tests, lint, manual exercise, docs, and changelog.
Asks for explicit reviewer notes so trade-offs surface in the
PR description rather than being lost in chat.
CODE_OF_CONDUCT.md: links to Contributor Covenant 2.1 verbatim
rather than inlining; documents scope, reporting address
(conduct@librete.ch), and points enforcement at the Covenant's
own Enforcement Guidelines.
README links the docs/ tree, CONTRIBUTING, and the CoC so new
contributors find the entry points.
Closes#31.
Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
CI deployment (.gitea/workflows/deploy.yml):
- Two jobs (build, deploy) gated on the repo variable
DEPLOY_ENABLED=true so the workflow exists but does nothing
until secrets and host are configured.
- Build pushes two image tags per run: rolling :main + the short
SHA on main, or vX.Y.Z + :latest on tag pushes. Immutable per
commit/tag tags make rollback trivial.
- Deploy SSHes to DEPLOY_HOST, runs docker compose pull && up -d
in DEPLOY_PATH, then polls HEALTH_URL for up to a minute. A
failed health check fails the workflow, which is the alert.
- Required secrets and the rollback procedure are documented in
docs/operations.md.
Backup tooling (scripts/):
- backup.sh: SQLite online .backup snapshot + tarball of the
per-tenant data dir + info.txt header, all wrapped into a
single librenotes-YYYYMMDD-HHMMSS.tar.gz. Optional BACKUP_REMOTE
triggers an rclone copy for off-site storage.
- backup-prune.sh: enforces retention "30 daily + 12 monthly".
Sorts archives by filename (date is in the name so lex order
matches chronological) and keeps the newest 30 plus the newest
archive for each of the most recent 12 months.
- backup-restore-test.sh: extracts the most recent archive into
a tmpdir, runs sqlite3 .schema (proves DB readability), and
asserts the notes tar has at least one entry. Failure is the
alert. Wired into a separate weekly timer.
- librenotes-backup.{service,timer}: systemd units for the daily
03:17 UTC run with 5min jitter; ProtectSystem=strict, only
/var/backups/librenotes is writable.
- librenotes-backup-verify.{service,timer}: weekly Monday
04:00 UTC restore test.
Closes#26 and #27.
Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
Runs on push to main and pull requests against main:
- go mod download + verify
- make lint (go vet)
- make build
- make test (race detector)
Uses actions/setup-go@v5 with built-in module caching, Go 1.22.
Workflow times out at 5 minutes per the acceptance criteria.
Closes#5.
Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>