Add Management Service and CLI components (design docs)

New components 18-19: ManagementService (Akka.NET actor on Central exposing
all admin operations via ClusterClientReceptionist) and CLI (console app using
ClusterClient for scripting). Updated HighLevelReqs, CLAUDE.md, README,
Component-Host, Component-Communication, Component-Security.
This commit is contained in:
Joseph Doherty
2026-03-17 14:28:02 -04:00
parent 7dcdcc46c7
commit 50dad61e72
8 changed files with 410 additions and 6 deletions

View File

@@ -36,7 +36,7 @@ There is no source code in this project — only design documentation in markdow
- Use `git diff` to review changes before committing.
- Commit related changes together with a descriptive message summarizing the design decision.
## Current Component List (17 components)
## Current Component List (19 components)
1. Template Engine — Template modeling, inheritance, composition, validation, flattening, diffs.
2. Deployment Manager — Central-side deployment pipeline, system-wide artifact deployment, instance lifecycle.
@@ -55,6 +55,8 @@ There is no source code in this project — only design documentation in markdow
15. Host — Single deployable binary, role-based component registration, Akka.NET bootstrap.
16. Commons — Shared types, POCO entity classes, repository interfaces, message contracts.
17. Configuration Database — EF Core data access layer, repositories, unit-of-work, audit logging (IAuditService), migrations.
18. Management Service — Akka.NET actor providing programmatic access to all admin operations, ClusterClientReceptionist registration.
19. CLI — Command-line tool using ClusterClient to interact with Management Service, System.CommandLine, JSON/table output.
## Key Design Decisions (for context across sessions)

215
Component-CLI.md Normal file
View File

