Provider Directory Service — Domain Model
Status: populated Owner: TBD Last updated: 2026-04-17 Companion: 02 DDD · SERVICE_OVERVIEW
1. Aggregate Map
2. Ubiquitous Language
| Term | Meaning |
|---|---|
| Practitioner | Licensed clinician (physician, nurse, pharmacist, dentist, technician) |
| PractitionerRole | Scoped role for a Practitioner (e.g., consultant in Ibn Sina ER) |
| Credential | Proof of licensure (license number, issuing authority, expiry) |
| Specialty | Clinical specialty codified (SNOMED or local system) |
| HealthcareService | Service offering (e.g., "ENT OPD clinic") bound to location |
| ServiceEndpoint | FHIR/HL7 URL per organisation/location used by partners |
| NameVariant | One of: local script (ps/fa-AF/ar), Latin transliteration |
| Privilege | Fine-grained capability: can.order.labs, can.prescribe.controlled, can.sign.notes |
3. Value Objects
| VO | Shape | Validation | Notes |
|---|---|---|---|
PractitionerId | Branded | ULID prc_ | F03 |
PractitionerRoleId | Branded | ULID prr_ | F03 |
CredentialId | Branded | ULID crd_ | F03 |
HealthcareServiceId | Branded | ULID hcs_ | F03 |
EndpointId | Branded | ULID end_ | F03 |
UserId | Branded (shared kernel with identity) | ULID usr_ | optional link |
TenantId | Branded | ULID ten_ | F03 |
PractitionerKind | enum | physician|nurse|midwife|pharmacist|dentist|technician|therapist|other | |
Identifier | { system: uri, value: string, authority: string, use?: 'official'|'temp' } | system unique per value per authority | |
SpecialtyCode | { system: uri, code: string, display?: string } | validated via terminology | |
NameVariant | { use: 'official'|'nickname'|'maiden', family, given[], middle?, scriptCode } | scriptCode = BCP-47 | |
Privilege | { key: string, source: 'role'|'credential', grantedAt, expiresAt? } | key in closed vocabulary | |
PhoneNumber | E.164 | country-code validated |
4. Aggregates
4.1 Practitioner (root)
interface Practitioner {
id: PractitionerId;
tenantId: TenantId;
userId?: UserId; // link to identity if this provider logs in
kind: PractitionerKind;
names: NameVariant[]; // at least one 'official'
identifiers: Identifier[]; // national IDs, council numbers
telecom: Array<{ system: 'phone'|'email'|'fax'|'url'; value: string; use?: string }>;
specialties: SpecialtyCode[];
credentials: Credential[];
preferredLanguage?: string; // BCP-47
status: 'active' | 'suspended' | 'deactivated';
employmentStatus: 'employed' | 'contract' | 'visiting' | 'inactive';
active: boolean;
version: number;
createdAt: ISODate;
updatedAt: ISODate;
}
interface Credential {
id: CredentialId;
type: 'license' | 'certification' | 'degree';
number: string;
issuingAuthority: string;
issuedAt: ISODate;
expiresAt?: ISODate;
status: 'active' | 'expired' | 'suspended' | 'revoked';
notes?: string;
}
Invariants:
- At least one
nameswithuse='official'. identifier.valueunique per(authority, system)(BR-PROV-003 style).- Deactivated practitioners cannot be selected in new clinical actions (BR-PROV-002 equivalent).
- Active
PractitionerRolecannot exist without at least oneactivecredential in required set (BR-PROV-001).
State machine:
4.2 PractitionerRole (root)
interface PractitionerRole {
id: PractitionerRoleId;
tenantId: TenantId;
practitionerId: PractitionerId;
hierarchyNodeId?: HierarchyNodeId; // scope: department/location/ward
healthcareServiceId?: HealthcareServiceId;
role: string; // e.g., 'consultant', 'resident', 'head-of-dept'
privileges: Privilege[];
period: { start: ISODate; end?: ISODate };
active: boolean;
version: number;
}
Invariants:
- Privileges requiring ordering require a valid
Credentialon the Practitioner (BR-PROV-001). - Cannot be created if Practitioner is
deactivated.
4.3 HealthcareService (root)
interface HealthcareService {
id: HealthcareServiceId;
tenantId: TenantId;
hierarchyNodeId?: HierarchyNodeId;
locationId?: LocationId;
name: string;
category: string; // e.g., 'outpatient', 'imaging', 'rehabilitation'
specialties: SpecialtyCode[];
active: boolean;
version: number;
}
4.4 ServiceEndpoint (root)
interface ServiceEndpoint {
id: EndpointId;
tenantId: TenantId;
organizationNodeId?: HierarchyNodeId;
locationId?: LocationId;
type: 'fhir-r4' | 'hl7v2' | 'dicom' | 'webhook' | 'other';
address: string; // URL
status: 'active' | 'inactive' | 'error' | 'deprecated';
authMethod: 'oauth2' | 'mtls' | 'basic' | 'none';
lastHealthCheck?: { status: 'ok'|'degraded'|'down'; at: ISODate; latencyMs?: number };
version: number;
}
5. Domain Events
| Event | Aggregate | Trigger |
|---|---|---|
provider_directory.practitioner.created.v1 | Practitioner | Create |
provider_directory.practitioner.updated.v1 | Practitioner | Name/telecom/specialty change |
provider_directory.practitioner.deactivated.v1 | Practitioner | Deactivate |
provider_directory.credential.added.v1 | Credential | Add credential |
provider_directory.credential.updated.v1 | Credential | Update (e.g., extend expiry) |
provider_directory.credential.expiring.v1 | Credential | Scheduled: 60/30/7 days pre-expiry |
provider_directory.credential.expired.v1 | Credential | Expiry date passed |
provider_directory.role.assigned.v1 | Role | Create role |
provider_directory.role.revoked.v1 | Role | End role |
provider_directory.healthcare_service.created.v1 | HealthcareService | Create |
provider_directory.endpoint.updated.v1 | Endpoint | Update |
provider_directory.endpoint.health_changed.v1 | Endpoint | Health status transition |