Skip to main content
pn-paper-channel uses Amazon SQS as its primary integration bus. External Channel pushes PaperProgressStatusEventDto events onto an inbound queue. A listener dispatches each event to a typed MessageHandler based on the status code. Handlers either record intermediate data, forward the event to pn-delivery-push, or do both in sequence.

Architecture overview

External Channel

      │  PaperProgressStatusEventDto

  SQS (inbound)


 HandlersFactory.getHandler(statusCode)

      ├─ SaveMetadataMessageHandler     → EventMetaDAO
      ├─ SaveDematMessageHandler        → EventDematDAO
      ├─ AggregatorMessageHandler       → EventMetaDAO + SendToDeliveryPushHandler
      ├─ ChainedMessageHandler          → sequential handler chain
      └─ SendToDeliveryPushHandler      → SQS (pn-delivery-push)
HandlersFactory is a Spring @Component that initialises a ConcurrentHashMap<String, MessageHandler> at startup via @PostConstruct. If no handler is registered for a given status code, LogMessageHandler is used as a no-op fallback.

Handler types

The root interface. All handlers implement Mono<Void> handleMessage(PnDeliveryRequest entity, PaperProgressStatusEventDto paperRequest).
No-op handler used as the fallback for unregistered status codes. It logs the event and returns immediately.
Executes a list of MessageHandler instances sequentially using Flux.fromIterable(handlers).concatMap(...). Used to compose multi-step processing pipelines.
Persists the event into EventMetaDAO for later retrieval by aggregator handlers. Optionally forwards the event to pn-delivery-push when the SendProgressMeta feature flag (isMetaEnabled()) is active.
Persists digital document (demat) data into EventDematDAO. Used for events carrying scanned attachments.
Handles final status codes that require enrichment with pre-closing metadata. It:
  1. Reads the correlated pre-closing PnEventMeta record from EventMetaDAO.
  2. Enriches the incoming event with deliveryFailureCause and discoveredAddress.
  3. Forwards the enriched event to pn-delivery-push via SendToDeliveryPushHandler.
  4. Cleans up META and DEMAT rows for the request via MetaDematCleaner.
A specialised aggregator for events like RECAG003C that require custom aggregation logic.
Pushes the event directly to the pn-delivery-push SQS queue. Used for progress events that need no prior metadata.
A proxy that routes events to an OCR processing queue when the driver is configured for OCR, and falls back to a wrapped MessageHandler otherwise. Used for RECRN001C, RECRN002C, RECRN002F, RECRN003C, RECRN004C, and RECRN005C.
Handles transient errors by retrying the External Channel send request. Used for codes like RECRS006, RECRN006, and RECAG004.
Handles permanent errors by recording the failure and notifying pn-delivery-push. Used for CON997, CON998, CON995, and CON993.
Records the error in PaperRequestErrorDAO without sending any event to pn-delivery-push. Used for P008P014.
Routes CON996 (postal code not covered) to either RetryableErrorMessageHandler or NotRetryableErrorMessageHandler depending on the pn.paper-channel.enable-retry-con996 flag.
Routes 890-family final events (RECAG005CRECAG008C) to one of: RECAG008CMessageHandler, Complex890MessageHandler, or Simple890MessageHandler, based on configuration.
Handles the PNAG012 storage-in-progress (compiuta giacenza) event for both 890 and AR flows.
Handle the two-step 890 storage notification sequence. RECAG011A saves metadata; RECAG011B saves demat data and may trigger PNAG012.
Saves RECAG012 metadata and posts simplified post-logic. Optionally sends RECAG012A when the isRECAG012AEnabled() flag is active.
Handles the final 890 delivery outcome, cleaning up meta/demat data and forwarding to pn-delivery-push.
Handle final AR delivery outcomes with OCR proxy support.
Handles the RECRN011 storage-in-progress event for AR deliveries.

Status code → handler mapping

RECAG family (Legge 890/1982 — raccomandata giudiziaria)

