Skip to content

Commit 1ac51d5

Browse files
docs(interoperability): add 10 issue context files matching template #76 (#92)
1 parent 8beb625 commit 1ac51d5

10 files changed

Lines changed: 691 additions & 0 deletions
Lines changed: 74 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,74 @@
1+
---
2+
id: cht-interoperability-116
3+
category: feature
4+
domain: interoperability
5+
subDomain: fhir-http-method-semantics
6+
issueNumber: 116
7+
issueUrl: https://github.com/medic/cht-interoperability/issues/116
8+
title: Allow mediators to update resources with PUT requests
9+
lastUpdated: 2025-01-07
10+
summary: The issue tracked support and validation for correct HTTP update semantics (PUT for updates vs POST for creates) in mediator-driven FHIR flows. The discussion evolved with architecture changes, and the issue was ultimately closed after confirming update behavior in the current mediator approach.
11+
services:
12+
- api
13+
techStack:
14+
- typescript
15+
- javascript
16+
---
17+
18+
## Problem
19+
20+
FHIR integrations expect create and update operations to use appropriate HTTP methods and endpoint semantics. The issue identified that update behavior needed clearer handling so existing remote resources are updated reliably instead of being treated as new creates.
21+
22+
## Root Cause
23+
24+
Initial mediator assumptions and earlier flow design favored `POST` behavior broadly. As interoperability logic evolved, method semantics and state-awareness needed explicit validation in the mediator path.
25+
26+
## Solution
27+
28+
Issue #116 was repurposed as a tracking item for validating update semantics under the newer mediator architecture. It is important to note that this issue did not result in a specific, discrete code change or pull request.
29+
30+
- It served to clarify expected behavior: existing resources should ideally be handled with update semantics.
31+
- It evaluated where this decision should live (mediator-side state/logic vs upstream assumptions).
32+
- It was ultimately closed as a tracking-item confirmation after reviewing the behavior in the updated architecture. There is no specific PR to look at for this issue.
33+
34+
## Code Patterns
35+
36+
- Route-level handling that can support distinct create/update logic:
37+
- `mediator/src/routes/patient.ts`
38+
- `mediator/src/routes/encounter.ts`
39+
- `mediator/src/routes/service-request.ts`
40+
- Shared FHIR request utility where method/path behavior is centralized:
41+
- `mediator/src/utils/fhir.ts`
42+
- Shared request wrapper pattern for consistent responses:
43+
- `mediator/src/utils/request.ts`
44+
45+
## Design Choices
46+
47+
- Preferred aligning with REST/FHIR semantics rather than relying on implicit upsert behavior.
48+
- Kept discussion open while architecture was changing, then closed once behavior was validated in the new flow.
49+
- Left room for future refinements where resource-specific behavior may require stricter method routing.
50+
51+
## Related Files
52+
53+
- mediator/src/routes/patient.ts
54+
- mediator/src/routes/encounter.ts
55+
- mediator/src/routes/service-request.ts
56+
- mediator/src/utils/fhir.ts
57+
- mediator/src/utils/request.ts
58+
- mediator/src/controllers/service-request.ts
59+
60+
## Testing
61+
62+
- Route/controller unit tests validate request/response behavior for mediator endpoints:
63+
- mediator/src/routes/tests/patient.spec.ts
64+
- mediator/src/routes/tests/encounter.spec.ts
65+
- mediator/src/routes/tests/service-request.spec.ts
66+
- FHIR utility tests cover helper behavior used by create/update paths:
67+
- mediator/src/utils/tests/fhir.spec.ts
68+
- End-to-end flow checks in mediator integration test suite:
69+
- mediator/test/ltfu-flow.spec.ts
70+
71+
## Related Issues
72+
73+
- #141: OpenMRS sync creates duplicate resources
74+
- #54: Make mediator endpoints FHIR compliant
Lines changed: 67 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,67 @@
1+
---
2+
id: cht-interoperability-141
3+
category: bug
4+
domain: interoperability
5+
subDomain: openmrs-sync-deduplication
6+
issueNumber: 141
7+
issueUrl: https://github.com/medic/cht-interoperability/issues/141
8+
title: OpenMRS sync creates duplicate resources
9+
lastUpdated: 2024-11-11
10+
summary: OpenMRS synchronization could create duplicate resources because uniqueness checks around identifiers and create/update paths were not reliable enough. Follow-up implementation (including PR #146) strengthened identifier-based checks and reduced duplicate creation behavior.
11+
services:
12+
- api
13+
techStack:
14+
- typescript
15+
- javascript
16+
---
17+
18+
## Problem
19+
20+
OpenMRS synchronization occasionally created duplicate resources in the interop flow. Duplicate behavior was observed around patient synchronization and, in related discussion, around conditions where repeated create behavior could occur if matching did not correctly detect existing resources.
21+
22+
A temporary time-window workaround (`SYNC_PERIOD` logic offset by `2 * SYNC_INTERVAL`) reduced symptoms but did not address the core defect.
23+
24+
## Root Cause
25+
26+
The synchronization path depended on imperfect existence checks. If matching by identifiers did not correctly detect an existing FHIR resource, the flow could attempt create operations again, leading to duplicates.
27+
28+
The time-window workaround masked race/boundary conditions but was not a true deduplication guarantee.
29+
30+
## Solution
31+
32+
Issue #141 was resolved by removing reliance on the workaround and strengthening deduplication logic with identifier checks (tracked in linked follow-up PR #146):
33+
34+
- Matching logic was improved to use identifier-based checks before create behavior.
35+
- Resource handling was tightened so duplicate create calls are less likely when a logically identical resource already exists.
36+
- Discussion also clarified neighboring setup concerns (for example channel/config behavior) vs the core duplication defect.
37+
38+
## Code Patterns
39+
40+
- Identifier-based resource lookup pattern before create:
41+
- `mediator/src/utils/fhir.ts` (resource retrieval helpers)
42+
- Service-request/controller orchestration for create/update decisions:
43+
- `mediator/src/controllers/service-request.ts`
44+
45+
## Design Choices
46+
47+
- Chose fixing identity checks over extending time-window heuristics.
48+
- Kept deduplication anchored to interoperable identifiers (for example OpenMRS/CHT IDs) rather than only timing assumptions.
49+
- Preferred deterministic identifier matching because sync scheduling can be delayed or interrupted in real deployments.
50+
51+
## Related Files
52+
53+
- mediator/src/utils/fhir.ts
54+
- mediator/src/controllers/service-request.ts
55+
- mediator/test/ltfu-flow.spec.ts
56+
57+
## Testing
58+
59+
- Reproduction and validation were done through sync flow testing and branch-level checks discussed in the issue.
60+
- Follow-up implementation merged via PR #146 and closed the issue.
61+
- Integration scenarios continue to be covered in mediator flow tests:
62+
- mediator/test/ltfu-flow.spec.ts
63+
64+
## Related Issues
65+
66+
- #116: Allow mediators to update resources with PUT requests
67+
- #54: Make mediator endpoints FHIR compliant
Lines changed: 89 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,89 @@
1+
---
2+
id: cht-interoperability-54
3+
category: feature
4+
domain: interoperability
5+
subDomain: mediator-fhir-endpoints
6+
issueNumber: 54
7+
issueUrl: https://github.com/medic/cht-interoperability/issues/54
8+
title: Make mediator endpoints FHIR compliant
9+
lastUpdated: 2023-04-28
10+
summary: The interoperability mediator endpoints were aligned to HL7 FHIR request/response expectations. The implementation in PR #76 added stricter resource validation, standardized route behavior, and broader unit/integration test coverage so CHT↔OpenHIM↔FHIR flows use consistent FHIR semantics.
11+
services:
12+
- api
13+
techStack:
14+
- typescript
15+
- javascript
16+
---
17+
18+
## Problem
19+
20+
The mediator accepted payloads for FHIR resources, but endpoint behavior and validation were not consistently aligned with FHIR expectations across all routes. That made integration behavior harder to reason about when external systems (through OpenHIM/FHIR server) relied on predictable resource handling.
21+
22+
This surfaced as interoperability friction in core mediator workflows (patient, encounter, endpoint, organization, service-request), where API shape consistency matters for upstream and downstream systems.
23+
24+
## Root Cause
25+
26+
FHIR validation and route-level schema validation were present in parts of the mediator, but not applied in a fully consistent pattern across all resources and handlers. The project also needed better route/controller test coverage to lock in behavior.
27+
28+
## Solution
29+
30+
Issue #54 was closed via PR #76, which standardized endpoint behavior and validation approach across mediator routes:
31+
32+
- Route handlers consistently pass through a shared request wrapper and validation middleware.
33+
- FHIR resource validation is applied per route/resource type.
34+
- Resource-specific Joi schemas are used where needed.
35+
- Endpoint and controller tests were expanded to protect behavior and avoid regressions.
36+
37+
This made the mediator endpoints more predictable for external systems and for future enhancements.
38+
39+
## Code Patterns
40+
41+
- Route-level FHIR validation pattern:
42+
- `mediator/src/routes/patient.ts`
43+
- `mediator/src/routes/encounter.ts`
44+
- `mediator/src/routes/endpoint.ts`
45+
- `mediator/src/routes/organization.ts`
46+
- `mediator/src/routes/service-request.ts`
47+
- Shared response handling pattern:
48+
- `mediator/src/utils/request.ts` (`requestHandler`)
49+
- Shared FHIR utility pattern:
50+
- `mediator/src/utils/fhir.ts` (`validateFhirResource`, resource helpers)
51+
- Middleware composition pattern for request validation:
52+
- `mediator/src/middlewares/index.ts`
53+
54+
## Design Choices
55+
56+
- Chose central validation/util wrappers (instead of per-route custom logic) to keep behavior consistent and maintainable.
57+
- Kept resource-specific schema checks where domain constraints differ (for example `ServiceRequest` and `Endpoint`) while reusing common FHIR validation.
58+
- Prioritized strong automated tests to stabilize mediator behavior as the interop surface grows.
59+
60+
## Related Files
61+
62+
- mediator/src/routes/patient.ts
63+
- mediator/src/routes/encounter.ts
64+
- mediator/src/routes/endpoint.ts
65+
- mediator/src/routes/organization.ts
66+
- mediator/src/routes/service-request.ts
67+
- mediator/src/middlewares/index.ts
68+
- mediator/src/utils/fhir.ts
69+
- mediator/src/utils/request.ts
70+
71+
## Testing
72+
73+
- Unit tests for route validation and handler behavior:
74+
- mediator/src/routes/tests/patient.spec.ts
75+
- mediator/src/routes/tests/encounter.spec.ts
76+
- mediator/src/routes/tests/endpoint.spec.ts
77+
- mediator/src/routes/tests/service-request.spec.ts
78+
- Unit tests for schema and FHIR utility behavior:
79+
- mediator/src/middlewares/schemas/tests/*.spec.ts
80+
- mediator/src/utils/tests/fhir.spec.ts
81+
- mediator/src/utils/tests/request.spec.ts
82+
- Integration/e2e path for mediator flow:
83+
- mediator/test/ltfu-flow.spec.ts
84+
85+
## Related Issues
86+
87+
- #124: Decouple OpenMRS and CHT Endpoints
88+
- #116: Allow mediators to update resources with PUT requests
89+
- #141: OpenMRS sync creates duplicate resources
Lines changed: 72 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,72 @@
1+
---
2+
id: cht-core-5904
3+
category: improvement
4+
domain: interoperability
5+
subDomain: credentials
6+
issueNumber: 5904
7+
issueUrl: https://github.com/medic/cht-core/issues/5904
8+
title: Cluster safe credentials
9+
lastUpdated: 2022-11-08
10+
summary: Integration secrets (API keys, passwords for Africa's Talking, SIH outbound push, etc.) were stored in the CouchDB node configuration (medic-credentials section) which is node-local and not replicated across cluster nodes. Shipped in CHT 4.0.0 (Nov 08, 2022) as a breaking change, credentials are now stored via a new PUT /api/v1/credentials/<key> API endpoint and kept in a cluster-replicated CouchDB location (medic-vault).
11+
services:
12+
- api
13+
- sentinel
14+
techStack:
15+
- javascript
16+
- nodejs
17+
- couchdb
18+
---
19+
20+
## Problem
21+
22+
CHT integrations that authenticate to external services (Africa's Talking SMS, SIH, outbound push targets with API key or basic auth) stored their credentials in the CouchDB node configuration under a section called `medic-credentials`. CouchDB protects this section so only admins can read it, but `local.ini` is node-local — it is not replicated across CouchDB nodes in a multi-node cluster. As CHT moved toward horizontal scalability (4.0.0 milestone), every new cluster node required manual credential configuration, and any rotation had to be applied to each node independently. The workaround was to manually set credentials on every node, which was operationally fragile.
23+
24+
## Root Cause
25+
26+
CouchDB's node configuration (`local.ini`) is intentionally not replicated — it holds machine-local settings. Using it for secrets was a pragmatic early choice that worked for single-node deployments but was not cluster-safe. There was also no structured API for setting or rotating credentials; operators wrote directly to the CouchDB node config endpoint.
27+
28+
## Solution
29+
30+
Introduced a dedicated `PUT /api/v1/credentials/<key>` API endpoint (implemented in PR #7577, merged Jul 22, 2022, shipped CHT 4.0.0). Credentials are now stored in a CouchDB document in the `medic-vault` database (or equivalent admin-only location) that replicates across cluster nodes automatically. The API endpoint accepts a plaintext credential value in the request body (`Content-Type: text/plain`) and stores it securely encrypted at rest under the given key.
31+
32+
Example usage:
33+
```bash
34+
curl -X PUT \
35+
-H "Content-Type: text/plain" \
36+
https://<user>:<pass>@<domain>/api/v1/credentials/Outbound \
37+
-d 'my-secret-value'
38+
```
39+
40+
This was a **breaking change**: existing deployments had to migrate credentials from the CouchDB node config (`medic-credentials`) to the new API before upgrading to 4.0.0. Outbound error messages were also updated to reference `medic-vault/credential:<key>` instead of the old `medic-credentials/<key>` path.
41+
42+
## Code Patterns
43+
44+
- Use `PUT /api/v1/credentials/<key>` to write a credential (admin auth required)
45+
- Use `GET /api/v1/credentials/<key>` to read a credential from application code (sentinel, API services) — never read directly from CouchDB node config after 4.0.0
46+
- The credential value is AES-256-CBC encrypted with a random 16-byte IV per write, rather than stored as plaintext. The storage format in the `medic-vault` document is `<iv_hex>:<ciphertext_hex>`.
47+
- Pattern: credentials must never appear in logs at any level (debug, info, error). The haproxy config already had a password-masking regex; ensure any new credential API path also matches that regex
48+
- Outbound push configs reference credentials by key in `password_key`; the sentinel outbound module calls the credentials API at push time, not at startup
49+
50+
## Design Choices
51+
52+
- Chose CouchDB document storage (rather than environment variables or external secret manager) because CouchDB replication handles cluster distribution automatically and is consistent with CHT's existing architecture
53+
- Made this a breaking change at 4.0.0 (alongside the horizontal scalability work) rather than transparently supporting both storage locations, to avoid a period of ambiguous credential sourcing
54+
- Scheduled for 4.0.0 specifically so it would be done alongside the cluster/scalability work (@garethbowen: "this should be done alongside the horizontal scalability work")
55+
- Admin-only access is enforced at the CouchDB layer, not in application code, so the credential document cannot be accessed by non-admin users regardless of which service is making the request
56+
- During AT (@ngaruko, Jul 2022), debug logging was found to emit credentials in plaintext. This was fixed before merge by masking the specific debug log line
57+
58+
## Related Files
59+
60+
- api/src/controllers/credentials.js
61+
- api/tests/mocha/controllers/credentials.spec.js
62+
63+
## Testing
64+
65+
- AT by @ngaruko (Jul 20, 2022) using the outbound-express support script: configured outbound push with `password_key`, set credentials via the new API, verified pushes succeeded and credentials appeared in the `medic-vault` database
66+
- Verified haproxy log masking: credentials do not appear in haproxy logs when the new API path is used
67+
- Caught and fixed during AT: debug logs were emitting the auth section (username + plaintext password) before the masking fix was applied
68+
69+
## Related Issues
70+
71+
- #5604: Integration with Africa's Talking SMS aggregator (first integration requiring the credential storage this issue improves)
72+
- #6306: Send outbound push without delay (outbound push uses credentials fetched via this mechanism)

0 commit comments

Comments
 (0)