From 865cf6796626cd18401bfba04297c5ea08e804ec Mon Sep 17 00:00:00 2001 From: Mikhail Yenuchenko Date: Wed, 5 Aug 2026 00:24:13 +0300 Subject: [PATCH] docs: plan specification retirement via D9 migration map After the documentation pass, specification.md moves to archive once its content lives in product, architecture, development, and security docs. Co-authored-by: Cursor --- CHANGELOG.md | 6 ++ docs/documentation-plan.md | 149 ++++++++++++++++++++++++------------- 2 files changed, 105 insertions(+), 50 deletions(-) diff --git a/CHANGELOG.md b/CHANGELOG.md index 5c05525..c19e792 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -5,6 +5,12 @@ Format follows [Keep a Changelog](https://keepachangelog.com/en/1.1.0/); version ## [Unreleased] +### Changed + +- docs: documentation plan now targets retiring `specification.md` after D9 — + migration map to `product.md`, `architecture.md`, `development.md`, and + expanded `security.md`; D9 added to the release gate. + ## [0.4.0] - 2026-08-04 ### Added diff --git a/docs/documentation-plan.md b/docs/documentation-plan.md index 3a2bab3..2331e15 100644 --- a/docs/documentation-plan.md +++ b/docs/documentation-plan.md @@ -1,11 +1,22 @@ # План документации SelfPost -**Зачем этот файл.** Документация — часть поставки (ТЗ раздел 11, пп. 5, 7, 9), -а не сопроводительный текст. Перед тегом релиза она обязана описывать **то, что -делает код**, а не то, что задумывалось: расхождение здесь — такой же дефект, -как несоответствие ТЗ, только обнаруживает его пользователь на своём проде. -План описывает, из чего состоит пакет, как он сверяется с кодом, что уже -разошлось (первый проход выполнен, результаты ниже) и что с этим делать. +**Зачем этот файл.** Документация — часть поставки (deliverables v1.0, пп. 5, 7, 9 +в [specification.md](specification.md)), а не сопроводительный текст. Перед тегом +релиза она обязана описывать **то, что делает код**, а не то, что задумывалось: +расхождение здесь — такой же дефект, как несоответствие требованиям, только +обнаруживает его пользователь на своём проде. План описывает, из чего состоит +пакет, как он сверяется с кодом, что уже разошлось (первый проход выполнен, +результаты ниже) и что с этим делать. + +**Цель после выполнения плана:** [specification.md](specification.md) (ТЗ v1.0) +**выводится из обращения** — не потому что требования исчезли, а потому что v1.0 +реализован и каждый блок ТЗ получает постоянный дом: пользовательское — в +README, устройство — в `architecture.md`, продуктовые границы — в +`product.md`, обязательная безопасность — в `security.md`, процесс разработки — +в `development.md`. Живой `specification.md` после этого держит два риска: +дублирование с кодом и ложное ощущение «источника истины», который уже не +сверяют. Задача **D9** — миграция остатков и снятие файла; до её закрытия +ссылки на ТЗ в этом файле — исторические. **Место в общем плане:** документационный проход идёт вместе с **D.5** ([implementation-plan.md](implementation-plan.md)) — до тега следующего релиза, @@ -32,38 +43,49 @@ ### Рабочие документы проекта (не поставка, но обязаны быть верны) -[specification.md](specification.md) — ТЗ v1.0, источник истины по требованиям. +[specification.md](specification.md) — ТЗ v1.0; **на вывод после D9** (см. карту +миграции ниже). До закрытия D9 — ещё используется как историческая ссылка в +находках раздела 3. [implementation-plan.md](implementation-plan.md) — открытые вопросы для v1.0/v1.x. [roadmap.md](roadmap.md) — линия 2.x.x. [progress.md](progress.md) — живой трекер, читается первым после `/clear`. -[security.md](security.md) — принятые риски. Этот файл — план по документации. +[security.md](security.md) — обязательные требования безопасности + принятые +риски. Этот файл — план по документации. -**Новое: `docs/architecture.md` и `docs/development.md` — нужны, решение -принято.** ТЗ их не требует (ТЗ 11 не относит их к обязательной поставке), но -без них понимание устройства и повторная сборка проекта держатся только на -памяти и контексте текущей сессии — то есть не переживают её потерю ни для -будущего контрибьютора, ни для будущего прохода без доступа к истории чата. -Обе — рабочие документы проекта (не часть поставки пользователю, не -упоминаются в README как обязательные), задача заведена в разделе 4 (**D8**). +**Новые `product.md`, `architecture.md`, `development.md` — решение принято.** +В обязательную поставку пользователю (README) они не входят, но без них +понимание проекта держится на памяти сессии. Их содержимое **заменяет** живой +`specification.md` для всех будущих проходов — задачи **D8** и **D9**. -- `docs/architecture.md` — компоненты контейнера (`supervisord`, - `postfix`, `opendkim`, `panel`, milter-цепочка) и как они связаны; путь - письма через тракт (SMTP submission → milter'ы → OpenDKIM → доставка); - что читает/пишет `/data` и в каком формате; где проходит граница - привилегий (root vs непривилегированный uid панели) и почему — - источник истины: код (`build/supervisord.conf`, `internal/`), а не - ТЗ, план сверки — тот же метод из раздела 2. -- `docs/development.md` — как собрать и прогнать тесты локально (Go - локально, без Docker — см. память проекта), когда нужен полный - контейнерный цикл на dev-сервере (сборка образа, milter/почтовые - изменения) и почему локальной сборки недостаточно, порядок ручной - проверки на `selfpost.example.com` перед мёржем. Заменяет часть, что - раньше держалась только в памяти проекта и `progress.md` — там - остаётся текущее состояние и следующий шаг, а не воспроизводимая - процедура. +- `docs/product.md` — из ТЗ §1–3 и §4.1: зачем SelfPost, инфраструктурные + предпосылки, out of scope, мультидоменная модель «домен ↔ приложения ↔ + режим From». Границы продукта, меняющиеся только явным решением. +- `docs/architecture.md` — as-built по коду: `supervisord`, `postfix`, + `opendkim`, panel (HTTP + journal-milter + log-tailer); порядок старта; + milter-цепочка; Postfix/SASL/TLS; журнал отправки и L1/L2 rate-limit; + бэкап/restore; персистентность `/data`. Источник истины — код, не ТЗ. +- `docs/development.md` — Go локально, `go test`/`go vet`, `make e2e`, когда + нужен полный контейнер на dev-сервере, ручная проверка на + `selfpost.example.com`, протокол коммитов/CHANGELOG, правила для агента + (бывшее ТЗ §12). В `progress.md` — текущее состояние, не процедура. + +### Карта миграции из `specification.md` + +| Блок ТЗ | Новый дом | Задача | +|---|---|---| +| §1–3, §4.1 | `product.md` | D9 | +| §4, §5–7 (техника), §9 | `architecture.md` | D8 | +| §7.6 | `security.md` («Обязательные требования») | D9 | +| §8 | README (таблица env) | D2 | +| §9 (путь `tar` для пользователя) | README | D3 | +| §10–11 | README + таблица «Поставка» выше | D1–D4 | +| §12 | `development.md` | D8 | + +После D9: `specification.md` → `docs/archive/specification-v1.0.md` (снимок, +не правится); в `docs/` живых ссылок на него нет. **Границы (без изменений):** отдельные `CONTRIBUTING.md`, man-страницы и сайт -документации ТЗ по-прежнему не требует и в объём v1.x не входят. +документации в объём v1.x не входят. --- @@ -82,11 +104,16 @@ | Сессии, вход, смена пароля | [internal/store/sessions.go](../internal/store/sessions.go), [internal/web/session.go](../internal/web/session.go), [internal/web/handlers_account.go](../internal/web/handlers_account.go) | | Ротация лога, периодический reload, интервалы | [build/logrotate-mail.conf](../build/logrotate-mail.conf), [build/logrotate-loop.sh](../build/logrotate-loop.sh), [build/postfix-cert-reload.sh](../build/postfix-cert-reload.sh) | | Деплой: тег образа, порты, монтирования, capabilities | [deploy/docker-compose.yml](../deploy/docker-compose.yml), [build/Dockerfile](../build/Dockerfile) | -| Требования, а не реализация (что вообще должно быть описано) | [specification.md](specification.md) разделы 9, 10, 11 | +| Обязательное содержание README (чеклист поставки) | таблица «Поставка» в §1 этого файла (бывшее ТЗ §10–11) | +| Границы продукта, out of scope | [product.md](product.md) *(после D9)* | +| As-built устройство (не пользовательский текст) | [architecture.md](architecture.md) *(после D8)* | +| Обязательные требования безопасности | [security.md](security.md) *(после D9)* | Порядок прохода: сначала перечислить фактическое (env-ключи, маршруты, -`postconf`-настройки), потом искать каждый пункт в README — так находится и -неверное, и **отсутствующее**. +`postconf`-настройки), потом искать каждый пункт в README / `architecture.md` — +так находится и неверное, и **отсутствующее**. До закрытия D9 для чеклиста +README допустима сверка с `specification.md` §10–11; после D9 — только с §1 +этого файла. --- @@ -230,7 +257,8 @@ DNS-карточка домена); прогрев IP; смысл фиксиро «на живом контейнере так делать не надо, потому что SQLite в WAL». Заодно упомянуть, что `manifest.json` после успешного восстановления потребляется. -**D4. Точечные правки.** Находки 5, 7, 8, 11: баннер статуса и ссылки; комментарий +**D4. Точечные правки.** Находки 5, 7, 8, 11: баннер статуса и ссылки (убрать +ссылку на `specification.md` — после D9 продукт в `product.md`); комментарий в шапке compose про `.env`; строка про 587; бамп тега образа (делается в релизном коммите, не раньше). @@ -245,17 +273,36 @@ DNS-карточка домена); прогрев IP; смысл фиксиро **D7. Регресс-защита (см. раздел 5).** -**D8. Новые документы: `docs/architecture.md` и `docs/development.md`.** -Пишутся с нуля (в разделе 3 их нет — это не расхождение с кодом, а -отсутствовавший артефакт). `architecture.md` сверяется тем же методом, что и -остальное (раздел 2): по факту компоновки образа и кода, не по памяти. -`development.md` фиксирует уже существующий, но нигде не описанный процесс -(Go локально / полный цикл на dev-сервере для Docker-зависимых изменений). +**D8. Новые документы: `architecture.md` и `development.md`.** Пишутся с нуля и +перенимают техническую часть ТЗ (§4–7, §9, §12) в форму as-built / процесса. +`architecture.md` сверяется методом из раздела 2 — по коду, не по памяти. +`development.md` фиксирует воспроизводимый процесс (Go локально / e2e / +dev-сервер). *Готово, когда:* `architecture.md` перечисляет все managed-процессы из [build/supervisord.conf](../build/supervisord.conf) и путь письма через milter-цепочку без противоречий коду; `development.md` позволяет с нуля -повторить локальную сборку + прогон тестов и понять, когда нужен -dev-сервер, не заглядывая в память проекта. +повторить локальную сборку + прогон тестов и понять, когда нужен dev-сервер, +не заглядывая в память проекта и не открывая `specification.md`. + +**D9. Вывод `specification.md` из обращения (после D1–D8).** Закрывает цель +плана: живой ТЗ больше не нужен. +1. Создать `docs/product.md` — §1–3, §4.1 (см. карту миграции в §1). +2. Дополнить [security.md](security.md) разделом «Обязательные требования» — + самодостаточный чеклист из бывшего §7.6 (setup-link, SASL, сессии, + rate-limit логина, `html/template`, не-root и т.д.), без отсылки «см. ТЗ». +3. Убедиться, что D1–D4 и D8 покрыли всё из §8–11, что должно жить в README / + `architecture.md` (пройти карту миграции построчно). +4. Перенести `specification.md` → `docs/archive/specification-v1.0.md` без + правок текста; в начале архива — одна строка: «исторический снимок v1.0, + не источник истины». +5. Обновить ссылки во всём репозитории: `progress.md` (убрать «ТЗ: + specification.md», заменить на `product.md` + `architecture.md`), + `implementation-plan.md` и `roadmap.md` («Основа» → `product.md`), + `security.md`, `README.md` (баннер D4 — не на ТЗ). `rg specification\.md` + по репо — только архив и CHANGELOG/история. +*Готово, когда:* в `docs/` нет `specification.md`; новый агент после `/clear` +может понять продукт, устройство, безопасность и процесс разработки, не +открывая архив. --- @@ -270,16 +317,18 @@ dev-сервер, не заглядывая в память проекта. новом недокументированном ключе. Ловит самый частый класс расхождений (находка 3) без ручного прохода. Границу «внутренних» ключей задать явным списком-исключением в самом тесте. -3. **Перед каждым тегом** — короткий проход по разделу 2 этого файла (семь - источников истины), а не полная ревизия текста. +3. **Перед каждым тегом** — короткий проход по разделу 2 (источники истины в + коде + README + `architecture.md` + `product.md`), а не полная ревизия текста + и не сверка с архивным ТЗ. --- ## 6. Гейт релиза Документационный проход — часть того же гейта, что e2e (C.4) и ревизия -безопасности (D.5): **D1–D6 закрыты до тега**. D7 и D8 — желательны, но тег не -блокируют: D8 не покрывает пробел против ТЗ (архитектура/разработка не входят -в обязательную поставку), поэтому может тянуться в фон после релиза. Находки, -обнаруженные позже, дописываются сюда, а не исправляются молча: этот файл — -журнал состояния документации, а не одноразовый список дел. +безопасности (D.5): **D1–D6 и D9 закрыты до тега**. D7 желателен, но тег не +блокирует. **D8** — обязателен до D9 (архитектура должна существовать до +миграции); D8 один тег не блокирует, если D9 отложен, но **полное закрытие +плана (= вывод specification) — только D1–D9 вместе**. Находки, обнаруженные +позже, дописываются сюда, а не исправляются молча: этот файл — журнал +состояния документации, а не одноразовый список дел.