From fd5a645b31e8e4d29f3195e42aca85ba6783118b Mon Sep 17 00:00:00 2001 From: Mike Wild Date: Tue, 10 Feb 2026 15:49:45 +0000 Subject: [PATCH 01/14] First pass implementation --- .../module_transform_filter_lambda.tf | 13 ++ .../callbacks/s3_bucket_client_config.tf | 116 ++++++++++++++++++ .../src/models/callback-event.ts | 62 ++++++++++ .../src/models/channel-status-data.ts | 55 +++++++++ .../src/models/client-callback-payload.ts | 55 +++++++++ .../src/models/client-config.ts | 49 ++++++++ .../src/models/message-status-data.ts | 41 +++++++ .../tsconfig.json | 3 + 8 files changed, 394 insertions(+) create mode 100644 infrastructure/terraform/components/callbacks/s3_bucket_client_config.tf create mode 100644 lambdas/client-transform-filter-lambda/src/models/callback-event.ts create mode 100644 lambdas/client-transform-filter-lambda/src/models/channel-status-data.ts create mode 100644 lambdas/client-transform-filter-lambda/src/models/client-callback-payload.ts create mode 100644 lambdas/client-transform-filter-lambda/src/models/client-config.ts create mode 100644 lambdas/client-transform-filter-lambda/src/models/message-status-data.ts diff --git a/infrastructure/terraform/components/callbacks/module_transform_filter_lambda.tf b/infrastructure/terraform/components/callbacks/module_transform_filter_lambda.tf index c0ce5da..d151c99 100644 --- a/infrastructure/terraform/components/callbacks/module_transform_filter_lambda.tf +++ b/infrastructure/terraform/components/callbacks/module_transform_filter_lambda.tf @@ -52,4 +52,17 @@ data "aws_iam_policy_document" "example_lambda" { module.kms.key_arn, ## Requires shared kms module ] } + + statement { + sid = "S3ClientConfigReadAccess" + effect = "Allow" + + actions = [ + "s3:GetObject", + ] + + resources = [ + "${aws_s3_bucket.client_config.arn}/*", + ] + } } diff --git a/infrastructure/terraform/components/callbacks/s3_bucket_client_config.tf b/infrastructure/terraform/components/callbacks/s3_bucket_client_config.tf new file mode 100644 index 0000000..d3b7208 --- /dev/null +++ b/infrastructure/terraform/components/callbacks/s3_bucket_client_config.tf @@ -0,0 +1,116 @@ +## +# S3 Bucket for Client Subscription Configuration +# +# Storage location for client subscription configurations loaded by Transform & Filter Lambda. +# Files are named {clientId}.json and contain ClientSubscriptionConfiguration arrays. +## + +resource "aws_s3_bucket" "client_config" { + bucket = "${local.csi}-client-config" + force_destroy = false + + tags = merge( + local.default_tags, + { + Name = "${local.csi}-client-config" + Description = "Client subscription configuration storage" + }, + ) +} + +resource "aws_s3_bucket_ownership_controls" "client_config" { + bucket = aws_s3_bucket.client_config.id + + rule { + object_ownership = "BucketOwnerPreferred" + } +} + +resource "aws_s3_bucket_server_side_encryption_configuration" "client_config" { + bucket = aws_s3_bucket.client_config.id + + rule { + apply_server_side_encryption_by_default { + sse_algorithm = "aws:kms" + kms_master_key_id = module.kms.key_arn + } + bucket_key_enabled = true + } +} + +resource "aws_s3_bucket_versioning" "client_config" { + bucket = aws_s3_bucket.client_config.id + + versioning_configuration { + status = "Enabled" + } +} + +resource "aws_s3_bucket_public_access_block" "client_config" { + depends_on = [ + aws_s3_bucket_policy.client_config + ] + + bucket = aws_s3_bucket.client_config.id + + block_public_acls = true + block_public_policy = true + ignore_public_acls = true + restrict_public_buckets = true +} + +## +# S3 Bucket Policy +# +# Allows EventBridge Pipes enrichment Lambda to read configuration files +## + +resource "aws_s3_bucket_policy" "client_config" { + bucket = aws_s3_bucket.client_config.id + policy = data.aws_iam_policy_document.client_config_bucket.json +} + +data "aws_iam_policy_document" "client_config_bucket" { + statement { + sid = "AllowLambdaReadAccess" + effect = "Allow" + + principals { + type = "AWS" + identifiers = [module.client_transform_filter_lambda.lambda_role_arn] + } + + actions = [ + "s3:GetObject", + ] + + resources = [ + "${aws_s3_bucket.client_config.arn}/*", + ] + } + + statement { + sid = "DenyInsecureTransport" + effect = "Deny" + + principals { + type = "*" + identifiers = ["*"] + } + + actions = [ + "s3:*", + ] + + resources = [ + aws_s3_bucket.client_config.arn, + "${aws_s3_bucket.client_config.arn}/*" + ] + + condition { + test = "Bool" + variable = "aws:SecureTransport" + values = ["false"] + } + } +} diff --git a/lambdas/client-transform-filter-lambda/src/models/callback-event.ts b/lambdas/client-transform-filter-lambda/src/models/callback-event.ts new file mode 100644 index 0000000..984bcc1 --- /dev/null +++ b/lambdas/client-transform-filter-lambda/src/models/callback-event.ts @@ -0,0 +1,62 @@ +/** + * CloudEvents-compliant event structure for callback delivery. + * Events carry complete payloads to avoid additional lookups. + */ + +import type { MessageStatusData } from "models/message-status-data"; +import type { ChannelStatusData } from "models/channel-status-data"; + +export interface NotifyMetadata { + teamResponsible: "Team 1" | "Team 2" | "Team 3"; + notifyDomain: "Ordering" | "Delivering" | "Reporting" | "Enquiries"; + microservice: string; + repositoryUrl: string; + accountId: string; + environment: "development" | "testing" | "staging" | "production"; + instance: string; + microserviceInstanceId: string; + microserviceVersion: string; +} + +export interface CallbackEvent { + profileversion: string; + profilepublished: string; + specversion: string; + id: string; + source: string; + subject: string; + type: string; + time: string; + recordedtime: string; + datacontenttype: string; + dataschema: string; + severitynumber: number; + severitytext: string; + traceparent: string; + + data: { + "notify-payload": { + "notify-data": T; + "notify-metadata": NotifyMetadata; + }; + }; +} + +export const EventTypes = { + MESSAGE_STATUS_TRANSITIONED: + "uk.nhs.notify.client-callbacks.message.status.transitioned.v1", + CHANNEL_STATUS_TRANSITIONED: + "uk.nhs.notify.client-callbacks.channel.status.transitioned.v1", +} as const; + +export { type MessageStatusData } from "./message-status-data"; +export { + type Channel, + type RoutingPlan, + type MessageStatus, +} from "models/message-status-data"; +export { + type ChannelStatus, + type SupplierStatus, + type ChannelStatusData, +} from "models/channel-status-data"; diff --git a/lambdas/client-transform-filter-lambda/src/models/channel-status-data.ts b/lambdas/client-transform-filter-lambda/src/models/channel-status-data.ts new file mode 100644 index 0000000..fa5bd1a --- /dev/null +++ b/lambdas/client-transform-filter-lambda/src/models/channel-status-data.ts @@ -0,0 +1,55 @@ +/** + * Channel-specific status change events. + * Contains fields for callback construction and subscription filtering. + */ + +export type Channel = "nhsapp" | "email" | "sms" | "letter"; + +export type ChannelStatus = + | "created" + | "sending" + | "delivered" + | "failed" + | "skipped"; + +export type SupplierStatus = + | "delivered" + | "read" + | "notification_attempted" + | "unnotified" + | "rejected" + | "notified" + | "received" + | "permanent_failure" + | "temporary_failure" + | "technical_failure" + | "accepted" + | "cancelled" + | "pending_virus_check" + | "validation_failed" + | "unknown"; + +/** + * Operational fields (nhsNumber, sendingGroupId, delayedFallback) are NOT included in client callbacks. + */ +export interface ChannelStatusData { + messageId: string; + messageReference: string; + channel: Channel; + channelStatus: ChannelStatus; + channelStatusDescription?: string; + channelFailureReasonCode?: string; + supplierStatus: SupplierStatus; + cascadeType: "primary" | "secondary"; + cascadeOrder: number; + timestamp: string; + retryCount: number; + + clientId: string; + previousChannelStatus?: ChannelStatus; + previousSupplierStatus?: string; + + nhsNumber?: string; + sendingGroupId?: string; + delayedFallback?: boolean; +} diff --git a/lambdas/client-transform-filter-lambda/src/models/client-callback-payload.ts b/lambdas/client-transform-filter-lambda/src/models/client-callback-payload.ts new file mode 100644 index 0000000..15bf9d6 --- /dev/null +++ b/lambdas/client-transform-filter-lambda/src/models/client-callback-payload.ts @@ -0,0 +1,55 @@ +/** + * JSON:API-compliant callback payload delivered to client webhooks. + * Operational fields are excluded from all callback payloads. + */ + +import type { + Channel, + ChannelStatus, + MessageStatus, + SupplierStatus, +} from "models/callback-event"; +import type { RoutingPlan } from "models/message-status-data"; + +export interface ClientCallbackPayload { + data: CallbackItem[]; +} + +export interface CallbackItem { + type: "MessageStatus" | "ChannelStatus"; + attributes: MessageStatusAttributes | ChannelStatusAttributes; + links: { + message: string; + }; + meta: { + idempotencyKey: string; + }; +} + +export interface MessageStatusAttributes { + messageId: string; + messageReference: string; + messageStatus: MessageStatus; + messageStatusDescription?: string; + messageFailureReasonCode?: string; + channels: { + type: Channel; + channelStatus: "delivered" | "failed"; + }[]; + timestamp: string; + routingPlan: RoutingPlan; +} + +export interface ChannelStatusAttributes { + messageId: string; + messageReference: string; + cascadeType: "primary" | "secondary"; + cascadeOrder: number; + channel: Channel; + channelStatus: ChannelStatus; + channelStatusDescription?: string; + channelFailureReasonCode?: string; + supplierStatus: SupplierStatus; + timestamp: string; + retryCount: number; +} diff --git a/lambdas/client-transform-filter-lambda/src/models/client-config.ts b/lambdas/client-transform-filter-lambda/src/models/client-config.ts new file mode 100644 index 0000000..59c7086 --- /dev/null +++ b/lambdas/client-transform-filter-lambda/src/models/client-config.ts @@ -0,0 +1,49 @@ +/** + * Client callback subscription configuration. + * Array of subscription rules (one per event type/channel combination). + */ + +export type ClientSubscriptionConfiguration = ( + | MessageStatusSubscriptionConfiguration + | ChannelStatusSubscriptionConfiguration +)[]; + +interface SubscriptionConfigurationBase { + Name: string; + ClientId: string; + Description: string; + EventSource: string; + EventDetail: string; + Targets: { + Type: "API"; + TargetId: string; + Name: string; + InputTransformer: { + InputPaths: string; + InputHeaders: { + "x-hmac-sha256-signature": string; + }; + }; + InvocationEndpoint: string; + InvocationMethod: "POST"; + InvocationRateLimit: number; + APIKey: { + HeaderName: string; + HeaderValue: string; + }; + }[]; +} + +export interface MessageStatusSubscriptionConfiguration + extends SubscriptionConfigurationBase { + SubscriptionType: "MessageStatus"; + Statuses: string[]; +} + +export interface ChannelStatusSubscriptionConfiguration + extends SubscriptionConfigurationBase { + SubscriptionType: "ChannelStatus"; + ChannelType: string; + ChannelStatuses: string[]; + SupplierStatuses: string[]; +} diff --git a/lambdas/client-transform-filter-lambda/src/models/message-status-data.ts b/lambdas/client-transform-filter-lambda/src/models/message-status-data.ts new file mode 100644 index 0000000..6a82de4 --- /dev/null +++ b/lambdas/client-transform-filter-lambda/src/models/message-status-data.ts @@ -0,0 +1,41 @@ +/** + * Message-level status change events. + * Contains fields for callback construction and subscription filtering. + */ + +export type MessageStatus = + | "created" + | "pending_enrichment" + | "enriched" + | "sending" + | "delivered" + | "failed"; + +export type Channel = "nhsapp" | "email" | "sms" | "letter"; + +export interface RoutingPlan { + id: string; + name: string; +} + +/** + * Operational fields (nhsNumber, sendingGroupId) are NOT included in client callbacks. + */ +export interface MessageStatusData { + messageId: string; + messageReference: string; + messageStatus: MessageStatus; + messageStatusDescription?: string; + messageFailureReasonCode?: string; + channels: { + type: Channel; + channelStatus: string; + }[]; + timestamp: string; + routingPlan: RoutingPlan; + + clientId: string; + + nhsNumber?: string; + sendingGroupId?: string; +} diff --git a/lambdas/client-transform-filter-lambda/tsconfig.json b/lambdas/client-transform-filter-lambda/tsconfig.json index 9e05f63..bbff7bf 100644 --- a/lambdas/client-transform-filter-lambda/tsconfig.json +++ b/lambdas/client-transform-filter-lambda/tsconfig.json @@ -1,4 +1,7 @@ { + "compilerOptions": { + "baseUrl": "src" + }, "extends": "../../tsconfig.base.json", "include": [ "src/**/*", From 84ae5d57ecf9b600daa68ace9bcfed90dca61892 Mon Sep 17 00:00:00 2001 From: Mike Wild Date: Tue, 10 Feb 2026 16:17:16 +0000 Subject: [PATCH 02/14] Update lambda placeholder IAM policy name --- .../components/callbacks/module_transform_filter_lambda.tf | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/infrastructure/terraform/components/callbacks/module_transform_filter_lambda.tf b/infrastructure/terraform/components/callbacks/module_transform_filter_lambda.tf index d151c99..8720c24 100644 --- a/infrastructure/terraform/components/callbacks/module_transform_filter_lambda.tf +++ b/infrastructure/terraform/components/callbacks/module_transform_filter_lambda.tf @@ -15,7 +15,7 @@ module "client_transform_filter_lambda" { kms_key_arn = module.kms.key_arn ## Requires shared kms module iam_policy_document = { - body = data.aws_iam_policy_document.example_lambda.json + body = data.aws_iam_policy_document.client_transform_filter_lambda.json } function_s3_bucket = local.acct.s3_buckets["lambda_function_artefacts"]["id"] @@ -38,7 +38,7 @@ module "client_transform_filter_lambda" { } } -data "aws_iam_policy_document" "example_lambda" { +data "aws_iam_policy_document" "client_transform_filter_lambda" { statement { sid = "KMSPermissions" effect = "Allow" From 8f8f6af9d4c30abe5bb9ec064d09caecbc259754 Mon Sep 17 00:00:00 2001 From: Mike Wild Date: Tue, 10 Feb 2026 17:00:00 +0000 Subject: [PATCH 03/14] Use shared module for s3 config --- .../terraform/components/callbacks/README.md | 1 + .../module_transform_filter_lambda.tf | 2 +- .../callbacks/s3_bucket_client_config.tf | 78 ++++++------------- 3 files changed, 26 insertions(+), 55 deletions(-) diff --git a/infrastructure/terraform/components/callbacks/README.md b/infrastructure/terraform/components/callbacks/README.md index d69eaeb..0040c28 100644 --- a/infrastructure/terraform/components/callbacks/README.md +++ b/infrastructure/terraform/components/callbacks/README.md @@ -32,6 +32,7 @@ | Name | Source | Version | |------|--------|---------| +| [client\_config\_bucket](#module\_client\_config\_bucket) | https://github.com/NHSDigital/nhs-notify-shared-modules/releases/download/v2.0.28/terraform-s3bucket.zip | n/a | | [client\_destination](#module\_client\_destination) | ../../modules/client-destination | n/a | | [client\_transform\_filter\_lambda](#module\_client\_transform\_filter\_lambda) | git::https://github.com/NHSDigital/nhs-notify-shared-modules.git//infrastructure/modules/lambda | v2.0.29 | | [kms](#module\_kms) | https://github.com/NHSDigital/nhs-notify-shared-modules/releases/download/v2.0.29/terraform-kms.zip | n/a | diff --git a/infrastructure/terraform/components/callbacks/module_transform_filter_lambda.tf b/infrastructure/terraform/components/callbacks/module_transform_filter_lambda.tf index 8720c24..ebbb3b0 100644 --- a/infrastructure/terraform/components/callbacks/module_transform_filter_lambda.tf +++ b/infrastructure/terraform/components/callbacks/module_transform_filter_lambda.tf @@ -62,7 +62,7 @@ data "aws_iam_policy_document" "client_transform_filter_lambda" { ] resources = [ - "${aws_s3_bucket.client_config.arn}/*", + "${module.client_config_bucket.arn}/*", ] } } diff --git a/infrastructure/terraform/components/callbacks/s3_bucket_client_config.tf b/infrastructure/terraform/components/callbacks/s3_bucket_client_config.tf index d3b7208..22e3e44 100644 --- a/infrastructure/terraform/components/callbacks/s3_bucket_client_config.tf +++ b/infrastructure/terraform/components/callbacks/s3_bucket_client_config.tf @@ -5,71 +5,41 @@ # Files are named {clientId}.json and contain ClientSubscriptionConfiguration arrays. ## -resource "aws_s3_bucket" "client_config" { - bucket = "${local.csi}-client-config" - force_destroy = false +module "client_config_bucket" { + source = "https://github.com/NHSDigital/nhs-notify-shared-modules/releases/download/v2.0.28/terraform-s3bucket.zip" - tags = merge( + name = "client-config" + + aws_account_id = var.aws_account_id + component = var.component + environment = var.environment + project = var.project + region = var.region + + default_tags = merge( local.default_tags, { - Name = "${local.csi}-client-config" Description = "Client subscription configuration storage" - }, - ) -} - -resource "aws_s3_bucket_ownership_controls" "client_config" { - bucket = aws_s3_bucket.client_config.id - - rule { - object_ownership = "BucketOwnerPreferred" - } -} - -resource "aws_s3_bucket_server_side_encryption_configuration" "client_config" { - bucket = aws_s3_bucket.client_config.id - - rule { - apply_server_side_encryption_by_default { - sse_algorithm = "aws:kms" - kms_master_key_id = module.kms.key_arn } - bucket_key_enabled = true - } -} - -resource "aws_s3_bucket_versioning" "client_config" { - bucket = aws_s3_bucket.client_config.id + ) - versioning_configuration { - status = "Enabled" - } -} + kms_key_arn = module.kms.key_arn + force_destroy = false + versioning = true + object_ownership = "BucketOwnerPreferred" + bucket_key_enabled = true -resource "aws_s3_bucket_public_access_block" "client_config" { - depends_on = [ - aws_s3_bucket_policy.client_config + policy_documents = [ + data.aws_iam_policy_document.client_config_bucket.json ] - - bucket = aws_s3_bucket.client_config.id - - block_public_acls = true - block_public_policy = true - ignore_public_acls = true - restrict_public_buckets = true } ## # S3 Bucket Policy # -# Allows EventBridge Pipes enrichment Lambda to read configuration files +# Allows Transform & Filter Lambda to read configuration files ## -resource "aws_s3_bucket_policy" "client_config" { - bucket = aws_s3_bucket.client_config.id - policy = data.aws_iam_policy_document.client_config_bucket.json -} - data "aws_iam_policy_document" "client_config_bucket" { statement { sid = "AllowLambdaReadAccess" @@ -77,7 +47,7 @@ data "aws_iam_policy_document" "client_config_bucket" { principals { type = "AWS" - identifiers = [module.client_transform_filter_lambda.lambda_role_arn] + identifiers = [module.client_transform_filter_lambda.iam_role_arn] } actions = [ @@ -85,7 +55,7 @@ data "aws_iam_policy_document" "client_config_bucket" { ] resources = [ - "${aws_s3_bucket.client_config.arn}/*", + "${module.client_config_bucket.arn}/*", ] } @@ -103,8 +73,8 @@ data "aws_iam_policy_document" "client_config_bucket" { ] resources = [ - aws_s3_bucket.client_config.arn, - "${aws_s3_bucket.client_config.arn}/*" + module.client_config_bucket.arn, + "${module.client_config_bucket.arn}/*" ] condition { From 924357dc83814e52e18b08a108cf82df5cde934e Mon Sep 17 00:00:00 2001 From: Mike Wild Date: Wed, 11 Feb 2026 15:30:59 +0000 Subject: [PATCH 04/14] Fix sonar scanner props --- scripts/config/sonar-scanner.properties | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/scripts/config/sonar-scanner.properties b/scripts/config/sonar-scanner.properties index 9fbc7fc..41482f4 100644 --- a/scripts/config/sonar-scanner.properties +++ b/scripts/config/sonar-scanner.properties @@ -3,8 +3,8 @@ sonar.host.url=https://sonarcloud.io sonar.qualitygate.wait=true sonar.sourceEncoding=UTF-8 -sonar.sources=lambdas/example-lambda -sonar.tests=tests/, lambdas/example-lambda/src/__tests__ +sonar.sources=lambdas/client-transform-filter-lambda +sonar.tests=tests/, lambdas/client-transform-filter-lambda/src/__tests__ sonar.exclusions=lambdas/*/src/__tests__/**/* sonar.terraform.provider.aws.version=5.54.1 sonar.cpd.exclusions=**.test.* From 11c6c81ab41525811f6e4da704d66bee05e45d34 Mon Sep 17 00:00:00 2001 From: Mike Wild Date: Thu, 12 Feb 2026 09:49:28 +0000 Subject: [PATCH 05/14] Placeholder tests to test coverage --- .../src/__tests__/models/callback-event.test.ts | 13 +++++++++++++ 1 file changed, 13 insertions(+) create mode 100644 lambdas/client-transform-filter-lambda/src/__tests__/models/callback-event.test.ts diff --git a/lambdas/client-transform-filter-lambda/src/__tests__/models/callback-event.test.ts b/lambdas/client-transform-filter-lambda/src/__tests__/models/callback-event.test.ts new file mode 100644 index 0000000..6d06f1d --- /dev/null +++ b/lambdas/client-transform-filter-lambda/src/__tests__/models/callback-event.test.ts @@ -0,0 +1,13 @@ +import { EventTypes } from "models/callback-event"; + +// coverage purposes +describe("EventTypes", () => { + it("should match the expected event type values", () => { + expect(EventTypes).toEqual({ + MESSAGE_STATUS_TRANSITIONED: + "uk.nhs.notify.client-callbacks.message.status.transitioned.v1", + CHANNEL_STATUS_TRANSITIONED: + "uk.nhs.notify.client-callbacks.channel.status.transitioned.v1", + }); + }); +}); From 4e27d7a2dd52fa616d85fb147abf1c0d4dfbda9c Mon Sep 17 00:00:00 2001 From: Mike Wild Date: Thu, 12 Feb 2026 09:59:24 +0000 Subject: [PATCH 06/14] Fix lambda jest config --- lambdas/client-transform-filter-lambda/jest.config.ts | 3 +++ 1 file changed, 3 insertions(+) diff --git a/lambdas/client-transform-filter-lambda/jest.config.ts b/lambdas/client-transform-filter-lambda/jest.config.ts index f88e727..4cec36d 100644 --- a/lambdas/client-transform-filter-lambda/jest.config.ts +++ b/lambdas/client-transform-filter-lambda/jest.config.ts @@ -55,6 +55,9 @@ const utilsJestConfig = { ...(baseJestConfig.coveragePathIgnorePatterns ?? []), "zod-validators.ts", ], + + // Mirror tsconfig's baseUrl: "src" - automatically resolves non-relative imports + modulePaths: ["/src"], }; export default utilsJestConfig; From a1fa0790779586ff9d5d475cd8ca2d5e8194d030 Mon Sep 17 00:00:00 2001 From: Mike Wild Date: Thu, 12 Feb 2026 15:17:27 +0000 Subject: [PATCH 07/14] Better name for config bucket --- .../terraform/components/callbacks/s3_bucket_client_config.tf | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/infrastructure/terraform/components/callbacks/s3_bucket_client_config.tf b/infrastructure/terraform/components/callbacks/s3_bucket_client_config.tf index 22e3e44..9f468ea 100644 --- a/infrastructure/terraform/components/callbacks/s3_bucket_client_config.tf +++ b/infrastructure/terraform/components/callbacks/s3_bucket_client_config.tf @@ -8,7 +8,7 @@ module "client_config_bucket" { source = "https://github.com/NHSDigital/nhs-notify-shared-modules/releases/download/v2.0.28/terraform-s3bucket.zip" - name = "client-config" + name = "subscription-config" aws_account_id = var.aws_account_id component = var.component From ff1695246d49245a2e9d2d652ed5dd031c2f3292 Mon Sep 17 00:00:00 2001 From: Mike Wild Date: Thu, 12 Feb 2026 15:52:38 +0000 Subject: [PATCH 08/14] Update with data-model changes --- .../src/__tests__/models/callback-event.test.ts | 2 +- .../src/models/channel-status-data.ts | 8 ++++---- .../src/models/client-callback-payload.ts | 4 ++-- .../src/models/message-status-data.ts | 8 ++------ .../src/models/routing-plan.ts | 9 +++++++++ .../models/{callback-event.ts => status-change-event.ts} | 8 ++------ 6 files changed, 20 insertions(+), 19 deletions(-) create mode 100644 lambdas/client-transform-filter-lambda/src/models/routing-plan.ts rename lambdas/client-transform-filter-lambda/src/models/{callback-event.ts => status-change-event.ts} (89%) diff --git a/lambdas/client-transform-filter-lambda/src/__tests__/models/callback-event.test.ts b/lambdas/client-transform-filter-lambda/src/__tests__/models/callback-event.test.ts index 6d06f1d..961b1c3 100644 --- a/lambdas/client-transform-filter-lambda/src/__tests__/models/callback-event.test.ts +++ b/lambdas/client-transform-filter-lambda/src/__tests__/models/callback-event.test.ts @@ -1,4 +1,4 @@ -import { EventTypes } from "models/callback-event"; +import { EventTypes } from "models/status-change-event"; // coverage purposes describe("EventTypes", () => { diff --git a/lambdas/client-transform-filter-lambda/src/models/channel-status-data.ts b/lambdas/client-transform-filter-lambda/src/models/channel-status-data.ts index fa5bd1a..8769554 100644 --- a/lambdas/client-transform-filter-lambda/src/models/channel-status-data.ts +++ b/lambdas/client-transform-filter-lambda/src/models/channel-status-data.ts @@ -2,6 +2,7 @@ * Channel-specific status change events. * Contains fields for callback construction and subscription filtering. */ +import type { RoutingPlan } from "models/routing-plan"; export type Channel = "nhsapp" | "email" | "sms" | "letter"; @@ -30,7 +31,7 @@ export type SupplierStatus = | "unknown"; /** - * Operational fields (nhsNumber, sendingGroupId, delayedFallback) are NOT included in client callbacks. + * Operational fields (nhsNumber, routingPlan) are NOT included in client callbacks. */ export interface ChannelStatusData { messageId: string; @@ -47,9 +48,8 @@ export interface ChannelStatusData { clientId: string; previousChannelStatus?: ChannelStatus; - previousSupplierStatus?: string; + previousSupplierStatus?: SupplierStatus; nhsNumber?: string; - sendingGroupId?: string; - delayedFallback?: boolean; + routingPlan: RoutingPlan; } diff --git a/lambdas/client-transform-filter-lambda/src/models/client-callback-payload.ts b/lambdas/client-transform-filter-lambda/src/models/client-callback-payload.ts index 15bf9d6..793745e 100644 --- a/lambdas/client-transform-filter-lambda/src/models/client-callback-payload.ts +++ b/lambdas/client-transform-filter-lambda/src/models/client-callback-payload.ts @@ -8,8 +8,8 @@ import type { ChannelStatus, MessageStatus, SupplierStatus, -} from "models/callback-event"; -import type { RoutingPlan } from "models/message-status-data"; +} from "models/status-change-event"; +import type { RoutingPlan } from "models/routing-plan"; export interface ClientCallbackPayload { data: CallbackItem[]; diff --git a/lambdas/client-transform-filter-lambda/src/models/message-status-data.ts b/lambdas/client-transform-filter-lambda/src/models/message-status-data.ts index 6a82de4..a906539 100644 --- a/lambdas/client-transform-filter-lambda/src/models/message-status-data.ts +++ b/lambdas/client-transform-filter-lambda/src/models/message-status-data.ts @@ -2,6 +2,7 @@ * Message-level status change events. * Contains fields for callback construction and subscription filtering. */ +import type { RoutingPlan } from "models/routing-plan"; export type MessageStatus = | "created" @@ -13,11 +14,6 @@ export type MessageStatus = export type Channel = "nhsapp" | "email" | "sms" | "letter"; -export interface RoutingPlan { - id: string; - name: string; -} - /** * Operational fields (nhsNumber, sendingGroupId) are NOT included in client callbacks. */ @@ -35,7 +31,7 @@ export interface MessageStatusData { routingPlan: RoutingPlan; clientId: string; + previousMessageStatus?: MessageStatus; nhsNumber?: string; - sendingGroupId?: string; } diff --git a/lambdas/client-transform-filter-lambda/src/models/routing-plan.ts b/lambdas/client-transform-filter-lambda/src/models/routing-plan.ts new file mode 100644 index 0000000..f71882e --- /dev/null +++ b/lambdas/client-transform-filter-lambda/src/models/routing-plan.ts @@ -0,0 +1,9 @@ +/** + * Routing plan metadata + */ +export interface RoutingPlan { + id: string; + name: string; + version: string; + createdDate: string; +} diff --git a/lambdas/client-transform-filter-lambda/src/models/callback-event.ts b/lambdas/client-transform-filter-lambda/src/models/status-change-event.ts similarity index 89% rename from lambdas/client-transform-filter-lambda/src/models/callback-event.ts rename to lambdas/client-transform-filter-lambda/src/models/status-change-event.ts index 984bcc1..9f213ec 100644 --- a/lambdas/client-transform-filter-lambda/src/models/callback-event.ts +++ b/lambdas/client-transform-filter-lambda/src/models/status-change-event.ts @@ -18,7 +18,7 @@ export interface NotifyMetadata { microserviceVersion: string; } -export interface CallbackEvent { +export interface StatusChangeEvent { profileversion: string; profilepublished: string; specversion: string; @@ -50,11 +50,7 @@ export const EventTypes = { } as const; export { type MessageStatusData } from "./message-status-data"; -export { - type Channel, - type RoutingPlan, - type MessageStatus, -} from "models/message-status-data"; +export { type Channel, type MessageStatus } from "models/message-status-data"; export { type ChannelStatus, type SupplierStatus, From ded5a058f53d556c8da6c6eb77a80a3def66a73d Mon Sep 17 00:00:00 2001 From: Mike Wild Date: Fri, 13 Feb 2026 11:55:23 +0000 Subject: [PATCH 09/14] Update event names/terminology and remove nhsnumber, routingplan fields which aren't needed --- ...-event.test.ts => status-transition-event.test.ts} | 2 +- .../src/models/channel-status-data.ts | 11 +---------- .../src/models/client-callback-payload.ts | 5 ++--- .../src/models/message-status-data.ts | 8 +------- .../src/models/routing-plan.ts | 3 --- ...tus-change-event.ts => status-transition-event.ts} | 4 +++- 6 files changed, 8 insertions(+), 25 deletions(-) rename lambdas/client-transform-filter-lambda/src/__tests__/models/{callback-event.test.ts => status-transition-event.test.ts} (86%) rename lambdas/client-transform-filter-lambda/src/models/{status-change-event.ts => status-transition-event.ts} (94%) diff --git a/lambdas/client-transform-filter-lambda/src/__tests__/models/callback-event.test.ts b/lambdas/client-transform-filter-lambda/src/__tests__/models/status-transition-event.test.ts similarity index 86% rename from lambdas/client-transform-filter-lambda/src/__tests__/models/callback-event.test.ts rename to lambdas/client-transform-filter-lambda/src/__tests__/models/status-transition-event.test.ts index 961b1c3..19f1244 100644 --- a/lambdas/client-transform-filter-lambda/src/__tests__/models/callback-event.test.ts +++ b/lambdas/client-transform-filter-lambda/src/__tests__/models/status-transition-event.test.ts @@ -1,4 +1,4 @@ -import { EventTypes } from "models/status-change-event"; +import { EventTypes } from "models/status-transition-event"; // coverage purposes describe("EventTypes", () => { diff --git a/lambdas/client-transform-filter-lambda/src/models/channel-status-data.ts b/lambdas/client-transform-filter-lambda/src/models/channel-status-data.ts index 8769554..6ee3839 100644 --- a/lambdas/client-transform-filter-lambda/src/models/channel-status-data.ts +++ b/lambdas/client-transform-filter-lambda/src/models/channel-status-data.ts @@ -1,9 +1,6 @@ /** - * Channel-specific status change events. - * Contains fields for callback construction and subscription filtering. + * Channel-level status transition event data. */ -import type { RoutingPlan } from "models/routing-plan"; - export type Channel = "nhsapp" | "email" | "sms" | "letter"; export type ChannelStatus = @@ -30,9 +27,6 @@ export type SupplierStatus = | "validation_failed" | "unknown"; -/** - * Operational fields (nhsNumber, routingPlan) are NOT included in client callbacks. - */ export interface ChannelStatusData { messageId: string; messageReference: string; @@ -49,7 +43,4 @@ export interface ChannelStatusData { clientId: string; previousChannelStatus?: ChannelStatus; previousSupplierStatus?: SupplierStatus; - - nhsNumber?: string; - routingPlan: RoutingPlan; } diff --git a/lambdas/client-transform-filter-lambda/src/models/client-callback-payload.ts b/lambdas/client-transform-filter-lambda/src/models/client-callback-payload.ts index 793745e..c5e8127 100644 --- a/lambdas/client-transform-filter-lambda/src/models/client-callback-payload.ts +++ b/lambdas/client-transform-filter-lambda/src/models/client-callback-payload.ts @@ -1,6 +1,5 @@ /** - * JSON:API-compliant callback payload delivered to client webhooks. - * Operational fields are excluded from all callback payloads. + * Message/Channel Status Callback payload delivered to client webhooks. */ import type { @@ -8,7 +7,7 @@ import type { ChannelStatus, MessageStatus, SupplierStatus, -} from "models/status-change-event"; +} from "models/status-transition-event"; import type { RoutingPlan } from "models/routing-plan"; export interface ClientCallbackPayload { diff --git a/lambdas/client-transform-filter-lambda/src/models/message-status-data.ts b/lambdas/client-transform-filter-lambda/src/models/message-status-data.ts index a906539..896937e 100644 --- a/lambdas/client-transform-filter-lambda/src/models/message-status-data.ts +++ b/lambdas/client-transform-filter-lambda/src/models/message-status-data.ts @@ -1,6 +1,5 @@ /** - * Message-level status change events. - * Contains fields for callback construction and subscription filtering. + * Message-level status transition event data. */ import type { RoutingPlan } from "models/routing-plan"; @@ -14,9 +13,6 @@ export type MessageStatus = export type Channel = "nhsapp" | "email" | "sms" | "letter"; -/** - * Operational fields (nhsNumber, sendingGroupId) are NOT included in client callbacks. - */ export interface MessageStatusData { messageId: string; messageReference: string; @@ -32,6 +28,4 @@ export interface MessageStatusData { clientId: string; previousMessageStatus?: MessageStatus; - - nhsNumber?: string; } diff --git a/lambdas/client-transform-filter-lambda/src/models/routing-plan.ts b/lambdas/client-transform-filter-lambda/src/models/routing-plan.ts index f71882e..07f348a 100644 --- a/lambdas/client-transform-filter-lambda/src/models/routing-plan.ts +++ b/lambdas/client-transform-filter-lambda/src/models/routing-plan.ts @@ -1,6 +1,3 @@ -/** - * Routing plan metadata - */ export interface RoutingPlan { id: string; name: string; diff --git a/lambdas/client-transform-filter-lambda/src/models/status-change-event.ts b/lambdas/client-transform-filter-lambda/src/models/status-transition-event.ts similarity index 94% rename from lambdas/client-transform-filter-lambda/src/models/status-change-event.ts rename to lambdas/client-transform-filter-lambda/src/models/status-transition-event.ts index 9f213ec..e53d9e7 100644 --- a/lambdas/client-transform-filter-lambda/src/models/status-change-event.ts +++ b/lambdas/client-transform-filter-lambda/src/models/status-transition-event.ts @@ -18,7 +18,9 @@ export interface NotifyMetadata { microserviceVersion: string; } -export interface StatusChangeEvent { +export interface StatusTransitionEvent< + T = MessageStatusData | ChannelStatusData, +> { profileversion: string; profilepublished: string; specversion: string; From 7f340cc24f69b5eeabc44b7672d3b6b006b6f426 Mon Sep 17 00:00:00 2001 From: Mike Wild Date: Fri, 13 Feb 2026 14:31:49 +0000 Subject: [PATCH 10/14] Refactor model type structure --- .../src/models/channel-status-data.ts | 27 +------------ .../src/models/channel-types.ts | 4 ++ .../src/models/client-callback-payload.ts | 23 ++++++----- .../src/models/message-status-data.ts | 12 +----- .../src/models/status-transition-event.ts | 13 +----- .../src/models/status-types.ts | 40 +++++++++++++++++++ 6 files changed, 64 insertions(+), 55 deletions(-) create mode 100644 lambdas/client-transform-filter-lambda/src/models/channel-types.ts create mode 100644 lambdas/client-transform-filter-lambda/src/models/status-types.ts diff --git a/lambdas/client-transform-filter-lambda/src/models/channel-status-data.ts b/lambdas/client-transform-filter-lambda/src/models/channel-status-data.ts index 6ee3839..d0d11e6 100644 --- a/lambdas/client-transform-filter-lambda/src/models/channel-status-data.ts +++ b/lambdas/client-transform-filter-lambda/src/models/channel-status-data.ts @@ -1,31 +1,8 @@ /** * Channel-level status transition event data. */ -export type Channel = "nhsapp" | "email" | "sms" | "letter"; - -export type ChannelStatus = - | "created" - | "sending" - | "delivered" - | "failed" - | "skipped"; - -export type SupplierStatus = - | "delivered" - | "read" - | "notification_attempted" - | "unnotified" - | "rejected" - | "notified" - | "received" - | "permanent_failure" - | "temporary_failure" - | "technical_failure" - | "accepted" - | "cancelled" - | "pending_virus_check" - | "validation_failed" - | "unknown"; +import type { Channel } from "models/channel-types"; +import type { ChannelStatus, SupplierStatus } from "models/status-types"; export interface ChannelStatusData { messageId: string; diff --git a/lambdas/client-transform-filter-lambda/src/models/channel-types.ts b/lambdas/client-transform-filter-lambda/src/models/channel-types.ts new file mode 100644 index 0000000..8844c7f --- /dev/null +++ b/lambdas/client-transform-filter-lambda/src/models/channel-types.ts @@ -0,0 +1,4 @@ +/** + * Communication channel types + */ +export type Channel = "NHSAPP" | "EMAIL" | "SMS" | "LETTER"; diff --git a/lambdas/client-transform-filter-lambda/src/models/client-callback-payload.ts b/lambdas/client-transform-filter-lambda/src/models/client-callback-payload.ts index c5e8127..0aaddd2 100644 --- a/lambdas/client-transform-filter-lambda/src/models/client-callback-payload.ts +++ b/lambdas/client-transform-filter-lambda/src/models/client-callback-payload.ts @@ -2,13 +2,18 @@ * Message/Channel Status Callback payload delivered to client webhooks. */ +import type { RoutingPlan } from "models/routing-plan"; +import type { Channel } from "models/channel-types"; import type { - Channel, ChannelStatus, MessageStatus, SupplierStatus, -} from "models/status-transition-event"; -import type { RoutingPlan } from "models/routing-plan"; +} from "models/status-types"; + +export type ClientChannel = Lowercase; +export type ClientMessageStatus = Lowercase; +export type ClientChannelStatus = Lowercase; +export type ClientSupplierStatus = Lowercase; export interface ClientCallbackPayload { data: CallbackItem[]; @@ -28,12 +33,12 @@ export interface CallbackItem { export interface MessageStatusAttributes { messageId: string; messageReference: string; - messageStatus: MessageStatus; + messageStatus: ClientMessageStatus; messageStatusDescription?: string; messageFailureReasonCode?: string; channels: { - type: Channel; - channelStatus: "delivered" | "failed"; + type: ClientChannel; + channelStatus: ClientChannelStatus; }[]; timestamp: string; routingPlan: RoutingPlan; @@ -44,11 +49,11 @@ export interface ChannelStatusAttributes { messageReference: string; cascadeType: "primary" | "secondary"; cascadeOrder: number; - channel: Channel; - channelStatus: ChannelStatus; + channel: ClientChannel; + channelStatus: ClientChannelStatus; channelStatusDescription?: string; channelFailureReasonCode?: string; - supplierStatus: SupplierStatus; + supplierStatus: ClientSupplierStatus; timestamp: string; retryCount: number; } diff --git a/lambdas/client-transform-filter-lambda/src/models/message-status-data.ts b/lambdas/client-transform-filter-lambda/src/models/message-status-data.ts index 896937e..84c3673 100644 --- a/lambdas/client-transform-filter-lambda/src/models/message-status-data.ts +++ b/lambdas/client-transform-filter-lambda/src/models/message-status-data.ts @@ -2,16 +2,8 @@ * Message-level status transition event data. */ import type { RoutingPlan } from "models/routing-plan"; - -export type MessageStatus = - | "created" - | "pending_enrichment" - | "enriched" - | "sending" - | "delivered" - | "failed"; - -export type Channel = "nhsapp" | "email" | "sms" | "letter"; +import type { Channel } from "models/channel-types"; +import type { MessageStatus } from "models/status-types"; export interface MessageStatusData { messageId: string; diff --git a/lambdas/client-transform-filter-lambda/src/models/status-transition-event.ts b/lambdas/client-transform-filter-lambda/src/models/status-transition-event.ts index e53d9e7..6ffa66c 100644 --- a/lambdas/client-transform-filter-lambda/src/models/status-transition-event.ts +++ b/lambdas/client-transform-filter-lambda/src/models/status-transition-event.ts @@ -1,8 +1,3 @@ -/** - * CloudEvents-compliant event structure for callback delivery. - * Events carry complete payloads to avoid additional lookups. - */ - import type { MessageStatusData } from "models/message-status-data"; import type { ChannelStatusData } from "models/channel-status-data"; @@ -52,9 +47,5 @@ export const EventTypes = { } as const; export { type MessageStatusData } from "./message-status-data"; -export { type Channel, type MessageStatus } from "models/message-status-data"; -export { - type ChannelStatus, - type SupplierStatus, - type ChannelStatusData, -} from "models/channel-status-data"; + +export { type ChannelStatusData } from "models/channel-status-data"; diff --git a/lambdas/client-transform-filter-lambda/src/models/status-types.ts b/lambdas/client-transform-filter-lambda/src/models/status-types.ts new file mode 100644 index 0000000..a4d104f --- /dev/null +++ b/lambdas/client-transform-filter-lambda/src/models/status-types.ts @@ -0,0 +1,40 @@ +/** + * Message-level statuses + */ +export type MessageStatus = + | "CREATED" + | "PENDING_ENRICHMENT" + | "ENRICHED" + | "SENDING" + | "DELIVERED" + | "FAILED"; + +/** + * Channel-level statuses + */ +export type ChannelStatus = + | "CREATED" + | "SENDING" + | "DELIVERED" + | "FAILED" + | "SKIPPED"; + +/** + * Supplier-reported statuses + */ +export type SupplierStatus = + | "DELIVERED" + | "READ" + | "NOTIFICATION_ATTEMPTED" + | "UNNOTIFIED" + | "REJECTED" + | "NOTIFIED" + | "RECEIVED" + | "PERMANENT_FAILURE" + | "TEMPORARY_FAILURE" + | "TECHNICAL_FAILURE" + | "ACCEPTED" + | "CANCELLED" + | "PENDING_VIRUS_CHECK" + | "VALIDATION_FAILED" + | "UNKNOWN"; From 152ef89b5157ddd797c2a88a6f170cf0787762de Mon Sep 17 00:00:00 2001 From: Mike Wild Date: Fri, 13 Feb 2026 14:52:27 +0000 Subject: [PATCH 11/14] Remove unncessary sonar exclusions --- scripts/config/sonar-scanner.properties | 7 +------ 1 file changed, 1 insertion(+), 6 deletions(-) diff --git a/scripts/config/sonar-scanner.properties b/scripts/config/sonar-scanner.properties index 41482f4..ae7c364 100644 --- a/scripts/config/sonar-scanner.properties +++ b/scripts/config/sonar-scanner.properties @@ -3,12 +3,7 @@ sonar.host.url=https://sonarcloud.io sonar.qualitygate.wait=true sonar.sourceEncoding=UTF-8 -sonar.sources=lambdas/client-transform-filter-lambda -sonar.tests=tests/, lambdas/client-transform-filter-lambda/src/__tests__ -sonar.exclusions=lambdas/*/src/__tests__/**/* sonar.terraform.provider.aws.version=5.54.1 sonar.cpd.exclusions=**.test.* -sonar.coverage.exclusions=tests/, **/*.dev.*, lambdas/**/src/__tests__, utils/utils/src/zod-validators.ts ,**/jest.config.ts,scripts/**/* - -#sonar.python.coverage.reportPaths=.coverage/coverage.xml +sonar.coverage.exclusions=tests/**, lambdas/**/src/__tests__/** sonar.javascript.lcov.reportPaths=lcov.info From 7ca497157df58d49cdb7aa556b86592dac4e1707 Mon Sep 17 00:00:00 2001 From: Mike Wild Date: Fri, 13 Feb 2026 14:54:44 +0000 Subject: [PATCH 12/14] update teamResponsible enum --- .../src/models/status-transition-event.ts | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/lambdas/client-transform-filter-lambda/src/models/status-transition-event.ts b/lambdas/client-transform-filter-lambda/src/models/status-transition-event.ts index 6ffa66c..8611d24 100644 --- a/lambdas/client-transform-filter-lambda/src/models/status-transition-event.ts +++ b/lambdas/client-transform-filter-lambda/src/models/status-transition-event.ts @@ -2,7 +2,7 @@ import type { MessageStatusData } from "models/message-status-data"; import type { ChannelStatusData } from "models/channel-status-data"; export interface NotifyMetadata { - teamResponsible: "Team 1" | "Team 2" | "Team 3"; + teamResponsible: "Team 1" | "Team 2" | "Team 3" | "Team 4"; notifyDomain: "Ordering" | "Delivering" | "Reporting" | "Enquiries"; microservice: string; repositoryUrl: string; From 40f54e9ddcd2208bc7fb0aa2ff97b72e9b453faf Mon Sep 17 00:00:00 2001 From: Mike Wild Date: Tue, 17 Feb 2026 16:37:02 +0000 Subject: [PATCH 13/14] Update event schema based on guidance from meeting --- .../src/models/status-transition-event.ts | 27 ++----------------- 1 file changed, 2 insertions(+), 25 deletions(-) diff --git a/lambdas/client-transform-filter-lambda/src/models/status-transition-event.ts b/lambdas/client-transform-filter-lambda/src/models/status-transition-event.ts index 8611d24..e9c52fc 100644 --- a/lambdas/client-transform-filter-lambda/src/models/status-transition-event.ts +++ b/lambdas/client-transform-filter-lambda/src/models/status-transition-event.ts @@ -1,23 +1,7 @@ import type { MessageStatusData } from "models/message-status-data"; import type { ChannelStatusData } from "models/channel-status-data"; -export interface NotifyMetadata { - teamResponsible: "Team 1" | "Team 2" | "Team 3" | "Team 4"; - notifyDomain: "Ordering" | "Delivering" | "Reporting" | "Enquiries"; - microservice: string; - repositoryUrl: string; - accountId: string; - environment: "development" | "testing" | "staging" | "production"; - instance: string; - microserviceInstanceId: string; - microserviceVersion: string; -} - -export interface StatusTransitionEvent< - T = MessageStatusData | ChannelStatusData, -> { - profileversion: string; - profilepublished: string; +export interface StatusTransitionEvent { specversion: string; id: string; source: string; @@ -27,16 +11,9 @@ export interface StatusTransitionEvent< recordedtime: string; datacontenttype: string; dataschema: string; - severitynumber: number; - severitytext: string; traceparent: string; - data: { - "notify-payload": { - "notify-data": T; - "notify-metadata": NotifyMetadata; - }; - }; + data: MessageStatusData | ChannelStatusData; } export const EventTypes = { From ac0273cbfae6f45d45d06e5d87189a8a44421990 Mon Sep 17 00:00:00 2001 From: Mike Wild Date: Tue, 17 Feb 2026 17:01:58 +0000 Subject: [PATCH 14/14] fixup! Update event schema based on guidance from meeting --- .../src/models/status-transition-event.ts | 12 ++++++++++-- 1 file changed, 10 insertions(+), 2 deletions(-) diff --git a/lambdas/client-transform-filter-lambda/src/models/status-transition-event.ts b/lambdas/client-transform-filter-lambda/src/models/status-transition-event.ts index e9c52fc..43efd3f 100644 --- a/lambdas/client-transform-filter-lambda/src/models/status-transition-event.ts +++ b/lambdas/client-transform-filter-lambda/src/models/status-transition-event.ts @@ -1,7 +1,15 @@ import type { MessageStatusData } from "models/message-status-data"; import type { ChannelStatusData } from "models/channel-status-data"; -export interface StatusTransitionEvent { +/** + * Status transition event following CloudEvents 2025-11-draft standard. + * Represents a status transition notification published by Core domain to the Shared Event Bus. + * + * @template T - The type of data payload (MessageStatusData or ChannelStatusData) + */ +export interface StatusTransitionEvent< + T = MessageStatusData | ChannelStatusData, +> { specversion: string; id: string; source: string; @@ -13,7 +21,7 @@ export interface StatusTransitionEvent { dataschema: string; traceparent: string; - data: MessageStatusData | ChannelStatusData; + data: T; } export const EventTypes = {