diff --git a/CHANGELOG.md b/CHANGELOG.md index d77d22d..050af13 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -7,6 +7,12 @@ Format follows [Keep a Changelog](https://keepachangelog.com/en/1.1.0/); version ### Added +- docs: **Plan checklists** in [development.md](docs/development.md) — format, + `Progress` column in [roadmap.md](docs/roadmap.md), per-step commit + + CHANGELOG, version cuts `1.3.1`…`1.8.0` per roadmap stage. +- docs: **Implementation checklists** with model routing in + [docs/plans/](docs/plans/) (queue-retries, inbound-relay, send-log-retention, + domain-stats-auto-ratelimit, dmarc-reports, panel-docs). - docs: roadmap candidates **send-log-retention** (panel Settings for delivery journal retention) and **domain-stats-auto-ratelimit** (30-day send stats per domain/application, auto level-2 rate limit from avg × multiplier) — plans in diff --git a/docs/development.md b/docs/development.md index 382ded3..2ffd831 100644 --- a/docs/development.md +++ b/docs/development.md @@ -66,6 +66,58 @@ mechanics → Haiku. Reviewers must not be the author of the code under review. --- +## Plan checklists + +Open [roadmap.md](roadmap.md) items with a linked plan file carry an +**Implementation checklist** in [plans/](plans/). After a context reset, work +the **active** plan — not the roadmap prose — from the first unchecked line. + +**Checklist format** + +- `- [ ] Step description — **Model**` (model from the routing table above). +- Mark `[x]` only in the commit that actually finishes the step. +- `candidate` items: checklist may exist, but no code until the roadmap status + is agreed. + +**Progress column** in the roadmap index (`0/N`) counts every checklist line in +that plan (including docs and `go vet` / `go test` steps). Update `N` when the +checklist changes; update the numerator when steps are checked off. + +### Roadmap track: commit and version + +For the current 1.x+ roadmap queue ([roadmap.md](roadmap.md) index), stricter +than the default «meaningful step» rule in [§ Commits and release build](#commits-and-release-build): + +**After each checklist step** + +1. Check off the step in the plan file; bump `Progress` in the roadmap index. +2. Append [CHANGELOG.md](../CHANGELOG.md) under `[Unreleased]` for that step. +3. Commit on `main` (push / tag / Release only on explicit request). + +**After each roadmap stage** (all checklist steps done; «Done when» satisfied) + +1. Version cut in one commit: rename `[Unreleased]` to `[X.Y.Z] - date`, open a + fresh `[Unreleased]`, bump the image pin in + [deploy/docker-compose.yml](../deploy/docker-compose.yml). +2. Git tag `vX.Y.Z` and publish the GitHub Release only on explicit request (see + [§ Release image](#release-image)). + +**Planned version cuts** (from pin `1.3.0`; adjust if semver changes mid-track): + +| Stage | ID | Cut | +|---|---|---| +| 1 | queue-retries | `1.3.1` (PATCH) | +| 2 | inbound-relay | `1.4.0` | +| 3 | send-log-retention | `1.5.0` | +| 4 | domain-stats-auto-ratelimit | `1.6.0` | +| 5 | dmarc-reports | `1.7.0` | +| 6 | panel-docs | `1.8.0` | + +Docs-only prep (checklists in plans, no product code) uses the same per-step +commit rule but **no** version cut until stage 1 ships. + +--- + ## Technology stack and tools | Component | Version / notes | diff --git a/docs/plans/dmarc-reports.md b/docs/plans/dmarc-reports.md index 6bf70e4..c2d0028 100644 --- a/docs/plans/dmarc-reports.md +++ b/docs/plans/dmarc-reports.md @@ -48,3 +48,18 @@ remain a separate, opt-in feature that does not forward mail upstream. - Attack surface of accepting mail (mitigate: strict recipient allow-list). - Report volume and retention (mitigate: caps + pruning). + +## Implementation checklist + +Target version cut: **`1.7.0`** (MINOR). One commit per step; code only after +roadmap status is **agreed**. Expand the sketch sections above before step 1 +if still thin. See [development.md](../development.md) § Plan checklists. + +- [ ] Expand plan: ingest path, `dmarc_reports` schema, retention caps — **Sonnet** +- [ ] Opt-in inbound SMTP for report addresses only (allow-list) — **Opus** +- [ ] Worker: gzip/XML parse → SQLite — **Opus** +- [ ] Panel: domain roll-up + parsed report (panel-ui mockups) — **Sonnet** +- [ ] Tie-in `dmarc_report_email` / `domains.dmarc_rua` — **Sonnet** +- [ ] Tests and [guide.md](../guide.md) — **Sonnet** +- [ ] Security review ingest path — **Fable** +- [ ] `go vet`, `go test` on touched packages — **Haiku** diff --git a/docs/plans/domain-stats-auto-ratelimit.md b/docs/plans/domain-stats-auto-ratelimit.md index 4301eb5..73495a9 100644 --- a/docs/plans/domain-stats-auto-ratelimit.md +++ b/docs/plans/domain-stats-auto-ratelimit.md @@ -185,3 +185,21 @@ change in [guide.md](../guide.md) § Export. from the panel. **Version:** `1.x` MINOR. + +## Implementation checklist + +Target version cut: **`1.6.0`** (MINOR). One commit per step; code only after +roadmap status is **agreed**. See [development.md](../development.md) § Plan +checklists. + +- [ ] Migration `0006_rate_limit_auto.sql` (`mode`, `auto_multiplier`, `auto_updated_at`) — **Opus** +- [ ] `internal/store/stats.go`: total / peak / avg over 30 days — **Opus** +- [ ] Auto recalc job (6h): `ceil(avg × multiplier)`, L1 cap, fail-open on error — **Opus** +- [ ] Extend `RateLimit` + handler forms (manual/auto) — **Opus** +- [ ] Domain page stats card + per-app stats (`domain_detail.html`) — **Sonnet** +- [ ] Domain export JSON includes rate limits — **Opus** +- [ ] Milter tests — enforced limit matches stored ceiling — **Opus** +- [ ] Store and handler tests — **Sonnet** +- [ ] [guide.md](../guide.md) — **Sonnet** +- [ ] Security review rate-limit path — **Fable** +- [ ] `go vet`, `go test` on touched packages — **Haiku** diff --git a/docs/plans/inbound-relay.md b/docs/plans/inbound-relay.md index a22a011..5d5f964 100644 --- a/docs/plans/inbound-relay.md +++ b/docs/plans/inbound-relay.md @@ -169,3 +169,25 @@ the SelfPost image, brought up by the operator when the option is enabled. A finished outbound path (already implemented). Agreement obtained — see the status above. + +## Implementation checklist + +Target version cut: **`1.4.0`** (MINOR). One commit per step; see +[development.md](../development.md) § Plan checklists. UI reference: +[panel-ui inbound mockups](../assets/panel-ui/inbound.html). + +- [ ] Migration: inbound domain / recipient / transport tables under `/data` — **Opus** +- [ ] `INBOUND_RELAY_ENABLE` (default false) in entrypoint + `postfix-config.sh` — **Opus** +- [ ] `master.cf`: inbound `smtp inet` on 25; separate from 465/587 — **Opus** +- [ ] Generate `relay_domains`, `transport_maps`, `relay_recipient_maps` (injection-safe) — **Opus** +- [ ] `smtpd_relay_restrictions` / recipient maps — no open relay, no backscatter — **Opus** +- [ ] `internal/store` CRUD + validation (domain, host, port) — **Opus** +- [ ] Panel: list, add, domain detail, recipients, danger zone (mockups) — **Sonnet** +- [ ] Rate limit + `message_size_limit` on inbound smtpd — **Opus** +- [ ] Optional `INBOUND_ANTISPAM_MILTER` + compose fragment — **Opus** +- [ ] DNS MX copy in README/guide; `.env.example` — **Sonnet** +- [ ] Backup/export inbound config (per plan optional flag) — **Opus** +- [ ] Unit + handler tests; image build and container smoke — **Opus** +- [ ] [guide.md](../guide.md) and [security.md](../security.md) — **Sonnet** +- [ ] Security review inbound path — **Fable** +- [ ] `go vet`, `go test`, e2e if applicable — **Haiku** diff --git a/docs/plans/panel-docs.md b/docs/plans/panel-docs.md new file mode 100644 index 0000000..dac8014 --- /dev/null +++ b/docs/plans/panel-docs.md @@ -0,0 +1,54 @@ +# Plan: panel-docs (in-panel operator documentation) + +**Status:** candidate +**Date:** 2026-08-17 +**Version:** `1.x` MINOR; `candidate` until explicitly agreed. + +--- + +## Goal + +Built-in operator documentation in the panel — short pages or a help drawer that +explain what each Status check and other controls mean, without sending the +operator out to [guide.md](../guide.md). + +## Scope + +**In:** + +- Help drawer or short help pages (CSS-checkbox pattern from + [panel-ui mockups](../assets/panel-ui/system.html)). +- Seed content: Status blurbs removed from cards for a denser layout — Machine + (kernel counters / rate window), TLS certificate (port 465, reverse-proxy + mount), Hostname / reverse DNS (FCrDNS, PTR at the hosting provider), and + similar notes for other surfaces as inline commentary is removed. +- «?» entry points on domain cards (mockups). + +**Out:** + +- A second copy of the full operator guide. +- Translation workflow beyond English (same as the rest of the panel). + +## Done when + +An operator can open help from the panel for those topics; the removed Status +blurbs are preserved there (or equivalent); no requirement to read the git +tree for day-to-day meaning of a card. + +## Risks + +Copy ownership and keeping help in sync when checks change; not bloating every +page with a second column of prose. + +## Implementation checklist + +Target version cut: **`1.8.0`** (MINOR). One commit per step; code only after +roadmap status is **agreed**. See [development.md](../development.md) § Plan +checklists. + +- [ ] Help drawer / pages shell (CSS checkbox pattern from mockups) — **Sonnet** +- [ ] Seed Status blurbs (Machine, TLS, PTR, …) — **Sonnet** +- [ ] «?» entry points on domain cards — **Sonnet** +- [ ] [guide.md](../guide.md) boundary: in-panel help vs full guide — **Sonnet** +- [ ] Template tests — **Sonnet** +- [ ] `go vet`, `go test` on touched packages — **Haiku** diff --git a/docs/plans/queue-retries.md b/docs/plans/queue-retries.md index 003daa3..0dc17f0 100644 --- a/docs/plans/queue-retries.md +++ b/docs/plans/queue-retries.md @@ -139,3 +139,18 @@ lifetime runs out. - Showing compiled-in fallbacks when `postconf` failed would mislead if the operator had overridden them — mitigate with the muted note on the card. - Inventing a max-attempt count would be false; the copy must stay time-based. + +## Implementation checklist + +Target version cut: **`1.3.1`** (PATCH). One commit per step; see +[development.md](../development.md) § Plan checklists. + +- [ ] `internal/postfix`: parse Postfix time units (`5d`, `300s`, bare seconds) + tests — **Opus** +- [ ] `internal/postfix`: one-shot `postconf -h` (six keys), fallback + warn — **Opus** +- [ ] Load policy at HTTP start in `cmd/panel/httpserver.go`; cache on handlers config — **Opus** +- [ ] Human-readable duration formatter (shared by Mail queue card and delivery history) — **Sonnet** +- [ ] «How delivery retries work» card on `/mail-queue` (outside HTMX fragment) — **Sonnet** +- [ ] `deliveryEvents(row, policy)` — intervals in deferred/bounced copy — **Sonnet** +- [ ] Handler and template tests (`handlers_monitor_test.go`, `templates_test.go`) — **Sonnet** +- [ ] [guide.md](../guide.md) and [architecture.md](../architecture.md) — **Sonnet** +- [ ] `go vet`, `go test` on touched packages — **Haiku** diff --git a/docs/plans/send-log-retention.md b/docs/plans/send-log-retention.md index d3d484b..b7b4e91 100644 --- a/docs/plans/send-log-retention.md +++ b/docs/plans/send-log-retention.md @@ -122,3 +122,18 @@ Domain administrators keep the narrow credentials-only settings page. stale int from panel start only. **Version:** `1.x` MINOR. + +## Implementation checklist + +Target version cut: **`1.5.0`** (MINOR). One commit per step; code only after +roadmap status is **agreed**. See [development.md](../development.md) § Plan +checklists. + +- [ ] `GetSendLogRetentionDays` / `SetSetting` key `send_log_retention_days` (7–365) — **Opus** +- [ ] Bootstrap from `SEND_LOG_RETENTION_DAYS` when settings empty — **Opus** +- [ ] `logtail.retentionLoop`: read setting each prune cycle — **Opus** +- [ ] Settings card on `/settings` (`settings.html`) — **Sonnet** +- [ ] Remove hardcoded «ninety days» in handlers and templates — **Sonnet** +- [ ] Tests: save/load, range, loop without restart — **Sonnet** +- [ ] [guide.md](../guide.md) — **Sonnet** +- [ ] `go vet`, `go test` on touched packages — **Haiku** diff --git a/docs/roadmap.md b/docs/roadmap.md index 62476f6..edd6be2 100644 --- a/docs/roadmap.md +++ b/docs/roadmap.md @@ -26,16 +26,16 @@ in `git log` and [CHANGELOG.md](../CHANGELOG.md). ## Index -| ID | Topic | Status | Plan | -|---|---|---|---| -| queue-retries | Postfix retry policy in the panel (queue lifetime, backoff) | **agreed** | [plans/queue-retries.md](plans/queue-retries.md) | -| inbound-relay | Inbound relay (backup-MX / forwarding) | **agreed** | [plans/inbound-relay.md](plans/inbound-relay.md) | -| send-log-retention | Send-log retention days in panel Settings | candidate | [plans/send-log-retention.md](plans/send-log-retention.md) | -| domain-stats-auto-ratelimit | 30-day send stats + auto level-2 rate limit | candidate | [plans/domain-stats-auto-ratelimit.md](plans/domain-stats-auto-ratelimit.md) | -| contributing | `CONTRIBUTING.md` | candidate | — | -| dmarc-reports | DMARC aggregate report ingestion and panel UI | candidate | [plans/dmarc-reports.md](plans/dmarc-reports.md) | -| panel-docs | In-panel operator documentation | candidate | — | -| schema-squash | Squash SQLite migrations into a 2.x baseline | **2.x** | — | +| ID | Topic | Status | Progress | Plan | +|---|---|---|---|---| +| queue-retries | Postfix retry policy in the panel (queue lifetime, backoff) | **agreed** | 0/9 | [plans/queue-retries.md](plans/queue-retries.md) | +| inbound-relay | Inbound relay (backup-MX / forwarding) | **agreed** | 0/15 | [plans/inbound-relay.md](plans/inbound-relay.md) | +| send-log-retention | Send-log retention days in panel Settings | candidate | 0/8 | [plans/send-log-retention.md](plans/send-log-retention.md) | +| domain-stats-auto-ratelimit | 30-day send stats + auto level-2 rate limit | candidate | 0/11 | [plans/domain-stats-auto-ratelimit.md](plans/domain-stats-auto-ratelimit.md) | +| contributing | `CONTRIBUTING.md` | candidate | — | — | +| dmarc-reports | DMARC aggregate report ingestion and panel UI | candidate | 0/8 | [plans/dmarc-reports.md](plans/dmarc-reports.md) | +| panel-docs | In-panel operator documentation | candidate | 0/6 | [plans/panel-docs.md](plans/panel-docs.md) | +| schema-squash | Squash SQLite migrations into a 2.x baseline | **2.x** | — | — | **Recommended order** (not binding): **queue-retries** is a small panel item that can land first or in parallel; the next feature is **inbound-relay**. @@ -47,7 +47,9 @@ fail-closed paths, docs, GUI, tests, licence) are closed — history in explicit agreement before they join the queue. After a context reset, pick an item marked `agreed` or `in progress`, then work -the checklist in its linked plan. +the **Implementation checklist** in its linked plan. The `Progress` column above +is `done/total` checklist steps in that plan ([development.md](development.md) +§ Plan checklists). ---