docs: publish LocalDb 0.1.0 to the feed + reconcile component status against verified state

Publishes the three ZB.MOM.WW.LocalDb packages to the Gitea feed (restore-verified
from a scratch consumer) and adds the build/push.sh the other shared libs already have.

The status prose across CLAUDE.md, README.md and components/*/GAPS.md had drifted from
reality, so it was re-derived from the feed listing and the actual PackageReferences +
registration calls on each consumer's default branch rather than from prior claims.
Five claims were false: Health "not yet adopted" (all four apps wire MapZbHealth),
GalaxyRepository's mxaccessgw adoption "a follow-on" (its Server wires
AddZbGalaxyRepository), Configuration "not yet pushed", Secrets G-8 "not yet
committed", and Theme pinned at 0.2.0 (all four are on 0.3.1). Every doc also said
"three apps" while HistorianGateway is a fourth consumer of seven libs, and all
eight libraries' test counts were stale (re-ran each suite; all green).

Surfaces one previously unrecorded gap: Secrets source is at 0.1.3 with KEK rotation
committed, but the feed tops out at 0.1.2, so no app can consume rotation until it
is published.

Health and observability divergence tables are labelled historical, not re-verified —
the libraries are proven wired, but per-app probe coverage vs spec was not re-walked.

Claude-Session: https://claude.ai/code/session_01BL2Vu1ESDQ9SCN4gVKkdts
This commit is contained in:
Joseph Doherty
2026-07-18 03:06:49 -04:00
parent 9cb6831380
commit 3dd7aa40ff
11 changed files with 195 additions and 56 deletions
+27 -22
View File
@@ -6,14 +6,19 @@ This file provides guidance to Claude Code (claude.ai/code) when working with co
`scadaproj` is primarily an umbrella/index workspace that aggregates a family of
related SCADA / OT / Wonderware / OPC UA "sister projects" that live as **sibling
directories under `~/Desktop/`**. It now also **hosts six pieces of source itself**
the shared [`ZB.MOM.WW.Auth/`](ZB.MOM.WW.Auth/) library, the shared
[`ZB.MOM.WW.Theme/`](ZB.MOM.WW.Theme/) UI kit, the shared
[`ZB.MOM.WW.Health/`](ZB.MOM.WW.Health/) health-check library, the shared
[`ZB.MOM.WW.Telemetry/`](ZB.MOM.WW.Telemetry/) observability library, the shared
[`ZB.MOM.WW.Configuration/`](ZB.MOM.WW.Configuration/) config-validation library, and the new
[`ZB.MOM.WW.GalaxyRepository/`](ZB.MOM.WW.GalaxyRepository/) Galaxy browse library — all the realized output of their
directories under `~/Desktop/`**. It now also **hosts nine shared libraries itself** (verified
2026-07-18) — [`ZB.MOM.WW.Auth/`](ZB.MOM.WW.Auth/) (login/identity),
[`ZB.MOM.WW.Theme/`](ZB.MOM.WW.Theme/) (UI kit),
[`ZB.MOM.WW.Health/`](ZB.MOM.WW.Health/) (health checks),
[`ZB.MOM.WW.Telemetry/`](ZB.MOM.WW.Telemetry/) (observability),
[`ZB.MOM.WW.Configuration/`](ZB.MOM.WW.Configuration/) (config validation),
[`ZB.MOM.WW.Audit/`](ZB.MOM.WW.Audit/) (audit event model),
[`ZB.MOM.WW.Secrets/`](ZB.MOM.WW.Secrets/) (encrypted secret store),
[`ZB.MOM.WW.GalaxyRepository/`](ZB.MOM.WW.GalaxyRepository/) (Galaxy browse), and
[`ZB.MOM.WW.LocalDb/`](ZB.MOM.WW.LocalDb/) (embedded cache + 2-node sync) — all the realized output of their
respective component normalizations (see [Component normalization](#component-normalization)).
(A tenth directory, `ZB.MOM.WW.SPHistorianClient/`, is **retired** — 0 tracked files, only
gitignored build residue left on disk.)
The point of this file is to give a high-level scan of each sister project — its purpose,
location, stack, and primary commands — so a fresh Claude Code session can orient across
the whole family without opening each repo first.
@@ -137,14 +142,14 @@ each project's **code-verified current state**, and the **gaps** between. See
| Component | Status | Goal | Design | Implementation |
|---|---|---|---|---|
| Auth (login / identity / authz) | Adopted (lib `0.1.4`; all 3 apps, merged to **local default** main/master + **pushed to origin** (gitea)) | Shared `ZB.MOM.WW.Auth` lib | [`components/auth/`](components/auth/) | [`ZB.MOM.WW.Auth/`](ZB.MOM.WW.Auth/) |
| UI Theme (layout / tokens / components) | Adopted (lib `0.2.0`; all 3 apps, merged to **local default** + **pushed to origin** (gitea)) | Shared `ZB.MOM.WW.Theme` RCL | [`components/ui-theme/`](components/ui-theme/) | [`ZB.MOM.WW.Theme/`](ZB.MOM.WW.Theme/) |
| Health (readiness / liveness / active-node) | Built (lib `0.1.0`) | Shared `ZB.MOM.WW.Health` lib | [`components/health/`](components/health/) | [`ZB.MOM.WW.Health/`](ZB.MOM.WW.Health/) |
| Observability (metrics / traces / logs) | Built (lib `0.1.0`) | Shared `ZB.MOM.WW.Telemetry` lib + `.Serilog` | [`components/observability/`](components/observability/) | [`ZB.MOM.WW.Telemetry/`](ZB.MOM.WW.Telemetry/) |
| Config + validation (options / startup validation) | Adopted (lib `0.1.0`; all 3 apps, local) | Shared `ZB.MOM.WW.Configuration` lib | [`components/configuration/`](components/configuration/) | [`ZB.MOM.WW.Configuration/`](ZB.MOM.WW.Configuration/) |
| Audit (event model + writer seam) | Adopted (lib `0.1.0`; all 3 apps, merged to **local default** main/master + **pushed to origin** (gitea)) | Shared `ZB.MOM.WW.Audit` lib | [`components/audit/`](components/audit/) | [`ZB.MOM.WW.Audit/`](ZB.MOM.WW.Audit/) |
| Galaxy Repository (object-hierarchy SQL browse + gRPC service) | Built (lib `0.1.0`, **published to the Gitea feed**; consumed by HistorianGateway as a feed `PackageReference`) | Shared `ZB.MOM.WW.GalaxyRepository` lib | _(design in histsdk + design doc 2026-06-23)_ | [`ZB.MOM.WW.GalaxyRepository/`](ZB.MOM.WW.GalaxyRepository/) |
| Secrets (encrypted store + `${secret:}` resolution) | Built (libs `0.1.2`, **published to the Gitea feed**; **HistorianGateway adopted + live-proven** 2026-07-16; **mxaccessgw adopted G-4/G-5/G-6 + merged to `origin/main` @ `e088dfa`** 2026-07-16, box-verified fail-closed + encrypt-at-rest; **ScadaBridge adopted G-3/G-4/G-5/G-6 + merged to `origin/main` @ `128f1596`** 2026-07-16, **G-3 live-proven vs the real production MxGateway gateway** `wonder-app-vd03:5120` (secret-ref ApiKey → Connected + browsed real Galaxy); **OtOpcUa adopted G-2/G-4/G-5/G-6 + merged to `origin/master` @ `872cf7e3`** (lmxopcua) 2026-07-16 — the last app, so **all four now adopted**; Layer-B driver secrets (Galaxy API key + OpcUaClient `Password`/`UserCertificatePassword`) resolve fail-closed at driver session-open, `AddZbSecrets` registered unconditionally so driver-only nodes work; **G-2 live-proven vs the real production MxGateway** `wonder-app-vd03:5120` — a `secret:`-ref Galaxy ApiKey resolved through OtOpcUa's real `GalaxyDriverBrowser` → dummy key `MxGatewayAuthenticationException`, real key → browsed the real Galaxy root (10 nodes); temp key minted+revoked+deleted); **G-8 KEK-rotation BUILT (lib bumped `0.1.2`→`0.1.3`, 2026-07-17):** `Rewrap` DEK primitive + CAS-guarded `ApplyRewrapAsync` + `KekRotationService.RewrapAllAsync` + `secret rewrap-all` CLI + operator runbook (`ZB.MOM.WW.Secrets/docs/operations/kek-rotation.md`), full suite green + CLI smoke + adversarial crypto review PASS (TOCTOU closed via compare-and-swap); republish to feed is opt-in. **G-7 clustered replication DESIGNED + PLANNED** — fork resolved to **build the shared SQL-Server `ISecretStore`** (Akka replicator deferred phase-2), executable plan `docs/plans/2026-07-17-secrets-g7-*`. Both not yet committed/pushed (awaiting go-ahead) | Shared `ZB.MOM.WW.Secrets` lib (3 packages + CLI) | [`components/secrets/`](components/secrets/) | [`ZB.MOM.WW.Secrets/`](ZB.MOM.WW.Secrets/) |
| LocalDb (embedded cache + 2-node sync) | Built (3 pkgs `0.1.0`, **NOT yet published to the feed**; no app adoption yet) | Shared `ZB.MOM.WW.LocalDb` lib | [`docs/plans/2026-07-17-localdb-design.md`](docs/plans/2026-07-17-localdb-design.md) | [`ZB.MOM.WW.LocalDb/`](ZB.MOM.WW.LocalDb/) |
| UI Theme (layout / tokens / components) | Adopted (feed `0.2.0``0.3.1`; **all 4 apps pinned `0.3.1`**, pushed to origin) | Shared `ZB.MOM.WW.Theme` RCL | [`components/ui-theme/`](components/ui-theme/) | [`ZB.MOM.WW.Theme/`](ZB.MOM.WW.Theme/) |
| Health (readiness / liveness / active-node) | **Adopted** (lib `0.1.0`, on the feed; **all 4 apps** reference it + wire `MapZbHealth` — verified 2026-07-18; the prior "not yet adopted" claim was stale) | Shared `ZB.MOM.WW.Health` lib | [`components/health/`](components/health/) | [`ZB.MOM.WW.Health/`](ZB.MOM.WW.Health/) |
| Observability (metrics / traces / logs) | **Adopted** (libs `0.1.0`, on the feed; **all 4 apps** call `AddZbTelemetry`; `AddZbSerilog` in all but ScadaBridge, which keeps its own factory by design) | Shared `ZB.MOM.WW.Telemetry` lib + `.Serilog` | [`components/observability/`](components/observability/) | [`ZB.MOM.WW.Telemetry/`](ZB.MOM.WW.Telemetry/) |
| Config + validation (options / startup validation) | Adopted (lib `0.1.0`, on the feed; **all 4 apps**, pushed — the "local only / not yet pushed" caveat was stale) | Shared `ZB.MOM.WW.Configuration` lib | [`components/configuration/`](components/configuration/) | [`ZB.MOM.WW.Configuration/`](ZB.MOM.WW.Configuration/) |
| Audit (event model + writer seam) | Adopted (lib `0.1.0`, on the feed; **all 4 apps**, pushed to origin) | Shared `ZB.MOM.WW.Audit` lib | [`components/audit/`](components/audit/) | [`ZB.MOM.WW.Audit/`](ZB.MOM.WW.Audit/) |
| Galaxy Repository (object-hierarchy SQL browse + gRPC service) | **Adopted** (feed `0.1.0` + `0.2.0`; consumed at `0.2.0` by HistorianGateway **and mxaccessgw**, whose Server wires `AddZbGalaxyRepository` — verified 2026-07-18; the prior "mxaccessgw adoption is a follow-on" claim was stale) | Shared `ZB.MOM.WW.GalaxyRepository` lib | _(design in histsdk + design doc 2026-06-23)_ | [`ZB.MOM.WW.GalaxyRepository/`](ZB.MOM.WW.GalaxyRepository/) |
| Secrets (encrypted store + `${secret:}` resolution) | Built (libs `0.1.2`, **published to the Gitea feed**; **HistorianGateway adopted + live-proven** 2026-07-16; **mxaccessgw adopted G-4/G-5/G-6 + merged to `origin/main` @ `e088dfa`** 2026-07-16, box-verified fail-closed + encrypt-at-rest; **ScadaBridge adopted G-3/G-4/G-5/G-6 + merged to `origin/main` @ `128f1596`** 2026-07-16, **G-3 live-proven vs the real production MxGateway gateway** `wonder-app-vd03:5120` (secret-ref ApiKey → Connected + browsed real Galaxy); **OtOpcUa adopted G-2/G-4/G-5/G-6 + merged to `origin/master` @ `872cf7e3`** (lmxopcua) 2026-07-16 — the last app, so **all four now adopted**; Layer-B driver secrets (Galaxy API key + OpcUaClient `Password`/`UserCertificatePassword`) resolve fail-closed at driver session-open, `AddZbSecrets` registered unconditionally so driver-only nodes work; **G-2 live-proven vs the real production MxGateway** `wonder-app-vd03:5120` — a `secret:`-ref Galaxy ApiKey resolved through OtOpcUa's real `GalaxyDriverBrowser` → dummy key `MxGatewayAuthenticationException`, real key → browsed the real Galaxy root (10 nodes); temp key minted+revoked+deleted); **G-8 KEK-rotation BUILT (lib bumped `0.1.2`→`0.1.3`, 2026-07-17):** `Rewrap` DEK primitive + CAS-guarded `ApplyRewrapAsync` + `KekRotationService.RewrapAllAsync` + `secret rewrap-all` CLI + operator runbook (`ZB.MOM.WW.Secrets/docs/operations/kek-rotation.md`), full suite green + CLI smoke + adversarial crypto review PASS (TOCTOU closed via compare-and-swap). **G-7 clustered replication DESIGNED + PLANNED** — fork resolved to **build the shared SQL-Server `ISecretStore`** (Akka replicator deferred phase-2), executable plan `docs/plans/2026-07-17-secrets-g7-*`. **Corrected 2026-07-18:** G-8 + the G-7 plan **ARE committed and pushed** on `main` (`d82d345`) — the "not yet committed/pushed" note was stale. The real open gap is that **`0.1.3` is NOT on the feed** (feed tops out at `0.1.2`, where all 4 apps are pinned), so KEK rotation is unconsumable until published; G-7 has no `ISecretStore` SQL implementation yet | Shared `ZB.MOM.WW.Secrets` lib (3 packages + CLI) | [`components/secrets/`](components/secrets/) | [`ZB.MOM.WW.Secrets/`](ZB.MOM.WW.Secrets/) |
| LocalDb (embedded cache + 2-node sync) | Built (3 pkgs `0.1.0`, **published to the Gitea feed** 2026-07-18, restore-verified from a scratch consumer; no app adoption yet) | Shared `ZB.MOM.WW.LocalDb` lib | [`docs/plans/2026-07-17-localdb-design.md`](docs/plans/2026-07-17-localdb-design.md) | [`ZB.MOM.WW.LocalDb/`](ZB.MOM.WW.LocalDb/) |
The auth component is fully populated: a normalized [`spec`](components/auth/spec/SPEC.md), a
proposed [`shared-contract`](components/auth/shared-contract/ZB.MOM.WW.Auth.md), three
@@ -154,7 +159,7 @@ the authz vocabularies (OPC-UA permissions / gRPC scopes / roles + site-scoping)
The shared library is **built and lives in this repo** at [`ZB.MOM.WW.Auth/`](ZB.MOM.WW.Auth/)
(its own nested git repo; .NET 10; 4 packages — `Abstractions`, `Ldap`, `ApiKeys`, `AspNetCore`;
172 tests; `dotnet pack` → 4 nupkgs @ 0.1.0). The implementation plan is at
215 tests passing + 1 skipped (verified 2026-07-18); feed carries `0.1.0``0.1.4`). The implementation plan is at
[`docs/plans/2026-06-01-zb-mom-ww-auth-shared-library.md`](docs/plans/2026-06-01-zb-mom-ww-auth-shared-library.md).
**Adopted across all three apps on 2026-06-02** (auth GAPS #1#8) on each repo's `feat/adopt-zb-auth` branch —
committed + reviewed, then **fast-forward-merged into the repo's local default (main/master) and PUSHED to origin
@@ -176,7 +181,7 @@ backlog. Shared = Technical-Light tokens + IBM Plex fonts + side-rail shell + wi
per-project = each app's `site.css` page layout, route content, scoped `.razor.css`.
The shared RCL is **built and lives in this repo** at [`ZB.MOM.WW.Theme/`](ZB.MOM.WW.Theme/)
(.NET 10 Razor Class Library; single package; 44 bUnit tests; `dotnet pack` → 1 nupkg @ 0.2.0,
(.NET 10 Razor Class Library; single package; 48 bUnit tests (verified 2026-07-18); feed carries `0.2.0``0.3.1`,
**published to the Gitea feed**). The build plan is at
[`docs/plans/2026-06-01-zb-mom-ww-theme-shared-library.md`](docs/plans/2026-06-01-zb-mom-ww-theme-shared-library.md);
the adoption plan at [`docs/plans/2026-06-03-ui-theme-adoption.md`](docs/plans/2026-06-03-ui-theme-adoption.md).
@@ -201,8 +206,8 @@ orchestrator wiring, and ScadaBridge's distributed health-monitoring pipeline.
The shared library is **built and lives in this repo** at [`ZB.MOM.WW.Health/`](ZB.MOM.WW.Health/)
(.NET 10; 3 packages — `ZB.MOM.WW.Health`, `ZB.MOM.WW.Health.Akka`, `ZB.MOM.WW.Health.EntityFrameworkCore`;
58 tests; `dotnet pack` → 3 nupkgs @ 0.1.0).
**Not yet adopted** by the three apps — that's the follow-on tracked in [`components/health/GAPS.md`](components/health/GAPS.md).
64 tests (verified 2026-07-18); `dotnet pack` → 3 nupkgs @ 0.1.0).
**Adopted by all four apps** — verified 2026-07-18 (each references the package and wires `MapZbHealth`); the previous "not yet adopted" claim was stale. Per-app probe coverage vs the spec has NOT been re-verified — see [`components/health/GAPS.md`](components/health/GAPS.md).
Build/test from `ZB.MOM.WW.Health/`: `dotnet test`. Consumer matrix: MxAccessGateway → core only;
OtOpcUa & ScadaBridge → all three packages.
@@ -217,7 +222,7 @@ backlog. Shared = OTel Resource (service.name/site.id/node.role identity triple)
enrichers, and redaction policies.
The shared library is **built and lives in this repo** at [`ZB.MOM.WW.Telemetry/`](ZB.MOM.WW.Telemetry/)
(.NET 10; 2 packages — `ZB.MOM.WW.Telemetry`, `ZB.MOM.WW.Telemetry.Serilog`; 19 tests;
(.NET 10; 2 packages — `ZB.MOM.WW.Telemetry`, `ZB.MOM.WW.Telemetry.Serilog`; 34 tests (verified 2026-07-18);
`dotnet pack` → 2 nupkgs @ 0.1.0). **Adopted across all three apps on 2026-06-01** (branch
`feat/adopt-zb-telemetry` per repo, behaviour-preserving): `AddZbTelemetry` (Resource + standard
instrumentation + Prometheus `/metrics`) everywhere; OtOpcUa + MxGateway on `AddZbSerilog` (MxGateway's
@@ -240,7 +245,7 @@ message); left per-project = each app's options classes + domain rules, and OtOp
draft/generation-content validation (DB-side `sp_ValidateDraft`; its C# `DraftValidator` is dormant).
The shared library is **built and lives in this repo** at [`ZB.MOM.WW.Configuration/`](ZB.MOM.WW.Configuration/)
(.NET 10; single package `ZB.MOM.WW.Configuration`; 27 tests; `dotnet pack` → 1 nupkg @ 0.1.0).
(.NET 10; single package `ZB.MOM.WW.Configuration`; 42 tests (verified 2026-07-18); `dotnet pack` → 1 nupkg @ 0.1.0).
The implementation plan is at
[`docs/plans/2026-06-01-zb-mom-ww-configuration-shared-library.md`](docs/plans/2026-06-01-zb-mom-ww-configuration-shared-library.md).
**Adopted across all three apps on 2026-06-01** (OtOpcUa, MxAccessGateway, ScadaBridge) on each repo's
@@ -265,7 +270,7 @@ principal. `IAuditRedactor` is aligned with Telemetry's `ILogRedactor` seam conv
The shared library is **built and lives in this repo** at [`ZB.MOM.WW.Audit/`](ZB.MOM.WW.Audit/)
(.NET 10; 1 package — `ZB.MOM.WW.Audit`; only non-BCL dependency `Microsoft.Extensions.DependencyInjection.Abstractions`;
19 tests; `dotnet pack` → 1 nupkg @ 0.1.0). Repo: `https://gitea.dohertylan.com/dohertj2/zb-mom-ww-audit`.
23 tests (verified 2026-07-18); `dotnet pack` → 1 nupkg @ 0.1.0). Repo: `https://gitea.dohertylan.com/dohertj2/zb-mom-ww-audit`.
**Adopted across all three apps on 2026-06-02** (audit GAPS #1#6) on each repo's `feat/adopt-zb-audit` branch
(stacked on `feat/adopt-zb-auth`) — committed + reviewed, then **merged into the repo's local default (main/master)
and PUSHED to origin (gitea) on 2026-06-03** (in sync). Depth =
+72 -30
View File
@@ -15,12 +15,18 @@ it produces.
| Path | What it is |
|---|---|
| [`CLAUDE.md`](CLAUDE.md) | High-level index of the sister projects + working guidance |
| [`components/`](components/) | Component-normalization framework (per concern: target spec, current state, gaps) |
| [`components/auth/`](components/auth/) | First normalized component — login / identity / authorization |
| [`components/ui-theme/`](components/ui-theme/) | Second normalized component — UI theme / design tokens / layout |
| [`docs/plans/`](docs/plans/) | Implementation plans (e.g. the ZB.MOM.WW.Auth and ZB.MOM.WW.Theme builds) |
| [`ZB.MOM.WW.Auth/`](ZB.MOM.WW.Auth/) | **Built shared library** (.NET 10) — the realized output of the auth normalization |
| [`ZB.MOM.WW.Theme/`](ZB.MOM.WW.Theme/) | **Built shared RCL** (.NET 10) — the realized output of the UI-theme normalization |
| [`components/`](components/) | Component-normalization framework (per concern: target spec, current state, gaps) — 7 components |
| [`docs/plans/`](docs/plans/) | Implementation + design plans (incl. Galaxy Repository and LocalDb, which have no `components/` entry) |
| [`infra/glauth/`](infra/glauth/) | The shared GLAuth every app's dev/test LDAP points at (`10.100.0.35:3893`) |
| [`ZB.MOM.WW.Auth/`](ZB.MOM.WW.Auth/) | **Built shared library** (.NET 10) — login / identity / API keys |
| [`ZB.MOM.WW.Theme/`](ZB.MOM.WW.Theme/) | **Built shared RCL** (.NET 10) — Technical-Light design system |
| [`ZB.MOM.WW.Audit/`](ZB.MOM.WW.Audit/) | **Built shared library** — canonical audit event + writer seam |
| [`ZB.MOM.WW.Health/`](ZB.MOM.WW.Health/) | **Built shared library** — readiness / liveness / active-node probes |
| [`ZB.MOM.WW.Telemetry/`](ZB.MOM.WW.Telemetry/) | **Built shared library** — OTel metrics / traces + Serilog |
| [`ZB.MOM.WW.Configuration/`](ZB.MOM.WW.Configuration/) | **Built shared library** — options validation + startup preflight |
| [`ZB.MOM.WW.Secrets/`](ZB.MOM.WW.Secrets/) | **Built shared library** — AES-256-GCM secret store + `${secret:}` resolution + CLI |
| [`ZB.MOM.WW.GalaxyRepository/`](ZB.MOM.WW.GalaxyRepository/) | **Built shared library** — Galaxy object-hierarchy SQL browse + gRPC service |
| [`ZB.MOM.WW.LocalDb/`](ZB.MOM.WW.LocalDb/) | **Built shared library** — embedded SQLite cache + 2-node gRPC replication |
## The sister projects
@@ -33,6 +39,8 @@ not by a shared build. scadaproj *indexes* them; it does not contain them.
MXAccess parity without loading 32-bit COM. The linchpin both others depend on.
- **ScadaBridge** — distributed SCADA platform on Akka.NET (hub-and-spoke: one central cluster
+ N site clusters); its Data Connection Layer ingests OPC UA and MxAccess.
- **HistorianGateway** (`historiangw`) — gRPC sidecar over the AVEVA Historian (read/write) plus
read-only Galaxy browse; no COM, no x86 worker. OtOpcUa's sole historian backend.
Data flow:
@@ -51,17 +59,27 @@ The sister repos kept re-implementing the same cross-cutting concerns and drifti
**code-verified current state**, and a **gaps / adoption backlog**. Convention + workflow in
[`components/README.md`](components/README.md).
| Component | Status | Folder |
|---|---|---|
| Auth (login / identity / authz) | Built (library 0.1.0); apps not yet adopted | [`components/auth/`](components/auth/) |
| UI Theme (layout / tokens / components) | Built (RCL 0.1.0); apps not yet adopted | [`components/ui-theme/`](components/ui-theme/) |
Status verified 2026-07-18 against the feed + consumer branches (see [Roadmap](#roadmap)).
"All four" = OtOpcUa, MxAccessGateway, ScadaBridge, HistorianGateway.
| Component | Feed | Adoption | Folder |
|---|---|---|---|
| Auth (login / identity / authz) | `0.1.0``0.1.4` | all four (pins drift `0.1.1``0.1.4`) | [`components/auth/`](components/auth/) |
| UI Theme (layout / tokens / components) | `0.2.0``0.3.1` | all four @ `0.3.1` | [`components/ui-theme/`](components/ui-theme/) |
| Audit (event model + writer seam) | `0.1.0` | all four (DEEP) | [`components/audit/`](components/audit/) |
| Config + validation | `0.1.0` | all four | [`components/configuration/`](components/configuration/) |
| Observability (metrics / traces / logs) | `0.1.0` | all four | [`components/observability/`](components/observability/) |
| Health (readiness / liveness / active-node) | `0.1.0` | all four | [`components/health/`](components/health/) |
| Secrets (encrypted store + `${secret:}`) | `0.1.0``0.1.2` | all four @ `0.1.2` (lib `0.1.3` unpublished) | [`components/secrets/`](components/secrets/) |
| Galaxy Repository (SQL browse + gRPC) | `0.1.0`, `0.2.0` | HistorianGateway + mxaccessgw | _(design in `docs/plans/`)_ |
| LocalDb (embedded cache + 2-node sync) | `0.1.0` | none yet | _(design in `docs/plans/`)_ |
## `ZB.MOM.WW.Theme` — the shared UI kit
The UI-theme component, realized as a single-package .NET 10 Razor Class Library the three
apps can adopt to stop copy-pasting the Technical-Light design system. **Built and tested at
0.1.0; adoption by the apps is the follow-on** (tracked in
[`components/ui-theme/GAPS.md`](components/ui-theme/GAPS.md)).
The UI-theme component, realized as a single-package .NET 10 Razor Class Library that replaced
each app's copy-pasted Technical-Light design system. **Adopted by all four apps, currently on
`0.3.1`** (feed carries `0.2.0``0.3.1`); adoption history in
[`components/ui-theme/GAPS.md`](components/ui-theme/GAPS.md).
| Asset / Component | Purpose | Used by |
|---|---|---|
@@ -74,16 +92,16 @@ apps can adopt to stop copy-pasting the Technical-Light design system. **Built a
| `LoginCard` | Static form-POST sign-in card | OtOpcUa, ScadaBridge (MxGateway when login page added) |
| `TechButton`, `TechCard`, `TechField` | Common controls (Bootstrap 5 wrappers) | all |
**Consumer matrix:** all three apps consume the single `ZB.MOM.WW.Theme` package —
OtOpcUa `AdminUI`, MxAccessGateway `Server`, ScadaBridge `Host` + `CentralUI`.
**Consumer matrix:** all four apps consume the single `ZB.MOM.WW.Theme` package —
OtOpcUa `AdminUI`, MxAccessGateway `Server`, ScadaBridge `Host` + `CentralUI`, HistorianGateway `Server`.
### Build & test
```bash
cd ZB.MOM.WW.Theme
dotnet build -c Release # 0 warnings (TreatWarningsAsErrors)
dotnet test # 32 bUnit tests
./build/pack.sh # → ./artifacts/ZB.MOM.WW.Theme.0.1.0.nupkg
dotnet test # 48 bUnit tests (verified 2026-07-18)
./build/pack.sh # → ./artifacts/ZB.MOM.WW.Theme.<version>.nupkg (feed is at 0.3.1)
```
Stack: .NET 10 · Razor Class Library · bUnit · xUnit · central package management.
@@ -93,9 +111,10 @@ More detail: [`ZB.MOM.WW.Theme/README.md`](ZB.MOM.WW.Theme/README.md).
## `ZB.MOM.WW.Auth` — the shared library
The auth component, realized as a four-package .NET 10 library the three apps can adopt to stop
re-implementing authentication. **Built and tested at 0.1.0; adoption by the apps is the
follow-on** (tracked in [`components/auth/GAPS.md`](components/auth/GAPS.md)).
The auth component, realized as a four-package .NET 10 library that replaced each app's
re-implemented authentication. **Adopted by all four apps** — pins drift deliberately
(OtOpcUa `0.1.1`, ScadaBridge `0.1.3`, MxAccessGateway + HistorianGateway `0.1.4`); history in
[`components/auth/GAPS.md`](components/auth/GAPS.md).
| Package | Purpose | Used by |
|---|---|---|
@@ -105,7 +124,7 @@ follow-on** (tracked in [`components/auth/GAPS.md`](components/auth/GAPS.md)).
| `ZB.MOM.WW.Auth.AspNetCore` | Canonical claim types, cookie defaults, LDAP DI helpers | all (web UIs) |
**Consumer matrix:** OtOpcUa → `Abstractions + Ldap + AspNetCore` (no ApiKeys / SQLite);
MxAccessGateway & ScadaBridge → all four.
MxAccessGateway, ScadaBridge & HistorianGateway → all four packages.
Identity (LDAP / GLAuth, the canonical role set) is normalized; each app keeps its own
**authorization enforcement** (OPC-UA permissions / gRPC scopes / roles + site-scoping) and maps
@@ -117,8 +136,8 @@ and [`CANONICAL-ROLES.md`](components/auth/spec/CANONICAL-ROLES.md).
```bash
cd ZB.MOM.WW.Auth
dotnet build -c Release # 0 warnings
dotnet test # 172 passing, 1 skipped (opt-in LDAP integration test)
dotnet pack -c Release -o ./artifacts # → 4 nupkgs @ 0.1.0
dotnet test # 215 passing, 1 skipped (opt-in LDAP integration test) — verified 2026-07-18
dotnet pack -c Release -o ./artifacts # → 4 nupkgs (feed is at 0.1.4)
```
Stack: .NET 10 · xUnit · `Novell.Directory.Ldap.NETStandard` · `Microsoft.Data.Sqlite` · central
@@ -133,10 +152,33 @@ ZB_LDAP_IT=1 dotnet test # requires a reachable GLAuth (e.g. a sister repo's i
## Roadmap
- ✅ Auth component normalized (spec + canonical roles + current-state + gaps).
-`ZB.MOM.WW.Auth` shared library built and tested (0.1.0).
- ⬜ Adopt `ZB.MOM.WW.Auth` in OtOpcUa, MxAccessGateway, ScadaBridge — [`components/auth/GAPS.md`](components/auth/GAPS.md) (#8).
- ✅ UI-theme component normalized (spec + design tokens + current-state + gaps).
-`ZB.MOM.WW.Theme` shared UI kit built and tested (0.1.0); apps not yet adopted.
- ⬜ Adopt `ZB.MOM.WW.Theme` in OtOpcUa [low risk], ScadaBridge [med], MxAccessGateway [high risk] — [`components/ui-theme/GAPS.md`](components/ui-theme/GAPS.md).
> **Verified 2026-07-18** against the Gitea feed (`nuget/query?q=ZB.MOM.WW`) and the actual
> `PackageReference`s on each consumer's default branch — not from status claims in docs.
> Per-component detail in each `components/<name>/GAPS.md`.
**Shipped**
- ✅ Auth normalized + `ZB.MOM.WW.Auth` built (feed: `0.1.0``0.1.4`) and **adopted by all four apps**.
Version pins drift on purpose: OtOpcUa `0.1.1`, ScadaBridge `0.1.3`, MxAccessGateway + HistorianGateway `0.1.4`.
- ✅ UI Theme normalized + `ZB.MOM.WW.Theme` built (feed: `0.2.0``0.3.1`); **all four apps on `0.3.1`**.
- ✅ Audit — `ZB.MOM.WW.Audit` `0.1.0` on the feed; adopted by all four (DEEP: canonical record everywhere).
- ✅ Configuration — `ZB.MOM.WW.Configuration` `0.1.0` on the feed; adopted by all four.
- ✅ Observability — `ZB.MOM.WW.Telemetry` + `.Serilog` `0.1.0` on the feed; adopted by all four.
- ✅ Health — `ZB.MOM.WW.Health` (+ `.Akka`, `.EntityFrameworkCore`) `0.1.0` on the feed; **adopted by all four**
(`MapZbHealth` wired in each; previously documented as "not yet adopted" — that was stale).
- ✅ Galaxy Repository — `ZB.MOM.WW.GalaxyRepository` `0.2.0` on the feed; consumed by HistorianGateway
**and mxaccessgw** (which wires `AddZbGalaxyRepository` in its Server; previously documented as a
pending follow-on — also stale).
- ✅ Secrets — `ZB.MOM.WW.Secrets` (+ `.Abstractions`, `.Ui`) published through `0.1.2`; all four apps on `0.1.2`.
- ✅ LocalDb — `ZB.MOM.WW.LocalDb` (+ `.Contracts`, `.Replication`) built at `0.1.0` and **published to the
feed 2026-07-18** (restore-verified from a scratch consumer).
**Open**
- ⬜ Publish `ZB.MOM.WW.Secrets` `0.1.3` (KEK rotation — built, feed still tops out at `0.1.2`) and execute
the G-7 clustered-replication plan — [`components/secrets/GAPS.md`](components/secrets/GAPS.md).
- ⬜ Adopt `ZB.MOM.WW.LocalDb` in an app — no consumer references it yet.
- ⬜ Give LocalDb a `components/localdb/` entry; it is the one shared lib whose design lives only in
[`docs/plans/2026-07-17-localdb-design.md`](docs/plans/2026-07-17-localdb-design.md).
- ⬜ Converge the Auth version pins (OtOpcUa is three minors behind at `0.1.1`).
- ⬜ Normalize the next cross-cutting component.
+1 -1
View File
@@ -18,7 +18,7 @@ last-writer-wins over a hybrid logical clock. All timestamps are UTC.
| `ZB.MOM.WW.LocalDb.Contracts` | `localdb_sync.v1` proto + generated gRPC types (packable; a future peer could be non-.NET). |
| `ZB.MOM.WW.LocalDb.Replication` | gRPC sync engine: passive `LocalDbSyncService`, initiating `SyncBackgroundService`, `MaintenanceBackgroundService`, LWW apply, watermark acks + pruning, snapshot resync, `ISyncStatus`, `LocalDbMetrics`, `AddZbLocalDbReplication()` / `MapZbLocalDbSync()`. |
> Status: **built, not yet published to the Gitea feed; no app has adopted it yet.**
> Status: **built and published to the Gitea feed at `0.1.0` (2026-07-18); no app has adopted it yet.**
## Quickstart
+24
View File
@@ -0,0 +1,24 @@
#!/usr/bin/env bash
# push.sh — pack and push the ZB.MOM.WW.LocalDb NuGet packages (core, Contracts, Replication) to the Gitea feed.
#
# Required environment variables:
# GITEA_NUGET_SOURCE — full URL of the Gitea NuGet feed
# e.g. https://gitea.dohertylan.com/api/packages/dohertj2/nuget/index.json
# GITEA_NUGET_KEY — Gitea access token with package:write permission
#
# Usage:
# export GITEA_NUGET_SOURCE="https://gitea.dohertylan.com/api/packages/dohertj2/nuget/index.json"
# export GITEA_NUGET_KEY="your-gitea-token"
# ./build/push.sh
set -euo pipefail
: "${GITEA_NUGET_SOURCE:?set GITEA_NUGET_SOURCE to your Gitea NuGet feed URL}"
: "${GITEA_NUGET_KEY:?set GITEA_NUGET_KEY to your Gitea access token}"
dotnet pack -c Release -o ./artifacts
dotnet nuget push "./artifacts/*.nupkg" \
--source "$GITEA_NUGET_SOURCE" \
--api-key "$GITEA_NUGET_KEY" \
--skip-duplicate
+4
View File
@@ -3,6 +3,10 @@
Divergence of each project from [`spec/SPEC.md`](spec/SPEC.md), and the ordered backlog to
reach the shared `ZB.MOM.WW.Audit` library. Status legend: ⛔ gap · 🟡 partial · ✅ matches.
> **Current state (verified 2026-07-18):** `ZB.MOM.WW.Audit` `0.1.0` is on the Gitea feed and
> **all four** apps reference it — **HistorianGateway is a fourth consumer** this file predates.
> Library suite: **23 tests**, green 2026-07-18.
>
> **✅ ADOPTED 2026-06-02 (local-only) — DEEP.** The backlog (#1#6) was implemented across all three apps on each repo's
> **`feat/adopt-zb-audit`** branch (stacked on `feat/adopt-zb-auth`) — committed + spec/code-reviewed, then **merged to
> each repo's local default (main/master) and PUSHED to origin (gitea) on 2026-06-03** (in sync). The user chose **DEEP adopt**:
+6
View File
@@ -3,6 +3,12 @@
Divergence of each project from [`spec/SPEC.md`](spec/SPEC.md), and the ordered backlog to
reach the shared `ZB.MOM.WW.Auth` library. Status legend: ⛔ gap · 🟡 partial · ✅ matches.
> **Current state (verified 2026-07-18):** feed carries `0.1.0``0.1.4`; consumer pins are
> OtOpcUa `0.1.1`, ScadaBridge `0.1.3`, MxAccessGateway `0.1.4`, **HistorianGateway `0.1.4`**
> (a fourth consumer this file predates, taking all four packages). OtOpcUa is three minors
> behind — it does not get the `0.1.4` API-key-expiry enforcement. Library suite: **215 passing,
> 1 skipped**, green 2026-07-18.
>
> **✅ ADOPTED 2026-06-02 (local-only).** The full backlog (#1#8) was implemented across all three apps on each repo's
> **`feat/adopt-zb-auth`** branch — committed + spec/code-reviewed, then **merged to each repo's local default
> (main/master) and PUSHED to origin (gitea) on 2026-06-03** (in sync; `feat/*` kept locally). Shared
+6 -3
View File
@@ -1,10 +1,13 @@
# Configuration validation — gaps & adoption backlog
Divergence of each project from [`spec/SPEC.md`](spec/SPEC.md), and the ordered backlog to adopt
the shared `ZB.MOM.WW.Configuration` library. The library is **BUILT @ 0.1.0** (42 tests) at
the shared `ZB.MOM.WW.Configuration` library. The library is **BUILT @ 0.1.0** (42 tests, re-run
green 2026-07-18) at
[`../../ZB.MOM.WW.Configuration/`](../../ZB.MOM.WW.Configuration/) and was **ADOPTED across all three
apps on 2026-06-01** — published to the Gitea feed, then consumed on each repo's local default branch
(merged, **not yet pushed** to remotes). The adoption items below are now largely closed: MxGateway +
apps on 2026-06-01** — published to the Gitea feed, then consumed on each repo's local default branch.
**Re-verified 2026-07-18:** `0.1.0` is on the feed and **all four** apps reference it (HistorianGateway
too, which this file predates) on their pushed default branches — the earlier "merged, **not yet pushed**
to remotes" caveat is stale and has been removed. The adoption items below are now largely closed: MxGateway +
ScadaBridge migrated to `OptionsValidatorBase`/`AddValidatedOptions` behaviour-preservingly (validator
messages byte-identical), ScadaBridge's `StartupValidator``ConfigPreflight`, and OtOpcUa gained
net-new `Ldap`/`OpcUa` validators (plus a follow-on pass: real `Security:Ldap` binding, `ValidateOnStart`
+14
View File
@@ -3,6 +3,20 @@
Divergence of each project from [`spec/SPEC.md`](spec/SPEC.md), and the ordered backlog to
reach the shared `ZB.MOM.WW.Health` library. Status legend: ⛔ gap · 🟡 partial · ✅ matches.
> **✅ ADOPTED — verified 2026-07-18.** This file previously carried no adoption banner and the
> root docs claimed the library was "**not yet adopted**". That was stale. Verified directly:
> `ZB.MOM.WW.Health` `0.1.0` is on the Gitea feed, and **all four apps reference it and wire
> `MapZbHealth`** — OtOpcUa (+ `.Akka` + `.EntityFrameworkCore`, uses `AkkaClusterHealthCheck`),
> MxAccessGateway (core only), ScadaBridge (all three packages; uses `AkkaClusterHealthCheck` +
> `IActiveNodeGate`), HistorianGateway (core; uses `GrpcDependencyHealthCheck`).
>
> **Caveat on the evidence:** this was verified by `PackageReference` + registration-call grep,
> which proves the library is wired in — *not* that every per-app probe below is registered or
> that the endpoint tiers match the spec. The divergence tables further down were written
> pre-adoption and have **not** been re-verified against current code; treat them as historical
> until someone re-walks them. They also predate HistorianGateway, which is absent from every
> table below.
## Divergence vs spec
### §1 Endpoint tiers
+13
View File
@@ -3,6 +3,19 @@
Divergence of each project from [`spec/SPEC.md`](spec/SPEC.md), and the ordered backlog to
reach the shared `ZB.MOM.WW.Telemetry` library. Status legend: ⛔ gap · 🟡 partial · ✅ matches.
> **✅ ADOPTED — verified 2026-07-18.** `ZB.MOM.WW.Telemetry` + `.Serilog` `0.1.0` are on the Gitea
> feed and **all four apps reference both and call `AddZbTelemetry`** (Resource + standard
> instrumentation + Prometheus `/metrics`). Logging: OtOpcUa, MxAccessGateway and **HistorianGateway**
> (a fourth consumer this file predates) use `AddZbSerilog`; ScadaBridge deliberately keeps its own
> `LoggerConfigurationFactory` for min-level governance and adds only the shared `TraceContextEnricher`
> — that split is by design, not a gap. Library suite: **34 tests**, green 2026-07-18.
>
> **The `⛔ not set` divergence tables below are the pre-adoption 2026-06-01 snapshot** — the §1
> Resource-attribute gaps they describe are what `AddZbTelemetry` closed. Read them as the
> historical case for the library, not as current state. Deferred items noted at the time
> (MxGateway `ms`→`s` + Meter rename, ScadaBridge app instruments + Site-node HTTP/1.1 metrics
> listener, OTLP wiring) were **not** re-verified in this pass.
## Divergence vs spec
### §1 OTel Resource / `service.name` (P1 — nobody has it)
+22
View File
@@ -5,6 +5,28 @@ The delta between each project's [`current-state`](current-state/) and the
reference-consumer-proven**; everything here is per-app adoption of an existing lib (not lib
construction).
## Current state (verified 2026-07-18)
- **Source is at `0.1.3`; the feed is at `0.1.2`.** `ZB.MOM.WW.Secrets/Directory.Build.props`
declares `<Version>0.1.3</Version>` and the G-8 KEK-rotation work (`KekRotationService`,
`RewrapReport`, `secret rewrap-all`, `docs/operations/kek-rotation.md`) is **committed and
pushed** on `main` (`d82d345`). The Gitea feed carries only `0.1.0``0.1.2` for all three
packages. **`0.1.3` is unpublished: no app can consume KEK rotation yet.** (An earlier note
claiming G-8 was "not yet committed/pushed" was stale — it is committed; only the *publish*
is outstanding.)
- **All four apps are pinned to `0.1.2`** — OtOpcUa, MxAccessGateway, ScadaBridge take
`Secrets` + `.Abstractions` + `.Ui`; HistorianGateway takes `Secrets` + `.Ui`.
- **G-7 clustered replication is designed + planned, not built** — plan at
`docs/plans/2026-07-17-secrets-g7-*` (resolved to build the shared SQL-Server `ISecretStore`;
Akka replicator deferred to phase 2). No `ISecretStore` SQL-Server implementation exists yet.
- Library suite: **97 passing, 1 skipped**, green 2026-07-18.
### Open
- ⬜ Publish `ZB.MOM.WW.Secrets` `0.1.3` (+ `.Abstractions`, `.Ui`) to the Gitea feed.
- ⬜ Execute the G-7 plan (shared SQL-Server `ISecretStore`).
- ⬜ Per-app live wonder gates for the G-8 rotation path.
## Execution status (2026-07-16)
- **mxaccessgw — G-4 + G-5 + G-6 DONE.** Executed via the plan below (8 tasks, subagent-driven,
+6
View File
@@ -3,6 +3,12 @@
Divergence of each project from [`spec/SPEC.md`](spec/SPEC.md), and the ordered backlog to
reach adoption of the `ZB.MOM.WW.Theme` shared RCL. Status legend: ⛔ gap · 🟡 partial · ✅ matches.
> **Current state (verified 2026-07-18):** the kit has moved on from the `0.2.0` this banner
> describes — the Gitea feed carries `0.2.0`, `0.2.1`, `0.3.0`, `0.3.1`, and **all four apps are
> pinned to `0.3.1`** (HistorianGateway is a fourth consumer this file predates). The `0.3.0`/`0.3.1`
> nav/aria/login fixes are recorded in `themeissues.md`, not here. Library suite: **48 bUnit tests**,
> green 2026-07-18. History below is accurate for the original cutover.
>
> **✅ ADOPTED 2026-06-03 (local-only).** Backlog #2#4 implemented across all three apps on each repo's
> **`feat/adopt-zb-theme`** branch — full canonical cutover (SPEC §7): `<ThemeHead/>`/`<ThemeScripts/>`,
> thin `MainLayout``<ThemeShell>` + `NavRailItem`/`NavRailSection`, per-app `theme.css`/IBM-Plex fonts/