Skip to main content
fi-fhir docs

FHIR Profiles Planning

This document details US Core, Da Vinci, and other FHIR profile requirements for fi-fhir output generation.

Version and accuracy notice (updated 2026-08-09, Slice 5.1a). This document is design background written against US Core 6.1.0. The 1.0 release target is US Core 9.0.0 (.loom/20-product-spec-integration-engine-ide-completion.md:262, docs/operations/SUPPORTED-1.0.md). The 6.1.0 references in the body are annotated in place rather than rewritten, because re-versioning a design document without re-verifying its must-support tables against the 9.0.0 package would replace a visible staleness with an invisible one. That re-verification belongs to Slice 5.1b, which pins the IG.

Two claims corrected by Slice 5.1a:

  • The DiagnosticReport row in the Quick Reference read us-core-diagnosticreport-note against MapLabResult(). MapLabResult stamps us-core-diagnosticreport-**lab**; -note is what MapDiagnosticReportNote() produces. Both rows are now listed, and the checker accepts both (pkg/fhir/profiles_diagnosticreport.go).
  • "Profile metadata injection (Meta.Profile set on all resources)" was false: MapCoverageEligibilityResponse never sets Meta and MapClaim sets it only for pre-authorization. The checklist item is corrected below.

Profile-version assertion policy (Slice 5.1a): the mapper asserts bare canonicals; the checker accepts a bare canonical or any |version-pinned form of it (pkg/fhir/validate.go ProfileCanonical). None of the 32 profile constants is version-pinned, and that is deliberate — see .loom/40-decisions.md (2026-08-09) and docs/operations/SUPPORTED-1.0.md.

For what the shipped mapper and validator actually cover, read FHIR-CONFORMANCE-MATRIX.md, which is written against code with file:line citations and whose numbers are asserted by TestFHIRConformance_CheckerCoverageIsDerivableFromCode.

Quick Reference

ResourceUS Core ProfileStatusImplementation
Patientus-core-patientpkg/fhir/mapper.go:MapPatient()
Encounterus-core-encounterpkg/fhir/mapper.go:MapEncounter()
Observationus-core-observation-labpkg/fhir/mapper.go:MapLabObservation()
DiagnosticReport (lab)us-core-diagnosticreport-labpkg/fhir/mapper.go:MapLabResult()
DiagnosticReport (note)us-core-diagnosticreport-notepkg/fhir/mapper.go:MapDiagnosticReportNote()
Conditionus-core-conditionpkg/fhir/mapper.go:MapCondition()
Coverageus-core-coveragepkg/fhir/mapper.go:MapCoverage()
Claim(Da Vinci PAS)pkg/fhir/mapper.go:MapClaim()
ExplanationOfBenefit(PDex)pkg/fhir/mapper.go:MapExplanationOfBenefit()
CoverageEligibilityResponse(base R4)pkg/fhir/mapper.go:MapCoverageEligibilityResponse()
Procedureus-core-procedurepkg/fhir/mapper.go:MapProcedure()
Immunizationus-core-immunizationpkg/fhir/mapper.go:MapImmunization()
Observation (Vital Signs)us-core-vital-signspkg/fhir/mapper.go:MapVitalSign()
MedicationRequestus-core-medicationrequestpkg/fhir/mapper.go:MapMedicationRequest()
AllergyIntoleranceus-core-allergyintolerancepkg/fhir/mapper.go:MapAllergyIntolerance()
CarePlanus-core-careplanpkg/fhir/mapper.go:MapCarePlan()
Goalus-core-goalpkg/fhir/mapper.go:MapGoal()
CareTeamus-core-careteampkg/fhir/mapper.go:MapCareTeam()
ServiceRequestus-core-servicerequestpkg/fhir/mapper.go:MapServiceRequest()
FeatureStatusImplementation
Transaction bundlespkg/fhir/mapper.go:CreateTransactionBundle()
Profile metadataAuto-injected Meta.Profile
Race/ethnicity extensionsUS Core OMB categories

