merge: AdminUI sweep foundation — scoped-bundle link, btn sizing vars, notice-alert, tree-twist, doc relocations

This commit is contained in:
Joseph Doherty
2026-08-10 16:33:24 -04:00
5 changed files with 89 additions and 1 deletions
+22
View File
@@ -297,6 +297,28 @@ unset (⇒ `Dps`) until the rig is flipped with `Telemetry__Mode=Grpc` / `Teleme
The Config DB itself (the EF Core `OtOpcUaConfigDbContext`, entities, draft/publish generations, `NodeAcl`, `LdapGroupRoleMapping`, migrations) is the durable home for the fleet's drivers, UNS hierarchy, ACLs, and audit log. For the **full schema** see [`docs/v2/config-db-schema.md`](v2/config-db-schema.md). This page does not duplicate it.
### Audit log (`ConfigAuditLog`)
The cluster audit log lives in the Config DB and is written by `ActorAuditWriter`; the AdminUI reads it
per cluster at `/clusters/{id}/audit`. It has no `appsettings` section — it is on whenever an admin node
has a `ConfigDb` — but one schema property is worth recording here because it constrains how callers may
write to it:
- **`EventId` gives cross-restart deduplication, and the DB enforces it.** Each row carries the
stable per-event `AuditEvent.EventId`, under a *filtered* unique index
(`UX_ConfigAuditLog_EventId`, `WHERE [EventId] IS NOT NULL` — so the nullable pre-v2 backfill rows
do not collide with each other). That is what makes an Akka actor safe to retry an apply against
the audit log: the batched writer flushing again after a process crash, a supervision restart, or
an at-least-once redelivery re-sends the same `EventId` and does **not** insert a duplicate row.
`CorrelationId` is the companion column — it joins a row to its originating request/workflow, so
the several rows of one logical operation group together.
- Consequently, **mint the `EventId` per event, never per write attempt.** An id generated inside
the retry path defeats the unique index rather than tripping it, and nothing downstream flags the
result — the log simply grows a second copy of a deployment's audit trail. Carry the id with the
command.
For the full column list see [`docs/v2/config-db-schema.md`](v2/config-db-schema.md).
### Galaxy / MxAccess driver config (`DriverConfig` JSON, not `appsettings`)
The Galaxy/MxAccess connection settings are **not an `appsettings` section.** They are driver-instance options stored in the `DriverConfig` JSON column of the Config DB (edited via the Admin UI), bound to `GalaxyDriverOptions` (`src/Drivers/ZB.MOM.WW.OtOpcUa.Driver.Galaxy.Contracts/GalaxyDriverOptions.cs`, namespace `...Driver.Galaxy.Config`). It decomposes into nested records:
+15
View File
@@ -97,6 +97,21 @@ single stream per (central, driver-node) pair carries all four, rather than one
Proto field evolution is additive-only (never renumber/reuse a tag), locked by a contract test that
reflects over the `oneof` cases.
### `driver-health` is keyed per driver instance, not per Akka member
`DriverHealthChanged` carries no per-Akka-member identity — a snapshot names the driver instance it
describes, never the node that published it. `IDriverStatusSnapshotStore` therefore keys on the
driver instance, and the `/hosts` driver table renders **cluster-scoped** rows: one entry per
configured driver instance, grouped under its cluster, rather than one entry per (member, driver)
pair. A pair's two nodes running the same deployed driver contribute to the same row, with the most
recent snapshot winning.
That is the correct granularity for what the channel reports — a driver instance's transport health
is a property of the instance's configuration and its device, not of which member happens to host
it — but it does mean the panel cannot answer "which node saw this?". Adding that would mean
widening the wire record, not changing the page. The one sub-instance breakdown the channel *does*
carry is per-host connectivity, below.
### Per-host connectivity rides `driver-health` (Gitea #521)
`DriverHealthChanged.HostStatuses` carries each driver's `IHostConnectivityProbe.GetHostStatuses()`