diff --git a/AGENTS.md b/AGENTS.md index 6137ff9..2185249 100644 --- a/AGENTS.md +++ b/AGENTS.md @@ -115,6 +115,12 @@ uv run ansible-galaxy install --role-file requirements.yml - `gitleaks` — поиск секретов в staged-файлах. - Проверка что секретные файлы зашифрованы vault. +## Конвенции + +Договорённости о том, как делать однотипные вещи, живут в [`docs/conventions/`](docs/conventions) — одна конвенция на файл, у каждой статус (рекомендуемая / обязательная) и честный список уже существующих отступлений. Это правила на будущее, в отличие от [`docs/adr/`](docs/adr) (однажды принятые решения, постфактум и неизменяемо) и [`docs/drafts/`](docs/drafts) (черновики и хроника). Перед тем как заводить новое приложение или директорию — заглянуть туда. + +- [Категории директорий приложения](docs/conventions/app-directories.md) — содержимое `base_dir` делится на конфигурацию (восстанавливается плейбуком, бэкап не нужен), данные (создаёт приложение, бэкапить обязательно) и кеш (создаёт приложение, перегенерирует само). Из категорий механически выводится `backup-targets`. + ## Соглашения по коду - Отступы: 2 пробела для YAML/Jinja, 4 пробела в остальных файлах (`.editorconfig`). diff --git a/docs/conventions/README.md b/docs/conventions/README.md new file mode 100644 index 0000000..76385a0 --- /dev/null +++ b/docs/conventions/README.md @@ -0,0 +1,46 @@ +# Конвенции + +Склад договорённостей о том, **как делать однотипные вещи** в этом +репозитории. Одна конвенция — один файл. + +Конвенция описывает повторяющийся выбор: как называть директории, как +раскладывать данные, как оформлять шаблоны. Она отвечает на вопрос «как +принято», а не «что здесь происходит». + +Чем отличается от соседей: + +- [`../adr/`](../adr) — **решение**, принятое однажды и постфактум + («почему выбрали Authelia, а не Keycloak»). Запись неизменяема. +- [`../drafts/`](../drafts) — оперативная хроника и черновики («что + собираюсь сделать»). +- `conventions/` — **правило на будущее**, применяемое многократно. + Живой документ: правится, когда договорённость меняется. + +## Статус + +Каждая конвенция начинается со строки статуса: + +- **Рекомендуемая** — так стоит делать в новом коде; существующий код + переезжает по мере касания, отдельной кампанией не переписывается. +- **Обязательная** — нарушение считается ошибкой; по возможности + проверяется линтером или хуком, а не вниманием. + +Конвенция без механической проверки держится только на внимании — это +нормально для рекомендуемой и плохо для обязательной. + +## Когда заводить + +Когда одно и то же решение принимается третий раз и каждый раз чуть +по-другому. Единичный выбор — не конвенция; если он ещё и был спорным, +ему место в ADR. + +## Соглашения + +- Имя файла — kebab-case, по теме: `app-directories.md`. +- В теле честно перечислены отступления, которые уже есть в коде, — + иначе документ описывает не репозиторий, а пожелание. + +## Список + +- [Категории директорий приложения](app-directories.md) — конфигурация / + данные / кеш: делим по тому, кто создаёт и что будет при потере. diff --git a/docs/conventions/app-directories.md b/docs/conventions/app-directories.md new file mode 100644 index 0000000..7aa141f --- /dev/null +++ b/docs/conventions/app-directories.md @@ -0,0 +1,73 @@ +# Категории директорий приложения + +**Статус:** рекомендуемая. + +Директории приложения внутри `base_dir` делим на три категории по +принципу создания и ценности содержимого: + +- **конфигурация** — то, что восстанавливается прогоном плейбука, в том + числе секреты; +- **данные** — то, что генерирует приложение и что нужно бэкапить; +- **кеш** — то, что генерирует приложение и что не нужно бэкапить: + приложение перегенерирует заново. + +Цель — упростить оперирование данными. Категория сразу отвечает на два +вопроса, которые иначе приходится выяснять по коду приложения: **кто +создаёт** содержимое и **что будет, если его потерять**. + +## Категории + +| Категория | Директория | Создаёт | Потеря содержимого | Бэкап | +| --- | --- | --- | --- | --- | +| Конфигурация | `config/` | плейбук | `inv pl -- ` восстанавливает | не нужен | +| Данные | `data/` | приложение | невосполнима | обязателен | +| Кеш | `cache/` | приложение | приложение перегенерирует | не нужен | + +Тест на границе данных и кеша: что будет, если сделать `rm -rf` и +поднять приложение заново. Поднимется само и наверстает — кеш. Не +поднимется или поднимется пустым — данные. + +Конфигурацию бэкапить не только не нужно, но и не стоит: там лежат +секреты, а бэкапы уезжают в облако. Источник истины для конфигурации — +репозиторий и vault, а не снапшот restic. + +## Практика + +- Переменные плейбука — `config_dir`, `data_dir`, `cache_dir` внутри + `base_dir`; директории создаются одной задачей `Create application + internal directories`. +- Файл `backup-targets` выводится из категорий механически: в него идут + данные, не идут конфигурация и кеш. +- Монтирование в контейнер: конфигурацию — `:ro`, где приложение это + позволяет. Данные и кеш — на запись. +- `docker-compose.yml` остаётся в корне `base_dir`: туда смотрит + `project_src` модуля `docker_compose_v2`. + +Пример, где категории разведены полностью, — `playbook-gramps.yml`: +`data` (база), `media` (файлы), `cache` (миниатюры и кеш отчётов), +`backups` (дампы). В `backup-targets` попадают первые три без `cache`. + +## Отступления, которые уже есть + +Конвенция рекомендуемая, поэтому список честный, а не пустой. + +- **`backups/`** — четвёртая директория рядом с тремя категориями. + Формально это производное от данных (дамп, который делает gobackup или + `pg_dump`), но именно она уезжает в restic, а сырые данные приложения — + не всегда. Держим отдельно и относим к данным. +- **`media/`** (gramps, outline) — это данные, просто вынесенные в + отдельную директорию: крупные файлы отделены от базы, чтобы их можно + было двигать между дисками независимо. +- **Конфигурация без `config/`** — она есть только у девяти плейбуков из + тридцати трёх, у остальных конфиги лежат прямо в `base_dir` рядом с + `docker-compose.yml`. Переезд по мере касания приложения, отдельной + кампанией не переписываем. +- **Легаси-раскладка `data/` под всё** — у части сервисов внутри `data/` + лежит и то, что по этой конвенции было бы кешем. Разделять имеет смысл + тогда, когда кеш заметен по объёму в бэкапе, а не ради самой схемы. + +## Связано + +- [ADR-2025-12-07](../adr/ADR-2025-12-07-app-data-on-separate-disk.md) — + почему всё это лежит на отдельном диске в `/mnt/applications`. +- `files/backups/backup-all.py` — оркестратор, читающий `backup-targets`.