diff --git a/CHANGELOG.md b/CHANGELOG.md
index 884d2b5..1c201bc 100644
--- a/CHANGELOG.md
+++ b/CHANGELOG.md
@@ -31,6 +31,19 @@ Format follows [Keep a Changelog](https://keepachangelog.com/en/1.1.0/); version
must be named in `docs/roadmap.md`. The two queues had been deferred on
2026-10-09 with no roadmap row and were forgotten; development.md says so.
+### Fixed
+
+Two gaps a comparison of every mockup with the panel found (the rest
+matches):
+
+- **Server › Users, the user form:** with *All outbound domains* (or *All
+ inbound domains*) ticked, that list's single domains are disabled, as the
+ mockup draws them - the server ignored them already, which the help line
+ says. panel.js does it; without scripts they stay clickable.
+- **Server › Backup, Import a domain:** "the domain's settings" links to
+ Outbound › Domains, where each domain's settings are, as the mockup's link
+ does.
+
## [2.15.0] - 2026-10-18
The two proposals the security audit left as product choices. Migration
diff --git a/internal/web/handlers/handlers_delegation_test.go b/internal/web/handlers/handlers_delegation_test.go
index b5d336e..61f647f 100644
--- a/internal/web/handlers/handlers_delegation_test.go
+++ b/internal/web/handlers/handlers_delegation_test.go
@@ -431,7 +431,7 @@ func TestUserFormAssignsBothDirections(t *testing.T) {
body := send(h.HandleUserEdit, &root, "GET", "/server/users/"+idStr(other.ID), map[string]string{"uid": idStr(other.ID)}, nil).Body.String()
for _, want := range []string{
`name="all_domains"`, `name="all_inbound_domains"`, "out.example.com",
- `name="inbound_domain_ids" value="` + idStr(in.ID) + `" checked`,
+ `name="inbound_domain_ids" value="` + idStr(in.ID) + `" data-single-in checked`,
} {
if !strings.Contains(body, want) {
t.Errorf("the user form is missing %q", want)
diff --git a/internal/web/view/paneljs_test.go b/internal/web/view/paneljs_test.go
index 4b489a5..24bb3eb 100644
--- a/internal/web/view/paneljs_test.go
+++ b/internal/web/view/paneljs_test.go
@@ -17,7 +17,7 @@ func TestPanelJS(t *testing.T) {
if err != nil {
t.Skip("node is not installed")
}
- for _, script := range []string{"poll_test.js", "unsaved_test.js", "filename_test.js"} {
+ for _, script := range []string{"poll_test.js", "unsaved_test.js", "filename_test.js", "alldomains_test.js"} {
t.Run(script, func(t *testing.T) {
out, err := exec.Command(node, filepath.Join("testdata", script), filepath.Join("static", "panel.js")).CombinedOutput()
if err != nil {
diff --git a/internal/web/view/server_test.go b/internal/web/view/server_test.go
index ca0dbff..7c1183b 100644
--- a/internal/web/view/server_test.go
+++ b/internal/web/view/server_test.go
@@ -59,6 +59,7 @@ func TestBackupHasBothFormsAndTheEncryptionHooks(t *testing.T) {
`name="password"`, `name="password_confirm"`, `minlength="12"`, `placeholder="at least 12 characters"`,
`name="file"`, `accept=".json,.spde,application/json"`, `required data-import-file`,
`data-import-password-fields`, `name="import_password"`, `
`,
+ `The export itself is made on the domain's settings.`,
)
pageLacks(t, "Backup", out, `notification`)
}
@@ -157,8 +158,8 @@ func TestUserFormShowsWhatIsStoredUnderTheHandlersFieldNames(t *testing.T) {
`name="password" type="password" autocomplete="new-password">`,
`Leave empty to keep the current one.`,
`