This functionality is available in Aidbox versions 2409 and later and requires FHIR Schema validation engine to be enabled.

Overview

This feature enables dynamic subscriptions to changes in FHIR resources, allowing users/systems to receive notifications through multiple channels, including Kafka.

For an application example, refer to Aidbox Subscriptions & Kafka AidboxTopicDestination

Key Components

  • AidboxSubscriptionTopic is a custom Aidbox resource modeled after the FHIR R6 SubscriptionTopic resource. The resource allows defining a set of events that clients can subscribe to, such as changes in specific resources.
  • AidboxTopicDestination is a custom Aidbox resource that defines where and how the notifications triggered by an AidboxSubscriptionTopic should be sent. This resource offers flexibility in specifying various types of destinations. And is considered as a system configuration resource.
  • AidboxSubscriptionStatus is a custom Aidbox resource which describes the notifications: what messages stored in the bundle, source and destination.

AidboxSubscriptionTopic

The AidboxSubscriptionTopic resource describes the data sources for subscriptions. It allows clients to subscribe to events in Aidbox and filter them using user-defined triggers, which are specified by the trigger element. Supported properties:

PropertyTypeDescription
resource *uriResource (reference to definition) for this trigger definition. It is binding to All Resource Types.
supportedInteractioncodecreate | update | delete
fhirPathCriteriastringFHIRPath based trigger rule. FHIRPath criteria are evaluated only within the context of the current resource. Supports %current and %previous variables for comparing resource states during updates.
descriptionstringText representation of the event trigger.

* required.

Create AidboxSubscriptionTopic resource

POST /fhir/AidboxSubscriptionTopic
content-type: application/json
accept: application/json

{
  "resourceType": "AidboxSubscriptionTopic",
  "url": "http://example.org/FHIR/R5/SubscriptionTopic/QuestionnaireResponse-topic",
  "status": "active",
  "trigger": [
    {
      "resource": "QuestionnaireResponse",
      "fhirPathCriteria": "status = 'completed' or status = 'amended'"
    }
  ]
}

AidboxTopicDestination

The AidboxTopicDestination resource is used to define channel configurations for processing subscription data.

Create a TopicDestination

To start processing subscription data, create a AidboxTopicDestination resource with a reference to the AidboxSubscriptionTopic. Examples of AidboxTopicDestination resources can be found in sub-sections.

Stop subscription data processing

To stop processing subscription data, delete the AidboxTopicDestination resource.

AidboxTopicDestination Profile

Ensure that the resource metadata contains the kind-specific AidboxTopicDestination profile.

Elements

PropertyTypeDescription
statuscodeactive - the only possible value for now. Expected to be expanded.
topic *stringUrl of AidboxSubscriptionTopic resource.
kind *codeDefines the destination for sending notifications. Supported values: kafka-at-least-once, kafka-best-effort, webhook-at-least-once, gcp-pubsub-at-least-once
parameter *FHIR parametersDefines the destination parameters for sending notifications. Parameters are restricted by profiles for each destination.
contentSubscription payload content

full-resource | id-only | empty

full-resource is the default value.

* required.

Organization-based hierarchical filtering

Organization-based hierarchical filtering is available starting from version 2509.

Both AidboxSubscriptionTopic and AidboxTopicDestination support organization-based hierarchical access control.

How it works

The filtering mechanism uses organization extensions and works as consecutive filters:

  1. 1.

    Use organization extension:

    In organizational-based access control, both events (resources) and subscription resources (AidboxSubscriptionTopic and AidboxTopicDestination) are automatically marked with organization extensions when created through organization-specific APIs (/Organization/<org-id>/fhir/...).

  2. 2.

    Consecutive filtering: The filters work in sequence - first the topic filter is applied, then the destination filter.

  3. 3.

    Resources without organization extension: If topic/destination resources are created without organization extension, they completely ignore organization information and work as before. All events will be caught by the topic if triggered (regardless of whether the event has organization extension or not).

  4. 4.

    Resources with organization extension:

    • Events without organization extension: Will always be skipped
    • Events with organization extension:
      • Caught: If the event organization is under or equal to the topic/destination organization in the hierarchy
      • Skipped: If the event organization is above or unrelated to the topic/destination organization

Examples

Example 1: Organization hierarchy with event filtering

Consider an organization structure where Organization B is part of Organization A. The diagram below shows how events flow through the subscription system with hierarchical filtering:

graph TD

    %% Org hierarchy
    subgraph OrgHierarchy ["Organization Hierarchy"]
        OrgA("Organization A<br/>(Parent)"):::violet1
        OrgB("Organization B<br/>(Child of Org A)"):::blue1
        OrgA --> OrgB
    end

    %% Event from Org A
    subgraph FlowA ["Event from Org A Flow"]
        direction LR
        EventA("📋 Event from Org A"):::violet1
        TopicAA("AidboxSubscriptionTopic<br/>(related to Org A)"):::red1
        DestBA("AidboxTopicDestination<br/>(related to Org B)"):::red1
        ExternalDestBA("Kafka"):::green1

        EventA --> TopicAA
        TopicAA -->|✅ Forward| DestBA
        DestBA -->|❌ Filtered out| ExternalDestBA
    end

    %% Event from Org B
    subgraph FlowB ["Event from Org B Flow"]
        direction LR
        EventB("📋 Event from Org B"):::blue1
        TopicAB("AidboxSubscriptionTopic<br/>(related to Org A)"):::red1
        DestBB("AidboxTopicDestination<br/>(related to Org B)"):::red1
        ExternalDestBB("Kafka"):::green1

        EventB --> TopicAB
        TopicAB -->|✅ Forward| DestBB
        DestBB -->|✅ Forward| ExternalDestBB
    end

    %% invisible ordering links
    OrgHierarchy -.-> FlowA
    FlowA -.-> FlowB

    %% make the links invisible
    linkStyle 7,8 opacity:0;

