# Domain Entities — Unit 2: slave-availability-extension ## Entity Relationship Diagram ```mermaid graph TD subgraph AvailabilityModule["Availability Module (slave side)"] DbCtx["AvailabilityDbContext"] MR["MasterRegistration\n(singleton row)"] Cache["MasterStatusCache\n(static fields)"] MAS["IMasterAvailabilityService\n/MasterAvailabilityService"] end DbCtx -->|owns| MR MAS -->|reads/writes| DbCtx MAS -->|updates| Cache MW["AvailabilityMiddleware\n(extended)"] -->|reads synchronously| Cache MC["MasterController\n(new)"] -->|delegates to| MAS classDef entity fill:#FFC107,stroke:#F57F17,color:#000 classDef service fill:#9ae6b4,stroke:#2f855a,color:#000 classDef infra fill:#63b3ed,stroke:#2b6cb0,color:#000 classDef cache fill:#CE93D8,stroke:#6A1B9A,color:#000 class MR entity class MAS service class DbCtx,MC infra class Cache,MW cache ``` Text alternative: `AvailabilityDbContext` owns the singleton `MasterRegistration` row. `MasterAvailabilityService` reads/writes the DbContext and updates the in-process `MasterStatusCache` (static fields). `AvailabilityMiddleware` reads the cache synchronously. `MasterController` delegates all logic to `MasterAvailabilityService`. --- ## Entity: MasterRegistration Singleton row — at most one record exists per slave instance. Upserted on each successful registration. | Field | Type | Constraints | Notes | |-------|------|-------------|-------| | `Id` | `Guid` | PK | Fixed value (e.g. `Guid.Empty`) enforces singleton | | `MasterUrl` | `string` | Required, max 500 | URL of the master CMS that registered this slave | | `ApiKey` | `string` | Required, max 1000 | API key sent in first registration, encrypted via `IMasterApiKeyProtector` (ASP.NET Core Data Protection) before storage, decrypted for each subsequent validation — **corrected 2026-07-04**, this was previously (incorrectly) documented as stored plain-text | | `RegisteredAt` | `DateTimeOffset` | Required | Timestamp of first registration | | `LastContactedAt` | `DateTimeOffset?` | Optional | Updated on every successful master-initiated call (register, status push, get-url) | | `LastPolledAt` | `DateTimeOffset?` | Optional | **Added 2026-07-04**. Updated on every successful *slave-initiated* poll (`MasterStatusPollingBackgroundService`) — the counterpart to `LastContactedAt`, tracking the opposite direction of contact. Also the basis for the fail-open timeout (see below). | > **Singleton enforcement**: The `Id` is a fixed known value (`Guid.Parse("00000000-0000-0000-0000-000000000001")`). On first `POST /api/v1/master/register` the row is created; on re-registration the same row is updated in-place. This avoids a composite unique constraint and makes EF upsert trivial. --- ## In-Process Cache: MasterStatusCache (static fields) Not a DB entity — lives in memory on the slave process. | Field | Type | Default | Notes | |-------|------|---------|-------| | `_masterIsAvailable` | `bool` | `true` | Set by status push **or** successful poll; forced back to `true` on prolonged poll failure (fail-open) | | `_masterDisableMessage` | `string?` | `null` | Message forwarded from master to 503 response; cleared to `null` on fail-open | > **Updated 2026-07-04**: originally documented as having "no expiry" (Q4=A), valid indefinitely until the next push. This is no longer accurate now that `MasterStatusPollingBackgroundService` actively polls the master (see Rule Set 5 / Flow 5 in the sibling docs) and forces the cache back to `Available`/`null` if the master has been unreachable via poll for longer than `MasterPolling:FailOpenAfterMinutes` (default 5 min, measured from `MasterRegistration.LastPolledAt`). Push-driven updates (this section's original description) are unchanged and still apply; the poll is an additional, independent path that can also write to this same cache. --- ## DbContext: AvailabilityDbContext New per-module DbContext in `SlpModularCms.Modules.Availability`. Separate from `ApplicationDbContext` (Core). | DbSet | Entity | Table Name | |-------|--------|-----------| | `MasterRegistrations` | `MasterRegistration` | `AvailabilityMasterRegistrations` | Migration assembly: `SlpModularCms.Modules.Availability`. Applied at startup in `AvailabilityModule.UseModule`.