Files
slp-modular-cms/aidlc-docs/features/master-cms-module/construction/master-backend/functional-design/business-rules.md
T

7.0 KiB

Business Rules — Unit 1: master-backend

BR-01 — Status Update Decision Logic

graph TD
    Start(["UpdateStatusAsync called"])
    CheckExists{"Entity exists\nfor given id?"}
    NotFound["Throw NotFoundException\n404 to caller"]
    CheckMsg{"newStatus = NotAvailable\nAND disableMessage\nis null or empty?"}
    ValidationErr["Throw ValidationException\nDisableMessage required"]
    CheckInactive{"newStatus\n= Inactive?"}
    SetInactive["Status = Inactive\nDisableMessage = null\nNo HTTP push\nSlaveContactSuccess = true"]
    PersistStatus["Persist Status + DisableMessage\nto MasterDbContext"]
    DecryptKey["Decrypt ApiKey\nvia IDataProtector"]
    PushSlave["PushStatusAsync\nto slave endpoint"]
    PushOk{"HTTP push\nsucceeded?"}
    UpdatePushed["LastStatusPushedAt = UtcNow\nSave"]
    ReturnOk["Return UpdateStatusResult\nSuccess=true\nSlaveContactSuccess=true"]
    ReturnWarn["Return UpdateStatusResult\nSuccess=true\nSlaveContactSuccess=false"]
    Done(["Return result to controller"])

    Start --> CheckExists
    CheckExists -->|"no"| NotFound
    CheckExists -->|"yes"| CheckMsg
    CheckMsg -->|"yes — invalid"| ValidationErr
    CheckMsg -->|"no — valid"| CheckInactive
    CheckInactive -->|"yes"| SetInactive --> Done
    CheckInactive -->|"no"| PersistStatus --> DecryptKey --> PushSlave --> PushOk
    PushOk -->|"yes"| UpdatePushed --> ReturnOk --> Done
    PushOk -->|"no"| ReturnWarn --> Done

    classDef decision fill:#FFC107,stroke:#F57F17,stroke-width:2px,color:#000
    classDef action fill:#63b3ed,stroke:#2b6cb0,stroke-width:1px,color:#000
    classDef terminal fill:#9ae6b4,stroke:#2f855a,stroke-width:2px,color:#000
    classDef error fill:#FC8181,stroke:#C53030,stroke-width:2px,color:#000
    class CheckExists,CheckMsg,CheckInactive,PushOk decision
    class PersistStatus,DecryptKey,PushSlave,UpdatePushed,SetInactive action
    class Start,Done terminal
    class NotFound,ValidationErr error

Text alternative: Load entity (404 if missing) → validate DisableMessage required for NotAvailable → for Inactive skip push → for others persist, decrypt key, push to slave, set SlaveContactSuccess based on push result.


BR-02 — Integrity Check Decision Logic

graph TD
    Start(["VerifyIntegrityAsync\nper instance"])
    GetUrl["GetRegisteredMasterUrlAsync\n(slaveUrl, plainApiKey)"]
    Reachable{"Slave\nreachable?"}
    SetFailed["LastIntegrityCheckFailedAt = UtcNow\nSave — continue to next"]
    UrlMatch{"registeredMasterUrl\n= expected masterUrl?"}
    ClearOk["LastIntegrityCheckFailedAt = null\nLastContactedAt = UtcNow\nSave"]
    ReRegister["RegisterMasterAsync\n(slaveUrl, plainApiKey, masterUrl)"]
    RegOk{"Re-registration\nsucceeded?"}
    ClearAfterReg["LastIntegrityCheckFailedAt = null\nLastContactedAt = UtcNow\nSave"]
    SetFailedReg["LastIntegrityCheckFailedAt = UtcNow\nSave"]
    Next(["Next instance"])

    Start --> GetUrl --> Reachable
    Reachable -->|"no"| SetFailed --> Next
    Reachable -->|"yes"| UrlMatch
    UrlMatch -->|"match"| ClearOk --> Next
    UrlMatch -->|"mismatch"| ReRegister --> RegOk
    RegOk -->|"yes"| ClearAfterReg --> Next
    RegOk -->|"no"| SetFailedReg --> Next

    classDef decision fill:#FFC107,stroke:#F57F17,stroke-width:2px,color:#000
    classDef action fill:#63b3ed,stroke:#2b6cb0,stroke-width:1px,color:#000
    classDef terminal fill:#9ae6b4,stroke:#2f855a,stroke-width:2px,color:#000
    classDef error fill:#FC8181,stroke:#C53030,stroke-width:2px,color:#000
    class Reachable,UrlMatch,RegOk decision
    class GetUrl,SetFailed,ClearOk,ReRegister,ClearAfterReg,SetFailedReg action
    class Start,Next terminal

Text alternative: For each active slave — attempt to get its registered master URL; if unreachable set failure flag; if reachable and URL matches clear flag; if mismatch re-register; clear flag on success, set flag on failure.


Validation Rules

Rule Field Condition Error
BR-VAL-01 Name Must not be null or whitespace Name is required
BR-VAL-02 Url Must not be null or whitespace Url is required
BR-VAL-03 Url Must start with http:// or https:// Url must be a valid absolute HTTP(S) URL
BR-VAL-04 ApiKey Must not be null or whitespace (on create) ApiKey is required
BR-VAL-05 DisableMessage Required (non-empty) when Status = NotAvailable DisableMessage is required when status is NotAvailable
BR-VAL-06 Status Must be a valid CmsInstanceStatus enum value Invalid status value
BR-VAL-07 id (update) CmsInstance with given id must exist CmsInstance not found (404)

Status Transition Rules

From To DisableMessage HTTP Push Notes
Any Available Clear to null Yes Slave re-enabled
Any NotAvailable Required, non-empty Yes Slave disabled with message
Any Inactive Clear to null No Master stops all contact
Inactive Available Clear to null Yes Reactivation
Inactive NotAvailable Required, non-empty Yes Reactivation with disable

ApiKey Encryption Rules

Rule Description
BR-ENC-01 ApiKey is encrypted via IDataProtector before writing to MasterDbContext
BR-ENC-02 ApiKey is decrypted via IDataProtector immediately before each HTTP call requiring it
BR-ENC-03 ApiKey is never included in CmsInstanceDto or any other API response
BR-ENC-04 ApiKey is accepted in CreateCmsInstanceRequest on creation only; no update endpoint for ApiKey

Master URL Resolution Rules

Context Resolution Strategy
Controller-originated calls (Add) Derive from HttpContext.Request scheme + host + (optional port) via IHttpContextAccessor
Background service calls (Integrity Check) Read MasterModuleOptions.MasterUrl from configuration
MasterModuleOptions.MasterUrl is null in background context Log a warning; skip registration/integrity for that cycle

HTTP Contact Exclusion Rules

Rule Description
BR-CONTACT-01 Instances with Status = Inactive are excluded from GetActiveAsync and never contacted via HTTP
BR-CONTACT-02 Status push is skipped when transitioning any status → Inactive
BR-CONTACT-03 Integrity check runs only against instances where Status != Inactive

Background Service Rules

Rule Description
BR-BG-01 IntegrityCheckBackgroundService resolves ICmsInstanceService via IServiceScopeFactory per tick (not injected directly, as service is Scoped)
BR-BG-02 Each tick creates and disposes its own IServiceScope
BR-BG-03 Exceptions within a single slave's integrity check are caught, logged, and do not abort processing for remaining slaves
BR-BG-04 If MasterModuleOptions.MasterUrl is null or empty, the background service logs a warning and skips the entire integrity check for that cycle