Skip to content
Open
Show file tree
Hide file tree
Changes from all commits
Commits
Show all changes
24 commits
Select commit Hold shift + click to select a range
49da984
Supplier Config table
nhsd-david-wass Feb 19, 2026
cb45071
Get the variant details
nhsd-david-wass Feb 20, 2026
651f80e
get rest of dbdata
nhsd-david-wass Feb 23, 2026
3cf12dc
fix typescript
nhsd-david-wass Feb 23, 2026
1c3c32b
index rename and permissions
nhsd-david-wass Feb 24, 2026
5b6d30e
repo logging
nhsd-david-wass Feb 24, 2026
636862a
Fix PK name
nhsd-david-wass Feb 24, 2026
04ef19b
add filters and error checking
nhsd-david-wass Feb 24, 2026
33783cc
refactor to supplier-config services
nhsd-david-wass Feb 24, 2026
d2afc98
finally get the pool of supplier details
nhsd-david-wass Feb 24, 2026
77fa518
import schemas from nhs-notify-event-schemas-supplier-config
nhsd-david-wass Feb 25, 2026
79959d7
new unit tests
nhsd-david-wass Feb 26, 2026
3a68d4a
Fix tests due to ESM Error - Not sure why
nhsd-david-wass Feb 26, 2026
184a41f
new unit tests
nhsd-david-wass Feb 26, 2026
183c315
transform ignore
nhsd-david-wass Feb 26, 2026
e4b737c
review changes
nhsd-david-wass Mar 9, 2026
ab9c89b
package lock
nhsd-david-wass Mar 9, 2026
9240b8d
lint fix
nhsd-david-wass Mar 9, 2026
07325d8
Log errors but do not fail for new allocations
nhsd-david-wass Mar 12, 2026
e59635e
CCM-13752 Added specificationBillingId
nhsd-david-wass Mar 11, 2026
366a7b7
add to cloudevents
nhsd-david-wass Mar 11, 2026
7d4f544
target specific internal dev branch - DO NOT MERGE
nhsd-david-wass Mar 12, 2026
3dd83f4
CCM-15148 - Add BillingId to variant map
nhsd-david-wass Mar 12, 2026
5061073
update test utility
nhsd-david-wass Mar 12, 2026
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
3 changes: 2 additions & 1 deletion .github/workflows/stage-3-build.yaml
Original file line number Diff line number Diff line change
Expand Up @@ -161,7 +161,8 @@ jobs:
--targetAccountGroup "nhs-notify-supplier-api-dev" \
--terraformAction "apply" \
--overrideProjectName "nhs" \
--overrideRoleName "nhs-main-acct-supplier-api-github-deploy"
--overrideRoleName "nhs-main-acct-supplier-api-github-deploy" \
--internalRef "feature/CCM-15148"
artefact-proxies:
name: "Build proxies"
runs-on: ubuntu-latest
Expand Down
2 changes: 1 addition & 1 deletion infrastructure/terraform/components/api/README.md
Original file line number Diff line number Diff line change
Expand Up @@ -34,7 +34,7 @@ No requirements.
| <a name="input_group"></a> [group](#input\_group) | The group variables are being inherited from (often synonmous with account short-name) | `string` | n/a | yes |
| <a name="input_kms_deletion_window"></a> [kms\_deletion\_window](#input\_kms\_deletion\_window) | When a kms key is deleted, how long should it wait in the pending deletion state? | `string` | `"30"` | no |
| <a name="input_letter_table_ttl_hours"></a> [letter\_table\_ttl\_hours](#input\_letter\_table\_ttl\_hours) | Number of hours to set as TTL on letters table | `number` | `24` | no |
| <a name="input_letter_variant_map"></a> [letter\_variant\_map](#input\_letter\_variant\_map) | n/a | `map(object({ supplierId = string, specId = string }))` | <pre>{<br/> "lv1": {<br/> "specId": "spec1",<br/> "supplierId": "supplier1"<br/> },<br/> "lv2": {<br/> "specId": "spec2",<br/> "supplierId": "supplier1"<br/> },<br/> "lv3": {<br/> "specId": "spec3",<br/> "supplierId": "supplier2"<br/> }<br/>}</pre> | no |
| <a name="input_letter_variant_map"></a> [letter\_variant\_map](#input\_letter\_variant\_map) | n/a | `map(object({ supplierId = string, specId = string, billingId = string }))` | <pre>{<br/> "lv1": {<br/> "billingId": "billing1",<br/> "specId": "spec1",<br/> "supplierId": "supplier1"<br/> },<br/> "lv2": {<br/> "billingId": "billing2",<br/> "specId": "spec2",<br/> "supplierId": "supplier1"<br/> },<br/> "lv3": {<br/> "billingId": "billing3",<br/> "specId": "spec3",<br/> "supplierId": "supplier2"<br/> }<br/>}</pre> | no |
| <a name="input_log_level"></a> [log\_level](#input\_log\_level) | The log level to be used in lambda functions within the component. Any log with a lower severity than the configured value will not be logged: https://docs.python.org/3/library/logging.html#levels | `string` | `"INFO"` | no |
| <a name="input_log_retention_in_days"></a> [log\_retention\_in\_days](#input\_log\_retention\_in\_days) | The retention period in days for the Cloudwatch Logs events to be retained, default of 0 is indefinite | `number` | `0` | no |
| <a name="input_manually_configure_mtls_truststore"></a> [manually\_configure\_mtls\_truststore](#input\_manually\_configure\_mtls\_truststore) | Manually manage the truststore used for API Gateway mTLS (e.g. for prod environment) | `bool` | `false` | no |
Expand Down
Original file line number Diff line number Diff line change
@@ -0,0 +1,59 @@
resource "aws_dynamodb_table" "supplier-configuration" {
name = "${local.csi}-supplier-config"
billing_mode = "PAY_PER_REQUEST"

hash_key = "PK"
range_key = "SK"

ttl {
attribute_name = "ttl"
enabled = true
}

attribute {
name = "PK"
type = "S"
}

attribute {
name = "SK"
type = "S"
}

attribute {
name = "entityType"
type = "S"
}

attribute {
name = "volumeGroup"
type = "S"
}

// The type-index GSI allows us to query for all supplier configurations of a given type (e.g. all letter supplier configurations)
global_secondary_index {
name = "EntityTypeIndex"
hash_key = "entityType"
range_key = "SK"
projection_type = "ALL"
}

global_secondary_index {
name = "volumeGroup-index"
hash_key = "PK"
range_key = "volumeGroup"
projection_type = "ALL"
}

point_in_time_recovery {
enabled = true
}

tags = merge(
local.default_tags,
{
NHSE-Enable-Dynamo-Backup-Acct = "True"
}
)

}
19 changes: 10 additions & 9 deletions infrastructure/terraform/components/api/locals.tf
Original file line number Diff line number Diff line change
Expand Up @@ -20,15 +20,16 @@ locals {
destination_arn = "arn:aws:logs:${var.region}:${var.shared_infra_account_id}:destination:nhs-main-obs-firehose-logs"

common_lambda_env_vars = {
LETTERS_TABLE_NAME = aws_dynamodb_table.letters.name,
MI_TABLE_NAME = aws_dynamodb_table.mi.name,
LETTER_TTL_HOURS = 12960, # 18 months * 30 days * 24 hours
MI_TTL_HOURS = 2160 # 90 days * 24 hours
SUPPLIER_ID_HEADER = "nhsd-supplier-id",
APIM_CORRELATION_HEADER = "nhsd-correlation-id",
DOWNLOAD_URL_TTL_SECONDS = 60
SNS_TOPIC_ARN = "${module.eventsub.sns_topic.arn}",
EVENT_SOURCE = "/data-plane/supplier-api/${var.group}/${var.environment}/letters"
LETTERS_TABLE_NAME = aws_dynamodb_table.letters.name,
MI_TABLE_NAME = aws_dynamodb_table.mi.name,
LETTER_TTL_HOURS = 12960, # 18 months * 30 days * 24 hours
MI_TTL_HOURS = 2160 # 90 days * 24 hours
SUPPLIER_ID_HEADER = "nhsd-supplier-id",
APIM_CORRELATION_HEADER = "nhsd-correlation-id",
DOWNLOAD_URL_TTL_SECONDS = 60
SNS_TOPIC_ARN = "${module.eventsub.sns_topic.arn}",
EVENT_SOURCE = "/data-plane/supplier-api/${var.group}/${var.environment}/letters"
SUPPLIER_CONFIG_TABLE_NAME = aws_dynamodb_table.supplier-configuration.name
}

core_pdf_bucket_arn = "arn:aws:s3:::comms-${var.core_account_id}-eu-west-2-${var.core_environment}-api-stg-pdf-pipeline"
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -82,4 +82,20 @@ data "aws_iam_policy_document" "supplier_allocator_lambda" {
module.sqs_letter_updates.sqs_queue_arn
]
}

statement {
sid = "AllowDynamoDBAccess"
effect = "Allow"

actions = [
"dynamodb:GetItem",
"dynamodb:Query"
]

resources = [
aws_dynamodb_table.supplier-configuration.arn,
"${aws_dynamodb_table.supplier-configuration.arn}/index/volumeGroup-index"

]
}
}
8 changes: 4 additions & 4 deletions infrastructure/terraform/components/api/variables.tf
Original file line number Diff line number Diff line change
Expand Up @@ -136,11 +136,11 @@ variable "eventpub_control_plane_bus_arn" {
}

variable "letter_variant_map" {
type = map(object({ supplierId = string, specId = string }))
type = map(object({ supplierId = string, specId = string, billingId = string }))
default = {
"lv1" = { supplierId = "supplier1", specId = "spec1" },
"lv2" = { supplierId = "supplier1", specId = "spec2" },
"lv3" = { supplierId = "supplier2", specId = "spec3" }
"lv1" = { supplierId = "supplier1", specId = "spec1", billingId = "billing1" },
"lv2" = { supplierId = "supplier1", specId = "spec2", billingId = "billing2" },
"lv3" = { supplierId = "supplier2", specId = "spec3", billingId = "billing3" }
}
}

Expand Down
3 changes: 3 additions & 0 deletions internal/datastore/jest.config.ts
Original file line number Diff line number Diff line change
Expand Up @@ -31,6 +31,9 @@ export const baseJestConfig: Config = {

coveragePathIgnorePatterns: ["/__tests__/"],
transform: { "^.+\\.ts$": "ts-jest" },
transformIgnorePatterns: [
"node_modules/(?!(@nhsdigital/nhs-notify-event-schemas-supplier-config)/)",
],
testPathIgnorePatterns: [".build"],
testMatch: ["**/?(*.)+(spec|test).[jt]s?(x)"],

Expand Down
1 change: 1 addition & 0 deletions internal/datastore/package.json
Original file line number Diff line number Diff line change
Expand Up @@ -3,6 +3,7 @@
"@aws-sdk/client-dynamodb": "^3.984.0",
"@aws-sdk/lib-dynamodb": "^3.984.0",
"@internal/helpers": "*",
"@nhsdigital/nhs-notify-event-schemas-supplier-config": "^1.0.1",
"pino": "^10.3.0",
"zod": "^4.1.11",
"zod-mermaid": "^1.0.9"
Expand Down
28 changes: 28 additions & 0 deletions internal/datastore/src/__test__/db.ts
Original file line number Diff line number Diff line change
Expand Up @@ -36,6 +36,7 @@ export async function setupDynamoDBContainer() {
lettersTtlHours: 1,
letterQueueTtlHours: 1,
miTtlHours: 1,
supplierConfigTableName: "supplier-config",
};

return {
Expand Down Expand Up @@ -145,6 +146,31 @@ const createLetterQueueTableCommand = new CreateTableCommand({
{ AttributeName: "queueTimestamp", AttributeType: "S" },
],
});
const createSupplierConfigTableCommand = new CreateTableCommand({
TableName: "supplier-config",
BillingMode: "PAY_PER_REQUEST",
KeySchema: [
{ AttributeName: "PK", KeyType: "HASH" }, // Partition key
{ AttributeName: "SK", KeyType: "RANGE" }, // Sort key
],
GlobalSecondaryIndexes: [
{
IndexName: "volumeGroup-index",
KeySchema: [
{ AttributeName: "PK", KeyType: "HASH" }, // Partition key for GSI
{ AttributeName: "volumeGroup", KeyType: "RANGE" }, // Sort key for GSI
],
Projection: {
ProjectionType: "ALL",
},
},
],
AttributeDefinitions: [
{ AttributeName: "PK", AttributeType: "S" },
{ AttributeName: "SK", AttributeType: "S" },
{ AttributeName: "volumeGroup", AttributeType: "S" },
],
});

export async function createTables(context: DBContext) {
const { ddbClient } = context;
Expand All @@ -155,6 +181,7 @@ export async function createTables(context: DBContext) {
await ddbClient.send(createMITableCommand);
await ddbClient.send(createSupplierTableCommand);
await ddbClient.send(createLetterQueueTableCommand);
await ddbClient.send(createSupplierConfigTableCommand);
}

export async function deleteTables(context: DBContext) {
Expand All @@ -165,6 +192,7 @@ export async function deleteTables(context: DBContext) {
"management-info",
"suppliers",
"letter-queue",
"supplier-config",
]) {
await ddbClient.send(
new DeleteTableCommand({
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -30,6 +30,7 @@ function createLetter(
source: "/data-plane/letter-rendering/pdf",
subject: `client/1/letter-request/${letterId}`,
billingRef: "specification1",
specificationBillingId: "billing1",
};
}

Expand Down
Loading
Loading