-
Notifications
You must be signed in to change notification settings - Fork 67
198 ecw v2 #3874
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
198 ecw v2 #3874
Conversation
refs. metriport/metriport-internal#198 Signed-off-by: Syed Husain <syed@metriport.com>
Ref: ENG-198 Ref: #1040 Signed-off-by: Thomas Yopes <thomasyopes@Thomass-MBP.attlocal.net>
Ref: ENG-198 Ref: #1040 Signed-off-by: Thomas Yopes <thomasyopes@Thomass-MBP.attlocal.net>
Ref: ENG-198 Ref: #1040 Signed-off-by: Thomas Yopes <thomasyopes@Thomass-MBP.attlocal.net>
Ref: ENG-199 Ref: #1040 Signed-off-by: Thomas Yopes <thomasyopes@Thomass-MBP.attlocal.net>
Ref: ENG-199 Ref: #1040 Signed-off-by: Thomas Yopes <thomasyopes@Thomass-MBP.attlocal.net>
refs. metriport/metriport-internal#198 Signed-off-by: Syed Husain <syed@metriport.com>
Ref: ENG-198 Ref: #1040 Signed-off-by: Thomas Yopes <thomasyopes@Thomass-MBP.attlocal.net>
…triport into 198-ecw-patientflow Signed-off-by: Thomas Yopes <thomasyopes@Thomass-MBP.attlocal.net>
Ref: ENG-198 Ref: #1040 Signed-off-by: Thomas Yopes <thomasyopes@Thomass-MBP.attlocal.net>
Ref: ENG-198 Ref: #1040 Signed-off-by: Thomas Yopes <thomasyopes@Thomass-MBP.attlocal.net>
Warning Rate limit exceeded@thomasyopes has exceeded the limit for the number of commits or files that can be reviewed per hour. Please wait 1 minutes and 27 seconds before requesting another review. ⌛ How to resolve this issue?After the wait time has elapsed, a review can be triggered using the We recommend that you space out your commits to avoid hitting the rate limit. 🚦 How do rate limits work?CodeRabbit enforces hourly rate limits for each developer per organization. Our paid plans have higher rate limits than the trial, open-source and free plans. In all cases, we re-allow further reviews after a brief timeout. Please see our FAQ for further information. 📒 Files selected for processing (2)
WalkthroughThe changes introduce comprehensive support for the "eclinicalworks" EHR integration throughout the codebase. This includes new API client modules, JWT token schema and handling, synchronization workflows, Express routes and middleware, configuration methods, and updates to shared interfaces and enums. The integration enables secure patient data synchronization and access via new endpoints and middleware. Changes
Sequence Diagram(s)sequenceDiagram
participant Client
participant API_Router
participant Middleware
participant SyncLogic
participant EClinicalWorksAPI
participant MetriportDB
Client->>API_Router: Request (GET/POST /ehr/eclinicalworks/patient/:id)
API_Router->>Middleware: Validate & extract cxId, practiceId, tokenId, patientId
Middleware->>SyncLogic: syncEclinicalworksPatientIntoMetriport(params)
SyncLogic->>MetriportDB: Check for existing patient mapping
alt Mapping exists
MetriportDB-->>SyncLogic: Return Metriport patient ID
else No mapping
SyncLogic->>EClinicalWorksAPI: Fetch patient data (using JWT token)
EClinicalWorksAPI-->>SyncLogic: Return patient data
SyncLogic->>MetriportDB: Create/retrieve Metriport patient
SyncLogic->>MetriportDB: Create patient mapping
end
SyncLogic-->>API_Router: Return Metriport patient ID
API_Router
8000
-->>Client: Respond with patient ID (JSON)
sequenceDiagram
participant Client
participant API_Router
participant Middleware
participant JWTTokenLogic
participant DB
Client->>API_Router: GET /internal/token/eclinicalworks (with Authorization)
API_Router->>Middleware: requestLogger, asyncHandler
Middleware->>JWTTokenLogic: checkJwtToken(token, source)
JWTTokenLogic->>DB: Retrieve and validate JWT token
JWTTokenLogic-->>Middleware: Return token status
Middleware-->>API_Router: Pass response
API_Router-->>Client: Respond with status JSON
Client->>API_Router: POST /internal/token/eclinicalworks (with Authorization & body)
API_Router->>Middleware: requestLogger, asyncHandler
Middleware->>JWTTokenLogic: saveJwtToken(token, source, data)
JWTTokenLogic->>DB: Save JWT token
JWTTokenLogic-->>Middleware: OK
Middleware-->>API_Router: Pass response
API_Router-->>Client: Respond with 200 OK
✨ Finishing Touches
🪧 TipsChatThere are 3 ways to chat with CodeRabbit:
SupportNeed help? Create a ticket on our support page for assistance with any issues or questions. Note: Be mindful of the bot's finite context window. It's strongly recommended to break down tasks such as reading entire modules into smaller chunks. For a focused discussion, use review comments to chat about specific files and their changes, instead of using the PR comments. CodeRabbit Commands (Invoked using PR comments)
Other keywords and placeholders
CodeRabbit Configuration File (
|
… 198-ecw-v2 Signed-off-by: Thomas Yopes <thomasyopes@Thomass-MBP.attlocal.net>
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: 5
🧹 Nitpick comments (9)
packages/api/src/external/ehr/eclinicalworks/shared.ts (1)
9-20
: Clear environment validation with descriptive errorsThe implementation correctly retrieves and validates the EClinicalWorks environment. Consider enhancing the error message on line 15 to include what valid environments are expected.
- throw new MetriportError("Invalid EClinicalWorks environment", undefined, { environment }); + throw new MetriportError("Invalid EClinicalWorks environment", undefined, { + environment, + validEnvironments: eclinicalworksEnv + });packages/api/src/routes/ehr/eclinicalworks/patient.ts (3)
11-19
: JSDoc comments need correction.The JSDoc parameter documentation mentions
req.query.aud
but the code usesreq.query.tokenId
. This inconsistency should be fixed.* @param req.params.id The ID of Eclinicalworks Patient. * @param req.query.practiceId The ID of Eclinicalworks Practice. -* @param req.query.aud The ID of Eclinicalworks Aud. +* @param req.query.tokenId The ID of Eclinicalworks token. * @returns Metriport Patient if found.
39-47
: JSDoc comments need correction.The same JSDoc parameter inconsistency exists in the POST endpoint documentation.
* @param req.params.id The ID of Eclinicalworks Patient. * @param req.query.practiceId The ID of Eclinicalworks Practice. -* @param req.query.aud The ID of Eclinicalworks Aud. +* @param req.query.tokenId The ID of Eclinicalworks token. * @returns Metriport Patient if found.
20-65
: Consider refactoring duplicate code in GET and POST handlers.The GET and POST handlers contain identical logic. Consider extracting the common functionality into a shared helper function to reduce code duplication and improve maintainability.
+// Helper function to handle both GET and POST requests +async function handlePatientSync(req: Request, res: Response) { + const cxId = getCxIdOrFail(req); + const eclinicalworksPatientId = getFrom("params").orFail("id", req); + const eclinicalworksPracticeId = getFromQueryOrFail("practiceId", req); + const eclinicalworksTokenId = getFromQueryOrFail("tokenId", req); + const patientId = await syncEclinicalworksPatientIntoMetriport({ + cxId, + eclinicalworksPracticeId, + eclinicalworksPatientId, + eclinicalworksTokenId, + }); + return res.status(httpStatus.OK).json(patientId); +} // GET endpoint router.get( "/:id", handleParams, requestLogger, - asyncHandler(async (req: Request, res: Response) => { - const cxId = getCxIdOrFail(req); - const eclinicalworksPatientId = getFrom("params").orFail("id", req); - const eclinicalworksPracticeId = getFromQueryOrFail("practiceId", req); - const eclinicalworksTokenId = getFromQueryOrFail("tokenId", req); - const patientId = await syncEclinicalworksPatientIntoMetriport({ - cxId, - eclinicalworksPracticeId, - eclinicalworksPatientId, - eclinicalworksTokenId, - }); - return res.status(httpStatus.OK).json(patientId); - }) + asyncHandler(handlePatientSync) ); // POST endpoint router.post( "/:id", handleParams, requestLogger, - asyncHandler(async (req: Request, res: Response) => { - const cxId = getCxIdOrFail(req); - const eclinicalworksPatientId = getFrom("params").orFail("id", req); - const eclinicalworksPracticeId = getFromQueryOrFail("practiceId", req); - const eclinicalworksTokenId = getFromQueryOrFail("tokenId", req); - const patientId = await syncEclinicalworksPatientIntoMetriport({ - cxId, - eclinicalworksPracticeId, - eclinicalworksPatientId, - eclinicalworksTokenId, - }); - return res.status(httpStatus.OK).json(patientId); - }) + asyncHandler(handlePatientSync) );packages/api/src/routes/ehr/eclinicalworks/auth/middleware.ts (1)
33-37
: Avoid passing the resolved value tonext()
Promise.then(next)
forwards the resolved value (hereundefined
) as the first argument tonext()
.
Even thoughnext(undefined)
behaves likenext()
, the intent is less clear and can trip lint rules that disallow sending non-Error values to Express’ error handler.-export function processCxIdDash(req: Request, res: Response, next: NextFunction) { - processCxIdShared(req, eclinicalworksDashSource, parseEclinicalworksPracticeIdDash) - .then(next) - .catch(next); -} +export function processCxIdDash(req: Request, res: Response, next: NextFunction) { + processCxIdShared(req, eclinicalworksDashSource, parseEclinicalworksPracticeIdDash) + .then(() => next()) + .catch(next); +}Apply the same pattern to the two helpers below for consistency.
packages/core/src/external/ehr/eclinicalworks/index.ts (2)
26-33
: Redundant Axios instance creation
this.axiosFhirInstance = axios.create({})
in the constructor is overwritten a few lines later ininitialize()
.
Removing the first instantiation avoids an unnecessary allocation and keeps the intent clear.- this.axiosFhirInstance = axios.create({}); + // axiosFhirInstance will be initialised in `initialize`
43-48
: Consider setting anAccept
header instead ofContent-Type
for GETs
Content-Type
is mainly relevant for requests with a body.
For GET requests against FHIR endpoints anAccept: application/fhir+json
header better communicates the expected response format and avoids confusing upstream proxies that look atContent-Type
.- "Content-Type": "application/x-www-form-urlencoded", + Accept: "application/fhir+json",packages/api/src/external/ehr/eclinicalworks/command/sync-patient.ts (1)
66-71
: Un-awaited promise suppression might swallow critical sync errors
queryDocumentsAcrossHIEs(...).catch(processAsyncError())
is fire-and-forget, which is fine, but consider adding monitoring/logging that differentiates between expected background failures and unexpected ones to avoid silent data gaps.packages/api/src/external/ehr/shared.ts (1)
225-234
: Avoid variable shadowing for clearer intentUsing
getEnv
both as a parameter object and as the inner function name is confusing. Renaming the destructured result improves readability:- const [environment, twoLeggedAuthTokenInfo] = await Promise.all([ - getEnv.getEnv(getEnv.params), + const [envConfig, twoLeggedAuthTokenInfo] = await Promise.all([ + getEnv.getEnv(getEnv.params), ]); ... - ...environment, + ...envConfig,This tiny change eliminates mental overhead when scanning the async flow.
📜 Review details
Configuration used: CodeRabbit UI
Review profile: CHILL
Plan: Pro
📒 Files selected for processing (16)
packages/api/src/command/jwt-token.ts
(2 hunks)packages/api/src/external/ehr/eclinicalworks/command/sync-patient.ts
(1 hunks)packages/api/src/external/ehr/eclinicalworks/shared.ts
(1 hunks)packages/api/src/external/ehr/shared.ts
(1 hunks)packages/api/src/routes/ehr/eclinicalworks/auth/middleware.ts
(1 hunks)packages/api/src/routes/ehr/eclinicalworks/patient.ts
(1 hunks)packages/api/src/routes/ehr/eclinicalworks/routes/dash.ts
(1 hunks)packages/api/src/routes/ehr/index.ts
(2 hunks)packages/api/src/routes/ehr/shared.ts
(1 hunks)packages/api/src/routes/internal/jwt-token/eclinicalworks.ts
(1 hunks)packages/api/src/shared/config.ts
(1 hunks)packages/core/src/external/ehr/eclinicalworks/index.ts
(1 hunks)packages/lambdas/src/shared/ehr.ts
(1 hunks)packages/shared/src/interface/external/ehr/eclinicalworks/index.ts
(1 hunks)packages/shared/src/interface/external/ehr/eclinicalworks/jwt-token.ts
(1 hunks)packages/shared/src/interface/external/ehr/source.ts
(1 hunks)
🧰 Additional context used
📓 Path-based instructions (1)
`**/*.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...
**/*.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
- Use truthy syntax instead of
in
- i.e.,if (data.link)
notif ('link' in data)
- Error handling
- Pass the original error as the new one’s
cause
so the stack trace is persisted- Error messages should have a static message - add dynamic data to MetriportError's
additionalInfo
prop- Avoid sending multiple events to Sentry for a single error
- Global constants and variables
- Move literals to constants declared after imports when possible (avoid magic numbers)
- Avoid shared, global objects
- Avoid using
console.log
andconsole.error
in packages other than utils, infra and shared,
and try to useout().log
instead- Avoid multi-line logs
- don't send objects as a second parameter to
console.log()
orout().log()
- don't create multi-line strings when using
JSON.stringify()
- Use
eslint
to enforce code style- Use
prettier
to format code- max column length is 100 chars
- multi-line comments use
/** */
- scripts: top-level comments go after the import
packages/lambdas/src/shared/ehr.ts
packages/api/src/routes/ehr/index.ts
packages/shared/src/interface/external/ehr/eclinicalworks/index.ts
packages/api/src/shared/config.ts
packages/api/src/external/ehr/eclinicalworks/shared.ts
packages/shared/src/interface/external/ehr/source.ts
packages/api/src/routes/ehr/eclinicalworks/routes/dash.ts
packages/shared/src/interface/external/ehr/eclinicalworks/jwt-token.ts
packages/api/src/routes/internal/jwt-token/eclinicalworks.ts
packages/api/src/routes/ehr/shared.ts
packages/api/src/command/jwt-token.ts
packages/api/src/routes/ehr/eclinicalworks/patient.ts
packages/api/src/routes/ehr/eclinicalworks/auth/middleware.ts
packages/core/src/external/ehr/eclinicalworks/index.ts
packages/api/src/external/ehr/eclinicalworks/command/sync-patient.ts
packages/api/src/external/ehr/shared.ts
🧬 Code Graph Analysis (7)
packages/api/src/external/ehr/eclinicalworks/shared.ts (3)
packages/api/src/shared/config.ts (1)
getEClinicalWorksEnv
(351-353)packages/core/src/external/ehr/eclinicalworks/index.ts (2)
EClinicalWorksEnv
(15-15)isEClinicalWorksEnv
(16-18)packages/api/src/external/ehr/shared.ts (1)
EhrPerPracticeParams
(186-186)
packages/api/src/routes/ehr/eclinicalworks/routes/dash.ts (2)
packages/api/src/routes/ehr/shared.ts (4)
documentDownloadUrlRegex
(48-48)processPatientRoute
(91-100)processEhrPatientId
(135-154)processDocumentRoute
(102-111)packages/api/src/routes/ehr/eclinicalworks/auth/middleware.ts (3)
processPatientRoute
(39-41)tokenEhrPatientIdQueryParam
(12-12)processDocumentRoute
(43-45)
packages/api/src/routes/internal/jwt-token/eclinicalworks.ts (2)
packages/api/src/external/ehr/shared/utils/jwt-token.ts (2)
checkJwtToken
(68-82)saveJwtToken
(84-101)packages/shared/src/interface/external/ehr/eclinicalworks/jwt-token.ts (2)
eclinicalworksDashSource
(4-4)eclinicalworksDashJwtTokenDataSchema
(5-9)
packages/api/src/routes/ehr/shared.ts (3)
packages/api/src/domain/jwt-token.ts (1)
JwtTokenData
(21-21)packages/api/src/command/jwt-token.ts (1)
getJwtToken
(26-35)packages/shared/src/common/date.ts (1)
buildDayjs
(70-72)
packages/api/src/command/jwt-token.ts (2)
packages/api/src/domain/jwt-token.ts (1)
JwtToken
(30-30)packages/shared/src/index.ts (1)
NotFoundError
(41-41)
packages/api/src/routes/ehr/eclinicalworks/patient.ts (1)
packages/api/src/external/ehr/eclinicalworks/command/sync-patient.ts (1)
syncEclinicalworksPatientIntoMetriport
(25-79)
packages/api/src/routes/ehr/eclinicalworks/auth/middleware.ts (3)
packages/api/src/domain/jwt-token.ts (1)
JwtTokenData
(21-21)packages/api/src/routes/ehr/shared.ts (3)
ParseResponse
(17-20)processPatientRoute
(91-100)processDocumentRoute
(102-111)packages/shared/src/interface/external/ehr/eclinicalworks/jwt-token.ts (1)
eclinicalworksDashSource
(4-4)
🪛 GitHub Actions: PR Check - Core
packages/api/src/external/ehr/eclinicalworks/command/sync-patient.ts
[error] 13-13: TypeScript error TS2307: Cannot find module '../../shared-fhir' or its corresponding type declarations.
🪛 GitHub Actions: PR Check - API
packages/api/src/external/ehr/eclinicalworks/command/sync-patient.ts
[error] 13-13: TypeScript error TS2307: Cannot find module '../../shared-fhir' or its corresponding type declarations.
🪛 GitHub Actions: PR Check - Lambdas
packages/api/src/external/ehr/eclinicalworks/command/sync-patient.ts
[error] 13-13: TypeScript error TS2307: Cannot find module '../../shared-fhir' or its corresponding type declarations.
🪛 GitHub Actions: PR Check - Shared
packages/api/src/external/ehr/eclinicalworks/command/sync-patient.ts
[error] 13-13: TypeScript error TS2307: Cannot find module '../../shared-fhir' or its corresponding type declarations.
⏰ Context from checks skipped due to timeout of 90000ms (1)
- GitHub Check: Analyze (javascript)
🔇 Additional comments (26)
packages/shared/src/interface/external/ehr/source.ts (1)
6-6
: LGTM: Adding EClinicalWorks to EHR sourcesThe addition of EClinicalWorks as a new EHR source is straightforward and follows the existing pattern in the enum. Since the
ehrSources
array andEhrSource
type are derived from this enum, this change automatically makes EClinicalWorks available throughout the system.packages/api/src/shared/config.ts (1)
351-353
: LGTM: Configuration method for EClinicalWorks environmentThis method follows the established pattern for EHR environment configuration and correctly uses the optional
getEnvVar
helper.packages/lambdas/src/shared/ehr.ts (1)
37-37
: Fixed error message for departmentId validationGood catch - the error message now correctly refers to "departmentId" instead of what was likely "patientId" before, making the error more accurate and helpful for debugging.
packages/shared/src/interface/external/ehr/eclinicalworks/index.ts (1)
1-1
: LGTM: Clean export pattern for JWT token functionalityThis follows the common pattern of using index files to re-export functionality from specific modules, providing a cleaner public API for the EClinicalWorks integration.
packages/api/src/routes/ehr/index.ts (1)
11-12
: Integration of EClinicalWorks follows consistent pattern!The implementation for EClinicalWorks follows the same pattern as other EHR integrations, with proper middleware for customer ID processing and access checks.
Also applies to: 32-32
packages/api/src/command/jwt-token.ts (3)
3-3
: Code organization improvementMoving the
Op
import from Sequelize to the imports section is a good organizational change, maintaining consistency with other imports.
52-61
: LGTM: Token retrieval by IDThis function follows the established pattern for token retrieval without checking expiration, with proper typing and error handling.
63-70
: LGTM: Token retrieval with error handlingThis implementation correctly follows the existing pattern for throwing NotFoundError when a token doesn't exist, providing appropriate context in the error.
packages/api/src/routes/ehr/shared.ts (1)
25-32
: Modification to support token ID in parse functionThe updated function signature properly passes both token data and token ID to the parse function, enabling implementations to use the token ID when needed (specifically for EClinicalWorks integration).
packages/api/src/external/ehr/eclinicalworks/shared.ts (2)
22-24
: LGTM: Clear type extensionThe type definition correctly extends the base EHR practice parameters with the required auth token parameter.
26-35
:✅ Verification successful
Clean client creation implementation
The client creation function follows functional programming principles with good error handling. The
await
on line 30 might be unnecessary ifEClinicalWorksApi.create
isn't actually async - verify in the implementation.
🏁 Script executed:
#!/bin/bash # Check if EClinicalWorksApi.create is truly async ast-grep --pattern $'EClinicalWorksApi.create = async ({ practiceId, environment, authToken }: EClinicalWorksCreateParams): Promise<EClinicalWorksApi> =>'Length of output: 155
🏁 Script executed:
#!/bin/bash # Locate the file defining the EClinicalWorksApi class file=$(rg -l "class EClinicalWorksApi" -g '*.ts') if [ -z "$file" ]; then echo "EClinicalWorksApi class not found." exit 1 fi echo "EClinicalWorksApi defined in: $file" # Show the create method signature and surrounding lines rg -n -C 2 "create" "$file"Length of output: 987
Await on EClinicalWorksApi.create is required
Confirmed that
EClinicalWorksApi.create
is declared as anasync
static method and internally awaitsinitialize()
. Keeping theawait
increateEClinicalWorksClient
is correct.packages/api/src/routes/internal/jwt-token/eclinicalworks.ts (4)
1-11
: Imports and module structure look good.The imports are well-organized and appropriate for the functionality this module implements. You're correctly importing the eClinicalWorks JWT token schema from shared interfaces and using standard Express routing patterns.
15-34
: GET endpoint implementation looks correct.The endpoint properly extracts the authorization token, performs appropriate error handling when the token is missing, and correctly calls the
checkJwtToken
function with the eClinicalWorks source identifier. The response structure follows good REST practices.
36-39
: Zod schema definition is appropriate.The schema correctly validates the required fields for creating a JWT token, leveraging the imported eClinicalWorks JWT token data schema.
41-63
: POST endpoint implements proper validation and token saving.The implementation correctly validates the request token, checks the request body against the schema, and saves the JWT token with appropriate parameters. Error handling is well-implemented.
packages/shared/src/interface/external/ehr/eclinicalworks/jwt-token.ts (3)
1-4
: Imports are appropriate and concise.The file correctly imports Zod for schema validation and the EHR sources enumeration.
4-9
: JWT token schema definition looks good.The schema correctly defines the required fields for eClinicalWorks JWT tokens with proper typing. Using a literal type for the source field ensures that only the correct source value can be used.
10-10
: Type inference from Zod schema follows best practices.Using
z.infer
to derive the TypeScript type from the Zod schema ensures type consistency between runtime validation and compile-time type checking.packages/api/src/routes/ehr/eclinicalworks/routes/dash.ts (5)
1-14
: Imports are comprehensive and appropriate.The module imports all necessary components for the eClinicalWorks dashboard routes, including middleware, handlers, and utility functions.
17-17
: Skip paths definition is appropriate.The array correctly specifies which paths should skip the eClinicalWorks ID check, specifically for document download URLs.
19-27
: Patient route middleware chain looks good.The middleware chain for patient routes correctly applies parameter handling, route processing, EHR patient ID validation, and patient authorization before passing control to the patient handler.
28-37
: Document route middleware chain is properly implemented.The middleware chain for document routes correctly processes document routes, applies EHR patient ID validation with appropriate skip paths, and passes control to the document handler.
38-38
: Settings route is properly configured.The settings route is correctly set up to use the settings handler.
packages/api/src/routes/ehr/eclinicalworks/patient.ts (2)
1-8
: Imports are appropriate for the functionality.The module correctly imports the necessary dependencies for Express routing, HTTP status handling, and eClinicalWorks patient synchronization.
20-37
: GET endpoint implementation looks good.The endpoint correctly extracts required parameters, calls the synchronization function, and returns the patient ID. The use of helper functions for parameter extraction and validation is a good practice.
packages/api/src/routes/ehr/eclinicalworks/auth/middleware.ts (1)
18-30
: Confirm the correct identifier is returned asexternalId
parseEclinicalworksPracticeIdDash
returns the practiceId asexternalId
.
If downstream logic (e.g.replaceIdInQueryParams
inroutes/ehr/shared.ts
) expects the patient’s external ID, this could break patient-level mapping and cause data to be fetched for the wrong resource.Please double-check the contract of
processCxIdShared
and ensure thatexternalId
should indeed be the practice identifier.
packages/api/src/external/ehr/eclinicalworks/command/sync-patient.ts
Outdated
Show resolved
Hide resolved
packages/api/src/external/ehr/eclinicalworks/command/sync-patient.ts
Outdated
Show resolved
Hide resolved
packages/api/src/external/ehr/eclinicalworks/command/sync-patient.ts
Outdated
Show resolved
Hide resolved
Ref: ENG-198 Ref: #1040 Signed-off-by: Thomas Yopes <thomasyopes@Thomass-MBP.attlocal.net>
Ref: ENG-198 Ref: #1040 Signed-off-by: Thomas Yopes <thomasyopes@Thomass-MBP.attlocal.net>
Ref: ENG-198 Ref: #1040 Signed-off-by: Thomas Yopes <thomasyopes@Thomass-MBP.attlocal.net>
Ref: ENG-198 Ref: #1040 Signed-off-by: Thomas Yopes <thomasyopes@Thomass-MBP.attlocal.net>
Ref: ENG-198 Ref: #1040 Signed-off-by: Thomas Yopes <thomasyopes@Thomass-MBP.attlocal.net>
Ref: ENG-198 Ref: #1040 Signed-off-by: Thomas Yopes <thomasyopes@Thomass-MBP.attlocal.net>
… 198-ecw-v2 Signed-off-by: Thomas Yopes <thomasyopes@Thomass-MBP.attlocal.net>
Ref: ENG-198 Ref: #1040 Signed-off-by: Thomas Yopes <thomasyopes@Thomass-MBP.attlocal.net>
… 198-ecw-v2 Signed-off-by: Thomas Yopes <thomasyopes@Thomass-MBP.attlocal.net>
/** | ||
* POST /ehr/eclinicalworks/patient/:id | ||
* | ||
* Tries to retrieve the matching Metriport patient | ||
* @param req.params.id The ID of Eclinicalworks Patient. | ||
* @param req.query.practiceId The ID of Eclinicalworks Practice. | ||
* @param req.query.tokenId The ID of Eclinicalworks Token. | ||
* @returns Metriport Patient if found. | ||
*/ | ||
router.post( | ||
"/:id", | ||
handleParams, | ||
requestLogger, | ||
asyncHandler(async (req: Request, res: Response) => { | ||
const cxId = getCxIdOrFail(req); | ||
const eclinicalworksPatientId = getFrom("params").orFail("id", req); | ||
const eclinicalworksPracticeId = getFromQueryOrFail("practiceId", req); | ||
const eclinicalworksTokenId = getFromQueryOrFail("tokenId", req); | ||
const patientId = await syncEClinicalWorksPatientIntoMetriport({ | ||
cxId, | ||
eclinicalworksPracticeId, | ||
eclinicalworksPatientId, | ||
eclinicalworksTokenId, | ||
}); | ||
return res.status(httpStatus.OK).json(patientId); | ||
}) | ||
); | ||
|
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.
Why do we have the same logic but one is post and the other get?
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.
We wanted to eventually migrate to POST as it creates a mapping on our end (so not a pure GET) but frontend needs an update to roll this out completely
import ElationApi, { ElationEnv } from "@metriport/core/external/ehr/elation/index"; | ||
import { HealthieEnv } from "@metriport/core/external/ehr/healthie/index"; |
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.
Did we forget to do this before?
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.
Yes
Ref: ENG-198 Ref: #1040 Signed-off-by: Thomas Yopes <thomasyopes@Thomass-MBP.attlocal.net>
Ref: ENG-198 Ref: #1040 Signed-off-by: Thomas Yopes <thomasyopes@Thomass-MBP.attlocal.net>
Issues:
Dependencies
Description
Testing
Release Plan
Summary by CodeRabbit
New Features
Bug Fixes
Other Improvements