diff --git a/docs/specification.md b/docs/specification.md index f689eeb..ac77da3 100644 --- a/docs/specification.md +++ b/docs/specification.md @@ -401,6 +401,19 @@ DKIM-подпись — **строго per-domain**. Каждый отправл 10. **`docker-compose.yml` должен использовать фиксированный тег версии образа** (например, `selfpost:1.3.0`), не `:latest`. Это прямое следствие требования версионирования бэкапов (раздел 7.5.А) — без явного тега невозможно достоверно определить, какой версией был создан конкретный бэкап, и проверка совместимости при восстановлении теряет смысл. 11. Документация должна указывать **ориентировочные минимальные требования к машине**: 1 vCPU, ~512МБ–1ГБ RAM (при простое стек занимает ориентировочно 100–150МБ, с запасом под нагрузку), 8–10ГБ диска — с оговоркой, что диск растёт в первую очередь за счёт журнала отправки (ограничен `SEND_LOG_RETENTION_DAYS`) и ротируемого `mail.log` (раздел 9), а не самого приложения. Отдельно упомянуть рекомендацию настроить небольшой swap на машинах с малым объёмом RAM — дешёвая страховка на случай одновременного всплеска (бэкап + фильтрация журнала + несколько TLS-хендшейков одновременно). +### 10.1. Сборка и публикация образа (CI) + +Образ собирается автоматически в CI и публикуется в container registry как **неизменяемый артефакт под тегом версии**. Именно это делает реально работающими два уже принятых требования: проверку совместимости при восстановлении бэкапа (раздел 7.5.А) и фиксированный тег образа в `docker-compose.yml` (п. 10 выше). Если бы пользователь пересобирал образ локально из `Dockerfile`, две сборки «одной и той же версии» на разных машинах/в разное время не были бы идентичны (дрейф базового `debian:bookworm-slim` и версий apt-пакетов), и гарантия «восстанавливай в ту же версию» держалась бы на честном слове. Публикуемый по тегу immutable-образ снимает это: любой инстанс тянет побитово один и тот же образ. + +**Механика:** +1. **Триггер — git-тег вида `vX.Y.Z`.** Push тега запускает CI-сборку. Обычные коммиты в ветку образ не публикуют. +2. **Версия выводится из тега в одном месте** и прокидывается в сборку двумя связанными способами: в бинарник панели через `-ldflags "-X main.version=X.Y.Z"` (раздел 11.1) и в тег самого образа. Это структурно гарантирует инвариант «тег образа == вшитая версия бинарника», на который опирается 7.5.А, — версия не задаётся вручную в двух местах, где легко разойтись. +3. **Публикация** — `//selfpost:X.Y.Z`, тег иммутабельный. `:latest` для потребления в `docker-compose.yml` не используется (п. 10 выше). + +**CI и registry — GitHub.** Workflow (GitHub Actions) лежит в самом репозитории (`.github/workflows/`), зеркалится на GitHub вместе с остальным кодом (раздел 11.7) и **выполняется там**; образ публикуется в **GitHub Container Registry (`ghcr.io`)**. Обоснование: для public-образов `ghcr` бесплатен и **без rate-limit на анонимный pull** — в отличие от Docker Hub, где анонимный pull лимитирован, а образ тянут на голом VPS при деплое, часто без `docker login`. Связка Actions + `ghcr` не добавляет внешних сервисов сверх уже используемого GitHub-зеркала. + +**Альтернатива — `Quay.io` (задокументировать, но по умолчанию не реализовывать).** Нейтральный registry, тоже без лимитов на анонимный pull для public-образов, со встроенным сканированием уязвимостей, и не завязанный на конкретного CI-вендора (пушить в него можно из любого CI, включая тот же GitHub Actions). Зафиксирован как готовый путь отхода на случай, если в будущем захочется отвязать хранение образа от GitHub или уйти от моновендорности, — переезд не затрагивает остальной дизайн (меняется только адрес registry в workflow и в примере `docker-compose.yml`). На текущем этапе выбран `ghcr` ради минимума движущихся частей. + --- ## 11. Deliverables (что должно быть на выходе) @@ -411,9 +424,10 @@ DKIM-подпись — **строго per-domain**. Каждый отправл 4. Исходный код панели на Go (структурированный проект), с вендоренным HTMX. Включает: HTTP-сервер панели, journal-milter (приём From/To/Subject/SASL-user), log-tailer (обновление статусов доставки), rate-limit проверку, работу с SQLite, логику полного бэкапа/восстановления и экспорта/импорта домена (раздел 7.5). 5. `docker-compose.yml` — основной с Apache как reverse-proxy; альтернативные фрагменты для nginx/Caddy/Traefik. 6. **CLI-утилита резервного копирования** (например, `selfpost-backup`) внутри образа, вызываемая через `docker exec`, — эквивалент кнопки бэкапа в панели, для скриптовых/cron-сценариев (раздел 7.5.А). -7. `README.md` — установка, требования к площадке, per-domain настройка DNS, прогрев IP, эксплуатация, **процедура полного бэкапа/восстановления и процедура экспорта/импорта домена** (с явным указанием, что оба типа файлов содержат секреты и требуют бережного обращения, как пароль). Также ссылка на репозиторий: **Codeberg — основной, GitHub — зеркало** (настраивается push-зеркалированием средствами Codeberg, без CI/скриптов со стороны проекта). +7. `README.md` — установка, требования к площадке, per-domain настройка DNS, прогрев IP, эксплуатация, **процедура полного бэкапа/восстановления и процедура экспорта/импорта домена** (с явным указанием, что оба типа файлов содержат секреты и требуют бережного обращения, как пароль). Также ссылка на репозиторий: **Codeberg — основной, GitHub — зеркало** (зеркалирование кода настраивается push-зеркалированием средствами Codeberg; поверх зеркала на стороне GitHub работает CI-workflow сборки и публикации образа — см. раздел 10.1 и п. 10 ниже). README также указывает, откуда тянуть образ (`ghcr.io`), и что `docker-compose.yml` использует фиксированный тег версии (раздел 10, п. 10). 8. Первичная инициализация — реализована как secret-link при первом запуске (раздел 7.6, п. 1), отдельного скрипта для задания пароля администратора не требуется. DKIM-ключи генерируются панелью per-domain при добавлении домена, а не на этом шаге. 9. **`LICENSE` — AGPL-3.0.** Выбор осознанный: в отличие от GPL, AGPL закрывает «SaaS-лазейку» — обязывает раскрывать исходники изменённой версии, если её разворачивают как сервис, доступный через сеть, а не только при распространении копии кода. Файл лицензии — полный текст AGPL-3.0, без сокращений. В `README.md` — явное упоминание лицензии и её смысла в двух-трёх предложениях. +10. **CI-workflow сборки и публикации образа (GitHub Actions)** — файл в `.github/workflows/`, запускаемый по git-тегу `vX.Y.Z`: собирает образ, прокидывает версию из тега в `-ldflags "-X main.version=..."` и в тег образа, публикует в `ghcr.io` как `ghcr.io//selfpost:X.Y.Z` (раздел 10.1). Workflow зеркалится на GitHub и выполняется там. Публикация в `Quay.io` — как задокументированная альтернатива (раздел 10.1), не как основной путь. ---