Tenant Service

Overview

The Tenant service is the entry point for configuring a tenant into Link Cloud. The service is responsible for maintaining and generating events for the scheduled measure reporting periods that the tenant is configured for. These events contain the initial information needed for Link Cloud to query resources and perform measure evaluations based on a specific reporting period.

The Tenant service uses Quartz with ADO Job Stores to manage jobs across multiple instances of the service, primarily for producing ReportScheduled Kafka events.

flowchart LR
nTenantService_29AF3ECE["Service: Tenant Service"]
  nTenantService_29AF3ECE -->|produces| nAuditableEventOccurred_AF8D6F7["Event: AuditableEventOccurred"]
  nTenantService_29AF3ECE -->|produces| nReportScheduled_4CB82B8["Event: ReportScheduled"]
  nTenantService_29AF3ECE -->|sends| nGenerateReportRequested_5FF13A3F["Command: GenerateReportRequested"]
  nTenantService_29AF3ECE -->|provides| nGetFacilitiesList_48F17BCD["Query: GetFacilitiesList"]
  nTenantService_29AF3ECE -->|provides| nGetFacilityConfig_3026B4B5["Query: GetFacilityConfig"]
  nTenantService_29AF3ECE -->|provides| nGetServiceInfo_56528670["Query: GetServiceInfo"]
  nTenantService_29AF3ECE -->|requests| nGetFacilitiesList_48F17BCD["Query: GetFacilitiesList"]
  nTenantService_29AF3ECE -->|requests| nGetFacilityConfig_3026B4B5["Query: GetFacilityConfig"]
  nTenantService_29AF3ECE -->|requests| nGetServiceInfo_56528670["Query: GetServiceInfo"]
  subgraph nCompliance_11EAF98F_domain["Domain: Compliance"]
    nAuditableEventOccurred_AF8D6F7
  end
  subgraph nReport_523BC237_domain["Domain: Report"]
    nGenerateReportRequested_5FF13A3F
    nReportScheduled_4CB82B8
  end
  subgraph nTenant_223E8F95_domain["Domain: Tenant"]
    nGetFacilitiesList_48F17BCD
    nGetFacilityConfig_3026B4B5
    nGetServiceInfo_56528670
    nTenantService_29AF3ECE
  end

Common Configurations

Custom Configuration

Name Value Secret?
MeasureConfig__CheckIfMeasureExists true or false No

Soft Delete

The Tenant service supports soft deletion of facilities. Rather than permanently removing a facility record, the soft delete endpoint marks the facility with an isDeleted flag set to true. This preserves the facility's configuration and historical data while effectively removing it from active use.

DELETE /api/Facility/softDelete/{facilityId}

Soft deletes a facility by setting its isDeleted flag to true.

Parameters:

  • facilityId (path, required): The unique identifier of the facility to soft delete.

Response:

  • 200 OK: Facility soft deleted successfully. Returns the updated facility configuration.
  • 400 Bad Request: If the request is invalid.
  • 404 Not Found: If no facility exists for the specified facilityId.
  • 500 Internal Server Error: If an error occurs during processing.

Features and Functionality

Key Management

Keys are managed independently by the tenant service, and then associated with tenants. These keys are used for signing authentication JWTs that are passed to /token endpoints at the EHRs. EHRs check that the JWTs are signed using a key found in the JWKS endpoint exposed by Link.

  • Key Registry: A global repository where all JWT signing keys are stored and managed. Each key includes metadata such as kid, algorithm, creation timestamp, status (active, disabled, expired), and an optional primary flag.
  • Lifecycle Operations:
    • Create: Keys can be generated through the admin API/UI with algorithm selection and optional designation as primary.
    • Disable/Delete: Keys no longer in use can be deactivated or removed without disrupting tenant authentication, unless actively in use. This can occur when needing to rotate a key.
    • Rotating Keys:
      1. Create a new key
      2. Associate the new key with tenants
      3. Delete the old key.
  • Tenant Association (handled separately):
    • Tenants reference keys by kid through the Tenant Service configuration interface.
    • A tenant may use a shared or unique key from the registry.
    • Changing a tenant’s associated key does not impact the underlying key object—it only changes the reference.
  • JWKS documents are managed automatically
    • When keys change the JWKS document is re-generated
    • The JWKS document is stored on the file system
    • The JWKS document on the file system is exposed via proxy to external parties for verification (such as EHRs)

