docs: clear shipped plans and closed work out of the documents
test / test (push) Waiting to run

Owner, 2026-10-18: "Надо почистить документы от устаревшего и сделанного."

- Deleted, shipped: plans/delivery-log-storage, from-header-binding,
  inbound-antispam-panel, inbound-upstream-result, panel-dkim-signing,
  panel-notifications, and the own-mta-builds analysis (its three rows
  shipped as 2.6.1, 2.7.0, 2.8.0). What outlived them moved first: when a
  filter-list counter is worth a migration, and the notifications' "when"
  table, into architecture.md; the sender check's own-process trigger into
  security.md. Code comments that cited them point at architecture.md or
  security.md; CHANGELOG keeps their names, unlinked.
- Kept, marked closed: audit-2026-10-12, assumptions-2026-10-14 and
  security-audit-2026-10-17 - the code cites their finding ids in 50-84
  files. Their file:line refs are of the tree each audited.
- roadmap.md: open work only - stage H of the security audit (the owner's),
  go-milter-upstream (the owner posts), and queue-table, which the
  redesign left undecided and only its own shipped section still named;
  Dropped and Ideas as they were. 2.x versioning instead of 1.x.
- development.md: the 47-row planned-version-cuts table (history, in the
  CHANGELOG) gone; a stage's last step now removes its roadmap item and
  plan. Docs map lists the closed audits.
- panel-redesign.md: the done checklist out; Room for roadmap items says
  which drawn screens are unbuilt and why.
- Stale facts fixed: schema-migrations.md and architecture.md at schema 14
  (0013's users columns and user_links, 0014's secure TLS mode);
  security.md's accepted risk "profile saved without the password" - the
  e-mail asks for it since 2.14.0.

Tests: go build, go vet; go test of cmd and the touched internal packages
pass except logtail's three Windows-bound rotation tests (rename of an open
file; CI is Linux). Only comments changed in Go.

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
This commit is contained in:
mix
2026-10-18 22:37:22 +03:00
co-authored by Claude Opus 5.5
parent f20c942d64
commit 30fcf978e0
33 changed files with 211 additions and 2685 deletions
+21 -92
View File
@@ -1,15 +1,16 @@
# Plan: panel-redesign
**Status:** shipped in `2.0.0` (2026-10-11)
**Date:** 2026-09-21 (replaces the 2026-09-08 givens)
**Version:** `2.0.0` MAJOR — a breaking release by the owner's decision (§ No compatibility).
**Status:** the design contract of the panel; built and shipped in `2.0.0`
(2026-10-11), a breaking release by the owner's decision (§ No compatibility).
Its implementation checklist (27/27) is in the git history.
**Date:** 2026-09-21 (replaces the 2026-09-08 givens)
---
## What this file is
The design contract for the control panel and the plan to implement it. The
design itself is drawn and accepted:
The design contract for the control panel. The design itself is drawn and
accepted:
| Artefact | Role |
|---|---|
@@ -72,9 +73,9 @@ and the migration chain is deleted to zero.** The redesign is `2.0.0`.
- **Schema.** `internal/store/migrations/` is emptied and replaced by one
baseline, `0001_init.sql`, equal to the 2.0 schema (including the new
assignment table below). No historical `admin` table, no create-then-drop.
This is [schema-squash](../roadmap.md#schema-squash) with its trigger now
decided and without the upgrade gate that item planned: 2.0 starts from an
empty data directory.
This was the roadmap item schema-squash, with its trigger decided and
without the upgrade gate that item planned: 2.0 starts from an empty data
directory.
- **Docs.** `schema-migrations.md` shrinks to the 2.0 baseline; the 1.x chain
stays in git history.
@@ -145,8 +146,7 @@ shown another user's login name, and three explicit choices are simpler.
- The 2.0 baseline has `users.email`: the user's own address, edited on
**Account**, set by the global administrator on the user form and shown in
the users list. It is what the panel writes to — event notifications
([panel-notifications](../roadmap.md#panel-notifications)) and a reset link
([password-reset](../roadmap.md#password-reset)) — and what the fill button
(`2.3.0`) and a reset link (`2.14.0`) — and what the fill button
offers. **Account** is Profile and Password; Server › Settings keeps nothing
of DMARC.
- Baseline: `domains.dmarc_rua` alone (`''` = no reports). The hosted choice is
@@ -226,38 +226,24 @@ shell, and its menu entry is hidden if the page does not exist.
## Room for roadmap items
The mockups draw today's features, the four rows above, and the screens of
the open roadmap items — none of them needed a new component or layout. A
mockup of a feature is its target look, not a decision to build it: each item
keeps its own status and plan. From here on a feature's screens are drawn
The mockups drew the 2.0 pages and the screens of the roadmap items of the
time; none of them needed a new component or layout. A mockup of a feature is
its target look, not a decision to build it. A feature's screens are drawn
mockup-first in this system (`panel/src/`, `build.py`, `check.py --write`) as
the first step of that feature's plan — not invented during implementation.
the first step of that feature's work, not invented during implementation.
| Roadmap item | Where it lands | Built from | Drawn |
|---|---|---|---|
| inbound-antispam-panel (agreed, `2.1.0`) | journal = **Inbound › Log** (add client IP and engine to the mockup's columns; `quarantine` joins the decisions); lists = new **Inbound › Filter lists**, global-only because the lists are instance-wide | list layout: add form + two tables, `status_tag`, filter form in `box_head`; the log links *Allow / Deny sender* to the lists | `in-log`, `in-filter-lists` |
| inbound-quarantine (an idea, off the roadmap since 2026-10-12) | new **Inbound › Quarantine**, list + detail with *Release* / *Discard* | list layout; detail like `out-message` with `facts`, `log_pane` for headers only, Release beside a `sp-danger-zone` Discard | `in-quarantine`, `in-quarantine-message` — the open questions of its plan (where mail lives, what release means, retention, RBAC) stay open; the mockup assumes SelfPost-held mail, release to upstream, 14 days, delegated like the rest of Inbound |
| preflight (candidate) | new **Server › Preflight**, next to Health: Health is what runs now, Preflight is the deeper on-demand installation check with a test e-mail form | `postmark` verdict, a table of checks with `status_tag` and a *What to do* column, one form box for the test e-mail | `preflight` |
| panel-notifications (candidate) | one checkbox per user on **Account** (no choice per event, owner 2026-10-12); one switch under **Server › Settings** | a checkbox in a box, `help` | **no** — drawn once, taken out of `account` and `settings` on 2026-10-10 (owner): 2.0 ships no box for a feature that is not built; redrawn as the first step of its plan |
| password-reset (candidate) | a link on sign-in, two signed-out screens (request, set new password) | the signed-out layout | **no** |
| delivery-log-storage (candidate) | the *Delivery log* box of **Outbound › Log › message**, filled from a table instead of a grep of today's `mail.log` | `log_pane`, unchanged | `out-message` |
| csrf-tokens | no screen; every form gains a hidden field — forms are rendered through one helper so the token cannot be forgotten | — | n/a |
| template-data-typing | no screen; the component partials are the natural first users of typed data | — | n/a |
| structured-logging, contributing, review follow-ups | none | — | n/a |
Drawn and not built (`deferredScreens` in the guard tests):
| Screen | Item | State |
|---|---|---|
| `in-queue` | [queue-table](../roadmap.md#queue-table): the queue as a table from `postqueue -j`, and an Inbound › Queue | undecided; Outbound › Queue shows postqueue's listing in a log pane (`outlineExempt`) |
| `in-quarantine`, `in-quarantine-message` | inbound-quarantine, an idea off the roadmap ([its notes](inbound-quarantine.md)) | its open questions stay open; the mockup assumes SelfPost-held mail, release to upstream, 14 days, delegated like the rest of Inbound |
| `preflight` | preflight as a page of its own, dropped 2026-10-13 ([roadmap](../roadmap.md#dropped-with-the-condition-for-return)); its checks went to Server › Health, the test e-mail to its own form | a leftover of a dropped item |
The sibling strip under the navbar holds five or six entries per group without
wrapping; Inbound would reach five (Domains · Log · Queue · Quarantine ·
Filter lists), Server six. Past that a group is split rather than squeezed.
Ordering with 2.0 (owner, 2026-10-09: feature order is not fixed, take
whatever suits development): **the redesign ships first as `2.0.0`**, and
inbound-antispam-panel follows as `2.1.0`, built from the component kit on
the 2.0 baseline. The other way round would have styled two screens twice and
written a 1.x migration only to dissolve it into the baseline. The antispam
back end (journal milter, log tailer, list CRUD, rspamd map sync) touches
nothing under `internal/web/view` and may be built alongside stages 0–1 below
if time allows; its two screens wait for the kit.
## Three layers
1. **Bulma, as shipped.** Vendored `bulma.min.css`, never edited. Only the
@@ -485,60 +471,3 @@ reviewed.
- Dark scheme and the narrow-screen shell: Bulma ships both; they are drawn
and agreed as a `design:` change before anyone implements them.
- Weakening CSP; a JS bundler; a front-end framework.
## Implementation checklist
Roadmap status: **agreed** (owner, 2026-10-09). Stages are ordered for
development, not by feature priority (owner, 2026-10-09). Stage 1 touches no
file under `internal/web/view` and may run alongside stage 0; stage 2 starts
only when both are done. Every stage-2 step ends with the evidence of
§ Evidence for "done".
**Decided**
- [x] Owner decision recorded here: keep today's paths or rename with redirects — **owner** (2026-09-21: rename, § Routes)
- [x] Owner decision: no compatibility, migrations to zero, `2.0.0` — **owner** (2026-09-21, § No compatibility)
- [x] Owner decision: inbound is delegated per user, separately from outbound — **owner** (2026-09-21, § Who sees what)
- [x] Owner decision: the redesign ships before inbound-antispam-panel; feature order follows development convenience — **owner** (2026-10-09, § Room for roadmap items)
- [x] Decision inside 2.0: **Server › Health** is built with the restyle (the tables that leave Overview need a home, § Routes); **queue as a table** and the **inbound queue** stay roadmap decisions — both queue pages ship old content in the new shell, the Inbound › Queue entry hidden — (2026-10-09)
**Stage 0 — foundation and component kit** (§ Component kit)
- [x] Vendor Bulma 1.0.4 and the icon subset (MIT) under `/static`, NOTICE and development.md rows, pinned checksum — **Haiku**
- [x] Guard tests from § Enforcement and `TestRoutesFollowNavigation`, red against today's panel where expected, with the `legacyPages` ratchet listing every page; `design-first` CI step including the ratchet and the history-blob check (§ Against resurrected pages) — **Opus**
- [x] `panel.css` from `panel/theme.css` + `shared/brand.css`; `components.html` partials with typed inputs in `components.go`; `status_tag`, `copy_field`, `wbr_at` — **Sonnet**
- [x] `layout.html`: navbar, perforated edge, sibling strip, user menu, footer, visibility flags; the signed-out shell — **Sonnet**
- [x] `GET /server/components` behind the global role rendering every partial from fixtures; kit acceptance (§ Component kit) with evidence — **Sonnet**, reviewed by **Opus**
**Stage 1 — data and routes** (no template work; parallel with stage 0)
- [x] Schema from zero: single `0001_init.sql` baseline with `users.email`, `user_inbound_domains`, the two `all_*` flags; store tests; `schema-migrations.md` rewritten — **Opus**
- [x] Inbound delegation: `requireInboundDomain`, lists and log filtered in the query, two-list user form data, per-route 404 tests for both roles including another tenant's id — **Opus**
- [x] Routes renamed per § Routes: new paths, one fragment name, old paths removed, subtree `requireGlobal()` for `/server/`; links in the old templates retargeted so the panel works on every commit — **Opus**
- [x] The application form as one POST; `out-app-created` as the response with `Cache-Control: no-store` — **Opus**
- [x] Server › Health route and handler (tables and *Reload configuration* from `/status`); Overview handler reduced to verdicts — **Opus**
**Stage 2 — pages, in groups** (each step: partial calls only, page off the ratchet list, evidence pairs)
- [x] Signed-out pages: login, setup — **Sonnet**
- [x] Overview, Health, and the Account / Settings split — **Sonnet**
- [x] Outbound: domains, domain, domain settings, application form, shown-once password, delete — **Sonnet**
- [x] Outbound: log, message, DMARC hub / domain / report — **Sonnet**
- [x] Inbound: domains, domain with the *Spam filter* box, delete — **Sonnet**
- [x] Server: system log, backup, users, user form, delete; Help as `help_topic` partials, the drawer removed — **Sonnet**
- [x] Queues: old content inside the new shell (outbound), Inbound › Queue hidden — **Sonnet**
- [x] Remove the old `panel.css`, the drawer code in `panel.js` and every class nothing references; `legacyPages` empty, vocabulary test green with no allow-list — **Sonnet**
**Stage 3 — reviews, docs, 2.0.0**
- [x] Technical review of the whole against the mockups, evidence pairs complete — **Opus**
- [x] Security review of the route rename, subtree authorization and inbound delegation — **Fable**
- [x] guide.md screenshots and wording for the new navigation; architecture.md § Panel HTTP surface and § Persistence; security.md roles; *Removed* in the CHANGELOG with one line that 2.0 starts from an empty data directory; strike the three UI rows of review-2026-08-followups that the redesign retires — **Sonnet**
- [x] `go vet`, `go test ./...`, e2e suite; version cut `2.0.0` — **Haiku**
**After 2.0** — features land in the kit, each from its own plan, mockup first
(§ Room for roadmap items): inbound-antispam-panel `2.1.0`; then, in whatever
order suits development, preflight, delivery-log-storage, panel-notifications,
password-reset (two screens to draw first), queue as a table with the inbound
queue, csrf-tokens
(one hidden field in the form partial once security.md is settled).
inbound-quarantine is an idea outside the roadmap.