All phases (0-8) now have detailed implementation plans with: - Bullet-level requirement extraction from HighLevelReqs sections - Design constraint traceability (KDD + Component Design) - Work packages with acceptance criteria mapped to every requirement - Split-section ownership verified across phases - Orphan checks (forward, reverse, negative) all passing - Codex MCP (gpt-5.4) external verification completed per phase Total: 7,549 lines across 11 plan documents, ~160 work packages, ~400 requirements traced, ~25 open questions logged for follow-up.
682 lines
49 KiB
Markdown
682 lines
49 KiB
Markdown
# Phase 0: Solution Skeleton & Delivery Guardrails
|
|
|
|
**Date**: 2026-03-16
|
|
**Status**: Draft
|
|
**Components**: Commons, Host, Solution Structure, CI Baseline
|
|
|
|
---
|
|
|
|
## 1. Scope
|
|
|
|
This phase establishes the buildable, testable baseline for the entire ScadaLink system before any domain logic is implemented. It delivers:
|
|
|
|
- A .NET 10 solution with all 17 component projects and corresponding test projects, using the SLNX format.
|
|
- The Commons component with its complete namespace/folder skeleton, shared data types, entity POCOs, repository interfaces, cross-cutting service interfaces, message contracts, and protocol abstraction interfaces.
|
|
- A Host skeleton that boots by role from `appsettings.json`, demonstrates the extension method convention, and differentiates between central (WebApplication) and site (generic Host) startup paths.
|
|
- Per-component options classes in their respective component projects.
|
|
- Sample `appsettings.json` files for central and site topologies.
|
|
|
|
No business logic, actor systems, database connectivity, or web endpoints are implemented in this phase. The deliverable is a compiling solution with correct project references, enforceable architectural constraints, and a skeleton that subsequent phases build upon.
|
|
|
|
---
|
|
|
|
## 2. Prerequisites
|
|
|
|
- None. This is the first phase.
|
|
- Tooling: .NET 10 SDK, an IDE, Git.
|
|
|
|
---
|
|
|
|
## 3. Requirements Checklist
|
|
|
|
### HighLevelReqs 13.1 — Timestamps (UTC)
|
|
|
|
- `[13.1-1]` All timestamps throughout the system are stored, transmitted, and processed in UTC.
|
|
- `[13.1-2]` 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.
|
|
- `[13.1-3]` Local time conversion for display is a Central UI concern only — no other component performs timezone conversion.
|
|
|
|
### REQ-COM-1: Shared Data Type System
|
|
|
|
- `[COM-1-1]` `DataType` enum: Boolean, Int32, Float, Double, String, DateTime, Binary.
|
|
- `[COM-1-2]` `RetryPolicy`: record or immutable class with max retries and fixed delay.
|
|
- `[COM-1-3]` `Result<T>`: discriminated result type representing success or error.
|
|
- `[COM-1-4]` `InstanceState` enum: Enabled, Disabled.
|
|
- `[COM-1-5]` `DeploymentStatus` enum: Pending, InProgress, Success, Failed.
|
|
- `[COM-1-6]` `AlarmState` enum: Active, Normal.
|
|
- `[COM-1-7]` `AlarmTriggerType` enum: ValueMatch, RangeViolation, RateOfChange.
|
|
- `[COM-1-8]` `ConnectionHealth` enum: Connected, Disconnected, Connecting, Error.
|
|
- `[COM-1-9]` All types must be immutable and thread-safe.
|
|
- `[COM-1-10]` Timestamp convention: all timestamps must use UTC (`DateTime` with `DateTimeKind.Utc` or `DateTimeOffset` with zero offset).
|
|
- `[COM-1-11]` Timestamp convention applies to all stored timestamps (SQLite, MS SQL, audit entries), all message timestamps, and all wire-format timestamps.
|
|
- `[COM-1-12]` Local time conversion is a UI display concern only (negative: no other component performs timezone conversion).
|
|
|
|
### REQ-COM-2: Protocol Abstraction
|
|
|
|
- `[COM-2-1]` `IDataConnection` interface for reading, writing, and subscribing to device data.
|
|
- `[COM-2-2]` Related types: tag identifiers, read/write results, subscription callbacks, connection status enums, quality codes.
|
|
- `[COM-2-3]` Interfaces must not reference any specific protocol implementation (negative).
|
|
|
|
### REQ-COM-3: Domain Entity Classes (POCOs)
|
|
|
|
- `[COM-3-1]` Plain C# classes with properties — no EF attributes, no EF base classes, no navigation property annotations.
|
|
- `[COM-3-2]` May include navigation properties as plain collections (e.g., `ICollection<TemplateAttribute>`).
|
|
- `[COM-3-3]` May include constructors that enforce invariants.
|
|
- `[COM-3-4]` Must have no dependency on Entity Framework Core or any persistence library (negative).
|
|
- `[COM-3-5]` Template & Modeling entities: `Template`, `TemplateAttribute`, `TemplateAlarm`, `TemplateScript`, `TemplateComposition`, `Instance`, `InstanceAttributeOverride`, `InstanceConnectionBinding`, `Area`.
|
|
- `[COM-3-6]` Shared Scripts entities: `SharedScript`.
|
|
- `[COM-3-7]` Sites & Data Connections entities: `Site`, `DataConnection`, `SiteDataConnectionAssignment`.
|
|
- `[COM-3-8]` External Systems & Database Connections entities: `ExternalSystemDefinition`, `ExternalSystemMethod`, `DatabaseConnectionDefinition`.
|
|
- `[COM-3-9]` Notifications entities: `NotificationList`, `NotificationRecipient`, `SmtpConfiguration`.
|
|
- `[COM-3-10]` Inbound API entities: `ApiKey`, `ApiMethod`.
|
|
- `[COM-3-11]` Security entities: `LdapGroupMapping`, `SiteScopeRule`.
|
|
- `[COM-3-12]` Deployment entities: `DeploymentRecord`, `SystemArtifactDeploymentRecord`.
|
|
- `[COM-3-13]` Audit entities: `AuditLogEntry`.
|
|
|
|
### REQ-COM-4: Per-Component Repository Interfaces
|
|
|
|
- `[COM-4-1]` `ITemplateEngineRepository` — templates, attributes, alarms, scripts, compositions, instances, overrides, connection bindings, areas.
|
|
- `[COM-4-2]` `IDeploymentManagerRepository` — deployment records, deployed configuration snapshots, system-wide artifact deployment records.
|
|
- `[COM-4-3]` `ISecurityRepository` — LDAP group mappings, site scoping rules.
|
|
- `[COM-4-4]` `IInboundApiRepository` — API keys, API method definitions.
|
|
- `[COM-4-5]` `IExternalSystemRepository` — external system definitions, method definitions, database connection definitions.
|
|
- `[COM-4-6]` `INotificationRepository` — notification lists, recipients, SMTP configuration.
|
|
- `[COM-4-7]` `ICentralUiRepository` — read-oriented queries spanning multiple domain areas.
|
|
- `[COM-4-8]` All repository interfaces accept and return POCO entity classes.
|
|
- `[COM-4-9]` All repository interfaces include `SaveChangesAsync()` or equivalent.
|
|
- `[COM-4-10]` No dependency on Entity Framework Core — pure interfaces (negative).
|
|
|
|
### REQ-COM-4a: Cross-Cutting Service Interfaces
|
|
|
|
- `[COM-4a-1]` `IAuditService` with `LogAsync(user, action, entityType, entityId, entityName, afterState)`.
|
|
- `[COM-4a-2]` Defined in Commons so any central component can call it without depending on the audit implementation directly.
|
|
|
|
### REQ-COM-5: Cross-Component Message Contracts
|
|
|
|
- `[COM-5-1]` Deployment DTOs: configuration snapshots, deployment commands, deployment status, validation results.
|
|
- `[COM-5-2]` Instance Lifecycle DTOs: disable, enable, delete commands and responses.
|
|
- `[COM-5-3]` Health DTOs: health check results, site status reports, heartbeat messages, script error rates, alarm evaluation error rates.
|
|
- `[COM-5-4]` Communication DTOs: site identity, connection state, routing metadata.
|
|
- `[COM-5-5]` Attribute Stream DTOs: attribute value change messages (instance name, attribute path, value, quality, timestamp) and alarm state change messages (instance name, alarm name, state, priority, timestamp).
|
|
- `[COM-5-6]` Debug View DTOs: subscribe/unsubscribe requests, initial snapshot, stream filter criteria.
|
|
- `[COM-5-7]` Script Execution DTOs: script call requests (with recursion depth), return values, error results.
|
|
- `[COM-5-8]` System-Wide Artifact DTOs: shared script packages, external system definitions, database connection definitions, notification list definitions.
|
|
- `[COM-5-9]` All message types must be `record` types or immutable classes (negative: no mutable message types).
|
|
- `[COM-5-10]` Commons must not depend on Akka.NET (negative), even though messages will be used as Akka messages.
|
|
|
|
### REQ-COM-5a: Message Contract Versioning
|
|
|
|
- `[COM-5a-1]` Additive-only evolution: new fields with defaults; existing fields must not be removed or have types changed (negative).
|
|
- `[COM-5a-2]` Serialization must tolerate unknown fields (forward compatibility) and missing optional fields (backward compatibility).
|
|
- `[COM-5a-3]` Breaking changes require a new message type and coordinated deployment.
|
|
- `[COM-5a-4]` Akka.NET serialization binding must explicitly map message types to serializers (prevents binary serialization) — noted here but implemented in Phase 1/3A when Akka is bootstrapped.
|
|
|
|
### REQ-COM-5b: Namespace & Folder Convention
|
|
|
|
- `[COM-5b-1]` Top-level folders: `Types/`, `Interfaces/`, `Entities/`, `Messages/`.
|
|
- `[COM-5b-2]` `Types/` contains shared data types (REQ-COM-1) including `Enums/` subfolder.
|
|
- `[COM-5b-3]` `Interfaces/Protocol/` for IDataConnection and related types.
|
|
- `[COM-5b-4]` `Interfaces/Repositories/` for per-component repository interfaces.
|
|
- `[COM-5b-5]` `Interfaces/Services/` for cross-cutting service interfaces (IAuditService).
|
|
- `[COM-5b-6]` `Entities/` subfolders by domain area: Templates, Instances, Sites, ExternalSystems, Notifications, InboundApi, Security, Deployment, Scripts, Audit.
|
|
- `[COM-5b-7]` `Messages/` subfolders by concern: Deployment, Lifecycle, Health, Communication, Streaming, DebugView, ScriptExecution, Artifacts.
|
|
- `[COM-5b-8]` Namespaces mirror folder structure (e.g., `ScadaLink.Commons.Entities.Templates`).
|
|
- `[COM-5b-9]` Interface names use `I` prefix.
|
|
- `[COM-5b-10]` Entity classes named after domain concept — no `Entity` or `Model` suffixes.
|
|
- `[COM-5b-11]` Message contracts named as commands, events, or responses.
|
|
- `[COM-5b-12]` Enums use singular names.
|
|
|
|
### REQ-COM-6: No Business Logic
|
|
|
|
- `[COM-6-1]` Commons contains only: data structures (records, classes, structs), interfaces, enums, constants.
|
|
- `[COM-6-2]` Must not contain business logic, service implementations, actor definitions, or orchestration code (negative).
|
|
- `[COM-6-3]` Method bodies limited to trivial data-access logic (factory methods, constructor invariant validation).
|
|
|
|
### REQ-COM-7: Minimal Dependencies
|
|
|
|
- `[COM-7-1]` Depends only on core .NET libraries (`System.*`, `Microsoft.Extensions.Primitives` if needed).
|
|
- `[COM-7-2]` Must not reference Akka.NET or Akka.* packages (negative).
|
|
- `[COM-7-3]` Must not reference ASP.NET Core or Microsoft.AspNetCore.* packages (negative).
|
|
- `[COM-7-4]` Must not reference Entity Framework Core or Microsoft.EntityFrameworkCore.* packages (negative).
|
|
- `[COM-7-5]` Must not reference any third-party libraries requiring paid licenses (negative).
|
|
|
|
### REQ-HOST-1: Single Binary Deployment
|
|
|
|
- `[HOST-1-1]` Same compiled binary deployable to both central and site nodes.
|
|
- `[HOST-1-2]` Node role determined solely by configuration in `appsettings.json`.
|
|
- `[HOST-1-3]` No separate build targets, projects, or conditional compilation symbols for central vs. site (negative).
|
|
|
|
### REQ-HOST-2: Role-Based Service Registration (Phase 0 skeleton)
|
|
|
|
- `[HOST-2-1]` Host inspects configured node role at startup.
|
|
- `[HOST-2-2]` Registers only component services appropriate for the role.
|
|
- `[HOST-2-3]` Shared (both): ClusterInfrastructure, Communication, HealthMonitoring, ExternalSystemGateway, NotificationService.
|
|
- `[HOST-2-4]` Central only: TemplateEngine, DeploymentManager, Security, AuditLogging, CentralUI, InboundAPI.
|
|
- `[HOST-2-5]` Site only: SiteRuntime, DataConnectionLayer, StoreAndForward, SiteEventLogging.
|
|
- `[HOST-2-6]` Components not applicable to the role must not be registered (negative).
|
|
|
|
### REQ-HOST-3: Configuration Binding (Phase 0 skeleton)
|
|
|
|
- `[HOST-3-1]` Bind configuration sections from `appsettings.json` to strongly-typed options classes using .NET Options pattern.
|
|
- `[HOST-3-2]` Infrastructure sections: `ScadaLink:Node` (NodeOptions), `ScadaLink:Cluster` (ClusterOptions), `ScadaLink:Database` (DatabaseOptions).
|
|
- `[HOST-3-3]` Per-component sections: DataConnection, StoreAndForward, HealthMonitoring, SiteEventLog, Communication, Security, InboundApi, Notification, Logging.
|
|
- `[HOST-3-4]` Each component defines its own options class in its own project.
|
|
- `[HOST-3-5]` Host binds via `services.Configure<T>(configuration.GetSection("ScadaLink:<ComponentName>"))`.
|
|
- `[HOST-3-6]` Components read options via `IOptions<T>` — never `IConfiguration` directly (negative).
|
|
|
|
### REQ-HOST-7: ASP.NET vs Generic Host (Phase 0 skeleton)
|
|
|
|
- `[HOST-7-1]` Central nodes use `WebApplication.CreateBuilder` (ASP.NET Core host with Kestrel).
|
|
- `[HOST-7-2]` Site nodes use `Host.CreateDefaultBuilder` (generic `IHost` — no Kestrel, no HTTP, no web pipeline).
|
|
- `[HOST-7-3]` Site nodes must never accept inbound HTTP connections (negative).
|
|
|
|
### REQ-HOST-10: Extension Method Convention
|
|
|
|
- `[HOST-10-1]` Each component exposes `IServiceCollection.AddXxx()` for DI registration.
|
|
- `[HOST-10-2]` Each component with actors exposes `AkkaConfigurationBuilder.AddXxxActors()` (stub in Phase 0).
|
|
- `[HOST-10-3]` CentralUI and InboundAPI expose `WebApplication.MapXxx()` (stub in Phase 0).
|
|
- `[HOST-10-4]` Host's `Program.cs` calls these extension methods; component libraries own the registration logic.
|
|
- `[HOST-10-5]` Host remains thin — no component-specific logic in `Program.cs`.
|
|
|
|
---
|
|
|
|
## 4. Design Constraints Checklist
|
|
|
|
### From CLAUDE.md Key Design Decisions
|
|
|
|
- `[KDD-data-6]` All timestamps are UTC throughout the system. → Enforced in type system (COM-1-10, COM-1-11, COM-1-12).
|
|
- `[KDD-code-1]` Entity classes are persistence-ignorant POCOs in Commons; EF mappings in Configuration Database. → Phase 0 delivers the POCOs; Phase 1 delivers the EF mappings.
|
|
- `[KDD-code-2]` Repository interfaces in Commons; implementations in Configuration Database. → Phase 0 delivers the interfaces; Phase 1 delivers implementations.
|
|
- `[KDD-code-3]` Commons namespace hierarchy: Types/, Interfaces/, Entities/, Messages/ with domain area subfolders. → Directly maps to REQ-COM-5b.
|
|
- `[KDD-code-4]` Message contracts follow additive-only evolution rules. → Directly maps to REQ-COM-5a.
|
|
- `[KDD-code-5]` Per-component configuration via appsettings.json sections bound to options classes. → Directly maps to REQ-HOST-3.
|
|
- `[KDD-code-6]` Options classes owned by component projects, not Commons. → Directly maps to HOST-3-4.
|
|
|
|
### From Component-Commons.md
|
|
|
|
- `[CD-Commons-1]` Commons is referenced by all component libraries and the Host — project reference structure must reflect this.
|
|
- `[CD-Commons-2]` No EF navigation property annotations on POCOs (Fluent API only in Configuration Database).
|
|
- `[CD-Commons-3]` Configuration Database implements repository interfaces and maps POCOs — Phase 0 establishes the interface contract; implementation deferred.
|
|
|
|
### From Component-Host.md
|
|
|
|
- `[CD-Host-1]` Host is the composition root — references every component project to call their extension methods.
|
|
- `[CD-Host-2]` Configuration Database registration (DbContext, repository wiring) is a Host responsibility — Phase 0 includes ConfigurationDatabase in Host's `AddXxx()` call chain (skeleton); full DbContext/repository wiring in Phase 1.
|
|
- `[CD-Host-3]` Component registration matrix defines which components register for which roles (14 components + ConfigurationDatabase).
|
|
|
|
### From Resolved Questions (questions.md)
|
|
|
|
- `[Q1]` .NET 10 LTS.
|
|
- `[Q3]` Single monorepo with SLNX solution file.
|
|
- `[Q4]` No CI/CD pipeline (build/test/format is local tooling only).
|
|
|
|
---
|
|
|
|
## 5. Work Packages
|
|
|
|
### WP-0.1: Solution Structure
|
|
|
|
**Description**: Create the .NET 10 solution with all 17 component projects, their test projects, and the Host project using the SLNX format. Establish project references: all components reference Commons; Host references all components.
|
|
|
|
**Acceptance Criteria**:
|
|
- 15 component class library projects exist under `src/` (all components except Host and Commons: TemplateEngine, DeploymentManager, SiteRuntime, DataConnectionLayer, Communication, StoreAndForward, ExternalSystemGateway, NotificationService, CentralUI, Security, HealthMonitoring, SiteEventLogging, ClusterInfrastructure, InboundAPI, ConfigurationDatabase).
|
|
- 1 Commons class library project exists under `src/`.
|
|
- 1 Host project (console/web application) exists under `src/`.
|
|
- 17 corresponding test projects exist under `tests/` (one per component + Commons + Host, xUnit).
|
|
- SLNX solution file at the repository root includes all 17 source projects and 17 test projects.
|
|
- All 15 component library projects have a project reference to `ScadaLink.Commons`.
|
|
- `ScadaLink.Host` has project references to all 15 component library projects + Commons (16 total).
|
|
- `dotnet build` succeeds with zero errors and zero warnings.
|
|
- `dotnet test` succeeds (no tests yet, but framework is wired).
|
|
|
|
**Complexity**: M
|
|
|
|
**Requirements Traced**: [HOST-1-1], [HOST-1-3], [CD-Host-1], [CD-Commons-1], [Q1], [Q3]
|
|
|
|
---
|
|
|
|
### WP-0.2: Commons Namespace & Folder Skeleton
|
|
|
|
**Description**: Create the complete folder and namespace structure for Commons as specified by REQ-COM-5b. All folders exist with placeholder files or namespace declarations as appropriate.
|
|
|
|
**Acceptance Criteria**:
|
|
- Top-level folders exist: `Types/`, `Types/Enums/`, `Interfaces/`, `Interfaces/Protocol/`, `Interfaces/Repositories/`, `Interfaces/Services/`, `Entities/`, `Messages/`.
|
|
- Entity subfolders exist: `Templates/`, `Instances/`, `Sites/`, `ExternalSystems/`, `Notifications/`, `InboundApi/`, `Security/`, `Deployment/`, `Scripts/`, `Audit/`.
|
|
- Message subfolders exist: `Deployment/`, `Lifecycle/`, `Health/`, `Communication/`, `Streaming/`, `DebugView/`, `ScriptExecution/`, `Artifacts/`.
|
|
- Namespace conventions match folder structure (e.g., `ScadaLink.Commons.Entities.Templates`).
|
|
|
|
**Complexity**: S
|
|
|
|
**Requirements Traced**: [COM-5b-1], [COM-5b-2], [COM-5b-3], [COM-5b-4], [COM-5b-5], [COM-5b-6], [COM-5b-7], [COM-5b-8], [KDD-code-3]
|
|
|
|
---
|
|
|
|
### WP-0.3: Commons Shared Data Types
|
|
|
|
**Description**: Implement all shared data types defined by REQ-COM-1, including enums, `RetryPolicy`, `Result<T>`, and the UTC timestamp convention.
|
|
|
|
**Acceptance Criteria**:
|
|
- `DataType` enum with values: Boolean, Int32, Float, Double, String, DateTime, Binary.
|
|
- `RetryPolicy` as a record or immutable class with `MaxRetries` (int) and `Delay` (TimeSpan) properties.
|
|
- `Result<T>` as a discriminated result type with success/error states and factory methods (`Success(T)`, `Failure(string)`).
|
|
- `InstanceState` enum: Enabled, Disabled.
|
|
- `DeploymentStatus` enum: Pending, InProgress, Success, Failed.
|
|
- `AlarmState` enum: Active, Normal.
|
|
- `AlarmTriggerType` enum: ValueMatch, RangeViolation, RateOfChange.
|
|
- `ConnectionHealth` enum: Connected, Disconnected, Connecting, Error.
|
|
- All types are immutable and thread-safe (record types for value objects — immutability guarantees thread safety; enums are inherently thread-safe).
|
|
- A `UtcTimestamp` helper or convention document/attribute is provided to enforce UTC on `DateTime`/`DateTimeOffset` fields. Unit test verifies that constructing a `DateTimeOffset` with non-zero offset is rejected or documented as invalid.
|
|
- Enum names are singular (not plural).
|
|
- Unit tests verify: `Result<T>` success/error construction, pattern matching, immutability of `RetryPolicy`.
|
|
|
|
**Complexity**: S
|
|
|
|
**Requirements Traced**: [COM-1-1], [COM-1-2], [COM-1-3], [COM-1-4], [COM-1-5], [COM-1-6], [COM-1-7], [COM-1-8], [COM-1-9], [COM-1-10], [COM-1-11], [COM-1-12], [COM-5b-2], [COM-5b-12], [13.1-1], [13.1-2], [13.1-3], [KDD-data-6]
|
|
|
|
---
|
|
|
|
### WP-0.4: Commons Domain Entity POCOs
|
|
|
|
**Description**: Implement all persistence-ignorant POCO entity classes organized by domain area, with appropriate properties, navigation collections, and constructor invariants.
|
|
|
|
**Acceptance Criteria**:
|
|
- **Templates/**: `Template` (Id, Name, Description, ParentTemplateId, navigation to Attributes/Alarms/Scripts/Compositions), `TemplateAttribute` (Id, TemplateId, Name, Value, DataType, IsLocked, Description, DataSourceReference), `TemplateAlarm` (Id, TemplateId, Name, Description, PriorityLevel, IsLocked, TriggerType, TriggerConfig, OnTriggerScriptId), `TemplateScript` (Id, TemplateId, Name, IsLocked, Code, TriggerType, TriggerConfig, Parameters, ReturnDefinition, MinTimeBetweenRuns), `TemplateComposition` (Id, TemplateId, ComposedTemplateId, InstanceName).
|
|
- **Instances/**: `Instance` (Id, TemplateId, SiteId, AreaId, UniqueName, State), `InstanceAttributeOverride` (Id, InstanceId, AttributeName, OverrideValue), `InstanceConnectionBinding` (Id, InstanceId, AttributeName, DataConnectionId), `Area` (Id, SiteId, Name, ParentAreaId, navigation to children).
|
|
- **Sites/**: `Site` (Id, Name, SiteId), `DataConnection` (Id, Name, Protocol, Configuration), `SiteDataConnectionAssignment` (Id, SiteId, DataConnectionId).
|
|
- **ExternalSystems/**: `ExternalSystemDefinition` (Id, Name, EndpointUrl, AuthType, AuthConfig, RetryPolicy), `ExternalSystemMethod` (Id, ExternalSystemDefinitionId, Name, Parameters, ReturnDefinition), `DatabaseConnectionDefinition` (Id, Name, ConnectionString, RetryPolicy).
|
|
- **Notifications/**: `NotificationList` (Id, Name, navigation to recipients), `NotificationRecipient` (Id, NotificationListId, Name, EmailAddress), `SmtpConfiguration` (Id, Host, Port, AuthType, Credentials, FromAddress).
|
|
- **InboundApi/**: `ApiKey` (Id, Name, KeyValue, IsEnabled), `ApiMethod` (Id, Name, Script, ApprovedApiKeyIds, Parameters, ReturnDefinition, TimeoutSeconds).
|
|
- **Security/**: `LdapGroupMapping` (Id, LdapGroupName, Role), `SiteScopeRule` (Id, LdapGroupMappingId, SiteId).
|
|
- **Deployment/**: `DeploymentRecord` (Id, InstanceId, Status, DeploymentId, RevisionHash, DeployedBy, DeployedAt, CompletedAt), `SystemArtifactDeploymentRecord` (Id, ArtifactType, DeployedBy, DeployedAt, PerSiteStatus).
|
|
- **Scripts/**: `SharedScript` (Id, Name, Code, Parameters, ReturnDefinition).
|
|
- **Audit/**: `AuditLogEntry` (Id, User, Action, EntityType, EntityId, EntityName, AfterStateJson, Timestamp).
|
|
- All timestamp properties use `DateTimeOffset` (UTC).
|
|
- No EF attributes (`[Key]`, `[ForeignKey]`, etc.) on any POCO.
|
|
- No dependency on `Microsoft.EntityFrameworkCore` in the Commons `.csproj`.
|
|
- Navigation properties use `ICollection<T>` or `IReadOnlyCollection<T>`.
|
|
- Unit tests verify: timestamp properties are UTC-only (where enforced by constructor), no EF references in assembly metadata.
|
|
|
|
**Complexity**: L
|
|
|
|
**Requirements Traced**: [COM-3-1], [COM-3-2], [COM-3-3], [COM-3-4], [COM-3-5], [COM-3-6], [COM-3-7], [COM-3-8], [COM-3-9], [COM-3-10], [COM-3-11], [COM-3-12], [COM-3-13], [COM-5b-6], [COM-5b-10], [KDD-code-1], [CD-Commons-2]
|
|
|
|
---
|
|
|
|
### WP-0.5: Commons Repository Interfaces
|
|
|
|
**Description**: Define all per-component repository interfaces with method signatures matching the data needs of their consuming components. Interfaces accept and return POCOs, include `SaveChangesAsync()`, and have no EF dependency.
|
|
|
|
**Acceptance Criteria**:
|
|
- `ITemplateEngineRepository` with CRUD methods for templates, attributes, alarms, scripts, compositions, instances, overrides, connection bindings, areas. Includes `SaveChangesAsync()`.
|
|
- `IDeploymentManagerRepository` with methods for deployment records, deployed configuration snapshots, system-wide artifact deployment records. Includes `SaveChangesAsync()`.
|
|
- `ISecurityRepository` with methods for LDAP group mappings and site scope rules. Includes `SaveChangesAsync()`.
|
|
- `IInboundApiRepository` with methods for API keys and API method definitions. Includes `SaveChangesAsync()`.
|
|
- `IExternalSystemRepository` with methods for external system definitions, method definitions, and database connection definitions. Includes `SaveChangesAsync()`.
|
|
- `INotificationRepository` with methods for notification lists, recipients, and SMTP configuration. Includes `SaveChangesAsync()`.
|
|
- `ICentralUiRepository` with read-oriented query methods spanning multiple domain areas.
|
|
- All methods accept and return POCO types from `ScadaLink.Commons.Entities.*`.
|
|
- No `using` or reference to `Microsoft.EntityFrameworkCore.*` in any interface file.
|
|
- All interfaces are in `ScadaLink.Commons.Interfaces.Repositories` namespace.
|
|
- Interface names use `I` prefix.
|
|
|
|
**Complexity**: M
|
|
|
|
**Requirements Traced**: [COM-4-1], [COM-4-2], [COM-4-3], [COM-4-4], [COM-4-5], [COM-4-6], [COM-4-7], [COM-4-8], [COM-4-9], [COM-4-10], [COM-5b-4], [COM-5b-9], [KDD-code-2]
|
|
|
|
---
|
|
|
|
### WP-0.6: Commons Cross-Cutting Service Interfaces
|
|
|
|
**Description**: Define the `IAuditService` interface in Commons for cross-cutting audit logging.
|
|
|
|
**Acceptance Criteria**:
|
|
- `IAuditService` interface with `LogAsync(string user, string action, string entityType, int entityId, string entityName, object? afterState)` method (or equivalent signature).
|
|
- Located in `ScadaLink.Commons.Interfaces.Services` namespace.
|
|
- No dependency on Configuration Database or EF Core.
|
|
- Interface is callable by any central component without depending on the audit implementation.
|
|
|
|
**Complexity**: S
|
|
|
|
**Requirements Traced**: [COM-4a-1], [COM-4a-2], [COM-5b-5]
|
|
|
|
---
|
|
|
|
### WP-0.7: Commons Message Contracts
|
|
|
|
**Description**: Define all cross-component message contracts as record types organized by concern area. Establish the additive-only versioning convention with documentation.
|
|
|
|
**Acceptance Criteria**:
|
|
- **Deployment/**: Records for `DeployInstanceCommand`, `DeploymentStatusResponse`, `DeploymentValidationResult`, `FlattenedConfigurationSnapshot` (or similar).
|
|
- **Lifecycle/**: Records for `DisableInstanceCommand`, `EnableInstanceCommand`, `DeleteInstanceCommand`, `InstanceLifecycleResponse`.
|
|
- **Health/**: Records for `HealthCheckResult` (per-metric check outcome), `SiteStatusReport` (aggregated site health snapshot), `SiteHealthReport` (periodic report with script error rates, alarm evaluation error rates, S&F buffer depths), `HeartbeatMessage`.
|
|
- **Communication/**: Records for `SiteIdentity`, `ConnectionStateMessage`, `RoutingMetadata`.
|
|
- **Streaming/**: Records for `AttributeValueChanged` (instance name, attribute path, value, quality, timestamp) and `AlarmStateChanged` (instance name, alarm name, state, priority, timestamp).
|
|
- **DebugView/**: Records for `SubscribeDebugView`, `UnsubscribeDebugView`, `DebugViewSnapshot`, `DebugViewFilterCriteria`.
|
|
- **ScriptExecution/**: Records for `ScriptCallRequest` (with recursion depth), `ScriptCallResult`, `ScriptErrorResult`.
|
|
- **Artifacts/**: Records for `SharedScriptPackage`, `ExternalSystemDefinitionArtifact`, `DatabaseConnectionDefinitionArtifact`, `NotificationListDefinitionArtifact`.
|
|
- All message types are `record` types (immutable by default).
|
|
- No `Akka.*` references in Commons `.csproj` or any message file.
|
|
- All timestamp fields use `DateTimeOffset` (UTC).
|
|
- Message naming convention: commands, events, or responses (e.g., `DeployInstanceCommand`, `AttributeValueChanged`, `DeploymentStatusResponse`).
|
|
- A `VERSIONING.md` or code comment documents the additive-only evolution rules: no field removal, no type changes, new fields must have defaults, breaking changes require new types.
|
|
- Unit tests verify: all message types are records, all have `init`-only or constructor-set properties (immutability check).
|
|
- Unit tests verify forward/backward compatibility convention: a representative message contract can be serialized to JSON then deserialized with an extra unknown field (forward compat) and with an optional field missing (backward compat) without error. This validates the structural design supports [COM-5a-2].
|
|
|
|
**Complexity**: M
|
|
|
|
**Requirements Traced**: [COM-5-1], [COM-5-2], [COM-5-3], [COM-5-4], [COM-5-5], [COM-5-6], [COM-5-7], [COM-5-8], [COM-5-9], [COM-5-10], [COM-5a-1], [COM-5a-2], [COM-5a-3], [COM-5b-7], [COM-5b-11], [KDD-code-4]
|
|
|
|
---
|
|
|
|
### WP-0.8: Commons Protocol Abstraction
|
|
|
|
**Description**: Define the `IDataConnection` interface and related types for the Data Connection Layer's protocol abstraction.
|
|
|
|
**Acceptance Criteria**:
|
|
- `IDataConnection` interface with methods for: connect, disconnect, subscribe to tag paths, unsubscribe, read tag value, write tag value.
|
|
- Related types in `Interfaces/Protocol/`: `TagIdentifier` (tag path), `TagValue` (value + quality + timestamp), `ReadResult` (value or error), `WriteResult` (success/failure), `SubscriptionCallback` (delegate or interface for value change notifications), `ConnectionStatus` enum (mirrors `ConnectionHealth`: Connected, Disconnected, Connecting, Error), `QualityCode` enum (Good, Bad, Uncertain, etc.).
|
|
- No protocol-specific references (no OPC UA types, no gRPC types) — pure abstraction.
|
|
- Located in `ScadaLink.Commons.Interfaces.Protocol` namespace.
|
|
- All timestamp fields use `DateTimeOffset` (UTC).
|
|
|
|
**Complexity**: S
|
|
|
|
**Requirements Traced**: [COM-2-1], [COM-2-2], [COM-2-3], [COM-5b-3]
|
|
|
|
---
|
|
|
|
### WP-0.9: Commons Architectural Constraint Enforcement
|
|
|
|
**Description**: Verify and enforce that Commons has no business logic and minimal dependencies through tests and project configuration.
|
|
|
|
**Acceptance Criteria**:
|
|
- Commons `.csproj` references only `System.*` and optionally `Microsoft.Extensions.Primitives`. No other package references.
|
|
- An architectural test (using reflection or a test library) verifies:
|
|
- No classes in Commons implement business logic (no service classes, no actor classes).
|
|
- No reference to `Akka.*`, `Microsoft.AspNetCore.*`, or `Microsoft.EntityFrameworkCore.*` assemblies.
|
|
- No reference to paid-license third-party packages.
|
|
- All method bodies in entity classes are limited to: constructors (invariant enforcement), factory methods, property getters/setters, `ToString()` overrides, equality comparisons.
|
|
- Test validates that no class in Commons has methods with complex logic (heuristic: methods with more than a configurable line threshold, excluding property accessors).
|
|
|
|
**Complexity**: S
|
|
|
|
**Requirements Traced**: [COM-6-1], [COM-6-2], [COM-6-3], [COM-7-1], [COM-7-2], [COM-7-3], [COM-7-4], [COM-7-5]
|
|
|
|
---
|
|
|
|
### WP-0.10: Host Skeleton with Role-Based Startup
|
|
|
|
**Description**: Implement the Host `Program.cs` skeleton that reads node role from configuration and branches into WebApplication (central) or generic Host (site) startup paths. Wire the extension method convention with stub `AddXxx()` calls for all components, conditional on role.
|
|
|
|
**Acceptance Criteria**:
|
|
- `Program.cs` reads `ScadaLink:Node:Role` from configuration.
|
|
- When role is `Central`: uses `WebApplication.CreateBuilder`, calls `AddXxx()` for shared + central-only components, calls `MapCentralUI()` and `MapInboundAPI()` stubs.
|
|
- When role is `Site`: uses `Host.CreateDefaultBuilder`, calls `AddXxx()` for shared + site-only components. Does **not** configure Kestrel, HTTP, or any web middleware.
|
|
- Component registration follows the registration matrix exactly (14 components + ConfigurationDatabase on central).
|
|
- Configuration binding: `services.Configure<NodeOptions>(config.GetSection("ScadaLink:Node"))` and equivalent for all component sections.
|
|
- Each of the 15 component library projects exposes at minimum an `AddXxx()` extension method on `IServiceCollection` (can be empty body for Phase 0).
|
|
- Each component that has actors (per registration matrix: ClusterInfrastructure, Communication, HealthMonitoring, ExternalSystemGateway, NotificationService, TemplateEngine, DeploymentManager, Security, SiteRuntime, DataConnectionLayer, StoreAndForward, SiteEventLogging) exposes an `AddXxxActors()` stub extension method. The method signature accepts the Akka configuration builder type (or a placeholder interface if Akka.Hosting is not yet referenced) and has an empty body in Phase 0.
|
|
- CentralUI and InboundAPI expose `MapCentralUI()` and `MapInboundAPI()` stub extension methods on `WebApplication` (or `IEndpointRouteBuilder`).
|
|
- Host `Program.cs` calls `AddXxxActors()` stubs for applicable components (conditional on role), and calls `MapCentralUI()`/`MapInboundAPI()` on central.
|
|
- Host compiles and runs to completion with a minimal `appsettings.json` for both central and site roles.
|
|
- Site-role startup does not open any network port (verified by test or manual check).
|
|
- Unit test: host starts with central role config and does not throw; host starts with site role config and does not throw.
|
|
|
|
**Complexity**: M
|
|
|
|
**Requirements Traced**: [HOST-1-1], [HOST-1-2], [HOST-1-3], [HOST-2-1], [HOST-2-2], [HOST-2-3], [HOST-2-4], [HOST-2-5], [HOST-2-6], [HOST-7-1], [HOST-7-2], [HOST-7-3], [HOST-10-1], [HOST-10-2], [HOST-10-3], [HOST-10-4], [HOST-10-5], [CD-Host-1], [CD-Host-2], [CD-Host-3]
|
|
|
|
---
|
|
|
|
### WP-0.11: Per-Component Options Classes
|
|
|
|
**Description**: Create strongly-typed options classes in each component project, matching the configuration sections defined in REQ-HOST-3. Wire binding in Host `Program.cs`.
|
|
|
|
**Acceptance Criteria**:
|
|
- `NodeOptions` in Host project: `Role` (string/enum), `NodeHostname` (string), `SiteId` (string), `RemotingPort` (int).
|
|
- `ClusterOptions` in ClusterInfrastructure project: `SeedNodes` (list), `SplitBrainResolverStrategy`, `StableAfter`, `HeartbeatInterval`, `FailureDetectionThreshold`, `MinNrOfMembers`.
|
|
- `DatabaseOptions` in Host project: `ConfigurationDb` (string), `MachineDataDb` (string), SQLite paths.
|
|
- `DataConnectionOptions` in DataConnectionLayer project: `ReconnectInterval`, `TagResolutionRetryInterval`, `WriteTimeout`.
|
|
- `StoreAndForwardOptions` in StoreAndForward project: `SqliteDbPath`, `ReplicationEnabled`.
|
|
- `HealthMonitoringOptions` in HealthMonitoring project: `ReportInterval`, `OfflineTimeout`.
|
|
- `SiteEventLogOptions` in SiteEventLogging project: `RetentionDays`, `MaxStorageMb`, `PurgeScheduleCron`.
|
|
- `CommunicationOptions` in Communication project: `DeploymentTimeout`, `LifecycleTimeout`, `QueryTimeout`, `TransportHeartbeatInterval`, `TransportFailureThreshold`.
|
|
- `SecurityOptions` in Security project: `LdapServer`, `LdapPort`, `LdapUseTls`, `JwtSigningKey`, `JwtExpiryMinutes`, `IdleTimeoutMinutes`.
|
|
- `InboundApiOptions` in InboundApi project: `DefaultMethodTimeout`.
|
|
- `NotificationOptions` in NotificationService project (minimal — SMTP config is in config DB).
|
|
- `LoggingOptions` in Host project: Serilog sink configuration, log level overrides.
|
|
- All options classes are plain POCOs with public properties.
|
|
- Options classes live in their respective component projects, not in Commons.
|
|
- Host `Program.cs` binds all sections via `services.Configure<T>()`.
|
|
- Architectural test: no component library project (excluding Host) contains any `using` of `Microsoft.Extensions.Configuration` or accepts `IConfiguration` in its `AddXxx()` method signature. Components access configuration only via `IOptions<T>` / `IOptionsSnapshot<T>`.
|
|
|
|
**Complexity**: M
|
|
|
|
**Requirements Traced**: [HOST-3-1], [HOST-3-2], [HOST-3-3], [HOST-3-4], [HOST-3-5], [HOST-3-6], [KDD-code-5], [KDD-code-6]
|
|
|
|
---
|
|
|
|
### WP-0.12: Local Dev Topology Documentation & Sample Configuration
|
|
|
|
**Description**: Create sample `appsettings.json` files for central and site roles demonstrating the full configuration structure. Document the local development topology.
|
|
|
|
**Acceptance Criteria**:
|
|
- `appsettings.Central.json` with: `ScadaLink:Node` (Role=Central, NodeHostname, RemotingPort), `ScadaLink:Cluster` (seed nodes for 2-node central), `ScadaLink:Database` (ConfigurationDb and MachineDataDb connection strings pointing to local Docker SQL Server), and all per-component sections with sensible defaults.
|
|
- `appsettings.Site.json` with: `ScadaLink:Node` (Role=Site, NodeHostname, SiteId, RemotingPort), `ScadaLink:Cluster` (seed nodes for 2-node site), `ScadaLink:Database` (SQLite paths), and all per-component sections with sensible defaults.
|
|
- Both files are valid JSON and the Host loads them without error.
|
|
- A brief topology comment block or accompanying doc section explains: 2-node central cluster, 2-node site cluster, what ports are used, how to run locally with different roles.
|
|
|
|
**Complexity**: S
|
|
|
|
**Requirements Traced**: [HOST-1-2], [HOST-3-2], [HOST-3-3]
|
|
|
|
---
|
|
|
|
## 6. Test Strategy
|
|
|
|
### Unit Tests
|
|
|
|
| Area | Tests | Work Package |
|
|
|------|-------|-------------|
|
|
| `Result<T>` | Success construction, error construction, map/bind, pattern matching | WP-0.3 |
|
|
| `RetryPolicy` | Immutability, default values | WP-0.3 |
|
|
| Enums | All enum values present and correctly named (singular) | WP-0.3 |
|
|
| Entity POCOs | No EF attributes via reflection, timestamp properties are `DateTimeOffset`, navigation properties are `ICollection<T>` | WP-0.4 |
|
|
| Repository interfaces | No EF references in assembly, all include `SaveChangesAsync` | WP-0.5 |
|
|
| Message contracts | All are record types, all timestamp fields are `DateTimeOffset`, immutability check | WP-0.7 |
|
|
| Protocol abstraction | No protocol-specific type references | WP-0.8 |
|
|
| Architectural constraints | Commons has no forbidden dependencies, no business logic classes | WP-0.9 |
|
|
| Host startup | Central role boots without error, site role boots without error | WP-0.10 |
|
|
| Options classes | All options classes are POCOs, none in Commons project | WP-0.11 |
|
|
|
|
### Integration Tests
|
|
|
|
| Area | Tests | Work Package |
|
|
|------|-------|-------------|
|
|
| Solution build | `dotnet build` zero errors, zero warnings | WP-0.1 |
|
|
| Host central boot | Host starts with central appsettings, binds all config sections, no crash | WP-0.10, WP-0.12 |
|
|
| Host site boot | Host starts with site appsettings, binds all config sections, no crash, no HTTP listener | WP-0.10, WP-0.12 |
|
|
|
|
### Negative Tests
|
|
|
|
| Requirement | Negative Test | Work Package |
|
|
|-------------|--------------|-------------|
|
|
| [COM-3-4] No EF dependency | Reflection test: Commons assembly does not reference EF Core | WP-0.9 |
|
|
| [COM-5-10] No Akka dependency | Reflection test: Commons assembly does not reference Akka | WP-0.9 |
|
|
| [COM-6-2] No business logic | Scan for service/actor classes in Commons — expect none | WP-0.9 |
|
|
| [COM-7-2] No Akka packages | Verify Commons `.csproj` has no Akka PackageReference | WP-0.9 |
|
|
| [COM-7-3] No ASP.NET packages | Verify Commons `.csproj` has no ASP.NET PackageReference | WP-0.9 |
|
|
| [COM-7-4] No EF packages | Verify Commons `.csproj` has no EF PackageReference | WP-0.9 |
|
|
| [HOST-1-3] No conditional compilation | Verify no `#if` directives in Host project | WP-0.10 |
|
|
| [HOST-2-6] Non-applicable components not registered | Site boot does not register central-only services; central boot does not register site-only services | WP-0.10 |
|
|
| [HOST-7-3] Site nodes no HTTP | Site boot does not listen on any port | WP-0.10 |
|
|
| [HOST-3-6] Components never read IConfiguration directly | No component library `AddXxx()` method accepts `IConfiguration`; no `using Microsoft.Extensions.Configuration` in component libraries | WP-0.11 |
|
|
| [COM-1-12] / [13.1-3] No timezone conversion outside UI | No `ToLocalTime()` calls in Commons or any non-UI component | WP-0.9 |
|
|
|
|
---
|
|
|
|
## 7. Verification Gate
|
|
|
|
Phase 0 is complete when all of the following pass:
|
|
|
|
1. `dotnet build ScadaLink.slnx` completes with zero errors and zero warnings.
|
|
2. `dotnet test ScadaLink.slnx` passes all unit and integration tests.
|
|
3. Host boots successfully in central role from `appsettings.Central.json` and exits cleanly.
|
|
4. Host boots successfully in site role from `appsettings.Site.json` and exits cleanly.
|
|
5. Site-role Host does not open any network port.
|
|
6. All 17 component projects compile with correct references to Commons.
|
|
7. Commons project has zero non-core-NET package references.
|
|
8. All architectural constraint tests pass (no EF, no Akka, no ASP.NET in Commons).
|
|
9. All entity POCOs use `DateTimeOffset` for timestamp fields.
|
|
10. All message contracts are record types.
|
|
11. Every item in the Requirements Checklist (Section 3) and Design Constraints Checklist (Section 4) maps to a work package with acceptance criteria.
|
|
|
|
---
|
|
|
|
## 8. Open Questions
|
|
|
|
| # | Question | Context | Impact | Status |
|
|
|---|----------|---------|--------|--------|
|
|
| Q16 | Should `Result<T>` use a OneOf-style library or be hand-rolled? | Affects COM-7-1 (minimal dependencies). A hand-rolled `Result<T>` keeps zero external dependencies. | Phase 0. | Recommend hand-rolled to maintain zero-dependency constraint. Log for implementer's decision. |
|
|
| Q17 | Should entity POCO properties be required (init-only) or settable? | EF Core Fluent API mapping may need settable properties. POCOs must be persistence-ignorant but still mappable by Phase 1. | Phase 0 / Phase 1 boundary. | Recommend `{ get; set; }` for EF compatibility, with constructor invariants for required fields. Log for implementer. |
|
|
| Q18 | What `QualityCode` values should the protocol abstraction define? | OPC UA has a rich quality model (Good, Uncertain, Bad with subtypes). Need to decide on a simplified shared set. | Phase 0. | Recommend: Good, Bad, Uncertain as the minimal set, with room to extend. |
|
|
| Q19 | Should `IDataConnection` be `IAsyncDisposable` for connection cleanup? | Affects DCL connection actor lifecycle. | Phase 0 / Phase 3B boundary. | Recommend yes — add `IAsyncDisposable` to support proper cleanup. |
|
|
|
|
These questions have been added to `docs/plans/questions.md`.
|
|
|
|
---
|
|
|
|
## 9. Post-Generation Verification (Orphan Check)
|
|
|
|
### Forward Check: Requirements → Work Packages
|
|
|
|
Every item in the Requirements Checklist (Section 3) and Design Constraints Checklist (Section 4) has been verified against work package mappings:
|
|
|
|
| Requirement ID(s) | Work Package | Verified |
|
|
|-------------------|-------------|----------|
|
|
| [13.1-1], [13.1-2], [13.1-3] | WP-0.3 (UTC in type system), WP-0.4 (DateTimeOffset on entities), WP-0.7 (DateTimeOffset on messages) | Yes |
|
|
| [COM-1-1] through [COM-1-12] | WP-0.3 | Yes |
|
|
| [COM-2-1], [COM-2-2], [COM-2-3] | WP-0.8 | Yes |
|
|
| [COM-3-1] through [COM-3-13] | WP-0.4 | Yes |
|
|
| [COM-4-1] through [COM-4-10] | WP-0.5 | Yes |
|
|
| [COM-4a-1], [COM-4a-2] | WP-0.6 | Yes |
|
|
| [COM-5-1] through [COM-5-10] | WP-0.7 | Yes |
|
|
| [COM-5a-1] through [COM-5a-3] | WP-0.7 | Yes |
|
|
| [COM-5a-4] | Explicitly deferred to Phase 1/3A (Akka serialization binding). Noted in plan; no Phase 0 work package. | Yes (deferred) |
|
|
| [COM-5b-1] through [COM-5b-12] | WP-0.2, WP-0.3, WP-0.4, WP-0.5, WP-0.6, WP-0.7, WP-0.8 | Yes |
|
|
| [COM-6-1] through [COM-6-3] | WP-0.9 | Yes |
|
|
| [COM-7-1] through [COM-7-5] | WP-0.9 | Yes |
|
|
| [HOST-1-1] through [HOST-1-3] | WP-0.1, WP-0.10 | Yes |
|
|
| [HOST-2-1] through [HOST-2-6] | WP-0.10 | Yes |
|
|
| [HOST-3-1] through [HOST-3-6] | WP-0.11 | Yes |
|
|
| [HOST-7-1] through [HOST-7-3] | WP-0.10 | Yes |
|
|
| [HOST-10-1] through [HOST-10-5] | WP-0.10 | Yes |
|
|
| [KDD-data-6] | WP-0.3, WP-0.4, WP-0.7 | Yes |
|
|
| [KDD-code-1] | WP-0.4 (POCOs), WP-0.9 (no EF) | Yes |
|
|
| [KDD-code-2] | WP-0.5 (interfaces), WP-0.9 (no EF) | Yes |
|
|
| [KDD-code-3] | WP-0.2 | Yes |
|
|
| [KDD-code-4] | WP-0.7 | Yes |
|
|
| [KDD-code-5] | WP-0.11 | Yes |
|
|
| [KDD-code-6] | WP-0.11 | Yes |
|
|
| [CD-Commons-1] | WP-0.1 | Yes |
|
|
| [CD-Commons-2] | WP-0.4 | Yes |
|
|
| [CD-Commons-3] | WP-0.5 (interface contract; implementation deferred) | Yes |
|
|
| [CD-Host-1] | WP-0.1, WP-0.10 | Yes |
|
|
| [CD-Host-2] | WP-0.10 (ConfigurationDatabase in Host AddXxx() call chain) | Yes |
|
|
| [CD-Host-3] | WP-0.10 | Yes |
|
|
| [Q1], [Q3], [Q4] | WP-0.1 | Yes |
|
|
|
|
**Result**: All requirements and design constraints map to at least one work package. **No orphans found.**
|
|
|
|
### Reverse Check: Work Packages → Requirements
|
|
|
|
| Work Package | Requirements Traced | Has Source Requirement | Verified |
|
|
|-------------|--------------------|-----------------------|----------|
|
|
| WP-0.1 | HOST-1-1, HOST-1-3, CD-Host-1, CD-Commons-1, Q1, Q3 | Yes | Yes |
|
|
| WP-0.2 | COM-5b-1 through COM-5b-8, KDD-code-3 | Yes | Yes |
|
|
| WP-0.3 | COM-1-1 through COM-1-12, COM-5b-2, COM-5b-12, 13.1-1 through 13.1-3, KDD-data-6 | Yes | Yes |
|
|
| WP-0.4 | COM-3-1 through COM-3-13, COM-5b-6, COM-5b-10, KDD-code-1, CD-Commons-2 | Yes | Yes |
|
|
| WP-0.5 | COM-4-1 through COM-4-10, COM-5b-4, COM-5b-9, KDD-code-2 | Yes | Yes |
|
|
| WP-0.6 | COM-4a-1, COM-4a-2, COM-5b-5 | Yes | Yes |
|
|
| WP-0.7 | COM-5-1 through COM-5-10, COM-5a-1 through COM-5a-4, COM-5b-7, COM-5b-11, KDD-code-4 | Yes | Yes |
|
|
| WP-0.8 | COM-2-1, COM-2-2, COM-2-3, COM-5b-3 | Yes | Yes |
|
|
| WP-0.9 | COM-6-1 through COM-6-3, COM-7-1 through COM-7-5 | Yes | Yes |
|
|
| WP-0.10 | HOST-1-1 through HOST-1-3, HOST-2-1 through HOST-2-6, HOST-7-1 through HOST-7-3, HOST-10-1 through HOST-10-5, CD-Host-1, CD-Host-2, CD-Host-3 | Yes | Yes |
|
|
| WP-0.11 | HOST-3-1 through HOST-3-6, KDD-code-5, KDD-code-6 | Yes | Yes |
|
|
| WP-0.12 | HOST-1-2, HOST-3-2, HOST-3-3 | Yes | Yes |
|
|
|
|
**Result**: All work packages trace to source requirements. **No untraceable work.**
|
|
|
|
### Split-Section Check
|
|
|
|
Phase 0 covers only HighLevelReqs section 13.1 (Timestamps). This section is **not split** across phases — Phase 0 owns it entirely. All three bullets ([13.1-1], [13.1-2], [13.1-3]) are covered.
|
|
|
|
Phase 0 covers REQ-COM and REQ-HOST requirements. The following are split with other phases:
|
|
|
|
| REQ ID | Phase 0 Scope | Other Phase(s) Scope |
|
|
|--------|---------------|---------------------|
|
|
| REQ-COM-2 | Interface definition only | Phase 3B: OPC UA and LmxProxy implementations |
|
|
| REQ-COM-4a | Interface definition only | Phase 1: `IAuditService` implementation in Configuration Database |
|
|
| REQ-COM-5a-4 | Noted in plan; versioning rules documented | Phase 1/3A: Akka serialization binding configuration |
|
|
| REQ-HOST-2 | Skeleton role branching with stub `AddXxx()` calls | Phase 1: Full service registration with real implementations |
|
|
| REQ-HOST-3 | Options classes created and bound | Phase 1: Startup validation of option values (REQ-HOST-4) |
|
|
| REQ-HOST-7 | WebApplication vs generic Host branching | Phase 1: Actual web endpoint mapping |
|
|
|
|
**Result**: No unowned bullets. All split items have clear phase ownership.
|
|
|
|
### Negative Requirement Check
|
|
|
|
| Negative Requirement | Acceptance Criterion | Adequate |
|
|
|---------------------|---------------------|----------|
|
|
| [COM-2-3] No protocol-specific references | WP-0.8: "No protocol-specific references" in AC | Yes |
|
|
| [COM-3-4] No EF dependency on POCOs | WP-0.4 + WP-0.9: reflection test on assembly refs | Yes |
|
|
| [COM-4-10] Repository interfaces no EF | WP-0.5: no EF `using` or reference check | Yes |
|
|
| [COM-5-9] Messages must be record/immutable (no mutable) | WP-0.7: unit test verifies all are records | Yes |
|
|
| [COM-5-10] Commons no Akka dependency | WP-0.9: reflection test | Yes |
|
|
| [COM-5a-1] No field removal, no type changes | WP-0.7: versioning rules documented | Yes (convention; runtime enforcement N/A at compile time) |
|
|
| [COM-6-2] No business logic/services/actors | WP-0.9: scan for service/actor classes | Yes |
|
|
| [COM-7-2] No Akka packages | WP-0.9: csproj check | Yes |
|
|
| [COM-7-3] No ASP.NET packages | WP-0.9: csproj check | Yes |
|
|
| [COM-7-4] No EF packages | WP-0.9: csproj check | Yes |
|
|
| [COM-7-5] No paid-license packages | WP-0.9: csproj check | Yes |
|
|
| [HOST-1-3] No separate build targets/conditional compilation | WP-0.10: no `#if` directives check | Yes |
|
|
| [HOST-2-6] Non-applicable components not registered | WP-0.10: site boot test verifies no central services registered | Yes |
|
|
| [HOST-3-6] Components never read IConfiguration directly | WP-0.11: architectural test verifies no component library uses `Microsoft.Extensions.Configuration` or accepts `IConfiguration` in `AddXxx()` | Yes |
|
|
| [HOST-7-3] Site nodes never accept HTTP | WP-0.10: site boot no-port check | Yes |
|
|
| [COM-1-12] / [13.1-3] No timezone conversion outside UI | WP-0.9: no `ToLocalTime()` calls in non-UI code | Yes |
|
|
|
|
**Result**: All negative requirements have corresponding acceptance criteria that would catch violations. **No weak checks identified.**
|
|
|
|
---
|
|
|
|
## Codex MCP Verification
|
|
|
|
**Model**: gpt-5.4
|
|
**Date**: 2026-03-16
|
|
|
|
### Step 1: Requirements Coverage Review
|
|
|
|
Codex identified 10 findings. Disposition:
|
|
|
|
| # | Finding | Disposition |
|
|
|---|---------|------------|
|
|
| 1 | Project count inconsistency (17 component projects + 1 Host = 18) | **Corrected.** WP-0.1 now explicitly lists 15 component library projects + 1 Commons + 1 Host = 17 total source projects. The "17 components" in CLAUDE.md includes Host and Commons in the count. |
|
|
| 2 | COM-5a-4 (Akka serialization binding) not covered by Phase 0 work package | **Acknowledged.** Correctly deferred to Phase 1/3A. Forward check updated to mark as explicitly deferred. COM-5a-4 requires Akka.NET which Phase 0 does not introduce. |
|
|
| 3 | 13.1-2 partially covered (event log and S&F timestamps) | **Dismissed.** Phase 0 establishes the UTC convention in the type system and on all entity/message timestamp fields. Specific event log and S&F entities created in Phase 0 (AuditLogEntry, DeploymentRecord, etc.) already use DateTimeOffset. The convention applies system-wide; later phases creating additional timestamp-bearing types must follow it. |
|
|
| 4 | COM-2-2 missing ReadResult and ConnectionStatus enum in WP-0.8 | **Corrected.** WP-0.8 acceptance criteria now include `ReadResult` and `ConnectionStatus` enum. |
|
|
| 5 | COM-5-3 missing HealthCheckResult and SiteStatusReport DTOs | **Corrected.** WP-0.7 Health section now requires `HealthCheckResult`, `SiteStatusReport`, `SiteHealthReport`, and `HeartbeatMessage`. |
|
|
| 6 | HOST-10-2 (AddXxxActors stubs) not in WP-0.10 acceptance criteria | **Corrected.** WP-0.10 now explicitly requires `AddXxxActors()` stub extension methods for all actor-bearing components, and `MapXxx()` stubs for CentralUI/InboundAPI. Host Program.cs calls them. |
|
|
| 7 | HOST-3-6 (no IConfiguration in components) not testable | **Corrected.** WP-0.11 now includes an architectural test: no component library uses `Microsoft.Extensions.Configuration` or accepts `IConfiguration` in its `AddXxx()` signature. Added to negative tests table. |
|
|
| 8 | CD-Host-2 weakly traced to WP-0.12 (sample configs) | **Corrected.** CD-Host-2 retraced to WP-0.10 (Host skeleton includes ConfigurationDatabase `AddConfigurationDatabase()` in its call chain). |
|
|
| 9 | COM-1-9 thread safety not explicitly verified | **Dismissed.** Immutable record types are inherently thread-safe in .NET. WP-0.3 AC updated to state "immutable and thread-safe (record types — immutability guarantees thread safety)." No additional runtime thread-safety test needed for data-only types. |
|
|
| 10 | COM-5a-1 through COM-5a-3 only documented, not tested | **Corrected.** WP-0.7 now includes a JSON serialization round-trip test verifying forward compatibility (unknown fields tolerated) and backward compatibility (missing optional fields tolerated). Structural enforcement at Phase 0; full Akka serialization testing in Phase 1/3A. |
|
|
|
|
### Step 2: Negative Requirement Review
|
|
|
|
Not submitted separately — negative requirements were reviewed as part of Step 1 findings. All negative requirement acceptance criteria were evaluated as adequate by Codex (no findings on negative tests specifically).
|
|
|
|
### Step 3: Split-Section Gap Review
|
|
|
|
Phase 0 covers HighLevelReqs 13.1 exclusively (not split). No split-section review needed for this phase.
|
|
|
|
**Outcome**: Pass with corrections. All 10 findings addressed (7 corrected, 3 dismissed with rationale).
|