FHIR Overview

Version Timeline

VersionStatusKey Features
DSTU2LegacyStill in some Epic instances
STU3LegacyTransitional
R4CurrentUS regulatory standard
R4BCurrentMinor updates to R4
R5NewNot yet widely adopted

fi-fhir targets R4 as it's the US regulatory standard (21st Century Cures Act, CMS mandates).

Resource Categories

CategoryResourcesUse Case
ClinicalPatient, Observation, Condition, ProcedureCore clinical data
AdministrativeEncounter, Location, OrganizationVisits, facilities
FinancialClaim, ClaimResponse, CoverageBilling/insurance
WorkflowAppointment, ServiceRequestScheduling, orders
DocumentsDocumentReference, DiagnosticReportReports, attachments

US Core Profile

What is US Core?

US Core is the minimum required FHIR profile for US healthcare interoperability. Mandated by ONC for certified EHRs.

Current version this section was written against: US Core 6.1.0 (based on FHIR R4 4.0.1). The 1.0 release target is US Core 9.0.0; the must-support tables below have not been re-verified against it. See the notice at the top.

US Core Resource Requirements

ResourceMust Support ElementsKey Constraints
Patientidentifier, name, gender, birthDateAt least one identifier required
Observationstatus, category, code, subjectLab results, vitals
ConditionclinicalStatus, code, subjectActive problems
Encounterstatus, class, type, subjectVisit information
DiagnosticReportstatus, category, code, subjectResults summary
DocumentReferencestatus, type, subject, contentClinical documents
Procedurestatus, code, subjectCompleted procedures
MedicationcodeDrug information
MedicationRequeststatus, intent, medication, subjectPrescriptions
Immunizationstatus, vaccineCode, patientVaccine records
AllergyIntoleranceclinicalStatus, code, patientAllergies

US Core Patient Profile

{
  "resourceType": "Patient",
  "id": "example",
  "meta": {
    "profile": ["http://hl7.org/fhir/us/core/StructureDefinition/us-core-patient"]
  },
  "identifier": [
    {
      "system": "http://hospital.example.org/mrn",
      "value": "123456"
    }
  ],
  "name": [
    {
      "family": "Doe",
      "given": ["John", "William"]
    }
  ],
  "gender": "male",
  "birthDate": "1965-03-15",
  "address": [
    {
      "line": ["123 Main St"],
      "city": "Anytown",
      "state": "VA",
      "postalCode": "24101"
    }
  ],
  "extension": [
    {
      "url": "http://hl7.org/fhir/us/core/StructureDefinition/us-core-race",
      "extension": [
        {
          "url": "ombCategory",
          "valueCoding": {
            "system": "urn:oid:2.16.840.1.113883.6.238",
            "code": "2106-3",
            "display": "White"
          }
        }
      ]
    }
  ]
}

US Core Observation (Lab Result)

{
  "resourceType": "Observation",
  "id": "lab-result-example",
  "meta": {
    "profile": ["http://hl7.org/fhir/us/core/StructureDefinition/us-core-observation-lab"]
  },
  "status": "final",
  "category": [
    {
      "coding": [
        {
          "system": "http://terminology.hl7.org/CodeSystem/observation-category",
          "code": "laboratory"
        }
      ]
    }
  ],
  "code": {
    "coding": [
      {
        "system": "http://loinc.org",
        "code": "6690-2",
        "display": "Leukocytes [#/volume] in Blood"
      }
    ]
  },
  "subject": {
    "reference": "Patient/example"
  },
  "effectiveDateTime": "2024-01-15T14:25:00Z",
  "valueQuantity": {
    "value": 12.5,
    "unit": "10*3/uL",
    "system": "http://unitsofmeasure.org",
    "code": "10*3/uL"
  },
  "interpretation": [
    {
      "coding": [
        {
          "system": "http://terminology.hl7.org/CodeSystem/v3-ObservationInterpretation",
          "code": "H",
          "display": "High"
        }
      ]
    }
  ],
  "referenceRange": [
    {
      "low": {"value": 4.5, "unit": "10*3/uL"},
      "high": {"value": 11.0, "unit": "10*3/uL"}
    }
  ]
}

