Files
slp-modular-cms/aidlc-docs/features/master-cms-module/construction/plans/slave-availability-extension-code-generation-plan.md
T

63 lines
4.6 KiB
Markdown

# Code Generation Plan — Unit 2: slave-availability-extension
## Scope
**Modify**: `src/SlpModularCms.Modules.Availability/` (existing project)
**Create**: `src/SlpModularCms.Modules.Availability.Master.Tests/` (new test project)
**Update**: `SlpModularCms.sln` (add new test project)
**Update**: existing `AvailabilityMiddlewareTests.cs` in `Availability.Tests` (new 3-param signature)
---
## Steps
### Part A — Production Code (Availability module)
- [x] **Step 1**`SlpModularCms.Modules.Availability.csproj` — add `InternalsVisibleTo` for new test project
- [x] **Step 2**`Data/Entities/MasterRegistration.cs` — entity with singleton Id constant
- [x] **Step 3**`Data/AvailabilityDbContext.cs` — DbContext with MasterRegistrations DbSet + OnModelCreating
- [x] **Step 4**`Repositories/IMasterRegistrationRepository.cs``GetAsync`, `AddAsync`, `Update`, `SaveChangesAsync`
- [x] **Step 5**`Repositories/MasterRegistrationRepository.cs` — EF Core implementation
- [x] **Step 6**`Services/IMasterApiKeyProtector.cs``Protect` + `Unprotect` (null on crypto failure)
- [x] **Step 7**`Services/MasterApiKeyProtector.cs` — wraps `IDataProtectionProvider`; purpose `"SlpModularCms.Availability.MasterApiKey"`
- [x] **Step 8**`Services/MasterGateStatus.cs``record MasterGateStatus(bool IsAvailable, string? DisableMessage)`
- [x] **Step 9**`Services/MasterAvailabilityServiceDependencies.cs` — record with repo, protector, logger
- [x] **Step 10**`Services/IMasterAvailabilityService.cs``RegisterAsync(bool)`, `PushStatusAsync(bool)`, `GetRegisteredUrlAsync(string?)`, `GetMasterStatus()`
- [x] **Step 11**`Services/MasterAvailabilityService.cs` — volatile static fields + implementation of all 4 methods
- [x] **Step 12**`Models/RegisterMasterRequest.cs` + `Models/PushStatusRequest.cs``[ExcludeFromCodeCoverage]` records
- [x] **Step 13**`Controllers/MasterController.cs` — 3 endpoints; header extraction; delegate to service; Unauthorized() on false/null
- [x] **Step 14**`Middleware/AvailabilityMiddleware.cs` — extend: add `/api/v1/master/` bypass; move admin check before local gate; add master gate between admin check and local gate
- [x] **Step 15**`AvailabilityModule.cs` — add DbContext, protector, repo, deps, service registrations; add `MigrateAsync` in UseModule
### Part B — Test Project (new)
- [x] **Step 16**`SlpModularCms.Modules.Availability.Master.Tests.csproj` — new project; copy packages from Master.Tests; add `Microsoft.IdentityModel.Tokens` for JWT tests
- [x] **Step 17**`Repositories/MasterRegistrationRepositoryTests.cs` — EF InMemory; GetAsync (null + found); AddAsync; Update; SaveChanges
- [x] **Step 18**`Services/MasterApiKeyProtectorTests.cs``EphemeralDataProtectionProvider`; round-trip; invalid ciphertext returns null
- [x] **Step 19**`Services/MasterAvailabilityServiceTests.cs` — NSubstitute; all 4 public methods; key mismatch; first registration; re-registration; static cache state
- [x] **Step 20**`Controllers/MasterControllerTests.cs` — NSubstitute; missing header → 401; success → 200; service returns false/null → 401
- [x] **Step 21**`Middleware/AvailabilityMiddlewareMasterGateTests.cs` — NSubstitute; master gate blocks → 503; master gate passes → local gate evaluated; `/api/v1/master/` bypasses; master gate + admin JWT → pass through
### Part C — Cross-cutting
- [x] **Step 22**`SlpModularCms.sln` — add `Availability.Master.Tests` project with new GUID
- [x] **Step 23**`src/SlpModularCms.Modules.Availability.Tests/AvailabilityMiddlewareTests.cs` — update all `InvokeAsync(context, _service)` calls to `InvokeAsync(context, _service, masterSvc)` (masterSvc stub returning `IsAvailable=true`)
---
## Key Design Notes
| Concern | Decision |
|---------|----------|
| Singleton Id | `public static readonly Guid SingletonId = new("00000000-0000-0000-0000-000000000001")` |
| IMasterAvailabilityService.RegisterAsync | Returns `bool` (true=ok, false=key mismatch) |
| IMasterAvailabilityService.PushStatusAsync | Returns `bool` (true=ok, false=key mismatch) |
| IMasterAvailabilityService.GetRegisteredUrlAsync | Returns `string?` (null=unauthorized) |
| Unprotect null guard | `storedKey is null \|\| storedKey != incoming` → treat as mismatch |
| Middleware InvokeAsync order | bypass paths → admin JWT → master gate → local gate |
| Existing AvailabilityMiddlewareTests | Add stub `IMasterAvailabilityService` returning `IsAvailable=true` as 3rd param |
---
*Artifact path*: `aidlc-docs/features/master-cms-module/construction/plans/slave-availability-extension-code-generation-plan.md`