diff --git a/docs/v1.x-closure-plan.md b/docs/v1.x-closure-plan.md new file mode 100644 index 0000000..4cee7a4 --- /dev/null +++ b/docs/v1.x-closure-plan.md @@ -0,0 +1,200 @@ +# План закрытия хвоста v1.x + +**Статус:** в работе. **Целевой релиз:** `v1.0.0` / `ghcr.io/mixeme/selfpost:1.0.0`. + +**Временный файл:** после закрытия v1.x удалить (история — git + CHANGELOG). Не часть постоянного пакета docs. + +**Контекст:** релизный гейт по коду закрыт (B.1–B.3, C.4 e2e, § D Fable). Остаток — [roadmap.md](roadmap.md) § «v1.x — хвост документации и деплоя» + код из того же секции. + +**Политика docs:** `docs/archive/` не храним; устаревшие планы удаляем после переноса полезного в [development.md](development.md). + +--- + +## Рекомендация по модели + +Общее правило (переносится в development.md): + +| Тип работы | Модель | Примеры в этом плане | +|------------|--------|---------------------| +| Безопасность, инфра, права файлов, postfix/postqueue, open-relay-риски | **Opus** | mail.log в `/data`, entrypoint permissions, postqueue reconcile | +| UI/JS/CSS, шаблоны, документация (English), README | **Sonnet** | adaptive polling, development.md § Documentation, README index | +| Тривиальная механика: retarget ссылок, grep, compose bump, CHANGELOG cut | **Haiku** | Makefile/release.yml комментарии, удаление файлов | +| Ревизия безопасности (**review**, не authorship) | **Fable** | не в этом плане (§ D уже выполнен) | + +| Фаза / коммит | Модель | Почему | +|---------------|--------|--------| +| 1. Polling | Sonnet | panel.js + HTMX, CSP | +| 2. mail.log + reconcile | Opus (+ Sonnet на unit-тесты) | postfix path, logrotate, entrypoint, postqueue | +| 3. Docs consolidation | Sonnet | development.md, README, agent-rules | +| 4. Release `1.0.0` | Haiku / Sonnet | механика релиза, без новой логики | +| 5. Tag / push | **Оператор** | явная команда | + +Сообщение коммита: трейлер `Co-Authored-By: Claude <модель> ` с моделью, которая делала шаг. + +--- + +## Общий чек-лист прогресса + +- [ ] **Фаза 1** — адаптивный опрос мониторинга +- [ ] **Фаза 2** — mail.log в `/data` + postqueue reconcile +- [ ] **Фаза 3** — docs: development.md, README, удаление планов и `docs/archive/` +- [ ] **Фаза 4** — релизный коммит `1.0.0` (по явной команде) +- [ ] **Фаза 5** — tag `v1.0.0` + push (по явной команде) +- [ ] **Фаза 6** — выкат на прод (оператор) + +**Гейт перед тегом:** + +- [ ] `gofmt -l .` чистый +- [ ] `go vet ./...` чистый +- [ ] `go test ./...` чистый (Windows-падения domain/logtail — известны, не блокер) +- [ ] `make e2e` зелёный (если Docker доступен) +- [ ] grep: нет ссылок на удалённые docs в живых файлах + +--- + +## Фаза 1 — Адаптивный опрос мониторинга + +**Модель:** Sonnet. + +**Цель:** 5 s при активности, 30 s при простое; скрытая вкладка — 0 запросов. Без `hx-trigger="every 5s [expr]"` (CSP / `unsafe-eval`). + +### Чек-лист + +- [ ] `status_body.html`, `mail_queue_body.html`, `system_log_body.html`, `deliveries_rows.html` — `hx-trigger="load"` + маркер polling +- [ ] `panel.js` — `lastActivity`, schedule после `htmx:afterRequest` (5s / 30s) +- [ ] `htmx:afterSwap` — реинициализация polling-элементов +- [ ] `beforeRequest` для hidden tab — оставлен +- [ ] `architecture.md` — одна строка про polling +- [ ] CHANGELOG `[Unreleased]` +- [ ] Стенд (опционально): idle → ~30s; активность → ~5s; hidden → 0 запросов + +--- + +## Фаза 2 — Send-log vs `mail.log` + +**Модель:** Opus (infra); Sonnet (тесты). + +### 2.1 `mail.log` → `/data/log/mail.log` + +- [ ] `build/postfix-config.sh` — `maillog_file` +- [ ] `build/logrotate-mail.conf` — путь +- [ ] `build/entrypoint.sh` — `mkdir`, права (postfix write, panel read) +- [ ] `cmd/panel/main.go` — default `MAIL_LOG` +- [ ] `test/e2e/mail_helpers.go` — путь в контейнере +- [ ] `guide.md` — `MAIL_LOG`, рост диска `/data/log` +- [ ] `envdoc_test` — при изменении env + +### 2.2 Postqueue reconcile + +- [ ] `internal/postfix` — парсер queue-id из `postqueue -p` + тест +- [ ] `internal/store` — `ListQueuedOlderThan(grace)` +- [ ] `internal/logtail` — periodic sweep, grace ~2 min → `bounced` +- [ ] Тесты reconcile + +### 2.3 Документация и риски + +- [ ] `architecture.md` — `/data/log`, reconcile; убрать gap «container recreate» +- [ ] `security.md` — снять принятый риск «вечный queued» +- [ ] CHANGELOG `[Unreleased]` + +--- + +## Фаза 3 — Документация + +**Модель:** Sonnet. + +### 3.1 `documentation-plan.md` → development.md, затем delete + +- [ ] development.md § **Documentation**: + - [ ] Documentation map (без archive; история = git + CHANGELOG) + - [ ] User-facing deliverables + - [ ] Maintaining documentation (§3 правила) + - [ ] Verifying docs against code (полная таблица §2) +- [ ] `architecture.md` шапка → development.md +- [ ] Удалить `documentation-plan.md` +- [ ] Retarget `roadmap.md` + +### 3.2 `progress.md` → development.md, затем delete + +- [ ] development.md § **Resuming work** +- [ ] development.md § **Model routing** +- [ ] development.md § **Commits** (слить с Release build) +- [ ] development.md § **Phase closure** (roadmap, не progress) +- [ ] `agent-rules.mdc` → development.md +- [ ] Удалить `progress.md` +- [ ] Retarget все ссылки + +### 3.3 Удалить `docs/archive/` + +- [ ] Удалить `docs/archive/specification-v1.0.md` +- [ ] Удалить каталог `docs/archive/` +- [ ] Убрать ссылки на archive из живых docs (CHANGELOG историю ниже 0.6.0 не трогать) + +### 3.4 README + +- [ ] § Documentation: operator docs + roadmap (internal, Russian) +- [ ] Без секции Archive + +### 3.5 Проверка + +- [ ] `gofmt` / `vet` / `test` +- [ ] grep живых ссылок на удалённые файлы + +--- + +## Фаза 4 — Релизный коммит R1 + +**Модель:** Haiku / Sonnet. **Только по явной команде оператора.** + +- [ ] CHANGELOG: `[Unreleased]` → `[1.0.0] - дата`, новая `[Unreleased]` +- [ ] `deploy/docker-compose.yml` → `ghcr.io/mixeme/selfpost:1.0.0` +- [ ] Удалить `implementation-plan.md` (если ещё есть) +- [ ] Makefile, `.github/workflows/release.yml`, `test/e2e/main_test.go` → development.md +- [ ] `roadmap.md` — секция v1.x **закрыта**; убрать «переместить в archive» +- [ ] Финальный grep ссылок +- [ ] Удалить этот файл (`v1.x-closure-plan.md`) в том же или следующем коммите + +--- + +## Фаза 5 — Tag и push + +**Оператор.** Явная команда. + +```sh +git tag v1.0.0 +git push origin v1.0.0 +``` + +- [ ] `release.yml` — build amd64+arm64, e2e gate, push GHCR `1.0.0` +- [ ] compose tag и git tag совпадают + +--- + +## Фаза 6 — Прод (оператор) + +- [ ] `docker compose pull` → `1.0.0` +- [ ] Разлогин (cookie `__Host-`) +- [ ] Reverse-proxy передаёт `Host` +- [ ] `./data/log/` создался после upgrade + +--- + +## Критерий «хвост v1.x закрыт» + +- [ ] Все чек-листы фаз 1–4 отмечены +- [ ] `compose` = `1.0.0`, тег `v1.0.0` в репо +- [ ] Нет `implementation-plan.md`, `documentation-plan.md`, `progress.md`, `docs/archive/`, `v1.x-closure-plan.md` +- [ ] Нет активных ссылок на удалённые пути +- [ ] `development.md` — процесс + Documentation + model routing +- [ ] `roadmap.md` — единственный internal tracker +- [ ] Polling 5s/30s; mail.log в `/data`; reconcile; риск security снят + +--- + +## Разбивка коммитов + +1. **Polling** — panel.js, templates, architecture (+ CHANGELOG) +2. **mail.log + reconcile** — build, logtail, store, postfix, docs (+ CHANGELOG) +3. **Docs** — development.md, README, agent-rules; delete documentation-plan, progress, archive; retarget (+ CHANGELOG) +4. **Release 1.0.0** — CHANGELOG cut, compose, delete implementation-plan, roadmap closure, delete `v1.x-closure-plan.md` +5. **Tag/push** — оператор