Skip to main content

Config Service — Domain Model

Status: populated Owner: TBD Last updated: 2026-04-18 Companion: Service Template · 03 platform-services · 02 DDD


1. Aggregates

1.1 ConfigNode

The universal node in the configuration DAG. All configurable entities are ConfigNode instances.

FieldTypeInvariants
idConfigNodeId (prefix cfgn_)Immutable after creation
tenantIdTenantId | nullnull = global node; all non-global nodes must be tenant-scoped
nodeTypeConfigNodeTypeMust be one of 13 valid types (see §4)
nodeKeystringStable within scope; unique per (tenantId, nodeType, nodeKey)
parentIdConfigNodeId | nullParent must exist; parent type must be valid per taxonomy
payloadJSONBType-specific; validated against node-type schema on write
scopeChainConfigNodeId[]Denormalised ancestor array; updated on parentId change
isActivebooleanSoft-disable only; hard-delete not supported
versionnumberOptimistic lock
createdAtTimestamp
updatedAtTimestamp

State machine:

Invariants:

  • parentId edge that would form a cycle → CONFIG_CIRCULAR_REFERENCE.
  • Soft-deleting a node with active children → CONFIG_NODE_HAS_CHILDREN.
  • GLOBAL node and isSystem=true roles: creatable/mutable by SUPER_ADMIN only.

1.2 FeatureDefinition

Defines a named capability within a module, its permitted actions, and data scope.

FieldTypeNotes
idFeatureId (prefix feat_)
tenantIdTenantId
featureKeystringStable code, e.g. ViewMedications
moduleKeystringParent module key, e.g. CLIN-MEDS
allowedActionsstring[]Actions this feature may grant
dataScopeTypeDataScopeTypeworld | tenant | networkOnly | facilityOnly | sameFacility | self
isActiveboolean

1.3 RoleDefinition

A named capability group; supports inheritance.

FieldTypeNotes
idRoleId (prefix role_)
tenantIdTenantId | nullnull = system/platform role
roleKeystringStable code, e.g. PHYSICIAN, NURSE
displayNamestringHuman-readable
isAbstractbooleanCannot be directly assigned to users
isSystembooleanOnly SUPER_ADMIN can create/modify

1.4 RoleInheritance

A DAG edge from child role to parent role.

FieldTypeNotes
idRoleInheritanceId (prefix ri_)
tenantIdTenantId
childRoleIdRoleIdRole that inherits
parentRoleIdRoleIdRole being inherited from
inheritanceTypefull | partialfull = all grants propagate

Invariant: Edge creating a cycle → CIRCULAR_ROLE_INHERITANCE. Max depth 10 enforced at definition time.


1.5 RoleFeatureGrant

Explicit grant or deny of a feature + action set for a role.

FieldTypeNotes
idGrantId (prefix grant_)
tenantIdTenantId
roleIdRoleId
featureKeystring
grantedActionsstring[]Explicit allows
deniedActionsstring[]Explicit denies; override inherited grants

1.6 UserNodeOverride

Explicit per-user per-node allow/deny; highest resolution priority.

FieldTypeNotes
idOverrideId (prefix ovr_)
tenantIdTenantId
userIdUserIdMust belong to same tenant as caller
nodeIdConfigNodeIdHierarchy node where override applies
featureKeystring
actionstringThe specific action
effectallow | deny
justificationstringMandatory non-empty
effectiveFromDateRequired
effectiveToDate | nullOptional; expired = silently ignored
grantedByUserIdCreating actor

Invariants:

  • One active override per (userId, nodeId, featureKey, action) → conflict: OVERRIDE_CONFLICT.
  • ExplicitDeny is final; no role grant or ABAC policy can override it.
  • ExplicitAllow cascades to UI element visibility for the bound action at that node.

1.7 UIDefinition

A UI element and its relationship to features and actions.

FieldTypeNotes
idUIDefId (prefix uid_)
tenantIdTenantId
elementKeystringStable key, e.g. add-medication-btn
elementTypescreen | component | element | action_binding
parentElementIdUIDefId | nullHierarchy: screen → component → element
featureKeystringFeature this element belongs to
actionBindingstring | nullAction triggered, e.g. medication:write
defaultProps{ visible: boolean, interactable: boolean }

