From 71936f6173fb23e5766b63fa3b301e060081295b Mon Sep 17 00:00:00 2001 From: Claudio Ortolina Date: Wed, 22 Apr 2026 21:01:52 +0100 Subject: [PATCH] Update project conventions and infrastructure docs --- docs/production-infrastructure.md | 22 ++++++++++++++-------- docs/project-conventions.md | 4 ++-- 2 files changed, 16 insertions(+), 10 deletions(-) diff --git a/docs/production-infrastructure.md b/docs/production-infrastructure.md index b9e771aa..7cc2fd6b 100644 --- a/docs/production-infrastructure.md +++ b/docs/production-infrastructure.md @@ -25,9 +25,9 @@ push via GitHub Actions. The Docker image is a multi-stage build: -1. **Builder** — `hexpm/elixir:1.20.0-rc.4-erlang-28.4.2-debian-trixie-20260406-slim` with +1. **Builder** — `hexpm/elixir:1.20.0-rc.4-erlang-28.4.3-debian-trixie-20260421-slim` with Node.js 25, compiles deps, builds assets (`mix assets.deploy`), generates an OTP release. -2. **Runner** — `debian:trixie-20260406-slim` with minimal runtime deps (`libstdc++6`, +2. **Runner** — `debian:trixie-20260421-slim` with minimal runtime deps (`libstdc++6`, `openssl`, `libncurses6`, `ca-certificates`). Runs as unprivileged `nobody` user. Fluxon UI (licensed dependency) is fetched during build via Docker build secrets @@ -61,18 +61,24 @@ Configured inline in `compose.yaml`. Runs as a separate Docker Compose service |---------|-------| | S3 endpoint | `https://nbg1.your-objectstorage.com` | | Bucket | `ffmusiclibrary` | -| Sync interval | 24 hours | -| Snapshot interval | 24 hours | -| Retention | 168 hours (1 week) | +| Sync interval | 60 minutes | +| Retention | 672 hours (28 days) | | Healthcheck | `litestream databases` every 30s (timeout 10s, 3 retries) | Credentials via environment: `LITESTREAM_ACCESS_KEY_ID`, `LITESTREAM_SECRET_ACCESS_KEY`. ### Manual backup -`mise run prod:backup` pulls the production database via `rsync` and saves it locally -as `data/music_library_prod_.db`. Old backups can be cleaned with -`mise run prod:prune-backups`. +Two manual options are available: + +- `mise run prod:backup` — takes an atomic snapshot of the live database on the + production server using `sqlite3 .backup`, then rsyncs it locally as + `data/music_library_prod_.db`. Safe under concurrent writes. +- `mise run prod:litestream-backup` — restores the production database locally from + the S3 Litestream replica. Requires `LITESTREAM_ACCESS_KEY_ID` and + `LITESTREAM_SECRET_ACCESS_KEY`. + +Old backups can be cleaned with `mise run prod:prune-backups`. --- diff --git a/docs/project-conventions.md b/docs/project-conventions.md index 1602d426..d7056337 100644 --- a/docs/project-conventions.md +++ b/docs/project-conventions.md @@ -100,9 +100,9 @@ Rules extracted from commit history that are specific to this project and not al - **Alias nested modules at the top** rather than referencing them inline (e.g. `alias LastFm.Fixtures.RecentTracks` then `RecentTracks.get()`, not `LastFm.Fixtures.RecentTracks.get()`). Enforced by Credo's `AliasUsage` check. - **Markdown sanitization via MDEx (ammonia).** Use `Markdown.to_html/1` for user content. Annotate raw output with `# sobelow_skip ["XSS.Raw"]` and a comment explaining the sanitization. - **Sobelow runs on CI and pre-commit** in skip mode for security analysis. -- **ExSlop checks run via Credo** for code quality: no narrator/boilerplate docs (use `@moduledoc false` instead), no obvious/step/narrator comments, no identity `case`/`with` patterns, no `Repo.all` then filter, no `Enum.map` with inline queries. Violations are caught by CI. +- **ExSlop checks run via Credo** for code quality: no narrator/boilerplate docs (use `@moduledoc false` instead), no obvious/step/narrator comments, no identity `case`/`with` patterns, no `Repo.all` then filter, no `Enum.map` with inline queries, no unaliased nested module use (nested modules must be aliased at the top). Violations are caught by CI. - **All modules require `@moduledoc`.** The Credo `ModuleDoc` check is enforced in strict mode. -- **The project does not use dialyzer**. If any skill suggests its usage, ignore it. +- **Dialyzer is enabled via `dialyxir` (dev/test only) with the `:no_opaque` flag.** Specs are required and checked. Opaque type checking is disabled to tolerate third-party opaque types (e.g., `Ecto.Changeset`). - **Validate Docker builder image before updating versions.** When changing `ELIXIR_VERSION`, `OTP_VERSION`, or `DEBIAN_VERSION` in the Dockerfile, run `mise run dev:validate-docker-image` to confirm the generated `hexpm/elixir` tag exists on Docker Hub and supports both `linux/amd64` and `linux/arm64`. ## Reviews & Audits