Projo FHIR Documentation
0.1.0 - ci-build Switzerland flag

Projo FHIR Documentation - Local Development build (v0.1.0) built by the FHIR (HL7® FHIR® Standard) Build Tools. See the Directory of published versions

Artifacts Summary

This page provides a list of the FHIR artifacts defined as part of this implementation guide.

Behavior: Search Parameters

These define the properties by which a RESTful server can be searched. They can also be used for sorting and including related resources.

CommunicationRequest Web Answer Token

Searches CommunicationRequests by the web-answer-token extension value. Auto-created by the web-functions sweeper on first tick; triggers $reindex on CommunicationRequest after create/update. Used by web-functions to look up the CR a patient is submitting answers for, given the bearer token in the web POST.

Structures: Logical Models

These define data models that represent the domain covered by this implementation guide in more business-friendly terms than the underlying FHIR resources.

Conversational State (Stateless Projection)

The sidecar's stateless projection of conversational state, computed from FHIR resources on each inbound message. The sidecar has NO private database — every state view is a pure function of FHIR queries. Five projection helpers live in lib/projection/: isDuplicateInbound, compute24hWindow, currentQuestion, conversationState, lastActivityForCR. Any new sidecar state view must add a new projection here, never a cache.

Identity Resolution Decision

The decision matrix the orchestrator follows when processing a reverse CommunicationRequest (category=identity-resolution-required). The sidecar stamps the identity-resolution-reason code; the orchestrator reads it and executes the corresponding action. The five reasons and their responses are documented in ARCHITECTURE.md:432-451.

Structures: Resource Profiles

These define constraints on FHIR resources for systems conforming to this implementation guide.

Projo CarePlan
Schedule container produced by PlanDefinition/$apply. The orchestrator never creates CarePlans directly — they are server-side output of $apply. CarePlans carry the subject, status, and a timezone extension. Fire Arrow tags CarePlans with careplan-scheduling scheduled after $subscribe-due-events. The orchestrator's careplan-bootstrap Subscription picks up new active CarePlans and subscribes them to due-event scheduling. Supersede-then-enroll: the intake CarePlan is completed before a follow-up plan is enrolled.
Projo Communication

Per-message audit record + projection state. The sidecar creates a Communication for every inbound and outbound message. Outbound messages start in-progress (no wamid yet) and are finalized to completed when the WhatsApp API returns the wamid. Inbound messages are created as completed immediately (webhook = receipt). Abandoned messages are marked entered-in-error. Each Communication is partOf a CommunicationRequest and carries the wamid as an identifier for idempotency.

Projo CommunicationRequest

The contract surface between the orchestrator and the sidecar (and between the orchestrator and web-functions). The orchestrator creates an outbound CR when a Task is due; the sidecar picks it up via the cr-events Subscription, sends WhatsApp messages, and marks it completed. Reverse CRs (category=identity-resolution-required) are created by the sidecar when it cannot resolve an inbound sender. Reminder CRs (category=reminder) are created by the orchestrator's sweeper. Web CRs (medium=web) are created by the orchestrator and completed by web-functions.

Projo Flag

Review flag raised by the route-to-review bounded action when the clinical router cannot enroll the patient in a follow-up plan. Carries the bounded-action code on Flag.code, a clinical category, a deterministic routing-resource identifier for idempotency, and the Patient subject. The flag signals to a human reviewer that a routing decision needs manual attention.

Projo Organization

