783dabbea5fcb917b2d0dd086c58eab17a4a2dfd
5
Commits
| Author | SHA1 | Message | Date | |
|---|---|---|---|---|
|
|
bd746c61d7 |
panel-redesign: paths follow the menu; Account and Server settings split
Stage 1, step 3 (plan § Routes). BREAKING: every panel URL changes and the
old paths are removed without redirects.
Routes (web.go)
- /status -> /overview; /domains -> /outbound/domains with the domain's
settings actions under .../settings/ (reports, ratelimit, export);
/deliveries -> /outbound/log; /mail-queue -> /outbound/queue; /dmarc ->
/outbound/dmarc; /inbound -> /inbound/domains; /system-log ->
/server/log; /backup -> /server/backup (import under it); /users ->
/server/users; recheck and reload under /server/health/.
- One fragment name: <page>/fragment everywhere.
- Everything under /server/ is registered through server(), which wraps
the handler in globalOnly: the subtree is guarded once, where a new
route cannot forget it. Handlers keep their own requireGlobal.
- GET / leads to /overview, /outbound/domains or /inbound/domains.
- The /account -> /settings redirect is gone with /settings.
Account and Server > Settings
- handlers_account.go: GET /account and three POSTs - profile (username,
e-mail; no password asked, as designed), password (current password,
rate-limited like a sign-in, signs out other sessions), dmarc (the
user's default: hosted / account / custom / none, each validated).
This replaces step 1's bridge through the old Settings form.
- handlers_settings.go is the instance's page only: log retention and the
read-only rate limits, global role.
- One legacy template serves both pages by a flag until stage 2 gives each
its own: a new legacy page cannot be added to the ratchet.
Still to come inside stage 1, and why @routes stays on the ratchet:
- step 4: the application routes (one POST, under the domain);
- step 5: GET /server/health.
With @routes removed by hand TestRoutesFollowNavigation reports exactly
those and nothing else - no template links to a path the router lacks.
Old templates, tests and the e2e client are retargeted. The e2e module was
edited but not run here (no Docker, and its dependency could not be
downloaded on this machine).
Tests: Account (page, profile, password, DMARC default in every mode, a
domain administrator's own row only), Server settings (saved without a
password, range, global only), the /server/ subtree answered 404 by the
router for a domain administrator with All on both lists and for no
principal.
go test ./... green except the two Windows-only failures in internal/domain
and internal/logtail.
Roadmap 13/27.
Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
|
||
|
|
3b86f6c3b6 |
panel-redesign: inbound is delegated per user, separately from outbound
Stage 1, step 2 (plan § Who sees what).
Store
- Reach{AllDomains, DomainIDs, AllInbound, InboundDomainIDs} is what a
domain user is assigned. CreateUser takes it; SetUserReach / ClearUserReach
replace SetUserDomains / ClearUserDomains and write both directions in one
transaction. A domain user with nothing on either list is refused
(ErrEmptyReach). With All set the rows of that direction are not stored,
so clearing All later brings nothing stale back.
- ListDomainsForUser honours all_domains; ListInboundDomainsForUser is its
inbound twin. Both filter in the query.
Authorization
- auth.Principal carries the whole reach: CanAccessDomain (now also true
with All), CanAccessInboundDomain, HasOutbound, HasInbound. An id or a
name on one list opens nothing on the other.
- Inbound handlers in three strengths: requireInbound (the list, filtered),
requireInboundDomain (one domain: page, DNS re-check, upstream,
recipients), requireInboundGlobal (add, delete confirm, delete). All
answer the same 404.
- domainIDSet and the DMARC report pages go through the principal instead
of looking at p.Domains themselves.
Panel (old templates, until stage 2)
- User form: two lists with All; inbound is offered only where the feature
is on, and saving the form with it off keeps the user's inbound reach.
Promotion to global drops the reach.
- Menu: a group with nothing assigned is absent; / sends an inbound-only
administrator to Inbound. The inbound pages hide add / delete from a
domain administrator.
Tests: every route of one inbound domain against five kinds of refused
request (another tenant's id, a missing id, outbound-only reach, an outbound
domain with the same id, one with the same name, no principal) with the 404
bodies compared; add/delete as every non-global user; the filtered list
including a domain added later; thirteen outbound routes against another
tenant's domain and application id; the user form; the reach in the store;
the principal matrix; the menu; the home redirect. Removing the access check
or the query filter makes the tests fail (checked by hand).
go test ./... green except the two Windows-only failures in internal/domain
and internal/logtail that predate this work.
Roadmap 12/27.
Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
|
||
|
|
8d1af89e1a |
panel-redesign: the 2.0 schema from zero - one baseline, no 1.x chain
Stage 1, step 1. BREAKING: a 1.x database is not migrated.
Schema
- internal/store/migrations/ holds one file, 0001_init.sql, equal to the
2.0 schema; 0002..0010 are deleted (they stay in history at 1.9.5). No
admin table created and dropped, no ALTERs.
- users.email replaces users.dmarc_report_email: the address is the
user's own. The default DMARC report address is a user's setting
(dmarc_default_mode hosted/account/custom/none, dmarc_default_address);
the instance setting that mirrored the global user's field is gone.
- domains.dmarc_rua_user_id: a domain follows a named user's default, or
has an address of its own in dmarc_rua ('' = none). ON DELETE SET NULL
leaves it at "no reports", never at someone else's default.
- user_inbound_domains, users.all_domains, users.all_inbound_domains: in
the schema for the inbound delegation of the next step.
- users.role is 'global' / 'domain' (was 'domain_admin');
rate_limits.allowed_ips, unused since 1.9.0, is dropped.
Opening a database
- The baseline sets PRAGMA application_id ("SP20"). store.Open refuses a
file that has a schema version without it (ErrForeignSchema) and one
newer than the build. A 1.x file at user_version 10 would otherwise read
as already migrated. The refused file is left untouched.
Code
- Store.DomainDMARCRua is the one place a domain's report address is
resolved; dnscheck.ResolveDMARCRua and Store.GlobalDMARCReportEmail are
gone. dmarc.AllowedRecipients, the domain page, the dashboard and the
DNS re-check go through it.
- The old templates keep working on the new model until their pages are
restyled: the Settings form's address field is the account e-mail and
switches the user's default between it and none; a domain's "Same as
Settings" makes it follow the user who chose it; a new or imported
domain follows its creator.
- Domain export/import: a domain that follows a user exports no address.
Tests: the baseline pinned table by table (TestBaselineSchema), refusal of a
1.x and of a newer database, constraints and cascades of the new columns and
table, resolution in every default mode, the deleted-user case, and the three
bridged handlers.
docs/schema-migrations.md is rewritten for the baseline; roadmap 11/27,
schema-squash marked built.
go test ./... (Windows)
ok for every package except two that fail the same way before this commit:
internal/domain TestWriteLoadPrivateKeyRoundtrip (file mode on NTFS)
internal/logtail TestFollowTailsAndRotates (rename of an open file)
Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
|
||
|
|
0730b2090e |
release: 1.3.0: 1.3.0-1.3.1: security pass, queue persist, full backup layout
[1.3.0] Security and quality after 1.2.5: domain-admin send-log authorization, fail-closed sign-in and application delete, level-2 rate-limit race fix, restore Resync, expanded tests, operator docs, release CI, and OFL for IBM Plex. Upgrading from 1.2.x is a tag bump; no migration. Added: - licence: the SIL Open Font License 1.1 text now travels with the IBM Plex - docs: agreed roadmap item **queue-retries** — show this Postfix's retry Security: - The independent security review of the send-log authorization and Fixed: - test (e2e): send-log status scrapers follow the badge markup in - security (panel): the Deliveries list is scoped to a domain administrator's - mail (level-2 rate limit): the ceiling is no longer overshot by messages that - panel (sign-in): a session that cannot be written to the database no longer - panel (applications): deleting an application removes its SASL credentials … (2 more in CHANGELOG) Changed: - docs: operator and as-built docs aligned with the code after a full - docs: [guide.md](docs/guide.md) reorganised into **Installation**, **Instance - docs: the 2026-08-13 full-tree review plan is complete — every phase (P0–P7) - licence: [NOTICE](NOTICE) tells modifiers to update `SourceURL` in - ci: the release image is published only for a **published** GitHub Release … (9 more in CHANGELOG) [1.3.1] Retry policy in the panel, persistent Postfix queue, and self-contained full backups. Mail queue and delivery history show this Postfix's first retry, backoff cap, and queue lifetime. Deferred mail survives container recreate. Full backups now archive `data/`, compose, `.env`, and `certs/`; the archive layout breaks 1.3.0 flat backups (unpack those with `tar xzf backup.tar.gz -C ./data` as before). Upgrading from 1.3.0 is a tag bump; no schema migration. Added: - Mail queue and a delivery's history show this Postfix's retry policy - docs: **Plan checklists** in [development.md](docs/development.md) — format, - docs: **Implementation checklists** with model routing in - docs: roadmap candidates **send-log-retention** (panel Settings for delivery - Postfix queue under `/data/postfix/queue` — deferred and active mail survive … (1 more in CHANGELOG) Changed: - **Breaking:** full-backup archive layout — paths are prefixed with `data/`; - docs: operator guide, architecture, security, and backup UI updated for - docs: HTML mockups for a full panel UI refresh Changed: - docs: panel UI mockups after review — Status restored to live readings - docs: panel UI design system and mockups rebuilt as separate pages - docs: panel UI mockups — add-domain sits in the list card (Domains and Fixed: - ci (GHCR): per-arch package tags (`X.Y.Z-amd64`, `X.Y.Z-arm64`) are dropped Squashed CHANGELOG sections: [1.3.0], [1.3.1]. Full detail: CHANGELOG.md (1.3.0, 1.3.1). |
||
|
|
60e08e802e |
release: 1.2.0: Panel 1.2.0-1.2.5: layout, RBAC, tests, GUI and CI fixes
[1.2.0] The second MINOR after 1.0.0: domain administrators with per-domain scope, a panel visual refresh on the SelfPost palette, and refinements to navigation and the send log. Upgrading runs one SQLite migration (`0005_panel_users`); the single administrator becomes a global user. Added: - panel: **domain-admin role** — global administrators manage panel users and Fixed: - Docker build: `LICENSE` is no longer excluded by `.dockerignore`, so the - panel: on signed-in pages with a narrow card (**Settings**, the user form) Changed: - panel: navigation session icons are distinct — **Settings** uses a gear, - panel: `/` redirects domain administrators to `/domains`; global users still - panel: **Sign out** in the navigation column uses the same type size and - panel: **visual style** brought in line with the SelfPost mark — brick accent - panel: the send log's **status is a badge**, in the same ok/warn/error/unknown … (1 more in CHANGELOG) [1.2.1] Panel refinements after 1.2.0: navigation icons, status-badge centreing, drill-down back-link placement, and safeguards for the sole global administrator. Upgrading is a tag bump; no migration. Fixed: - panel: status badge text sat low in the box (and below the heading or label - panel: the **Users** navigation icon was two full silhouettes with staggered - panel: the **Settings** navigation icon was a sun-with-rays (circle plus - panel: the user create/edit form placed «Back to users» at the bottom of the Changed: - panel: the user edit form disables role change and delete for the only global - panel: the user create/edit form hides **Assigned domains** when the role is - panel: **Settings** shows panel credentials and DMARC aggregate reports side [1.2.2] Status page layout after 1.2.1: paired cards in a wide column, denser machine and check copy, and a user-form checkbox fix. Upgrading is a tag bump; no migration. Changed: - panel: **Status** is wide again so paired cards fill the column. Layout: Fixed: - panel: cards inside `.split` used `margin: 0 auto`, which in a CSS grid - panel: on the user create/edit form, **Assigned domains** checkboxes stacked [1.2.3] Domain detail layout and panel polish after 1.2.2. Upgrading is a tag bump; no migration. Changed: - panel: the domain detail page is wide with paired cards (DKIM+SPF ‖ DMARC; - panel: Domains list — **Add domain** sits beside the domain field; the - panel: page URLs, browser titles, and headings are aligned — **Settings** is Fixed: - image: `mail.log` rotation no longer silently stops when the build context [1.2.4] Level-2 rate-limit semantics inverted after 1.2.3, plus a small DNS field height fix. Upgrading is a tag bump; no migration. Changed: - rate limiting (level 2): domain ceilings apply to every client IP (no IP Fixed: - panel: on the domain DNS status grid, the Type (TXT) field height matches [1.2.5] Rate-limit form polish after 1.2.4. Upgrading is a tag bump; no migration. Changed: - panel: rate-limit forms refined — level-1 backstop as muted copy on the Squashed CHANGELOG sections: [1.2.0], [1.2.1], [1.2.2], [1.2.3], [1.2.4], [1.2.5]. Full detail: CHANGELOG.md (1.2.0, 1.2.1, 1.2.2, 1.2.3, 1.2.4, 1.2.5). |