Files
slp-modular-cms/aidlc-docs/features/master-cms-module/inception/application-design/application-design.md
T

7.8 KiB

Application Design — Master CMS Module

Design Decisions Summary

Question Decision
Q1 — HTTP client (Master → Slave) A) Typed clientISlaveApiClient / SlaveApiClient via AddHttpClient<>
Q2 — Two-phase gate middleware B) Extend AvailabilityMiddleware — Master gate added at top of InvokeAsync
Q3 — Slave-side status caching A) Static field + timestamp — consistent with existing circuit breaker pattern
Q4 — Service responsibility split B) CmsInstanceRepository + CmsInstanceService — data and orchestration separated
Q5 — Master controller granularity A) Single CmsInstanceController — all actions in one controller
Q6 — Slave internal endpoint placement B) Extended AvailabilityController — registration endpoint added to existing controller
Q7 — Frontend hooks organization B) Separate hook files — one file per hook: useCmsInstances.ts, useAddCmsInstance.ts, useUpdateCmsInstanceStatus.ts

Architecture Overview

graph TD
    subgraph MasterCms["Master CMS Instance"]
        MasterModule["MasterModule\n(IModule)"]
        CmsCtrl["CmsInstanceController\n/api/v1/CmsInstances"]
        CmsService["CmsInstanceService\n(orchestration)"]
        CmsRepo["CmsInstanceRepository\n(data access)"]
        MasterDb["MasterDbContext\nCmsInstances table"]
        SlaveClient["SlaveApiClient\n(typed HTTP client)"]
        BgService["IntegrityCheckBackgroundService\n(PeriodicTimer)"]
        MasterOpts["MasterModuleOptions"]
    end

    subgraph SlaveCms["Slave CMS Instance"]
        ExtAvailMw["AvailabilityMiddleware\n(EXTENDED — two-phase gate)"]
        MasterAvailSvc["MasterAvailabilityService\n(pull + cache + fallback)"]
        LocalAvailSvc["IAvailabilityService\n(existing local gate)"]
        AvailDb["AvailabilityDbContext\nMasterRegistrations table"]
        ExtAvailCtrl["AvailabilityController\n(EXTENDED + RegisterMaster)"]
        SlaveOpts["MasterModuleOptions\n(ApiKey, CacheMinutes)"]
    end

    subgraph FrontendApp["Frontend (Master UI)"]
        CmsPage["CmsPage\n(/cms route)"]
        Hooks["TanStack Query Hooks\n(useCmsInstances, useAddCmsInstance,\nuseUpdateCmsInstanceStatus)"]
        Components["Components\n(CmsInstanceList,\nAddCmsInstanceDialog,\nSetStatusDialog)"]
    end

    FrontendApp -->|"REST /api/v1/CmsInstances"| MasterCms
    MasterCms -->|"HTTP slave API"| SlaveCms
    SlaveCms -->|"HTTP pull status"| MasterCms

    CmsPage --> Components
    Components --> Hooks
    Hooks -->|"GET/POST/PUT"| CmsCtrl
    CmsCtrl --> CmsService
    CmsService --> CmsRepo
    CmsService --> SlaveClient
    CmsRepo --> MasterDb
    BgService --> CmsService
    CmsService --> MasterOpts
    BgService --> MasterOpts
    ExtAvailMw --> MasterAvailSvc
    ExtAvailMw --> LocalAvailSvc
    MasterAvailSvc --> AvailDb
    MasterAvailSvc --> SlaveOpts
    ExtAvailCtrl --> AvailDb
    ExtAvailCtrl --> SlaveOpts

    classDef module fill:#9ae6b4,stroke:#2f855a,stroke-width:2px,color:#000
    classDef controller fill:#63b3ed,stroke:#2b6cb0,stroke-width:1px,color:#000
    classDef service fill:#FFC107,stroke:#F57F17,stroke-width:1px,color:#000
    classDef data fill:#CE93D8,stroke:#6A1B9A,stroke-width:1px,color:#000
    classDef frontend fill:#FC8181,stroke:#C53030,stroke-width:1px,color:#000
    classDef config fill:#B0BEC5,stroke:#546E7A,stroke-width:1px,color:#000
    class MasterModule module
    class CmsCtrl,ExtAvailCtrl controller
    class CmsService,MasterAvailSvc,SlaveClient,LocalAvailSvc,BgService service
    class CmsRepo,MasterDb,AvailDb data
    class CmsPage,Hooks,Components frontend
    class MasterOpts,SlaveOpts config