The following sequence diagram illustrates how the keys are used during the authentication requests to EHRs:

sequenceDiagram
    participant L as Link
    participant J as JWKS Endpoint
    participant E as EHR Vendor

    L->>L: Create JWT
    L->>L: Sign JWT (with kid)
    L->>J: Publish key to JWKS
    L->>E: POST /token (with JWT)
    E->>J: GET /.well-known/jwks.json
    J-->>E: Return JWKS document
    E->>E: Verify signature using kid
    E-->>L: Return access token

Database Schema

NameTypeRequired?Length
MigrationIdstringYes150
ProductVersionstringYes32
NameTypeRequired?Length
IdstringYes
FacilityIdstringYes
FacilityNamestringNo
CreateDatestring (date-time)Yes
ModifyDatestring (date-time)No
ScheduledReportsstringYes
TimeZonestringYes
IsDeletedbooleanYes
VendorVersionIdstringNo
NameTypeRequired?Length
IdstringYes450
CreateDatestring (date-time)Yes
ModifyDatestring (date-time)No
FacilityIdstringYes100
IsReportingbooleanYes
MeasureMappingIdstringYes450
ReportingMonthintegerYes
ReportingYearintegerYes
NameTypeRequired?Length
IdstringYes450
CreateDatestring (date-time)Yes
ModifyDatestring (date-time)No
DQMstringYes255
FrequencystringYes
MeasurestringYes255
NameTypeRequired?Length
IdstringYes
NamestringYes255
AuthenticationstringNo
NameTypeRequired?Length
IdstringYes
VendorIdstringYes
VersionstringYes255
NameTypeRequired?Length
SCHED_NAMEstringYes120
TRIGGER_NAMEstringYes150
TRIGGER_GROUPstringYes150
BLOB_DATAstringNo
NameTypeRequired?Length
SCHED_NAMEstringYes120
CALENDAR_NAMEstringYes200
CALENDARstringYes
NameTypeRequired?Length
SCHED_NAMEstringYes120
TRIGGER_NAMEstringYes150
TRIGGER_GROUPstringYes150
CRON_EXPRESSIONstringYes120
TIME_ZONE_IDstringNo120
NameTypeRequired?Length
SCHED_NAMEstringYes120
ENTRY_IDstringYes140
TRIGGER_NAMEstringYes150
TRIGGER_GROUPstringYes150
INSTANCE_NAMEstringYes150
FIRED_TIMEintegerYes
SCHED_TIMEintegerYes
PRIORITYintegerYes
STATEstringYes16
JOB_NAMEstringNo150
JOB_GROUPstringNo150
IS_NONCONCURRENTbooleanYes
REQUESTS_RECOVERYbooleanNo
NameTypeRequired?Length
SCHED_NAMEstringYes120
JOB_NAMEstringYes150
JOB_GROUPstringYes150
DESCRIPTIONstringNo250
JOB_CLASS_NAMEstringYes250
IS_DURABLEbooleanYes
IS_NONCONCURRENTbooleanYes
IS_UPDATE_DATAbooleanYes
REQUESTS_RECOVERYbooleanYes
JOB_DATAstringNo
NameTypeRequired?Length
SCHED_NAMEstringYes120
LOCK_NAMEstringYes40
NameTypeRequired?Length
SCHED_NAMEstringYes120
TRIGGER_GROUPstringYes150
NameTypeRequired?Length
SCHED_NAMEstringYes120
INSTANCE_NAMEstringYes200
LAST_CHECKIN_TIMEintegerYes
CHECKIN_INTERVALintegerYes
NameTypeRequired?Length
SCHED_NAMEstringYes120
TRIGGER_NAMEstringYes150
TRIGGER_GROUPstringYes150
REPEAT_COUNTintegerYes
REPEAT_INTERVALintegerYes
TIMES_TRIGGEREDintegerYes
NameTypeRequired?Length
SCHED_NAMEstringYes120
TRIGGER_NAMEstringYes150
TRIGGER_GROUPstringYes150
STR_PROP_1stringYes512
STR_PROP_2stringYes512
STR_PROP_3stringYes512
INT_PROP_1integerNo
INT_PROP_2integerNo
LONG_PROP_1integerNo
LONG_PROP_2integerNo
DEC_PROP_1numberNo
DEC_PROP_2numberNo
BOOL_PROP_1booleanNo
BOOL_PROP_2booleanNo
TIME_ZONE_IDstringNo80
NameTypeRequired?Length
SCHED_NAMEstringYes120
TRIGGER_NAMEstringYes150
TRIGGER_GROUPstringYes150
JOB_NAMEstringYes150
JOB_GROUPstringYes150
DESCRIPTIONstringNo250
NEXT_FIRE_TIMEintegerNo
PREV_FIRE_TIMEintegerNo
PRIORITYintegerNo
TRIGGER_STATEstringYes16
TRIGGER_TYPEstringYes8
START_TIMEintegerYes
END_TIMEintegerNo
CALENDAR_NAMEstringNo200
MISFIRE_INSTRintegerNo
JOB_DATAstringNo
MISFIRE_ORIG_FIRE_TIMEintegerNo

