Files
scadalink-design/docs/plans/2026-03-17-deploy-artifacts-remove-configdb.md

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 (DeployArtifactsCommandDeploymentManagerActorSiteStorageService). 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.