KRS Practitioner Replication
Practitioner Replication (CCR0297)
Overview
In addition to citizen (patient) replication from CPR/Sikrede, fut-krs-client also replicates
healthcare practitioner data from two SKRS registers maintained on NSP:
Autorisationsregisteret — the Danish Health Authority's register of healthcare professional
authorizations (læger, sygeplejersker, fysioterapeuter, etc.)Yderregisteret — SDSD's register of general practitioners (ydere) and their affiliated
personnel (yderpersoner)
The goal is to keep FHIR Practitioner resources in the Organization Service up to date with the
latest authorization and provider affiliation data from the national registers, without requiring
manual maintenance.
Practitioner replication is controlled by a single PractitionerReplicationRunner that coordinates
the two phases: authorization replication always runs first, and provider (yder) replication only
runs when authorization is fully caught up within the current transaction budget. This ordering
preserves the invariant that yder data enriches practitioners that already exist — practitioners
are created by authorization replication, never by yder replication.
CPR-to-Keycloak-UUID resolution
Both SKRS registers identify practitioners by CPR number, while FHIR resources in FUT are
identified by their Keycloak UUID (the kc-uuid identifier). The kc-uuid is the stable internal
user identity used across all FUT services.
During replication, CPR numbers are resolved to Keycloak UUIDs by calling the kc-uuid API onfut-keycloak. The API either returns an existing mapping or creates a new UUID entry for
previously unseen CPR numbers. The base URL for the kc-uuid API is derived fromehealth.client.authz.url and ehealth.client.authz.realm:
<ehealth.client.authz.url>/realms/<ehealth.client.authz.realm>/kc-uuid/batch-map-cpr-to-uuidAuthorization register integration
Source register: autorisationsregisteret / datatype autorisation (SKRS version 5)
NSP reference: https://www.nspop.dk/spaces/Web3/pages/94656873/B02+Autorisations+registret
The authorization register contains one record per healthcare professional authorization. A single
person may hold multiple authorizations (e.g. both nurse and midwife). Each record includes:
SKRS field | Description | Mapped to FHIR |
|---|---|---|
| Authorization identifier |
|
| Practitioner CPR number | Used for kc-uuid resolution only |
| First name |
|
| Last name |
|
| Profession group code (DK Core) |
|
| Whether the authorization is valid | Affects qualification period end date |
| Record validity start (SKRS replication field) |
|
| Record validity end (SKRS replication field) |
|
When practitioners are created or updated from authorization data:
A Practitioner is created when the CPR resolves to a UUID that has no existing Practitioner
resource in the Organization Service.A Practitioner is updated when a resource already exists for the resolved UUID. Only the
name and qualifications are written — other attributes are not touched.Records with an expired
validTo(SKRS replication validity, not the authorization period) are
filtered out before processing.Records without an
uddannelseskodeare skipped because the DK Coreehealth-practitioner
profile requires a qualification code.If a CPR number cannot be resolved to a UUID (the kc-uuid API returns no result), the record is
skipped and a debug log entry is written.Qualification deduplication: An authorization qualification is only added to a Practitioner if
no existing qualification already carries the sameautorisationsnummeridentifier. This prevents
duplicates across replication runs.Qualification period:
validFrommaps toperiod.start.validTomaps toperiod.end.
IfvalidTois absent butautorisationGyldigis"0"or"false",period.endis set to
the current timestamp to indicate a revoked authorization.
Yder register integration
Source register: yderregister — two datatypes processed in sequence:
Datatype | SKRS identifier key | Purpose |
|---|---|---|
|
| Yder (clinic) records, including activation/deactivation dates |
|
| Person-yder affiliation links (CPR → ydernr) |
NSP reference: https://www.nspop.dk/spaces/Web3/pages/99445253/B25+Yderregisteret
Yder fields (yder datatype):
SKRS field | Description | Mapped to FHIR |
|---|---|---|
| Yder number (padded to 6 digits) |
|
| Yder registration date | Not directly mapped |
| Yder deregistration/closure date |
|
| Record validity start (SKRS field) | Used for filtering only |
| Record validity end (SKRS field) | Used for filtering only |
YderPerson fields (person datatype):
SKRS field | Description | Mapped to FHIR |
|---|---|---|
| Yder number the person is affiliated with |
|
| Practitioner CPR number | Used for kc-uuid resolution only |
| Link validity start (SKRS field) |
|
| Link validity end (SKRS field) |
|
The yder FHIR extension is at:<http://ehealth.sundhed.dk/fhir/StructureDefinition/ehealth-practitioner-yder>
When practitioners are updated from yder data:
Yder replication does not create new Practitioner resources. It only enriches practitioners
that were created by authorization replication.If no existing Practitioner is found for a resolved UUID, the yderperson record is normally
skipped. Exception: if the most recentvalidFromdate among the person's yder links is
withinprovider.replication.missingPractitionerPauseDaysdays (default: 2), replication pauses at the current offset and does not advance. This allows authorization replication to create the missing Practitioner on the next run before yder data is applied.Each yder affiliation is stored as a separate
yderextension entry on the Practitioner,
identified by ydernr. Existing entries for the same ydernr are updated in place; new ydernr
entries are added.period.startis set fromvalidFromon the yderperson link.period.endis set fromAfgDatoYderon the yder record (clinic deactivation) if present,
otherwise fromvalidToon the yderperson link.When a yder is deactivated (
AfgDatoYderset), all practitioners associated with that ydernr
have theirperiod.endupdated regardless of yderperson replication progress.
Error handling
Situation | Behaviour |
|---|---|
SKRS SOAP fault or connection error |
|
kc-uuid API returns no result for a CPR | Record is skipped; logged at DEBUG level. |
Authorization record without | Record is skipped; logged at WARN level. |
FHIR version conflict on update (HTTP 409) | Practitioner is re-fetched by UUID and the update is retried once. If it fails again, the error is logged at ERROR level and the next practitioner is processed. |
Offset not advancing after a SKRS page fetch |
|
Yderperson references a practitioner that does not yet exist with a recent | Replication pauses at the current offset until the next run. Authorization replication has a chance to create the practitioner first. |
Any other exception during create/update of a single practitioner | Error is logged and the next practitioner is processed. The offset is still advanced at end of page. |