OpenAPI Operations

Get facilities

Route Parameters

None

Query Parameters
NameTypeRequired?Description
facilityIdNo
facilityNameNo
timeZoneNo
sortByNo
sortOrderNo
pageSizeNo
pageNumberNo
includeDeletedNo

Creates a facility configuration.

Route Parameters

None

Query Parameters

None

Get a list of all facilities

Route Parameters

None

Query Parameters
NameTypeRequired?Description
searchNo
includeDeletedNo

Gets a facility configuration by facilityId.

Route Parameters
NameTypeRequired?Description
facilityIdYes
Query Parameters

None

Updates a facility configuration.

Route Parameters
NameTypeRequired?Description
facilityIdYes
Query Parameters

None

Deletes a facility configuration.

Route Parameters
NameTypeRequired?Description
facilityIdYes
Query Parameters

None

Route Parameters
NameTypeRequired?Description
facilityIdYes
Query Parameters

None

Restores a soft-deleted facility configuration.

Route Parameters
NameTypeRequired?Description
facilityIdYes
Query Parameters

None

Generate

Route Parameters
NameTypeRequired?Description
facilityIdYes
Query Parameters

None

Route Parameters
NameTypeRequired?Description
facilityIdYes
Query Parameters

None

Gets a paged list of every facility reporting plan.

Route Parameters

None

Query Parameters
NameTypeRequired?Description
sortByNoColumn to sort by: Id, FacilityId, MeasureMappingId, ReportingMonth, ReportingYear, IsReporting, CreateDate or ModifyDate. Defaults to Id. Any other value is refused.
sortOrderNoAscending or Descending. Defaults to Descending.
pageSizeNoRows per page, 1 to 100. Defaults to 10.
pageNumberNoOne-based page number. Defaults to 1.

Creates a facility reporting plan.

Route Parameters

None

Query Parameters

None

Deletes every facility reporting plan.

Route Parameters

None

Query Parameters

None

Gets all reporting plans for a facility, optionally narrowed to a reporting period or reporting state.

Route Parameters
NameTypeRequired?Description
facilityIdYesThe reporting facility, as the Tenant service knows it (the NHSN Org Id).
Query Parameters
NameTypeRequired?Description
monthNoOptional reporting month, 1 to 12. Omit to return every month.
yearNoOptional reporting year, 2000 to 2100. Omit to return every year.
isReportingNoOptional. True returns only measures the facility is enrolled in, false only those it has withdrawn from. Omit to return both.