@@ -0,0 +1,215 @@
# Component: CLI
## Purpose
The CLI is a standalone command-line tool for scripting and automating administrative operations against the ScadaLink central cluster. It connects to the ManagementActor via Akka.NET ClusterClient — it does not join the cluster as a full member and does not use HTTP/REST. The CLI provides the same administrative capabilities as the Central UI, enabling automation, batch operations, and integration with CI/CD pipelines.
## Location
Standalone executable, not part of the Host binary. Deployed on any Windows machine with network access to the central cluster.
`src/ScadaLink.CLI/`
## Responsibilities
- Parse command-line arguments and dispatch to the appropriate management operation.
- Authenticate the user via LDAP credentials and include identity in every message sent to the ManagementActor.
- Connect to the central cluster via Akka.NET ClusterClient using configured contact points.
- Send management messages to the ManagementActor and display structured responses.
- Support both JSON and human-readable table output formats.
## Technology
- **Argument parsing**: `System.CommandLine` library for command/subcommand/option parsing with built-in help generation.
- **Transport**: Akka.NET `ClusterClient` connecting to `ClusterClientReceptionist` on the central cluster. The CLI does not join the cluster — it is a lightweight external client.
- **Serialization**: Message contracts from Commons (`Messages/Management/`), same as ManagementActor expects.
## Authentication
The CLI authenticates the user against LDAP/AD before any operation:
1. The user provides credentials via `--username` / `--password` options, or is prompted interactively if omitted.
2. The CLI performs a direct LDAP bind against the configured LDAP server (same mechanism as the Central UI login).
3. On successful bind, the CLI queries group memberships to determine roles and permitted sites.
4. Every message sent to the ManagementActor includes the `AuthenticatedUser` envelope with the user's identity, roles, and site permissions.
5. Credentials are not stored or cached between invocations. Each CLI invocation requires fresh authentication.
LDAP connection settings are read from the CLI configuration (see Configuration section).
## Connection
The CLI uses Akka.NET ClusterClient to connect to the central cluster:
- **Contact points**: One or more seed node addresses for the ClusterClientReceptionist. The CLI sends an initial contact to these addresses; the receptionist responds with the current set of cluster nodes hosting the ManagementActor.
- **No cluster membership**: The CLI does not join the Akka.NET cluster. It is an external process that communicates via the ClusterClient protocol.
- **Failover**: If the active central node fails over, ClusterClient transparently reconnects to the new active node via the receptionist. In-flight commands may time out and need to be retried.
## Command Structure
The CLI uses a hierarchical subcommand structure mirroring the Management Service message groups:
```
scadalink <group> <action> [options]
```
### Template Commands
```
scadalink template list [--format json|table]
scadalink template get <name> [--format json|table]
scadalink template create --name <name> [--parent <parent>] --file <path>
scadalink template update <name> --file <path>
scadalink template delete <name>
scadalink template validate <name>
scadalink template diff <instance-code>
```
### Instance Commands
```
scadalink instance list [--site <site>] [--area <area>] [--format json|table]
scadalink instance get <code> [--format json|table]
scadalink instance create --template <name> --site <site> --code <code> [--area <area>]
scadalink instance set-overrides <code> --file <path>
scadalink instance bind-connections <code> --file <path>
scadalink instance assign-area <code> --area <area>
scadalink instance enable <code>
scadalink instance disable <code>
scadalink instance delete <code>
```
### Site Commands
```
scadalink site list [--format json|table]
scadalink site get <site-id> [--format json|table]
scadalink site create --name <name> --id <site-id>
scadalink site update <site-id> --file <path>
scadalink site delete <site-id>
scadalink site area list <site-id>
scadalink site area create <site-id> --name <name> [--parent <parent-area>]
scadalink site area delete <site-id> --name <name>
```
### Deployment Commands
```
scadalink deploy instance <code>
scadalink deploy artifacts [--site <site>] [--type <artifact-type>]
scadalink deploy status [--format json|table]
```
### Data Connection Commands
```
scadalink data-connection list [--format json|table]
scadalink data-connection get <name> [--format json|table]
scadalink data-connection create --file <path>
scadalink data-connection update <name> --file <path>
scadalink data-connection delete <name>
scadalink data-connection assign <name> --site <site-id>
scadalink data-connection unassign <name> --site <site-id>
```
### External System Commands
```
scadalink external-system list [--format json|table]
scadalink external-system get <name> [--format json|table]
scadalink external-system create --file <path>
scadalink external-system update <name> --file <path>
scadalink external-system delete <name>
```
### Notification Commands
```
scadalink notification list [--format json|table]
scadalink notification get <name> [--format json|table]
scadalink notification create --file <path>
scadalink notification update <name> --file <path>
scadalink notification delete <name>
scadalink notification smtp get [--format json|table]
scadalink notification smtp update --file <path>
```
### Security Commands
```
scadalink security api-key list [--format json|table]
scadalink security api-key create --name <name>
scadalink security api-key enable <name>
scadalink security api-key disable <name>
scadalink security api-key delete <name>
scadalink security role-mapping list [--format json|table]
scadalink security role-mapping create --group <ldap-group> --role <role> [--site <site>]
scadalink security role-mapping delete --group <ldap-group> --role <role>
```
### Audit Log Commands
```
scadalink audit-log query [--user <username>] [--entity-type <type>] [--from <date>] [--to <date>] [--format json|table]
```
### Health Commands
```
scadalink health summary [--format json|table]
scadalink health site <site-id> [--format json|table]
```
## Configuration
Configuration is resolved in the following priority order (highest wins):
1. **Command-line options**: `--contact-points`, `--username`, `--password`, `--format`.
2. **Environment variables**:
- `SCADALINK_CONTACT_POINTS` — Comma-separated list of central cluster contact point addresses (e.g., `akka.tcp://ScadaLink@central1:8081,akka.tcp://ScadaLink@central2:8081`).
- `SCADALINK_LDAP_SERVER` — LDAP server address.
- `SCADALINK_LDAP_PORT` — LDAP port (default: 636 for LDAPS).
- `SCADALINK_FORMAT` — Default output format (`json` or `table`).
3. **Configuration file**: `~/.scadalink/config.json` — Persistent defaults for contact points, LDAP settings, and output format.
### Configuration File Format
```json
{
"contactPoints": [
"akka.tcp://ScadaLink@central1:8081",
"akka.tcp://ScadaLink@central2:8081"
],
"ldap": {
"server": "ad.example.com",
"port": 636,
"useTls": true
},
"defaultFormat": "json"
}
```
## Output Formats
- **JSON** (default): Machine-readable JSON output to stdout. Suitable for piping to `jq` or processing in scripts. Errors are written to stderr as JSON objects with `error` and `code` fields.
- **Table** (`--format table` or `--table`): Human-readable tabular output with aligned columns. Suitable for interactive use.
## Exit Codes
| Code | Meaning |
|------|---------|
| 0 | Success |
| 1 | General error (command failed) |
| 2 | Authentication failure (LDAP bind failed) |
| 3 | Authorization failure (insufficient role) |
| 4 | Connection failure (cannot reach central cluster) |
| 5 | Validation failure (e.g., template validation errors) |
## Error Handling
- **Connection failure**: If the CLI cannot establish a ClusterClient connection within a timeout (default 10 seconds), it exits with code 4 and a descriptive error message.
- **Command timeout**: If the ManagementActor does not respond within 30 seconds (configurable), the command fails with a timeout error.
- **Authentication failure**: If the LDAP bind fails, the CLI exits with code 2 before sending any commands.
- **Authorization failure**: If the ManagementActor returns an Unauthorized response, the CLI exits with code 3.
## Dependencies
- **Commons**: Message contracts (`Messages/Management/`), shared types.
- **System.CommandLine**: Command-line argument parsing.
- **Akka.NET (Akka.Cluster.Tools)**: ClusterClient for communication with the central cluster.
- **LDAP client library**: For direct LDAP bind authentication (same approach as Security & Auth component).
## Interactions
- **Management Service (ManagementActor)**: The CLI's sole runtime dependency. All operations are sent as messages to the ManagementActor via ClusterClient.
- **Security & Auth**: The CLI performs LDAP authentication independently (same LDAP server, same bind mechanism) and passes the authenticated identity to the ManagementActor. The ManagementActor enforces authorization.
- **LDAP/Active Directory**: Direct bind for user authentication before any operation.

