Files
slp-modular-cms/aidlc-docs/features/master-cms-module/construction/slave-availability-extension/nfr-requirements/tech-stack-decisions.md
T

4.7 KiB

Tech Stack Decisions — Unit 2: slave-availability-extension

Data Protection

Decision: IMasterApiKeyProtector wrapping ASP.NET Core Data Protection

Aspect Decision Rationale
Interface IMasterApiKeyProtector with Protect(string) / Unprotect(string) Testable; mirrors Unit 1's IApiKeyProtector pattern
Implementation MasterApiKeyProtector : IMasterApiKeyProtector Wraps IDataProtectionProvider; purpose-scoped
Purpose string "SlpModularCms.Availability.MasterApiKey" Prevents cross-module decryption with Unit 1's scope
On Unprotect failure Catch CryptographicException, return null Service treats null as key mismatch → 401; logs Error
Key ring Default file system (inherits app-level AddDataProtection() setup) No extra configuration needed; same caveat as Unit 1 regarding containerized deployments

Production note: Same as Unit 1 — for multi-instance or containerized deployments, configure a shared key ring (PersistKeysToDbContext, PersistKeysToAzureBlobStorage, etc.). Without it, a restarted container cannot decrypt keys stored by the previous instance.


Static Cache

Decision: volatile static fields in MasterAvailabilityService

Aspect Decision Rationale
_masterIsAvailable private static volatile bool Atomic read/write for bool; volatile ensures CPU cache flush visibility
_masterDisableMessage private static volatile string? Reference assignment is atomic in .NET; volatile ensures visibility
Default _masterIsAvailable = true, _masterDisableMessage = null Fail-open: process startup = Available
Write location MasterAvailabilityService.PushStatusAsync only Single write point; no other code modifies cache
Read location AvailabilityMiddleware.InvokeAsync only Single read point; no async overhead

Why not lock: No multi-field invariant to protect (fields are read/written independently). volatile matches the existing pattern in PersistentAvailabilityService (_lastErrorTime).


EF Core / Database

Decision: New AvailabilityDbContext with own migrations

Aspect Decision
DbContext class AvailabilityDbContext : DbContext in SlpModularCms.Modules.Availability
Migration assembly SlpModularCms.Modules.Availability (same project)
Migration application app.ApplicationServices.CreateScope()AvailabilityDbContext.Database.MigrateAsync() in AvailabilityModule.UseModule(IApplicationBuilder)
DbSet DbSet<MasterRegistration> MasterRegistrations
Table name AvailabilityMasterRegistrations
Connection string Reuses ConnectionStrings:DefaultConnection (same as ApplicationDbContext and MasterDbContext)
Registration services.AddDbContext<AvailabilityDbContext>((sp, options) => ...) using IConfiguration from service provider

Singleton enforcement: MasterRegistration.Id is always new Guid("00000000-0000-0000-0000-000000000001"). EF AddOrUpdate via ExecuteUpdateAsync / find-by-id pattern.


Repository

Decision: IMasterRegistrationRepository / MasterRegistrationRepository

Method Signature Notes
GetAsync Task<MasterRegistration?> Loads singleton by fixed Id; returns null if not exists
UpsertAsync Task UpsertAsync(MasterRegistration registration) Add or Update based on whether row exists
SaveChangesAsync Task SaveChangesAsync() Explicit save; keeps service in control of transaction boundary

Controller

Decision: New MasterController in Availability module

Aspect Decision
Class MasterController : ControllerBase in SlpModularCms.Modules.Availability.Controllers
Route [Route("[controller]")]/api/v1/master via ApiPrefixConvention("api/v1")
Auth No [Authorize] — API key validated in service layer
Response on 401 Unauthorized() (HTTP 401) — no ProblemDetails body to avoid leaking info
Response on success Ok() for register/status; Ok(new { MasterUrl }) for registered-url

New Dependencies

Package Already present? Notes
Microsoft.AspNetCore.DataProtection Yes (shared framework) No NuGet addition needed
EF Core SqlServer Yes (via Core project) No addition needed
xUnit / NSubstitute / FluentAssertions Yes (existing test projects) Reference same versions as Availability.Tests
EF Core InMemory Likely yes Confirm in Availability.Tests.csproj

Net new NuGet packages required: None.