Status codeHandlerDescription
RECAG001ASaveMetadataMessageHandler890 progress: in transit
RECAG001BSaveDematMessageHandler890 demat: in transit
RECAG001CAggregatorMessageHandler890 final: in transit
RECAG002ASaveMetadataMessageHandler890 progress: delivery attempt
RECAG002BSaveDematMessageHandler890 demat: delivery attempt
RECAG002CAggregatorMessageHandler890 final: delivery attempt
RECAG003ASaveMetadataMessageHandler890 progress: not delivered
RECAG003BSaveDematMessageHandler890 demat: not delivered
RECAG003CCustomAggregatorMessageHandler890 final: not delivered (custom)
RECAG003DSaveMetadataMessageHandler890 progress: not delivered (variant)
RECAG003ESaveDematMessageHandler890 demat: not delivered (variant)
RECAG003FAggregatorMessageHandler890 final: not delivered (variant)
RECAG004RetryableErrorMessageHandler890 retryable error
RECAG005ASaveMetadataMessageHandler890 progress: storage pending
RECAG005BChainedMessageHandler (SaveDemat + SimplifiedPostLogic)890 demat: storage
RECAG005CProxy890MessageHandler890 final: storage
RECAG006ASaveMetadataMessageHandler890 progress: delivered to post office
RECAG006BChainedMessageHandler (SaveDemat + SimplifiedPostLogic)890 demat: delivered to post office
RECAG006CProxy890MessageHandler890 final: delivered to post office
RECAG007ASaveMetadataMessageHandler890 progress: returned to sender
RECAG007BChainedMessageHandler (SaveDemat + SimplifiedPostLogic)890 demat: returned to sender
RECAG007CProxy890MessageHandler890 final: returned to sender
RECAG008ASaveMetadataMessageHandler890 progress: compiuta giacenza
RECAG008BChainedMessageHandler (SaveDemat + SimplifiedPostLogic)890 demat: compiuta giacenza
RECAG008CProxy890MessageHandler890 final: compiuta giacenza
RECAG010SendToDeliveryPushHandler890 progress: inesito
RECAG011ARECAG011AMessageHandler890 storage in-progress: meta
RECAG011BRECAG011BMessageHandler890 storage in-progress: demat
RECAG012ChainedMessageHandler (RECAG012 + SimplifiedPostLogic [+ RECAG012A])890 registered mail receipt
RECAG013RetryableErrorMessageHandler890 retryable error (variant)
RECAG015SendToDeliveryPushHandler890 progress: in transit (variant)

RECRN family (raccomandata normale — AR/RS)

Status codeHandlerDescription
RECRN001ASaveMetadataMessageHandlerAR/RS progress: in transit
RECRN001BSaveDematMessageHandlerAR/RS demat: in transit
RECRN001CSendToOcrProxyHandler (wraps AggregatorMessageHandler)AR/RS final: in transit
RECRN002ASaveMetadataMessageHandlerAR/RS progress: delivery attempt
RECRN002BSaveDematMessageHandlerAR/RS demat: delivery attempt
RECRN002CSendToOcrProxyHandler (wraps CustomAggregatorMessageHandler)AR/RS final: not delivered
RECRN002DSaveMetadataMessageHandlerAR/RS progress: not delivered
RECRN002ESaveDematMessageHandlerAR/RS demat: not delivered
RECRN002FSendToOcrProxyHandler (wraps AggregatorMessageHandler)AR/RS final: not delivered (variant)
RECRN003ASaveMetadataMessageHandlerAR/RS progress: storage pending
RECRN003BSaveDematMessageHandlerAR/RS demat: storage pending
RECRN003CSendToOcrProxyHandler (wraps RECRN003CMessageHandler)AR/RS final: delivered at post office
RECRN004ASaveMetadataMessageHandlerAR/RS progress: compiuta giacenza
RECRN004BSaveDematMessageHandlerAR/RS demat: compiuta giacenza
RECRN004CSendToOcrProxyHandler (wraps RECRN004CMessageHandler)AR/RS final: compiuta giacenza
RECRN005ASaveMetadataMessageHandlerAR/RS progress: returned to sender
RECRN005BSaveDematMessageHandlerAR/RS demat: returned to sender
RECRN005CSendToOcrProxyHandler (wraps RECRN005CMessageHandler)AR/RS final: returned to sender
RECRN006RetryableErrorMessageHandlerAR/RS retryable error
RECRN010SaveMetadataMessageHandlerAR/RS progress: delivery info
RECRN011RECRN011MessageHandlerAR/RS storage in-progress
RECRN013RetryableErrorMessageHandlerAR/RS retryable error (variant)
RECRN015SendToDeliveryPushHandlerAR/RS progress

RECRS family (raccomandata semplice)

