Skip to content

CHI-3946-productionise_backend - #4575

Open
stephenhand wants to merge 34 commits into
masterfrom
CHI-3946-productionise_backend
Open

CHI-3946-productionise_backend#4575
stephenhand wants to merge 34 commits into
masterfrom
CHI-3946-productionise_backend

Conversation

@stephenhand

Copy link
Copy Markdown
Collaborator

Description

  • Add extra data to task for recording callback
  • Add try catch defensive code
  • TODO: unit tests

Checklist

  • Corresponding issue has been opened
  • New tests added
  • Feature flags added
  • Strings are localized
  • [n/a] Tested for chat contacts
  • Tested for call contacts

Other Related Issues

None

Verification steps

AFTER YOU MERGE

  1. Cut a release tag using the Github workflow. Wait for it to complete and notify in the #aselo-deploys Slack channel.
  2. Comment on the ticket with the release tag version AND any additional instructions required to configure an environment to test the changes.
  3. Only then move the ticket into the QA column in JIRA

You are responsible for ensuring the above steps are completed. If you move a ticket into QA without advising what version to test, the QA team will assume the latest tag has the changes. If it does not, the following confusion is on you! :-P

@stephenhand
stephenhand requested review from gpaoloni and a lite review from Copilot August 4, 2026 13:53

Copilot AI left a comment

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Pull request overview

Adds first-pass voicemail channel support end-to-end: a new Flex UI panel for voicemail tasks, backend webhook handling to create voicemail TaskRouter tasks on recording completion, and wiring to attach voicemail recordings (S3) to newly created HRM contacts. It also standardizes channel typing by moving custom channel constants/types into @tech-matters/twilio-types and updates lambdas/tests accordingly.

Changes:

  • Introduces a voicemail task panel in the Flex plugin (recording playback + callback action) and registers it in plugin setup.
  • Adds an account-scoped voicemail/recordingCompleteCallback webhook to create voicemail tasks and enrich attributes for downstream processing.
  • Expands channel type support (voicemail) across shared types, identifier sanitization, queue UI, icons/colors, and custom-channel typing.

Reviewed changes

Copilot reviewed 35 out of 35 changed files in this pull request and generated 7 comments.

Show a summary per file
File Description
plugin-hrm-form/src/voicemail/VoicemailTaskPanel.tsx New voicemail task UI panel (recording playback + callback action).
plugin-hrm-form/src/voicemail/setUpVoicemailComponents.tsx Registers voicemail UI components into Flex.
plugin-hrm-form/src/utils/task.ts Adds identifier normalization for voicemail channel.
plugin-hrm-form/src/translations/en.json Adds UI strings for voicemail panel actions.
plugin-hrm-form/src/transfer/transferTaskState.ts Adjusts conference transfer gating to use isVoiceTask.
plugin-hrm-form/src/states/DomainConstants.ts Adds voicemail to channel constants.
plugin-hrm-form/src/HrmFormPlugin.tsx Wires voicemail component setup into plugin initialization.
plugin-hrm-form/src/components/queuesStatus/QueueCard.tsx Displays voicemail channel in queue status UI.
plugin-hrm-form/src/components/queuesStatus/helpers.ts Initializes voicemail counts in queue status data model.
plugin-hrm-form/src/components/profile/IdentifierBanner/iconsFromTask.ts Adds voicemail icon mapping for task identifier banner.
plugin-hrm-form/src/components/contact/MediaSection/RecordingSection.tsx Adds autoLoad support and makes overlay-loader optional.
plugin-hrm-form/src/components/common/icons/VoicemailIcon.tsx Adds voicemail SVG icon component.
plugin-hrm-form/src/components/case/timeline/TimelineIcon.tsx Adds voicemail icon support in timeline rendering.
plugin-hrm-form/src/channels/colors.ts Adds voicemail color (mapped to voice color).
lambdas/packages/twilio-types/src/index.ts Adds RecordingSid type and re-exports channel type definitions.
lambdas/packages/twilio-types/src/channelType.ts Introduces shared channel/custom-channel constants and type guards.
lambdas/packages/hrm-types/src/index.ts Adds voicemail to HRM ChannelTypes.
lambdas/account-scoped/tests/unit/hrm/getProfileFlagsForIdentifier.test.ts Updates tests to use shared channel constants/types.
lambdas/account-scoped/tests/unit/conversation/janitorTaskRouterListener.test.ts Updates custom-channel mocking to use shared type guard.
lambdas/account-scoped/tests/service/hrm/getProfileFlagsForIdentifier.test.ts Adjusts service test fixture channel typing.
lambdas/account-scoped/src/voicemail/recordingCompleteCallback.ts New webhook handler to create voicemail tasks on recording completion.
lambdas/account-scoped/src/router.ts Registers the new voicemail webhook route.
lambdas/account-scoped/src/hrm/sanitizeIdentifier.ts Adds voicemail identifier sanitization and tightens channel typing.
lambdas/account-scoped/src/hrm/createHrmContactTaskRouterListener.ts Attaches external voicemail recording (S3) to HRM contact on creation.
lambdas/account-scoped/src/customChannels/telegram/telegramToFlex.ts Switches to shared custom-channel constants.
lambdas/account-scoped/src/customChannels/modica/modicaToFlex.ts Switches to shared custom-channel constants.
lambdas/account-scoped/src/customChannels/line/lineToFlex.ts Switches to shared custom-channel constants.
lambdas/account-scoped/src/customChannels/instagram/instagramToFlex.ts Switches to shared custom-channel constants.
lambdas/account-scoped/src/customChannels/customChannelToFlex.ts Removes re-export of custom-channel enum/guard from local module.
lambdas/account-scoped/src/customChannels/configuration.ts Tightens channel typing for Studio flow SID lookup.
lambdas/account-scoped/src/conversation/janitorTaskRouterListener.ts Uses shared custom-channel type guard and channel typing.
lambdas/account-scoped/src/conversation/getExternalRecordingS3Location.ts Refactors to expose a reusable function used by HRM contact creation.
lambdas/account-scoped/src/conversation/createConversation.ts Updates conversation creation typing to shared channel types.
lambdas/account-scoped/src/channelCapture/postSurveyListener.ts Tightens channel typing to shared ChannelType.
lambdas/account-scoped/src/channelCapture/channelCaptureHandlers.ts Tightens captured channel typing to shared ChannelType.
Suppressed comments (5)

