9. Configure, Document, and Review
Your service works. On this last page, you finish it the way a real service is finished: you describe it in its CapabilityStatement, review its configuration, document it, fill the remaining gaps in its tests, and present it to the onboarding team.
Describe Your FHIR Server
Look at the software element of the CapabilityStatement at /metadata: your server is still called "HAPI FHIR Server". Add the following to src/main/resources/application.properties, after va.mobile.fhir.server.path:
# Name and description of the FHIR server, published in the CapabilityStatement (software.name, implementation.description)
va.mobile.fhir.server.server-name=FHIR Starter Service
va.mobile.fhir.server.implementation-description=FHIR Starter Project: patient demographics from MVI and encounters from Oracle Health
After skaffold dev redeploys, /metadata describes your server:
"software":{"name":"FHIR Starter Service","version":"8.12.1"},"implementation":{"description":"FHIR Starter Project: patient demographics from MVI and encounters from Oracle Health","url":"http://localhost:8080/fhirstarter/v1/fhir"}
The Swagger UI, at http://localhost:8080/fhirstarter/v1/fhir/swagger-ui/, shows the server name in its heading.
The framework has more properties for the FHIR server, such as page sizes and pretty-printed JSON; see FHIR Server Properties in the appendix.
|
When you debug, turn on request logging in
There are also |
Document the Service
Every VA Mobile service documents what it does, what it depends on, and how to deploy it. Update the documents that the archetype generated.
README
Replace the placeholders in README.md:
-
The Summary: describe what the service provides, and to whom. For example:
The fhir-starter-service is a FHIR R4 server for staff and veteran users. It provides Patient resources with demographics and identifiers from the Mobile MVI Service, and Encounter resources from Oracle Health (Cerner). Staff users may access any patient; veteran users may access only their own records. -
The Project Structure table: add the classes you created, and update the descriptions of the providers, which are no longer samples. Then remove the
[//]: # (TODO: expand summary)line at the end of the table. Despite its wording, it belongs to the Project Structure section:| Location | Description | |:---|:---| | `resource/PatientProvider.java` | Patient read, search by ICN, and the `$identifiers` operation. Spring beans that implement `IResourceProvider` are registered with the FHIR server automatically | | `resource/EncounterProvider.java` | Encounter search by patient and status | | `resource/PatientAccess.java` | ICN validation and the veteran access check, shared by the resource providers | | `resource/SystemOperationsProvider.java` | System level operation (`$validate-icn`), a plain provider registered in `FhirConfig` | | `client/MviClient.java` | Calls the Mobile MVI Service with the `mvi` REST client | | `client/CernerClient.java` | Calls Oracle Health with the `cerner` FHIR client | | `client/CernerAuthInterceptor.java` | Adds an Oracle Health OAuth 2.0 access token to each request of the `cerner` FHIR client | | `mapper/PatientMapper.java` | Maps MVI data to FHIR `Patient` and `Parameters` resources | | `interceptor/CacheControlInterceptor.java` | Adds `Cache-Control: no-store` to successful responses | | `config/FhirConfig.java` | Registers plain providers and interceptors with the FHIR server | | `config/CernerConfig.java` | Registers `CernerAuthInterceptor` with the `cerner` FHIR client | | `exception/` | `ErrorMessage` catalog and HAPI FHIR exceptions, which are returned to clients as an `OperationOutcome` | | `AppProperties.java` | Service settings, bound from `va.mobile.fhirstarter.*` | | `docs/capability-statement*.json` | CapabilityStatement and OpenAPI documents, written by `CapabilityStatementITCase` | -
The Dependencies table: replace the example rows with your two downstream systems, and remove the
[//]: # (TODO: Fill in Dependencies)line:| External Dependency | Version | Description | |:-----------------------------------------------|:--------|:-------------------------------------------------------------| | Mobile MVI Service (`mobile-mvi-service`) | v1 | Provides patient demographics and identifiers, by ICN | | Oracle Health (Cerner) Millennium FHIR R4 API | R4 | Provides patient encounters; requires an OAuth 2.0 client | -
The Service Interface table: add the
$identifiersoperation and the Encounter search, and remove "stub" from the Patient rows:| Endpoint | Description | |:---|:---| | `GET /fhirstarter/v1/fhir/metadata` | FHIR CapabilityStatement ([docs/capability-statement.json](docs/capability-statement.json)) | | `GET /fhirstarter/v1/fhir/api-docs` | OpenAPI document ([docs/capability-statement-openapi.json](docs/capability-statement-openapi.json)) | | `GET /fhirstarter/v1/fhir/swagger-ui/` | Swagger UI | | `GET /fhirstarter/v1/fhir/Patient?identifier=urn:oid:2.16.840.1.113883.4.349\|{icn}` | Patient search by ICN (staff, or a veteran for their own ICN) | | `GET /fhirstarter/v1/fhir/Patient/{icn}` | Patient read (staff, or a veteran for their own ICN) | | `GET /fhirstarter/v1/fhir/Patient/{icn}/$identifiers` | Identifiers of the patient, from MVI (staff, or a veteran for their own ICN) | | `GET /fhirstarter/v1/fhir/Encounter?patient={icn}&status={status}` | Encounter search by patient, with an optional status (staff, or a veteran for their own ICN) | | `GET /fhirstarter/v1/fhir/$validate-icn?icn={icn}` | Checks whether an identifier is a valid ICN (staff only) | -
Under Health Check APIs, add a sentence about readiness, for example: "The readiness group (
/actuator/health/readiness) includes themviandcernerhealth indicators, so the service only receives requests while the Mobile MVI Service and Oracle Health are reachable." -
Delete the Infrastructure Notes and Atypical Patterns sections, which don’t apply to this service, and the italic instructions in Additional Documentation. Keep the line about the NGSS defect process.
The build copies README.md to docs/index.md, with its links adjusted for the docs directory, so commit both.
Service Design Document
docs/SRVDD.md is the service design document. A real service completes all of it with the tech lead before its first release. For this project, fill in its two most important tables, in your own words. The three short sections after them are optional.
-
Data Access / Storage Overview: replace the placeholder row with one row for each kind of data your service reads: patient demographics and patient identifiers from the Mobile MVI Service, encounters from Oracle Health, and the Oracle Health credentials and access tokens. Classify the patient data as PHI and the credentials as Sensitive. The template’s example table shows the format; delete it when your rows are done.
-
Logical Interactions: replace the example rows with one row for each endpoint of your service, with the external endpoints it calls. Use the CapabilityStatement and your clients,
MviClientandCernerClient, to find them.
Optional:
-
Service Information: the repository, on your branch:
https://coderepo.mobilehealth.va.gov/projects/CKM/repos/starter-project/browse/fhir-starter-service?at=fhir_starter_<firstname>_<lastname>. The service doesn’t exist onmain, so a link without?at=leads nowhere. -
Purpose: one bullet that describes the service, and "This is the initial release of the service."
-
Intended Service Availability: check both Veteran and Staff. Your service is registered with both API gateways, as
docs/dibr.mdsays.
Leave the other sections as they are, including the sequence diagrams under Logical Interface Design; a real service adds those with its tech lead.
When you’re done, compare your tables with the example answers below.
Example answer: Data Access / Storage Overview
| **Data Type** | **VAMF/VA Source** | **CRUD Operations** | **DB Type** | **DB Name** | **Data Classification** | **Reason / Requirement** |
|:---|:---:|:---:|:---:|:---:|:---:|:---:|
|Patient demographics (name, gender, birth date, address, phone) | mobile-mvi-service | R | N/A | N/A | PHI | Return FHIR Patient resources |
|Patient identifiers (ICN and correlated identifiers) | mobile-mvi-service | R | N/A | N/A | PHI | Return the result of the Patient `$identifiers` operation |
|Encounters | Oracle Health Millennium FHIR R4 API | R | N/A | N/A | PHI | Return FHIR Encounter resources |
|Oracle Health client ID, client secret, and access tokens | Vault; Oracle Health token endpoint | R | N/A | N/A | Sensitive | Authenticate the service to Oracle Health; the access token is held in memory only |
Example answer: Logical Interactions
|Endpoint|HTTP Action|External System Endpoint (table mapping for databases) | Authorization Type |Description|
|---|---|---|--------------------|---|
|/fhirstarter/v1/fhir/Patient?identifier={system}\|{icn}|GET|mobile-mvi-service: GET /mvi/v1/patients/ICN/{icn}/mvi/person| JWT Role-Based |Search for a patient by ICN|
|/fhirstarter/v1/fhir/Patient/{icn}|GET|mobile-mvi-service: GET /mvi/v1/patients/ICN/{icn}/mvi/person| JWT Role-Based |Read a patient|
|/fhirstarter/v1/fhir/Patient/{icn}/$identifiers|GET|mobile-mvi-service: GET /mvi/v1/patients/ICN/{icn}/mvi/identifiers| JWT Role-Based |Return the identifiers that MVI correlates with a patient|
|/fhirstarter/v1/fhir/Encounter?patient={icn}&status={status}|GET|Oracle Health: POST {token URL} (OAuth 2.0 client credentials)<br/>Oracle Health: GET {FHIR URL}/Patient?identifier={system}\|{icn}<br/>Oracle Health: GET {FHIR URL}/Encounter?subject=Patient/{id}&status={status}| JWT Role-Based |Search for the encounters of a patient|
|/fhirstarter/v1/fhir/$validate-icn?icn={icn}|GET|None| JWT Role-Based |Check whether an identifier is a valid ICN|
|/fhirstarter/v1/fhir/metadata<br/>/fhirstarter/v1/fhir/api-docs<br/>/fhirstarter/v1/fhir/swagger-ui/|GET|None| Unauthenticated |CapabilityStatement, OpenAPI document, and Swagger UI|
Change Log and Deployment Documentation
Describe what release 1.0.0 contains in CHANGELOG.md. Replace CKM-## with the Jira issue of your onboarding work, if you have one:
# fhir-starter-service Changelog
## Release 1.0.0
* CKM-####: Initial release
* Patient read and search by ICN, with demographics from the Mobile MVI Service
* Patient `$identifiers` operation, with the identifiers that MVI correlates with the patient
* Encounter search by patient and status, with encounters from Oracle Health
* `$validate-icn` system operation
* `Cache-Control: no-store` on successful responses
* HTTP 503 when the Mobile MVI Service is unavailable
You documented the Consul settings and Vault secrets in metadata.yaml on page 7. Check that docs/dibr.md, which the build generates from it, lists the Vault secrets.
The integration tests write the CapabilityStatement and OpenAPI documents to docs/capability-statement.json and docs/capability-statement-openapi.json. They are the contract of your service, so review their changes before you commit them.
Complete the Tests
| To check your tests, compare them with the test classes in the "FHIR starter page 9" commit of the reference branch; see When You Get Stuck. |
Check the Server Description
In CapabilityStatementITCase, add two assertions to verifyCapabilityStatement:
-
capabilityStatement.getSoftware().getName()isFHIR Starter Service. -
The Encounter resource declares the
patientandstatussearch parameters. Select the Encounter resource the way the assertion for the Patientidentifiersoperation selects the Patient resource.getSearchParam()returns the search parameters of a resource, and each one has agetName(). Their class is nested inCapabilityStatement, which the test already imports, so you can refer to the method asCapabilityStatement.CapabilityStatementRestResourceSearchParamComponent::getName.
Fill the Gaps in the Test Matrix (Optional)
| This section is optional. Nothing later in the guide depends on it. The five tests follow patterns you have already practiced, so if you are short on time, skip them, or pair with a teammate on them before your review. |
Your integration tests check each interaction for each kind of user and each kind of failure. The table below shows which test covers each case. The five tests in bold don’t exist yet:
| Interaction | Staff | Veteran, own ICN | Veteran, other ICN | Unauthenticated | Invalid input | Not found | Downstream problem |
|---|---|---|---|---|---|---|---|
Patient search |
|
|
|
|
|
|
|
Patient read |
|
|
|
|
|
|
|
|
|
|
|
|
|
|
Same code as the read |
Encounter search |
|
|
|
|
|
|
|
Add the five tests. Each one follows a test you already have:
| Test | Class | Request | Expected result |
|---|---|---|---|
|
|
Read |
|
|
|
|
Two |
|
|
|
|
|
|
|
|
|
|
Search for the encounters of |
|
There is no integration test for an Oracle Health failure, because cerner-mock can’t be made to fail for one patient. CernerClient.send handles failures the same way as MviClient.send, which the MVI error stubs test.
Run the Full Build
./mvnw clean install -Pwith-skaffold
The reference solution of this guide has 43 unit tests and 40 integration tests, and your build should report the same numbers, or 35 integration tests if you skipped the optional gap tests. Parameterized tests count once for each case, so if your unit test count is different, compare your toGender cases with the hint on page 4. Open target/site/jacoco-aggregate/index.html and look at the coverage of the classes you wrote.
Commit and Push
git add .
git commit -m "Describe and document the service, and complete its tests"
git push
Review / Acceptance
Make sure all your changes are committed and pushed before you start your review.
When you have completed the FHIR Starter Project, work with the onboarding team to review it. The review is informal, and focuses on making sure you understand how a FHIR service is built, and the tools we use to build it. Be ready to:
-
Show your CapabilityStatement at
/metadata, and the Swagger UI. -
Call each interaction with curl or Postman: the Patient search, read, and
$identifiersoperation, the Encounter search, and$validate-icn. Show that$VETERAN_JWTcan read PATIENT FIFTEEN’s records, and no one else’s. -
Show one error of each kind, and explain where it comes from: HTTP 400 (
Patient/not-an-icn), 401 (no JWT), 403 (Patient/10132V467385with$VETERAN_JWT), 404 (Patient/1012845331V153043), 500 (Encounter?patient=10180V273016), and 503 (Patient/10108V420871). -
Show
/actuator/health, with themviandcernercomponents. -
Walk through your test classes, and explain how the test matrix covers the access rules.
-
Explain how a request flows from HAPI through your provider to the Mobile MVI Service or Oracle Health, and back to the client as a FHIR resource or an
OperationOutcome.
Questions and open discussion are encouraged; this is your opportunity to get answers and provide feedback.
You’re Done When
-
/metadatanames and describes your server -
README.md,docs/SRVDD.md,CHANGELOG.md, andmetadata.yamldescribe what you built -
The full build passes (and, if you did the optional section, the test matrix has no gaps)
-
Your branch is pushed
-
You have scheduled your review with the onboarding team
Congratulations, you have built a FHIR service! Return to the New Hire Checklist for your next onboarding steps.