Huli FHIR Core Implementation Guide (R4)
0.1.0 - Release

Huli FHIR Core Implementation Guide (R4) - Local Development build (v0.1.0) built by the FHIR (HL7® FHIR® Standard) Build Tools. See the Directory of published versions

Encounter Mapping

Encounter Mapping: Huli -> FHIR R4

Write-path behavior

POST / PUT /fhir/R4/Encounter route through the same practice encounter service the in-app clinical chart uses, so the public API enforces the application's clinical guards rather than writing straight to the database:

  • Deceased-patient write guard — creating or amending an encounter against a deceased patient is rejected (409 Conflict), matching the in-app behavior.
  • Readiness validators — custom-form numeric bounds and section rules, plus the close-readiness checks, run on save.
  • Template-backed finalize guard — a template-backed encounter is finalized (finished) through the seal-the-snapshot path; the public API cannot produce a partial finalize.
  • MX consultation-start gates — for an organization/practitioner that is effectively active under la normativa, the consultation-start gate suite (activation, clinic, patient-data, personnel role) applies on create.
  • Appointment-binding integrity — a linked appointment must belong to the same patient and practitioner.
  • 24h auto-close — an encounter created in-progress is scheduled for the 24-hour auto-close by the durable reconciler.

Encounter.subject is immutable on update — a PUT whose subject differs from the stored patient is rejected.

No version history surface. The Encounter resource exposes only its current state — there is no _history / vread / Provenance amendment surface (it had no application equivalent). meta.versionId tracks the row's modified_on (mirrored in the ETag) and advances on every update, but prior versions are not addressable.

Resource Identity

FHIR path Cardinality Must Support Justification
Encounter.id 1..1 PK, always present
Encounter.meta.lastUpdated 0..1 Auto-updated trigger
Encounter.serviceProvider 0..1 Yes Resolves to an Organization reference

Status

FHIR path Cardinality Must Support Justification
Encounter.status 1..1 Yes Required; defaults to in-progress

Value mapping:

Huli value FHIR value Notes
planned planned Direct match
in-progress in-progress Direct match
completed finished KEY DIVERGENCE: Huli uses "completed", FHIR R4 uses "finished"
cancelled cancelled Direct match

Source: Huli Public FHIR API (Encounter status values)

Accepted status on create vs. update

The set of Encounter.status values accepted depends on the operation:

  • Create (POST) — restricted to planned, in-progress, finished, cancelled (the four states the codec round-trips). The transitional/terminal markers (arrived, triaged, onleave, entered-in-error, unknown) are rejected at the adapter boundary with Encounter.status must be one of: planned, in-progress, finished, cancelled on create — they have no meaning as an initial state.
  • Update (PUT) — accepts the broader FHIR R4 status set. Which target status is actually reachable is governed by the status-transition table: an illegal transition (e.g. finishedplanned) is rejected by the use-case with 422 Unprocessable Entity.

Class

FHIR path Cardinality Must Support Justification
Encounter.class 1..1 Yes Required; defaults to ambulatory

Value mapping:

Huli value FHIR system FHIR code FHIR display
ambulatory http://terminology.hl7.org/CodeSystem/v3-ActCode AMB ambulatory
emergency (same) EMER emergency
inpatient (same) IMP inpatient encounter
virtual (same) VR virtual

Source: Huli Public FHIR API (Encounter class values)

Subject and References

FHIR path Cardinality Must Support Justification
Encounter.subject 1..1 Yes Required; references the patient
Encounter.participant[0].individual 1..* Yes Required; references the user
Encounter.appointment[0] 0..1 Nullable; no enforced referential constraint

Participant write behavior. On write, only participant[0].individual is read, and it is honored as a Practitioner reference (a Huli user id). Additional participant[] entries and PractitionerRole references are not consumed on write, even though the profile cardinality allows 1..* participants and a Practitioner or PractitionerRole individual.

Period

FHIR path Cardinality Must Support Justification
Encounter.period.start 1..1 Yes Required; timestamp with offset
Encounter.period.end 0..1 NULL while in-progress

Reason

FHIR path Cardinality Must Support Justification
Encounter.reasonCode[0].text 0..* Free text chief complaint (LOINC 10154-3)

Diagnosis

FHIR path Cardinality Must Support Justification
Encounter.diagnosis[].condition (contained HuliCondition) .code.coding[0].code 0..* ICD-10 code
Contained Condition .code.coding[0].system Always "http://hl7.org/fhir/sid/icd-10"
Contained Condition .code.coding[0].display Diagnosis display name
Encounter.diagnosis[].rank "primary"->rank=1, "secondary"->rank=2+

Mapping rule: Each diagnosis entry becomes:

  1. A contained HuliCondition resource with ICD-10 coding
  2. An Encounter.diagnosis backbone entry referencing the contained Condition
  3. rank = 1 for type="primary", rank = 2 (incrementing) for type="secondary"