Text alternative: Master CMS has new module with controller, service, repository, typed HTTP client, and background service; Slave CMS has extended middleware with two-phase gate, new MasterAvailabilityService, new AvailabilityDbContext, and extended controller; Frontend has CmsPage with hooks and components calling Master REST API.


Component Inventory

Unit 1 — master-backend (SlpModularCms.Modules.Master)

Component Type New/Modified
MasterModule IModule New
MasterDbContext EF Core DbContext New
CmsInstance Entity New
CmsInstanceStatus Enum New
ICmsInstanceRepository / CmsInstanceRepository Repository New
ICmsInstanceService / CmsInstanceService Service New
ISlaveApiClient / SlaveApiClient Typed HTTP client New
CmsInstanceController Controller New
IntegrityCheckBackgroundService BackgroundService New
MasterModuleOptions Config POCO New
CmsInstanceDto DTO New
CreateCmsInstanceRequest Request model New
UpdateStatusRequest Request model New

Unit 2 — slave-availability-extension (SlpModularCms.Modules.Availability)

Component Type New/Modified
MasterRegistration Entity New
AvailabilityDbContext EF Core DbContext New
IMasterAvailabilityService / MasterAvailabilityService Service New
AvailabilityMiddleware Middleware Modified
AvailabilityController Controller Modified
MasterGateResult Result record New
RegisterMasterRequest Request model New

Unit 3 — frontend-cms-page (frontend/)

Component Type New/Modified
CmsPage React page New
CmsInstanceList React component New
AddCmsInstanceDialog React component New
SetStatusDialog React component New
useCmsInstances TanStack Query hook New
useAddCmsInstance TanStack Query hook New
useUpdateCmsInstanceStatus TanStack Query hook New
CmsInstance TypeScript type New
CmsInstanceStatus TypeScript enum New

Unit 4 — documentation

Artifact Type New/Modified
README.md — Migrations section Documentation Modified
README.md — Module guide section Documentation Modified
README.md — Production env vars Documentation Modified
frontend/README.md Documentation Modified

Key Design Constraints

Constraint Source Impact
ApiKey never returned in API responses NFR-MASTER-03 CmsInstanceDto excludes ApiKey; only accepted in CreateCmsInstanceRequest
Fail-open on Master unreachable NFR-MASTER-01 MasterAvailabilityService returns last cached status (default Available) on HTTP failure
Per-module DbContext + migrations NFR-MASTER-06 New MasterDbContext in Modules.Master; new AvailabilityDbContext in Modules.Availability
Master exemption from own gate FR-MASTER-09 Handled naturally: no MasterRegistration record exists on Master instance → gate skipped
Disable message required for NotAvailable FR-MASTER-14 Validated in CmsInstanceService.UpdateStatusAsync before persistence
Inactive slaves: no HTTP contact FR-MASTER-13 GetActiveAsync() filters out Inactive before integrity checks and status pushes
Owner role only FR-MASTER-10 [Authorize(Policy = "OwnerOnly")] on all CmsInstanceController actions

Artifact References

Artifact Path
Component definitions aidlc-docs/features/master-cms-module/inception/application-design/components.md
Method signatures aidlc-docs/features/master-cms-module/inception/application-design/component-methods.md
Service orchestration + flows aidlc-docs/features/master-cms-module/inception/application-design/services.md
Dependency diagrams + matrix aidlc-docs/features/master-cms-module/inception/application-design/component-dependency.md