From 39b02232b7fac32391cbfc68a0e54cc13b3d3bb4 Mon Sep 17 00:00:00 2001 From: oliverduenielsen Date: Wed, 19 Nov 2025 14:24:22 +0100 Subject: [PATCH 01/27] first draft of ehealth-carecommunication --- input/fsh/ehealth-carecommunication.fsh | 176 ++++++++++++++++++++++++ 1 file changed, 176 insertions(+) create mode 100644 input/fsh/ehealth-carecommunication.fsh diff --git a/input/fsh/ehealth-carecommunication.fsh b/input/fsh/ehealth-carecommunication.fsh new file mode 100644 index 000000000..59316a121 --- /dev/null +++ b/input/fsh/ehealth-carecommunication.fsh @@ -0,0 +1,176 @@ +// comment for later: +// The note "should also exist in the MedcomCareCommunicationMessage bundle" is a packaging rule—consider documenting +// this in your IG narrative, as you can't force presence in a different Bundle with profile alone. + + +Profile: ehealth-carecommunication +Id: ehealth-carecommunication +Parent: Communication + +* identifier 1..1 MS +* identifier.use 0..1 +* identifier.use from http://hl7.org/fhir/ValueSet/identifier-use (required) +* identifier.value 1..1 MS +* identifier ^short = "The communication identifier" + +* status 1..1 MS + +// we do not want medcom categories in our IG +* category 1..1 MS +* category.coding 1..1 MS +* category.coding.system = "http://medcomfhir.dk/ig/terminology/CodeSystem/medcom-careCommunication-categoryCodes" MS +* category.coding.code from http://medcomfhir.dk/ig/terminology/CodeSystem/medcom-careCommunication-categoryCodes (required) MS + +* subject 1..1 MS +* subject only Reference(Patient) + +* encounter MS + +* topic 0..1 MS +* topic.text 1..1 MS +* topic.text ^short = "Plain text representation of the concept." +* topic.text ^definition = "The topic must be present." + +* priority MS +* priority ^short = "The priority of the communication." +* priority only code +* priority from http://ehealth.sundhed.dk/vs/priority (required) + +* extension contains ehealth-practitionerrole-extension named practitionerRole 0..1 + +* extension contains ehealth-practitioner-extension named author 0..1 MS + +* extension contains ehealth-destination-extension named destination 1..1 MS + +* recipient only Reference(CareTeam) MS + +* extension contains ehealth-administrative-status named administrativeStatus 1..1 + +* extension contains ehealth-Carecommunication-bundle-extension named careCommunicationBundle 1..1 MS + +* payload 1..* +* payload ^slicing.discriminator.type = #value +* payload ^slicing.discriminator.path = "content[x]" +* payload ^slicing.rules = #open + +* payload contains string 1..* +* payload[string].contentString 1..1 MS +* payload[string].contentString ^short = "Message payload." +* payload[string].extension contains + ehealth-datetime-extension named date 1..1 MS and + ehealth-practitioner-extension named author 1..1 MS and + ehealth-contact-extension named authorContact 1..1 MS and + ehealth-sending-organization-extension named sendingOrganization 1..1 MS + +* payload contains Attachment 0..* +* payload[Attachment].contentAttachment 1..1 MS +* payload[Attachment].contentAttachment ^short = "The payload with an attachment shall contain a link or content attached to the message." +* payload[attachment].extension contains + ehealth-datetime-extension named date 1..1 MS and + ehealth-practitioner-extension named author 0..1 MS and + ehealth-contact-extension named authorContact 0..1 MS and + ehealth-sending-organization-extension named sendingOrganization 1..1 MS + +Extension: ehealth-practitionerrole-extension +Title: "PractitionerRole Extension" +Description: "Reference to the sending PractitionerRole for this communication." +* . ^short = "sending practitioner role" +* value[x] only Reference(PractitionerRole) + +Extension: ehealth-practitioner-extension +Title: "Practitioner Extension" +Description: "Reference to the sending Practitioner for this communication." +* . ^short = "sending practitioner" +* value[x] only Reference(Practitioner) + +Extension: ehealth-destination-extension +Title: "Destination Extension" +Description: "Reference to the destination Organization for this communication." +* . ^short = "destination organization" +* value[x] only Reference(Organization) + +Extension: ehealth-Carecommunication-bundle-extension +Title: "Destination Extension" +Description: "Reference to the careCommunication Bundle received." +* . ^short = "carecommunication bundle" +* value[x] only Reference(Bundle) + +Extension: ehealth-administrative-status +Title: "Administrative status" +Description: "The administrative status of how a message recipient has handled a message" +* . ^short = "The administrative status of how a message recipient has handled a message" +* value[x] only Coding +* valueCoding from http://ehealth.sundhed.dk/vs/administrative-status +* valueCoding 1..1 + +Extension: ehealth-datetime-extension +Title: "DateTime Extension" +Description: "Date and time of the payload segment." +* . ^short = "Payload dateTime" +* value[x] only dateTime + +Extension: ehealth-practitioner-extension +Title: "Practitioner Extension" +Description: "Reference to the author (practitioner role) of this payload segment." +* . ^short = "Payload author" +* value[x] only Reference(MedComCorePractitionerRole) + +Extension: ehealth-contact-extension +Title: "Contact Extension" +Description: "Contact point for the author of this payload segment." +* . ^short = "Payload author contact" +* value[x] only ContactPoint + +Extension: ehealth-sending-organization-extension +Title: "sender Organization" +Description: "Reference to the sending organization for this payload segment." +* . ^short = "Reference to the sending organization" +* value[x] only Reference(Organization) + +// invariants + +Invariant: stopped-status-statusReason +Description: "If status is 'stopped', statusReason must be either 'system-error' or 'recipient-unavailable'." +Expression: "status != 'stopped' or statusReason.coding.where(code = 'system-error' or code = 'recipient-unavailable').exists()" +Severity: #error + +Invariant: only-asap-or-routine +Description: "priority must be either 'asap' or 'routine'" +Expression: "priority = 'asap' or priority = 'routine'" +Severity: #error + +Invariant: topic-required-when-category-other +Description: "topic must be present when category is 'other'." +Expression: "iif(category.coding.code != 'other', true, category.coding.code = 'other' and topic.exists())" +Severity: #error + +Invariant: practitionerrole-author-coding-xor-text +Description: "If a PractitionerRole is used as an author (via the Practitioner extension), then either code.coding.code or code.text must exist—but not both." +Expression: "payload.extension('http://ehealth.sundhed.dk/fhir/StructureDefinition/ehealth-practitioner').value.resolve().all(code.coding.code.exists() xor code.text.exists())" +Severity: #error + +Invariant: practitioner-author-must-have-name +Description: "If a Practitioner is used as author in a message segment, the referenced Practitioner must have a name." +Expression: "payload.where(extension('http://ehealth.sundhed.dk/fhir/StructureDefinition/ehealth-practitioner').exists()).extension.value.reference.resolve().practitioner.resolve().name.exists()" +Severity: #error + +Invariant: priority-category-invariant +Description: "Priority must not be present when category is not 'regarding-referral'." +Expression: "where(category.coding.code != 'regarding-referral').priority.empty()" +Severity: #error + +Invariant: uuidv4 +Description: "The identifier.value SHALL be a valid UUID v4" +Expression: "identifier.value.matches('^[0-9a-f]{8}-[0-9a-f]{4}-4[0-9a-f]{3}-[89ab][0-9a-f]{3}-[0-9a-f]{12}$')" +Severity: #error + +Invariant: atLeastOnePayloadString +Description: "At least one payload segment shall have a message text (payload.contentString)" +Expression: "payload.contentString.exists()" +Severity: #error + +Invariant: payloadAttachment-contentType-required +Description: "contentType SHALL be present if data or url is present in Attachment" +Expression: "payload.contentAttachment.data.exists() or payload.contentAttachment.url.exists() implies payload.contentAttachment.contentType.exists()" +Severity: #error + From 962684d9bd01b305b412283b4cc7959bcd6079c6 Mon Sep 17 00:00:00 2001 From: oliverduenielsen Date: Wed, 19 Nov 2025 14:37:58 +0100 Subject: [PATCH 02/27] MS fix --- input/fsh/ehealth-carecommunication.fsh | 12 ++++-------- 1 file changed, 4 insertions(+), 8 deletions(-) diff --git a/input/fsh/ehealth-carecommunication.fsh b/input/fsh/ehealth-carecommunication.fsh index 59316a121..c612a4ad5 100644 --- a/input/fsh/ehealth-carecommunication.fsh +++ b/input/fsh/ehealth-carecommunication.fsh @@ -18,8 +18,10 @@ Parent: Communication // we do not want medcom categories in our IG * category 1..1 MS * category.coding 1..1 MS -* category.coding.system = "http://medcomfhir.dk/ig/terminology/CodeSystem/medcom-careCommunication-categoryCodes" MS -* category.coding.code from http://medcomfhir.dk/ig/terminology/CodeSystem/medcom-careCommunication-categoryCodes (required) MS +* category.coding.system = "http://medcomfhir.dk/ig/terminology/CodeSystem/medcom-careCommunication-categoryCodes" +* category.coding.system MS +* category.coding.code from http://medcomfhir.dk/ig/terminology/CodeSystem/medcom-careCommunication-categoryCodes (required) +* category.coding.code MS * subject 1..1 MS * subject only Reference(Patient) @@ -109,12 +111,6 @@ Description: "Date and time of the payload segment." * . ^short = "Payload dateTime" * value[x] only dateTime -Extension: ehealth-practitioner-extension -Title: "Practitioner Extension" -Description: "Reference to the author (practitioner role) of this payload segment." -* . ^short = "Payload author" -* value[x] only Reference(MedComCorePractitionerRole) - Extension: ehealth-contact-extension Title: "Contact Extension" Description: "Contact point for the author of this payload segment." From 53c93583cf84c01e0fc715552c3375ccb20c4bba Mon Sep 17 00:00:00 2001 From: oliverduenielsen Date: Wed, 19 Nov 2025 14:45:43 +0100 Subject: [PATCH 03/27] MS fix --- input/fsh/ehealth-carecommunication.fsh | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/input/fsh/ehealth-carecommunication.fsh b/input/fsh/ehealth-carecommunication.fsh index c612a4ad5..c1a0f4a9f 100644 --- a/input/fsh/ehealth-carecommunication.fsh +++ b/input/fsh/ehealth-carecommunication.fsh @@ -44,7 +44,8 @@ Parent: Communication * extension contains ehealth-destination-extension named destination 1..1 MS -* recipient only Reference(CareTeam) MS +* recipient only Reference(CareTeam) +* recipient MS * extension contains ehealth-administrative-status named administrativeStatus 1..1 From e43d8d05b85edf24aad2ebf843d6092e6c0bfeeb Mon Sep 17 00:00:00 2001 From: oliverduenielsen Date: Fri, 21 Nov 2025 13:16:02 +0100 Subject: [PATCH 04/27] building for carecommunication works --- input/fsh/ehealth-carecommunication.fsh | 46 ++++++++++++------------- 1 file changed, 23 insertions(+), 23 deletions(-) diff --git a/input/fsh/ehealth-carecommunication.fsh b/input/fsh/ehealth-carecommunication.fsh index c1a0f4a9f..3a9057293 100644 --- a/input/fsh/ehealth-carecommunication.fsh +++ b/input/fsh/ehealth-carecommunication.fsh @@ -7,6 +7,17 @@ Profile: ehealth-carecommunication Id: ehealth-carecommunication Parent: Communication +* obeys + stopped-status-statusReason + and only-asap-or-routine + and topic-required-when-category-other + and practitionerrole-author-coding-xor-text + and practitioner-author-must-have-name + and priority-category-invariant + and uuidv4 + and atLeastOnePayloadString + and payloadAttachment-contentType-required + * identifier 1..1 MS * identifier.use 0..1 * identifier.use from http://hl7.org/fhir/ValueSet/identifier-use (required) @@ -17,10 +28,9 @@ Parent: Communication // we do not want medcom categories in our IG * category 1..1 MS +* category from http://medcomfhir.dk/ig/terminology/CodeSystem/medcom-careCommunication-categoryCodes (required) * category.coding 1..1 MS -* category.coding.system = "http://medcomfhir.dk/ig/terminology/CodeSystem/medcom-careCommunication-categoryCodes" * category.coding.system MS -* category.coding.code from http://medcomfhir.dk/ig/terminology/CodeSystem/medcom-careCommunication-categoryCodes (required) * category.coding.code MS * subject 1..1 MS @@ -34,16 +44,17 @@ Parent: Communication * topic.text ^definition = "The topic must be present." * priority MS -* priority ^short = "The priority of the communication." +* priority ^short = "Shall be present if the message priority is known to be ASAP, but is only allowed when the category is 'regarding referral', see priority-category-invariant" * priority only code * priority from http://ehealth.sundhed.dk/vs/priority (required) * extension contains ehealth-practitionerrole-extension named practitionerRole 0..1 -* extension contains ehealth-practitioner-extension named author 0..1 MS +* extension contains ehealth-practitioner-extension named practitioner 0..1 MS * extension contains ehealth-destination-extension named destination 1..1 MS +* recipient 0..1 * recipient only Reference(CareTeam) * recipient MS @@ -52,22 +63,19 @@ Parent: Communication * extension contains ehealth-Carecommunication-bundle-extension named careCommunicationBundle 1..1 MS * payload 1..* -* payload ^slicing.discriminator.type = #value +* payload ^slicing.discriminator.type = #type * payload ^slicing.discriminator.path = "content[x]" * payload ^slicing.rules = #open +* payload contains string 1..* and attachment 0..* -* payload contains string 1..* * payload[string].contentString 1..1 MS -* payload[string].contentString ^short = "Message payload." * payload[string].extension contains - ehealth-datetime-extension named date 1..1 MS and - ehealth-practitioner-extension named author 1..1 MS and - ehealth-contact-extension named authorContact 1..1 MS and - ehealth-sending-organization-extension named sendingOrganization 1..1 MS - -* payload contains Attachment 0..* -* payload[Attachment].contentAttachment 1..1 MS -* payload[Attachment].contentAttachment ^short = "The payload with an attachment shall contain a link or content attached to the message." + ehealth-datetime-extension named date 1..1 MS and + ehealth-practitioner-extension named author 1..1 MS and + ehealth-contact-extension named authorContact 1..1 MS and + ehealth-sending-organization-extension named sendingOrganization 1..1 MS + +* payload[attachment].contentAttachment 1..1 MS * payload[attachment].extension contains ehealth-datetime-extension named date 1..1 MS and ehealth-practitioner-extension named author 0..1 MS and @@ -98,14 +106,6 @@ Description: "Reference to the careCommunication Bundle received." * . ^short = "carecommunication bundle" * value[x] only Reference(Bundle) -Extension: ehealth-administrative-status -Title: "Administrative status" -Description: "The administrative status of how a message recipient has handled a message" -* . ^short = "The administrative status of how a message recipient has handled a message" -* value[x] only Coding -* valueCoding from http://ehealth.sundhed.dk/vs/administrative-status -* valueCoding 1..1 - Extension: ehealth-datetime-extension Title: "DateTime Extension" Description: "Date and time of the payload segment." From 10db7d2ff9c42788732ad2ff90efc6bf96ab50ee Mon Sep 17 00:00:00 2001 From: oliverduenielsen Date: Fri, 5 Dec 2025 08:37:44 +0100 Subject: [PATCH 05/27] Added valueset with conceptmap to priority and category elements, changed card. for inReferenceTo and sender --- input/fsh/ehealth-carecommunication.fsh | 148 +++++++++++-- ...ConceptMap-CareCommunication-Priority.json | 36 ++++ ...ConceptMap-CareCommunucation-Category.json | 196 ++++++++++++++++++ 3 files changed, 361 insertions(+), 19 deletions(-) create mode 100644 input/resources/ConceptMap-CareCommunication-Priority.json create mode 100644 input/resources/ConceptMap-CareCommunucation-Category.json diff --git a/input/fsh/ehealth-carecommunication.fsh b/input/fsh/ehealth-carecommunication.fsh index 3a9057293..bee3e5cb3 100644 --- a/input/fsh/ehealth-carecommunication.fsh +++ b/input/fsh/ehealth-carecommunication.fsh @@ -17,6 +17,8 @@ Parent: Communication and uuidv4 and atLeastOnePayloadString and payloadAttachment-contentType-required + and no-standard-sender + and category-not-required-if-dest-TBD * identifier 1..1 MS * identifier.use 0..1 @@ -26,12 +28,11 @@ Parent: Communication * status 1..1 MS -// we do not want medcom categories in our IG -* category 1..1 MS -* category from http://medcomfhir.dk/ig/terminology/CodeSystem/medcom-careCommunication-categoryCodes (required) +* category 0..1 MS +* category from http://ehealth.sundhed.dk/vs/ehealth-carecommunication-category (required) * category.coding 1..1 MS -* category.coding.system MS -* category.coding.code MS +* category.coding.system 1..1 MS +* category.coding.code 1..1 MS * subject 1..1 MS * subject only Reference(Patient) @@ -46,7 +47,7 @@ Parent: Communication * priority MS * priority ^short = "Shall be present if the message priority is known to be ASAP, but is only allowed when the category is 'regarding referral', see priority-category-invariant" * priority only code -* priority from http://ehealth.sundhed.dk/vs/priority (required) +* priority from http://ehealth.sundhed.dk/vs/ehealth-carecommunication-priority (required) * extension contains ehealth-practitionerrole-extension named practitionerRole 0..1 @@ -54,13 +55,28 @@ Parent: Communication * extension contains ehealth-destination-extension named destination 1..1 MS +* extension contains ehealth-origin-organization-extension named origin 1..1 MS + +* extension contains ehealth-sending-actor-extension named sender 0..1 MS + +* extension contains ehealth-message-Type-extension named messageType 1..1 MS + * recipient 0..1 -* recipient only Reference(CareTeam) +* recipient only Reference(CareTeam or PractitionerRole) * recipient MS +* recipient ^short = "The recieving actor of the message" + +* inResponseTo 0..1 MS + +* sender 0..0 + +* basedOn 0..0 + +* partOf 0..0 * extension contains ehealth-administrative-status named administrativeStatus 1..1 -* extension contains ehealth-Carecommunication-bundle-extension named careCommunicationBundle 1..1 MS +* extension contains ehealth-Carecommunication-bundle-extension named medComCareCommunicationBundle 0..1 MS * payload 1..* * payload ^slicing.discriminator.type = #type @@ -71,16 +87,12 @@ Parent: Communication * payload[string].contentString 1..1 MS * payload[string].extension contains ehealth-datetime-extension named date 1..1 MS and - ehealth-practitioner-extension named author 1..1 MS and - ehealth-contact-extension named authorContact 1..1 MS and - ehealth-sending-organization-extension named sendingOrganization 1..1 MS + ehealth-contact-extension named authorContact 1..1 MS * payload[attachment].contentAttachment 1..1 MS * payload[attachment].extension contains ehealth-datetime-extension named date 1..1 MS and - ehealth-practitioner-extension named author 0..1 MS and - ehealth-contact-extension named authorContact 0..1 MS and - ehealth-sending-organization-extension named sendingOrganization 1..1 MS + ehealth-contact-extension named authorContact 0..1 MS Extension: ehealth-practitionerrole-extension Title: "PractitionerRole Extension" @@ -97,7 +109,7 @@ Description: "Reference to the sending Practitioner for this communication." Extension: ehealth-destination-extension Title: "Destination Extension" Description: "Reference to the destination Organization for this communication." -* . ^short = "destination organization" +* . ^short = "Organization receiving the message" * value[x] only Reference(Organization) Extension: ehealth-Carecommunication-bundle-extension @@ -118,13 +130,102 @@ Description: "Contact point for the author of this payload segment." * . ^short = "Payload author contact" * value[x] only ContactPoint -Extension: ehealth-sending-organization-extension -Title: "sender Organization" +Extension: ehealth-origin-organization-extension +Title: "sender organization" Description: "Reference to the sending organization for this payload segment." -* . ^short = "Reference to the sending organization" +* . ^short = "Reference to the sending organization of the message" * value[x] only Reference(Organization) -// invariants +Extension: ehealth-message-Type-extension +Title: "Message type" +Description: "The type of the message. If inResponseTo is present, the type can not be new-message." +* value[x] only code +* valueCode from MessageTypeVS (required) +* . ^short = "Message type" + +Extension: ehealth-sending-actor-extension +Title: "Sending Actor Extension" +Description: "Reference to the sending actor (e.g., CareTeam or PractitionerRole) for this communication." +* . ^short = "Sending actor" +* value[x] only Reference(CareTeam or PractitionerRole) + + +// Valuesets + +ValueSet: MessageTypeVS +Title: "Message Type ValueSet" +Description: "Allowed message types: new, reply, forward." +* ^compose.include.system = "http://ehealth.sundhed.dk/cs/message-type" +* ^compose.include.concept[+].code = #new +* ^compose.include.concept[=].display = "New Message" +* ^compose.include.concept[+].code = #reply +* ^compose.include.concept[=].display = "Reply" +* ^compose.include.concept[+].code = #forward +* ^compose.include.concept[=].display = "Forward" + +ValueSet: EhealthCareCommunicationCategoryVS +Id: ehealth-carecommunication-category +Title: "eHealth CareCommunication Categories" +* ^url = "http://ehealth.sundhed.dk/vs/ehealth-carecommunication-category" +* ^status = #active +* ^description = "Categories used for CareCommunciation messages." +* ^compose.include.system = "http://ehealth.sundhed.dk/cs/ehealth-carecommunication-category" + +ValueSet: EhealthCareCommunicationPriorityVS +Id: ehealth-carecommunication-priority +Title: "eHealth CareCommunication Priorities" +* ^url = "http://ehealth.sundhed.dk/vs/ehealth-carecommunication-priority" +* ^status = #active +* ^description = "Priorities used for CareCommunication messages." +* ^compose.include.system = "http://ehealth.sundhed.dk/cs/ehealth-carecommunication-priority" + + +// CodeSystems + +CodeSystem: MessageTypeCS +Title: "Message Type CodeSystem" +Description: "Allowed codes for message type." +* ^url = "http://ehealth.sundhed.dk/cs/message-type" +* #new "New Message" +* #reply "Reply" +* #forward "Forward" + +CodeSystem: EhealthCareCommunicationCategoryCS +Id: ehealth-carecommunication-category +Title: "eHealth CareCommunication Category codes" +Description: "The set of CareCommunication category code." +* ^url = "http://ehealth.sundhed.dk/cs/ehealth-carecommunication-category" +* #alcohol-and-drug-treatment "Alcohol and drug treatment" +* #assistive-devices "Assistive technology" +* #carecoordination "Care Coordination" +* #decease "Decease" +* #discharge "Discharge" +* #examination-results "Examination Results" +* #healthcare "Healthcare" +* #home-care-assessment "Home care assessment" +* #medicine "Medicine" +* #nursing "Nursing" +* #outpatient "Outpatient" +* #psychiatry-social-disability "Psychiatry, Social, Disability" +* #regarding-referral "Regarding Referral" +* #telemedicine "Telemedicine" +* #training "Training" +* #acute-ambulant "Acute ambulant" +* #extended-care-responsibility "Extended care responsibility" +* #other "Other" + +CodeSystem: EhealthCareCommunicationPriorityCS +Id: ehealth-carecommunication-priority +Title: "eHealth CareCommunication Priority codes" +Description: "The set of CareCommunication priority code." +* ^url = "http://ehealth.sundhed.dk/cs/ehealth-carecommunication-priority" +* #routine "Routine" +* #asap "ASAP" + + + + +// Invariants Invariant: stopped-status-statusReason Description: "If status is 'stopped', statusReason must be either 'system-error' or 'recipient-unavailable'." @@ -171,3 +272,12 @@ Description: "contentType SHALL be present if data or url is present in Attachme Expression: "payload.contentAttachment.data.exists() or payload.contentAttachment.url.exists() implies payload.contentAttachment.contentType.exists()" Severity: #error +Invariant: no-standard-sender +Description: "The standard Communication.sender element SHALL NOT be used. Use the ehealth-sending-actor extension instead." +Expression: "sender.empty()" +Severity: #error + +Invariant: category-not-required-if-dest-TBD +Description: "category may be omitted if extension 'destination' is the reference FUTORGANIZATIONREFERENCETBD, otherwise category must be present" +Expression: "extension('http://ehealth.sundhed.dk/fhir/StructureDefinition/ehealth-destination-extension').value.as(Reference).reference = 'FUTORGANIZATIONREFERENCETBD' or category.exists()" +Severity: #error \ No newline at end of file diff --git a/input/resources/ConceptMap-CareCommunication-Priority.json b/input/resources/ConceptMap-CareCommunication-Priority.json new file mode 100644 index 000000000..31d46f981 --- /dev/null +++ b/input/resources/ConceptMap-CareCommunication-Priority.json @@ -0,0 +1,36 @@ +{ + "resourceType": "ConceptMap", + "id": "ehealth-to-medcom-carecommunication-priority", + "url": "http://ehealth.sundhed.dk/cm/ehealth-to-medcom-carecommunication-priority", + "version": "1.0.0", + "status": "active", + "title": "eHealth to MedCom CareCommunication Priority Map", + "group": [ + { + "source": "http://ehealth.sundhed.dk/cs/ehealth-carecommunication-priority", + "target": "http://medcomfhir.dk/ig/terminology/ValueSet/medcom-careCommunication-requestPriority", + "element": [ + { + "code": "routine", + "target": [ + { + "code": "routine", + "display": "Routine", + "relationship": "equivalent" + } + ] + }, + { + "code": "asap", + "target": [ + { + "code": "asap", + "display": "ASAP", + "relationship": "equivalent" + } + ] + } + ] + } + ] +} \ No newline at end of file diff --git a/input/resources/ConceptMap-CareCommunucation-Category.json b/input/resources/ConceptMap-CareCommunucation-Category.json new file mode 100644 index 000000000..a71865a70 --- /dev/null +++ b/input/resources/ConceptMap-CareCommunucation-Category.json @@ -0,0 +1,196 @@ +{ + "resourceType": "ConceptMap", + "id": "ehealth-to-medcom-carecommunication-category", + "url": "http://ehealth.sundhed.dk/cm/ehealth-to-medcom-carecommunication-category", + "version": "1.0.0", + "status": "active", + "title": "eHealth to MedCom CareCommunication Category Map", + "group": [ + { + "source": "http://ehealth.sundhed.dk/cs/ehealth-carecommunication-category", + "target": "http://medcomfhir.dk/ig/terminology/ValueSet/medcom-careCommunication-categories", + "element": [ + { + "code": "alcohol-and-drug-treatment", + "target": [ + { + "code": "alcohol-and-drug-treatment", + "display": "Alcohol and drug treatment", + "relationship": "equivalent" + } + ] + }, + { + "code": "assistive-devices", + "target": [ + { + "code": "assistive-devices", + "display": "Assistive technology", + "relationship": "equivalent" + } + ] + }, + { + "code": "carecoordination", + "target": [ + { + "code": "carecoordination", + "display": "Care Coordination", + "relationship": "equivalent" + } + ] + }, + { + "code": "decease", + "target": [ + { + "code": "decease", + "display": "Decease", + "relationship": "equivalent" + } + ] + }, + { + "code": "discharge", + "target": [ + { + "code": "discharge", + "display": "Discharge", + "relationship": "equivalent" + } + ] + }, + { + "code": "examination-results", + "target": [ + { + "code": "examination-results", + "display": "Examination Results", + "relationship": "equivalent" + } + ] + }, + { + "code": "healthcare", + "target": [ + { + "code": "healthcare", + "display": "Healthcare", + "relationship": "equivalent" + } + ] + }, + { + "code": "home-care-assessment", + "target": [ + { + "code": "home-care-assessment", + "display": "Home care assessment", + "relationship": "equivalent" + } + ] + }, + { + "code": "medicine", + "target": [ + { + "code": "medicine", + "display": "Medicine", + "relationship": "equivalent" + } + ] + }, + { + "code": "nursing", + "target": [ + { + "code": "nursing", + "display": "Nursing", + "relationship": "equivalent" + } + ] + }, + { + "code": "outpatient", + "target": [ + { + "code": "outpatient", + "display": "Outpatient", + "relationship": "equivalent" + } + ] + }, + { + "code": "psychiatry-social-disability", + "target": [ + { + "code": "psychiatry-social-disability", + "display": "Psychiatry, Social, Disability", + "relationship": "equivalent" + } + ] + }, + { + "code": "regarding-referral", + "target": [ + { + "code": "regarding-referral", + "display": "Regarding Referral", + "relationship": "equivalent" + } + ] + }, + { + "code": "telemedicine", + "target": [ + { + "code": "telemedicine", + "display": "Telemedicine", + "relationship": "equivalent" + } + ] + }, + { + "code": "training", + "target": [ + { + "code": "training", + "display": "Training", + "relationship": "equivalent" + } + ] + }, + { + "code": "acute-ambulant", + "target": [ + { + "code": "acute-ambulant", + "display": "Acute ambulant", + "relationship": "equivalent" + } + ] + }, + { + "code": "extended-care-responsibility", + "target": [ + { + "code": "extended-care-responsibility", + "display": "Extended care responsibility", + "relationship": "equivalent" + } + ] + }, + { + "code": "other", + "target": [ + { + "code": "other", + "display": "Other", + "relationship": "equivalent" + } + ] + } + ] + } + ] +} \ No newline at end of file From 1d767baee83cc25cbf32e187d1ac52ee995d2cae Mon Sep 17 00:00:00 2001 From: oliverduenielsen Date: Wed, 17 Dec 2025 09:55:03 +0100 Subject: [PATCH 06/27] refactor of sender extension - now holds PractitionerRole, Practitioner and CareTeam --- input/fsh/ehealth-carecommunication.fsh | 119 ++++++++++++------------ input/pagecontent/changelog.md | 9 ++ 2 files changed, 67 insertions(+), 61 deletions(-) diff --git a/input/fsh/ehealth-carecommunication.fsh b/input/fsh/ehealth-carecommunication.fsh index bee3e5cb3..3e82eef7e 100644 --- a/input/fsh/ehealth-carecommunication.fsh +++ b/input/fsh/ehealth-carecommunication.fsh @@ -11,14 +11,12 @@ Parent: Communication stopped-status-statusReason and only-asap-or-routine and topic-required-when-category-other - and practitionerrole-author-coding-xor-text - and practitioner-author-must-have-name and priority-category-invariant and uuidv4 and atLeastOnePayloadString and payloadAttachment-contentType-required and no-standard-sender - and category-not-required-if-dest-TBD + and sender-required-based-on-messagetype * identifier 1..1 MS * identifier.use 0..1 @@ -28,38 +26,37 @@ Parent: Communication * status 1..1 MS -* category 0..1 MS +* category 1..1 MS * category from http://ehealth.sundhed.dk/vs/ehealth-carecommunication-category (required) * category.coding 1..1 MS * category.coding.system 1..1 MS +* category.coding.system = "http://ehealth.sundhed.dk/cs/ehealth-carecommunication-category" * category.coding.code 1..1 MS * subject 1..1 MS * subject only Reference(Patient) * encounter MS +* encounter ^short = "Shall contain a reference to an Encounter resource with a episodeOfCare-identifier, if the identifier is included in a previous message." * topic 0..1 MS +* topic ^short = "Must be added when category is "other". Topic must be added in the text-element." * topic.text 1..1 MS * topic.text ^short = "Plain text representation of the concept." * topic.text ^definition = "The topic must be present." * priority MS -* priority ^short = "Shall be present if the message priority is known to be ASAP, but is only allowed when the category is 'regarding referral', see priority-category-invariant" +* priority ^short = "Only used when the category is 'regarding referral', see priority-category-invariant." * priority only code * priority from http://ehealth.sundhed.dk/vs/ehealth-carecommunication-priority (required) -* extension contains ehealth-practitionerrole-extension named practitionerRole 0..1 +* extension contains ehealth-carecommunication-sender named sender 0..1 MS -* extension contains ehealth-practitioner-extension named practitioner 0..1 MS +* extension contains ehealth-carecommunication-destination named destination 1..1 MS -* extension contains ehealth-destination-extension named destination 1..1 MS +* extension contains ehealth-carecommunication-origin named origin 1..1 MS -* extension contains ehealth-origin-organization-extension named origin 1..1 MS - -* extension contains ehealth-sending-actor-extension named sender 0..1 MS - -* extension contains ehealth-message-Type-extension named messageType 1..1 MS +* extension contains ehealth-carecommunication-message-Type named messageType 1..1 MS * recipient 0..1 * recipient only Reference(CareTeam or PractitionerRole) @@ -76,7 +73,7 @@ Parent: Communication * extension contains ehealth-administrative-status named administrativeStatus 1..1 -* extension contains ehealth-Carecommunication-bundle-extension named medComCareCommunicationBundle 0..1 MS +* extension contains ehealth-carecommunication-bundle named CorrespondingMedComCareCommunicationBundle 0..1 MS * payload 1..* * payload ^slicing.discriminator.type = #type @@ -86,75 +83,82 @@ Parent: Communication * payload[string].contentString 1..1 MS * payload[string].extension contains - ehealth-datetime-extension named date 1..1 MS and - ehealth-contact-extension named authorContact 1..1 MS + ehealth-carecommunication-datetime named date 1..1 MS and + ehealth-carecommunication-contact-point named authorContact 1..1 MS and + ehealth-carecommunication-payload-identifier named identifier 0..1 MS * payload[attachment].contentAttachment 1..1 MS * payload[attachment].extension contains - ehealth-datetime-extension named date 1..1 MS and - ehealth-contact-extension named authorContact 0..1 MS - -Extension: ehealth-practitionerrole-extension -Title: "PractitionerRole Extension" -Description: "Reference to the sending PractitionerRole for this communication." -* . ^short = "sending practitioner role" -* value[x] only Reference(PractitionerRole) - -Extension: ehealth-practitioner-extension -Title: "Practitioner Extension" -Description: "Reference to the sending Practitioner for this communication." -* . ^short = "sending practitioner" -* value[x] only Reference(Practitioner) - -Extension: ehealth-destination-extension + ehealth-carecommunication-datetime named date 1..1 MS and + ehealth-carecommunication-contact-point named authorContact 0..1 MS and + ehealth-carecommunication-payload-identifier named identifier 0..1 MS + + +// Extensions + +Extension: ehealth-carecommunication-sender +Id: ehealth-carecommunication-sender +Title: "Sender Extension, contains the sending PractitionerRole, Practitioner and CareTeam." +Description: "References the sending PractitionerRole (Actor), the Practitioner, and optionally a CareTeam." +* extension contains + actor 1..1 MS and + practitioner 1..1 MS and + careteam 0..1 MS +* extension[actor] ^short = "Sending PractitionerRole" +* extension[actor].value[x] only Reference(PractitionerRole) +* extension[practitioner] ^short = "The underlying Practitioner for this sender" +* extension[practitioner].value[x] only Reference(Practitioner) +* extension[careteam] ^short = "Optionally, the involved CareTeam" +* extension[careteam].value[x] only Reference(CareTeam) + +Extension: ehealth-carecommunication-destination Title: "Destination Extension" Description: "Reference to the destination Organization for this communication." * . ^short = "Organization receiving the message" * value[x] only Reference(Organization) -Extension: ehealth-Carecommunication-bundle-extension +Extension: ehealth-carecommunication-bundle Title: "Destination Extension" Description: "Reference to the careCommunication Bundle received." * . ^short = "carecommunication bundle" * value[x] only Reference(Bundle) -Extension: ehealth-datetime-extension +Extension: ehealth-carecommunication-datetime Title: "DateTime Extension" Description: "Date and time of the payload segment." * . ^short = "Payload dateTime" * value[x] only dateTime -Extension: ehealth-contact-extension +Extension: ehealth-carecommunication-contact-point Title: "Contact Extension" Description: "Contact point for the author of this payload segment." * . ^short = "Payload author contact" * value[x] only ContactPoint -Extension: ehealth-origin-organization-extension +Extension: ehealth-carecommunication-payload-identifier +Title: "Identifier Extension" +Description: "Extension to hold an Identifier for a payload. Value shall be a UUID identifier version 4." +* value[x] only Identifier + +Extension: ehealth-carecommunication-origin Title: "sender organization" Description: "Reference to the sending organization for this payload segment." * . ^short = "Reference to the sending organization of the message" * value[x] only Reference(Organization) -Extension: ehealth-message-Type-extension +Extension: ehealth-carecommunication-message-Type Title: "Message type" Description: "The type of the message. If inResponseTo is present, the type can not be new-message." -* value[x] only code -* valueCode from MessageTypeVS (required) +* value[x] only Coding +* valueCoding from MessageType (required) * . ^short = "Message type" -Extension: ehealth-sending-actor-extension -Title: "Sending Actor Extension" -Description: "Reference to the sending actor (e.g., CareTeam or PractitionerRole) for this communication." -* . ^short = "Sending actor" -* value[x] only Reference(CareTeam or PractitionerRole) - - // Valuesets -ValueSet: MessageTypeVS +ValueSet: MessageType Title: "Message Type ValueSet" Description: "Allowed message types: new, reply, forward." +* ^url = "http://ehealth.sundhed.dk/cm/ehealth-to-medcom-carecommunication-category" * ^compose.include.system = "http://ehealth.sundhed.dk/cs/message-type" * ^compose.include.concept[+].code = #new * ^compose.include.concept[=].display = "New Message" @@ -242,16 +246,6 @@ Description: "topic must be present when category is 'other'." Expression: "iif(category.coding.code != 'other', true, category.coding.code = 'other' and topic.exists())" Severity: #error -Invariant: practitionerrole-author-coding-xor-text -Description: "If a PractitionerRole is used as an author (via the Practitioner extension), then either code.coding.code or code.text must exist—but not both." -Expression: "payload.extension('http://ehealth.sundhed.dk/fhir/StructureDefinition/ehealth-practitioner').value.resolve().all(code.coding.code.exists() xor code.text.exists())" -Severity: #error - -Invariant: practitioner-author-must-have-name -Description: "If a Practitioner is used as author in a message segment, the referenced Practitioner must have a name." -Expression: "payload.where(extension('http://ehealth.sundhed.dk/fhir/StructureDefinition/ehealth-practitioner').exists()).extension.value.reference.resolve().practitioner.resolve().name.exists()" -Severity: #error - Invariant: priority-category-invariant Description: "Priority must not be present when category is not 'regarding-referral'." Expression: "where(category.coding.code != 'regarding-referral').priority.empty()" @@ -273,11 +267,14 @@ Expression: "payload.contentAttachment.data.exists() or payload.contentAttachmen Severity: #error Invariant: no-standard-sender -Description: "The standard Communication.sender element SHALL NOT be used. Use the ehealth-sending-actor extension instead." +Description: "The standard Communication.sender element SHALL NOT be used. Use the ehealth-carecommunication-sender extension instead." Expression: "sender.empty()" Severity: #error -Invariant: category-not-required-if-dest-TBD -Description: "category may be omitted if extension 'destination' is the reference FUTORGANIZATIONREFERENCETBD, otherwise category must be present" -Expression: "extension('http://ehealth.sundhed.dk/fhir/StructureDefinition/ehealth-destination-extension').value.as(Reference).reference = 'FUTORGANIZATIONREFERENCETBD' or category.exists()" +Invariant: sender-required-based-on-messagetype +Description: """ +If messagetype is 'new' or 'reply', the sender extension must be present. +If 'forward', sender may be absent. +""" +Expression: "extension('http://ehealth.sundhed.dk/fhir/StructureDefinition/ehealth-carecommunication-message-Type').value.coding.where(code = 'new' or code = 'reply').exists() implies extension('http://ehealth.sundhed.dk/fhir/StructureDefinition/ehealth-carecommunication-sender').exists()" Severity: #error \ No newline at end of file diff --git a/input/pagecontent/changelog.md b/input/pagecontent/changelog.md index 0a29629e7..47e991cc1 100644 --- a/input/pagecontent/changelog.md +++ b/input/pagecontent/changelog.md @@ -1,5 +1,14 @@ This is the log of changes made to the eHealth Implementation Guide. +# Next Release + +### Model +- Added http://ehealth.sundhed.dk/fhir/StructureDefinition/ehealth-carecommunication + +### Conceptmaps +- Added http://ehealth.sundhed.dk/cm/ehealth-to-medcom-carecommunication-priority +- Added http://ehealth.sundhed.dk/cm/ehealth-to-medcom-carecommunication-category + ## 7.0.0 ### CodeSystems - Added 'http://ehealth.sundhed.dk/policy/dk/aeldreloven' to http://ehealth.sundhed.dk/cs/ehealth-provenance-policies From 28999349455221374f934a614829a90bf9399a39 Mon Sep 17 00:00:00 2001 From: Mahler Date: Tue, 27 Jan 2026 09:27:58 +0100 Subject: [PATCH 07/27] [(CCR0224-changes-for-media)] Updated ehealth-media profile to allow assigning patient and relatedPerson references to operator. --- input/fsh/ehealth-media.fsh | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/input/fsh/ehealth-media.fsh b/input/fsh/ehealth-media.fsh index 4b6442bdd..3fb9bd6aa 100644 --- a/input/fsh/ehealth-media.fsh +++ b/input/fsh/ehealth-media.fsh @@ -19,7 +19,7 @@ Parent: Media * subject ^type.aggregation = #referenced * subject.reference 1..1 * created[x] 1..1 -* operator only Reference(ehealth-practitioner) +* operator only Reference(ehealth-practitioner or ehealth-patient or ehealth-relatedperson) * operator ^type.aggregation = #referenced * device only Reference(ehealth-device or ehealth-devicemetric) * device ^type.aggregation = #referenced From 5ed1b9ca7bdfc571cb6d7893fc5122bcf9bb95fd Mon Sep 17 00:00:00 2001 From: Mahler Date: Tue, 27 Jan 2026 14:34:39 +0100 Subject: [PATCH 08/27] [(CCR0224-changes-for-media)] updated changelog --- input/pagecontent/changelog.md | 12 ++++++++++++ 1 file changed, 12 insertions(+) diff --git a/input/pagecontent/changelog.md b/input/pagecontent/changelog.md index eb3af7e1a..3488fba00 100644 --- a/input/pagecontent/changelog.md +++ b/input/pagecontent/changelog.md @@ -1,5 +1,17 @@ This is the log of changes made to the eHealth Implementation Guide. +## Release 2026.2. todo: change to semver format before release +### General changes +- Updated ehealth-media to allow patient and relatedPerson references in it's operator field. +### Custom operations +#### System operations +#### Instance operations +### Code systems +### ValueSets +### ConceptMaps +### Resource/profile changes +- Updated ehealth-media to allow patient and relatedPerson references in it's operator field. + ## Release 2026.2. todo: change to semver format before release ### General changes ### Custom operations From 9970ddc3c324539f52add6332d77a2daa9b441fe Mon Sep 17 00:00:00 2001 From: Mahler Date: Tue, 27 Jan 2026 14:41:16 +0100 Subject: [PATCH 09/27] [(CCR0224-changes-for-media)] updated changelog --- input/pagecontent/changelog.md | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/input/pagecontent/changelog.md b/input/pagecontent/changelog.md index 3488fba00..1f11011e0 100644 --- a/input/pagecontent/changelog.md +++ b/input/pagecontent/changelog.md @@ -1,6 +1,6 @@ This is the log of changes made to the eHealth Implementation Guide. -## Release 2026.2. todo: change to semver format before release +## Release 2026.3. ### General changes - Updated ehealth-media to allow patient and relatedPerson references in it's operator field. ### Custom operations From 04662c762300350cb2f5aa2d2f435f6a52641f25 Mon Sep 17 00:00:00 2001 From: oliverduenielsen Date: Wed, 11 Mar 2026 10:42:13 +0100 Subject: [PATCH 10/27] Consolidate contact-point into sender, rename message type codes, make identifier required - Removed ehealth-carecommunication-bundle and ehealth-carecommunication-contact-point extensions - Consolidated contactPoint (0..1) into sender extension; renamed careteam -> careTeam - Made payload identifier required (1..1) for both string and attachment payloads - Renamed message type codes to full hyphenated names (new-message, reply-message, forward-message) - Updated sender-required invariant expression to match new code names Co-Authored-By: Claude Sonnet 4.6 --- input/fsh/ehealth-carecommunication.fsh | 53 ++++++++++--------------- 1 file changed, 20 insertions(+), 33 deletions(-) diff --git a/input/fsh/ehealth-carecommunication.fsh b/input/fsh/ehealth-carecommunication.fsh index 3e82eef7e..7a7822a92 100644 --- a/input/fsh/ehealth-carecommunication.fsh +++ b/input/fsh/ehealth-carecommunication.fsh @@ -40,7 +40,7 @@ Parent: Communication * encounter ^short = "Shall contain a reference to an Encounter resource with a episodeOfCare-identifier, if the identifier is included in a previous message." * topic 0..1 MS -* topic ^short = "Must be added when category is "other". Topic must be added in the text-element." +* topic ^short = "Must be added when category is \"other\". Topic must be added in the text-element." * topic.text 1..1 MS * topic.text ^short = "Plain text representation of the concept." * topic.text ^definition = "The topic must be present." @@ -73,8 +73,6 @@ Parent: Communication * extension contains ehealth-administrative-status named administrativeStatus 1..1 -* extension contains ehealth-carecommunication-bundle named CorrespondingMedComCareCommunicationBundle 0..1 MS - * payload 1..* * payload ^slicing.discriminator.type = #type * payload ^slicing.discriminator.path = "content[x]" @@ -84,14 +82,12 @@ Parent: Communication * payload[string].contentString 1..1 MS * payload[string].extension contains ehealth-carecommunication-datetime named date 1..1 MS and - ehealth-carecommunication-contact-point named authorContact 1..1 MS and - ehealth-carecommunication-payload-identifier named identifier 0..1 MS + ehealth-carecommunication-payload-identifier named identifier 1..1 MS * payload[attachment].contentAttachment 1..1 MS * payload[attachment].extension contains ehealth-carecommunication-datetime named date 1..1 MS and - ehealth-carecommunication-contact-point named authorContact 0..1 MS and - ehealth-carecommunication-payload-identifier named identifier 0..1 MS + ehealth-carecommunication-payload-identifier named identifier 1..1 MS // Extensions @@ -103,13 +99,16 @@ Description: "References the sending PractitionerRole (Actor), the Practitioner, * extension contains actor 1..1 MS and practitioner 1..1 MS and - careteam 0..1 MS + contactPoint 0..1 MS and + careTeam 0..1 MS * extension[actor] ^short = "Sending PractitionerRole" * extension[actor].value[x] only Reference(PractitionerRole) * extension[practitioner] ^short = "The underlying Practitioner for this sender" * extension[practitioner].value[x] only Reference(Practitioner) -* extension[careteam] ^short = "Optionally, the involved CareTeam" -* extension[careteam].value[x] only Reference(CareTeam) +* extension[careTeam] ^short = "Optionally, the involved CareTeam" +* extension[careTeam].value[x] only Reference(CareTeam) +* extension[contactPoint] ^short = "Optional contactpoint for the sender" +* extension[contactPoint].value[x] only ContactPoint Extension: ehealth-carecommunication-destination Title: "Destination Extension" @@ -117,28 +116,16 @@ Description: "Reference to the destination Organization for this communication." * . ^short = "Organization receiving the message" * value[x] only Reference(Organization) -Extension: ehealth-carecommunication-bundle -Title: "Destination Extension" -Description: "Reference to the careCommunication Bundle received." -* . ^short = "carecommunication bundle" -* value[x] only Reference(Bundle) - Extension: ehealth-carecommunication-datetime Title: "DateTime Extension" Description: "Date and time of the payload segment." * . ^short = "Payload dateTime" * value[x] only dateTime -Extension: ehealth-carecommunication-contact-point -Title: "Contact Extension" -Description: "Contact point for the author of this payload segment." -* . ^short = "Payload author contact" -* value[x] only ContactPoint - Extension: ehealth-carecommunication-payload-identifier Title: "Identifier Extension" Description: "Extension to hold an Identifier for a payload. Value shall be a UUID identifier version 4." -* value[x] only Identifier +* value[x] Extension: ehealth-carecommunication-origin Title: "sender organization" @@ -157,15 +144,15 @@ Description: "The type of the message. If inResponseTo is present, the type can ValueSet: MessageType Title: "Message Type ValueSet" -Description: "Allowed message types: new, reply, forward." +Description: "Allowed message types: new-message, reply-message, forward-message." * ^url = "http://ehealth.sundhed.dk/cm/ehealth-to-medcom-carecommunication-category" * ^compose.include.system = "http://ehealth.sundhed.dk/cs/message-type" -* ^compose.include.concept[+].code = #new +* ^compose.include.concept[+].code = #new-message * ^compose.include.concept[=].display = "New Message" -* ^compose.include.concept[+].code = #reply -* ^compose.include.concept[=].display = "Reply" -* ^compose.include.concept[+].code = #forward -* ^compose.include.concept[=].display = "Forward" +* ^compose.include.concept[+].code = #reply-message +* ^compose.include.concept[=].display = "Reply Message" +* ^compose.include.concept[+].code = #forward-message +* ^compose.include.concept[=].display = "Forward Message" ValueSet: EhealthCareCommunicationCategoryVS Id: ehealth-carecommunication-category @@ -190,9 +177,9 @@ CodeSystem: MessageTypeCS Title: "Message Type CodeSystem" Description: "Allowed codes for message type." * ^url = "http://ehealth.sundhed.dk/cs/message-type" -* #new "New Message" -* #reply "Reply" -* #forward "Forward" +* #new-message "New Message" +* #reply-message "Reply" +* #forward-message "Forward" CodeSystem: EhealthCareCommunicationCategoryCS Id: ehealth-carecommunication-category @@ -276,5 +263,5 @@ Description: """ If messagetype is 'new' or 'reply', the sender extension must be present. If 'forward', sender may be absent. """ -Expression: "extension('http://ehealth.sundhed.dk/fhir/StructureDefinition/ehealth-carecommunication-message-Type').value.coding.where(code = 'new' or code = 'reply').exists() implies extension('http://ehealth.sundhed.dk/fhir/StructureDefinition/ehealth-carecommunication-sender').exists()" +Expression: "extension('http://ehealth.sundhed.dk/fhir/StructureDefinition/ehealth-carecommunication-message-Type').value.coding.where(code = 'new-message' or code = 'reply-message').exists() implies extension('http://ehealth.sundhed.dk/fhir/StructureDefinition/ehealth-carecommunication-sender').exists()" Severity: #error \ No newline at end of file From 0e650f3acc01744aee6bf302b5314fe3daf5cd2c Mon Sep 17 00:00:00 2001 From: oliverduenielsen Date: Mon, 20 Apr 2026 12:36:41 +0200 Subject: [PATCH 11/27] Add messageHeaderId as identifier --- input/fsh/ehealth-carecommunication.fsh | 20 +++++++++++++++----- 1 file changed, 15 insertions(+), 5 deletions(-) diff --git a/input/fsh/ehealth-carecommunication.fsh b/input/fsh/ehealth-carecommunication.fsh index 7a7822a92..ba2384adc 100644 --- a/input/fsh/ehealth-carecommunication.fsh +++ b/input/fsh/ehealth-carecommunication.fsh @@ -18,11 +18,21 @@ Parent: Communication and no-standard-sender and sender-required-based-on-messagetype -* identifier 1..1 MS -* identifier.use 0..1 -* identifier.use from http://hl7.org/fhir/ValueSet/identifier-use (required) -* identifier.value 1..1 MS -* identifier ^short = "The communication identifier" +* identifier 1..2 MS +* identifier ^slicing.discriminator.type = #value +* identifier ^slicing.discriminator.path = "system" +* identifier ^slicing.rules = #open +* identifier contains communicationId 1..1 MS and messageHeaderId 0..1 MS + +* identifier[communicationId].use 0..1 +* identifier[communicationId].use from http://hl7.org/fhir/ValueSet/identifier-use (required) +* identifier[communicationId].value 1..1 MS +* identifier[communicationId] ^short = "The communication identifier" + +* identifier[messageHeaderId].system 1..1 MS +* identifier[messageHeaderId].system = "http://ehealth.sundhed.dk/id/ehealth-carecommunication-messageHeaderId" +* identifier[messageHeaderId].value 1..1 MS +* identifier[messageHeaderId] ^short = "The ID of the originating MessageHeader resource" * status 1..1 MS From e2013d99ba83676b7589e0853e1ce106031f199e Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Jon=20Juhl=20N=C3=B8rrelykke?= Date: Mon, 20 Apr 2026 13:50:32 +0200 Subject: [PATCH 12/27] docs(event-messages): document tightened EHealthApplicationEvent schema constraints (CCR0303 AC-7) Mirrors the schema tightening from ehealth-commons (trifork/ehealth#3143) so the IG and the Java-runtime schema agree on the contract: - resourceReference requires minItems: 1. - allOf / if-then / contains rules assert the obligatory resourceReference.label per eventType (AppointmentReminder, VideoAppointmentReminder, ReminderSubmitMeasurement, MissingMeasurement, NewEHealthMessage). Changelog updated under Release 2026.2 > Event messages. --- input/pagecontent/changelog.md | 2 ++ input/pagecontent/event-messages.md | 24 ++++++++++++++++++++---- 2 files changed, 22 insertions(+), 4 deletions(-) diff --git a/input/pagecontent/changelog.md b/input/pagecontent/changelog.md index a6a040b56..a25ca8e2d 100644 --- a/input/pagecontent/changelog.md +++ b/input/pagecontent/changelog.md @@ -55,6 +55,8 @@ This is the log of changes made to the eHealth Implementation Guide. - Added `ehealth-message-author` extension to `ehealth-message` (`Communication`). When an attorney (`RELATED_PERSON`) sends a message on behalf of a patient, `Communication.sender` must reference the grantor patient. The vendor application must populate the `ehealth-message-author` extension with a reference to the acting `RelatedPerson`. Patient Service validates this on every write by a `RELATED_PERSON` user. ### Search parameters - Added search parameter `topic` on `ehealth-communication` to be able to query by topic +### Event messages +- Tightened the `EHealthApplicationEvent` JSON schema: `resourceReference` now requires `minItems: 1`, and per-eventType `if`/`then`/`contains` rules assert the obligatory `resourceReference.label` per CCR0303 AC-7. ## 8.0.1 (2026-03-02) ### Custom operations diff --git a/input/pagecontent/event-messages.md b/input/pagecontent/event-messages.md index dcd056fad..fc279aa22 100644 --- a/input/pagecontent/event-messages.md +++ b/input/pagecontent/event-messages.md @@ -162,9 +162,11 @@ topic: `ehealth-application-event` }, "resourceReference" : { "type" : "array", - "description" : "References to related resources", + "minItems" : 1, + "description" : "References to related resources (at least one obligatory entry per eventType — see Event Types table)", "items" : { "type" : "object", + "required" : [ "label", "reference" ], "properties" : { "label" : { "type" : "string", @@ -177,7 +179,19 @@ topic: `ehealth-application-event` } } } - } + }, + "allOf" : [ + { "if" : { "properties" : { "eventType" : { "const" : "AppointmentReminder" } } }, + "then" : { "properties" : { "resourceReference" : { "contains" : { "properties" : { "label" : { "const" : "Appointment" } } } } } } }, + { "if" : { "properties" : { "eventType" : { "const" : "VideoAppointmentReminder" } } }, + "then" : { "properties" : { "resourceReference" : { "contains" : { "properties" : { "label" : { "const" : "Appointment" } } } } } } }, + { "if" : { "properties" : { "eventType" : { "const" : "ReminderSubmitMeasurement" } } }, + "then" : { "properties" : { "resourceReference" : { "contains" : { "properties" : { "label" : { "const" : "ServiceRequest" } } } } } } }, + { "if" : { "properties" : { "eventType" : { "const" : "MissingMeasurement" } } }, + "then" : { "properties" : { "resourceReference" : { "contains" : { "properties" : { "label" : { "const" : "ServiceRequest" } } } } } } }, + { "if" : { "properties" : { "eventType" : { "const" : "NewEHealthMessage" } } }, + "then" : { "properties" : { "resourceReference" : { "contains" : { "properties" : { "label" : { "const" : "EhealthMessage" } } } } } } } + ] } ``` ##### Properties @@ -187,11 +201,13 @@ topic: `ehealth-application-event` - `messageVersion`: The version of the message type, eg. "1.0" - `payload`: Notification text content from the CommunicationRequest - `userReference`: The reference (absolute URL) of the Patient resource representing the citizen -- `resourceReference`: Array of references to related resources, each with a `label` (resource type) and `reference` (absolute URL) +- `resourceReference`: Non-empty array of references to related resources. Each entry has a `label` (resource type) and `reference` (absolute URL). The obligatory entries per `eventType` are listed in the Event Types table. ##### Event Types -| eventType | Description | resourceReference label | Source | +Each `eventType` guarantees at least one `resourceReference` entry with the indicated `label`. This is enforced by the JSON schema's `allOf` / `if`-`then` / `contains` block above. + +| eventType | Description | Obligatory resourceReference label | Source | |---|---|---|---| | AppointmentReminder | Appointment reminder | Appointment | fut-appointment-notification-job | | VideoAppointmentReminder | Video appointment reminder | Appointment | fut-appointment-notification-job | From 1182b551a80e7dda898b7294bf3521475b12c490 Mon Sep 17 00:00:00 2001 From: oliverduenielsen Date: Mon, 27 Apr 2026 14:40:42 +0200 Subject: [PATCH 13/27] Add system to carecommunication identifier --- input/fsh/ehealth-carecommunication.fsh | 2 ++ 1 file changed, 2 insertions(+) diff --git a/input/fsh/ehealth-carecommunication.fsh b/input/fsh/ehealth-carecommunication.fsh index ba2384adc..859e32192 100644 --- a/input/fsh/ehealth-carecommunication.fsh +++ b/input/fsh/ehealth-carecommunication.fsh @@ -24,6 +24,8 @@ Parent: Communication * identifier ^slicing.rules = #open * identifier contains communicationId 1..1 MS and messageHeaderId 0..1 MS +* identifier[communicationId].system 1..1 MS +* identifier[communicationId].system = "http://ehealth.sundhed.dk/id/ehealth-carecommunication-identifier" * identifier[communicationId].use 0..1 * identifier[communicationId].use from http://hl7.org/fhir/ValueSet/identifier-use (required) * identifier[communicationId].value 1..1 MS From 476df182475faadacab8d428197972927d93c4b7 Mon Sep 17 00:00:00 2001 From: Bastian Date: Tue, 28 Apr 2026 09:20:43 +0200 Subject: [PATCH 14/27] set version to SNAPSHOT on snapshot branch --- sushi-config.yaml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/sushi-config.yaml b/sushi-config.yaml index cb7992848..9dd21d1b7 100644 --- a/sushi-config.yaml +++ b/sushi-config.yaml @@ -7,7 +7,7 @@ canonical: http://ehealth.sundhed.dk/fhir name: eHealth Infrastructure title: eHealth Infrastructure status: active # draft | active | retired | unknown -version: 9.0.1 +version: 9.0.2-SNAPSHOT fhirVersion: 4.0.1 copyrightYear: 2021+ From 4b9a184c0c0e4216d2c515728b72e71ddfdd9f9f Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Jon=20Juhl=20N=C3=B8rrelykke?= Date: Wed, 29 Apr 2026 09:22:05 +0200 Subject: [PATCH 15/27] docs(event-messages): refine EHealthApplicationEvent schema constraints (CCR0303 AC-7) - declare JSON Schema Draft-07 (clarifies that if/then/contains semantics apply) - mark eventType and resourceReference as top-level required - add required: [eventType] inside each if-clause to avoid the missing-discriminator gotcha - reword inline description; expand changelog with vendor-facing note about the item-level required: [label, reference] --- input/pagecontent/changelog.md | 6 ++++-- input/pagecontent/event-messages.md | 14 ++++++++------ 2 files changed, 12 insertions(+), 8 deletions(-) diff --git a/input/pagecontent/changelog.md b/input/pagecontent/changelog.md index a25ca8e2d..c69de54bf 100644 --- a/input/pagecontent/changelog.md +++ b/input/pagecontent/changelog.md @@ -1,5 +1,9 @@ This is the log of changes made to the eHealth Implementation Guide. +## Release 2026.3. todo: change to semver format before release +### Event messages +- Tightened the `EHealthApplicationEvent` JSON schema (CCR0303 AC-7): the schema is now declared as JSON Schema draft-07; `eventType` and `resourceReference` are top-level required; `resourceReference` requires `minItems: 1` with each entry requiring both `label` and `reference`; and per-`eventType` `if`/`then`/`contains` rules assert the obligatory `resourceReference.label`. **Note for vendors:** producers must now emit both `label` and `reference` on every `resourceReference` entry and include the `eventType`-specific obligatory label. + ## 9.0.0 (2026-05-05) ### General changes - dk.core updated from 1.1.0 to 3.5.0 @@ -55,8 +59,6 @@ This is the log of changes made to the eHealth Implementation Guide. - Added `ehealth-message-author` extension to `ehealth-message` (`Communication`). When an attorney (`RELATED_PERSON`) sends a message on behalf of a patient, `Communication.sender` must reference the grantor patient. The vendor application must populate the `ehealth-message-author` extension with a reference to the acting `RelatedPerson`. Patient Service validates this on every write by a `RELATED_PERSON` user. ### Search parameters - Added search parameter `topic` on `ehealth-communication` to be able to query by topic -### Event messages -- Tightened the `EHealthApplicationEvent` JSON schema: `resourceReference` now requires `minItems: 1`, and per-eventType `if`/`then`/`contains` rules assert the obligatory `resourceReference.label` per CCR0303 AC-7. ## 8.0.1 (2026-03-02) ### Custom operations diff --git a/input/pagecontent/event-messages.md b/input/pagecontent/event-messages.md index fc279aa22..2b7d26e2a 100644 --- a/input/pagecontent/event-messages.md +++ b/input/pagecontent/event-messages.md @@ -133,8 +133,10 @@ topic: `ehealth-application-event` ``` { + "$schema" : "http://json-schema.org/draft-07/schema#", "type" : "object", "id" : "urn:jsonschema:dk:sundhed:ehealth:event:models:EHealthApplicationEvent", + "required" : [ "eventType", "resourceReference" ], "properties" : { "messageType" : { "type" : "string", @@ -163,7 +165,7 @@ topic: `ehealth-application-event` "resourceReference" : { "type" : "array", "minItems" : 1, - "description" : "References to related resources (at least one obligatory entry per eventType — see Event Types table)", + "description" : "References to related resources. At least one entry is required; the obligatory label per eventType is listed in the Event Types table below.", "items" : { "type" : "object", "required" : [ "label", "reference" ], @@ -181,15 +183,15 @@ topic: `ehealth-application-event` } }, "allOf" : [ - { "if" : { "properties" : { "eventType" : { "const" : "AppointmentReminder" } } }, + { "if" : { "required" : [ "eventType" ], "properties" : { "eventType" : { "const" : "AppointmentReminder" } } }, "then" : { "properties" : { "resourceReference" : { "contains" : { "properties" : { "label" : { "const" : "Appointment" } } } } } } }, - { "if" : { "properties" : { "eventType" : { "const" : "VideoAppointmentReminder" } } }, + { "if" : { "required" : [ "eventType" ], "properties" : { "eventType" : { "const" : "VideoAppointmentReminder" } } }, "then" : { "properties" : { "resourceReference" : { "contains" : { "properties" : { "label" : { "const" : "Appointment" } } } } } } }, - { "if" : { "properties" : { "eventType" : { "const" : "ReminderSubmitMeasurement" } } }, + { "if" : { "required" : [ "eventType" ], "properties" : { "eventType" : { "const" : "ReminderSubmitMeasurement" } } }, "then" : { "properties" : { "resourceReference" : { "contains" : { "properties" : { "label" : { "const" : "ServiceRequest" } } } } } } }, - { "if" : { "properties" : { "eventType" : { "const" : "MissingMeasurement" } } }, + { "if" : { "required" : [ "eventType" ], "properties" : { "eventType" : { "const" : "MissingMeasurement" } } }, "then" : { "properties" : { "resourceReference" : { "contains" : { "properties" : { "label" : { "const" : "ServiceRequest" } } } } } } }, - { "if" : { "properties" : { "eventType" : { "const" : "NewEHealthMessage" } } }, + { "if" : { "required" : [ "eventType" ], "properties" : { "eventType" : { "const" : "NewEHealthMessage" } } }, "then" : { "properties" : { "resourceReference" : { "contains" : { "properties" : { "label" : { "const" : "EhealthMessage" } } } } } } } ] } From 4895cc86e97feddcfad49aff88616cf49ec0ba26 Mon Sep 17 00:00:00 2001 From: Bastian Date: Wed, 29 Apr 2026 09:46:18 +0200 Subject: [PATCH 16/27] re-add poa privilege --- README.md | 3 +++ .../CodeSystem-ehealth-poa-privilege.json | 25 +++++++++++++++++++ ...health-relatedperson-relationshiptype.json | 6 ++++- sushi.sh | 4 +++ 4 files changed, 37 insertions(+), 1 deletion(-) create mode 100644 input/resources/CodeSystem-ehealth-poa-privilege.json create mode 100644 sushi.sh diff --git a/README.md b/README.md index 72039a645..c392c4cc1 100644 --- a/README.md +++ b/README.md @@ -31,6 +31,9 @@ The CI/CD pipeline uses the HL7 CI/CD infrastructure and Github webhooks which i ## Local development +### Running SUSHI +Use `./sushi.sh` instead of `npx sushi` to suppress known-safe naming warnings (ehealth-* names that don't follow PascalCase) while keeping all other output intact. + ### Running locally Do `rm -rf output && rm -rf temp/ && ./_genonce.sh` diff --git a/input/resources/CodeSystem-ehealth-poa-privilege.json b/input/resources/CodeSystem-ehealth-poa-privilege.json new file mode 100644 index 000000000..2937ee4ac --- /dev/null +++ b/input/resources/CodeSystem-ehealth-poa-privilege.json @@ -0,0 +1,25 @@ +{ + "resourceType": "CodeSystem", + "id": "ehealth-poa-privilege", + "url": "http://ehealth.sundhed.dk/cs/poa-privilege", + "version": "0.0.1", + "name": "PoAPrivilege", + "title": "Power of Attorney Privilege", + "status": "active", + "experimental": false, + "date": "2026-03-24T00:00:00+00:00", + "publisher": "ehealth.sundhed.dk", + "contact": [ + { + "telecom": [ + { + "system": "url", + "value": "http://ehealth.sundhed.dk/terminology" + } + ] + } + ], + "description": "Vendor-specific power of attorney privilege codes used by Keycloak when creating RelatedPerson resources for PoA-authenticated citizens. The full set of codes is externally governed and not enumerated here.", + "caseSensitive": true, + "content": "not-present" +} diff --git a/input/resources/ValueSet-ehealth-relatedperson-relationshiptype.json b/input/resources/ValueSet-ehealth-relatedperson-relationshiptype.json index b1224550d..93cb9a2a2 100644 --- a/input/resources/ValueSet-ehealth-relatedperson-relationshiptype.json +++ b/input/resources/ValueSet-ehealth-relatedperson-relationshiptype.json @@ -24,7 +24,8 @@ { "system": "http://terminology.hl7.org/CodeSystem/v3-RoleCode", "code": "O", "display": "Operator Proficiency" }, { "system": "http://terminology.hl7.org/CodeSystem/v3-RoleCode", "code": "CHILD", "display": "child" }, { "system": "http://terminology.hl7.org/CodeSystem/v3-RoleCode", "code": "SPS", "display": "spouse" }, - { "system": "http://terminology.hl7.org/CodeSystem/v3-RoleCode", "code": "POWATT", "display": "power of attorney" } + { "system": "http://terminology.hl7.org/CodeSystem/v3-RoleCode", "code": "POWATT", "display": "power of attorney" }, + { "system": "http://ehealth.sundhed.dk/cs/poa-privilege", "abstract": true, "display": "Vendor-specific PoA privilege codes (externally governed, not enumerated)" } ] }, "compose": { @@ -72,6 +73,9 @@ "code": "POWATT" } ] + }, + { + "system": "http://ehealth.sundhed.dk/cs/poa-privilege" } ] } diff --git a/sushi.sh b/sushi.sh new file mode 100644 index 000000000..85a3f1608 --- /dev/null +++ b/sushi.sh @@ -0,0 +1,4 @@ +#!/bin/bash +# Runs SUSHI and filters out known-safe naming warnings for ehealth-* slice names. +# Use 'npx sushi' directly if you want unfiltered output. +FORCE_COLOR=1 npx sushi "$@" 2>&1 | sed '/Valid names start with an upper-case ASCII letter/{N;N;d}' \ No newline at end of file From d734025e65716c6c329fc17145efcca761d68353 Mon Sep 17 00:00:00 2001 From: Bastian Date: Wed, 29 Apr 2026 09:51:20 +0200 Subject: [PATCH 17/27] updated changelog.md --- input/pagecontent/changelog.md | 2 ++ 1 file changed, 2 insertions(+) diff --git a/input/pagecontent/changelog.md b/input/pagecontent/changelog.md index 0edb157fc..69bdc0766 100644 --- a/input/pagecontent/changelog.md +++ b/input/pagecontent/changelog.md @@ -7,7 +7,9 @@ This is the log of changes made to the eHealth Implementation Guide. #### System operations #### Instance operations ### Code systems +- Re-added `http://ehealth.sundhed.dk/cs/poa-privilege` (Power of Attorney Privilege) CodeSystem. Content is `not-present` — codes are vendor-specific and externally governed. ### ValueSets +- Re-added `http://ehealth.sundhed.dk/cs/poa-privilege` as an include in `http://ehealth.sundhed.dk/vs/relatedperson-relationshiptype`. ### ConceptMaps ### Resource/profile changes - Updated ehealth-media to allow patient and relatedPerson references in it's operator field. From 847cbed374ee5300a8539e231dced04b87181d23 Mon Sep 17 00:00:00 2001 From: Bastian Staunstrup Date: Thu, 30 Apr 2026 10:51:25 +0200 Subject: [PATCH 18/27] make relationship.coding extensible --- input/fsh/ehealth-relatedperson.fsh | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/input/fsh/ehealth-relatedperson.fsh b/input/fsh/ehealth-relatedperson.fsh index 5be02dc9a..3a0caa317 100644 --- a/input/fsh/ehealth-relatedperson.fsh +++ b/input/fsh/ehealth-relatedperson.fsh @@ -12,7 +12,7 @@ Parent: RelatedPerson * patient only Reference(ehealth-patient) * patient ^type.aggregation = #referenced -* relationship.coding from http://ehealth.sundhed.dk/vs/relatedperson-relationshiptype +* relationship.coding from http://ehealth.sundhed.dk/vs/relatedperson-relationshiptype (extensible) * name 1..* Instance: relatedperson01 From 2b402019cafc780e57312040600c30b7c2cc726e Mon Sep 17 00:00:00 2001 From: oliverduenielsen Date: Mon, 4 May 2026 09:42:32 +0200 Subject: [PATCH 19/27] add intro to ehealth-carecommunication --- input/fsh/ehealth-carecommunication.fsh | 43 +++++++++++++- ...inition-ehealth-carecommunication-intro.md | 58 +++++++++++++++++++ 2 files changed, 99 insertions(+), 2 deletions(-) create mode 100644 input/intro-notes/StructureDefinition-ehealth-carecommunication-intro.md diff --git a/input/fsh/ehealth-carecommunication.fsh b/input/fsh/ehealth-carecommunication.fsh index 859e32192..6a2c0fd31 100644 --- a/input/fsh/ehealth-carecommunication.fsh +++ b/input/fsh/ehealth-carecommunication.fsh @@ -17,6 +17,7 @@ Parent: Communication and payloadAttachment-contentType-required and no-standard-sender and sender-required-based-on-messagetype + and reply-requires-inResponseTo * identifier 1..2 MS * identifier ^slicing.discriminator.type = #value @@ -76,6 +77,7 @@ Parent: Communication * recipient ^short = "The recieving actor of the message" * inResponseTo 0..1 MS +* inResponseTo ^short = "references the Ehealth-CareCommunication Communication.id, which this message is a response to." * sender 0..0 @@ -96,11 +98,22 @@ Parent: Communication ehealth-carecommunication-datetime named date 1..1 MS and ehealth-carecommunication-payload-identifier named identifier 1..1 MS +* payload[attachment].content[x] only Attachment * payload[attachment].contentAttachment 1..1 MS * payload[attachment].extension contains ehealth-carecommunication-datetime named date 1..1 MS and ehealth-carecommunication-payload-identifier named identifier 1..1 MS - +* payload[attachment].contentAttachment.contentType MS +* payload[attachment].contentAttachment.contentType ^short = "The content type shall be present when the content is an attachment included in the data element." +* payload[attachment].contentAttachment.contentType from http://ehealth.sundhed.dk/vs/ehealth-carecommunication-mimetypes (required) +* payload[attachment].contentAttachment.data MS +* payload[attachment].contentAttachment.data ^short = "Shall be present and contain the base64 encoded content of the attachment." +* payload[attachment].contentAttachment.url MS +* payload[attachment].contentAttachment.url ^short = "Shall be present if the attachment is a link to a web page." +* payload[attachment].contentAttachment.title 1.. MS +* payload[attachment].contentAttachment.title ^short = "Note: it is not allowed for the system to automatically include '.filetype' in the title." +* payload[attachment].contentAttachment.creation MS +* payload[attachment].contentAttachment.creation ^short = "The time the attachment was created" // Extensions @@ -137,7 +150,8 @@ Description: "Date and time of the payload segment." Extension: ehealth-carecommunication-payload-identifier Title: "Identifier Extension" Description: "Extension to hold an Identifier for a payload. Value shall be a UUID identifier version 4." -* value[x] +* value[x] only string +* valueString 1..1 Extension: ehealth-carecommunication-origin Title: "sender organization" @@ -174,6 +188,26 @@ Title: "eHealth CareCommunication Categories" * ^description = "Categories used for CareCommunciation messages." * ^compose.include.system = "http://ehealth.sundhed.dk/cs/ehealth-carecommunication-category" +ValueSet: EhealthCareCommunicationMimeTypesVS +Id: ehealth-carecommunication-mimetypes +Title: "eHealth CareCommunication Attachment MIME Types" +Description: "Allowed MIME types for attachments in eHealth CareCommunication messages. Mirrors MedCom's medcom-core-attachmentMimeTypes ValueSet." +* ^url = "http://ehealth.sundhed.dk/vs/ehealth-carecommunication-mimetypes" +* ^status = #active +* ^compose.include.system = "urn:ietf:bcp:13" +* ^compose.include.concept[+].code = #application/pdf +* ^compose.include.concept[=].display = "application/pdf" +* ^compose.include.concept[+].code = #image/gif +* ^compose.include.concept[=].display = "image/gif" +* ^compose.include.concept[+].code = #image/jpeg +* ^compose.include.concept[=].display = "image/jpeg" +* ^compose.include.concept[+].code = #image/png +* ^compose.include.concept[=].display = "image/png" +* ^compose.include.concept[+].code = #image/tiff +* ^compose.include.concept[=].display = "image/tiff" +* ^compose.include.concept[+].code = #image/bmp +* ^compose.include.concept[=].display = "image/bmp" + ValueSet: EhealthCareCommunicationPriorityVS Id: ehealth-carecommunication-priority Title: "eHealth CareCommunication Priorities" @@ -270,6 +304,11 @@ Description: "The standard Communication.sender element SHALL NOT be used. Use t Expression: "sender.empty()" Severity: #error +Invariant: reply-requires-inResponseTo +Description: "If messageType is 'reply-message', inResponseTo SHALL be populated." +Expression: "extension('http://ehealth.sundhed.dk/fhir/StructureDefinition/ehealth-carecommunication-message-Type').value.coding.where(code = 'reply-message').exists() implies inResponseTo.exists()" +Severity: #error + Invariant: sender-required-based-on-messagetype Description: """ If messagetype is 'new' or 'reply', the sender extension must be present. diff --git a/input/intro-notes/StructureDefinition-ehealth-carecommunication-intro.md b/input/intro-notes/StructureDefinition-ehealth-carecommunication-intro.md new file mode 100644 index 000000000..7db8e2c44 --- /dev/null +++ b/input/intro-notes/StructureDefinition-ehealth-carecommunication-intro.md @@ -0,0 +1,58 @@ +# Introduction + +An Ehealth-CareCommunication is an FUT abstraction of a MedCom CareCommunication. +This is needed to support communication through the VANS network with parties outside the FUT infrastructure, as well as inside FUT. +The Ehealth-CareCommunication's primary feature is to enable communication in relation to several images of different file types. + +# Remarks about status and administrative-status + +- __status__: + - A message is considered "not yet sent" when it has one of the following status and can freely transition from one to another: 'preparation', 'on-hold', 'not-done', 'entered-in-error' + - A message is considered "being sent" when created or patched into status 'in-progress' and cannot be patched further or deleted by the sender + - The server will automatically transition a message from 'in-progress' to 'completed' when it has been sent successfully (happens when the Vans-Relay has received a positive acknowledgement on the send message) + - The server will automatically transition a message from 'in-progress' to 'stopped' if it could not be sent (happens when the Vans-Relay has received a negative acknowledgement on the send message, or at 3 failed attempts at sending) + - The client can never create or patch a message into status 'completed' or 'stopped' + - The sender cannot patch, only delete messages with status 'stopped' + - The sender cannot patch or delete messages with status 'completed' + - The recipient can patch /received and administrative-status on messages with status 'completed' + +- __administrative-status__ (extension): Makes it possible for the message __recipient__ to indicate the state of a message. A message may hold an administrative status that defines the last action the recipient took on the message in question. At first, the message has administrative-status "activate". The recipient may mark the message as read by setting administrative-status "read". If the recipient considers the message a sort of "task", the message may also be updated with + administrative-status "complete" when the task is done, or "reactivate" if the task was not complete anyway. + +# Scope and Usage + +In the eHealth Infrastructure the ehealth-CareCommunication resource is used in conjunction with the +following resources: + +- Patient + - As a subject of a message + +- PractitionerRole + - As specific sender/recipient of a message + +- Practitioner + - the Practitioner of the PractitionerRole + +- CareTeam + - as specific sender/recipient of a message + +- Organization + - as sender/recipient of a message + +__note on sender__: The sender of a message is structured as a complex extension, +holding a reference to the sending PractitionerRole, the linked Practitioner and optional +CareTeam. If a CareTeam is present, that CareTeam is considered the specific sender, +not the PractitionerRole. PractitionerRole is still required, since every message has to +have a PractitionerRole representing that message. + +# General rules + +- The sender/receiver Organizations have to have both a SOR and GLN (EAN) identifier to be eligible for VANS communication. +- If the message type is Forward, you as a sender have to pick which payloads should be included in the message. +- If the message type is Reply, the message will be populated automatically with all prior payloads of the given conversation. +- The Communication identifier is the same for all Ehealth-CareCommunications of the same conversation. A new Communication Id is needed for a Forward message type, even though bundles from a prior conversation are included. +- The MessageHeader identifier is set for received messages, as client-side assignment of id's is not possible. For messages sent from the FUT infrastructure, it is not needed. +The reasoning for the use of this identifier is that the correlating MedCom model for Ehealth-CareCommunications identifies specific messages based on the MessageHeader identifier. +- inResponseTo has to be included for Reply messages. It points to the previous MessageHeader identifier in the conversation if present, otherwise Ehealth-CareCommunication.id. +- If category is other, the topic.text element has to be populated. +- recipient can be excluded, which means the message is considered sent to the destination organization. \ No newline at end of file From 2625f3eff78291b584037d2c7869a17f22cfb41d Mon Sep 17 00:00:00 2001 From: oliverduenielsen Date: Mon, 4 May 2026 10:30:46 +0200 Subject: [PATCH 20/27] version 9.0.2-snapshot --- sushi-config.yaml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/sushi-config.yaml b/sushi-config.yaml index cb7992848..9dd21d1b7 100644 --- a/sushi-config.yaml +++ b/sushi-config.yaml @@ -7,7 +7,7 @@ canonical: http://ehealth.sundhed.dk/fhir name: eHealth Infrastructure title: eHealth Infrastructure status: active # draft | active | retired | unknown -version: 9.0.1 +version: 9.0.2-SNAPSHOT fhirVersion: 4.0.1 copyrightYear: 2021+ From f2b8224e43a75d745654625be8a355d00e1fb63f Mon Sep 17 00:00:00 2001 From: oliverduenielsen Date: Mon, 4 May 2026 11:07:06 +0200 Subject: [PATCH 21/27] added change to changelog --- input/pagecontent/changelog.md | 16 ++++++++++++++++ 1 file changed, 16 insertions(+) diff --git a/input/pagecontent/changelog.md b/input/pagecontent/changelog.md index 10e1ff516..de8b49f79 100644 --- a/input/pagecontent/changelog.md +++ b/input/pagecontent/changelog.md @@ -15,6 +15,22 @@ This is the log of changes made to the eHealth Implementation Guide. ### Event messages - Tightened the `EHealthApplicationEvent` JSON schema (CCR0303 AC-7): the schema is now declared as JSON Schema draft-07; `eventType` and `resourceReference` are top-level required; `resourceReference` requires `minItems: 1` with each entry requiring both `label` and `reference`; and per-`eventType` `if`/`then`/`contains` rules assert the obligatory `resourceReference.label`. **Note for vendors:** producers must now emit both `label` and `reference` on every `resourceReference` entry and include the `eventType`-specific obligatory label. +## 9.0.2-SNAPSHOT (2026-05-04) +### Code systems +- Added http://ehealth.sundhed.dk/cs/ehealth-carecommunication-category for CareCommunication category codes. +- Added http://ehealth.sundhed.dk/cs/ehealth-carecommunication-priority for CareCommunication priority codes. +- Added http://ehealth.sundhed.dk/cs/message-type for CareCommunication message types (new-message, reply-message, forward-message). +### ValueSets +- Added http://ehealth.sundhed.dk/vs/ehealth-carecommunication-category. +- Added http://ehealth.sundhed.dk/vs/ehealth-carecommunication-priority. +- Added http://ehealth.sundhed.dk/vs/ehealth-carecommunication-mimetypes for allowed CareCommunication attachment MIME types. +- Added MessageType ValueSet for CareCommunication message types. +### ConceptMaps +- Added ConceptMap CareCommunication-Priority mapping CareCommunication priorities to MedCom equivalents. +- Added ConceptMap CareCommunucation-Category mapping CareCommunication categories to MedCom equivalents. +### Resource/profile changes +- Added new `ehealth-carecommunication` Communication profile with extensions for sender (PractitionerRole, Practitioner, optional CareTeam and ContactPoint), destination Organization, origin Organization, payload datetime, payload identifier, and message type. + ## 9.0.1 (2026-05-05) ### ValueSets - Removed http://ehealth.sundhed.dk/cs/poa-privilege CodeSystem and http://ehealth.sundhed.dk/vs/relatedperson-relationshiptype ValueSet include of the CodeSystem, since they were causing some issues during release, and are not strictly needed until 2026.3. From f29a0950a2ce331b327b55e183d73463f5e3a65f Mon Sep 17 00:00:00 2001 From: oliverduenielsen Date: Mon, 4 May 2026 13:46:30 +0200 Subject: [PATCH 22/27] added ehealth-carecommunication to supported profiles for Communication resource --- input/resources/CapabilityStatement-patient.json | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/input/resources/CapabilityStatement-patient.json b/input/resources/CapabilityStatement-patient.json index fbeefb64e..98386ec9f 100644 --- a/input/resources/CapabilityStatement-patient.json +++ b/input/resources/CapabilityStatement-patient.json @@ -751,7 +751,8 @@ "supportedProfile": [ "http://ehealth.sundhed.dk/fhir/StructureDefinition/ehealth-communication", "http://ehealth.sundhed.dk/fhir/StructureDefinition/ehealth-material-communication", - "http://ehealth.sundhed.dk/fhir/StructureDefinition/ehealth-message" + "http://ehealth.sundhed.dk/fhir/StructureDefinition/ehealth-message", + "http://ehealth.sundhed.dk/fhir/StructureDefinition/ehealth-carecommunication" ], "interaction": [ { From a354b6a8db8f57e482958c9b0ba9fb16494f86d3 Mon Sep 17 00:00:00 2001 From: oliverduenielsen Date: Mon, 11 May 2026 08:05:30 +0200 Subject: [PATCH 23/27] fix carecommunication profile --- input/fsh/ehealth-carecommunication.fsh | 13 +++++++------ 1 file changed, 7 insertions(+), 6 deletions(-) diff --git a/input/fsh/ehealth-carecommunication.fsh b/input/fsh/ehealth-carecommunication.fsh index 6a2c0fd31..85a937c5f 100644 --- a/input/fsh/ehealth-carecommunication.fsh +++ b/input/fsh/ehealth-carecommunication.fsh @@ -89,7 +89,7 @@ Parent: Communication * payload 1..* * payload ^slicing.discriminator.type = #type -* payload ^slicing.discriminator.path = "content[x]" +* payload ^slicing.discriminator.path = "$this.content" * payload ^slicing.rules = #open * payload contains string 1..* and attachment 0..* @@ -136,6 +136,7 @@ Description: "References the sending PractitionerRole (Actor), the Practitioner, * extension[contactPoint].value[x] only ContactPoint Extension: ehealth-carecommunication-destination +Id: ehealth-carecommunication-destination Title: "Destination Extension" Description: "Reference to the destination Organization for this communication." * . ^short = "Organization receiving the message" @@ -171,7 +172,7 @@ Description: "The type of the message. If inResponseTo is present, the type can ValueSet: MessageType Title: "Message Type ValueSet" Description: "Allowed message types: new-message, reply-message, forward-message." -* ^url = "http://ehealth.sundhed.dk/cm/ehealth-to-medcom-carecommunication-category" +* ^url = "http://ehealth.sundhed.dk/vs/ehealth-carecommunication-message-type" * ^compose.include.system = "http://ehealth.sundhed.dk/cs/message-type" * ^compose.include.concept[+].code = #new-message * ^compose.include.concept[=].display = "New Message" @@ -271,7 +272,7 @@ Severity: #error Invariant: only-asap-or-routine Description: "priority must be either 'asap' or 'routine'" -Expression: "priority = 'asap' or priority = 'routine'" +Expression: "priority.empty() or priority = 'asap' or priority = 'routine'" Severity: #error Invariant: topic-required-when-category-other @@ -281,7 +282,7 @@ Severity: #error Invariant: priority-category-invariant Description: "Priority must not be present when category is not 'regarding-referral'." -Expression: "where(category.coding.code != 'regarding-referral').priority.empty()" +Expression: "category.coding.code = 'regarding-referral' or priority.empty()" Severity: #error Invariant: uuidv4 @@ -306,7 +307,7 @@ Severity: #error Invariant: reply-requires-inResponseTo Description: "If messageType is 'reply-message', inResponseTo SHALL be populated." -Expression: "extension('http://ehealth.sundhed.dk/fhir/StructureDefinition/ehealth-carecommunication-message-Type').value.coding.where(code = 'reply-message').exists() implies inResponseTo.exists()" +Expression: "extension('http://ehealth.sundhed.dk/fhir/StructureDefinition/ehealth-carecommunication-message-Type').value.where(code = 'reply-message').exists() implies inResponseTo.exists()" Severity: #error Invariant: sender-required-based-on-messagetype @@ -314,5 +315,5 @@ Description: """ If messagetype is 'new' or 'reply', the sender extension must be present. If 'forward', sender may be absent. """ -Expression: "extension('http://ehealth.sundhed.dk/fhir/StructureDefinition/ehealth-carecommunication-message-Type').value.coding.where(code = 'new-message' or code = 'reply-message').exists() implies extension('http://ehealth.sundhed.dk/fhir/StructureDefinition/ehealth-carecommunication-sender').exists()" +Expression: "extension('http://ehealth.sundhed.dk/fhir/StructureDefinition/ehealth-carecommunication-message-Type').value.where(code = 'new-message' or code = 'reply-message').exists() implies extension('http://ehealth.sundhed.dk/fhir/StructureDefinition/ehealth-carecommunication-sender').exists()" Severity: #error \ No newline at end of file From 30ee735ea65d0341b01609940836e5ca88e716c3 Mon Sep 17 00:00:00 2001 From: oliverduenielsen Date: Mon, 11 May 2026 15:02:23 +0200 Subject: [PATCH 24/27] fix carecommunication profile --- input/fsh/ehealth-carecommunication.fsh | 16 ++++++++++------ 1 file changed, 10 insertions(+), 6 deletions(-) diff --git a/input/fsh/ehealth-carecommunication.fsh b/input/fsh/ehealth-carecommunication.fsh index 85a937c5f..c00b59c08 100644 --- a/input/fsh/ehealth-carecommunication.fsh +++ b/input/fsh/ehealth-carecommunication.fsh @@ -30,11 +30,15 @@ Parent: Communication * identifier[communicationId].use 0..1 * identifier[communicationId].use from http://hl7.org/fhir/ValueSet/identifier-use (required) * identifier[communicationId].value 1..1 MS +* identifier[communicationId].value ^short = "UUID v4 in URN form (urn:uuid:)" +* identifier[communicationId].value ^definition = "The communication identifier as a UUID v4 in URN form. The URN form (urn:uuid:) is used so the same UUID is byte-identical to Bundle.entry.fullUrl and references in the MedCom careCommunication Bundle this profile is aligned with." * identifier[communicationId] ^short = "The communication identifier" * identifier[messageHeaderId].system 1..1 MS -* identifier[messageHeaderId].system = "http://ehealth.sundhed.dk/id/ehealth-carecommunication-messageHeaderId" +* identifier[messageHeaderId].system = "http://ehealth.sundhed.dk/fhir/system/medcom-message-header-id" * identifier[messageHeaderId].value 1..1 MS +* identifier[messageHeaderId].value ^short = "UUID v4 in URN form (urn:uuid:)" +* identifier[messageHeaderId].value ^definition = "The MessageHeader identifier as a UUID v4 in URN form. The URN form (urn:uuid:) is used so the same UUID is byte-identical to Bundle.entry.fullUrl and references in the MedCom careCommunication Bundle this profile is aligned with." * identifier[messageHeaderId] ^short = "The ID of the originating MessageHeader resource" * status 1..1 MS @@ -150,9 +154,9 @@ Description: "Date and time of the payload segment." Extension: ehealth-carecommunication-payload-identifier Title: "Identifier Extension" -Description: "Extension to hold an Identifier for a payload. Value shall be a UUID identifier version 4." -* value[x] only string -* valueString 1..1 +Description: "Extension to hold an Identifier for a payload. Identifier.value shall be a UUID v4 in URN form (urn:uuid:)." +* value[x] only Identifier +* valueIdentifier 1..1 Extension: ehealth-carecommunication-origin Title: "sender organization" @@ -286,8 +290,8 @@ Expression: "category.coding.code = 'regarding-referral' or priority.empty()" Severity: #error Invariant: uuidv4 -Description: "The identifier.value SHALL be a valid UUID v4" -Expression: "identifier.value.matches('^[0-9a-f]{8}-[0-9a-f]{4}-4[0-9a-f]{3}-[89ab][0-9a-f]{3}-[0-9a-f]{12}$')" +Description: "Each identifier.value SHALL be a valid UUID v4 in URN form (urn:uuid:)" +Expression: "identifier.all(value.matches('^urn:uuid:[0-9a-f]{8}-[0-9a-f]{4}-4[0-9a-f]{3}-[89ab][0-9a-f]{3}-[0-9a-f]{12}$'))" Severity: #error Invariant: atLeastOnePayloadString From 66c07cbfa30ce06ac1acf1da14f6094bb94d2042 Mon Sep 17 00:00:00 2001 From: oliverduenielsen Date: Tue, 12 May 2026 09:30:51 +0200 Subject: [PATCH 25/27] invariant for urn:uuid: only for carecommunication identifier --- input/fsh/ehealth-carecommunication.fsh | 8 +++----- 1 file changed, 3 insertions(+), 5 deletions(-) diff --git a/input/fsh/ehealth-carecommunication.fsh b/input/fsh/ehealth-carecommunication.fsh index c00b59c08..8960be2ac 100644 --- a/input/fsh/ehealth-carecommunication.fsh +++ b/input/fsh/ehealth-carecommunication.fsh @@ -12,7 +12,6 @@ Parent: Communication and only-asap-or-routine and topic-required-when-category-other and priority-category-invariant - and uuidv4 and atLeastOnePayloadString and payloadAttachment-contentType-required and no-standard-sender @@ -25,6 +24,7 @@ Parent: Communication * identifier ^slicing.rules = #open * identifier contains communicationId 1..1 MS and messageHeaderId 0..1 MS +* identifier[communicationId] obeys uuidv4 * identifier[communicationId].system 1..1 MS * identifier[communicationId].system = "http://ehealth.sundhed.dk/id/ehealth-carecommunication-identifier" * identifier[communicationId].use 0..1 @@ -37,8 +37,6 @@ Parent: Communication * identifier[messageHeaderId].system 1..1 MS * identifier[messageHeaderId].system = "http://ehealth.sundhed.dk/fhir/system/medcom-message-header-id" * identifier[messageHeaderId].value 1..1 MS -* identifier[messageHeaderId].value ^short = "UUID v4 in URN form (urn:uuid:)" -* identifier[messageHeaderId].value ^definition = "The MessageHeader identifier as a UUID v4 in URN form. The URN form (urn:uuid:) is used so the same UUID is byte-identical to Bundle.entry.fullUrl and references in the MedCom careCommunication Bundle this profile is aligned with." * identifier[messageHeaderId] ^short = "The ID of the originating MessageHeader resource" * status 1..1 MS @@ -290,8 +288,8 @@ Expression: "category.coding.code = 'regarding-referral' or priority.empty()" Severity: #error Invariant: uuidv4 -Description: "Each identifier.value SHALL be a valid UUID v4 in URN form (urn:uuid:)" -Expression: "identifier.all(value.matches('^urn:uuid:[0-9a-f]{8}-[0-9a-f]{4}-4[0-9a-f]{3}-[89ab][0-9a-f]{3}-[0-9a-f]{12}$'))" +Description: "identifier.value SHALL be a valid UUID v4 in URN form (urn:uuid:)" +Expression: "value.matches('^urn:uuid:[0-9a-f]{8}-[0-9a-f]{4}-4[0-9a-f]{3}-[89ab][0-9a-f]{3}-[0-9a-f]{12}$')" Severity: #error Invariant: atLeastOnePayloadString From 7c4ae8fc90bc3fea6b350febb05ca15e9117a357 Mon Sep 17 00:00:00 2001 From: Bastian Date: Tue, 12 May 2026 14:07:04 +0200 Subject: [PATCH 26/27] bump SNAPSHOT version after merging snapshot version into 2026.3 --- sushi-config.yaml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/sushi-config.yaml b/sushi-config.yaml index 9dd21d1b7..c29f40f8e 100644 --- a/sushi-config.yaml +++ b/sushi-config.yaml @@ -7,7 +7,7 @@ canonical: http://ehealth.sundhed.dk/fhir name: eHealth Infrastructure title: eHealth Infrastructure status: active # draft | active | retired | unknown -version: 9.0.2-SNAPSHOT +version: 9.0.4-SNAPSHOT fhirVersion: 4.0.1 copyrightYear: 2021+ From 43d16e53129f3a60ff217fb30d78186c06b79ad5 Mon Sep 17 00:00:00 2001 From: Bastian Staunstrup Date: Tue, 19 May 2026 11:00:34 +0200 Subject: [PATCH 27/27] exclude inherited eCPR identifier slices from ehealth-patient --- input/fsh/ehealth-patient.fsh | 2 ++ input/pagecontent/changelog.md | 1 + 2 files changed, 3 insertions(+) diff --git a/input/fsh/ehealth-patient.fsh b/input/fsh/ehealth-patient.fsh index fc2d3b264..6a0c97db1 100644 --- a/input/fsh/ehealth-patient.fsh +++ b/input/fsh/ehealth-patient.fsh @@ -31,6 +31,8 @@ Parent: DkCorePatient * telecom[eBoks].rank 0..0 * identifier[cpr] 1..1 +* identifier[x-ecpr] 0..0 +* identifier[d-ecpr] 0..0 * gender 1..1 * contact.extension contains ehealth-patient-contactnote named patientContactnote 0..* diff --git a/input/pagecontent/changelog.md b/input/pagecontent/changelog.md index 91d72d3e5..344fcbc88 100644 --- a/input/pagecontent/changelog.md +++ b/input/pagecontent/changelog.md @@ -13,6 +13,7 @@ This is the log of changes made to the eHealth Implementation Guide. ### ConceptMaps ### Resource/profile changes - Updated ehealth-media to allow patient and relatedPerson references in it's operator field. +- Excluded inherited `x-ecpr` and `d-ecpr` identifier slices from `ehealth-patient`. These slices were added on `DkCorePatient` in dk-core 3.x and flowed into `ehealth-patient` silently; FUT does not support electronic CPR identifiers, so both are now constrained to `0..0`. Real CPR identifiers (`identifier[cpr]`, system `urn:oid:1.2.208.176.1.2`) are unaffected. ### Event messages - Tightened the `EHealthApplicationEvent` JSON schema (CCR0303 AC-7): the schema is now declared as JSON Schema draft-07; `eventType` and `resourceReference` are top-level required; `resourceReference` requires `minItems: 1` with each entry requiring both `label` and `reference`; and per-`eventType` `if`/`then`/`contains` rules assert the obligatory `resourceReference.label`. **Note for vendors:** producers must now emit both `label` and `reference` on every `resourceReference` entry and include the `eventType`-specific obligatory label.