Deletes every reporting plan belonging to a facility.

Route Parameters
NameTypeRequired?Description
facilityIdYesThe facility whose plans are removed.
Query Parameters

None

Gets a facility reporting plan by Id.

Route Parameters
NameTypeRequired?Description
idYesThe reporting plan's own identifier, as returned by create or search.
Query Parameters

None

Updates a facility reporting plan.

Route Parameters
NameTypeRequired?Description
idYesThe reporting plan to replace.
Query Parameters

None

Deletes a facility reporting plan.

Route Parameters
NameTypeRequired?Description
idYesThe reporting plan to delete.
Query Parameters

None

Gets a measure mapping by Id.

Route Parameters
NameTypeRequired?Description
idYesThe mapping's own identifier, as returned by create or search.
Query Parameters

None

Updates a measure mapping.

Route Parameters
NameTypeRequired?Description
idYesThe mapping to replace. This wins over any id in the body.
Query Parameters

None

Deletes a measure mapping.

Route Parameters
NameTypeRequired?Description
idYesThe mapping to delete.
Query Parameters

None

Creates a measure mapping.

Route Parameters

None

Query Parameters

None

Deletes all measure mappings.

Route Parameters

None

Query Parameters

None

Route Parameters

None

Query Parameters

None

Route Parameters
NameTypeRequired?Description
idYes
Query Parameters

None

Route Parameters
NameTypeRequired?Description
idYes
Query Parameters

None

Route Parameters
NameTypeRequired?Description
idYes
Query Parameters

None

Route Parameters

None

Query Parameters

None

Route Parameters

None

Query Parameters

None

Route Parameters
NameTypeRequired?Description
idYes
Query Parameters

None

Route Parameters
NameTypeRequired?Description
idYes
Query Parameters

None

Route Parameters
NameTypeRequired?Description
idYes
Query Parameters

None

Route Parameters

None

Query Parameters
NameTypeRequired?Description
vendorIdNo
Route Parameters

None

Query Parameters

None

Health check endpoint

Route Parameters

None

Query Parameters

None

Relationships

flowchart LR
nTenantService_29AF3ECE["Service: Tenant Service"]
  nTenantService_29AF3ECE -->|produces| nAuditableEventOccurred_AF8D6F7["Event: AuditableEventOccurred"]
  nTenantService_29AF3ECE -->|produces| nReportScheduled_4CB82B8["Event: ReportScheduled"]
  nTenantService_29AF3ECE -->|sends| nGenerateReportRequested_5FF13A3F["Command: GenerateReportRequested"]
  nTenantService_29AF3ECE -->|provides| nGetFacilitiesList_48F17BCD["Query: GetFacilitiesList"]
  nTenantService_29AF3ECE -->|provides| nGetFacilityConfig_3026B4B5["Query: GetFacilityConfig"]
  nTenantService_29AF3ECE -->|provides| nGetServiceInfo_56528670["Query: GetServiceInfo"]
  nTenantService_29AF3ECE -->|requests| nGetFacilitiesList_48F17BCD["Query: GetFacilitiesList"]
  nTenantService_29AF3ECE -->|requests| nGetFacilityConfig_3026B4B5["Query: GetFacilityConfig"]
  nTenantService_29AF3ECE -->|requests| nGetServiceInfo_56528670["Query: GetServiceInfo"]
  subgraph nCompliance_11EAF98F_domain["Domain: Compliance"]
    nAuditableEventOccurred_AF8D6F7
  end
  subgraph nReport_523BC237_domain["Domain: Report"]
    nGenerateReportRequested_5FF13A3F
    nReportScheduled_4CB82B8
  end
  subgraph nTenant_223E8F95_domain["Domain: Tenant"]
    nGetFacilitiesList_48F17BCD
    nGetFacilityConfig_3026B4B5
    nGetServiceInfo_56528670
    nTenantService_29AF3ECE
  end