# План закрытия хвоста 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 <модель> ` с моделью, которая делала шаг. --- ## Общий чек-лист прогресса - [x] **Фаза 1** — адаптивный опрос мониторинга - [x] **Фаза 2** — mail.log в `/data` + postqueue reconcile - [x] **Фаза 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`). ### Чек-лист - [x] `status_body.html`, `mail_queue_body.html`, `system_log_body.html`, `deliveries_rows.html` — `hx-trigger="load"` + маркер polling - [x] `panel.js` — `lastActivity`, schedule после `htmx:afterRequest` (5s / 30s) - [x] `htmx:afterSwap` — реинициализация polling-элементов - [x] `beforeRequest` для hidden tab — оставлен - [x] `architecture.md` — одна строка про polling - [x] CHANGELOG `[Unreleased]` - [ ] Стенд (опционально): idle → ~30s; активность → ~5s; hidden → 0 запросов --- ## Фаза 2 — Send-log vs `mail.log` **Модель:** Opus (infra); Sonnet (тесты). ### 2.1 `mail.log` → `/data/log/mail.log` - [x] `build/postfix-config.sh` — `maillog_file` из `MAIL_LOG` - [x] `build/logrotate-mail.conf` — путь + `create 0640 postfix selfpost` - [x] `build/entrypoint.sh` — `mkdir`, права (`2750 postfix:selfpost`, файл `0640`), исключение `/data/log` из общего `chown` на `panel` - [x] `cmd/panel/main.go` — default `MAIL_LOG` - [x] `internal/backup` — исключить `log/` из архива (+ тест) - [x] `test/e2e/mail_helpers.go` — путь в контейнере - [x] `guide.md` — `MAIL_LOG`, System log, бэкап `./data`; README — рост диска - [x] `envdoc_test` — `MAIL_LOG` в `buildScriptKeys` ### 2.2 Postqueue reconcile - [x] `internal/postfix` — `QueueIDs` / парсер queue-id из `postqueue -p` + тест - [x] `internal/store` — `ListQueuedOlderThan(cutoff)` - [x] `internal/logtail` — periodic sweep (5 min), grace 2 min → `bounced`, старт только после того, как tailer дочитал лог до конца - [x] Тесты reconcile ### 2.3 Документация и риски - [x] `architecture.md` — `/data/log`, reconcile; gap «container recreate» убран - [x] `security.md` — риск «вечный queued» снят; на его месте — ложный `bounced` и права на лог - [x] CHANGELOG `[Unreleased]` **Стенд (остаток, для оператора):** Docker на машине разработки недоступен — сборка образа и старт контейнера не проверены. Проверить при выкате: `/data/log` создаётся с нужными правами, панель читает `mail.log`, logrotate проворачивает файл, `postqueue -p` читается из-под `panel`. --- ## Фаза 3 — Документация **Модель:** Sonnet. ### 3.1 `documentation-plan.md` → development.md, затем delete - [x] development.md § **Documentation**: - [x] Documentation map (без archive; история = git + CHANGELOG) - [x] User-facing deliverables - [x] Maintaining documentation (§3 правила) - [x] Verifying docs against code (полная таблица §2) - [x] `architecture.md` шапка → development.md - [x] Удалить `documentation-plan.md` - [x] Retarget `roadmap.md` ### 3.2 `progress.md` → development.md, затем delete - [x] development.md § **Resuming work** - [x] development.md § **Model routing** - [x] development.md § **Commits** (слить с Release build) - [x] development.md § **Phase closure** (roadmap, не progress) - [x] `agent-rules.mdc` → development.md - [x] Удалить `progress.md` - [x] Retarget все ссылки ### 3.3 Удалить `docs/archive/` - [x] Удалить `docs/archive/specification-v1.0.md` - [x] Удалить каталог `docs/archive/` - [x] Убрать ссылки на archive из живых docs (CHANGELOG историю ниже 0.6.0 не трогать) ### 3.4 README - [x] § Documentation: operator docs + roadmap (internal, Russian) - [x] Без секции Archive ### 3.5 Проверка - [x] `gofmt` / `vet` / `test` - [x] 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** — оператор