4.4 KiB
4.4 KiB
NFR Requirements — Unit 1: master-backend
Performance
| Requirement | Specification | Source |
|---|---|---|
| HTTP timeout for slave calls | Configurable via MasterModuleOptions.HttpTimeoutSeconds; default 10 seconds |
Q1 |
| HTTP retry budget | Maximum 3 attempts (initial + 2 retries) with exponential backoff (1s, 2s); per-attempt timeout applies | Q2 |
| Background service interval | Configurable via MasterModuleOptions.IntegrityCheckIntervalMinutes; default 60 minutes |
NFR-MASTER-04 |
| Controller endpoint latency | No explicit SLA; bounded by HTTP timeout × retry attempts (worst case ~33s for a single unresponsive slave during Add/UpdateStatus) | derived |
Security
| Requirement | Specification | Source |
|---|---|---|
| ApiKey at-rest encryption | Encrypted with ASP.NET Core Data Protection before writing to DB; decrypted immediately before HTTP calls | Q3 (+ functional design) |
| Data Protection key storage | Default file system (platform default); machine-bound; acceptable for single-instance deployment | Q3 |
| ApiKey exposure | Never included in CmsInstanceDto or any API response; [JsonIgnore] or explicit DTO mapping |
NFR-MASTER-03 |
| Endpoint authorization | All CmsInstanceController actions require [Authorize(Policy = "OwnerOnly")] |
FR-MASTER-10 |
| Internal slave endpoint auth | POST /api/internal/master/register validated via X-Master-Api-Key header (Unit 2 concern) |
FR-MASTER-03 |
Reliability
| Requirement | Specification | Source |
|---|---|---|
| Fail-open on slave unreachability | Status push failure returns SlaveContactSuccess = false but does not roll back DB change; integrity check sets LastIntegrityCheckFailedAt and continues |
NFR-MASTER-01 |
| Retry policy | Exponential backoff: attempt 1 (immediate), attempt 2 (+1s delay), attempt 3 (+2s delay); implemented via Polly ResiliencePipeline |
Q2 |
| Background service isolation | Exceptions per slave instance are caught, logged, and do not abort the full integrity check batch | BR-BG-03 |
| Background service scope | IServiceScopeFactory used per tick to resolve scoped ICmsInstanceService; scope disposed after each tick |
BR-BG-01/02 |
Testability
| Requirement | Specification | Source |
|---|---|---|
| Minimum test coverage | ≥ 80% line/branch coverage for SlpModularCms.Modules.Master (excluding items below) |
NFR-MASTER-05 |
| Coverage exclusions | Apply [ExcludeFromCodeCoverage] to: MasterModule.cs (IModule boilerplate), EF Core migration files, plain DTO/record classes with no logic |
Q4 |
| Test project | SlpModularCms.Modules.Master.Tests — separate project; mirrors production project structure |
Unit decomposition decision |
| Key test targets | CmsInstanceService, SlaveApiClient, IntegrityCheckBackgroundService, CmsInstanceController |
NFR-MASTER-05 |
| Interface-driven design | ICmsInstanceRepository, ICmsInstanceService, ISlaveApiClient interfaces required to enable unit test mocking |
derived |
Maintainability
| Requirement | Specification | Source |
|---|---|---|
| Log level — integrity check failures | Warning — slave unreachability during background checks is expected; does not require immediate attention | Q5 |
| Log level — status push failures | Error — owner-triggered action failed to reach slave; requires visibility | Q5 |
| Log level — re-registration on mismatch | Information — expected recovery action | derived |
| Log level — background service tick | Debug — high frequency; only visible when debugging | derived |
| Structured logging | Use ILogger<T> with structured message templates; include slaveUrl and instanceId in log scope |
derived |
Updated MasterModuleOptions Fields
The following field is added as a result of Q1:
| Property | Type | Default | Notes |
|---|---|---|---|
HttpTimeoutSeconds |
int |
10 |
Timeout applied to each individual HTTP attempt in SlaveApiClient |
Full updated options shape:
| Property | Type | Default | Side |
|---|---|---|---|
IntegrityCheckIntervalMinutes |
int |
60 |
Master |
HttpTimeoutSeconds |
int |
10 |
Master |
MasterUrl |
string? |
null |
Master |
CacheMinutes |
int |
60 |
Slave |
ApiKey |
string? |
null |
Slave |