Da Vinci Implementation Guides

Da Vinci Overview

Da Vinci is a set of FHIR implementation guides for payer-provider data exchange:

IGPurposeStatus
PDex (Payer Data Exchange)Share claims data with patientsSTU 2.0
CDex (Clinical Data Exchange)Request clinical data from providersSTU 2.0
PAS (Prior Authorization Support)Automate prior authSTU 2.0
DTR (Documentation Templates & Rules)Smart forms for PASTU 2.0
CRD (Coverage Requirements Discovery)Check coverage at order timeSTU 2.0
ATR (Member Attribution)Attribute patients to providersSTU 1.0
PCDE (Payer Coverage Decision Exchange)Coverage decisionsDraft

CMS Mandates Using Da Vinci

January 2026 Deadline (CMS-0057-F):

  • Medicare Advantage plans must implement:
    • Patient Access API (PDex)
    • Prior Authorization API (PAS)
    • Provider Directory API
  • Electronic prior auth decisions within 72 hours (urgent: 24 hours)

Da Vinci PAS (Prior Authorization)

Key resources:

  • Claim with PAS profile for auth requests
  • ClaimResponse for decisions
  • Task for async workflow
{
  "resourceType": "Claim",
  "id": "prior-auth-request",
  "meta": {
    "profile": ["http://hl7.org/fhir/us/davinci-pas/StructureDefinition/profile-claim"]
  },
  "status": "active",
  "type": {
    "coding": [
      {
        "system": "http://terminology.hl7.org/CodeSystem/claim-type",
        "code": "professional"
      }
    ]
  },
  "use": "preauthorization",
  "patient": {
    "reference": "Patient/example"
  },
  "provider": {
    "reference": "Organization/requesting-provider"
  },
  "insurer": {
    "reference": "Organization/payer"
  },
  "item": [
    {
      "sequence": 1,
      "productOrService": {
        "coding": [
          {
            "system": "http://www.ama-assn.org/go/cpt",
            "code": "27447",
            "display": "Total knee replacement"
          }
        ]
      },
      "servicedDate": "2024-02-15"
    }
  ]
}

Terminology Bindings

Required Code Systems

ElementCode SystemBinding Strength
Patient.genderAdministrativeGenderRequired
Observation.statusObservationStatusRequired
Observation.categoryObservationCategoryPreferred
Observation.codeLOINCExtensible
Condition.codeSNOMED CT / ICD-10Extensible
Procedure.codeSNOMED CT / CPTExtensible
Medication.codeRxNormExtensible

Binding Strength Meanings

StrengthMeaning
RequiredMust use code from value set
ExtensibleMust use if code exists, can extend
PreferredShould use, but alternatives allowed
ExampleJust suggestions

fi-fhir FHIR Generation Strategy

Canonical Event → FHIR Mapping

// Map semantic event to FHIR resources
type FHIRMapper interface {
    MapPatient(p *events.Patient) *fhir.Patient
    MapEncounter(e *events.Encounter, patientRef string) *fhir.Encounter
    MapObservation(lab *events.LabResultEvent) *fhir.Observation
    MapClaim(claim *events.ClaimEvent) *fhir.Claim
}

// US Core compliant mapper
type USCoreMapper struct {
    profile string // "http://hl7.org/fhir/us/core/StructureDefinition/..."
}

func (m *USCoreMapper) MapPatient(p *events.Patient) *fhir.Patient {
    patient := &fhir.Patient{
        Meta: &fhir.Meta{
            Profile: []string{m.profile + "us-core-patient"},
        },
        Identifier: m.mapIdentifiers(p.Identifiers),
        Name: []fhir.HumanName{
            {
                Family: p.FamilyName,
                Given:  []string{p.GivenName},
            },
        },
        Gender: m.mapGender(p.Gender),
        BirthDate: m.formatDate(p.DateOfBirth),
    }

    // Add US Core extensions
    if p.Race != "" {
        patient.Extension = append(patient.Extension,
            m.buildRaceExtension(p.Race))
    }

    return patient
}