Customer/tenant. Each Organization maps to one WhatsApp phone number. Carries the repeating plan-slot extension (ADR 0002) that binds plan kinds to versioned PlanDefinition canonicals, the cached wa-phone-number-id for outbound routing, the WABA account ID for multi-WABA support (issue #238), per-WABA template overrides, and the preferred-language default for onboarded patients. Created by operators (root org) or stub-upserted by the orchestrator on unresolved-receiver identity resolution.

Projo Patient

End user. Created by the orchestrator on a no-match identity resolution, or matched from an inbound WhatsApp message by phone number or BSUID. Linked to Organization via managingOrganization. Carries phone (telecom), BSUID (identifier), name (parsed from WhatsApp profile name), and preferred language (communication). May be written back via extraction-writeback (Binary-wrapped JSON-Patch, ADR 0010).

Projo Provenance
Idempotency + audit anchor for SDC extraction and clinical routing. FHIR R4 Provenance has no identifier, so the meta.tag + entity[0].what (QR reference) combination is the idempotency key. Two tag systems: extraction-provenance sdc-extraction (for $extract) and routing-provenance clinical-routing (for routing decisions). activity is always DERIVE (v3-DataOperation).
Projo QuestionnaireResponse
Patient's answers, built conversationally by the sidecar as WhatsApp messages arrive. Created in-progress on the first answer (or pre-populated from initial values), updated per-answer with If-Match optimistic concurrency, and marked completed when the last answer is applied. The CR<->QR link lives on CommunicationRequest.payload[].contentReference — QuestionnaireResponse.basedOn is NOT used because FHIR R4 restricts it to CarePlan ServiceRequest and HAPI rejects others (HAPI-0931).
Projo Subscription

One of the four managed Subscriptions that wire the orchestrator and sidecar together. Each carries a meta.tag from the managed-subscription code system identifying its role. Reconciliation is by _tag search (always indexed in HAPI), NOT by criteria — so criteria changes are recoverable without duplicates. Channel type is message; endpoint is channel:fire-arrow-azure-queue:<queueName>. Projo never resets Subscription.status (would tear down the live subscription).

Projo Task

A single questionnaire dispatch. Tasks are materialized server-side by Fire Arrow from CarePlan (via PlanDefinition/$apply), then claimed and driven to completion by the orchestrator's handleTaskDue handler. The Task is the central anchor: it links to the CarePlan it came from (basedOn), the CommunicationRequest it dispatched (output), and the QuestionnaireResponse it ultimately collected (output). HAPI does not auto-index CommunicationRequest.about (HAPI-0524), so the CR↔Task link lives on Task.output rather than ?about= searches. Carries the delivery-time extension (the only active Task extension Projo writes today).

Structures: Extension Definitions

These define constraints on FHIR data types for systems conforming to this implementation guide.

Default Plan (Legacy)

Legacy single-plan pointer on Organization. Set by operators before plan-slot migration. Replaced by the repeating plan-slot extension (ADR 0002). Retained as a read-fallback for onboarding during the plan-slot transition (ADR 0003): resolvePlanCanonicalForKind reads plan-slot first, then falls back to default-plan for kind=onboarding only. Migration script migrate:plan-slots removes this extension in Phase 2 (–remove-legacy-default-plan).

Delivery Time

Stamps the actual instant a CommunicationRequest was delivered to the transport layer. Set by handleTaskDue (buildOutboundCRTransactionBundle) to new Date().toISOString() immediately before building and committing the CR — deliberately after all pre-commit FHIR round-trips (idempotency scan, atomic claim, locale resolution) so the patient's response window is measured from when we actually reach them, not shrunk by locale-resolution latency. Read by the deadline sweeper (keys off CR.occurrencePeriod.end, which is derived from delivery-time) and by operators for audit/triage. The only Task extension Projo actively writes today; the rest of the wa-* Task extensions are retired (see extensions-retired.fsh).

Extraction Writeback

Complex extension on a Questionnaire group item that routes its extracted content to a writeback target instead of creating a fresh resource. Sub-extensions: target (only code 'subject' — write back to the Patient referenced by QR.subject); mode (only code 'fill-if-empty' — patch only fields that are absent). Set by clinical questionnaire authors. Read by the orchestrator's classifyExtractedResources during SDC $extract: the extracted Patient fragment is wrapped as a Binary carrying a base64-encoded RFC 6902 JSON-Patch, posted as a transaction entry with method=PATCH. The patch leads with a test op on /meta/versionId to fail closed on concurrent writes. Requires Patient/patch authorization on the Device role. Used by the dermacare-language-selection Questionnaire to write back Patient.communication.language (ADR 0010).

Identity Resolution Reason

Reason code stamped on a reverse CommunicationRequest (category=identity-resolution-required) explaining why the sidecar could not attach an inbound message to an existing identity. Set by the sidecar. Codes: no-match (no existing identity matches sender's phone or BSUID), multiple-matches (more than one identity matches), non-conversational-only (matches exist but none of a conversational type — walk Person.link), no-active-cr (identity matched but no active CommunicationRequest to attach to), unresolved-receiver (receiver Organization unknown — upsert stub). Read by the orchestrator to decide its response (create identity, refuse, walk Person.link, reattach, upsert stub Organization).

Inbound Business Phone

E.164 business phone number that received the inbound message. Set by the sidecar on reverse CommunicationRequests from the Meta webhook's metadata.phone_number_id. Read by the orchestrator to upsert a stub Organization on the unresolved-receiver path (upsertOrganizationFromInboundBusinessPhone).

Inbound Business Phone ID

Meta Phone Number ID of the receiving business number. Set by the sidecar on reverse CommunicationRequests. Read by the orchestrator to cache wa-phone-number-id onto the upserted stub Organization, so the sidecar's WABA cache hit skips a Meta lookup on the next inbound.

Inbound Message Timestamp

Timestamp at which the inbound WhatsApp message arrived (per Meta webhook). Set by the sidecar on reverse CommunicationRequests. Preserves the original event time across identity-resolution latency.

Inbound Sender BSUID

WhatsApp Business Scope User ID (BSUID) of the inbound sender. Set by the sidecar on reverse CommunicationRequests (category=identity-resolution-required) from the Meta webhook's from_user_id. Read by the orchestrator to resolve identity (scanSenderIdentities by BSUID). BSUID persists across phone-number changes. Also used as a fallback identifier on Patient/Practitioner/RelatedPerson.identifier.

Inbound Sender Profile Name

WhatsApp profile name of the inbound sender. Set by the sidecar on reverse CommunicationRequests from the Meta webhook's contacts.profile.name. Read by the orchestrator as a hint for identity resolution and as input to Patient.name (family extracted if possible, given carries full profile name as fallback) when creating a new Patient.

Last Inbound Message Timestamp

Sidecar-owned transport stamp recording when the most recent inbound message for this CR arrived. Set by the sidecar's stampLastActivity on every patient interaction (answer, constraint re-prompt, resume signal, markCompleted). Read by the orchestrator sweeper's processReminderSchedule to reset the reminder schedule when the patient is active: if lastActivity > (nextReminder - threshold), the next reminder is pushed out to lastActivity + threshold. Best-effort: a missed stamp means a reminder might fire one cycle early, which is self-correcting on the next interaction.

Last Used Messaging Channel

The messaging channel the patient last used to send an inbound (a CommunicationMedium code: whatsapp, rcs, web). Set by the orchestrator's identityResolution handler: stamped at Patient creation (buildPatient) and updated whenever an inbound arrives on a different channel than the recorded value (read-modify-write via updatePatientWithRetry). Read by buildOutboundCR to default a new outbound CommunicationRequest's medium to the patient's last-used channel, with an explicit per-CR mediumCodeOverride seam for future channel-forcing (e.g. email-only). Falls back to the configured default (whatsapp) when absent. Lives under the projo.evoleen.com namespace (orchestrator-owned — the sidecar never reads or writes this extension; it routes by medium on the CR).

Next Reminder Timestamp

Orchestrator-owned schedule for when to send the next reminder CommunicationRequest. Set by handleTaskDue at dispatch: deliveryTime + REMINDER_THRESHOLD_MINUTES (default 60). Updated by the sweeper in three scenarios: (1) bootstrap if absent (CR.meta.lastUpdated + threshold); (2) reset when the patient is active (last-inbound-message-timestamp + threshold); (3) advanced after a successful reminder send (last reminder completion + REMINDER_INTERVAL_MINUTES default 24h). Read only by the orchestrator sweeper; the sidecar never reads or writes this extension. When the timestamp passes, the sweeper creates a reminder CR (category=reminder, basedOn=parent CR) via conditional create, up to MAX_REMINDERS_PER_CR (default 3).

Opted Out

Timestamp marking that the patient opted out of messaging by sending a STOP command. Set by handleStopCommand (via setOptedOut) — idempotent, skipped when already present. Read by the opt-out guards in handleIdentityResolutionRequired and applyTriggeredPlanIfNeeded to suppress plan application / re-engagement so the patient is not re-enrolled despite the STOP confirmation promising no further messages. The sweeper's Phase 3 re-engagement also checks this. Previously written inline as a literal URL in identityResolution.ts; centralized in the PatientExtensions constant + IG (ADR 0012 housekeeping).

Plan Slot

Repeating complex extension on Organization that binds a plan kind to a versioned PlanDefinition canonical (ADR 0002, ADR 0007). Set by operators via migration/seeding scripts (setOrganizationPlanSlot). Projo runtime never writes plan-slot — only reads it. Read by the orchestrator's applyTriggeredPlanIfNeeded: selectPlanKind picks the lifecycle kind (onboarding for new patients, re-engagement for returning, default otherwise), then resolvePlanCanonicalForKind looks up the slot. For onboarding only, falls back to legacy default-plan (ADR 0003). The onboarding-routing slot is read separately by clinical routing after onboarding completion. plan-slot-kind precedence on cold inbound: onboarding > re-engagement > default.

Preferred Language

Default preferred language for onboarded patients of this Organization. ISO 639-1 (e.g. 'de', 'en'). Set by operators at Organization creation time. Projo never writes this extension — only reads it. Read by buildPatient during identity resolution: getOrganizationPreferredLanguage reads the extension and stamps it onto Patient.communication[0].language.coding[0].code with preferred=true. If absent, the Patient is created without communication preferences and the sidecar's resolvePatientLanguage falls back to 'en'. The patient can later change their language via the dermacare-language-selection Questionnaire, which uses extraction-writeback (target=subject, mode=fill-if-empty) to update Patient.communication.language.

WABA Account ID

WhatsApp Business Account ID for this Organization. Set by operators for manually-created Organizations, or by the orchestrator's upsertOrganizationFromInboundBusinessPhone on the unresolved-receiver path. Read by the sidecar to resolve per-WABA credentials from Key Vault (whatsapp-{wabaId}-access-token, whatsapp-{wabaId}-app-secret) with an in-memory LRU cache (TTL 1 hour). No silent fallback — a missing WABA ID causes the sidecar to defer the CR for retry. Multi-WABA support (issue #238): each Organization carries its own WABA id.

WABA Account ID (on CR)

WABA account ID propagated onto the reverse CommunicationRequest by the sidecar. Read by the orchestrator to stamp waba-account-id onto the upserted stub Organization on the unresolved-receiver path.

WABA Invitation Template Override

Per-Organization override of the invitation message template name (default WHATSAPP_INVITATION_TEMPLATE_NAME). Set by operators. Read by the sidecar when sending the invitation template. Org-specific templates allow per-customer localization or branding of the initial questionnaire invitation.

WABA Reminder Template Override

Per-Organization override of the reminder message template name (default WHATSAPP_REMINDER_TEMPLATE_NAME). Set by operators. Read by the sidecar when sending reminder templates.

WABA Web Invitation Template Override

Per-Organization override of the web-channel invitation message template name (default WHATSAPP_WEB_INVITATION_TEMPLATE_NAME). Set by operators. Read by the sidecar when sending web-channel invitation templates. See ADR 0011.

WABA Web Reminder Template Override

Per-Organization override of the web-channel reminder message template name (default WHATSAPP_WEB_REMINDER_TEMPLATE_NAME). Set by operators. Read by the sidecar when sending web-channel reminder templates. See ADR 0011.

Web Answer Link

Absolute URL the patient opens to submit answers via the web channel (ADR 0011). Set by the orchestrator (handleTaskDue) on outbound CRs at dispatch time — unconditionally for RCS-medium questionnaire CRs (ADR 0012: the RCS sidecar renders this as an in-messenger webview button and never plays the questionnaire in-band), and conditionally for WhatsApp/web CRs (locale-gated). Read by each consumer channel to embed the link: WhatsApp embeds it in the invitation template payload; RCS renders it as an OpenUrl webview suggestion (openUrlProperties.application=WEBVIEW). The web-functions app renders the questionnaire at this URL.

Web Answer Token

SHA-256 hash of a 256-bit bearer token used by the web answer channel (ADR 0011). Set by the orchestrator (handleTaskDue) on CommunicationRequests with medium=web at dispatch time. Read by web-functions to validate the bearer token on the POST that submits the QuestionnaireResponse and completes the CR. Lives under the projo.evoleen.com namespace (hardcoded, not EXTENSION_BASE_URL).

WhatsApp Attempt Count (Retired)

Retired. Was the count of outbound delivery attempts on a Task. Superseded by the sidecar's retry logic.

WhatsApp Conversation Status (Retired)

Retired. Was the orchestrator-side conversation state on a Task. Codes: invited, in_progress, completed, failed, expired. Superseded by Task.businessStatus + the sidecar-owned Communication lifecycle.

WhatsApp Current Link ID (Retired)

Retired. Was the WhatsApp Cloud API link id for the in-flight conversation on a Task. Superseded by CommunicationRequest.partOf tracking.

WhatsApp Error Code (Retired)

Retired. Was the WhatsApp Cloud API error code from the last failed send on a Task. Superseded by Communication.statusReason on the sidecar.

WhatsApp Error Detail (Retired)

Retired. Was the WhatsApp Cloud API error detail string from the last failed send on a Task.

WhatsApp Last Activity Timestamp (Retired)

Retired. Was the timestamp of the most recent inbound or outbound activity on a Task. Superseded by last-inbound-message-timestamp on the CR.

WhatsApp Last Inbound Message ID (Retired)

Retired. Was the wamid of the most recent inbound message on a Task. Superseded by Communication.identifier (wamid system) on the sidecar.

WhatsApp Last Outbound Message ID (Retired)

Retired. Was the wamid of the most recent outbound message on a Task. Superseded by Communication.identifier (wamid system) on the sidecar.

WhatsApp Last Reminder Timestamp (Retired)

Retired. Was the timestamp of the most recent reminder sent on a Task. Superseded by the reminder CR's own Communication.sent.

WhatsApp Last Sender Phone Number ID (Retired)

Retired. Was the cached Meta Phone Number ID of the sender's business number, used for per-business-number 24h window tracking. Superseded by the sidecar's compute24hWindow projection.

WhatsApp Last User Message Timestamp (Retired)

Retired. Was the timestamp of the most recent inbound message from this Patient, used to compute the 24h messaging window. Superseded by the sidecar's compute24hWindow projection (no Patient extension).

WhatsApp Phone Number ID

Cached Meta Phone Number ID for the Organization's WhatsApp number. Set by two writers: (1) the orchestrator's upsertOrganizationFromInboundBusinessPhone on the unresolved-receiver path (from the reverse CR's inbound-business-phone-id extension); (2) the sidecar's ensureWhatsAppPhoneNumberId on the first outbound dispatch — queries Meta Graph API GET /{WABA-ID}/phone_numbers, matches by normalized E.164 digits, caches back to Organization. Read by the sidecar on every outbound dispatch to skip the Graph API lookup. No active refresh — if the cached value becomes stale (e.g. Meta rotates the phone-number-id), WhatsApp sends fail and an operator must clear the extension.

Terminology: Value Sets

These define sets of codes used by systems conforming to this implementation guide.

Extraction Writeback Mode Value Set

Allowable mode codes for the extraction-writeback extension's mode sub-extension. Only fill-if-empty is supported (patch only fields that are absent on the target Patient).

Extraction Writeback Target Value Set

Allowable target codes for the extraction-writeback extension's target sub-extension. Only subject is supported (write back to the Patient referenced by QR.subject).

Fire Arrow Communication Medium Value Set

Allowable mediums for a CommunicationRequest or Communication.

Fire Arrow CommunicationRequest Category Value Set

Categories used on CommunicationRequest.

Fire Arrow Managed Subscription Value Set

Tag values identifying the four managed Subscriptions.

Projo Bounded Action (All Codes)

All bounded-action codes, including designed-but-not-implemented.

Projo Bounded Action (Implemented Subset)

Bounded actions the orchestrator will actually execute. Designed-but-not-implemented codes (notify-practitioner, raise-flag, send-message, create-task, assign-careteam) are excluded — the orchestrator rejects these if proposed by the router.

Projo Identity Resolution Reason Value Set

Reason codes stamped on a reverse CommunicationRequest (category=identity-resolution-required) explaining why the sidecar could not attach an inbound message. Codes: no-match (no existing identity matches the sender's phone or BSUID), multiple-matches (more than one identity matches), non-conversational-only (matches exist but none of a conversational type — walk Person.link), no-active-cr (identity matched but no active CommunicationRequest to attach to), unresolved-receiver (receiver Organization unknown — upsert stub).

Projo Plan Slot Kind Value Set

Allowable kinds for the plan-slot extension's kind sub-extension.

Projo Task Business Status (Active Subset)

The subset of task-business-status codes that current Projo code writes. Historical codes (invited, reminder-sent, collecting-responses, delivery-failed) are documented in the code system but excluded from this value set.

Projo Task Business Status (All Codes)

All task-business-status codes, including historical ones that may appear on older Tasks.

Projo Task Output Type Value Set

Type codes for Task.output entries.

Terminology: Code Systems

These define new code systems used by systems conforming to this implementation guide.

Fire Arrow CarePlan Scheduling

Tag stamped on CarePlan.meta.tag by the Fire Arrow $subscribe-due-events operation to mark that due-event scheduling is active. Projo's careplan-bootstrap Subscription excludes CarePlans tagged scheduled to avoid double-subscription. Projo never writes this tag directly.

Fire Arrow Communication Category

Per-Communication category stamped by the WhatsApp sidecar. Codes classify each message in the conversation audit trail: invitation (initial template), question (next-question template), answer (patient reply), reminder (reminder template), abandoned (message that could not be delivered / conversation abandoned), completion (closing message). The sidecar's sweeper also uses reminder as the category for reminder CommunicationRequests.

Fire Arrow Communication Medium

The transport medium for a CommunicationRequest or Communication. Codes: whatsapp (default — WhatsApp Cloud API via the WhatsApp sidecar), rcs (RCS Business Messaging via CM.com — ADR 0012), web (browser-based answer channel, ADR 0011). The system URL is configurable via COMMUNICATION_MEDIUM_SYSTEM (default https://firearrow.io/fhir/CodeSystem/communication-medium); the default code is configurable via COMMUNICATION_MEDIUM_CODE (default whatsapp). Each sidecar's cr-events Subscription filters on its own medium so a sidecar only sees CRs for its channel.

Fire Arrow CommunicationRequest Category

Category on CommunicationRequest. The two projo-relevant categories are: identity-resolution-required (reverse CR — sidecar could not attach an inbound message to an existing identity and asks the orchestrator to resolve) and reminder (orchestrator-created reminder CR, basedOn=parent CR).

Fire Arrow Managed Subscription

Tag value on Subscription.meta.tag identifying the four managed Subscriptions that wire the orchestrator and sidecar together. Each consuming app's sweeper (every 5 min) reconciles its own Subscription by _tag search (always indexed in HAPI), NOT by criteria — so criteria changes are recoverable without duplicates. Codes: sidecar-cr-events, projo-cr-status-events, projo-identity-resolution-events, projo-careplan-bootstrap.

Projo Bounded Action

Allow-listed actions that the orchestrator will execute from a router PlanDefinition $apply output (RequestGroup.action). The router (CQL Library + PlanDefinition) proposes; the orchestrator disposes (ADR 0006 — 'router proposes, projo disposes'). Implemented codes: enroll-plan, supersede-plan, route-to-review. Designed but explicitly not implemented (rejected): notify-practitioner, raise-flag, send-message, create-task, assign-careteam.

Projo Extraction Provenance

Tag value stamped on Provenance.meta.tag for SDC $extract idempotency. Provenance has no identifier in R4; the meta.tag + entity[0].what (QR reference) combination is the idempotency key: a Provenance with the same tag AND same entity[0].what implies extraction has already run for that QuestionnaireResponse, and the deterministic identifiers on extracted resources prevent duplicate creates.

Projo Extraction Writeback Mode

Mode codes for the extraction-writeback extension's mode sub-extension. Only fill-if-empty is supported — the JSON-Patch may only set fields that are currently absent on the target Patient. The leading test op on /meta/versionId also enforces optimistic concurrency.

Projo Extraction Writeback Target

Target codes for the extraction-writeback extension's target sub-extension. Only subject is supported — route the extracted Patient fragment back to the Patient referenced by QR.subject.

Projo Identifier Systems

Catalog of identifier system URIs used by Projo. Each code documents the value format and where the identifier is carried. Identifier systems are NOT FHIR conformance resources — they are URI strings used in Patient.identifier[].system, Communication.identifier[].system, etc. This CodeSystem exists only to document them.

Projo Identity Resolution Reason

Reason codes stamped on a reverse CommunicationRequest (category=identity-resolution-required) explaining why the WhatsApp sidecar could not attach an inbound message to an existing identity. The orchestrator reads this code to decide its response (see 09_identity.md).

Projo Plan Slot Kind

Kinds of plan slot bound on an Organization. Used by the orchestrator to select which PlanDefinition to $apply when an identity-resolution decision (no-match, no-active-cr, unresolved-receiver) calls for a triggered plan. Precedence on cold inbound: onboarding > re-engagement > default. onboarding-routing (ADR 0007) is the router-side slot that pins the CQL-driven clinical routing PlanDefinition, not a lifecycle plan.

Projo Routing Provenance

Tag value stamped on Provenance.meta.tag for clinical-routing idempotency. Same pattern as extraction provenance: meta.tag + entity[0].what (QR reference) is the idempotency key. Provenance.target[] references the enrolled/superseded CarePlan or the raised review Flag.

Projo Task Business Status

Lifecycle states for a Projo Task (single questionnaire dispatch). Carried on Task.businessStatus.coding. Projo currently writes only a subset: waiting-for-delivery, responses-collected, expired. The remaining codes (invited, reminder-sent, collecting-responses, delivery-failed) are documented for historical compatibility — they may appear on older Tasks but are no longer written by current code.

Projo Task Output Type

Type codes for Task.output entries. The orchestrator stamps Task.output with these codes to link a Task to its side-effect resources: the CommunicationRequest it dispatched (code=communication-request) and the QuestionnaireResponse it ultimately collected (code=questionnaire-response). Used because HAPI does not auto-index CommunicationRequest.about (HAPI-0524), so the link is carried on Task.output rather than searched via ?about=.

Example: Example Instances

These are example instances that show what data produced and consumed by systems conforming with this implementation guide might look like.

Example Extracted Observation

An Observation extracted from a QuestionnaireResponse via SDC $extract. code=Questionnaire.item.code (LOINC), derivedFrom=QR, identifier=extracted-resource (deterministic).

Example Extraction Provenance

Provenance recording SDC $extract results. meta.tag=sdc-extraction, entity[0].what=QR, target[]=extracted Observation, activity=DERIVE.

Example Inbound Communication (Answer)

An inbound patient reply. status=completed, category=answer, medium=whatsapp, partOf=CR, sender=Patient, payload.contentString=message text, identifier=wamid.

Example Managed Subscription (cr-status-events)

The projo-cr-status-events managed Subscription. Criteria: CommunicationRequest?status=completed,revoked&category:not=identity-resolution. Channel: message, endpoint=fire-arrow-azure-queue:cr-status-events. meta.tag=projo-cr-status-events.

Example Organization (multi-plan, multi-WABA)

A customer Organization carrying two plan-slots (onboarding + default), a cached wa-phone-number-id, a WABA account id, and a preferred language.

Example Outbound CommunicationRequest

An outbound CR created by handleTaskDue: medium=whatsapp, status=active, subject+recipient=Patient, about=Task, payload=Questionnaire ref, occurrencePeriod=delivery-anchored window. Carries web-answer-link + next-reminder-timestamp extensions.

Example Patient

A patient created from a no-match identity resolution. Carries phone (telecom), BSUID (identifier), managingOrganization, name, and preferred language.

Example QuestionnaireResponse (in-progress)

A QR in-progress with one answer applied. questionnaire=Questionnaire canonical, subject=Patient, status=in-progress. basedOn is intentionally NOT set (see profile comment).

Example Reverse CommunicationRequest

A reverse CR created by the sidecar when an inbound WhatsApp message cannot be attached to an existing identity. category=identity-resolution-required, medium=whatsapp, identifier=inbound-sender-phone, extension=identity-resolution-reason (no-match).

Example Routing Flag (route-to-review)

A Flag raised by the route-to-review bounded action. category=clinical, code=route-to-review, subject=Patient, identifier=routing-resource <qrId>:review.

Example Task (in-progress)

A Task in-progress with business-status=waiting-for-delivery. basedOn=CarePlan, for=Patient, output=CommunicationRequest ref, extension=delivery-time.