rank is writable and round-trips. On write, the Encounter.diagnosis[].rank of the entry referencing each contained Condition selects the app's binary primary/secondary classification:

  • rank: 1primary diagnosis.
  • rank ≥ 2, or no ranksecondary diagnosis.

Because the app model is binary (primary vs. secondary), the ordinal rank collapses: a rank: 3 (or higher) is stored as secondary and reads back as secondary (rank: 2), not rank: 3. Only the rank-1 / not-rank-1 distinction survives the round-trip.

Clinical content carried outside the Encounter resource

The following SOAP-structured fields are carried by the Public API as discrete Observation resources, as contained resources on the Encounter, or are not modelled through FHIR in this IG. They are listed here so partner systems know where to look for the corresponding clinical content.

Contained-resource id conventions

The SOAP narrative blocks ride on the Encounter as contained resources identified by a stable, well-known id. The Public API both emits these ids on read and uses them to route the corresponding contained entries on write — so a client must set the exact id below for a write to land in the right place:

Contained resource contained[].id Maps to
ClinicalImpression (subjective/objective) subjective-objective-summary SOAP S + O narratives
ClinicalImpression (diagnostic impression) diagnostic-impression Diagnostic impression narrative
CarePlan (follow-up plan) care-plan Follow-up plan narrative
HuliCondition (each diagnosis) server-allocated per diagnosis The encounter's structured diagnoses

Subjective / Objective summary. The SOAP Subjective (S) and Objective (O) narratives both map to the single contained ClinicalImpression with id: "subjective-objective-summary": on read, S and O are concatenated into its summary with a blank line between them (S\n\nO); on write, the public API splits summary back into S and O on the first blank-line separator. Supplying a summary with no blank-line separator stores the whole value as the Subjective narrative.

Diagnostic impression ("Impresión diagnóstica"). A contained ClinicalImpression with id: "diagnostic-impression" carries the diagnostic-impression narrative in its summary. The entry may optionally carry the LOINC code 51848-0 (Evaluation note) on code.coding[0]; the code is advisory — routing is driven by the contained id, not by the code.

Follow-up plan ("Plan de seguimiento"). A contained CarePlan with id: "care-plan" carries the follow-up-plan narrative in its description.

Example contained block

A write that sets the diagnostic impression and follow-up plan (alongside the subjective/objective summary) supplies:

{
  "resourceType": "Encounter",
  "status": "in-progress",
  "subject": { "reference": "Patient/01936b7c-8d4e-7000-8000-000000004001" },
  "contained": [
    {
      "resourceType": "ClinicalImpression",
      "id": "subjective-objective-summary",
      "status": "completed",
      "subject": { "reference": "Patient/01936b7c-8d4e-7000-8000-000000004001" },
      "summary": "Refiere cefalea de 3 días.\n\nTA 120/80, afebril, consciente y orientado."
    },
    {
      "resourceType": "ClinicalImpression",
      "id": "diagnostic-impression",
      "status": "completed",
      "code": { "coding": [{ "system": "http://loinc.org", "code": "51848-0" }] },
      "subject": { "reference": "Patient/01936b7c-8d4e-7000-8000-000000004001" },
      "summary": "Cefalea tensional, probable origen postural."
    },
    {
      "resourceType": "CarePlan",
      "id": "care-plan",
      "status": "active",
      "intent": "plan",
      "subject": { "reference": "Patient/01936b7c-8d4e-7000-8000-000000004001" },
      "description": "Control en 1 semana. Higiene postural y analgésico de rescate."
    }
  ]
}

Where each SOAP block lives

Huli concept FHIR equivalent on the Public API
Vital signs Observation with category = vital-signs (see Observation Mapping)
Clinical observations / lab results Observation with category = laboratory
Subjective narrative (S in SOAP) Contained ClinicalImpression#subjective-objective-summary.summary (writable; S then O, separated by a blank line)
Objective narrative (O in SOAP) Contained ClinicalImpression#subjective-objective-summary.summary (writable; S then O, separated by a blank line)
Diagnostic impression (A in SOAP) Contained ClinicalImpression#diagnostic-impression.summary (writable; optional LOINC 51848-0)
Care plan narrative (P in SOAP) Contained CarePlan#care-plan.description (writable)
Orders — medications MedicationRequest resource (see MedicationRequest Mapping)
Orders — studies / labs ServiceRequest resource (see ServiceRequest Mapping)
Custom intake forms Not modelled through FHIR in this IG
Drawings / body-site annotations Not modelled through FHIR in this IG

Fields NOT Mapped (Huli-internal)

Huli concept Reason
Soft-delete status Not exposed; internal lifecycle
Record creation timestamp Not exposed; no standard FHIR path
Search index Not exposed; internal search index