186 lines
7.3 KiB
Markdown
186 lines
7.3 KiB
Markdown
# Deploy Artifacts to Sites — Remove Config DB Dependency
|
|
|
|
> **For Claude:** REQUIRED SUB-SKILL: Use superpowers-extended-cc:executing-plans to implement this plan task-by-task.
|
|
|
|
**Goal:** Make site servers fully self-contained by reading external system, notification, and data connection configs from local SQLite instead of the central config DB.
|
|
|
|
**Architecture:** The artifact deployment pipeline already exists (`DeployArtifactsCommand` → `DeploymentManagerActor` → `SiteStorageService`). The gap is that runtime services still query the config DB. We create site-local repository implementations backed by SQLite, wire them into DI, add a UI button to trigger deployment, and extend artifacts to include data connections.
|
|
|
|
**Tech Stack:** C#, SQLite (Microsoft.Data.Sqlite), Blazor Server, Akka.NET messaging
|
|
|
|
---
|
|
|
|
### Task 1: Create SiteExternalSystemRepository
|
|
|
|
**Files:**
|
|
- Create: `src/ScadaLink.SiteRuntime/Repositories/SiteExternalSystemRepository.cs`
|
|
|
|
**Step 1:** Create `SiteExternalSystemRepository` implementing `IExternalSystemRepository`. Read-only methods query `SiteStorageService` SQLite tables. Write methods throw `NotSupportedException` (site is read-only for these configs).
|
|
|
|
```csharp
|
|
// Key methods to implement:
|
|
// GetAllExternalSystemsAsync → query external_systems table, deserialize method_definitions JSON
|
|
// GetMethodsByExternalSystemIdAsync → parse method_definitions from external_systems row
|
|
// GetAllDatabaseConnectionsAsync → query database_connections table
|
|
// All Add/Update/Delete methods → throw NotSupportedException("Managed via artifact deployment")
|
|
```
|
|
|
|
The `external_systems` table stores `method_definitions` as JSON. Parse it into `List<ExternalSystemMethod>` on read. The `ExternalSystemDefinition` entity needs Id, Name, EndpointUrl, AuthType, AuthConfiguration. Map the `name` column to a synthetic Id (hash or sequential).
|
|
|
|
**Step 2:** Build and verify no compile errors.
|
|
|
|
**Step 3:** Commit: `feat: add SiteExternalSystemRepository backed by SQLite`
|
|
|
|
---
|
|
|
|
### Task 2: Create SiteNotificationRepository
|
|
|
|
**Files:**
|
|
- Create: `src/ScadaLink.SiteRuntime/Repositories/SiteNotificationRepository.cs`
|
|
|
|
**Step 1:** Create `SiteNotificationRepository` implementing `INotificationRepository`. Read-only methods query `SiteStorageService` SQLite tables.
|
|
|
|
```csharp
|
|
// Key methods:
|
|
// GetListByNameAsync → query notification_lists by name
|
|
// GetRecipientsByListIdAsync → parse recipient_emails JSON from notification_lists row
|
|
// GetAllSmtpConfigurationsAsync → needs new smtp_configurations SQLite table
|
|
// All Add/Update/Delete → throw NotSupportedException
|
|
```
|
|
|
|
**Step 2:** Add `smtp_configurations` table to `SiteStorageService.InitializeAsync()`:
|
|
|
|
```sql
|
|
CREATE TABLE IF NOT EXISTS smtp_configurations (
|
|
name TEXT PRIMARY KEY,
|
|
server TEXT NOT NULL,
|
|
port INTEGER NOT NULL,
|
|
auth_mode TEXT NOT NULL,
|
|
from_address TEXT NOT NULL,
|
|
username TEXT,
|
|
password TEXT,
|
|
oauth_config TEXT,
|
|
updated_at TEXT NOT NULL
|
|
);
|
|
```
|
|
|
|
**Step 3:** Add `StoreSmtpConfigurationAsync` method to `SiteStorageService`.
|
|
|
|
**Step 4:** Build and verify.
|
|
|
|
**Step 5:** Commit: `feat: add SiteNotificationRepository and SMTP storage`
|
|
|
|
---
|
|
|
|
### Task 3: Add data connections to DeployArtifactsCommand
|
|
|
|
**Files:**
|
|
- Modify: `src/ScadaLink.Commons/Messages/Artifacts/DeployArtifactsCommand.cs`
|
|
- Modify: `src/ScadaLink.SiteRuntime/Actors/DeploymentManagerActor.cs` (HandleDeployArtifacts)
|
|
- Modify: `src/ScadaLink.SiteRuntime/Persistence/SiteStorageService.cs`
|
|
|
|
**Step 1:** Add `DataConnectionArtifact` record and include it in `DeployArtifactsCommand`:
|
|
|
|
```csharp
|
|
public record DataConnectionArtifact(
|
|
string Name, string Protocol, string? ConfigurationJson);
|
|
|
|
// Add to DeployArtifactsCommand:
|
|
IReadOnlyList<DataConnectionArtifact>? DataConnections
|
|
```
|
|
|
|
**Step 2:** Add `data_connection_definitions` table to `SiteStorageService.InitializeAsync()`:
|
|
|
|
```sql
|
|
CREATE TABLE IF NOT EXISTS data_connection_definitions (
|
|
name TEXT PRIMARY KEY,
|
|
protocol TEXT NOT NULL,
|
|
configuration TEXT,
|
|
updated_at TEXT NOT NULL
|
|
);
|
|
```
|
|
|
|
**Step 3:** Add `StoreDataConnectionDefinitionAsync` and `GetAllDataConnectionDefinitionsAsync` to `SiteStorageService`.
|
|
|
|
**Step 4:** Update `DeploymentManagerActor.HandleDeployArtifacts` to persist data connections.
|
|
|
|
**Step 5:** Update `HandleDeployArtifacts` SMTP config storage (add to the existing handler alongside external systems and db connections).
|
|
|
|
**Step 6:** Build and verify.
|
|
|
|
**Step 7:** Commit: `feat: include data connections and SMTP in artifact deployment`
|
|
|
|
---
|
|
|
|
### Task 4: Wire site-local repositories into DI
|
|
|
|
**Files:**
|
|
- Modify: `src/ScadaLink.Host/Program.cs` (Site role, lines ~155-160)
|
|
- Modify: `src/ScadaLink.Host/appsettings.Site.json`
|
|
- Modify: `src/ScadaLink.SiteRuntime/ServiceCollectionExtensions.cs`
|
|
|
|
**Step 1:** In `ServiceCollectionExtensions.AddSiteRuntime()`, register the site-local repositories:
|
|
|
|
```csharp
|
|
services.AddScoped<IExternalSystemRepository, SiteExternalSystemRepository>();
|
|
services.AddScoped<INotificationRepository, SiteNotificationRepository>();
|
|
```
|
|
|
|
**Step 2:** Remove `AddConfigurationDatabase` call from the Site role in `Program.cs`. Remove the `ConfigurationDb` connection string check.
|
|
|
|
**Step 3:** Remove `ConfigurationDb` from `appsettings.Site.json`.
|
|
|
|
**Step 4:** Build and verify — site should start without SQL Server.
|
|
|
|
**Step 5:** Commit: `feat: wire site-local repos, remove config DB dependency from Site`
|
|
|
|
---
|
|
|
|
### Task 5: Add Deploy Artifacts button to Sites admin page
|
|
|
|
**Files:**
|
|
- Modify: `src/ScadaLink.CentralUI/Components/Pages/Admin/Sites.razor`
|
|
|
|
**Step 1:** Inject `ArtifactDeploymentService` and add a "Deploy Artifacts" button in each site's action column (next to Edit/Delete).
|
|
|
|
**Step 2:** Add handler method that:
|
|
- Collects all external systems, db connections, notification lists, SMTP configs, shared scripts, and data connections from config DB repositories
|
|
- Builds a `DeployArtifactsCommand`
|
|
- Calls `ArtifactDeploymentService.DeployToAllSitesAsync` (or per-site variant)
|
|
- Shows success/failure toast
|
|
|
|
**Step 3:** Add a "Deploy Artifacts to All Sites" button in the page header for bulk deployment.
|
|
|
|
**Step 4:** Build and verify UI renders.
|
|
|
|
**Step 5:** Commit: `feat: add Deploy Artifacts button to Sites admin page`
|
|
|
|
---
|
|
|
|
### Task 6: Update ArtifactDeploymentService to include all artifact types
|
|
|
|
**Files:**
|
|
- Modify: `src/ScadaLink.DeploymentManager/ArtifactDeploymentService.cs`
|
|
|
|
**Step 1:** Inject `ISiteRepository` (for data connections) and `INotificationRepository` (for SMTP configs). Update the command-building logic to include:
|
|
- Data connections from `ISiteRepository.GetAllDataConnectionsAsync()`
|
|
- SMTP configurations from `INotificationRepository.GetAllSmtpConfigurationsAsync()`
|
|
|
|
**Step 2:** Build and verify.
|
|
|
|
**Step 3:** Commit: `feat: include data connections and SMTP in artifact collection`
|
|
|
|
---
|
|
|
|
### Task 7: End-to-end test
|
|
|
|
**Step 1:** Start Central and Site servers.
|
|
|
|
**Step 2:** Login as admin, navigate to Sites page, click "Deploy Artifacts" on Test Plant A.
|
|
|
|
**Step 3:** Verify site logs show artifact receipt and SQLite storage.
|
|
|
|
**Step 4:** Restart Site without config DB connection string — verify it starts and ExternalSystemClient/NotificationDeliveryService work from local data.
|
|
|
|
**Step 5:** Commit any fixes.
|