From 2679f641589e225e5c8dfa0d27e8c87b9731b5e7 Mon Sep 17 00:00:00 2001 From: aacruzgon Date: Thu, 5 Mar 2026 18:37:13 -0500 Subject: [PATCH] S3 + ELASTIC --- Cargo.lock | 1 + README.md | 25 +- .../R6/Requirements-example1(example1).xml | 4 + .../tests/data/xml/R6/account.profile.xml | 92 +- .../xml/R6/activitydefinition.profile.xml | 150 +- .../data/xml/R6/actordefinition.profile.xml | 56 +- .../tests/data/xml/R6/address.profile.xml | 24 +- ...administrableproductdefinition.profile.xml | 76 +- .../data/xml/R6/adverseevent.profile.xml | 78 +- crates/fhir/tests/data/xml/R6/age.profile.xml | 4 +- .../xml/R6/allergyintolerance.profile.xml | 62 +- .../tests/data/xml/R6/annotation.profile.xml | 14 +- .../tests/data/xml/R6/appointment.profile.xml | 130 +- .../xml/R6/appointmentresponse.profile.xml | 30 +- .../xml/R6/artifactassessment.profile.xml | 74 +- .../tests/data/xml/R6/attachment.profile.xml | 30 +- .../tests/data/xml/R6/auditevent.profile.xml | 114 +- .../data/xml/R6/availability.profile.xml | 22 +- .../data/xml/R6/backboneelement.profile.xml | 6 +- .../data/xml/R6/backbonetype.profile.xml | 6 +- .../fhir/tests/data/xml/R6/base.profile.xml | 4 +- .../data/xml/R6/base64binary.profile.xml | 2 +- .../fhir/tests/data/xml/R6/basic.profile.xml | 16 +- .../data/xml/R6/batch-bundle.profile.xml | 2 +- .../xml/R6/batch-response-bundle.profile.xml | 2 +- .../fhir/tests/data/xml/R6/binary.profile.xml | 12 +- .../R6/biologicallyderivedproduct.profile.xml | 68 +- crates/fhir/tests/data/xml/R6/bmi.profile.xml | 11 +- .../tests/data/xml/R6/bodyheight.profile.xml | 11 +- .../data/xml/R6/bodystructure.profile.xml | 46 +- .../tests/data/xml/R6/bodytemp.profile.xml | 11 +- .../tests/data/xml/R6/bodyweight.profile.xml | 11 +- .../tests/data/xml/R6/boolean.profile.xml | 2 +- crates/fhir/tests/data/xml/R6/bp.profile.xml | 17 +- ...ex(bundle-request-transaction-complex).xml | 2 +- ...x(bundle-response-transaction-complex).xml | 2 +- .../fhir/tests/data/xml/R6/bundle.profile.xml | 64 +- .../tests/data/xml/R6/canonical.profile.xml | 2 +- .../data/xml/R6/canonicalresource.profile.xml | 46 +- .../data/xml/R6/capabilitystatement-base.xml | 56 +- .../data/xml/R6/capabilitystatement-base2.xml | 4 +- .../xml/R6/capabilitystatement.profile.xml | 190 +- .../tests/data/xml/R6/careplan.profile.xml | 54 +- .../tests/data/xml/R6/careteam.profile.xml | 42 +- .../fhir/tests/data/xml/R6/claim.profile.xml | 298 +- .../data/xml/R6/claimresponse.profile.xml | 320 +- .../xml/R6/clinicalusedefinition.profile.xml | 100 +- .../fhir/tests/data/xml/R6/code.profile.xml | 2 +- .../data/xml/R6/codeableconcept.profile.xml | 8 +- .../data/xml/R6/codeablereference.profile.xml | 8 +- .../tests/data/xml/R6/codesystem.profile.xml | 140 +- .../fhir/tests/data/xml/R6/coding.profile.xml | 14 +- .../data/xml/R6/communication.profile.xml | 56 +- .../xml/R6/communicationrequest.profile.xml | 66 +- .../xml/R6/compartmentdefinition-device.xml | 286 +- .../R6/compartmentdefinition-encounter.xml | 286 +- .../xml/R6/compartmentdefinition-group.xml | 286 +- .../xml/R6/compartmentdefinition-patient.xml | 286 +- .../R6/compartmentdefinition-practitioner.xml | 286 +- .../compartmentdefinition-relatedperson.xml | 286 +- .../xml/R6/compartmentdefinition.profile.xml | 50 +- .../tests/data/xml/R6/composition.profile.xml | 112 +- .../tests/data/xml/R6/conceptmap-103(103).xml | 4 +- .../data/xml/R6/conceptmap-example(101).xml | 4 +- ...map-example-metadata(example-metadata).xml | 4 +- ...example-metadata-2(example-metadata-2).xml | 4 +- .../conceptmap-example-specimen-type(102).xml | 8 +- .../tests/data/xml/R6/conceptmap.profile.xml | 184 +- crates/fhir/tests/data/xml/R6/conceptmaps.xml | 754 +-- .../tests/data/xml/R6/condition.profile.xml | 68 +- .../tests/data/xml/R6/consent.profile.xml | 90 +- .../data/xml/R6/contactdetail.profile.xml | 8 +- .../data/xml/R6/contactpoint.profile.xml | 14 +- .../tests/data/xml/R6/contract.profile.xml | 324 +- .../fhir/tests/data/xml/R6/count.profile.xml | 4 +- .../tests/data/xml/R6/coverage.profile.xml | 80 +- .../R6/coverageeligibilityrequest.profile.xml | 88 +- .../coverageeligibilityresponse.profile.xml | 110 +- .../fhir/tests/data/xml/R6/dataelements.xml | 1320 ++--- .../data/xml/R6/datarequirement.profile.xml | 64 +- .../tests/data/xml/R6/datatype.profile.xml | 4 +- .../fhir/tests/data/xml/R6/date.profile.xml | 2 +- .../tests/data/xml/R6/datetime.profile.xml | 2 +- .../tests/data/xml/R6/decimal.profile.xml | 6 +- .../data/xml/R6/detectedissue.profile.xml | 62 +- .../fhir/tests/data/xml/R6/device.profile.xml | 112 +- .../tests/data/xml/R6/devicealert.profile.xml | 64 +- .../data/xml/R6/deviceassociation.profile.xml | 26 +- .../data/xml/R6/devicedefinition.profile.xml | 988 ++-- .../data/xml/R6/devicemetric.profile.xml | 34 +- .../data/xml/R6/devicerequest.profile.xml | 82 +- .../data/xml/R6/diagnosticreport.profile.xml | 70 +- .../tests/data/xml/R6/distance.profile.xml | 4 +- .../data/xml/R6/document-bundle.profile.xml | 2 +- .../data/xml/R6/documentreference.profile.xml | 80 +- .../data/xml/R6/domainresource.profile.xml | 14 +- .../fhir/tests/data/xml/R6/dosage.profile.xml | 50 +- .../data/xml/R6/dosagecondition.profile.xml | 14 +- .../data/xml/R6/dosagedetails.profile.xml | 22 +- .../data/xml/R6/dosagesafety.profile.xml | 22 +- .../tests/data/xml/R6/duration.profile.xml | 4 +- .../tests/data/xml/R6/element.profile.xml | 8 +- .../data/xml/R6/elementdefinition.profile.xml | 192 +- .../tests/data/xml/R6/encounter.profile.xml | 110 +- .../tests/data/xml/R6/endpoint.profile.xml | 40 +- .../data/xml/R6/enrollmentrequest.profile.xml | 20 +- .../xml/R6/enrollmentresponse.profile.xml | 24 +- .../data/xml/R6/episodeofcare.profile.xml | 44 +- .../data/xml/R6/eventdefinition.profile.xml | 76 +- .../tests/data/xml/R6/evidence.profile.xml | 208 +- .../data/xml/R6/evidencevariable.profile.xml | 174 +- .../data/xml/R6/examplescenario.profile.xml | 142 +- .../xml/R6/explanationofbenefit.profile.xml | 542 +- .../tests/data/xml/R6/expression.profile.xml | 14 +- .../xml/R6/extendedcontactdetail.profile.xml | 18 +- .../tests/data/xml/R6/extension.profile.xml | 8 +- .../tests/data/xml/R6/external-resources.xml | 2 +- .../xml/R6/familymemberhistory.profile.xml | 104 +- .../fhir/tests/data/xml/R6/flag.profile.xml | 24 +- .../fhir/tests/data/xml/R6/goal.profile.xml | 74 +- .../fhir/tests/data/xml/R6/group.profile.xml | 116 +- .../data/xml/R6/guidanceresponse.profile.xml | 42 +- .../tests/data/xml/R6/headcircum.profile.xml | 11 +- .../data/xml/R6/healthcareservice.profile.xml | 72 +- .../tests/data/xml/R6/heartrate.profile.xml | 11 +- .../data/xml/R6/history-bundle.profile.xml | 2 +- .../tests/data/xml/R6/humanname.profile.xml | 18 +- crates/fhir/tests/data/xml/R6/id.profile.xml | 2 +- .../tests/data/xml/R6/identifier.profile.xml | 16 +- .../data/xml/R6/imagingselection.profile.xml | 76 +- .../data/xml/R6/imagingstudy.profile.xml | 74 +- .../data/xml/R6/immunization.profile.xml | 96 +- .../xml/R6/implementationguide.profile.xml | 150 +- .../tests/data/xml/R6/ingredient.profile.xml | 80 +- .../tests/data/xml/R6/instant.profile.xml | 2 +- .../data/xml/R6/insuranceplan.profile.xml | 44 +- .../data/xml/R6/insuranceproduct.profile.xml | 56 +- .../tests/data/xml/R6/integer.profile.xml | 2 +- .../tests/data/xml/R6/integer64.profile.xml | 2 +- .../tests/data/xml/R6/invoice.profile.xml | 64 +- .../tests/data/xml/R6/library.profile.xml | 84 +- .../fhir/tests/data/xml/R6/list.profile.xml | 40 +- .../tests/data/xml/R6/location.profile.xml | 54 +- .../R6/manufactureditemdefinition.profile.xml | 66 +- .../tests/data/xml/R6/markdown.profile.xml | 2 +- .../data/xml/R6/marketingstatus.profile.xml | 14 +- .../tests/data/xml/R6/measure.profile.xml | 220 +- .../data/xml/R6/measurereport.profile.xml | 186 +- .../tests/data/xml/R6/medication.profile.xml | 50 +- .../R6/medicationadministration.profile.xml | 74 +- .../xml/R6/medicationdispense.profile.xml | 80 +- .../data/xml/R6/medicationrequest.profile.xml | 112 +- .../xml/R6/medicationstatement.profile.xml | 50 +- .../R6/medicinalproductdefinition.profile.xml | 120 +- .../data/xml/R6/messagedefinition.profile.xml | 78 +- .../data/xml/R6/messageheader.profile.xml | 58 +- .../fhir/tests/data/xml/R6/meta.profile.xml | 16 +- .../data/xml/R6/metadataresource.profile.xml | 26 +- .../data/xml/R6/monetarycomponent.profile.xml | 12 +- .../fhir/tests/data/xml/R6/money.profile.xml | 8 +- .../data/xml/R6/moneyquantity.profile.xml | 2 +- .../data/xml/R6/namingsystem.profile.xml | 86 +- .../tests/data/xml/R6/narrative.profile.xml | 8 +- .../data/xml/R6/nutritionintake.profile.xml | 84 +- .../data/xml/R6/nutritionorder.profile.xml | 136 +- .../data/xml/R6/nutritionproduct.profile.xml | 76 +- .../tests/data/xml/R6/observation.profile.xml | 565 +- .../xml/R6/observationdefinition.profile.xml | 124 +- crates/fhir/tests/data/xml/R6/oid.profile.xml | 2 +- .../R6/operation-activitydefinition-apply.xml | 2 +- ...n-activitydefinition-data-requirements.xml | 2 +- ...on-canonicalresource-current-canonical.xml | 2 +- ...operation-capabilitystatement-versions.xml | 2 +- .../data/xml/R6/operation-claim-submit.xml | 2 +- .../xml/R6/operation-codesystem-lookup.xml | 2 +- .../xml/R6/operation-codesystem-subsumes.xml | 2 +- .../R6/operation-codesystem-validate-code.xml | 2 +- .../xml/R6/operation-composition-document.xml | 2 +- .../xml/R6/operation-conceptmap-translate.xml | 2 +- ...tion-coverageeligibilityrequest-submit.xml | 2 +- .../R6/operation-documentreference-docref.xml | 2 +- .../xml/R6/operation-group-everything.xml | 2 +- .../data/xml/R6/operation-group-purge.xml | 2 +- .../operation-library-data-requirements.xml | 2 +- .../xml/R6/operation-measure-care-gaps.xml | 2 +- .../xml/R6/operation-measure-collect-data.xml | 2 +- .../operation-measure-data-requirements.xml | 2 +- .../R6/operation-measure-evaluate-measure.xml | 2 +- .../xml/R6/operation-measure-evaluate.xml | 4 +- .../xml/R6/operation-measure-submit-data.xml | 2 +- ...-medicinalproductdefinition-everything.xml | 2 +- ...peration-messageheader-process-message.xml | 2 +- .../operation-namingsystem-preferred-id.xml | 2 +- .../operation-namingsystem-translate-id.xml | 2 +- .../xml/R6/operation-observation-lastn.xml | 2 +- .../xml/R6/operation-observation-stats.xml | 2 +- .../data/xml/R6/operation-patient-match.xml | 2 +- .../data/xml/R6/operation-patient-purge.xml | 2 +- .../xml/R6/operation-plandefinition-apply.xml | 2 +- ...ation-plandefinition-data-requirements.xml | 2 +- .../xml/R6/operation-resource-convert.xml | 2 +- .../xml/R6/operation-resource-graphql.xml | 2 +- .../xml/R6/operation-resource-validate.xml | 4 +- ...operation-structuredefinition-snapshot.xml | 6 +- .../R6/operation-structuremap-transform.xml | 2 +- .../xml/R6/operation-subscription-events.xml | 2 +- .../xml/R6/operation-subscription-status.xml | 2 +- .../data/xml/R6/operation-valueset-expand.xml | 2 +- .../R6/operation-valueset-validate-code.xml | 2 +- .../xml/R6/operationdefinition.profile.xml | 112 +- .../data/xml/R6/operationoutcome.profile.xml | 20 +- .../data/xml/R6/organization.profile.xml | 36 +- .../R6/organizationaffiliation.profile.xml | 30 +- .../tests/data/xml/R6/oxygensat.profile.xml | 11 +- .../R6/packagedproductdefinition.profile.xml | 82 +- .../xml/R6/parameterdefinition.profile.xml | 18 +- .../tests/data/xml/R6/parameters.profile.xml | 16 +- .../tests/data/xml/R6/patient.profile.xml | 76 +- .../data/xml/R6/paymentnotice.profile.xml | 32 +- .../xml/R6/paymentreconciliation.profile.xml | 110 +- .../fhir/tests/data/xml/R6/period.profile.xml | 8 +- .../fhir/tests/data/xml/R6/person.profile.xml | 44 +- .../data/xml/R6/plandefinition.profile.xml | 272 +- .../tests/data/xml/R6/positiveint.profile.xml | 2 +- .../data/xml/R6/practitioner.profile.xml | 48 +- .../data/xml/R6/practitionerrole.profile.xml | 38 +- .../data/xml/R6/primitivetype.profile.xml | 4 +- .../tests/data/xml/R6/procedure.profile.xml | 88 +- .../data/xml/R6/productshelflife.profile.xml | 14 +- .../tests/data/xml/R6/profiles-others.xml | 141 +- .../tests/data/xml/R6/provenance.profile.xml | 54 +- .../tests/data/xml/R6/quantity.profile.xml | 14 +- .../data/xml/R6/questionnaire.profile.xml | 176 +- .../xml/R6/questionnaireresponse.profile.xml | 66 +- .../fhir/tests/data/xml/R6/range.profile.xml | 8 +- .../fhir/tests/data/xml/R6/ratio.profile.xml | 8 +- .../tests/data/xml/R6/ratiorange.profile.xml | 10 +- .../tests/data/xml/R6/reference.profile.xml | 12 +- .../xml/R6/regulatedauthorization.profile.xml | 52 +- .../data/xml/R6/relatedartifact.profile.xml | 28 +- .../data/xml/R6/relatedperson.profile.xml | 38 +- .../data/xml/R6/relativetime.profile.xml | 20 +- .../xml/R6/requestorchestration.profile.xml | 168 +- .../data/xml/R6/requirements.profile.xml | 572 +- .../data/xml/R6/researchstudy.profile.xml | 180 +- .../data/xml/R6/researchsubject.profile.xml | 46 +- .../tests/data/xml/R6/resource.profile.xml | 14 +- .../tests/data/xml/R6/resprate.profile.xml | 11 +- .../data/xml/R6/riskassessment.profile.xml | 64 +- .../tests/data/xml/R6/sampleddata.profile.xml | 24 +- ...c-valueset-allergyintolerance-clinical.xml | 2 +- ...lueset-allergyintolerance-verification.xml | 2 +- .../xml/R6/sc-valueset-condition-clinical.xml | 2 +- .../R6/sc-valueset-condition-ver-status.xml | 2 +- .../sc-valueset-document-reference-status.xml | 2 +- .../data/xml/R6/sc-valueset-event-status.xml | 2 +- .../xml/R6/sc-valueset-goal-achievement.xml | 2 +- .../xml/R6/sc-valueset-publication-status.xml | 2 +- .../xml/R6/sc-valueset-request-status.xml | 2 +- .../tests/data/xml/R6/schedule.profile.xml | 24 +- .../tests/data/xml/R6/search-parameters.xml | 2876 +++++----- .../data/xml/R6/search-set-bundle.profile.xml | 2 +- .../data/xml/R6/searchparameter.profile.xml | 86 +- .../data/xml/R6/servicerequest.profile.xml | 118 +- .../tests/data/xml/R6/signature.profile.xml | 18 +- .../data/xml/R6/simplequantity.profile.xml | 2 +- .../fhir/tests/data/xml/R6/slot.profile.xml | 30 +- .../tests/data/xml/R6/specimen.profile.xml | 383 +- .../xml/R6/specimendefinition.profile.xml | 132 +- .../fhir/tests/data/xml/R6/string.profile.xml | 2 +- .../xml/R6/structuredefinition.profile.xml | 86 +- .../data/xml/R6/structuremap.profile.xml | 156 +- ...bscription-notification-bundle.profile.xml | 2 +- .../data/xml/R6/subscription.profile.xml | 58 +- .../xml/R6/subscriptionstatus.profile.xml | 42 +- .../data/xml/R6/subscriptiontopic.profile.xml | 108 +- .../tests/data/xml/R6/substance.profile.xml | 20 +- .../xml/R6/substancedefinition.profile.xml | 192 +- .../fhir/tests/data/xml/R6/task.profile.xml | 92 +- .../R6/terminologycapabilities.profile.xml | 122 +- .../fhir/tests/data/xml/R6/time.profile.xml | 2 +- .../fhir/tests/data/xml/R6/timing.profile.xml | 50 +- .../xml/R6/transaction-bundle.profile.xml | 2 +- .../transaction-response-bundle.profile.xml | 2 +- .../data/xml/R6/triggerdefinition.profile.xml | 24 +- .../tests/data/xml/R6/unsignedint.profile.xml | 2 +- crates/fhir/tests/data/xml/R6/uri.profile.xml | 2 +- crates/fhir/tests/data/xml/R6/url.profile.xml | 2 +- .../data/xml/R6/usagecontext.profile.xml | 18 +- .../fhir/tests/data/xml/R6/uuid.profile.xml | 2 +- ...ueset-example-cpt-all(example-cpt-all).xml | 2 +- .../valueset-example-inactive(inactive).xml | 10 +- ...t-example-yesnodontknow(yesnodontknow).xml | 6 +- .../R6/valueset-ucum-common(ucum-common).xml | 2 +- .../tests/data/xml/R6/valueset.profile.xml | 206 +- crates/fhir/tests/data/xml/R6/valuesets.xml | 4604 +++++++++-------- .../xml/R6/virtualservicedetail.profile.xml | 22 +- .../xml/R6/visionprescription.profile.xml | 60 +- .../tests/data/xml/R6/vitalsigns.profile.xml | 9 +- .../tests/data/xml/R6/vitalspanel.profile.xml | 9 +- .../fhir/tests/data/xml/R6/xhtml.profile.xml | 2 +- crates/hfs/Cargo.toml | 1 + crates/hfs/src/main.rs | 571 +- crates/persistence/README.md | 92 +- .../docs/s3-elasticsearch/IMPLEMENTATION.md | 134 + .../persistence/docs/s3-elasticsearch/M1.md | 61 + .../persistence/docs/s3-elasticsearch/M2.md | 53 + .../persistence/docs/s3-elasticsearch/M3.md | 45 + .../persistence/docs/s3-elasticsearch/M4.md | 37 + .../S3+ELASTIC-ImplementationPlan.md | 129 + .../elasticsearch/Documents/discussion.md | 985 ++++ .../src/backends/elasticsearch/backend.rs | 33 +- .../src/backends/elasticsearch/storage.rs | 124 +- crates/persistence/src/backends/s3/mod.rs | 4 + .../persistence/src/backends/s3/reindex_es.rs | 248 + crates/persistence/src/composite/storage.rs | 110 +- crates/persistence/src/composite/sync.rs | 246 +- .../tests/composite_s3_elasticsearch_tests.rs | 229 + .../persistence/tests/elasticsearch_tests.rs | 100 +- .../tests/minio_s3_elasticsearch_tests.rs | 456 ++ crates/rest/src/config.rs | 31 +- 321 files changed, 16982 insertions(+), 13723 deletions(-) create mode 100644 crates/persistence/docs/s3-elasticsearch/IMPLEMENTATION.md create mode 100644 crates/persistence/docs/s3-elasticsearch/M1.md create mode 100644 crates/persistence/docs/s3-elasticsearch/M2.md create mode 100644 crates/persistence/docs/s3-elasticsearch/M3.md create mode 100644 crates/persistence/docs/s3-elasticsearch/M4.md create mode 100644 crates/persistence/src/backends/elasticsearch/Documents/S3+ELASTIC-ImplementationPlan.md create mode 100644 crates/persistence/src/backends/elasticsearch/Documents/discussion.md create mode 100644 crates/persistence/src/backends/s3/reindex_es.rs create mode 100644 crates/persistence/tests/composite_s3_elasticsearch_tests.rs create mode 100644 crates/persistence/tests/minio_s3_elasticsearch_tests.rs diff --git a/Cargo.lock b/Cargo.lock index c9e6c27a5..686e02b85 100644 --- a/Cargo.lock +++ b/Cargo.lock @@ -2798,6 +2798,7 @@ dependencies = [ "helios-persistence", "helios-rest", "openssl", + "parking_lot", "reqwest", "tokio", "tracing", diff --git a/README.md b/README.md index 7a337a79b..18be22339 100644 --- a/README.md +++ b/README.md @@ -172,6 +172,7 @@ The Helios FHIR Server supports multiple storage backend configurations. Choose | **PostgreSQL** | Built-in full-text search (tsvector/tsquery) | Production OLTP deployments | | **PostgreSQL + Elasticsearch** | Elasticsearch-powered search with PostgreSQL CRUD | Production deployments needing RDBMS + robust search | | **S3** | Object storage for CRUD, versioning, history, and bulk operations (no search) | Archival, bulk analytics, cost-effective storage | +| **S3 + Elasticsearch** | Elasticsearch-powered search with S3 object storage as canonical source | Object-storage-first deployments needing robust FHIR search | ### Running the Server @@ -202,13 +203,23 @@ HFS_S3_BUCKET=my-fhir-bucket \ AWS_PROFILE=your-aws-profile \ AWS_REGION=us-east-1 \ ./hfs + +# S3 + Elasticsearch (S3 is canonical, Elasticsearch handles all search) +HFS_STORAGE_BACKEND=s3-elasticsearch \ +HFS_ELASTICSEARCH_NODES=http://localhost:9200 \ +HFS_S3_TENANCY_MODE=prefix-per-tenant \ +HFS_S3_BUCKET=hfs \ +HFS_S3_ENDPOINT_URL=http://localhost:9000 \ +HFS_S3_ALLOW_HTTP=true \ +HFS_S3_FORCE_PATH_STYLE=true \ + ./hfs ``` ### Environment Variables | Variable | Default | Description | |---|---|---| -| `HFS_STORAGE_BACKEND` | `sqlite` | Backend mode: `sqlite`, `sqlite-elasticsearch`, `postgres`, `postgres-elasticsearch`, or `s3` | +| `HFS_STORAGE_BACKEND` | `sqlite` | Backend mode: `sqlite`, `sqlite-elasticsearch`, `postgres`, `postgres-elasticsearch`, `s3`, or `s3-elasticsearch` | | `HFS_SERVER_PORT` | `8080` | Server port | | `HFS_SERVER_HOST` | `127.0.0.1` | Host to bind | | `HFS_DATABASE_URL` | `fhir.db` | Database URL (SQLite path or PostgreSQL connection string) | @@ -219,8 +230,19 @@ AWS_REGION=us-east-1 \ | `HFS_ELASTICSEARCH_USERNAME` | *(none)* | ES basic auth username | | `HFS_ELASTICSEARCH_PASSWORD` | *(none)* | ES basic auth password | | `HFS_S3_BUCKET` | `hfs` | S3 bucket name (prefix-per-tenant mode) | +| `HFS_S3_TENANCY_MODE` | `prefix-per-tenant` | S3 tenant isolation mode (`prefix-per-tenant` or `bucket-per-tenant`) | +| `HFS_S3_TENANT_BUCKET_MAP` | *(none)* | Per-tenant bucket mapping (`tenant=bucket,tenant2=bucket2`) for bucket-per-tenant mode | +| `HFS_S3_DEFAULT_SYSTEM_BUCKET` | *(none)* | Optional fallback bucket for non-tenant/system artifacts | | `HFS_S3_REGION` | *(AWS provider chain)* | AWS region override | +| `HFS_S3_PREFIX` | *(none)* | Optional global key prefix inside bucket(s) | +| `HFS_S3_ENDPOINT_URL` | *(none)* | Custom S3 endpoint (for MinIO/local S3-compatible storage) | +| `HFS_S3_FORCE_PATH_STYLE` | `false` | Use path-style addressing (`http://host/bucket/key`) | +| `HFS_S3_ALLOW_HTTP` | `false` | Allow plain HTTP endpoints for local/dev environments | | `HFS_S3_VALIDATE_BUCKETS` | `true` | Validate bucket access on startup | +| `HFS_S3_ES_REINDEX_ON_STARTUP` | `false` | Rebuild Elasticsearch index from S3 current objects at startup (`s3-elasticsearch` mode) | +| `HFS_S3_ES_REINDEX_BATCH_SIZE` | `500` | Batch size for startup S3->ES reindex | +| `HFS_S3_ES_REINDEX_CLEAR_EXISTING` | `false` | Clear tenant/type ES indices before reindex replay | +| `HFS_S3_ES_REINDEX_RESOURCE_TYPES` | *(none)* | Optional comma-separated resource type filter for reindex | For detailed backend setup instructions (building from source, Docker commands, and search offloading architecture), see the [persistence crate documentation](crates/persistence/README.md#building--running-storage-backends). @@ -432,4 +454,3 @@ The Helios FHIR Server is licensed under the [MIT License](LICENSE). --- HL7® and FHIR® are registered trademarks of Health Level Seven International. - diff --git a/crates/fhir/tests/data/xml/R6/Requirements-example1(example1).xml b/crates/fhir/tests/data/xml/R6/Requirements-example1(example1).xml index 48707b637..68331bee5 100644 --- a/crates/fhir/tests/data/xml/R6/Requirements-example1(example1).xml +++ b/crates/fhir/tests/data/xml/R6/Requirements-example1(example1).xml @@ -50,6 +50,10 @@