From 9ec5d8394a44d35667aea2671d00a495dc496204 Mon Sep 17 00:00:00 2001 From: Mark Slowey Date: Tue, 23 Dec 2025 16:23:02 +0000 Subject: [PATCH 1/4] swap partition and sort for letters --- infrastructure/terraform/components/api/ddb_table_letters.tf | 4 ++-- internal/datastore/src/__test__/db.ts | 4 ++-- internal/datastore/src/__test__/heathcheck.test.ts | 4 ++++ internal/datastore/src/letter-repository.ts | 4 ++-- 4 files changed, 10 insertions(+), 6 deletions(-) diff --git a/infrastructure/terraform/components/api/ddb_table_letters.tf b/infrastructure/terraform/components/api/ddb_table_letters.tf index 6a3c3e48..44c882c4 100644 --- a/infrastructure/terraform/components/api/ddb_table_letters.tf +++ b/infrastructure/terraform/components/api/ddb_table_letters.tf @@ -2,8 +2,8 @@ resource "aws_dynamodb_table" "letters" { name = "${local.csi}-letters" billing_mode = "PAY_PER_REQUEST" - hash_key = "supplierId" - range_key = "id" + hash_key = "id" + range_key = "supplierId" ttl { attribute_name = "ttl" diff --git a/internal/datastore/src/__test__/db.ts b/internal/datastore/src/__test__/db.ts index f3606b92..1d364b9f 100644 --- a/internal/datastore/src/__test__/db.ts +++ b/internal/datastore/src/__test__/db.ts @@ -51,8 +51,8 @@ const createLetterTableCommand = new CreateTableCommand({ TableName: "letters", BillingMode: "PAY_PER_REQUEST", KeySchema: [ - { AttributeName: "supplierId", KeyType: "HASH" }, // Partition key - { AttributeName: "id", KeyType: "RANGE" }, // Sort key + { AttributeName: "id", KeyType: "HASH" }, // Partition key (letter ID) + { AttributeName: "supplierId", KeyType: "RANGE" }, // Sort key ], GlobalSecondaryIndexes: [ { diff --git a/internal/datastore/src/__test__/heathcheck.test.ts b/internal/datastore/src/__test__/heathcheck.test.ts index 315144d7..40545364 100644 --- a/internal/datastore/src/__test__/heathcheck.test.ts +++ b/internal/datastore/src/__test__/heathcheck.test.ts @@ -24,6 +24,10 @@ describe("DBHealthcheck", () => { await deleteTables(db); }); + afterAll(async () => { + await db.container.stop(); + }); + it("passes when the database is available", async () => { const dbHealthCheck = new DBHealthcheck(db.docClient, db.config); await expect(dbHealthCheck.check()).resolves.not.toThrow(); diff --git a/internal/datastore/src/letter-repository.ts b/internal/datastore/src/letter-repository.ts index 547b1788..13aa6adf 100644 --- a/internal/datastore/src/letter-repository.ts +++ b/internal/datastore/src/letter-repository.ts @@ -109,8 +109,8 @@ export class LetterRepository { new GetCommand({ TableName: this.config.lettersTableName, Key: { - supplierId, id: letterId, + supplierId, }, }), ); @@ -194,8 +194,8 @@ export class LetterRepository { new UpdateCommand({ TableName: this.config.lettersTableName, Key: { - supplierId: letterToUpdate.supplierId, id: letterToUpdate.id, + supplierId: letterToUpdate.supplierId, }, UpdateExpression: updateExpression, ConditionExpression: "attribute_exists(id)", // Ensure letter exists From 2a92c2ffd0d4d69051ee43d4161882a3beafa6c4 Mon Sep 17 00:00:00 2001 From: Mark Slowey Date: Wed, 24 Dec 2025 10:27:07 +0000 Subject: [PATCH 2/4] store changes and source, subject, billingref --- .../datastore/src/__test__/letter-repository.test.ts | 2 ++ internal/datastore/src/types.ts | 1 + internal/events/package.json | 2 +- internal/events/schemas/examples/letter.ACCEPTED.json | 1 + internal/events/schemas/examples/letter.FORWARDED.json | 1 + internal/events/schemas/examples/letter.RETURNED.json | 1 + internal/events/src/domain/letter.ts | 7 +++++++ .../__tests__/letter-status-change-events.test.ts | 1 + .../letter.ACCEPTED-with-invalid-major-version.json | 1 + .../testData/letter.ACCEPTED-with-missing-fields.json | 1 + .../src/events/__tests__/testData/letter.ACCEPTED.json | 1 + .../events/__tests__/testData/letter.FORWARDED.json | 1 + .../src/events/__tests__/testData/letter.RETURNED.json | 1 + .../src/mappers/__tests__/letter-mapper.test.ts | 10 ++++++++++ .../src/services/__tests__/letter-operations.test.ts | 2 ++ .../src/__tests__/letter-updates-transformer.test.ts | 5 +++++ .../src/mappers/__tests__/letter-mapper.test.ts | 10 +++++++--- .../src/mappers/letter-mapper.ts | 5 +++-- lambdas/letter-updates-transformer/src/types.ts | 10 +++++----- .../src/handler/__tests__/upsert-handler.test.ts | 1 + lambdas/upsert-letter/src/handler/upsert-handler.ts | 3 +++ .../src/__test__/helpers/create_letter_helpers.test.ts | 4 ++++ .../src/helpers/create_letter_helpers.ts | 4 ++++ 23 files changed, 64 insertions(+), 11 deletions(-) diff --git a/internal/datastore/src/__test__/letter-repository.test.ts b/internal/datastore/src/__test__/letter-repository.test.ts index 5e92e685..1be0cb93 100644 --- a/internal/datastore/src/__test__/letter-repository.test.ts +++ b/internal/datastore/src/__test__/letter-repository.test.ts @@ -27,6 +27,7 @@ function createLetter( updatedAt: now, source: "/data-plane/letter-rendering/pdf", subject: `client/1/letter-request/${letterId}`, + billingRef: "specification1", }; } @@ -112,6 +113,7 @@ describe("LetterRepository", () => { expect(letter.reasonCode).toBeUndefined(); expect(letter.reasonText).toBeUndefined(); expect(letter.subject).toBe(`client/1/letter-request/${letterId}`); + expect(letter.billingRef).toBe("specification1"); assertTtl(letter.ttl, before, after); }); diff --git a/internal/datastore/src/types.ts b/internal/datastore/src/types.ts index a77e8e66..a0b9f719 100644 --- a/internal/datastore/src/types.ts +++ b/internal/datastore/src/types.ts @@ -50,6 +50,7 @@ export const LetterSchema = LetterSchemaBase.extend({ ttl: z.int(), source: z.string(), subject: z.string(), + billingRef: z.string(), }).describe("Letter"); /** diff --git a/internal/events/package.json b/internal/events/package.json index 2d799646..8005d13e 100644 --- a/internal/events/package.json +++ b/internal/events/package.json @@ -50,5 +50,5 @@ "typecheck": "tsc --noEmit" }, "types": "dist/index.d.ts", - "version": "1.0.5" + "version": "1.0.6" } diff --git a/internal/events/schemas/examples/letter.ACCEPTED.json b/internal/events/schemas/examples/letter.ACCEPTED.json index f9a1177c..c6533b93 100644 --- a/internal/events/schemas/examples/letter.ACCEPTED.json +++ b/internal/events/schemas/examples/letter.ACCEPTED.json @@ -1,5 +1,6 @@ { "data": { + "billingRef": "1y3q9v1zzzz", "domainId": "f47ac10b-58cc-4372-a567-0e02b2c3d479", "groupId": "client_template", "origin": { diff --git a/internal/events/schemas/examples/letter.FORWARDED.json b/internal/events/schemas/examples/letter.FORWARDED.json index bf12ed69..6661fe6c 100644 --- a/internal/events/schemas/examples/letter.FORWARDED.json +++ b/internal/events/schemas/examples/letter.FORWARDED.json @@ -1,5 +1,6 @@ { "data": { + "billingRef": "1y3q9v1zzzz", "domainId": "f47ac10b-58cc-4372-a567-0e02b2c3d479", "groupId": "client_template", "origin": { diff --git a/internal/events/schemas/examples/letter.RETURNED.json b/internal/events/schemas/examples/letter.RETURNED.json index e273029d..f0cfa376 100644 --- a/internal/events/schemas/examples/letter.RETURNED.json +++ b/internal/events/schemas/examples/letter.RETURNED.json @@ -1,5 +1,6 @@ { "data": { + "billingRef": "1y3q9v1zzzz", "domainId": "f47ac10b-58cc-4372-a567-0e02b2c3d479", "groupId": "client_template", "origin": { diff --git a/internal/events/src/domain/letter.ts b/internal/events/src/domain/letter.ts index 7e854d41..67ed8bbe 100644 --- a/internal/events/src/domain/letter.ts +++ b/internal/events/src/domain/letter.ts @@ -76,6 +76,13 @@ The identifier will be included as the origin domain in the subject of any corre examples: ["1y3q9v1zzzz"], }), + billingRef: z.string().meta({ + title: "Billing Reference", + description: + "A billing reference determined for this letter based on its specification", + examples: ["1y3q9v1zzzz"], + }), + supplierId: z.string().meta({ title: "Supplier ID", description: "Supplier ID allocated to the letter during creation.", diff --git a/internal/events/src/events/__tests__/letter-status-change-events.test.ts b/internal/events/src/events/__tests__/letter-status-change-events.test.ts index 25541fc5..48215545 100644 --- a/internal/events/src/events/__tests__/letter-status-change-events.test.ts +++ b/internal/events/src/events/__tests__/letter-status-change-events.test.ts @@ -37,6 +37,7 @@ describe("LetterStatus event validations", () => { }), domainId: "f47ac10b-58cc-4372-a567-0e02b2c3d479", specificationId: "1y3q9v1zzzz", + billingRef: "1y3q9v1zzzz", groupId: "client_template", status, }), diff --git a/internal/events/src/events/__tests__/testData/letter.ACCEPTED-with-invalid-major-version.json b/internal/events/src/events/__tests__/testData/letter.ACCEPTED-with-invalid-major-version.json index 5458449d..192ea5e2 100644 --- a/internal/events/src/events/__tests__/testData/letter.ACCEPTED-with-invalid-major-version.json +++ b/internal/events/src/events/__tests__/testData/letter.ACCEPTED-with-invalid-major-version.json @@ -1,5 +1,6 @@ { "data": { + "billingRef": "1y3q9v1zzzz", "domainId": "f47ac10b-58cc-4372-a567-0e02b2c3d479", "groupId": "client_template", "origin": { diff --git a/internal/events/src/events/__tests__/testData/letter.ACCEPTED-with-missing-fields.json b/internal/events/src/events/__tests__/testData/letter.ACCEPTED-with-missing-fields.json index b7a1358b..54000422 100644 --- a/internal/events/src/events/__tests__/testData/letter.ACCEPTED-with-missing-fields.json +++ b/internal/events/src/events/__tests__/testData/letter.ACCEPTED-with-missing-fields.json @@ -1,5 +1,6 @@ { "data": { + "billingRef": "1y3q9v1zzzz", "domainId": "f47ac10b-58cc-4372-a567-0e02b2c3d479", "groupId": "client_template", "origin": { diff --git a/internal/events/src/events/__tests__/testData/letter.ACCEPTED.json b/internal/events/src/events/__tests__/testData/letter.ACCEPTED.json index e39b8366..7ffac10f 100644 --- a/internal/events/src/events/__tests__/testData/letter.ACCEPTED.json +++ b/internal/events/src/events/__tests__/testData/letter.ACCEPTED.json @@ -1,5 +1,6 @@ { "data": { + "billingRef": "1y3q9v1zzzz", "domainId": "f47ac10b-58cc-4372-a567-0e02b2c3d479", "groupId": "client_template", "origin": { diff --git a/internal/events/src/events/__tests__/testData/letter.FORWARDED.json b/internal/events/src/events/__tests__/testData/letter.FORWARDED.json index 6b7b4c45..28c6111f 100644 --- a/internal/events/src/events/__tests__/testData/letter.FORWARDED.json +++ b/internal/events/src/events/__tests__/testData/letter.FORWARDED.json @@ -1,5 +1,6 @@ { "data": { + "billingRef": "1y3q9v1zzzz", "domainId": "f47ac10b-58cc-4372-a567-0e02b2c3d479", "groupId": "client_template", "origin": { diff --git a/internal/events/src/events/__tests__/testData/letter.RETURNED.json b/internal/events/src/events/__tests__/testData/letter.RETURNED.json index 8a4a9e44..07b28154 100644 --- a/internal/events/src/events/__tests__/testData/letter.RETURNED.json +++ b/internal/events/src/events/__tests__/testData/letter.RETURNED.json @@ -1,5 +1,6 @@ { "data": { + "billingRef": "1y3q9v1zzzz", "domainId": "f47ac10b-58cc-4372-a567-0e02b2c3d479", "groupId": "client_template", "origin": { diff --git a/lambdas/api-handler/src/mappers/__tests__/letter-mapper.test.ts b/lambdas/api-handler/src/mappers/__tests__/letter-mapper.test.ts index 6f28ccf7..fa7f9f81 100644 --- a/lambdas/api-handler/src/mappers/__tests__/letter-mapper.test.ts +++ b/lambdas/api-handler/src/mappers/__tests__/letter-mapper.test.ts @@ -18,6 +18,7 @@ describe("letter-mapper", () => { status: "PENDING", supplierId: "supplier1", specificationId: "spec123", + billingRef: "spec123", groupId: "group123", url: "https://example.com/letter/abc123", createdAt: date, @@ -26,6 +27,7 @@ describe("letter-mapper", () => { supplierStatusSk: date, ttl: 123, source: "/data-plane/letter-rendering/pdf", + subject: "letter-rendering/source/letter/letter-id", }; const result: PatchLetterResponse = mapToPatchLetterResponse(letter); @@ -50,6 +52,7 @@ describe("letter-mapper", () => { status: "PENDING", supplierId: "supplier1", specificationId: "spec123", + billingRef: "spec123", groupId: "group123", url: "https://example.com/letter/abc123", createdAt: date, @@ -60,6 +63,7 @@ describe("letter-mapper", () => { reasonCode: "R01", reasonText: "Reason text", source: "/data-plane/letter-rendering/pdf", + subject: "letter-rendering/source/letter/letter-id", }; const result: PatchLetterResponse = mapToPatchLetterResponse(letter); @@ -86,6 +90,7 @@ describe("letter-mapper", () => { status: "PENDING", supplierId: "supplier1", specificationId: "spec123", + billingRef: "spec123", groupId: "group123", url: "https://example.com/letter/abc123", createdAt: date, @@ -94,6 +99,7 @@ describe("letter-mapper", () => { supplierStatusSk: date, ttl: 123, source: "/data-plane/letter-rendering/pdf", + subject: "letter-rendering/source/letter/letter-id", }; const result: GetLetterResponse = mapToGetLetterResponse(letter); @@ -118,6 +124,7 @@ describe("letter-mapper", () => { status: "PENDING", supplierId: "supplier1", specificationId: "spec123", + billingRef: "spec123", groupId: "group123", url: "https://example.com/letter/abc123", createdAt: date, @@ -128,6 +135,7 @@ describe("letter-mapper", () => { reasonCode: "R01", reasonText: "Reason text", source: "/data-plane/letter-rendering/pdf", + subject: "letter-rendering/source/letter/letter-id", }; const result: GetLetterResponse = mapToGetLetterResponse(letter); @@ -154,6 +162,7 @@ describe("letter-mapper", () => { status: "PENDING", supplierId: "supplier1", specificationId: "spec123", + billingRef: "spec123", groupId: "group123", url: "https://example.com/letter/abc123", createdAt: date, @@ -164,6 +173,7 @@ describe("letter-mapper", () => { reasonCode: "R01", reasonText: "Reason text", source: "/data-plane/letter-rendering/pdf", + subject: "letter-rendering/source/letter/letter-id", }; const result: GetLettersResponse = mapToGetLettersResponse([ diff --git a/lambdas/api-handler/src/services/__tests__/letter-operations.test.ts b/lambdas/api-handler/src/services/__tests__/letter-operations.test.ts index 185e462d..c7cfd592 100644 --- a/lambdas/api-handler/src/services/__tests__/letter-operations.test.ts +++ b/lambdas/api-handler/src/services/__tests__/letter-operations.test.ts @@ -29,6 +29,7 @@ function makeLetter(id: string, status: Letter["status"]): Letter { status, supplierId: "supplier1", specificationId: "spec123", + billingRef: "spec123", groupId: "group123", url: `s3://letterDataBucket/${id}.pdf`, createdAt: new Date().toISOString(), @@ -39,6 +40,7 @@ function makeLetter(id: string, status: Letter["status"]): Letter { reasonCode: "R01", reasonText: "Reason text", source: "/data-plane/letter-rendering/pdf", + subject: "letter-rendering/source/letter/letter-id", }; } diff --git a/lambdas/letter-updates-transformer/src/__tests__/letter-updates-transformer.test.ts b/lambdas/letter-updates-transformer/src/__tests__/letter-updates-transformer.test.ts index 17c271a0..67211462 100644 --- a/lambdas/letter-updates-transformer/src/__tests__/letter-updates-transformer.test.ts +++ b/lambdas/letter-updates-transformer/src/__tests__/letter-updates-transformer.test.ts @@ -257,9 +257,14 @@ function generateLetter(status: LetterStatus, id?: string): LetterForEventPub { id: id || "1", status, specificationId: "spec1", + billingRef: "spec1", supplierId: "supplier1", groupId: "group1", + createdAt: "2025-12-10T11:12:54Z", updatedAt: "2025-12-10T11:13:54Z", + url: "https://example.com/letter.pdf", + source: "test-source", + subject: "test-source/subject-id", }; } diff --git a/lambdas/letter-updates-transformer/src/mappers/__tests__/letter-mapper.test.ts b/lambdas/letter-updates-transformer/src/mappers/__tests__/letter-mapper.test.ts index fe5b5a79..7139165d 100644 --- a/lambdas/letter-updates-transformer/src/mappers/__tests__/letter-mapper.test.ts +++ b/lambdas/letter-updates-transformer/src/mappers/__tests__/letter-mapper.test.ts @@ -7,12 +7,15 @@ describe("letter-mapper", () => { const letter = { id: "id1", specificationId: "spec1", + billingRef: "spec1", supplierId: "supplier1", groupId: "group1", status: "PRINTED", reasonCode: "R02", reasonText: "Reason text", updatedAt: "2025-11-24T15:55:18.000Z", + source: "letter-rendering/source/test", + subject: "letter-rendering/source/letter/letter-id", } as Letter; const event = mapLetterToCloudEvent(letter); @@ -22,7 +25,7 @@ describe("letter-mapper", () => { expect(event.dataschema).toBe( `https://notify.nhs.uk/cloudevents/schemas/supplier-api/letter.PRINTED.${event.dataschemaversion}.schema.json`, ); - expect(event.dataschemaversion).toBe("1.0.5"); + expect(event.dataschemaversion).toBe("1.0.6"); expect(event.subject).toBe("letter-origin/supplier-api/letter/id1"); expect(event.time).toBe("2025-11-24T15:55:18.000Z"); expect(event.recordedtime).toBe("2025-11-24T15:55:18.000Z"); @@ -30,14 +33,15 @@ describe("letter-mapper", () => { domainId: "id1", status: "PRINTED", specificationId: "spec1", + billingRef: "spec1", supplierId: "supplier1", groupId: "group1", reasonCode: "R02", reasonText: "Reason text", origin: { domain: "supplier-api", - source: "/data-plane/supplier-api/letters", - subject: "letter-origin/supplier-api/letter/id1", + source: "letter-rendering/source/test", + subject: "letter-rendering/source/letter/letter-id", event: event.id, }, }); diff --git a/lambdas/letter-updates-transformer/src/mappers/letter-mapper.ts b/lambdas/letter-updates-transformer/src/mappers/letter-mapper.ts index 759f5f0f..34cd23c5 100644 --- a/lambdas/letter-updates-transformer/src/mappers/letter-mapper.ts +++ b/lambdas/letter-updates-transformer/src/mappers/letter-mapper.ts @@ -22,14 +22,15 @@ export default function mapLetterToCloudEvent( domainId: letter.id as LetterEvent["data"]["domainId"], status: letter.status, specificationId: letter.specificationId, + billingRef: letter.billingRef, supplierId: letter.supplierId, groupId: letter.groupId, reasonCode: letter.reasonCode, reasonText: letter.reasonText, origin: { domain: "supplier-api", - source: "/data-plane/supplier-api/letters", - subject: `letter-origin/supplier-api/letter/${letter.id}`, + source: letter.source, + subject: letter.subject, event: eventId, }, }, diff --git a/lambdas/letter-updates-transformer/src/types.ts b/lambdas/letter-updates-transformer/src/types.ts index b1b7f4c7..34920991 100644 --- a/lambdas/letter-updates-transformer/src/types.ts +++ b/lambdas/letter-updates-transformer/src/types.ts @@ -1,10 +1,10 @@ -import { LetterSchemaBase, SupplierSchema } from "@internal/datastore"; -import { idRef } from "@internal/helpers"; +import { LetterSchema } from "@internal/datastore"; import { z } from "zod"; -export const LetterSchemaForEventPub = LetterSchemaBase.extend({ - supplierId: idRef(SupplierSchema, "id"), - updatedAt: z.string(), +export const LetterSchemaForEventPub = LetterSchema.omit({ + supplierStatus: true, + supplierStatusSk: true, + ttl: true, }); export type LetterForEventPub = z.infer; diff --git a/lambdas/upsert-letter/src/handler/__tests__/upsert-handler.test.ts b/lambdas/upsert-letter/src/handler/__tests__/upsert-handler.test.ts index 78197a0a..a185e058 100644 --- a/lambdas/upsert-letter/src/handler/__tests__/upsert-handler.test.ts +++ b/lambdas/upsert-letter/src/handler/__tests__/upsert-handler.test.ts @@ -122,6 +122,7 @@ function createSupplierStatusChangeEvent( reasonCode: "R07", reasonText: "No such address", specificationId: "1y3q9v1zzzz", + billingRef: "1y3q9v1zzzz", status: "RETURNED", supplierId: "supplier1", }, diff --git a/lambdas/upsert-letter/src/handler/upsert-handler.ts b/lambdas/upsert-letter/src/handler/upsert-handler.ts index 26335450..141e37ce 100644 --- a/lambdas/upsert-letter/src/handler/upsert-handler.ts +++ b/lambdas/upsert-letter/src/handler/upsert-handler.ts @@ -47,6 +47,7 @@ function getOperationFromType(type: string): UpsertOperation { preparedRequest, supplierSpec.supplierId, supplierSpec.specId, + supplierSpec.specId, //use specId for now ); await deps.letterRepo.putLetter(letterToInsert); }, @@ -68,6 +69,7 @@ function mapToInsertLetter( upsertRequest: PreparedEvents, supplier: string, spec: string, + billingRef: string, ): InsertLetter { const now = new Date().toISOString(); return { @@ -84,6 +86,7 @@ function mapToInsertLetter( subject: upsertRequest.subject, createdAt: now, updatedAt: now, + billingRef: billingRef, }; } diff --git a/scripts/utilities/letter-test-data/src/__test__/helpers/create_letter_helpers.test.ts b/scripts/utilities/letter-test-data/src/__test__/helpers/create_letter_helpers.test.ts index b677fd5a..ad34b021 100644 --- a/scripts/utilities/letter-test-data/src/__test__/helpers/create_letter_helpers.test.ts +++ b/scripts/utilities/letter-test-data/src/__test__/helpers/create_letter_helpers.test.ts @@ -55,6 +55,8 @@ describe("Create letter helpers", () => { updatedAt: "2020-02-01T00:00:00.000Z", url: "s3://bucketName/supplierId/targetFilename", source: "/data-plane/letter-rendering/letter-test-data", + subject: "supplier-api/letter-test-data/letterId", + billingRef: "specificationId" }); }); @@ -83,6 +85,8 @@ describe("Create letter helpers", () => { createdAt: "2020-02-01T00:00:00.000Z", updatedAt: "2020-02-01T00:00:00.000Z", source: "/data-plane/letter-rendering/letter-test-data", + subject: "supplier-api/letter-test-data/testLetterId", + billingRef: "testSpecId" }); }); }); diff --git a/scripts/utilities/letter-test-data/src/helpers/create_letter_helpers.ts b/scripts/utilities/letter-test-data/src/helpers/create_letter_helpers.ts index 42798eca..e471bdb8 100644 --- a/scripts/utilities/letter-test-data/src/helpers/create_letter_helpers.ts +++ b/scripts/utilities/letter-test-data/src/helpers/create_letter_helpers.ts @@ -43,6 +43,8 @@ export async function createLetter(params: { createdAt: new Date().toISOString(), updatedAt: new Date().toISOString(), source: "/data-plane/letter-rendering/letter-test-data", + subject: `supplier-api/letter-test-data/${letterId}`, + billingRef: specificationId }; const letterRecord = await letterRepository.putLetter(letter); @@ -76,6 +78,8 @@ export function createLetterDto(params: { createdAt: new Date().toISOString(), updatedAt: new Date().toISOString(), source: "/data-plane/letter-rendering/letter-test-data", + subject: `supplier-api/letter-test-data/${letterId}`, + billingRef: specificationId }; return letter; From 548196c5737819b1dad62757a20ad5663f8a89a3 Mon Sep 17 00:00:00 2001 From: Mark Slowey Date: Wed, 24 Dec 2025 10:33:44 +0000 Subject: [PATCH 3/4] unsafe marker --- internal/datastore/src/letter-repository.ts | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/internal/datastore/src/letter-repository.ts b/internal/datastore/src/letter-repository.ts index 13aa6adf..d3af885e 100644 --- a/internal/datastore/src/letter-repository.ts +++ b/internal/datastore/src/letter-repository.ts @@ -70,7 +70,7 @@ export class LetterRepository { return LetterSchema.parse(letterDb); } - async putLetterBatch(letters: InsertLetter[]): Promise { + async unsafePutLetterBatch(letters: InsertLetter[]): Promise { let lettersDb: Letter[] = []; for (let i = 0; i < letters.length; i++) { const letter = letters[i]; From 6c5f0fcadee2d4d38a9952bc8dac1eb0765500c7 Mon Sep 17 00:00:00 2001 From: Mark Slowey Date: Wed, 24 Dec 2025 10:45:17 +0000 Subject: [PATCH 4/4] rename correctly --- internal/datastore/src/__test__/letter-repository.test.ts | 8 ++++---- scripts/utilities/letter-test-data/src/cli/index.ts | 2 +- 2 files changed, 5 insertions(+), 5 deletions(-) diff --git a/internal/datastore/src/__test__/letter-repository.test.ts b/internal/datastore/src/__test__/letter-repository.test.ts index 1be0cb93..393c3810 100644 --- a/internal/datastore/src/__test__/letter-repository.test.ts +++ b/internal/datastore/src/__test__/letter-repository.test.ts @@ -445,7 +445,7 @@ describe("LetterRepository", () => { test("should batch write letters to the database", async () => { const before = Date.now(); - await letterRepository.putLetterBatch([ + await letterRepository.unsafePutLetterBatch([ createLetter("supplier1", "letter1"), createLetter("supplier1", "letter2"), createLetter("supplier1", "letter3"), @@ -485,7 +485,7 @@ describe("LetterRepository", () => { const sendSpy = jest.spyOn(db.docClient, "send"); - await letterRepository.putLetterBatch(letters); + await letterRepository.unsafePutLetterBatch(letters); expect(sendSpy).toHaveBeenCalledTimes(3); @@ -499,7 +499,7 @@ describe("LetterRepository", () => { letters[0] = createLetter("supplier1", "letter1"); letters[2] = createLetter("supplier1", "letter3"); - await letterRepository.putLetterBatch(letters); + await letterRepository.unsafePutLetterBatch(letters); await checkLetterStatus("supplier1", "letter1", "PENDING"); await checkLetterStatus("supplier1", "letter3", "PENDING"); @@ -511,7 +511,7 @@ describe("LetterRepository", () => { lettersTableName: "nonexistent-table", }); await expect( - misconfiguredRepository.putLetterBatch([ + misconfiguredRepository.unsafePutLetterBatch([ createLetter("supplier1", "letter1"), ]), ).rejects.toThrow("Cannot do operations on a non-existent table"); diff --git a/scripts/utilities/letter-test-data/src/cli/index.ts b/scripts/utilities/letter-test-data/src/cli/index.ts index 915c392b..a3026200 100644 --- a/scripts/utilities/letter-test-data/src/cli/index.ts +++ b/scripts/utilities/letter-test-data/src/cli/index.ts @@ -174,7 +174,7 @@ async function main() { }; // Upload Letters - await letterRepository.putLetterBatch(letterDtos); + await letterRepository.unsafePutLetterBatch(letterDtos); console.log(`Created batch ${batchId} of ${letterDtos.length}`); },