-
Notifications
You must be signed in to change notification settings - Fork 72
RELEASE athena department ID validation #4496
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
Conversation
Ref: ENG-000 Ref: #1040 Signed-off-by: Thomas Yopes <thomasyopes@Mac.attlocal.net>
Ref: ENG-000 Ref: #1040 Signed-off-by: Thomas Yopes <thomasyopes@Mac.attlocal.net>
Ref: ENG-000 Ref: #1040 Signed-off-by: Thomas Yopes <thomasyopes@Mac.attlocal.net>
Ref: ENG-000 Ref: #1040 Signed-off-by: Thomas Yopes <thomasyopes@Mac.attlocal.net>
Ref: ENG-000 Ref: #1040 Signed-off-by: Thomas Yopes <thomasyopes@Mac.attlocal.net>
…-enforce-athena-department-ids Signed-off-by: Thomas Yopes <thomasyopes@Mac.attlocal.net>
Ref: ENG-000 Ref: #1040 Signed-off-by: Thomas Yopes <thomasyopes@Mac.attlocal.net>
…ment-ids feat(ehr): extra athenahealth validation on department id
WalkthroughRefactors EHR secondary-mapping utilities and types, introduces a generic helper to fetch and parse CX secondary mappings, adds department validation for Athena flows, updates webhook subscription flows (Elation, Healthie) to use the new helper, adjusts a domain import, and extends client credential types. Changes
Sequence Diagram(s)sequenceDiagram
autonumber
actor Caller
participant Cmd as Athena cmd (write-back/sync)
participant Shared as validateDepartmentId
participant Map as getCxMappingAndParsedSecondaryMappings
participant Mappings as CX Mapping Store
Caller->>Cmd: invoke(...)
Cmd->>Shared: validateDepartmentId({ cxId, athenaPracticeId, athenaPatientId, athenaDepartmentId })
Shared->>Map: getCxMappingAndParsedSecondaryMappings<Epic/Athena...>({ ehr: athena, practiceId })
Map->>Mappings: getCxMappingOrFail({ externalId: practiceId, source: athena })
Mappings-->>Map: cxMapping (with secondaryMappings)
Map-->>Shared: { parsedSecondaryMappings, cxMapping }
Shared->>Shared: normalize IDs and check department enabled
alt invalid department
Shared-->>Cmd: throw BadRequestError
Cmd-->>Caller: error
else valid
Shared-->>Cmd: ok
Cmd->>Cmd: createAthenaClient and proceed
Cmd-->>Caller: success
end
sequenceDiagram
autonumber
actor Caller
participant Sub as subscribeToWebhook (Elation/Healthie)
participant Helper as getCxMappingAndParsedSecondaryMappings
participant Store as CX Mapping Store
participant EHR as EHR API
Caller->>Sub: subscribeToWebhook(practiceId, resources)
Sub->>Helper: getCxMappingAndParsedSecondaryMappings<T>({ ehr, practiceId })
Helper->>Store: getCxMappingOrFail(...)
Store-->>Helper: cxMapping + secondaryMappings
Helper-->>Sub: { parsedSecondaryMappings, cxMapping }
Sub->>EHR: create/update webhook subscriptions
Sub->>Store: setSecondaryMappingsOnCxMappingById(merge parsedSecondaryMappings.webhooks)
Sub-->>Caller: done
Estimated code review effort🎯 4 (Complex) | ⏱️ ~60 minutes Possibly related PRs
Tip 🔌 Remote MCP (Model Context Protocol) integration is now available!Pro plan users can now connect to remote MCP servers from the Integrations page. Connect with popular remote MCPs such as Notion and Linear to add more context to your reviews and chats. ✨ Finishing Touches
🧪 Generate unit tests
🪧 TipsChatThere are 3 ways to chat with CodeRabbit:
SupportNeed help? Create a ticket on our support page for assistance with any issues or questions. CodeRabbit Commands (Invoked using PR/Issue comments)Type Other keywords and placeholders
CodeRabbit Configuration File (
|
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Actionable comments posted: 2
Caution
Some comments are outside the diff and can’t be posted inline due to platform limitations.
⚠️ Outside diff range comments (1)
packages/api/src/external/ehr/elation/command/subscribe-to-webhook.ts (1)
31-37
: Guard against undefined webhooks to avoid runtime spread error.If parsedSecondaryMappings.webhooks can be undefined, object spread will throw. Use nullish coalescing.
Apply:
- webhooks: { - ...parsedSecondaryMappings.webhooks, + webhooks: { + ...(parsedSecondaryMappings.webhooks ?? {}), [subscription.resource]: { url: subscription.target, signingKey: subscription.signing_pub_key, }, },
🧹 Nitpick comments (8)
packages/core/src/external/ehr/mappings.ts (1)
48-53
: General map is useful — minor naming consistency nit.eclinicalworks explicitly undefined is clear. Small nit: consider pluralizing to ehrSourcesWithSecondaryMappings for consistency with ehrSourcesWithClientCredentials (optional).
-export const ehrSourceWithSecondaryMappings = [ +export const ehrSourcesWithSecondaryMappings = [ EhrSources.athena, EhrSources.elation, EhrSources.canvas, EhrSources.healthie, ] as const; -export type EhrSourceWithSecondaryMappings = (typeof ehrSourceWithSecondaryMappings)[number]; +export type EhrSourceWithSecondaryMappings = (typeof ehrSourcesWithSecondaryMappings)[number]; export function isEhrSourceWithSecondaryMappings( ehr: string ): ehr is EhrSourceWithSecondaryMappings { - return ehrSourceWithSecondaryMappings.includes(ehr as EhrSourceWithSecondaryMappings); + return ehrSourcesWithSecondaryMappings.includes(ehr as EhrSourceWithSecondaryMappings); }packages/api/src/domain/cx-mapping.ts (1)
4-5
: Switch to general map looks right — tighten the map’s value type.Use the specific schema type to preserve compile-time safety.
-import { - EhrCxMappingSecondaryMappings, - ehrCxMappingSecondaryMappingsSchemaMapGeneral, -} from "@metriport/core/external/ehr/mappings"; +import { + EhrCxMappingSecondaryMappings, + ehrCxMappingSecondaryMappingsSchemaMapGeneral, +} from "@metriport/core/external/ehr/mappings"; export type CxMappingSecondaryMappings = EhrCxMappingSecondaryMappings | null; -export const secondaryMappingsSchemaMap: { [key in CxMappingSource]: z.Schema | undefined } = { - ...ehrCxMappingSecondaryMappingsSchemaMapGeneral, -}; +export const secondaryMappingsSchemaMap: { + [key in CxMappingSource]: z.Schema<EhrCxMappingSecondaryMappings> | undefined; +} = { + ...ehrCxMappingSecondaryMappingsSchemaMapGeneral, +};Also applies to: 15-17
packages/api/src/external/ehr/athenahealth/command/write-back/note.ts (1)
19-27
: Nice early failure; consider centralizing this pattern.These validate-then-client lines are duplicated across Athena write-backs. Consider a small wrapper to reduce repetition while keeping call sites simple.
Example wrapper usage in this file:
- await validateDepartmentId({ cxId, athenaPracticeId, athenaPatientId, athenaDepartmentId }); - const api = await createAthenaClient({ cxId, practiceId: athenaPracticeId }); + const api = await withValidatedDepartment( + { cxId, athenaPracticeId, athenaPatientId, athenaDepartmentId }, + () => createAthenaClient({ cxId, practiceId: athenaPracticeId }) + );(Wrapper could live under ../../shared.)
packages/api/src/external/ehr/athenahealth/command/write-back/lab.ts (1)
18-26
: Pre-validation is correct; please cover with tests.Add cases mirroring note/immunization to ensure failures short-circuit before API calls.
If you introduce the suggested wrapper, update here too to remove duplication.
packages/api/src/external/ehr/shared/command/mapping/get-cx-mapping-and-secondary-mappings.ts (1)
34-39
: Minor typing improvement to avoidas T
cast (optional).You can type the schema as z.Schema to remove the post-parse cast.
Apply:
+import type { z } from "zod"; @@ - const schema = ehrCxMappingSecondaryMappingsSchemaMap[ehr]; + const schema = ehrCxMappingSecondaryMappingsSchemaMap[ehr] as z.Schema<T>; return { - parsedSecondaryMappings: schema.parse(cxMapping.secondaryMappings) as T, + parsedSecondaryMappings: schema.parse(cxMapping.secondaryMappings), cxMapping, };packages/api/src/external/ehr/athenahealth/shared.ts (2)
4-7
: Unify EhrSources import path for consistencyOther files (e.g., Healthie) import EhrSources from the interface path. Align here to reduce import churn.
-import { BadRequestError, EhrSources, MetriportError } from "@metriport/shared"; +import { BadRequestError, MetriportError } from "@metriport/shared"; +import { EhrSources } from "@metriport/shared/interface/external/ehr/source";
72-84
: Confirm “allow-all when unset” semantics and enrich context
- Confirm that empty departmentIds means “no restriction.” If intentional, add a short comment.
- Consider adding allowed departmentIds to additionalInfo to speed up support triage.
- if (departmentIds.length > 0 && !departmentIds.includes(strippedDepartmentId)) { + // Empty list => no restriction (intended). + if (departmentIds.length > 0 && !departmentIds.includes(strippedDepartmentId)) { throw new BadRequestError( "AthenaHealth patient is not in a department that is enabled", undefined, { cxId, athenaPracticeId, athenaPatientId, athenaDepartmentId, + allowedDepartmentIds: departmentIds, } ); }packages/api/src/external/ehr/healthie/command/subscribe-to-webhook.ts (1)
41-49
: Avoid accidental overwrite on concurrent updatessetSecondaryMappingsOnCxMappingById appears to write the whole object. If multiple webhook subscriptions run concurrently, last-write-wins may drop keys. Prefer a read–merge–write with server-side merge/patch or optimistic concurrency (ETag/version).
If supported, patch only webhooks:
await setSecondaryMappingsOnCxMappingById({ cxId, id: cxMapping.id, - secondaryMappings: { - ...parsedSecondaryMappings, - webhooks: { - ...parsedSecondaryMappings.webhooks, - [eventType]: { url, secretKey }, - }, - }, + secondaryMappings: { + webhooks: { + ...parsedSecondaryMappings.webhooks, + [eventType]: { url, secretKey }, + }, + }, // ensure server merges instead of replacing });
📜 Review details
Configuration used: CodeRabbit UI
Review profile: CHILL
Plan: Pro
💡 Knowledge Base configuration:
- MCP integration is disabled by default for public repositories
- Jira integration is disabled
- Linear integration is disabled
You can enable these sources in your CodeRabbit configuration.
📒 Files selected for processing (17)
packages/api/src/domain/cx-mapping.ts
(2 hunks)packages/api/src/external/ehr/athenahealth/command/sync-patient.ts
(2 hunks)packages/api/src/external/ehr/athenahealth/command/write-back/allergy.ts
(2 hunks)packages/api/src/external/ehr/athenahealth/command/write-back/condition.ts
(2 hunks)packages/api/src/external/ehr/athenahealth/command/write-back/immunization.ts
(2 hunks)packages/api/src/external/ehr/athenahealth/command/write-back/lab.ts
(2 hunks)packages/api/src/external/ehr/athenahealth/command/write-back/medication.ts
(2 hunks)packages/api/src/external/ehr/athenahealth/command/write-back/note.ts
(2 hunks)packages/api/src/external/ehr/athenahealth/command/write-back/procedure.ts
(2 hunks)packages/api/src/external/ehr/athenahealth/command/write-back/vitals.ts
(2 hunks)packages/api/src/external/ehr/athenahealth/shared.ts
(2 hunks)packages/api/src/external/ehr/elation/command/subscribe-to-webhook.ts
(2 hunks)packages/api/src/external/ehr/healthie/command/subscribe-to-webhook.ts
(3 hunks)packages/api/src/external/ehr/shared/command/mapping/get-cx-mapping-and-secondary-mappings.ts
(1 hunks)packages/core/src/external/ehr/environment.ts
(1 hunks)packages/core/src/external/ehr/job/bundle/write-back-bundles/ehr-write-back-resource-diff-bundles-direct.ts
(2 hunks)packages/core/src/external/ehr/mappings.ts
(1 hunks)
🧰 Additional context used
📓 Path-based instructions (3)
**/*.{js,jsx,ts,tsx}
📄 CodeRabbit inference engine (.cursorrules)
**/*.{js,jsx,ts,tsx}
: Don’t use null inside the app, only on code interacting with external interfaces/services, like DB and HTTP; convert to undefined before sending inwards into the code
Useconst
whenever possible
Useasync/await
instead of.then()
Naming: classes, enums: PascalCase
Naming: constants, variables, functions: camelCase
Naming: file names: kebab-case
Naming: Don’t use negative names, likenotEnabled
, preferisDisabled
If possible, use decomposing objects for function parameters
Prefer Nullish Coalesce (??) than the OR operator (||) when you want to provide a default value
Avoid creating arrow functions
Use truthy syntax instead ofin
- i.e.,if (data.link)
notif ('link' in data)
While handling errors, keep the stack trace around: if you create a new Error (e.g., MetriportError), make sure to pass the original error as the new one’s cause so the stack trace is available upstream.
max column length is 100 chars
multi-line comments use/** */
top-level comments go after the import (save pre-import to basic file header, like license)
move literals to constants declared after imports when possible
Files:
packages/api/src/external/ehr/shared/command/mapping/get-cx-mapping-and-secondary-mappings.ts
packages/api/src/external/ehr/athenahealth/command/write-back/medication.ts
packages/api/src/external/ehr/athenahealth/command/write-back/procedure.ts
packages/api/src/external/ehr/athenahealth/command/write-back/lab.ts
packages/api/src/external/ehr/athenahealth/command/write-back/immunization.ts
packages/api/src/external/ehr/athenahealth/command/write-back/vitals.ts
packages/api/src/external/ehr/athenahealth/command/write-back/note.ts
packages/core/src/external/ehr/mappings.ts
packages/api/src/external/ehr/athenahealth/shared.ts
packages/api/src/external/ehr/athenahealth/command/write-back/condition.ts
packages/api/src/external/ehr/athenahealth/command/write-back/allergy.ts
packages/core/src/external/ehr/environment.ts
packages/api/src/external/ehr/elation/command/subscribe-to-webhook.ts
packages/api/src/domain/cx-mapping.ts
packages/api/src/external/ehr/athenahealth/command/sync-patient.ts
packages/core/src/external/ehr/job/bundle/write-back-bundles/ehr-write-back-resource-diff-bundles-direct.ts
packages/api/src/external/ehr/healthie/command/subscribe-to-webhook.ts
**/*.{ts,tsx}
📄 CodeRabbit inference engine (.cursorrules)
Use types whenever possible
Files:
packages/api/src/external/ehr/shared/command/mapping/get-cx-mapping-and-secondary-mappings.ts
packages/api/src/external/ehr/athenahealth/command/write-back/medication.ts
packages/api/src/external/ehr/athenahealth/command/write-back/procedure.ts
packages/api/src/external/ehr/athenahealth/command/write-back/lab.ts
packages/api/src/external/ehr/athenahealth/command/write-back/immunization.ts
packages/api/src/external/ehr/athenahealth/command/write-back/vitals.ts
packages/api/src/external/ehr/athenahealth/command/write-back/note.ts
packages/core/src/external/ehr/mappings.ts
packages/api/src/external/ehr/athenahealth/shared.ts
packages/api/src/external/ehr/athenahealth/command/write-back/condition.ts
packages/api/src/external/ehr/athenahealth/command/write-back/allergy.ts
packages/core/src/external/ehr/environment.ts
packages/api/src/external/ehr/elation/command/subscribe-to-webhook.ts
packages/api/src/domain/cx-mapping.ts
packages/api/src/external/ehr/athenahealth/command/sync-patient.ts
packages/core/src/external/ehr/job/bundle/write-back-bundles/ehr-write-back-resource-diff-bundles-direct.ts
packages/api/src/external/ehr/healthie/command/subscribe-to-webhook.ts
**/*.ts
⚙️ CodeRabbit configuration file
**/*.ts
: - Use the Onion Pattern to organize a package's code in layers
- Try to use immutable code and avoid sharing state across different functions, objects, and systems
- Try to build code that's idempotent whenever possible
- Prefer functional programming style functions: small, deterministic, 1 input, 1 output
- Minimize coupling / dependencies
- Avoid modifying objects received as parameter
- Only add comments to code to explain why something was done, not how it works
- Naming
- classes, enums:
PascalCase
- constants, variables, functions:
camelCase
- file names:
kebab-case
- table and column names:
snake_case
- Use meaningful names, so whoever is reading the code understands what it means
- Don’t use negative names, like
notEnabled
, preferisDisabled
- For numeric values, if the type doesn’t convey the unit, add the unit to the name
- Typescript
- Use types
- Prefer
const
instead oflet
- Avoid
any
and casting fromany
to other types- Type predicates: only applicable to narrow down the type, not to force a complete type conversion
- Prefer deconstructing parameters for functions instead of multiple parameters that might be of
the same type- Don’t use
null
inside the app, only on code interacting with external interfaces/services,
like DB and HTTP; convert toundefined
before sending inwards into the code- Use
async/await
instead of.then()
- Use the strict equality operator
===
, don’t use abstract equality operator==
- When calling a Promise-returning function asynchronously (i.e., not awaiting), use
.catch()
to
handle errors (seeprocessAsyncError
andemptyFunction
depending on the case)- Date and Time
- Always use
buildDayjs()
to createdayjs
instances- Prefer
dayjs.duration(...)
to create duration consts and keep them asduration
- Prefer Nullish Coalesce (??) than the OR operator (||) to provide a default value
- Avoid creating arrow functions
- U...
Files:
packages/api/src/external/ehr/shared/command/mapping/get-cx-mapping-and-secondary-mappings.ts
packages/api/src/external/ehr/athenahealth/command/write-back/medication.ts
packages/api/src/external/ehr/athenahealth/command/write-back/procedure.ts
packages/api/src/external/ehr/athenahealth/command/write-back/lab.ts
packages/api/src/external/ehr/athenahealth/command/write-back/immunization.ts
packages/api/src/external/ehr/athenahealth/command/write-back/vitals.ts
packages/api/src/external/ehr/athenahealth/command/write-back/note.ts
packages/core/src/external/ehr/mappings.ts
packages/api/src/external/ehr/athenahealth/shared.ts
packages/api/src/external/ehr/athenahealth/command/write-back/condition.ts
packages/api/src/external/ehr/athenahealth/command/write-back/allergy.ts
packages/core/src/external/ehr/environment.ts
packages/api/src/external/ehr/elation/command/subscribe-to-webhook.ts
packages/api/src/domain/cx-mapping.ts
packages/api/src/external/ehr/athenahealth/command/sync-patient.ts
packages/core/src/external/ehr/job/bundle/write-back-bundles/ehr-write-back-resource-diff-bundles-direct.ts
packages/api/src/external/ehr/healthie/command/subscribe-to-webhook.ts
🧠 Learnings (25)
📓 Common learnings
Learnt from: thomasyopes
PR: metriport/metriport#4483
File: packages/api/src/external/ehr/athenahealth/shared.ts:0-0
Timestamp: 2025-08-29T16:12:38.209Z
Learning: In Athena secondary mappings (packages/api/src/external/ehr/athenahealth/shared.ts), departmentIds is parsed via zod schema validation, so it will not be undefined and doesn't need null coalescing (departmentIds ?? []).
Learnt from: thomasyopes
PR: metriport/metriport#4478
File: package.json:14-16
Timestamp: 2025-08-27T23:20:44.517Z
Learning: thomasyopes prefers maintaining consistency with existing codebase patterns over introducing new approaches, even when the new approach might be technically cleaner (e.g., using workspace commands vs cd patterns).
Learnt from: thomasyopes
PR: metriport/metriport#4478
File: packages/core/src/external/ehr/elation/index.ts:639-657
Timestamp: 2025-08-27T23:18:23.105Z
Learning: thomasyopes prefers allowing mutation in reduce accumulators when it's the intended pattern, rather than forcing immutable approaches that may be unnecessarily complex.
📚 Learning: 2025-06-06T16:45:31.832Z
Learnt from: thomasyopes
PR: metriport/metriport#3970
File: packages/api/src/external/ehr/athenahealth/command/write-back/medication.ts:17-17
Timestamp: 2025-06-06T16:45:31.832Z
Learning: The writeMedicationToChart function in packages/api/src/external/ehr/athenahealth/command/write-back/medication.ts returns a response that is not currently used by any consumers, so changes to its return type are not breaking changes in practice.
Applied to files:
packages/api/src/external/ehr/athenahealth/command/write-back/medication.ts
packages/api/src/external/ehr/athenahealth/command/write-back/procedure.ts
packages/api/src/external/ehr/athenahealth/command/write-back/lab.ts
packages/api/src/external/ehr/athenahealth/command/write-back/immunization.ts
packages/api/src/external/ehr/athenahealth/command/write-back/vitals.ts
packages/api/src/external/ehr/athenahealth/command/write-back/note.ts
packages/api/src/external/ehr/athenahealth/command/write-back/condition.ts
packages/api/src/external/ehr/athenahealth/command/write-back/allergy.ts
packages/api/src/external/ehr/athenahealth/command/sync-patient.ts
packages/core/src/external/ehr/job/bundle/write-back-bundles/ehr-write-back-resource-diff-bundles-direct.ts
📚 Learning: 2025-08-29T16:12:38.209Z
Learnt from: thomasyopes
PR: metriport/metriport#4483
File: packages/api/src/external/ehr/athenahealth/shared.ts:0-0
Timestamp: 2025-08-29T16:12:38.209Z
Learning: In Athena secondary mappings (packages/api/src/external/ehr/athenahealth/shared.ts), departmentIds is parsed via zod schema validation, so it will not be undefined and doesn't need null coalescing (departmentIds ?? []).
Applied to files:
packages/api/src/external/ehr/athenahealth/command/write-back/medication.ts
packages/api/src/external/ehr/athenahealth/command/write-back/procedure.ts
packages/api/src/external/ehr/athenahealth/command/write-back/lab.ts
packages/api/src/external/ehr/athenahealth/command/write-back/immunization.ts
packages/api/src/external/ehr/athenahealth/command/write-back/vitals.ts
packages/api/src/external/ehr/athenahealth/command/write-back/note.ts
packages/core/src/external/ehr/mappings.ts
packages/api/src/external/ehr/athenahealth/shared.ts
packages/api/src/external/ehr/athenahealth/command/write-back/condition.ts
packages/api/src/external/ehr/athenahealth/command/write-back/allergy.ts
packages/api/src/external/ehr/athenahealth/command/sync-patient.ts
📚 Learning: 2025-05-20T21:26:26.804Z
Learnt from: leite08
PR: metriport/metriport#3814
File: packages/api/src/routes/internal/medical/patient-consolidated.ts:141-174
Timestamp: 2025-05-20T21:26:26.804Z
Learning: The functionality introduced in packages/api/src/routes/internal/medical/patient-consolidated.ts is planned to be refactored in downstream PR #3857, including improvements to error handling and validation.
Applied to files:
packages/api/src/external/ehr/athenahealth/command/write-back/medication.ts
packages/api/src/external/ehr/athenahealth/shared.ts
packages/api/src/external/ehr/athenahealth/command/sync-patient.ts
📚 Learning: 2025-06-25T18:42:07.231Z
Learnt from: keshavsaharia
PR: metriport/metriport#4075
File: packages/core/src/external/surescripts/fhir/medication-request.ts:76-83
Timestamp: 2025-06-25T18:42:07.231Z
Learning: In packages/core/src/external/surescripts/fhir/medication-request.ts, the getDispenseNote and getDosageInstruction functions are intentionally identical because the dashboard requires both the note and dosageInstruction fields of MedicationRequest to be populated with detail.directions for proper note display functionality.
Applied to files:
packages/api/src/external/ehr/athenahealth/command/write-back/medication.ts
📚 Learning: 2025-05-28T19:06:02.261Z
Learnt from: thomasyopes
PR: metriport/metriport#3882
File: packages/api/src/external/ehr/athenahealth/command/process-patients-from-appointments.ts:178-180
Timestamp: 2025-05-28T19:06:02.261Z
Learning: In Athena appointments, the `patientid` and `departmentid` fields will always be defined, so null checks are not necessary when calling `createPatientId()` and `createDepartmentId()` on these fields.
Applied to files:
packages/api/src/external/ehr/athenahealth/command/write-back/medication.ts
packages/api/src/external/ehr/athenahealth/command/write-back/procedure.ts
packages/api/src/external/ehr/athenahealth/command/write-back/lab.ts
packages/api/src/external/ehr/athenahealth/shared.ts
packages/api/src/external/ehr/athenahealth/command/write-back/condition.ts
packages/api/src/external/ehr/athenahealth/command/sync-patient.ts
📚 Learning: 2025-07-09T17:18:16.731Z
Learnt from: thomasyopes
PR: metriport/metriport#4164
File: packages/core/src/external/ehr/healthie/index.ts:939-953
Timestamp: 2025-07-09T17:18:16.731Z
Learning: In packages/core/src/external/ehr/healthie/index.ts, the immunization.cvx_code field is required and non-nullable according to the zod schema validation (z.coerce.string()), so null checks are not needed in the convertImmunizationToFhir method.
Applied to files:
packages/api/src/external/ehr/athenahealth/command/write-back/immunization.ts
📚 Learning: 2025-08-15T00:00:45.080Z
Learnt from: keshavsaharia
PR: metriport/metriport#4370
File: packages/shared/src/domain/patient.ts:5-5
Timestamp: 2025-08-15T00:00:45.080Z
Learning: The patientSchema in packages/shared/src/domain/patient.ts is used in a limited subsystem scope ("SS") and is not the same as other Patient schemas referenced throughout the codebase, making additive optional field changes like externalId safe and non-breaking.
Applied to files:
packages/core/src/external/ehr/mappings.ts
packages/api/src/external/ehr/athenahealth/command/sync-patient.ts
📚 Learning: 2025-08-25T17:29:10.848Z
Learnt from: thomasyopes
PR: metriport/metriport#4451
File: packages/core/src/external/ehr/command/get-client-token-info.ts:20-21
Timestamp: 2025-08-25T17:29:10.848Z
Learning: In the EHR integration architecture, OAuth-based providers (Canvas, Athena, Elation) are separated from API-key based providers (Healthie, eClinicalWorks) using type guards like `isEhrSourceWithClientCredentials()`. The `EhrSourceWithClientCredentials` union type only includes OAuth providers, allowing JWT token info retrieval flows to be cleanly separated from API-key authentication flows.
Applied to files:
packages/core/src/external/ehr/mappings.ts
packages/core/src/external/ehr/environment.ts
📚 Learning: 2025-08-13T21:37:33.680Z
Learnt from: thomasyopes
PR: metriport/metriport#4346
File: packages/core/src/external/ehr/athenahealth/command/get-bundle-by-resource-type.ts:25-29
Timestamp: 2025-08-13T21:37:33.680Z
Learning: In Athena EHR integration (packages/core/src/external/ehr/athenahealth/command/get-bundle-by-resource-type.ts), thomasyopes prefers hard-failing when secondary mappings fetch fails rather than graceful degradation, because these mappings control critical behaviors like contributionEncounterAppointmentTypesBlacklist and contributionEncounterSummariesEnabled. Running with default values when mappings are unavailable could lead to incorrect processing.
Applied to files:
packages/api/src/external/ehr/athenahealth/shared.ts
packages/core/src/external/ehr/job/bundle/write-back-bundles/ehr-write-back-resource-diff-bundles-direct.ts
📚 Learning: 2025-04-16T00:25:25.196Z
Learnt from: RamilGaripov
PR: metriport/metriport#3676
File: packages/core/src/command/hl7v2-subscriptions/hl7v2-to-fhir-conversion/shared.ts:1-10
Timestamp: 2025-04-16T00:25:25.196Z
Learning: The circular dependency between shared.ts (importing getPatientIdsOrFail) and adt/utils.ts (using unpackPidFieldOrFail) will be addressed in a follow-up PR.
Applied to files:
packages/api/src/external/ehr/athenahealth/shared.ts
📚 Learning: 2025-06-11T21:39:26.805Z
Learnt from: thomasyopes
PR: metriport/metriport#4000
File: packages/core/src/external/ehr/athenahealth/index.ts:504-507
Timestamp: 2025-06-11T21:39:26.805Z
Learning: In AthenaHealth write-back (`packages/core/src/external/ehr/athenahealth/index.ts`), only the condition statuses “relapse” and “recurrence” are currently mapped to AthenaHealth problem statuses (“CHRONIC”); other FHIR clinicalStatus values (e.g., “active”, “resolved”, “inactive”, “remission”) are not yet supported.
Applied to files:
packages/api/src/external/ehr/athenahealth/command/write-back/condition.ts
📚 Learning: 2025-08-26T17:43:13.189Z
Learnt from: thomasyopes
PR: metriport/metriport#4451
File: packages/core/src/external/ehr/api/get-client-key-and-secret.ts:0-0
Timestamp: 2025-08-26T17:43:13.189Z
Learning: In packages/core/src/external/ehr/api/get-client-key-and-secret.ts, the masking logic has been updated to be more secure than initially suggested. The getNumberOfCharactersToShow function correctly implements complete masking (0 characters) for short secrets and proportional masking for longer ones, following the "fail secure" principle better than showing a minimum number of characters.
Applied to files:
packages/core/src/external/ehr/environment.ts
📚 Learning: 2025-05-27T16:10:48.223Z
Learnt from: lucasdellabella
PR: metriport/metriport#3866
File: packages/core/src/command/hl7v2-subscriptions/hl7v2-roster-generator.ts:142-151
Timestamp: 2025-05-27T16:10:48.223Z
Learning: In packages/core/src/command/hl7v2-subscriptions/hl7v2-roster-generator.ts, the user prefers to let axios errors bubble up naturally rather than adding try-catch blocks that re-throw with MetriportError wrappers, especially when the calling code already has retry mechanisms in place via simpleExecuteWithRetries.
Applied to files:
packages/api/src/external/ehr/elation/command/subscribe-to-webhook.ts
packages/api/src/external/ehr/healthie/command/subscribe-to-webhook.ts
📚 Learning: 2025-08-25T18:29:06.278Z
Learnt from: thomasyopes
PR: metriport/metriport#4458
File: packages/api/src/external/ehr/elation/command/sync-patient.ts:0-0
Timestamp: 2025-08-25T18:29:06.278Z
Learning: The `inputMetriportPatientId` parameter in `syncElationPatientIntoMetriport` and `syncHealthiePatientIntoMetriport` functions is meant for optional validation in `getOrCreateMetriportPatient`, not as a required parameter that call sites need to explicitly map. It can remain undefined/unmapped at call sites and the function will work correctly without it.
Applied to files:
packages/api/src/external/ehr/athenahealth/command/sync-patient.ts
📚 Learning: 2025-07-30T14:51:29.865Z
Learnt from: RamilGaripov
PR: metriport/metriport#4187
File: packages/api/src/command/medical/patient/map-patient.ts:41-49
Timestamp: 2025-07-30T14:51:29.865Z
Learning: In the syncElationPatientIntoMetriport and syncHealthiePatientIntoMetriport functions, the patientId parameter is intended to receive the Metriport patient ID for demographic validation purposes via confirmPatientMatch, not the external system patient ID. The external patient ID should be passed through the specific external ID parameters (elationPatientId, healthiePatientId, etc.).
Applied to files:
packages/api/src/external/ehr/athenahealth/command/sync-patient.ts
📚 Learning: 2025-07-30T14:51:35.852Z
Learnt from: RamilGaripov
PR: metriport/metriport#4187
File: packages/api/src/command/medical/patient/map-patient.ts:50-59
Timestamp: 2025-07-30T14:51:35.852Z
Learning: In the EHR sync functions like syncHealthiePatientIntoMetriport and syncElationPatientIntoMetriport, the optional patientId parameter is intended to receive the Metriport patient ID (not the external patient ID) for patient match confirmation purposes via the confirmPatientMatch function.
Applied to files:
packages/api/src/external/ehr/athenahealth/command/sync-patient.ts
📚 Learning: 2025-03-11T20:42:46.516Z
Learnt from: thomasyopes
PR: metriport/metriport#3427
File: packages/core/src/external/ehr/api/sync-patient.ts:16-55
Timestamp: 2025-03-11T20:42:46.516Z
Learning: In the patient synchronization architecture, the flow follows this pattern: (1) `ehr-sync-patient-cloud.ts` sends messages to an SQS queue, (2) the `ehr-sync-patient` Lambda consumes these messages, and (3) the Lambda uses the `syncPatient` function to make the API calls to process the patient data.
Applied to files:
packages/api/src/external/ehr/athenahealth/command/sync-patient.ts
📚 Learning: 2025-05-19T13:53:09.828Z
Learnt from: leite08
PR: metriport/metriport#3814
File: packages/core/src/command/consolidated/search/fhir-resource/search-semantic.ts:36-36
Timestamp: 2025-05-19T13:53:09.828Z
Learning: In the `getConsolidatedPatientData` function from `metriport/core/command/consolidated/consolidated-get`, only the `patient` parameter is required. Other parameters like `requestId`, `resources`, `dateFrom`, `dateTo`, `fromDashboard`, and `forceDataFromFhir` are all optional.
Applied to files:
packages/api/src/external/ehr/athenahealth/command/sync-patient.ts
📚 Learning: 2025-06-03T21:02:23.374Z
Learnt from: leite08
PR: metriport/metriport#3953
File: packages/core/src/command/consolidated/search/fhir-resource/__tests__/search-consolidated-setup.ts:28-30
Timestamp: 2025-06-03T21:02:23.374Z
Learning: The `makePatient()` function returns `PatientWithId` type which requires the `id` field to be present, ensuring `patient.id` is never undefined.
Applied to files:
packages/api/src/external/ehr/athenahealth/command/sync-patient.ts
📚 Learning: 2025-08-25T23:28:41.385Z
Learnt from: keshavsaharia
PR: metriport/metriport#4459
File: packages/core/src/external/quest/fhir/patient.ts:22-24
Timestamp: 2025-08-25T23:28:41.385Z
Learning: FHIR resources should have their ID field determined by `uuidv7()` generated UUIDs. The import should be: `import { uuidv7 } from "metriport/shared/util/uuid-v7";`. External system IDs should not be used directly as FHIR resource IDs, even when sanitized, but should instead be preserved in the identifier field for reference mapping.
Applied to files:
packages/api/src/external/ehr/athenahealth/command/sync-patient.ts
📚 Learning: 2025-06-19T22:44:49.393Z
Learnt from: thomasyopes
PR: metriport/metriport#4061
File: packages/api/src/external/ehr/shared/job/bundle/create-resource-diff-bundles/run-job.ts:34-47
Timestamp: 2025-06-19T22:44:49.393Z
Learning: In packages/api/src/external/ehr/shared/job/bundle/create-resource-diff-bundles/run-job.ts, the team prefers to keep refreshEhrBundles operations grouped using fire-and-forget pattern rather than awaiting all operations with Promise.allSettled(). This allows individual refresh operations to run independently without blocking the job runner.
Applied to files:
packages/core/src/external/ehr/job/bundle/write-back-bundles/ehr-write-back-resource-diff-bundles-direct.ts
📚 Learning: 2025-08-25T17:29:25.387Z
Learnt from: thomasyopes
PR: metriport/metriport#4451
File: packages/core/src/external/ehr/job/bundle/write-back-bundles/ehr-write-back-resource-diff-bundles-direct.ts:143-151
Timestamp: 2025-08-25T17:29:25.387Z
Learning: In packages/core/src/external/ehr/job/bundle/write-back-bundles/ehr-write-back-resource-diff-bundles-direct.ts, the filterObservations function with vital.latestOnly=true is designed to keep only the most recent observation per LOINC code across all dates, not per date+LOINC pair. This behavior intentionally collapses multiple days into a single latest reading per code.
Applied to files:
packages/core/src/external/ehr/job/bundle/write-back-bundles/ehr-write-back-resource-diff-bundles-direct.ts
📚 Learning: 2025-08-12T17:28:06.150Z
Learnt from: thomasyopes
PR: metriport/metriport#4358
File: packages/core/src/external/ehr/command/write-back/shared.ts:21-21
Timestamp: 2025-08-12T17:28:06.150Z
Learning: In packages/core/src/external/ehr/command/write-back/shared.ts, the WriteBackResourceRequest.primaryResourceOrResources field deliberately uses the generic tuple [Date, Resource[]] instead of the more specific GroupedVitalsByDate type ([Date, Observation[]]) to keep the shared interface flexible for potentially grouping different resource types by date in the future.
Applied to files:
packages/core/src/external/ehr/job/bundle/write-back-bundles/ehr-write-back-resource-diff-bundles-direct.ts
📚 Learning: 2025-05-01T16:10:45.273Z
Learnt from: thomasyopes
PR: metriport/metriport#3771
File: packages/core/src/util/webhook.ts:34-45
Timestamp: 2025-05-01T16:10:45.273Z
Learning: The webhook signature verification code in packages/core/src/util/webhook.ts is copied directly from Healthie's documentation and should not be modified to maintain exact compliance with their implementation.
Applied to files:
packages/api/src/external/ehr/healthie/command/subscribe-to-webhook.ts
🧬 Code graph analysis (16)
packages/api/src/external/ehr/shared/command/mapping/get-cx-mapping-and-secondary-mappings.ts (4)
packages/core/src/external/ehr/mappings.ts (3)
EhrCxMappingSecondaryMappings
(33-37)EhrSourceWithSecondaryMappings
(26-26)ehrCxMappingSecondaryMappingsSchemaMap
(39-46)packages/api/src/domain/cx-mapping.ts (1)
CxMapping
(26-26)packages/api/src/command/mapping/cx.ts (1)
getCxMappingOrFail
(54-63)packages/shared/src/index.ts (1)
MetriportError
(43-43)
packages/api/src/external/ehr/athenahealth/command/write-back/medication.ts (1)
packages/api/src/external/ehr/athenahealth/shared.ts (1)
validateDepartmentId
(50-84)
packages/api/src/external/ehr/athenahealth/command/write-back/procedure.ts (1)
packages/api/src/external/ehr/athenahealth/shared.ts (1)
validateDepartmentId
(50-84)
packages/api/src/external/ehr/athenahealth/command/write-back/lab.ts (1)
packages/api/src/external/ehr/athenahealth/shared.ts (1)
validateDepartmentId
(50-84)
packages/api/src/external/ehr/athenahealth/command/write-back/immunization.ts (1)
packages/api/src/external/ehr/athenahealth/shared.ts (1)
validateDepartmentId
(50-84)
packages/api/src/external/ehr/athenahealth/command/write-back/vitals.ts (1)
packages/api/src/external/ehr/athenahealth/shared.ts (1)
validateDepartmentId
(50-84)
packages/api/src/external/ehr/athenahealth/command/write-back/note.ts (1)
packages/api/src/external/ehr/athenahealth/shared.ts (1)
validateDepartmentId
(50-84)
packages/core/src/external/ehr/mappings.ts (5)
packages/shared/src/interface/external/ehr/athenahealth/cx-mapping.ts (2)
AthenaSecondaryMappings
(14-14)athenaSecondaryMappingsSchema
(4-13)packages/shared/src/interface/external/ehr/canvas/cx-mapping.ts (2)
CanavsSecondaryMappings
(5-5)canvasSecondaryMappingsSchema
(4-4)packages/shared/src/interface/external/ehr/elation/cx-mapping.ts (2)
ElationSecondaryMappings
(23-23)elationSecondaryMappingsSchema
(10-22)packages/shared/src/interface/external/ehr/healthie/cx-mapping.ts (2)
HealthieSecondaryMappings
(24-24)healthieSecondaryMappingsSchema
(10-23)packages/shared/src/interface/external/ehr/source.ts (1)
EhrSource
(11-11)
packages/api/src/external/ehr/athenahealth/shared.ts (2)
packages/api/src/external/ehr/shared/command/mapping/get-cx-mapping-and-secondary-mappings.ts (1)
getCxMappingAndParsedSecondaryMappings
(17-39)packages/shared/src/interface/external/ehr/athenahealth/cx-mapping.ts (1)
AthenaSecondaryMappings
(14-14)
packages/api/src/external/ehr/athenahealth/command/write-back/condition.ts (1)
packages/api/src/external/ehr/athenahealth/shared.ts (1)
validateDepartmentId
(50-84)
packages/api/src/external/ehr/athenahealth/command/write-back/allergy.ts (1)
packages/api/src/external/ehr/athenahealth/shared.ts (1)
validateDepartmentId
(50-84)
packages/api/src/external/ehr/elation/command/subscribe-to-webhook.ts (3)
packages/api/src/external/ehr/shared/command/mapping/get-cx-mapping-and-secondary-mappings.ts (1)
getCxMappingAndParsedSecondaryMappings
(17-39)packages/shared/src/interface/external/ehr/elation/cx-mapping.ts (1)
ElationSecondaryMappings
(23-23)packages/api/src/command/mapping/cx.ts (1)
setSecondaryMappingsOnCxMappingById
(155-172)
packages/api/src/domain/cx-mapping.ts (1)
packages/core/src/external/ehr/mappings.ts (1)
ehrCxMappingSecondaryMappingsSchemaMapGeneral
(48-53)
packages/api/src/external/ehr/athenahealth/command/sync-patient.ts (1)
packages/api/src/external/ehr/athenahealth/shared.ts (1)
validateDepartmentId
(50-84)
packages/core/src/external/ehr/job/bundle/write-back-bundles/ehr-write-back-resource-diff-bundles-direct.ts (1)
packages/core/src/external/ehr/mappings.ts (1)
isEhrSourceWithSecondaryMappings
(27-31)
packages/api/src/external/ehr/healthie/command/subscribe-to-webhook.ts (2)
packages/api/src/external/ehr/shared/command/mapping/get-cx-mapping-and-secondary-mappings.ts (1)
getCxMappingAndParsedSecondaryMappings
(17-39)packages/shared/src/interface/external/ehr/healthie/cx-mapping.ts (1)
HealthieSecondaryMappings
(24-24)
⏰ Context from checks skipped due to timeout of 90000ms. You can increase the timeout in your CodeRabbit configuration to a maximum of 15 minutes (900000ms). (7)
- GitHub Check: check-pr / lint-build-test
- GitHub Check: check-pr / lint-build-test
- GitHub Check: Analyze (javascript)
- GitHub Check: ihe_stack / deploy
- GitHub Check: infra-api-lambdas / deploy
- GitHub Check: api / deploy
- GitHub Check: mllp-server / deploy
🔇 Additional comments (22)
packages/core/src/external/ehr/environment.ts (1)
23-27
: Ensure clientSecret is passed at all call sites and avoid logging it.
- Verified constructors/use-sites in
• packages/core/src/external/ehr/environment.ts
• packages/core/src/external/ehr/elation/environment.ts
• packages/core/src/external/ehr/canvas/environment.ts
• packages/core/src/external/ehr/athenahealth/environment.ts
• packages/core/src/external/ehr/command/get-secrets.ts
• packages/api/src/external/ehr/shared/utils/client.ts
now requireclientSecret
.- Confirm none of these functions or their callers log or emit the secret in metrics.
- Add a credentials-masking helper for any debug output that touches these values.
packages/core/src/external/ehr/mappings.ts (2)
20-31
: Good introduction of “with secondary mappings” guard.Solid separation of sources that actually support secondary mappings. This enables safe short-circuiting downstream.
39-46
: Narrowed schema map is correct — types align with supported EHRs.The keyed map to z.Schema looks right and pairs well with the guard.
packages/core/src/external/ehr/job/bundle/write-back-bundles/ehr-write-back-resource-diff-bundles-direct.ts (2)
41-44
: Importing the guard is correct — keeps lookups scoped to capable EHRs.Ensures we don’t attempt schema lookups for sources that don’t support secondary mappings.
302-327
: Early return for non-supporting EHRs is appropriate — behavior aligns with prior hard-fail policy.
- For EHRs without secondary mappings: returns undefined filters, leading to permissive write-back (intended).
- For supporting EHRs: still hard-fails if schema/mappings are absent or writeBackEnabled=false — consistent with earlier Athena stance.
If desired, add a unit test to assert that eclinicalworks skips mappings while athena requires them. I can draft tests.
packages/api/src/external/ehr/athenahealth/command/write-back/procedure.ts (1)
3-3
: Pre-validating departmentId before client init is implemented consistently
validateDepartmentId is now applied in all Athena write-back commands (allergy, condition, immunization, lab, medication, note, vitals, procedure), ensuring fail-fast behavior. departmentIds is guaranteed by zod, so no nullish fallback is required downstream.packages/api/src/external/ehr/athenahealth/command/write-back/vitals.ts (1)
3-3
: Pre-validation added in the right spot; parameters look correct.Validating the Athena department before creating the client is a good fail-fast guard and aligns with the secondary mapping contract. LGTM.
Also applies to: 18-18
packages/api/src/external/ehr/athenahealth/command/write-back/medication.ts (1)
3-3
: Good fail-fast department validation prior to API calls.The new validation call and import are correct and consistent with the shared validator. No issues spotted.
Also applies to: 18-18
packages/api/src/external/ehr/athenahealth/command/write-back/condition.ts (1)
3-3
: Solid placement of department validation.Pre-validating department IDs before client creation is correct and keeps the flow consistent across write-backs.
Also applies to: 18-18
packages/api/src/external/ehr/athenahealth/command/write-back/allergy.ts (1)
3-3
: LGTM on department validation integration.Import and invocation are accurate; this will short-circuit invalid contexts cleanly.
Also applies to: 18-18
packages/api/src/external/ehr/athenahealth/command/sync-patient.ts (1)
14-14
: Validation added correctly at the start of sync flow.Early department verification before any Athena calls is appropriate and maintains consistent error semantics with other commands.
Also applies to: 38-38
packages/api/src/external/ehr/athenahealth/command/write-back/immunization.ts (2)
3-3
: Pre-flight validation import looks right.Consistent with other Athena write-back flows. No issues.
18-25
: ValidateDepartmentId: add tests and confirm ID-prefix logic
- Add unit tests for validateDepartmentId(): when departmentIds includes the stripped ID (no throw), when it excludes it (throws BadRequestError), and when departmentIds is empty (no-op).
- The code strips
"a-1.Practice-"
then\
a-${strippedPracticeId}.Department-``; verify that all Athena practice/department IDs in prod/staging conform to that format or extend the logic accordingly.packages/api/src/external/ehr/athenahealth/command/write-back/note.ts (1)
2-2
: Importing validateDepartmentId here keeps enforcement consistent across write-backs.Good alignment with the shared validation strategy.
packages/api/src/external/ehr/athenahealth/command/write-back/lab.ts (1)
3-3
: Shared import update LGTM.Matches the new validation flow.
packages/api/src/external/ehr/elation/command/subscribe-to-webhook.ts (2)
1-9
: Good simplification via getCxMappingAndParsedSecondaryMappings.Reduces local parsing and keeps types safer. Import paths look correct.
20-24
: Typed helper usage is correct.Generic specialization to ElationSecondaryMappings is appropriate here.
packages/api/src/external/ehr/shared/command/mapping/get-cx-mapping-and-secondary-mappings.ts (1)
26-33
: Error semantics are good.Static message, useful context. Aligns with error-handling guidelines.
packages/api/src/external/ehr/athenahealth/shared.ts (1)
61-66
: Good use of the generic mapping helperFetching and parsing secondary mappings via the shared helper is clean and consistent.
packages/api/src/external/ehr/healthie/command/subscribe-to-webhook.ts (3)
2-2
: LGTM on type importUsing HealthieSecondaryMappings clarifies intent.
8-10
: LGTM on mapping helper migrationSwitch to getCxMappingAndParsedSecondaryMappings improves reuse and validation.
21-25
: Verify schema guarantees webhooks presenceWe spread parsedSecondaryMappings.webhooks; ensure the schema always defines it (object, not undefined), otherwise default to {}.
- const { parsedSecondaryMappings, cxMapping } = + const { parsedSecondaryMappings, cxMapping } = await getCxMappingAndParsedSecondaryMappings<HealthieSecondaryMappings>({ ehr: EhrSources.healthie, practiceId: healthiePracticeId, }); + // If schema doesn't guarantee it, ensure a default: + // const webhooks = parsedSecondaryMappings.webhooks ?? {};
const strippedPracticeId = athenaPracticeId.replace("a-1.Practice-", ""); | ||
const strippedDepartmentId = athenaDepartmentId.replace( | ||
`a-${strippedPracticeId}.Department-`, | ||
"" | ||
); |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
🛠️ Refactor suggestion
Make department ID parsing format-safe (avoid false positives)
Using replace() can silently mis-parse if the expected prefix isn’t present. Prefer an explicit prefix check + slice.
- const strippedPracticeId = athenaPracticeId.replace("a-1.Practice-", "");
- const strippedDepartmentId = athenaDepartmentId.replace(
- `a-${strippedPracticeId}.Department-`,
- ""
- );
+ const strippedPracticeId = athenaPracticeId.replace("a-1.Practice-", "");
+ const expectedDepartmentPrefix = `a-${strippedPracticeId}.Department-`;
+ if (!athenaDepartmentId.startsWith(expectedDepartmentPrefix)) {
+ throw new BadRequestError(
+ "Invalid Athena department ID format",
+ undefined,
+ { cxId, athenaPracticeId, athenaPatientId, athenaDepartmentId }
+ );
+ }
+ const strippedDepartmentId = athenaDepartmentId.slice(expectedDepartmentPrefix.length);
📝 Committable suggestion
‼️ IMPORTANT
Carefully review the code before committing. Ensure that it accurately replaces the highlighted code, contains no missing lines, and has no issues with indentation. Thoroughly test & benchmark the code to ensure it meets the requirements.
const strippedPracticeId = athenaPracticeId.replace("a-1.Practice-", ""); | |
const strippedDepartmentId = athenaDepartmentId.replace( | |
`a-${strippedPracticeId}.Department-`, | |
"" | |
); | |
const strippedPracticeId = athenaPracticeId.replace("a-1.Practice-", ""); | |
const expectedDepartmentPrefix = `a-${strippedPracticeId}.Department-`; | |
if (!athenaDepartmentId.startsWith(expectedDepartmentPrefix)) { | |
throw new BadRequestError( | |
"Invalid Athena department ID format", | |
undefined, | |
{ cxId, athenaPracticeId, athenaPatientId, athenaDepartmentId } | |
); | |
} | |
const strippedDepartmentId = athenaDepartmentId.slice(expectedDepartmentPrefix.length); |
🤖 Prompt for AI Agents
In packages/api/src/external/ehr/athenahealth/shared.ts around lines 67–71, the
department ID is parsed using replace(), which can silently mis-parse if the
expected prefix isn’t present; update this to compute the expected prefix (e.g.
`const prefix = \`a-${strippedPracticeId}.Department-\``), check with
startsWith(prefix) and then extract the suffix with slice(prefix.length); if the
department string does not start with the prefix, handle it explicitly (throw an
error, return null/undefined, or log and bail) rather than silently returning a
wrong value.
/** | ||
* Get the cx mapping and parsed secondary mappings for a given practice ID for all EHRs | ||
* | ||
* @param ehr - The EHR source. | ||
* @param practiceId - The practice id of the EHR integration. | ||
* @returns The secondary mappings for the practice or null if the EHR doesn't have secondary mappings. | ||
*/ |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Fix JSDoc: return description is inaccurate.
This function never returns null; it throws when mappings are absent and only accepts EHRs that support secondary mappings.
Apply:
- * @returns The secondary mappings for the practice or null if the EHR doesn't have secondary mappings.
+ * @returns Parsed secondary mappings and the cxMapping.
+ * @throws MetriportError if secondary mappings are missing for the given practice/EHR.
📝 Committable suggestion
‼️ IMPORTANT
Carefully review the code before committing. Ensure that it accurately replaces the highlighted code, contains no missing lines, and has no issues with indentation. Thoroughly test & benchmark the code to ensure it meets the requirements.
/** | |
* Get the cx mapping and parsed secondary mappings for a given practice ID for all EHRs | |
* | |
* @param ehr - The EHR source. | |
* @param practiceId - The practice id of the EHR integration. | |
* @returns The secondary mappings for the practice or null if the EHR doesn't have secondary mappings. | |
*/ | |
/** | |
* Get the cx mapping and parsed secondary mappings for a given practice ID for all EHRs | |
* | |
* @param ehr - The EHR source. | |
* @param practiceId - The practice id of the EHR integration. | |
* @returns Parsed secondary mappings and the cxMapping. | |
* @throws MetriportError if secondary mappings are missing for the given practice/EHR. | |
*/ |
🤖 Prompt for AI Agents
In
packages/api/src/external/ehr/shared/command/mapping/get-cx-mapping-and-secondary-mappings.ts
around lines 10 to 16, the JSDoc @returns is incorrect (it claims the function
can return null) — update the docblock to remove the null return description and
instead state that the function returns the parsed secondary mappings for the
practice (and that it will throw if mappings are absent and only supports EHRs
that provide secondary mappings); keep param descriptions as-is but ensure
@returns accurately reflects the actual return type and behavior (throwing on
missing mappings).
Issues:
Description
Testing
Check each PR.
Release Plan
master
Summary by CodeRabbit
New Features
Refactor
Chores