# 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.
