.. _multitenancy: Multitenancy ============ openFHIR Engine supports multitenancy, allowing multiple organizations or tenants to use the same openFHIR instance while maintaining complete data isolation and tenant-specific configurations. Tenant Isolation ----------------- All FhirConnect state and mapping access is completely separated per tenant. This includes: - **Operational Templates (OPTs)**: Each tenant maintains their own set of operational templates - **FhirConnect Context Mappers**: Context configurations are isolated per tenant - **FhirConnect Model Mappers**: Mapping definitions are tenant-specific - **ConceptMaps**: Terminology mappings are maintained separately for each tenant - **Mapping Insights**: All mapping execution history and insights are tenant-scoped When a tenant accesses any openFHIR functionality, they only see and can modify their own data. There is no cross-tenant data visibility or interference. Tenant-Specific Configuration ----------------------------- Each tenant can be configured with specific settings that control how openFHIR processes their data. These configurations are stored as JSON properties within each tenant entity. Currently available tenant configuration options: contained_to_separate_bundle_entry ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ **Type:** ``boolean`` **Default:** ``true`` Controls how referenced resources are handled in FHIR Bundle generation: - **true (default)**: Referenced resources (like PractitionerRole referenced by Consent) are created as separate entries in the FHIR Bundle. This results in more Bundle entries but follows standard FHIR referencing patterns. - **false**: Referenced resources are embedded as contained resources within the parent resource. This results in fewer Bundle entries but uses FHIR's contained resource mechanism. **Example:** When ``contained_to_separate_bundle_entry`` is ``false``: .. code-block:: json { "resourceType": "Bundle", "entry": [ { "resource": { "resourceType": "Consent", "contained": [ { "resourceType": "PractitionerRole", "id": "contained-practitioner" } ], "provision": { "actor": [ { "reference": { "reference": "#contained-practitioner" } } ] } } } ] } When ``contained_to_separate_bundle_entry`` is ``true``: .. code-block:: json { "resourceType": "Bundle", "entry": [ { "resource": { "resourceType": "Consent", "provision": { "actor": [ { "reference": { "reference": "PractitionerRole/separate-practitioner" } } ] } } }, { "resource": { "resourceType": "PractitionerRole", "id": "separate-practitioner" } } ] } Tenant Management API --------------------- Tenants can be managed through RESTful API endpoints: .. http:post:: /tenant Create a new tenant with specific configuration. **Example request**: .. sourcecode:: http POST /tenant HTTP/1.1 Content-Type: application/json Authorization: Bearer { "id": "organization-123", "properties": { "contained_to_separate_bundle_entry": false } } .. http:put:: /tenant/(id) Update an existing tenant's configuration. **Example request**: .. sourcecode:: http PUT /tenant/organization-123 HTTP/1.1 Content-Type: application/json Authorization: Bearer { "properties": { "contained_to_separate_bundle_entry": true } } .. http:get:: /tenant/(id) Retrieve a specific tenant's configuration. **Example request**: .. sourcecode:: http GET /tenant/organization-123 HTTP/1.1 Authorization: Bearer .. http:get:: /tenant Retrieve all tenants (administrative operation). **Example request**: .. sourcecode:: http GET /tenant HTTP/1.1 Authorization: Bearer .. http:delete:: /tenant/(id) Delete a tenant and all associated data. **Example request**: .. sourcecode:: http DELETE /tenant/organization-123 HTTP/1.1 Authorization: Bearer Security and Authorization -------------------------- Tenant operations require specific scopes: - ``tenant.c``: Create tenants - ``tenant.r``: Read tenant information - ``tenant.u``: Update tenant configuration - ``tenant.d``: Delete tenants All other openFHIR operations automatically scope to the authenticated user's tenant context, ensuring complete data isolation between organizations.