View File

@@ -121,6 +121,10 @@ This provides protocol-level safety beyond Akka.NET's transport guarantees, whic
Akka.NET guarantees message ordering between a specific sender/receiver actor pair. The Communication Layer relies on this guarantee — messages to a given site are processed in the order they are sent. Callers do not need to handle out-of-order delivery.
## ManagementActor and ClusterClient
The ManagementActor is registered at the well-known path `/user/management` on central nodes and advertised via **ClusterClientReceptionist**. External tools (primarily the CLI) connect using Akka.NET ClusterClient, which contacts the receptionist to discover the ManagementActor. ClusterClient is a separate communication channel from the inter-cluster remoting used for central-site messaging — it does not participate in cluster membership or affect the hub-and-spoke topology.
## Connection Failure Behavior
- **In-flight messages**: When a connection drops while a request is in flight (e.g., deployment sent but no response received), the Akka ask pattern times out and the caller receives a failure. There is **no automatic retry or buffering at central** — the engineer sees the failure in the UI and re-initiates the action. This is consistent with the design principle that central does not buffer messages.
@@ -144,3 +148,4 @@ Akka.NET guarantees message ordering between a specific sender/receiver actor pa
- **Health Monitoring**: Receives periodic health reports from sites.
- **Store-and-Forward Engine (site)**: Parked message queries/commands are routed through communication.
- **Site Event Logging**: Event log queries are routed through communication.
- **Management Service**: The ManagementActor is registered with ClusterClientReceptionist on central nodes. The CLI communicates with the ManagementActor via ClusterClient, which is a separate channel from inter-cluster remoting.

View File

