7.3 KiB
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).
// 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.
// 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():
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:
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():
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:
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.