diff --git a/docs/components/CLI.md b/docs/components/CLI.md index 68ed2808..a4de4d14 100644 --- a/docs/components/CLI.md +++ b/docs/components/CLI.md @@ -202,7 +202,7 @@ The management URL is resolved in this order: `--url` flag → `SCADABRIDGE_MANA ### No management URL -``` +```json {"error":"No management URL specified. Use --url, set SCADABRIDGE_MANAGEMENT_URL, or add 'managementUrl' to ~/.scadabridge/config.json.","code":"NO_URL"} ``` @@ -210,7 +210,7 @@ The URL is not set via `--url`, `SCADABRIDGE_MANAGEMENT_URL`, or the config file ### Connection failed -``` +```json {"error":"Connection failed: Connection refused (localhost:9000)","code":"CONNECTION_FAILED"} ``` @@ -222,7 +222,7 @@ The server returned HTTP 403 or an error code of `FORBIDDEN`/`UNAUTHORIZED`. The ### Malformed config file warning -``` +```text warning: ignoring malformed or unreadable /home/user/.scadabridge/config.json: ... ``` @@ -230,7 +230,7 @@ warning: ignoring malformed or unreadable /home/user/.scadabridge/config.json: . ### `audit-log` deprecation warning -``` +```text Warning: 'audit-log' is deprecated and will be removed in a future release. Use 'audit-config' instead. ``` diff --git a/docs/components/CentralUI.md b/docs/components/CentralUI.md index e076170c..a34b3780 100644 --- a/docs/components/CentralUI.md +++ b/docs/components/CentralUI.md @@ -176,7 +176,7 @@ The same keys are accepted by `GET /api/centralui/audit/export` for filtered CSV - [Configuration Database (#17)](./ConfigurationDatabase.md) — all central CRUD (templates, instances, sites, external systems, notifications, audit log, etc.) via scoped EF Core repositories (`ICentralUiRepository`, `IAuditLogRepository`, `ISiteRepository`, `ITemplateEngineRepository`, and others). The Data Protection keys that make sessions portable across failover are also stored here. - [Communication (#5)](./Communication.md) — `CommunicationService` for cross-site commands (deploy, disable, enable, delete, browse OPC UA nodes, read tag values); `DebugStreamService` for gRPC-backed debug stream sessions; KPI request/response messages for Notification Outbox and Site Calls KPIs. - [Deployment Manager (#2)](./DeploymentManager.md) — `IDeploymentStatusNotifier` for real-time deployment status push; deployment command routing. -- [Template Engine (#1)](./TemplateEngine.md) — `TemplateService`, `TemplateFolderService`, `TemplateValidationService` for template authoring, on-demand validation, and diff calculation. +- [Template Engine (#1)](./TemplateEngine.md) — `TemplateService`, `TemplateFolderService`, `ValidationService` for template authoring, on-demand validation, and diff calculation. - [Health Monitoring (#11)](./HealthMonitoring.md) — `ICentralHealthAggregator` for in-memory site health state on the Health Dashboard and audit backlog KPI tile. - [Audit Log (#23)](./AuditLog.md) — `IAuditLogRepository` (via `AuditLogQueryService`) for the Audit Log page query/drilldown/export; `IAuditLogQueryService.GetKpiSnapshotAsync` for the three Audit KPI tiles on the Health Dashboard. - [Notification Outbox (#21)](./NotificationOutbox.md) — Notification Report page queries and Retry/Discard actions; Notification KPI tiles on the Health Dashboard. diff --git a/docs/components/ClusterInfrastructure.md b/docs/components/ClusterInfrastructure.md index fc323300..c554e094 100644 --- a/docs/components/ClusterInfrastructure.md +++ b/docs/components/ClusterInfrastructure.md @@ -256,7 +256,7 @@ This returns `false` while the actor system is warming up — the safe-by-defaul - [Site Runtime (#3)](./SiteRuntime.md) — the Deployment Manager singleton is the most operationally critical singleton this infrastructure hosts. It re-creates the full Instance Actor hierarchy from local SQLite on failover. Staggered Instance Actor startup after failover is Site Runtime's responsibility; this component provides the singleton placement guarantee. - [Notification Outbox (#21)](./NotificationOutbox.md), [Site Call Audit (#22)](./SiteCallAudit.md), [Audit Log (#23)](./AuditLog.md) — each hosts one or more central singletons wired by `RegisterCentralActors`. Cluster Infrastructure provides the `ClusterSingletonManager`/`ClusterSingletonProxy` boilerplate and the graceful-shutdown hooks; the business logic lives in the owning component. - [Central–Site Communication (#5)](./Communication.md) — `CentralCommunicationActor` and `SiteCommunicationActor` are created and registered with `ClusterClientReceptionist` inside the same `AkkaHostedService` startup, making them addressable by remote `ClusterClient` instances. The transport-level heartbeat (`TransportHeartbeatInterval`, `TransportFailureThreshold`) is configured separately from the cluster failure-detector and comes from `CommunicationOptions`. -- [Inbound API (#14)](./InboundApi.md) — resolves `IActiveNodeGate` to return HTTP 503 on standby central nodes. Gate returns `false` until the actor system is `Up` and this node is the cluster leader. +- [Inbound API (#14)](./InboundAPI.md) — resolves `IActiveNodeGate` to return HTTP 503 on standby central nodes. Gate returns `false` until the actor system is `Up` and this node is the cluster leader. - Design spec: [Component-ClusterInfrastructure.md](../requirements/Component-ClusterInfrastructure.md). ## Troubleshooting diff --git a/docs/components/Commons.md b/docs/components/Commons.md index 16ba984e..dd1e3559 100644 --- a/docs/components/Commons.md +++ b/docs/components/Commons.md @@ -56,7 +56,7 @@ Commons may contain stateless, side-effect-free helper types that transform or v ### Namespace and folder structure -``` +```text ZB.MOM.WW.ScadaBridge.Commons/ ├── Types/ # Enums/, Alarms/, Audit/, DataConnections/, │ # Flattening/, InboundApi/, Notifications/, diff --git a/docs/components/Communication.md b/docs/components/Communication.md index fecc190d..4436cc37 100644 --- a/docs/components/Communication.md +++ b/docs/components/Communication.md @@ -259,7 +259,7 @@ After a site node failover, the `DebugStreamBridgeActor` attempts to reconnect t ### Heartbeats arrive but health reports do not -`SiteCommunicationActor` sends heartbeats and health reports via separate paths. Health reports are sent only when the site's `SiteHealthReportActor` publishes them (every 30 s by default). If heartbeats arrive but reports do not, the health reporting actor on the site may have faulted — check site-side logs for errors in `SiteHealthReportActor`. +`SiteCommunicationActor` sends heartbeats and health reports via separate paths. Health reports are sent only when the site's `HealthReportSender` publishes them (every 30 s by default). If heartbeats arrive but reports do not, the health-report sender on the site may have faulted — check site-side logs for errors in `HealthReportSender`. ## Related Documentation diff --git a/docs/components/ConfigurationDatabase.md b/docs/components/ConfigurationDatabase.md index 36792c50..84603a39 100644 --- a/docs/components/ConfigurationDatabase.md +++ b/docs/components/ConfigurationDatabase.md @@ -212,16 +212,16 @@ The `SCADABRIDGE_DESIGNTIME_CONNECTIONSTRING` environment variable is an alterna - [Commons (#16)](./Commons.md) — all POCO entity classes (`Templates`, `Instances`, `Sites`, `AuditLogEntry`, `SiteCall`, …) and all repository interfaces (`ITemplateEngineRepository`, `IDeploymentManagerRepository`, `ISecurityRepository`, `IInboundApiRepository`, `IExternalSystemRepository`, `INotificationRepository`, `INotificationOutboxRepository`, `ISiteCallAuditRepository`, `IAuditLogRepository`, `ICentralUiRepository`) live there. Commons also declares `IAuditService`, `IAuditCorrelationContext`, `IPartitionMaintenance`, and `IInstanceLocator` — all implemented here. - [Audit Log (#23)](./AuditLog.md) — `IAuditLogRepository` (implemented by `AuditLogRepository`) is the sole central write path for `dbo.AuditLog`. `AuditLogIngestActor`, `CentralAuditWriter`, and `SiteAuditReconciliationActor` all resolve it from a fresh per-message DI scope; the Audit Log component hosts the `AuditLogPartitionMaintenanceService` and `AuditLogPurgeActor` that drive the `IPartitionMaintenance` implementation registered here. -- [Template Engine (#1)](./Commons.md) — consumes `ITemplateEngineRepository` for all template, attribute, alarm, native alarm source, script, composition, instance, override, connection binding, and area operations. -- [Deployment Manager (#2)](./Commons.md) — consumes `IDeploymentManagerRepository` for deployment records and configuration snapshots. -- [Security & Auth (#10)](./Commons.md) — consumes `ISecurityRepository` for LDAP group mappings and site scoping rules. -- [Inbound API (#14)](./Commons.md) — consumes `IInboundApiRepository` for API method definitions. -- [External System Gateway (#7)](./Commons.md) — consumes `IExternalSystemRepository` for external system and database connection definitions. -- [Notification Service (#8)](./Commons.md) — consumes `INotificationRepository` for notification lists, recipients, and SMTP configuration. +- [Template Engine (#1)](./TemplateEngine.md) — consumes `ITemplateEngineRepository` for all template, attribute, alarm, native alarm source, script, composition, instance, override, connection binding, and area operations. +- [Deployment Manager (#2)](./DeploymentManager.md) — consumes `IDeploymentManagerRepository` for deployment records and configuration snapshots. +- [Security & Auth (#10)](./Security.md) — consumes `ISecurityRepository` for LDAP group mappings and site scoping rules. +- [Inbound API (#14)](./InboundAPI.md) — consumes `IInboundApiRepository` for API method definitions. +- [External System Gateway (#7)](./ExternalSystemGateway.md) — consumes `IExternalSystemRepository` for external system and database connection definitions. +- [Notification Service (#8)](./NotificationService.md) — consumes `INotificationRepository` for notification lists, recipients, and SMTP configuration. - [Notification Outbox (#21)](./NotificationOutbox.md) — consumes `INotificationOutboxRepository` for `dbo.Notifications` ingest, dispatcher polling, status transitions, KPI queries, and bulk purge of terminal rows. - [Site Call Audit (#22)](./SiteCallAudit.md) — consumes `ISiteCallAuditRepository` for `dbo.SiteCalls` ingest, KPI queries, and bulk purge of terminal rows. -- [Central UI (#9)](./Commons.md) — consumes `ICentralUiRepository` for read-oriented cross-domain queries and the configuration audit log viewer. -- [Host (#15)](./Commons.md) — provides the connection string, calls `AddConfigurationDatabase`, and invokes `MigrationHelper.ApplyOrValidateMigrationsAsync` at startup. +- [Central UI (#9)](./CentralUI.md) — consumes `ICentralUiRepository` for read-oriented cross-domain queries and the configuration audit log viewer. +- [Host (#15)](./Host.md) — provides the connection string, calls `AddConfigurationDatabase`, and invokes `MigrationHelper.ApplyOrValidateMigrationsAsync` at startup. - All central components that modify configuration state — call `IAuditService.LogAsync()` and then `SaveChangesAsync()` so audit entries commit atomically with entity changes. - Design spec: [Component-ConfigurationDatabase.md](../requirements/Component-ConfigurationDatabase.md) diff --git a/docs/components/DataConnectionLayer.md b/docs/components/DataConnectionLayer.md index 2a4f2dd2..2a3d2447 100644 --- a/docs/components/DataConnectionLayer.md +++ b/docs/components/DataConnectionLayer.md @@ -45,7 +45,7 @@ Adding a new protocol requires implementing `IDataConnection` (and optionally `I ### Actor hierarchy -``` +```text DataConnectionManagerActor (one per site; child of DeploymentManagerActor) ├── DataConnectionActor "OpcSrv1" (one per configured connection) ├── DataConnectionActor "Gateway2" diff --git a/docs/components/HealthMonitoring.md b/docs/components/HealthMonitoring.md index c7f78f33..4852c64e 100644 --- a/docs/components/HealthMonitoring.md +++ b/docs/components/HealthMonitoring.md @@ -151,7 +151,7 @@ The offline-check cadence is derived at runtime as `min(OfflineTimeout, CentralO - [Store-and-Forward Engine (#6)](./StoreAndForward.md) — `HealthReportSender` queries `StoreAndForwardStorage` for `GetParkedMessageCountAsync` and `GetBufferDepthByCategoryAsync`; the results populate `ParkedMessageCount` and `StoreAndForwardBufferDepths` (keyed by `StoreAndForwardCategory` name). - [Cluster Infrastructure (#13)](./ClusterInfrastructure.md) — `IClusterNodeProvider` supplies cluster node list and `SelfIsPrimary` flag to both `HealthReportSender` and `CentralHealthReportLoop`. Heartbeat cadence (default 5 s) is owned by Cluster Infrastructure / `SiteCommunicationActor`. - [Audit Log (#23)](./AuditLog.md) — `AddAuditLogHealthMetricsBridge` wires `HealthMetricsAuditWriteFailureCounter` and `HealthMetricsAuditRedactionFailureCounter` into the site collector, and registers `SiteAuditBacklogReporter` to poll the site-local SQLite drain backlog. On central, `AuditCentralHealthSnapshot` exposes `CentralAuditWriteFailures`, `AuditRedactionFailure`, and per-site `SiteAuditTelemetryStalled` alongside the aggregated site states on the health dashboard. -- [Central UI (#9)](./Host.md) — the health dashboard resolves `ICentralHealthAggregator` and polls `GetAllSiteStates()` on a ~10 s timer. Notification Outbox and Site Call Audit KPIs are computed on demand from their own central tables by those components; Health Monitoring does not own or cache them. +- [Central UI (#9)](./CentralUI.md) — the health dashboard resolves `ICentralHealthAggregator` and polls `GetAllSiteStates()` on a ~10 s timer. Notification Outbox and Site Call Audit KPIs are computed on demand from their own central tables by those components; Health Monitoring does not own or cache them. - [Host (#15)](./Host.md) — implements `ISiteIdentityProvider` (supplies `SiteId` for report payloads) and `IClusterNodeProvider`, and calls the appropriate `Add*` entry points from the role-specific composition root. ## Troubleshooting diff --git a/docs/components/InboundAPI.md b/docs/components/InboundAPI.md index 19eea6c7..db0b0845 100644 --- a/docs/components/InboundAPI.md +++ b/docs/components/InboundAPI.md @@ -63,7 +63,7 @@ Parameter and return field definitions share the same six-type vocabulary: ### Request pipeline -``` +```text POST /api/{methodName} │ ├─ AuditWriteMiddleware ← mints ExecutionId; buffers bodies; emits audit row in finally @@ -241,7 +241,7 @@ The inbound body-capture cap for audit is configured separately under `AuditLog: - [Commons (#16)](./Commons.md) — owns `ApiMethod`, `ParameterDefinition`, `ScriptParameters`, `ScriptParameterException`, the `RouteToCall*` / `RouteToGetAttributes*` / `RouteToSetAttributes*` message records, `IInboundApiRepository`, and `IInstanceLocator`. Also owns `ICentralAuditWriter` (via `ZB.MOM.WW.Audit`), `AuditChannel`, `AuditKind`, `AuditStatus`, and `ScadaBridgeAuditEventFactory`. - [Configuration Database (#17)](./ConfigurationDatabase.md) — provides the `IInboundApiRepository` implementation (`GetMethodByNameAsync`, `GetAllApiMethodsAsync`, CRUD). Method definitions persist in the central MS SQL configuration database. -- [Central–Site Communication (#5)](./Communication.md) — `CommunicationServiceInstanceRouter` delegates every `Route.To()` operation to `CommunicationService`. The routed call travels from the central `CommunicationActor` to the target site via `ClusterClient`, reaches the target `InstanceActor`, and a `ScriptExecutionActor` executes the named script. The return value flows back synchronously. +- [Central–Site Communication (#5)](./Communication.md) — `CommunicationServiceInstanceRouter` delegates every `Route.To()` operation to `CommunicationService`. The routed call travels from the central `CentralCommunicationActor` to the target site via `ClusterClient`, reaches the target `InstanceActor`, and a `ScriptExecutionActor` executes the named script. The return value flows back synchronously. - [Audit Log (#23)](./AuditLog.md) — `AuditWriteMiddleware` resolves `ICentralAuditWriter` to emit the `ApiInbound` row via the central direct-write path. The inbound request is the parent execution for any site script it spawns: the middleware's `ExecutionId` becomes `RouteToCallRequest.ParentExecutionId` on every routed `Call`. Cross-link: `AuditWriteMiddleware.InboundExecutionIdItemKey` / `AuditWriteMiddleware.AuditActorItemKey` are the `HttpContext.Items` keys that tie the endpoint handler and middleware together. - [Security (#10)](./Security.md) — API key verification (`IApiKeyVerifier`, `AddZbApiKeyAuth`) is registered by the Host. The inbound API uses a dedicated key scheme independent of LDAP/AD session auth. - [Cluster Infrastructure (#13)](./ClusterInfrastructure.md) — `IActiveNodeGate` (interface in this project; implementation in the Host) gates the endpoint to the active central node. A standby returns `503` without running any script logic. diff --git a/docs/components/ManagementService.md b/docs/components/ManagementService.md index 8e8ca1bb..83769615 100644 --- a/docs/components/ManagementService.md +++ b/docs/components/ManagementService.md @@ -141,7 +141,7 @@ Both endpoints apply the same HTTP Basic Auth / LDAP / role flow as `/management The CLI sends a single `POST /management` with JSON body and Basic Auth; it does not use `ClusterClient` directly. A typical request: -``` +```http POST /management Authorization: Basic base64(username:password) Content-Type: application/json @@ -178,7 +178,7 @@ The `ManagementActor` is also reachable from any `ClusterClient` that has a cont | Security | `ListRoleMappings`, `CreateRoleMapping`, `UpdateRoleMapping`, `DeleteRoleMapping`, `ListApiKeys`, `CreateApiKey`, `UpdateApiKey`, `DeleteApiKey`, `SetApiKeyMethods`, `ListScopeRules`, `AddScopeRule`, `DeleteScopeRule` | Administrator | | Deployments | `MgmtDeployArtifacts`, `QueryDeployments`, `GetDeploymentDiff` | Deployer | | Health | `GetHealthSummary`, `GetSiteHealth` | Any authenticated user | -| Remote queries | `QueryEventLogs`, `QueryParkedMessages`, `RetryParkedMessage`, `DiscardParkedMessage`, `DebugSnapshot` | Deployer | +| Remote queries | `QueryEventLogsCommand`, `QueryParkedMessagesCommand`, `RetryParkedMessageCommand`, `DiscardParkedMessageCommand`, `DebugSnapshotCommand` | Deployer | | Audit (legacy) | `QueryAuditLog` | Administrator | | Transport | `ExportBundle` (Designer), `PreviewBundle`, `ImportBundle` (Administrator) | Varies | @@ -200,7 +200,7 @@ The 200 MB per-request body cap (`ManagementEndpoints.MaxManagementRequestBodyBy - [Configuration Database (#17)](./ConfigurationDatabase.md) — every repository (`ITemplateEngineRepository`, `ISiteRepository`, `IExternalSystemRepository`, `INotificationRepository`, `ISecurityRepository`, `IInboundApiRepository`, `IDeploymentManagerRepository`, `ICentralUiRepository`) and `IAuditService` are backed by EF Core against the central MS SQL database. Management Service resolves them per-command through scoped DI. - [Template Engine (#1)](./TemplateEngine.md) — `TemplateService`, `TemplateFolderService`, `SharedScriptService`, and the `ValidationService` handle template authoring and validation. Management Service is the sole entry point for template mutations from outside the Central UI. - [Deployment Manager (#2)](./DeploymentManager.md) — `DeploymentService` and `ArtifactDeploymentService` own the deployment pipeline. `MgmtDeployInstance` and `MgmtDeployArtifacts` delegate here. -- [Central–Site Communication (#5)](./Communication.md) — `CommunicationService` routes `QueryEventLogs`, `QueryParkedMessages`, `RetryParkedMessage`, `DiscardParkedMessage`, and `DebugSnapshot` to site actors via `ClusterClient`. Deployment commands also flow through the communication layer. +- [Central–Site Communication (#5)](./Communication.md) — `CommunicationService` routes `QueryEventLogsCommand`, `QueryParkedMessagesCommand`, `RetryParkedMessageCommand`, `DiscardParkedMessageCommand`, and `DebugSnapshotCommand` to site actors via `ClusterClient`. Deployment commands also flow through the communication layer. - [Security & Auth (#10)](./Security.md) — `ILdapAuthService` and `RoleMapper` authenticate and map roles on every HTTP request; the `Roles` constants and `IInboundApiKeyAdmin` are also consumed here. - [Health Monitoring (#11)](./HealthMonitoring.md) — `ICentralHealthAggregator` answers `GetHealthSummary` and `GetSiteHealth` queries synchronously from its in-memory state. - [Audit Log (#23)](./AuditLog.md) — `AuditEndpoints` reads the central `AuditLog` table via `IAuditLogRepository` directly (no actor hop). `QueryAuditLogCommand` through `/management` is a legacy path for the configuration-change audit via `ICentralUiRepository`. diff --git a/docs/components/NotificationOutbox.md b/docs/components/NotificationOutbox.md index 21150628..170ac270 100644 --- a/docs/components/NotificationOutbox.md +++ b/docs/components/NotificationOutbox.md @@ -220,12 +220,12 @@ Delivery retry policy (`MaxRetries`, `RetryDelay`) is read at runtime from `Smtp - [Commons (#16)](./Commons.md) — owns `Notification`, `NotificationStatus`, `NotificationType`, `INotificationOutboxRepository`, `INotificationRepository`, and all message contracts (`NotificationSubmit`, `NotificationSubmitAck`, `NotificationStatusQuery`, `NotificationKpiRequest`, and their responses). Also owns `ScadaBridgeAuditEventFactory` and the `AuditChannel`/`AuditKind`/`AuditStatus` enums used to build dispatch audit rows. - [Configuration Database (#17)](./ConfigurationDatabase.md) — registers the scoped `INotificationOutboxRepository` (the central `dbo.Notifications` table) and `INotificationRepository` (notification-list, recipient, and SMTP configuration tables). Central hosts must call `AddConfigurationDatabase` before `AddNotificationOutbox`. -- [Notification Service (#8)](./StoreAndForward.md) — supplies `ISmtpClientWrapper`, `OAuth2TokenService`, `NotificationOptions`, `SmtpTlsModeParser`, `SmtpErrorClassifier`, and the `SmtpPermanentException` type. `AddNotificationOutbox` relies on `AddNotificationService` being called by the Host to register these shared SMTP primitives; registering them twice would duplicate them. +- [Notification Service (#8)](./NotificationService.md) — supplies `ISmtpClientWrapper`, `OAuth2TokenService`, `NotificationOptions`, `SmtpTlsModeParser`, `SmtpErrorClassifier`, and the `SmtpPermanentException` type. `AddNotificationOutbox` relies on `AddNotificationService` being called by the Host to register these shared SMTP primitives; registering them twice would duplicate them. - [Central–Site Communication (#5)](./Communication.md) — carries `NotificationSubmit` / `NotificationSubmitAck` between sites and central via ClusterClient, and `NotificationStatusQuery` / `NotificationStatusResponse` for the `Notify.Status` round-trip. - [Store-and-Forward Engine (#6)](./StoreAndForward.md) — the site-side component that durably buffers notifications in SQLite and retries forwarding until central acks. The outbox is the receiving end of the S&F handoff. - [Audit Log (#23)](./AuditLog.md) — the outbox is a central direct-write caller of `ICentralAuditWriter`. It emits `NotifyDeliver` rows (Attempted + terminal) per delivery attempt and per operator Discard. The upstream `NotifySend` row is emitted by the site and arrives at central via standard audit telemetry. -- [Health Monitoring (#11)](./Host.md) — polls `NotificationKpiRequest` / `PerSiteNotificationKpiRequest` for the headline KPI tiles on the health dashboard (queue depth, stuck count, parked count). These are central-computed from the `Notifications` table and are separate from the site S&F backlog metric. -- [Central UI (#9)](./Host.md) — hosts the Notification Outbox page: KPI tiles, a queryable/filterable notification list, per-row Retry/Discard actions on parked notifications, and a stuck-row badge. +- [Health Monitoring (#11)](./HealthMonitoring.md) — polls `NotificationKpiRequest` / `PerSiteNotificationKpiRequest` for the headline KPI tiles on the health dashboard (queue depth, stuck count, parked count). These are central-computed from the `Notifications` table and are separate from the site S&F backlog metric. +- [Central UI (#9)](./CentralUI.md) — hosts the Notification Outbox page: KPI tiles, a queryable/filterable notification list, per-row Retry/Discard actions on parked notifications, and a stuck-row badge. ## Troubleshooting @@ -257,4 +257,4 @@ A central failover while a delivery attempt is in flight leaves the row in its p - [Configuration Database](./ConfigurationDatabase.md) - [Central–Site Communication](./Communication.md) - [Store-and-Forward Engine](./StoreAndForward.md) -- [Health Monitoring](./Host.md) +- [Health Monitoring](./HealthMonitoring.md) diff --git a/docs/components/SiteCallAudit.md b/docs/components/SiteCallAudit.md index bd818f32..403a1ceb 100644 --- a/docs/components/SiteCallAudit.md +++ b/docs/components/SiteCallAudit.md @@ -20,7 +20,7 @@ The Notification Outbox (#21) ingests notifications and dispatches them centrall The `SiteCalls` table holds one row per `TrackedOperationId`. `ISiteCallAuditRepository.UpsertAsync` implements insert-if-not-exists followed by a conditional update that only applies when the incoming status has a strictly higher rank than the stored status: -``` +```text Submitted=0, Forwarded=1, Attempted=2, Skipped=2, Delivered=3, Failed=3, Parked=3, Discarded=3 ``` @@ -119,7 +119,7 @@ Unlike the `AuditLog` table, `SiteCalls` is a standard non-partitioned table on ### Status lifecycle -``` +```text Submitted → Forwarded → Attempted ──→ Delivered (terminal, success) └──→ Parked (non-terminal, awaiting operator action) └──→ Failed (terminal, permanent failure) @@ -221,7 +221,7 @@ Registration is via `ServiceCollectionExtensions.AddSiteCallAudit`, which binds - [Central–Site Communication (#5)](./Communication.md) — the `CentralCommunicationActor` is the transport the relay handlers use. It is registered via `RegisterCentralCommunication` by the Host after both actors are running. `CommunicationService` also provides the async wrappers (`RetrySiteCallAsync`, `DiscardSiteCallAsync`) that the Central UI calls; those methods Ask the `SiteCallAuditActor` with the outer `CommunicationOptions.QueryTimeout`. - [Store-and-Forward Engine (#6)](./StoreAndForward.md) — site-side executor of `RetryParkedOperation` and `DiscardParkedOperation`. The site's S&F buffer is the source of truth for parked cached calls; it emits updated telemetry after applying an operator action. - [Health Monitoring (#11)](./HealthMonitoring.md) — consumes `SiteCallKpiResponse` / `PerSiteSiteCallKpiResponse` to surface buffered count, parked count, stuck count, and throughput KPI tiles on the health dashboard alongside the Notification Outbox tiles. -- [Central UI (#9)](./Host.md) — the Site Calls page queries this actor for the paginated list, detail modal, and KPIs; it issues Retry/Discard actions that flow through `CommunicationService` to the relay handlers here. +- [Central UI (#9)](./CentralUI.md) — the Site Calls page queries this actor for the paginated list, detail modal, and KPIs; it issues Retry/Discard actions that flow through `CommunicationService` to the relay handlers here. - [Cluster Infrastructure (#13)](./ClusterInfrastructure.md) — hosts the `SiteCallAuditActor` singleton with active/standby failover via `ClusterSingletonManager`. ## Troubleshooting diff --git a/docs/components/SiteRuntime.md b/docs/components/SiteRuntime.md index 593b2174..206ec922 100644 --- a/docs/components/SiteRuntime.md +++ b/docs/components/SiteRuntime.md @@ -58,7 +58,7 @@ All in-memory state mutations (attribute values, qualities, alarm states) run in ### Actor hierarchy -``` +```text DeploymentManagerActor (Akka.NET cluster singleton) └── InstanceActor "MachineA-001" ├── ScriptActor "MonitorSpeed" (coordinator) diff --git a/docs/components/TemplateEngine.md b/docs/components/TemplateEngine.md index 919e96a5..89eafcc5 100644 --- a/docs/components/TemplateEngine.md +++ b/docs/components/TemplateEngine.md @@ -112,7 +112,7 @@ Template edits use **last-write-wins** — there is no optimistic concurrency to ### Service map -``` +```text AddTemplateEngine() ├── TemplateService (scoped) — template + member CRUD, collision/acyclicity pre-checks ├── SharedScriptService (scoped) — system-wide shared script CRUD + syntax validation diff --git a/docs/components/TraefikProxy.md b/docs/components/TraefikProxy.md index 52adb9cf..d635a80e 100644 --- a/docs/components/TraefikProxy.md +++ b/docs/components/TraefikProxy.md @@ -4,7 +4,7 @@ The Traefik Proxy is the reverse proxy and load balancer that fronts the central ## Overview -The proxy runs as the `scadabridge-traefik` Docker container in the main compose stack (`docker/docker-compose.yml`). It is a third-party infrastructure component (Traefik v3.4) — there is no C# project for it. Its entire configuration is two YAML files mounted read-only into the container: +The proxy runs as the `scadabridge-traefik` Docker container in the main compose stack (`docker/docker-compose.yml`). It is a third-party infrastructure component (Traefik; the image tag is pinned in `docker/docker-compose.yml`) — there is no C# project for it. Its entire configuration is two YAML files mounted read-only into the container: - `docker/traefik/traefik.yml` — static config: entrypoints, API dashboard, and file provider declaration. - `docker/traefik/dynamic.yml` — routing rules: the router that catches all traffic, the `central` load-balancer service listing both backend nodes, and the `/health/active` health-check settings. @@ -47,13 +47,13 @@ When the active central node goes down, the Akka cluster's keep-oldest split-bra ### Docker topology -``` +```text Clients (CLI, browser, external API) │ host:9000 (HTTP) │ ┌───────▼──────────────────┐ - │ scadabridge-traefik │ (Traefik v3.4 container) + │ scadabridge-traefik │ (Traefik container) │ entrypoint :80 │ └──────┬──────────┬─────────┘ │ /health/active poll (5s) diff --git a/docs/components/Transport.md b/docs/components/Transport.md index 088f7a91..f9605016 100644 --- a/docs/components/Transport.md +++ b/docs/components/Transport.md @@ -18,7 +18,7 @@ The single DI entry point is `ServiceCollectionExtensions.AddTransport`, registe A `.scadabundle` file is a ZIP archive with exactly two entries: -``` +```text bundle.scadabundle ├── manifest.json # always plaintext; never encrypted └── content.json # plaintext artifact data (no passphrase)