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

165 lines
7.8 KiB
Markdown

# 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` |