Api::V1::IssuesController#create (avg 2481ms, max 2615ms)
Completeness#
| # | Plan Item | Status | Evidence |
|---|---|---|---|
| 1 | create.ts: Remove getIssueWithFullInfo() call, construct response in-memory using write data + issueType object, parallelize notifications with Promise.all() |
PASS | applications/issue-service/src/lambda/issue/create.ts: lines 98-126 show removal of getIssueWithFullInfo(client, issueId) call, in-memory issue object construction (lines 100-113), and Promise.all(notifications) pattern (lines 115-121) |
| 2 | lambda-helper.ts: LambdaClient as module-scope singleton, remove per-function instantiation |
PASS | applications/issue-service/src/common/lambda-helper.ts: line 4 declares const lambdaClient = new LambdaClient() at module scope; lines 6 and 20 show removal of const lambdaClient = new LambdaClient() inside each function |
| 3 | config.ts: Add singleton DynamoDBClient export |
PASS | applications/issue-service/src/common/config.ts: line 1 adds import { DynamoDBClient } and line 10 adds export const dynamoDBClient = new DynamoDBClient(dynamoDBClientConfig) |
| 4 | dynamodb-helper.ts: No changes (API compatibility maintained) |
PASS | File does not appear in the diff -- no modifications made, as planned |
Acceptance Criteria#
| # | Criterion | Status | Evidence |
|---|---|---|---|
| 1 | create.ts removes getIssueWithFullInfo import and call |
PASS | create.ts: line 10 shows import changed from { getIssueTypByErrorCode, getIssueTypById, getIssueWithFullInfo } to { getIssueTypByErrorCode, getIssueTypById }; line 100 area shows getIssueWithFullInfo(client, issueId) call removed |
| 2 | Response object constructed in-memory with issueType data | PASS | create.ts: lines 100-113 build issue object with fields from data and issueType directly, including issue_type: issueType |
| 3 | Notification calls parallelized with Promise.all() |
PASS | create.ts: lines 115-121 build notifications array conditionally, then await Promise.all(notifications) at line 122 |
| 4 | LambdaClient is module-scope singleton in lambda-helper.ts |
PASS | lambda-helper.ts: line 4 declares const lambdaClient = new LambdaClient() outside any function |
| 5 | DynamoDBClient singleton exported from config.ts, reused in create.ts and findIssueType() |
PASS | config.ts: line 10 exports dynamoDBClient; create.ts: line 6 imports dynamoDBClient from config, line 98 uses it for BatchWriteItemCommand, lines 19/21 use it in findIssueType() via getIssueTypById(dynamoDBClient, ...) and getIssueTypByErrorCode(dynamoDBClient, ...) |
| 6 | Existing error handling (try-catch) structure maintained | PASS | create.ts: try-catch block preserved at lines 97-126 (handler) and lines 17-23 (findIssueType) |
| 7 | issue.issue_type.error_code?.startsWith("AGT") condition works correctly |
PASS | create.ts: line 119 checks !issueType.error_code?.startsWith("AGT") -- uses issueType directly which is the same object assigned to issue.issue_type, functionally equivalent to the original check |
Issues Found#
No blocking issues found.
Observations#
-
unmarshallimport removed: The diff removes theunmarshallimport fromcreate.ts(line 2). This is correct sincegetIssueWithFullInfo(which used unmarshalled DynamoDB responses) is no longer called. -
Notification invocation type: Both
sendEmailNotificationandsendMondayNotificationuseInvocationType.Event(fire-and-forget async Lambda invocation). ThePromise.all()wrapping them will resolve once the invoke API call returns (not when the downstream Lambda completes). This is functionally equivalent to the original sequential awaits but with reduced wall-clock time. -
In-memory response fidelity: The constructed
issueobject includes fields likecreated_at: Date.now()which may differ slightly from what DynamoDB would return (if there was any server-side transformation). Since the data was just written with the same values, this is acceptable. -
Null coalescing on issueType fields:
issueType.issue_type_id ?? nullandissueType.error_code ?? nullsafely handle cases whereissueTypemight be the empty object{}returned whenfindIssueTypereturns null (line 90 area, not shown in diff but inferred from the existing code flow whereissueTypedefaults). This is a minor robustness note -- the caller should verify thatissueTypeis guaranteed non-null at this point in the flow.