Gate Routing, Secrets, Host Console, and Mesh dashboard/settings surfaces on the existing useExperimental readiness flag so immature operator surfaces stay out of the default UI while paid and admin backend gates remain unchanged.
* fix(settings): clear stale pending and unsaved indicators after save
Settings sections held their saved baseline in a mutable ref and computed
the dirty count with useMemo keyed on the live values, so updating the ref
on a successful save never re-ran the calculation. The masthead pending
count and the sidebar unsaved dot stayed stale until the section remounted,
making operators think the save had failed.
Move the baseline into state behind a shared useSettingsDirty hook with
separate load (reset) and save-success (markSaved) operations. markSaved
adopts the submitted snapshot as the baseline only, so an edit made while a
save is in flight survives and a failed save stays dirty and retryable.
Migrate the five sections that used the pattern.
* test(settings): await the save-failure retry assertion to avoid a race
In the failed-save reconcile test, wait for the Save button to re-enable
after the PATCH settles instead of asserting synchronously, so the retry
check cannot race the isSaving reset.
* feat(snapshots): preserve stack dossiers with fleet snapshots
Fleet snapshots can now optionally capture each stack's Dossier notes
alongside its compose and .env files, so a recovery restores the
operational knowledge around a stack, not just its configuration.
- Opt-in global setting "snapshot_documentation" (default off), toggled
from the renamed Fleet settings section.
- Capture reads local dossiers from the database and remote dossiers over
the Distributed API proxy; only stacks with notes are recorded, and
secret values are never included.
- Captured notes are stored encrypted at rest in a new fleet_snapshots
column and surfaced in the snapshot detail view behind a badge.
- Cloud and downloaded archives gain a documentation.json (archive_version 2).
- Restore stays conservative: dossier notes are written back only when the
operator explicitly opts in, on both single-stack and restore-all paths.
- Existing snapshots and archives remain valid; behavior is unchanged when
the setting is off.
* fix(snapshots): harden dossier-notes restore against bad input and partial failures
Address review findings on the documentation-snapshots restore path:
- Parse `restoreNotes` strictly (=== true) on single-stack restore, matching
restore-all, so a stray non-boolean can never opt in to overwriting notes.
- Guard findSnapshotDossier: require an array of stacks and real dossier
content, so a malformed or all-blank entry can't clobber current notes.
- Make the dossier-notes write non-fatal relative to the file restore: a notes
failure (e.g. a remote dossier PUT) is caught, reported via `notesError`, and
no longer 500s the single restore or fails the stack in restore-all once the
files are already written.
- Surface the partial outcome in the UI: a warning toast on single restore, a
summary note on restore-all, and gate the "Documentation captured" badge and
restore-all notes control on captured stacks while rendering capture warnings.
Adds tests for strict parsing, malformed/blank blobs, remote notes restore
(success + non-fatal failure, single and bulk), and scheduled capture-on.
* fix(snapshots): drop unused binding in restore-all remote notes test
The restore-all remote notes test destructured a node id it never uses
(restore-all is driven by snapshot id alone), tripping no-unused-vars and
failing the lint step. Bind only the snapshot id.
* refactor(settings): split System Limits and regroup the hub
System Limits had grown into a grab-bag of host alert thresholds, Docker
cleanup, and mesh data-plane controls under one mislabeled section. Split it
into Host Alerts, Docker & Storage, and Fleet Mesh, and split Developer into
Developer Diagnostics and Data Retention. Reorganize the sidebar into ten
domain groups: Personal, Access, Infrastructure, Monitoring, Notifications,
Automation, Organization, Security, Operations, Help.
Each section now saves only its own keys, so a concurrent edit in one section
no longer clobbers another. Data Retention sends the audit-log window only on
a paid plan, matching the field's existing visibility, so a Community save no
longer fails on a key the operator cannot set. NumberChip moves to a shared
module and the toggle reuses the existing shared component. The /settings API
is unchanged.
* test(settings): cover registry structure and per-section save payloads
Add structural invariants for the ten-group registry (every item maps to a
real group, ids are unique, the System Limits and Developer splits land in the
right groups with the right gates, renamed labels and the Registries paid gate
hold) and per-section payload tests asserting each split section patches only
its own keys, including the Community path where Data Retention omits the paid
audit-log key.
* docs(settings): document the regrouped settings hub
Rewrite the settings reference for the ten-group layout, replace the System
Limits page with Host Alerts, Docker & Storage, and Fleet Mesh, and document
the prune-on-update, reclaimable-space banner, and mesh auto-recreate settings
that were previously undocumented. Update the Settings navigation breadcrumbs
across the feature docs and refresh the affected screenshots.
* fix(settings): show Access sections as instance-global, not operator-scoped
License, Users, SSO, and API Tokens are instance-global settings but the
masthead scope label rendered them as operator-scoped because it keyed off the
old Identity group. Only Personal sections (account, appearance) are
operator/browser-scoped now; everything else reads as global.
Also add a compile-time exhaustiveness guard to the section switch so a future
SectionId added without a matching case fails the build instead of silently
rendering a blank panel.
* docs(settings): remap remaining settings breadcrumbs to the new groups
Update the navigation breadcrumbs that still pointed at the removed Identity,
Alerts, and Advanced groups: API Tokens and Users now sit under Access, Webhooks
under Automation, Labels under Organization, App Store under Infrastructure,
Appearance under Personal, and scan policies under Security > Vulnerability
Scanning. Correct the settings reference scope note so Access reads as global.
* docs(settings): remap renamed-section breadcrumbs across feature docs
Sweep every feature, operations, getting-started, and reference page for
navigation paths that still named the renamed settings sections, and point them
at the current ones: Security becomes Security > Vulnerability Scanning,
Notifications becomes Notifications > Channels, Routing becomes Notifications >
Notification Routing, and Developer becomes Operations > Developer Diagnostics
(with its retention windows under Operations > Data Retention). App Store moves
under Infrastructure and the four-group overview in the getting-started intro is
rewritten to the ten groups. Separators each page already used are preserved.