Status codeHandlerDescription
RECRS001CSendToDeliveryPushHandlerRS final: delivered
RECRS002ASaveMetadataMessageHandlerRS progress
RECRS002BSaveDematMessageHandlerRS demat
RECRS002CAggregatorMessageHandlerRS final
RECRS002DSaveMetadataMessageHandlerRS progress (variant)
RECRS002ESaveDematMessageHandlerRS demat (variant)
RECRS002FAggregatorMessageHandlerRS final (variant)
RECRS003CSendToDeliveryPushHandlerRS final: returned to sender
RECRS004ASaveMetadataMessageHandlerRS progress: storage
RECRS004BSaveDematMessageHandlerRS demat: storage
RECRS004CAggregatorMessageHandlerRS final: storage
RECRS005ASaveMetadataMessageHandlerRS progress: compiuta giacenza
RECRS005BSaveDematMessageHandlerRS demat: compiuta giacenza
RECRS005CAggregatorMessageHandlerRS final: compiuta giacenza
RECRS006RetryableErrorMessageHandlerRS retryable error
RECRS010SendToDeliveryPushHandlerRS progress: inesito
RECRS013RetryableErrorMessageHandlerRS retryable error (variant)
RECRS015SendToDeliveryPushHandlerRS progress

RECRI / RECRSI family (international)

Status codeHandlerDescription
RECRI001SendToDeliveryPushHandlerInternational progress
RECRI002SendToDeliveryPushHandlerInternational progress
RECRI003ASaveMetadataMessageHandlerInternational progress
RECRI003BSaveDematMessageHandlerInternational demat
RECRI003CAggregatorMessageHandlerInternational final
RECRI004ASaveMetadataMessageHandlerInternational progress
RECRI004BSaveDematMessageHandlerInternational demat
RECRI004CAggregatorMessageHandlerInternational final
RECRI005RetryableErrorMessageHandlerInternational retryable error
RECRSI003CSendToDeliveryPushHandlerInternational simple final
RECRSI004ASaveMetadataMessageHandlerInternational simple progress
RECRSI004BSaveDematMessageHandlerInternational simple demat
RECRSI004CAggregatorMessageHandlerInternational simple final
RECRSI005RetryableErrorMessageHandlerInternational simple retryable error

CON family (connection / system events)

Status codeHandlerDescription
CON080SendToDeliveryPushHandlerProgress: sent to External Channel
CON018SendToDeliveryPushHandlerProgress (when isCON018Enabled())
CON020SendToDeliveryPushHandlerProgress (when sendCon020=true)
CON993NotRetryableErrorMessageHandlerNon-retryable error
CON995NotRetryableErrorMessageHandlerNon-retryable error
CON996ProxyCON996MessageHandlerCAP not covered (retry or non-retryable)
CON997NotRetryableErrorMessageHandlerNon-retryable error
CON998NotRetryableErrorMessageHandlerNon-retryable error

PNAG / P family

Status codeHandlerDescription
PNAG012PNAG012MessageHandlerCompiuta giacenza (storage) for 890 and AR
P008P014NotRetriableWithoutSendErrorMessageHandlerNon-retryable errors, no event sent to delivery-push

ToggleableQueueListener

ToggleableQueueListener is a @Configuration class that activates only when pn.paper-channel.enable-prepare-phase-one=true. It listens on the ${pn.paper-channel.queue-normalize-address} SQS queue and dispatches three internal event types:
Event typeHandler methodDescription
PREPARE_ASYNC_FLOWhandlePreparePhaseOneAsyncFlowEventStarts phase-1 address normalization
NATIONAL_REGISTRIES_ERRORhandleNationalRegistriesErrorEventRetries National Registry lookup up to attemptQueueNationalRegistries times
ADDRESS_MANAGER_ERRORhandleAddressManagerErrorEventFromPreparePhaseOneRetries Address Manager normalization up to attemptQueueAddressManager times
When pn.paper-channel.enable-prepare-phase-one=false, this listener is not registered and the legacy PrepareAsyncServiceImpl handles the full flow instead.

Outgoing events to pn-delivery-push

SqsSender publishes two event types to pn-delivery-push:
Event typeTriggerContent
PrepareEventEnd of successful Prepare phaserequestId, resolved address, StatusCodeEnum.OK or KO, optional KOReason
PaperChannelUpdate containing SendEventProgress events from External ChannelStatus code, delivery details, optional discoveredAddress
For requests originating from pn-service-desk (detected by PREFIX_REQUEST_ID_SERVICE_DESK in the requestId), events are sent to EventBridge instead of SQS via sqsSender.pushPrepareEventOnEventBridge().

Build docs developers (and LLMs) love