# Application Design — Master CMS Module ## Design Decisions Summary | Question | Decision | |----------|----------| | Q1 — HTTP client (Master → Slave) | **A) Typed client** — `ISlaveApiClient` / `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 ```mermaid 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` |