Profile Validation

// Validate resource against profile
type ProfileValidator struct {
    profiles map[string]*StructureDefinition
}

func (v *ProfileValidator) Validate(resource interface{}, profileURL string) []ValidationError {
    profile := v.profiles[profileURL]
    if profile == nil {
        return []ValidationError{{Message: "Unknown profile: " + profileURL}}
    }

    var errors []ValidationError

    // Check required elements
    for _, element := range profile.MustSupport {
        if !hasElement(resource, element.Path) {
            errors = append(errors, ValidationError{
                Path:    element.Path,
                Message: "Missing must-support element",
            })
        }
    }

    // Check terminology bindings
    for _, binding := range profile.Bindings {
        if !validCode(resource, binding) {
            errors = append(errors, ValidationError{
                Path:    binding.Path,
                Message: "Invalid code for binding",
            })
        }
    }

    return errors
}

Bundle Generation

Transaction Bundle (for writes)

func CreateTransactionBundle(resources []interface{}) *fhir.Bundle {
    bundle := &fhir.Bundle{
        Type: "transaction",
        Entry: make([]fhir.BundleEntry, len(resources)),
    }

    for i, resource := range resources {
        bundle.Entry[i] = fhir.BundleEntry{
            Resource: resource,
            Request: &fhir.BundleEntryRequest{
                Method: "POST",
                URL:    getResourceType(resource),
            },
        }
    }

    return bundle
}

Searchset Bundle (for reads)

func CreateSearchBundle(resources []interface{}, total int) *fhir.Bundle {
    bundle := &fhir.Bundle{
        Type:  "searchset",
        Total: total,
        Entry: make([]fhir.BundleEntry, len(resources)),
    }

    for i, resource := range resources {
        bundle.Entry[i] = fhir.BundleEntry{
            Resource: resource,
            Search: &fhir.BundleEntrySearch{
                Mode: "match",
            },
        }
    }

    return bundle
}

Profile Registry

Supported Profiles

# fi-fhir profile support configuration
profiles:
  us_core:
    version: "6.1.0" # design sketch; the 1.0 target is 9.0.0 (see the notice at the top)
    base_url: "http://hl7.org/fhir/us/core/StructureDefinition"
    resources:
      - Patient: us-core-patient
      - Observation: us-core-observation-lab
      - Condition: us-core-condition-problems-health-concerns
      - Encounter: us-core-encounter
      - DiagnosticReport: us-core-diagnosticreport-lab

  davinci_pas:
    version: "2.0.0"
    base_url: "http://hl7.org/fhir/us/davinci-pas/StructureDefinition"
    resources:
      - Claim: profile-claim
      - ClaimResponse: profile-claimresponse

  davinci_pdex:
    version: "2.0.0"
    base_url: "http://hl7.org/fhir/us/davinci-pdex/StructureDefinition"
    resources:
      - ExplanationOfBenefit: pdex-explanationofbenefit

Implementation Plan

Phase 1: Core FHIR Types ✅

  • FHIR R4 base types in Go - see pkg/fhir/types.go
  • JSON serialization with MarshalJSON methods
  • Reference handling with typed Reference struct
  • Standard URIs and code systems defined (LOINC, SNOMED, ICD-10, etc.)

Phase 2: US Core Mapping ✅

  • Patient (with race/ethnicity OMB extensions) - see pkg/fhir/mapper.go:MapPatient()
  • Observation (lab results) - see pkg/fhir/mapper.go:MapLabObservation()
  • Encounter (with participants, hospitalization, location) - see pkg/fhir/mapper.go:MapEncounter()
  • DiagnosticReport (for lab panels) - see pkg/fhir/mapper.go:MapLabResult()
  • Condition (for problems/diagnoses) - see pkg/fhir/mapper.go:MapCondition()
  • Coverage (from 271 eligibility responses) - see pkg/fhir/mapper.go:MapCoverage()