@@ -32,7 +32,7 @@ The same compiled binary must be deployable to both central and site nodes. The
At startup the Host must inspect the configured node role and register only the component services appropriate for that role:
- **Shared** (both Central and Site): ClusterInfrastructure, Communication, HealthMonitoring, ExternalSystemGateway, NotificationService.
- **Central only**: TemplateEngine, DeploymentManager, Security, AuditLogging, CentralUI, InboundAPI.
- **Central only**: TemplateEngine, DeploymentManager, Security, AuditLogging, CentralUI, InboundAPI, ManagementService.
- **Site only**: SiteRuntime, DataConnectionLayer, StoreAndForward, SiteEventLogging.
Components not applicable to the current role must not be registered in the DI container or the Akka.NET actor system.
@@ -61,6 +61,7 @@ The Host must bind configuration sections from `appsettings.json` to strongly-ty
| `ScadaLink:Security` | `SecurityOptions` | Security & Auth | LdapServer, LdapPort, LdapUseTls, JwtSigningKey, JwtExpiryMinutes, IdleTimeoutMinutes |
| `ScadaLink:InboundApi` | `InboundApiOptions` | Inbound API | DefaultMethodTimeout |
| `ScadaLink:Notification` | `NotificationOptions` | Notification Service | (SMTP config is stored in config DB and deployed to sites, not in appsettings) |
| `ScadaLink:ManagementService` | `ManagementServiceOptions` | Management Service | (Reserved for future configuration) |
| `ScadaLink:Logging` | `LoggingOptions` | Host | Serilog sink configuration, log level overrides |
#### Convention
@@ -107,6 +108,10 @@ The Host must configure the Akka.NET actor system using Akka.Hosting with:
- **Split-Brain Resolver**: Configured with the strategy and stable-after duration from `ClusterConfiguration`.
- **Actor registration**: Each component's actors registered via its `AddXxxActors()` extension method, conditional on the node's role.
### REQ-HOST-6a: ClusterClientReceptionist (Central Only)
On central nodes, the Host must configure the Akka.NET **ClusterClientReceptionist** and register the ManagementActor with it. This allows external processes (e.g., the CLI) to discover and communicate with the ManagementActor via ClusterClient without joining the cluster as full members. The receptionist is started as part of the Akka.NET bootstrap (REQ-HOST-6) on central nodes only.
### REQ-HOST-7: ASP.NET Web Endpoints (Central Only)
On central nodes, the Host must use `WebApplication.CreateBuilder` to produce a full ASP.NET Core host with Kestrel, and must map web endpoints for:
@@ -140,7 +145,7 @@ Each component library must expose its services to the Host via a consistent set
- `AkkaConfigurationBuilder.AddXxxActors()` — registers the component's actors with the Akka.NET actor system (for components that have actors).
- `WebApplication.MapXxx()` — maps the component's web endpoints (only for CentralUI and InboundAPI).
The Host's `Program.cs` calls these extension methods; the component libraries own the registration logic. This keeps the Host thin and each component self-contained.
The Host's `Program.cs` calls these extension methods; the component libraries own the registration logic. This keeps the Host thin and each component self-contained. The ManagementService component additionally registers the ManagementActor with ClusterClientReceptionist in its `AddManagementServiceActors()` method.
---
@@ -158,6 +163,7 @@ The Host's `Program.cs` calls these extension methods; the component libraries o
| Security | Yes | No | Yes | Yes | No |
| CentralUI | Yes | No | Yes | No | Yes |
| InboundAPI | Yes | No | Yes | No | Yes |
| ManagementService | Yes | No | Yes | Yes | No |
| SiteRuntime | No | Yes | Yes | Yes | No |
| DataConnectionLayer | No | Yes | Yes | Yes | No |
| StoreAndForward | No | Yes | Yes | Yes | No |
@@ -168,7 +174,7 @@ The Host's `Program.cs` calls these extension methods; the component libraries o
## Dependencies
- **All 15 component libraries**: The Host references every component project to call their extension methods.
- **All 17 component libraries**: The Host references every component project to call their extension methods (excludes CLI, which is a separate executable).
- **Akka.Hosting**: For `AddAkka()` and the hosting configuration builder.
- **Akka.Remote.Hosting, Akka.Cluster.Hosting, Akka.Persistence.Hosting**: For Akka subsystem configuration.
- **Serilog.AspNetCore**: For structured logging integration.
@@ -181,4 +187,5 @@ The Host's `Program.cs` calls these extension methods; the component libraries o
- **Configuration Database**: The Host registers the DbContext and wires repository implementations to their interfaces. In development, triggers auto-migration; in production, validates schema version.
- **ClusterInfrastructure**: The Host configures the underlying Akka.NET cluster that ClusterInfrastructure manages at runtime.
- **CentralUI / InboundAPI**: The Host maps their web endpoints into the ASP.NET Core pipeline on central nodes.
- **ManagementService**: The Host registers the ManagementActor and configures ClusterClientReceptionist on central nodes, enabling CLI access.
- **HealthMonitoring**: The Host's startup validation and logging configuration provide the foundation for health reporting.

View File