plugin-hrm-form/src/voicemail/VoicemailTaskPanel.tsx:35

  • task is dereferenced in the selector (task.taskSid) before the null guard, which can throw if the task context hasn’t been provided yet. Guard taskSid before calling selectContactByTaskSid so the component can safely render null when task is missing.
    lambdas/account-scoped/src/voicemail/recordingCompleteCallback.ts:39
  • Avoid logging the full webhook body (it includes PII like from, and potentially routing attributes). Also validate required fields (from, callSid, recordingSid, voicemailWorkflowSid) up-front so malformed callbacks return a controlled 400 instead of throwing downstream.
  console.debug('recordingCompleteCallback body', JSON.stringify(body, null, 2));
  const { from, callSid, recordingSid, maxCallbackAttempts } =
    body as RecordingCompleteCallbackRequestBody;

lambdas/account-scoped/src/voicemail/recordingCompleteCallback.ts:56

  • In the nested catch block you log recordingError instead of the actual callError, which makes troubleshooting fallback failures misleading.
        recordingError,

lambdas/account-scoped/src/voicemail/recordingCompleteCallback.ts:71

  • JSON.parse(body.routingAttributes) can throw and fail the whole callback if routingAttributes is missing or malformed. Since this is webhook input, parse defensively and fall back to {} on invalid JSON.
      attributes: JSON.stringify({
        ...(body.routingAttributes ? JSON.parse(body.routingAttributes) : {}),
        receivedTime: receivedTime.toISOString(),
        callbackAttemptsMade: 0,
        maxCallbackAttempts: maxCallbackAttempts ?? DEFAULT_MAX_CALLBACK_ATTEMPTS,

plugin-hrm-form/src/voicemail/VoicemailTaskPanel.tsx:53

  • externalStoredRecording can be undefined, but the panel still renders RecordingSection with autoLoad. With the current RecordingSection implementation this can trigger an exception path when no S3 recording exists yet. Also, the current file had a placeholder “Retry later” action; until it’s implemented it’s safer to keep it out of the UI.

Comment thread plugin-hrm-form/src/voicemail/VoicemailTaskPanel.tsx Outdated
Comment on lines +39 to +42
import {
ChannelType,
isAseloCustomChannelType,
} from '@tech-matters/twilio-types/src/channelType';
Comment thread plugin-hrm-form/src/transfer/transferTaskState.ts
Comment thread lambdas/account-scoped/src/router.ts
Comment thread lambdas/account-scoped/src/voicemail/recordingCompleteCallback.ts Outdated
Comment thread lambdas/account-scoped/src/voicemail/recordingCompleteCallback.ts
Comment thread lambdas/account-scoped/src/hrm/createHrmContactTaskRouterListener.ts Outdated
stephenhand and others added 4 commits August 4, 2026 15:55
Co-authored-by: Copilot Autofix powered by AI <175728472+Copilot@users.noreply.github.com>
Co-authored-by: Copilot Autofix powered by AI <175728472+Copilot@users.noreply.github.com>
Co-authored-by: Copilot Autofix powered by AI <175728472+Copilot@users.noreply.github.com>
…into CHI-3946-productionise_backend

# Conflicts:
#	lambdas/account-scoped/src/voicemail/recordingCompleteCallback.ts
@stephenhand

Copy link
Copy Markdown
Collaborator Author

@copilot Fix the failing tests and linter issues

Co-authored-by: stephenhand <1694716+stephenhand@users.noreply.github.com>

Copilot AI commented Aug 4, 2026

Copy link
Copy Markdown
Contributor

@copilot Fix the failing tests and linter issues

Fixed in the latest commit:

  • Removed unused channelTypes import from VoicemailTaskPanel.tsx
  • Updated janitorTaskRouterListener.ts and createHrmContactTaskRouterListener.ts to import from the @tech-matters/twilio-types package entrypoint instead of internal paths
  • Replaced the ('voicemail' as any) cast with channelTypes.VOICEMAIL
  • Updated transferTaskState.test.ts to mock isVoiceTask instead of isChatBasedTask to match the updated canTransferConference implementation — all 27 tests pass

@stephenhand

Copy link
Copy Markdown
Collaborator Author

@copilot Rework the code that posts conversationMedia to the HRM backend service. Currently requests are initiated from the flex front end plugin, or as part of the contact creation portion of the contact creation

Move all conversation media item creation to task router event handlers in the account scoped lambda. Voice recordings and transcripts media records should be created on task wrapup / completion, voicemail should continue to be executed from its current location but share common code

Retain the current flex code, have a feature flag to control whether conversationMedia items are created from Flex or the task router handler

Do this work in a separate PR

Copilot AI commented Aug 4, 2026

Copy link
Copy Markdown
Contributor

@stephenhand I've opened a new pull request, #4578, to work on those changes. Once the pull request is ready, I'll request review from you.

@stephenhand

Copy link
Copy Markdown
Collaborator Author

@copilot fix the failing lambda unit test by mocking patchTaskAttributes and expecting it to have been called with the correct attributes rather than testing for the underlying Twilio API call

…askAttributes

Co-authored-by: stephenhand <1694716+stephenhand@users.noreply.github.com>

Copilot AI commented Aug 5, 2026

Copy link
Copy Markdown
Contributor

@copilot fix the failing lambda unit test by mocking patchTaskAttributes and expecting it to have been called with the correct attributes rather than testing for the underlying Twilio API call

Fixed in the latest commit. The test now mocks patchTaskAttributes directly (rather than the underlying Twilio fetch/update calls) and asserts it is called with the correct accountSid, taskSid, and an attributes generator function that produces the expected contactId patch.

@stephenhand

Copy link
Copy Markdown
Collaborator Author

@copilot Add comprehensive unit test coverage for the new or extended lambda code in this PR

Co-authored-by: stephenhand <1694716+stephenhand@users.noreply.github.com>

Copilot AI commented Aug 5, 2026

Copy link
Copy Markdown
Contributor

@copilot Add comprehensive unit test coverage for the new or extended lambda code in this PR

Added comprehensive unit tests in the latest commit:

New file: tests/unit/voicemail/recordingCompleteCallback.test.ts (9 tests)

  • Missing callSid / from parameters return 400 errors
  • Creates task with recording start time when recording is found
  • Falls back to call start time when recording fetch fails
  • Falls back to current time when both recording and call fetches fail
  • routingAttributes are merged into task attributes
  • Custom maxCallbackAttempts overrides the default of 3
  • Proceeds without recordingSid (falls back gracefully)
  • Returns the created task in the ok result

Extended: tests/unit/hrm/createHrmContactTaskRouterListener.test.ts (3 new tests)

  • Voicemail task: creates contact and POSTs conversationMedia with correct S3 location
  • Voicemail task: skips conversationMedia POST when recording lookup fails
  • Non-voicemail task: does not call getExternalRecordingS3Location at all

All 44 unit test suites (402 tests) pass.

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

4 participants