Phase 3: Validation ⚠️

  • Profile metadata injection — Meta.Profile on every resource whose type the checker has a profile-presence check for (21 of the 24 produced types). Not on all resources: MapCoverageEligibilityResponse never sets Meta, and MapClaim sets it only for pre-authorization. Those two, plus MapExplanationOfBenefit, are the three produced types with neither a profile-presence nor a required-element check, which is asserted by TestFHIRConformance_CheckerCoverageIsDerivableFromCode.
  • Basic terminology system mapping (identifier type codes to URIs)
  • Built-in validator (OperationOutcome) + CLI/workflow integration (pkg/fhir/validate.go, fi-fhir fhir validate, workflow fhir action validate_fhir)
  • Full must-support element validation (beyond current “US Core-ish” checks) — #3
  • Terminology binding strength validation — #3
  • External FHIR Validator integration (optional, for deep IG conformance) — #3

Phase 4: Da Vinci Support ✅

  • PAS Claim/ClaimResponse (for 837P → FHIR) - see pkg/fhir/mapper.go:MapClaim()
  • PDex ExplanationOfBenefit (for 835 → FHIR) - see pkg/fhir/mapper.go:MapExplanationOfBenefit()
  • Coverage resource (from 271 eligibility responses) - see pkg/fhir/mapper.go:MapCoverage()
  • CoverageEligibilityResponse (FHIR equivalent of 271) - see pkg/fhir/mapper.go:MapCoverageEligibilityResponse()

Phase 5: Bundle Operations ✅

  • Transaction bundles - see pkg/fhir/mapper.go:CreateTransactionBundle()
  • Searchset bundles - see pkg/fhir/mapper.go:CreateSearchsetBundle()
  • Batch bundles — #3
  • Document bundles (if needed) — #3

Testing Strategy

Validation Testing

fi-fhir includes a built-in validator (pkg/fhir/validate.go) that produces a FHIR OperationOutcome:

  • mode=us-core: lightweight “US Core-ish” checks (required fields + profile presence warnings)
  • mode=none: structural-only (valid JSON + resourceType, plus Bundle traversal)

CLI usage (fails on warnings by default; opt out with --allow-warnings):

fi-fhir fhir validate --mode us-core patient.json
fi-fhir fhir validate --mode us-core --allow-warnings patient.json
fi-fhir fhir validate --mode none bundle.json

Workflow usage (opt-in validation before sending to the FHIR server):

actions:
  - type: fhir
    endpoint: https://fhir.example.com/fhir
    validate_fhir: "true"
    validate_mode: us-core   # or none
    allow_warnings: "false"  # default

Failure Policy

  • Errors: always fail validation.
  • Warnings:
    • CLI fi-fhir fhir validate: fail by default; use --allow-warnings to allow warning-only payloads.
    • Workflow fhir action: validation is opt-in (validate_fhir: "true"); when enabled, warnings fail by default unless allow_warnings: "true".
    • Library callers: ValidateJSON always returns an OperationOutcome; the caller decides how to treat warnings (CI should usually fail on warnings).

External Profile Conformance (Optional)

For deep IG conformance (terminology bindings, slicing, invariants), use the HL7 FHIR Validator CLI in CI or locally:

# Slice 5.1b, not shipped. The IG must be a pinned, digest-recorded, offline
# .tgz — a conformance gate that silently re-resolves its own IG is not a gate —
# and validator_cli.jar stays CI-only: the shipped image is distroless static
# with no JRE. Both are ratified in .loom/40-decisions.md (2026-08-09).
# Pin the 1.0 target version, not the 6.1.0 this document was drafted against.
java -jar validator_cli.jar patient.json \
  -ig hl7.fhir.us.core#9.0.0 \
  -profile http://hl7.org/fhir/us/core/StructureDefinition/us-core-patient

See Also

References

FHIR Profiles Planning | fi-fhir docs