@@ -0,0 +1,150 @@
# Component: Management Service
## Purpose
The Management Service is an Akka.NET actor on the central cluster that provides programmatic access to all administrative operations. It exposes the same capabilities as the Central UI but through an actor-based interface, enabling the CLI (and potentially other tooling) to interact with the system without going through the web UI. The ManagementActor registers with ClusterClientReceptionist so that external processes can reach it via ClusterClient without joining the cluster.
## Location
Central cluster only (active node). The ManagementActor runs as a cluster singleton on the central cluster.
`src/ScadaLink.ManagementService/`
## Responsibilities
- Provide an actor-based interface to all administrative operations available in the Central UI.
- Register with Akka.NET ClusterClientReceptionist so external tools (CLI) can discover and communicate with it via ClusterClient.
- Validate and authorize all incoming commands using the authenticated user identity carried in message envelopes.
- Delegate to the appropriate services and repositories for each operation.
- Return structured response messages for all commands and queries.
- Failover: The ManagementActor is available on the active central node and fails over with it. ClusterClient handles reconnection transparently.
## Key Classes
### ManagementActor
The central actor that receives and processes all management commands. Registered at a well-known actor path (`/user/management`) and with ClusterClientReceptionist.
### Message Contracts
All request/response messages are defined in **Commons** under `Messages/Management/`. Messages follow the existing additive-only evolution rules for version compatibility. Every request message includes:
- **CorrelationId**: Application-level correlation ID for request/response pairing.
- **AuthenticatedUser**: The identity and roles of the user issuing the command (username, display name, roles, permitted sites). This is populated by the CLI from the user's authenticated session.
## ClusterClientReceptionist Registration
The ManagementActor registers itself with `ClusterClientReceptionist` at startup. This allows external processes using `ClusterClient` to send messages to the ManagementActor without joining the Akka.NET cluster as a full member. The receptionist advertises the actor under its well-known path.
## Message Groups
### Templates
- **ListTemplates** / **GetTemplate**: Query template definitions.
- **CreateTemplate** / **UpdateTemplate** / **DeleteTemplate**: Manage templates.
- **ValidateTemplate**: Run on-demand pre-deployment validation (flattening, naming collisions, script compilation).
- **GetTemplateDiff**: Compare deployed vs. template-derived configuration for an instance.
### Instances
- **ListInstances** / **GetInstance**: Query instances, with filtering by site and area.
- **CreateInstance**: Create a new instance from a template.
- **UpdateInstanceOverrides**: Set attribute overrides on an instance.
- **BindDataConnections**: Bind data connections to instance attributes.
- **AssignArea**: Assign an instance to an area.
- **EnableInstance** / **DisableInstance** / **DeleteInstance**: Instance lifecycle commands.
### Sites
- **ListSites** / **GetSite**: Query site definitions.
- **CreateSite** / **UpdateSite** / **DeleteSite**: Manage site definitions.
- **ListAreas** / **CreateArea** / **UpdateArea** / **DeleteArea**: Manage area hierarchies per site.
### Data Connections
- **ListDataConnections** / **GetDataConnection**: Query data connection definitions.
- **CreateDataConnection** / **UpdateDataConnection** / **DeleteDataConnection**: Manage data connection definitions.
- **AssignDataConnectionToSite** / **UnassignDataConnectionFromSite**: Manage site assignments.
### Deployments
- **DeployInstance**: Deploy configuration to a specific instance (includes pre-deployment validation).
- **DeployArtifacts**: Deploy system-wide artifacts (shared scripts, external system definitions, DB connections, data connections, notification lists, SMTP config) to all sites or a specific site.
- **GetDeploymentStatus**: Query deployment status.
### External Systems
- **ListExternalSystems** / **GetExternalSystem**: Query external system definitions.
- **CreateExternalSystem** / **UpdateExternalSystem** / **DeleteExternalSystem**: Manage external system definitions.
### Notifications
- **ListNotificationLists** / **GetNotificationList**: Query notification lists.
- **CreateNotificationList** / **UpdateNotificationList** / **DeleteNotificationList**: Manage notification lists and recipients.
- **GetSmtpConfig** / **UpdateSmtpConfig**: Query and update SMTP configuration.
### Security (LDAP & API Keys)
- **ListApiKeys** / **CreateApiKey** / **EnableApiKey** / **DisableApiKey** / **DeleteApiKey**: Manage API keys.
- **ListRoleMappings** / **CreateRoleMapping** / **UpdateRoleMapping** / **DeleteRoleMapping**: Manage LDAP group-to-role mappings.
### Audit Log
- **QueryAuditLog**: Query audit log entries with filtering by entity type, user, date range, etc.
### Health
- **GetHealthSummary**: Query current health status of all sites.
- **GetSiteHealth**: Query detailed health for a specific site.
## Authorization
Every incoming message carries the authenticated user's identity and roles. The ManagementActor enforces the same role-based authorization rules as the Central UI:
- **Admin** role required for: site management, area management, API key management, role mapping management, system configuration.
- **Design** role required for: template authoring, shared scripts, external system definitions, database connection definitions, notification lists, inbound API method definitions.
- **Deployment** role required for: instance management, deployments, debug view, parked message management, site event log viewing. Site scoping is enforced for site-scoped Deployment users.
Unauthorized commands receive an `Unauthorized` response message. Failed authorization attempts are not audit logged (consistent with existing behavior).
## Service Dependencies (DI)
The ManagementActor receives the following services and repositories via DI (injected through the actor's constructor or via a service provider):
- `ITemplateEngineRepository` / `TemplateService` — Template operations.
- `InstanceService` — Instance lifecycle and configuration.
- `ISiteRepository` — Site definitions and area management.
- `IDeploymentManagerRepository` / `DeploymentService` — Deployment pipeline operations.
- `ArtifactDeploymentService` — System-wide artifact deployment.
- `IExternalSystemRepository` — External system definitions.
- `INotificationRepository` — Notification lists and SMTP config.
- `ISecurityRepository` — API keys and LDAP role mappings.
- `IInboundApiRepository` — Inbound API method definitions.
- `ICentralUiRepository` — UI-related queries (shared scripts, database connections).
- `ICentralHealthAggregator` — Health status aggregation.
- `CommunicationService` — Central-site communication for deployment and remote queries.
## Configuration
| Section | Options Class | Contents |
|---------|--------------|----------|
| `ScadaLink:ManagementService` | `ManagementServiceOptions` | (Reserved for future configuration — e.g., command timeout overrides) |
## Dependencies
- **Commons**: Message contracts (`Messages/Management/`), shared types, repository interfaces.
- **Configuration Database (MS SQL)**: All queries and mutations go through repositories backed by EF Core.
- **Configuration Database (via IAuditService)**: All mutating operations are audit logged through the existing transactional audit mechanism.
- **Communication Layer**: Deployment commands and remote queries (parked messages, event logs) are routed to sites via Communication.
- **Security & Auth**: Authorization rules are enforced on every command using the authenticated user identity from the message envelope.
- **Cluster Infrastructure**: ManagementActor runs on the active central node; ClusterClientReceptionist requires cluster membership.
- **All service components**: The ManagementActor delegates to the same services used by the Central UI — Template Engine, Deployment Manager, etc.
## Interactions
- **CLI**: The primary consumer. Connects via Akka.NET ClusterClient and sends management messages to the ManagementActor.
- **Host**: Registers the ManagementActor and ClusterClientReceptionist on central nodes during startup.
- **Central UI**: Shares the same underlying services and repositories. The ManagementActor and Central UI are parallel interfaces to the same operations.
- **Communication Layer**: Deployment commands and remote site queries flow through communication actors.
- **Configuration Database (via IAuditService)**: All configuration changes are audited.
- **Security & Auth**: The ManagementActor enforces authorization using user identity passed in messages. The CLI is responsible for authenticating the user and including their identity in every request.

View File

@@ -115,3 +115,4 @@ Central cluster. Sites do not have user-facing interfaces and do not perform ind
- **Template Engine**: Design role enforcement.
- **Deployment Manager**: Deployment role enforcement with site scoping.
- **All central components**: Role checks are a cross-cutting concern applied at the API layer.
- **Management Service**: The ManagementActor enforces role-based authorization on every incoming command using the authenticated user identity carried in the message envelope. The CLI authenticates users via the same LDAP bind mechanism and passes the user's identity (username, roles, permitted sites) in every request message. The ManagementActor applies the same role and site-scoping rules as the Central UI — no separate authentication path exists on the server side.

View File

@@ -464,9 +464,27 @@ Sites log operational events locally, including:
### 12.3 Central Access
- The central UI can **query site event logs remotely**, following the same pattern as parked message management — central requests data from the site over Akka.NET remoting.
## 13. General Conventions
## 13. Management Service & CLI
### 13.1 Timestamps
### 13.1 Management Service
- The central cluster exposes a **ManagementActor** that provides programmatic access to all administrative operations — the same operations available through the Central UI.
- The ManagementActor registers with Akka.NET **ClusterClientReceptionist**, allowing external tools to communicate with it via ClusterClient without joining the cluster.
- The ManagementActor enforces the **same role-based authorization** as the Central UI. Every incoming message carries the authenticated user's identity and roles.
- All mutating operations performed through the Management Service are **audit logged** via IAuditService, identical to operations performed through the Central UI.
- The ManagementActor runs on the **active central node** and fails over with it. ClusterClient handles reconnection transparently.
### 13.2 CLI
- The system provides a standalone **command-line tool** (`scadalink`) for scripting and automating administrative operations.
- The CLI connects to the ManagementActor via Akka.NET **ClusterClient** — it does not join the cluster as a full member and does not use HTTP/REST.
- The CLI authenticates the user against **LDAP/AD** (direct bind, same mechanism as the Central UI) and includes the authenticated identity in every message sent to the ManagementActor.
- CLI commands mirror all Management Service operations: templates, instances, sites, data connections, deployments, external systems, notifications, security (API keys and role mappings), audit log queries, and health status.
- Output is **JSON by default** (machine-readable, suitable for scripting) with an optional `--format table` flag for human-readable tabular output.
- Configuration is resolved from command-line options, **environment variables** (`SCADALINK_CONTACT_POINTS`, `SCADALINK_LDAP_SERVER`, etc.), or a **configuration file** (`~/.scadalink/config.json`).
- The CLI is a separate executable from the Host binary — it is deployed on any Windows machine with network access to the central cluster.
## 14. General Conventions
### 14.1 Timestamps
- All timestamps throughout the system are stored, transmitted, and processed in **UTC**.
- This applies to: attribute value timestamps, alarm state change timestamps, audit log entries, event log entries, deployment records, health reports, store-and-forward message timestamps, and all inter-node messages.
- Local time conversion for display is a **Central UI concern only** — no other component performs timezone conversion.

View File

@@ -51,6 +51,8 @@ This document serves as the master index for the SCADA system design. The system
| 15 | Host | [Component-Host.md](Component-Host.md) | Single deployable binary, role-based component registration, per-component config binding (Options pattern), readiness gating, dead letter monitoring, Akka.NET bootstrap, ASP.NET Core hosting for central. |
| 16 | Commons | [Component-Commons.md](Component-Commons.md) | Namespace/folder convention (Types/Interfaces/Entities/Messages), shared data types, POCOs, repository interfaces, message contracts with additive-only versioning, UTC timestamp convention. |
| 17 | Configuration Database | [Component-ConfigurationDatabase.md](Component-ConfigurationDatabase.md) | EF Core data access, per-component repositories, unit-of-work, optimistic concurrency on deployment status, audit logging (IAuditService), migration management. |
| 18 | Management Service | [Component-ManagementService.md](Component-ManagementService.md) | Akka.NET ManagementActor on central, ClusterClientReceptionist registration, programmatic access to all admin operations, CLI interface. |
| 19 | CLI | [Component-CLI.md](Component-CLI.md) | Standalone command-line tool, System.CommandLine, Akka.NET ClusterClient transport, LDAP auth, JSON/table output, mirrors all Management Service operations. |
### Reference Documentation
@@ -81,6 +83,10 @@ This document serves as the master index for the SCADA system design. The system
│ │ Inbound │ ◄── External Systems (X-API-Key) │
│ │ API │ POST /api/{method}, JSON │
│ └──────────┘ │
│ ┌──────────┐ │
│ │ Mgmt │ ◄── CLI (ClusterClient) │
│ │ Service │ ManagementActor + Receptionist │
│ └──────────┘ │
│ ┌───────────────────────────────────┐ │
│ │ Akka.NET Communication Layer │ │
│ │ (correlation IDs, per-pattern │ │