1.8 UIVisibilityRule

Per-role or per-user visibility override for a UI element.

FieldTypeNotes
idUIRuleId (prefix uir_)
tenantIdTenantId
elementIdUIDefIdFK → UIDefinition
subjectTyperole | user
subjectIdRoleId | UserId
isVisibleboolean
isInteractableboolean
nodeIdConfigNodeId | nullIf set, rule only applies at this node scope

Invariant: User rule always overrides conflicting role rule for same element + node.


1.9 DesignToken

A scoped design-system token value.

FieldTypeNotes
idTokenId (prefix tok_)
tenantIdTenantId
scopeNodeIdConfigNodeIdConfig node where this token is defined
scopeTypeglobal | tenant | module | user
tokenKeystringe.g. brand.primary, font.family.rtl
tokenValuestringe.g. #006600
localestring | nulle.g. ps-AF; overrides non-locale token for same key

Merge priority (LWW per tier): User > Module > OrgNode (deepest wins) > Tenant > Global


2. Value Objects

Value ObjectType / Notes
ConfigNodeIdBranded ULID, prefix cfgn_
FeatureIdBranded ULID, prefix feat_
RoleIdBranded ULID, prefix role_
OverrideIdBranded ULID, prefix ovr_
UIDefIdBranded ULID, prefix uid_
TokenIdBranded ULID, prefix tok_
ConfigNodeType13-value enum (see §4)
DataScopeTypeworld | tenant | networkOnly | facilityOnly | sameFacility | self
EvaluationResult{ effect, reason, policyId?, dataScope?, uiConfig?, designTokens? }
UIElementConfig{ elementKey, elementType, visible, interactable, actionBinding, children[] }

3. Domain Events

Event subject (NATS)TriggerRetention
config.feature.created.v1Feature definition created7 years
config.feature.updated.v1Feature definition updated7 years
config.role.created.v1Role definition created7 years
config.role.updated.v1Role definition updated7 years
config.role.deleted.v1Role soft-deleted7 years
config.role_grant.created.v1Role feature grant created7 years
config.role_grant.updated.v1Role feature grant updated7 years
config.ui_definition.created.v1UI element created7 years
config.ui_definition.updated.v1UI element updated7 years
config.user_override.created.v1User node override created7 years
config.user_override.deleted.v1User node override soft-deleted7 years
config.design_token.updated.v1Design token value changed7 years
config.config.cache_busted.v1Cache eviction for a tenant/scope7 days

4. DAG Node Taxonomy

node_typeDescriptionValid Parent Types
GLOBALPlatform-wide defaults— (root)
TENANTTenant root configGLOBAL
ORG_NODEMaps 1:1 to facility/hierarchy nodeTENANT, ORG_NODE
MODULEModule catalogue key scopeTENANT, ORG_NODE
FEATUREFeature within a moduleMODULE
ACTIONAllowed action within a featureFEATURE
ROLERole definitionTENANT
USERUser-level explicit override scopeTENANT
UI_SCREENScreen definitionFEATURE
UI_COMPONENTComponent within a screenUI_SCREEN
UI_ELEMENTElement within a componentUI_COMPONENT
ACTION_BINDINGElement → Action linkUI_ELEMENT
DESIGN_SYSTEMDesign token scope nodeGLOBAL, TENANT, MODULE, USER

5. Ubiquitous Language

TermDefinition
ConfigNodeAny node in the configuration DAG
Config SpineThe ancestor chain of hierarchy nodes used as resolution context
EvaluationResultFinal output of the 9-step resolution pipeline
ExplicitAllowUserNodeOverride with effect = "allow" — highest priority
ExplicitDenyUserNodeOverride with effect = "deny" — final, cannot be overridden
Role GraphBFS-expanded DAG of role inheritance edges
DataScopeDetermines which data records a granted action may touch
Design TokenKey-value pair defining a design-system variable
ActionBindingLink from a UI element to the action it triggers
Scope ChainDenormalised ancestor ID array on each ConfigNode
Module LicenseLicense record (owned by platform-admin-service) gating module access
Feature FlagPlatform-level toggle per tenant (owned by platform-admin-service)