+
## Notification channels
-Open **Settings · Notifications** to configure the three channel types. Each channel is per-node, so switching the active node via the node picker reloads the panel against that node's stored settings. The masthead carries a `CHANNELS` stat showing how many of the three slots are enabled.
+Open **Settings · Notifications · Channels** to configure the three channel types. Each channel is per-node, so switching the active node via the node picker reloads the panel against that node's stored settings. The masthead carries a `CHANNELS` stat showing how many of the three slots are enabled.
Each tab carries the same controls: an **Enabled** toggle (helper: `Send Sencho events to this
+
### How routing fits into dispatch
@@ -70,7 +70,7 @@ A route with all four matchers left empty matches every alert and intercepts glo
### Creating a routing rule
-Open **Settings · Routing** and click **+ Add Route**.
+Open **Settings · Notifications · Notification Routing** and click **+ Add Route**.
@@ -164,7 +164,7 @@ The **NOTIFICATION CHANNELS** banner above the rules list reflects what dispatch
- **Loading** is a spinner with `Checking notification channels...` while Sencho asks the target node for its agent state.
- **Remote node** is a blue banner reading `Remote node:
+
| Control | Range | Default | What it prunes |
@@ -365,15 +365,15 @@ A separate rate limit applies to crash and health alerts only: 20 emits per 60-s
## Crash detection toggle
-The global crash-capture switch lives under **Settings · System · Docker hygiene**.
+The global crash-capture switch lives under **Settings · Monitoring · Host Alerts**.
-
+
The **Global crash capture** toggle controls whether `DockerEventService` raises crash, OOM, and healthcheck alerts on the active node. Helper text: `Watch every managed container for unexpected exits.` Defaults to on; if the database read fails, Sencho falls back to default-deny so the system never leaks alerts you cannot turn off.
-The same panel carries the **Host thresholds** rows (CPU limit, RAM limit, Disk limit, all expressed as percent) that drive the host-level monitor warnings, and the **Janitor threshold** (in GiB) that drives the unused-Docker-data alert.
+The **Host Alerts** panel also carries the **Host thresholds** rows (CPU limit, RAM limit, Disk limit, all expressed as percent) that drive the host-level monitor warnings. The **Janitor threshold** (in GiB) that drives the unused-Docker-data alert lives in the **Docker & Storage** panel.
## Refresh cadence
@@ -396,7 +396,7 @@ Switching the active node tears down per-stack rule editors and reloads channel
@@ -358,7 +358,7 @@ Read Only is sufficient for the notification stream.
+
-1. Open **Settings › Advanced › App Store**.
+1. Open **Settings › Infrastructure › App Store**.
2. Type your catalogue URL into **Registry URL**. The URL must start with `http://` or `https://` and serve a JSON array of template objects in the [Portainer v2 template format](https://documentation.portainer.io/v2.0-be/api/templates/).
3. Click **Save & refresh**. Sencho persists the new URL and immediately invalidates the template cache so the App Store reloads from the new source.
@@ -143,7 +143,7 @@ The default registry display at the top of the page is informational only; you c
+
+
### Drift policy
@@ -313,7 +313,7 @@ A future Volume Migration feature will automate this with app-aware backup tooli
The reconciler will not auto-deploy a stateful blueprint to a node it has never run on. Click **Confirm deploy** on the row, then choose **Deploy fresh** in the dialog. Sencho will create empty named volumes and start the stack.
@@ -43,7 +43,7 @@ The dialog has the following fields:
### Suppressing directly from a scan result
-The panel's empty state hints at the faster path: from any vulnerability scan, click the small shield icon at the right edge of a finding's row. The dialog opens pre-filled with the CVE ID and the package name from that row (both read-only in this flow), leaving you to add a Reason, an optional Image pattern, and an optional Expiry. This is the recommended workflow for everyday triage, because it keeps the scope as narrow as the originating finding. To broaden the scope (for example, to suppress across every package), create the rule from **Settings → Security** instead.
+The panel's empty state hints at the faster path: from any vulnerability scan, click the small shield icon at the right edge of a finding's row. The dialog opens pre-filled with the CVE ID and the package name from that row (both read-only in this flow), leaving you to add a Reason, an optional Image pattern, and an optional Expiry. This is the recommended workflow for everyday triage, because it keeps the scope as narrow as the originating finding. To broaden the scope (for example, to suppress across every package), create the rule from **Settings → Security → Vulnerability Scanning** instead.
### How specificity is resolved
@@ -71,7 +71,7 @@ The same dim-and-icon treatment carries through to the **Compare** sheet, so a C
Suppressions are managed on the **control** Sencho instance and replicate automatically to every remote you've registered:
- Creating, editing, or removing a suppression on the control pushes the full list to every remote.
-- A Sencho instance that has received at least one push from a control is a **replica**. On a replica, **Settings → Security** shows the suppression list read-only, and replicated rows carry a small `replicated` badge so they are easy to tell apart from any locally-created entries.
+- A Sencho instance that has received at least one push from a control is a **replica**. On a replica, **Settings → Security → Vulnerability Scanning** shows the suppression list read-only, and replicated rows carry a small `replicated` badge so they are easy to tell apart from any locally-created entries.
- When you're signed into a control and have a **remote node selected** from the node switcher, the CVE Suppressions panel itself is hidden and a "Scanner is per-node" banner explains that scanning runs on the remote while rules live on the control.
The full replication, retry, and reanchor flow (including the API call to re-bind a replica to a new control) is documented in [Fleet Sync](/features/fleet-sync).
@@ -80,7 +80,7 @@ The full replication, retry, and reanchor flow (including the API call to re-bin
By default, suppressions do not affect [block-on-deploy policies](/features/vulnerability-scanning#honoring-suppressions-in-deploy-blocks). A policy evaluates the raw scan result, so a CVE you have suppressed still blocks a deploy that violates the threshold. Suppressions silence the noise; the gate stays strict.
-To have an accepted CVE stop counting toward the gate, an admin can enable **Honor suppressions in deploy blocks** in **Settings → Security**. With it on, a block-on-deploy policy re-derives each image's severity from the findings that remain after suppressions are applied, so a deploy whose only blocking findings are all suppressed proceeds without a manual bypass. Sencho records each such suppression-driven pass in the audit log.
+To have an accepted CVE stop counting toward the gate, an admin can enable **Honor suppressions in deploy blocks** in **Settings → Security → Vulnerability Scanning**. With it on, a block-on-deploy policy re-derives each image's severity from the findings that remain after suppressions are applied, so a deploy whose only blocking findings are all suppressed proceeds without a manual bypass. Sencho records each such suppression-driven pass in the audit log.
The toggle is off by default and is set per Sencho instance, because the gate runs on whichever instance performs the deploy.
@@ -101,7 +101,7 @@ Suppressed findings carry through to the [SARIF export](/features/vulnerability-
Badge counts reflect the raw findings so they remain meaningful for alerting. Suppressions apply when results are read for display (the scan drawer, the Compare sheet, the SARIF export), not when they are stored. Open the scan drawer to confirm the row is dimmed with a shield-off icon.
@@ -112,7 +112,7 @@ Neither drift mechanism blocks, stops, or quarantines a running stack automatica
+
## Using the modal
diff --git a/docs/features/fleet-backups.mdx b/docs/features/fleet-backups.mdx
index eea93e2b..1fad727d 100644
--- a/docs/features/fleet-backups.mdx
+++ b/docs/features/fleet-backups.mdx
@@ -93,14 +93,14 @@ Admins can delete snapshots from the list view by clicking the trash icon on the
## Cloud Backup
+
## Control and replica roles
-Every Sencho instance carries a `fleet_role` flag that is either `control` or `replica`. The flag is consulted on every write path for the replicated resources and by the **Settings → Security** UI when it decides whether to render the edit controls.
+Every Sencho instance carries a `fleet_role` flag that is either `control` or `replica`. The flag is consulted on every write path for the replicated resources and by the **Settings → Security → Vulnerability Scanning** UI when it decides whether to render the edit controls.
| Role | Behaviour |
|---|---|
| **Control** | The default for any fresh install and for the instance whose **Settings → Nodes** lists the rest of the fleet. Accepts create, edit, and delete on scan policies, CVE suppressions, and misconfig acknowledgements. Pushes the full current state of each resource to every reachable remote on every write. |
-| **Replica** | An instance that has received at least one Fleet Sync push. Renders replicated rules as read-only with a "Managed by control node" banner above the policy editor on **Settings → Security**. Returns `403 Forbidden` for any direct write attempt against the replicated tables. |
+| **Replica** | An instance that has received at least one Fleet Sync push. Renders replicated rules as read-only with a "Managed by control node" banner above the policy editor on **Settings → Security → Vulnerability Scanning**. Returns `403 Forbidden` for any direct write attempt against the replicated tables. |
The transition from control to replica happens automatically the first time a replica accepts a push: the apply transaction sets `fleet_role = 'replica'` atomically with the row replacement, so the role flip and the new rows land together or not at all. Going the other way is explicit: an admin clicks **Demote to control** on the replica (see [Demote a replica](#demote-a-replica) below).
@@ -38,7 +38,7 @@ What does *not* replicate:
- **Trivy itself.** The scanner binary is installed independently on each instance. The Security panel on a remote shows a "Scanner is per-node" callout in place of the full editor, since the scanner lifecycle is a node concern, not a fleet concern.
-
+
- **Everything outside the three resources above.** API tokens, audit logs, blueprints, secrets, alert rules, users, SSO config, and general settings stay per-instance.
- **Pilot-agent nodes.** Sync over the [pilot tunnel](/features/pilot-agent) is not part of v1; the control logs a one-time warning per pilot node and skips it during fanout. The pilot node's local rules are unaffected.
@@ -95,7 +95,7 @@ Stale pushes (`409 STALE_SYNC_PUSH`) are not counted as failures, since a newer
## Demote a replica
-An admin on a replica can take the instance back to a standalone control from **Settings → Security**. The button is "Demote to control" and sits inside the "Managed by control node" callout. The exact modal copy:
+An admin on a replica can take the instance back to a standalone control from **Settings → Security → Vulnerability Scanning**. The button is "Demote to control" and sits inside the "Managed by control node" callout. The exact modal copy:
> **Demote replica to control**
>
@@ -159,7 +159,7 @@ Fleet Sync v1 ships the three replicated resources and the control mechanics des
Misconfig acknowledgements ride the same channel as scan policies and CVE suppressions; if one resource replicates and another does not, it is almost always a per-resource watermark race. Re-save the acknowledgement on the control to produce a fresh `pushedAt`, then the next push catches the remote up. If the symptom persists, check the control's server logs for the `[FleetSync]` push outcome on that remote.
+
## How it works
@@ -45,7 +45,7 @@ For a deep look at how the pilot tunnel works under the hood (credential lifecyc
### Step 1. Open the Add node form
-On the control instance, click your avatar in the top-right and choose **Settings**. In the sidebar pick **System → Nodes**, then click **Add node**.
+On the control instance, click your avatar in the top-right and choose **Settings**. In the sidebar pick **Infrastructure → Nodes**, then click **Add node**.
@@ -90,7 +90,7 @@ Click the button to mint a fresh enrollment command. The previous tunnel is disc
### Step 1. Generate a long-lived token on the remote
-On the **remote** Sencho instance (the server you want to add), open **Settings → System → Nodes**. Click **Generate Token** in the **Generate Node Token** card and copy the token that appears.
+On the **remote** Sencho instance (the server you want to add), open **Settings → Infrastructure → Nodes**. Click **Generate Token** in the **Generate Node Token** card and copy the token that appears.
@@ -102,7 +102,7 @@ On the **remote** Sencho instance (the server you want to add), open **Settings
### Step 2. Add the node on your control instance
-Open **Settings → System → Nodes** on the control instance and click **Add node**. Set Type to **Remote** and Mode to **Distributed API Proxy** to reveal the URL and token fields.
+Open **Settings → Infrastructure → Nodes** on the control instance and click **Add node**. Set Type to **Remote** and Mode to **Distributed API Proxy** to reveal the URL and token fields.
@@ -185,10 +185,10 @@ When you select a remote node in the switcher, the Settings hub filters to the p
| Panel | Scope | Notes |
|-------|:-----:|-------|
| Appearance | Per browser | Theme and density preferences are stored in your browser, not on the node. |
-| System Limits | Per node | Host CPU, RAM, disk, and crash-loop thresholds for the selected node. |
-| Notifications | Per node | Discord, Slack, and Webhook channels fire from the node that detects the event. |
+| Host Alerts | Per node | Host CPU, RAM, disk, and crash thresholds for the selected node. |
+| Channels | Per node | Discord, Slack, and Webhook channels fire from the node that detects the event. |
| Labels | Per node | Stack and container label palettes. |
-| Security | Per node | Trivy install state and scanner readiness for the selected node. |
+| Vulnerability Scanning | Per node | Trivy install state and scanner readiness for the selected node. |
| Developer | Per node | Retention windows for metrics and logs, plus Developer Mode. |
| App Store | Per node | Template registry URL and featured-catalog source for the selected node's catalog. |
| Support | Per browser | Diagnostics bundle, docs links, contact channels. |
@@ -226,7 +226,7 @@ Click the trash icon to remove a remote node. The local row hides this icon beca
Bearer tokens grant full control over the remote Sencho instance. Treat them like passwords:
-- **Rotate immediately** if a token is compromised: open the remote instance's **Settings → System → Nodes** and click **Generate Token** to mint a new one. The previous token is invalidated instantly.
+- **Rotate immediately** if a token is compromised: open the remote instance's **Settings → Infrastructure → Nodes** and click **Generate Token** to mint a new one. The previous token is invalidated instantly.
- Tokens are **encrypted at rest** in the local SQLite database.
- Tokens cannot be used to open interactive terminals (Host Console or container exec). Interactive shell access always requires a real browser session on that specific instance.
diff --git a/docs/features/overview.mdx b/docs/features/overview.mdx
index d27e6895..4472b1e0 100644
--- a/docs/features/overview.mdx
+++ b/docs/features/overview.mdx
@@ -159,7 +159,7 @@ Generate scoped API tokens for CI/CD pipelines, scripts, and automation workflow
### Vulnerability scanning
-Scan container images for known CVEs with [Trivy](https://trivy.dev). Install Trivy with one click from Settings → Security on first use; the [setup guide](/operations/trivy-setup) covers bind-mounted and air-gapped alternatives. Manual scanning, secret and misconfiguration detection, scan comparison, scheduled scans, and CVE suppressions are available on every tier; scan policies that gate deploys, SBOM generation, SARIF export, and auto-update of the managed Trivy binary are Admiral. [Learn more →](/features/vulnerability-scanning)
+Scan container images for known CVEs with [Trivy](https://trivy.dev). Install Trivy with one click from Settings → Security → Vulnerability Scanning on first use; the [setup guide](/operations/trivy-setup) covers bind-mounted and air-gapped alternatives. Manual scanning, secret and misconfiguration detection, scan comparison, scheduled scans, and CVE suppressions are available on every tier; scan policies that gate deploys, SBOM generation, SARIF export, and auto-update of the managed Trivy binary are Admiral. [Learn more →](/features/vulnerability-scanning)
### CVE suppressions
diff --git a/docs/features/pilot-agent.mdx b/docs/features/pilot-agent.mdx
index a3516ae4..7f48bb11 100644
--- a/docs/features/pilot-agent.mdx
+++ b/docs/features/pilot-agent.mdx
@@ -52,7 +52,7 @@ Conceptually, the agent reverses the usual client/server direction.
Inside the control instance, the tunnel terminates at a **loopback bridge**: a tiny HTTP server on `127.0.0.1:
+
What rides through the tunnel:
@@ -302,7 +302,7 @@ The generic node-connectivity issues (a node showing Offline, a pilot agent stuc
+
The table shows one row per user with their **Username**, **Role** badge, account **Created** date, and per-row action icons. The signed-in admin's row carries a small `(you)` marker after the username and the delete icon is disabled, so you cannot lock yourself out by deleting your own account.
diff --git a/docs/features/resources.mdx b/docs/features/resources.mdx
index d06c65bd..b2c2339f 100644
--- a/docs/features/resources.mdx
+++ b/docs/features/resources.mdx
@@ -17,7 +17,7 @@ The hero stays hidden when there is nothing to reclaim, keeping the view focused
To set the banner aside without pruning, use the **×** in its top-right corner. It stays hidden on that browser until the reclaimable total grows past the amount it held when you dismissed it, so a small, stubborn remainder will not keep reappearing while a genuine new build-up still surfaces.
-To keep the banner off for a node entirely, open **Settings → System → Docker hygiene** and switch off **Show reclaimable-space banner**. It is on by default and applies per node.
+To keep the banner off for a node entirely, open **Settings → Monitoring → Docker & Storage** and switch off **Show reclaimable-space banner**. It is on by default and applies per node.
+
Hover any row to reveal a **Pencil** edit icon and a destructive **Trash** icon on the trailing edge. The edit dialog shares its chrome with the create dialog: the kicker reads `LABELS · NEW` for a new label or `LABELS · EDIT` when you opened it from the pencil, the body has a single `Label name` input plus the ten color swatches, and the footer has **Cancel** and **Create** (or **Save**) buttons.
@@ -67,7 +67,7 @@ Deleting a label opens a destructive confirmation with the kicker `LABELS · DEL
Right-clicking a stack in the sidebar (or using the three-dot kebab menu on its row) opens the same context menu under the **organize** group. Click **Labels** to open a submenu listing every label that exists on the active node, with a checkmark next to each one currently assigned to this stack. Clicking a label toggles the assignment immediately. The two trailing items handle creation and full management:
- **New label** drops an inline form into the same submenu (text input with placeholder `Label name`, the ten color swatches, **Create** / **Cancel** buttons). Submitting creates the label on this node and assigns it to the stack in a single round trip. The entry hides itself once the node hits 50 labels.
-- **Manage labels...** sends you to **Settings · Advanced · Labels** for bulk renames, recolors, and deletions.
+- **Manage labels...** sends you to **Settings · Organization · Labels** for bulk renames, recolors, and deletions.
@@ -111,19 +111,19 @@ The **Bulk label assign** card is per-node only by design. To re-tag stacks on a
- **Names are unique per node**, case-sensitive. The same name on two nodes is two separate label rows. Cross-node fleet stop matches on name; bulk assign always operates on one node's labels at a time.
- **Allowed name characters**: letters, digits, spaces, and hyphens. Empty names and names beyond 30 characters are rejected at the API.
- **Bulk-action concurrency**: only one label-driven bulk action can run on a single node at a time. A second concurrent attempt against the same node returns HTTP 429 and the operator sees an error toast; the in-flight action keeps running.
-- **Role visibility**: label authoring is open to every signed-in role. Sidebar grouping, trailing dots on stack rows, the **Settings · Advanced · Labels** panel, the inline create form in the stack menu, and the Fleet View **Tags** filter all work for every user.
+- **Role visibility**: label authoring is open to every signed-in role. Sidebar grouping, trailing dots on stack rows, the **Settings · Organization · Labels** panel, the inline create form in the stack menu, and the Fleet View **Tags** filter all work for every user.
## Troubleshooting
@@ -169,7 +169,7 @@ Sencho retains the last 100 executions per webhook and surfaces the 20 most rece
+
### Sidebar groups
| Group | What it covers |
|-------|----------------|
-| **Identity** | Account, Appearance, License, Users, SSO, API Tokens |
-| **System** | System Limits, Registries, Cloud Backup, Nodes (System Limits is per-node; the rest are global) |
-| **Alerts** | Notifications, Routing, Webhooks |
-| **Advanced** | Labels, Security, Developer, App Store, Support, About |
+| **Personal** | Account, Appearance |
+| **Access** | License, Users, SSO, API Tokens |
+| **Infrastructure** | Nodes, Fleet Mesh, Registries, Cloud Backup, App Store |
+| **Monitoring** | Host Alerts, Docker & Storage |
+| **Notifications** | Channels, Notification Routing |
+| **Automation** | Webhooks |
+| **Organization** | Labels |
+| **Security** | Vulnerability Scanning |
+| **Operations** | Data Retention, Developer Diagnostics, Recovery |
+| **Help** | Support, About |
-Sections that require a higher license tier stay hidden until the operator has the matching license. Admin-only sections (Users, SSO, API Tokens, Registries, Cloud Backup, Routing, Security) stay hidden for non-admin operators.
+Sections that require a higher license tier stay hidden until the operator has the matching license. Admin-only sections (Users, SSO, API Tokens, Fleet Mesh, Registries, Cloud Backup, Notification Routing, Vulnerability Scanning) stay hidden for non-admin operators.
### Page chrome
@@ -26,10 +32,10 @@ Every section renders inside the same masthead-and-sidebar layout. The masthead
| Pill | Meaning |
|------|---------|
-| **SCOPE** `operator` / `global` | Setting applies to your account (Identity sections) or to the whole instance (System and Advanced) |
+| **SCOPE** `operator` / `global` | Setting applies to your account or this browser (Personal sections) or to the whole instance (every other non-node group) |
| **NODE** `
+
---
@@ -211,32 +217,73 @@ See [API Tokens](/features/api-tokens) for the full walkthrough.
---
-## System Limits
+## Host Alerts
**Scope:** Per-node (applies to the currently selected node)
-Configure resource thresholds that trigger visual warnings on the dashboard stat cards. These are display thresholds only; Sencho does not throttle or kill containers when limits are reached. The masthead **NODE** pill names which node you are configuring; the **EDITED** pill counts unsaved changes.
+Configure the host resource thresholds that trigger warnings, the suppression cadence for repeated alerts, and whether unexpected container exits raise a crash alert. These are alerting thresholds, not enforcement: Sencho warns when a metric crosses a line, it never throttles or kills containers. The masthead **NODE** pill names which node you are configuring; the **EDITED** pill counts unsaved changes.
-
+
### Host thresholds
| Setting | Default | Description |
|---------|---------|-------------|
-| **CPU limit** | 90% | Alerts fire when the 5-minute average CPU exceeds this percentage. The input warns at values above 95%. |
+| **CPU limit** | 90% | Alerts fire when host CPU utilization exceeds this percentage. The input warns at values above 95%. |
| **RAM limit** | 90% | Set this below the point at which the host starts paging to swap. |
| **Disk limit** | 90% | Low free space slows image pulls and backups. |
+| **Alert suppression** | 60 min | How long to wait before resending a host alert while the metric stays over threshold. The follow-up message includes a count of suppressed cycles. Range 1 to 1,440 minutes. |
-### Docker hygiene
+### Crash capture
+
+| Setting | Default | Description |
+|---------|---------|-------------|
+| **Global crash capture** | On | Watch every managed container for unexpected exits. When on, Sencho sends a notification whenever a container exits with a non-zero status outside a planned stop. |
+
+Click **Save alerts** to apply.
+
+---
+
+## Docker & Storage
+
+**Scope:** Per-node (applies to the currently selected node)
+
+Configure the reclaimable-space alert, the reclaimable-space banner, and automatic image cleanup after updates.
+
+### Storage alerts
| Setting | Default | Description |
|---------|---------|-------------|
| **Janitor threshold** | 5 GiB | Alert when reclaimable Docker data (images, volumes, build cache that `docker prune` could free) exceeds this size. Set to `0` to disable the alert. |
-| **Global crash capture** | On | Watch every managed container for unexpected exits. When on, Sencho sends a notification whenever a container exits with a non-zero status outside a planned stop. |
+| **Show reclaimable-space banner** | On | Show the reclaimable-space banner at the top of the Resource Hub when this node has unused images, stopped containers, or dangling volumes to clear. |
-Click **Save limits** to apply.
+### Image cleanup
+
+| Setting | Default | Description |
+|---------|---------|-------------|
+| **Prune dangling images after updates** | On | When a stack update or a Sencho self-update finishes, remove the node's dangling (untagged) image layers, including the one the update just orphaned. Only untagged layers are touched: tagged images, your volumes, and your data are never removed. Turn it off to keep every old layer. |
+
+Click **Save settings** to apply.
+
+---
+
+## Fleet Mesh
+
+
-
-
-Advanced settings for debug diagnostics and data retention. Most operators can leave these at their defaults. The masthead publishes a **DEV MODE** pill (`on` / `off`).
-
-### Diagnostics
-
-| Setting | Default | Description |
-|---------|---------|-------------|
-| **Developer mode** | Off | Enables real-time metrics streams and verbose debug diagnostics in the UI. Does not affect [Global Observability](/features/global-observability) streaming, which is always on. |
-
-### Data retention
+How long Sencho keeps historical data on this node before pruning it.
| Setting | Default | Max | Description |
|---------|---------|-----|-------------|
| **Container metrics** | 24 hrs | 8,760 (1 year) | How long to keep per-container CPU, RAM, and network history for dashboard charts. |
| **Notification log** | 30 days | 365 | How long to keep alert and notification history. |
+| **Scan history per image** | 50 scans | 1,000 | How many vulnerability scans to keep per image. Older scans beyond the cap are pruned. |
| **Audit log** | 90 days | 365 | How long to keep audit trail entries. Requires Admiral. |
-Click **Save settings** to apply. Retention rows are global; the **Developer mode** toggle is per-node.
+Click **Save settings** to apply.
+
+---
+
+## Developer Diagnostics
+
+**Scope:** Per-node
+
+Debug diagnostics for this node. Most operators can leave this off. The masthead publishes a **DEV MODE** pill (`on` / `off`).
+
+| Setting | Default | Description |
+|---------|---------|-------------|
+| **Developer mode** | Off | Enables real-time metrics streams and verbose debug diagnostics in the UI. Does not affect [Global Observability](/features/global-observability) streaming, which is always on. |
+
+Click **Save settings** to apply.
---
diff --git a/frontend/src/components/dashboard/ConfigurationStatus.tsx b/frontend/src/components/dashboard/ConfigurationStatus.tsx
index 3a6c77d6..521cba63 100644
--- a/frontend/src/components/dashboard/ConfigurationStatus.tsx
+++ b/frontend/src/components/dashboard/ConfigurationStatus.tsx
@@ -158,12 +158,12 @@ export function ConfigurationStatus({ onOpenSection }: ConfigurationStatusProps