storage.yml— provisions all stateful resources (DynamoDB tables, SQS queues, KMS key, log groups).microservice.yml— provisions the ECS Fargate service, IAM policies, EventBridge pipes, Lambda, and API Gateway.
microservice-dev-cfg.json file contains the parameter values used in the dev environment.
DynamoDB
Fourteen tables store request state, addresses, tender configuration, costs, events, and more.
SQS
Multiple queues handle internal scheduling, external channel inputs, delivery push outputs, and OCR.
KMS
A symmetric AES-256-GCM key encrypts address data at rest in DynamoDB.
EventBridge
PaperChannelOutcomeEvent events are published to the pn-CoreEventBus. An EventBridge Pipe bridges the prepare-phase queue to the delayer.Lambda
pn-paper-channel-TenderAPI provides read-only access to tender data without going through the main ECS service.IAM
A managed policy grants the ECS task role least-privilege access to SQS, DynamoDB, KMS, EventBridge, and CloudWatch.
DynamoDB tables
All tables usePAY_PER_REQUEST billing mode and have point-in-time recovery enabled. Changes are streamed to Kinesis for CDC.
| CloudFormation resource | Table name (production) | Partition key | Sort key | Purpose |
|---|---|---|---|---|
RequestDeliveryDynamoTable | {ProjectName}-PaperRequestDelivery | requestId | — | Main delivery request records. GSIs on fiscalCode and correlationId. |
AddressDynamoTable | {ProjectName}-PaperAddress | requestId | addressType | Per-request addresses. KMS-encrypted at rest. TTL enabled. |
TenderDynamoTable | {ProjectName}-PaperTender | tenderCode | — | Legacy tender records. GSI on author+date. |
DeliveryDriverDynamoTable | {ProjectName}-PaperDeliveryDriver | tenderCode | taxId | Legacy delivery driver records. GSIs on author+startDate and tenderCode. |
CostDynamoTable | {ProjectName}-PaperCost | driverCode | uuidCode | Legacy cost records per driver. GSI on tenderCode. |
ZoneDynamoTable | {ProjectName}-PaperZone | countryIt | — | Country-to-zone mapping. GSI on countryEn. |
CapDynamoTable | {ProjectName}-PaperCap | author | cap | Italian CAP to lot mapping. |
DeliveryFileDynamoTable | {ProjectName}-PaperDeliveryFile | uuid | — | Tracks tender file upload status. |
PaperRequestErrorDynamoTable | {ProjectName}-PaperRequestError | requestId | created | Request processing errors. GSIs on author+created and category+cause. |
PaperEventsDynamoTable | {ProjectName}-PaperEvents | pk | sk | Paper delivery events. TTL enabled. |
ClientDynamoTable | {ProjectName}-Clients | clientId | — | Client ID to prefix-value mapping. GSI on prefixValue. |
AttachmentsConfigDynamoTable | {ProjectName}-AttachmentsConfig | configKey | startValidity | Time-based attachment rule configuration. TTL enabled. |
PaperEventErrorDynamoTable | {ProjectName}-PaperEventError | requestId | statusBusinessDateTime | Out-of-order event errors. GSI on flowType. TTL enabled. |
PaperChannelTenderDynamoTable | {ProjectName}-PaperChannelTender | tenderId | — | Simplified-flow tender records. |
PaperChannelGeokeyDynamoTable | {ProjectName}-PaperChannelGeokey | tenderProductGeokey | activationDate | Geokey versions per tender and product. |
PaperChannelDeliveryDriverDynamoTable | {ProjectName}-PaperChannelDeliveryDriver | deliveryDriverId | — | Simplified-flow delivery driver records. |
PaperChannelCostDynamoTable | {ProjectName}-PaperChannelCost | tenderId | productLotZone | Simplified-flow costs per tender, product, lot, and zone. |
SQS queues
Internal queues (owned by this microservice)
| CloudFormation resource | Queue name | Visibility timeout | Purpose |
|---|---|---|---|
ScheduledRequestsQueue | {ProjectName}-paper_channel_requests | 60 s | Internal scheduling queue for delivery requests. |
PaperNormalizeAddressQueue | {ProjectName}-paper-normalize-address | 60 s | Internal queue driving PREPARE phase 1 (address normalization). |
PaperChannelOcrOutputsQueue | {ProjectName}-paper_channel_ocr_outputs | 60 s | Receives OCR response messages. |
ExternalChannelToPaperChannelDryRunQueue | {ProjectName}-external_channel_to_paper_channel_dry_run | 60 s | Receives dry-run messages proxied from External Channel. |
External queues (consumed or produced)
| Property | Direction | Remote service |
|---|---|---|
pn.paper-channel.queue-external-channel | Consume (input) | External Channel — paper tracking events |
pn.paper-channel.queue-national-registries | Consume (input) | National Registries — address lookup responses |
pn.paper-channel.queue-f24 | Consume (input) | F24 — PDF generation responses |
pn.paper-channel.queue-radd-alt | Consume (input) | RADD Alt — alternative delivery events |
pn.paper-channel.queue-delayer-to-paperchannel | Consume (input) | pn-delayer — delayed prepare-phase events |
pn.paper-channel.queue-delivery-push | Produce (output) | Delivery Push — notification status updates |
pn.paper-channel.queue-paperchannel-to-delayer | Produce (output) | pn-delayer via EventBridge Pipe |
pn.paper-channel.queue-url-ocr-inputs | Produce (output) | OCR service in a separate AWS account |
KMS key
pn-paper-channel provisions a symmetric AES-256-GCM KMS key (PCKmsEncDecDynamoDataKey) with key rotation enabled. The key alias is alias/{ProjectName}-paper-channel-dynamo.
The key is used to encrypt the AddressDynamoTable at rest (SSESpecification). The ECS task role has kms:Encrypt, kms:Decrypt, and kms:ReEncrypt* permissions on this key.
For local development, retrieve the LocalStack KMS key ARN and set it in config/application.properties:
EventBridge
PaperChannelOutcomeEvent
The service publishes events to the{ProjectName}-CoreEventBus with:
detail-type:PaperChannelOutcomeEventsource:pn-paper-channel
pn.paper-channel.eventbus.detail.type and pn.paper-channel.eventbus.source.
Prepare-phase EventBridge Pipe
AnAWS::Pipes::Pipe resource (PaperChannelPrepareToDelayerQueuePipe) bridges the PaperChannelToDelayerQueue to CoreEventBus with detail-type: PreparePhaseOneOutcomeEvent. The pipe desired state is controlled by the PaperChannelPrepareToDelayerQueuePipeDesiredState parameter (RUNNING or STOPPED).
Lambda: TenderAPI
The{ProjectName}-paper-channel-TenderAPI Lambda (runtime: nodejs24.x, timeout: 30 s, memory: 512 MB) provides read-only access to tender data directly from DynamoDB. It is invoked using the AWS CLI or SDK and does not expose an HTTP endpoint.
See the Tender management guide for the full payload API.
IAM
ThePaperChannelMicroserviceTaskPolicy managed policy grants the ECS task role:
AddressManagerApiKey is stored in AWS Secrets Manager under the secret name pn-PaperChannel-Secrets and is injected into the container via ContainerSecret1.
CloudFormation deployment
Deploy the storage stack first, then the microservice stack. Pass the storage stack outputs as parameters to the microservice stack. Example using the AWS CLI:scripts/aws/cfn/microservice.yml and scripts/aws/cfn/microservice-dev-cfg.json.