Filtering behavior:

  • Event from Org A: Processed by the topic (same organization) but filtered out at the aidbox topic destination level
  • Event from Org B: Processed by the topic (child organization) and forwarded to destination at the aidbox topic destination level
  • Event from unrelated organization: Would be filtered out at the subscription topic level

Example 2: Filtering at the destination level only

Consider an organization structure which two organizations Organization A and Organization B. The diagram below shows how events flow through the subscription system when filtering is applied at the destination level only:

graph TD

    %% Org hierarchy
    subgraph OrgHierarchy ["Organization Hierarchy"]
        OrgA("Organization A"):::violet1
        OrgB("Organization B"):::blue1
    end

    %% Event from Org A
    subgraph FlowA ["Event from Org A Flow"]
        direction LR
        EventA("📋 Event from Org A"):::violet1
        TopicAA("AidboxSubscriptionTopic"):::red1
        DestBA("AidboxTopicDestination<br/>(related to Org A)"):::red1
        ExternalDestBA("Kafka"):::green1

        EventA --> TopicAA
        TopicAA -->|✅ Forward| DestBA
        DestBA -->|✅ Forward| ExternalDestBA
    end

    %% Event from Org B
    subgraph FlowB ["Event from Org B Flow"]
        direction LR
        EventB("📋 Event from Org B"):::blue1
        TopicAB("AidboxSubscriptionTopic"):::red1
        DestBB("AidboxTopicDestination<br/>(related to Org A)"):::red1
        ExternalDestBB("Kafka"):::green1

        EventB --> TopicAB
        TopicAB -->|✅ Forward| DestBB
        DestBB -->|❌ Filtered out| ExternalDestBB

    end

    %% invisible ordering links
    OrgHierarchy -.-> FlowA
    FlowA -.-> FlowB

    %% make the links invisible
    linkStyle 6,7 opacity:0;

Filtering behavior:

  • Event from Org A: Processed by the topic (no filtering) and forwarded to aidbox topic destination
  • Event from Org B: Processed by the topic (no filtering) but filtered out at the aidbox topic destination level
  • Event from unrelated organization: Would be filtered out at the aidbox topic destination level

Currently supported channels

Notification Shape

Notification is a FHIR Bundle resource with history type, containing relevant resources in its entries. The first entry is a AidboxSubscriptionStatus resource, which describes the payload.
The other entries depend on AidboxTopicDestination content parameter. This parameter is the binding to the FHIR subscription-payload-content value set: full-resource | id-only | empty

{
  "resourceType":"Bundle",
  "type":"history",
  "timestamp":"2024-10-03T10:07:55Z",
  "entry":[
    {
      "resource":{
        "resourceType":"AidboxSubscriptionStatus",
        "status":"active",
        "type":"event-notification",
        "notificationEvent":[
          {
            "eventNumber":1,
            "focus":{
              "reference":"QuestionnaireResponse/458e771c-0ff1-4858-ac07-93b7a10c8e3b"
            }
          }
        ],
        "topic":"http://example.org/FHIR/R5/SubscriptionTopic/QuestionnaireResponse-topic",
        "topic-destination":{
          "reference":"AidboxTopicDestination/kafka-destination"
        }
      }
    },
    {
      "resource":{
        "id":"458e771c-0ff1-4858-ac07-93b7a10c8e3b",
        "item":[
          {
            "text":"Leishmania sp 14kD IgG Ser Ql IB",
            "answer":[
              {
                "valueString":"123"
              }
            ],
            "linkId":"128852"
          },
          {
            "text":"Leishmania sp 16kD IgG Ser Ql IB",
            "answer":[
              {
                "valueString":"432"
              }
            ],
            "linkId":"128851"
          }
        ],
        "meta":{
          "lastUpdated":"2024-10-03T10:07:55.843374Z",
          "versionId":"1970",
          "extension":[
            {
              "url":"ex:createdAt",
              "valueInstant":"2024-10-03T10:07:42.342731Z"
            }
          ]
        },
        "author":{
          "identifier":{
            "type":{
              "coding":[
                {
                  "code":"UID",
                  "system":"urn:system:aidbox",
                  "display":"User ID"
                }
              ]
            },
            "value":"admin",
            "system":"http://localhost:8765"
          }
        },
        "status":"completed",
        "authored":"2024-10-03T10:07:55.664Z",
        "resourceType":"QuestionnaireResponse",
        "questionnaire":"http://loinc.org/q/100109-8"
      },
      "fullUrl": "http://aidbox-server/fhir/QuestionnaireResponse/458e771c-0ff1-4858-ac07-93b7a10c8e3b",
      "request":{
        "method":"POST",
        "url":"/fhir/QuestionnaireResponse"
      }
    }
  ]
}