In UK and European commercial freight logistics, transport operators and independent carriers face crippling cashflow bottlenecks:
- Net-30 to Net-90 Payment Terms: Shippers typically settle freight invoices 30 to 90 days after delivery. Carriers, however, must immediately pay for fuel, truck leases, and driver wages.
- Fragile Paperwork & Disputes: Traditional proof of delivery (POD) involves physical paper notes that get lost, delayed, or disputed, delaying payments for weeks.
- Double-Spending & Reconciliation Chaos: Financial teams manually match bank statement lines to invoices and ledger accounts, resulting in reconciliation backlogs, audit risk, and accounting discrepancies.
SmartPay is an enterprise-grade, event-driven financial logistics platform that automates the entire invoice-to-settlement lifecycle in sub-second real-time:
[ Cargo Delivery ] βββΆ [ Cryptographic ePOD ] βββΆ [ Automated Invoice ] βββΆ [ Instant Factoring Payout (<1s) ] βββΆ [ Bank Statement Recon ]
- Cryptographic Electronic Proof of Delivery (ePOD): Drivers record delivery completions with GPS geolocation, delivery photos, and immutable SHA-256 cryptographic signature digests.
-
Automated Freight Pricing Engine:
Invoices are generated dynamically based on vehicle type (Articulated Lorry, Rigid Truck, Van), mileage rates, dynamic fuel surcharges (12%), and statutory VAT (20%) using precision
Moneyvalue objects. - Instant Carrier Factoring Liquidity (< 1s Payout): Upon ePOD verification, carriers receive instant factoring liquidity (gross invoice minus a 2.5% platform fee) disbursed directly over bank rails (Faster Payments / VRP) without waiting 30β90 days.
-
Luca Pacioli Double-Entry Ledger:
An immutable, append-only financial general ledger enforcing the strict zero-sum invariant:
$\sum \text{Debits} == \sum \text{Credits}$ . Balances are guarded against double-spending and deadlocks via strict account-order pessimistic locking. - Two-Tier Distributed Idempotency: Cryptographic SHA-256 request fingerprinting paired with database locks ensures that client retries or network replays never produce duplicate withdrawals or payments.
-
Automated Bank Reconciliation:
Parses ISO 20022 CAMT.053 XML and SWIFT MT940 bank statement feeds, auto-matching statement entries against ledger records via unique
end_to_end_idtokens.
The platform is structured into bounded contexts interacting via gRPC over HTTP/2 for synchronous internal RPC, REST (OpenAPI 3.1) for public ingress, and Redpanda (Kafka API) for event streaming.
flowchart TD
subgraph Clients["External Actors & Clients"]
Shipper["π’ Shipper Web Portal"]
Carrier["π Carrier / Driver Mobile App"]
Bank["π¦ UK Banking Rails (Faster Payments / CAMT.053)"]
Auditor["π Financial Auditor / Finance Ops"]
end
subgraph Ingress["Ingress Layer"]
Gateway["smartpay-gateway (Port 8080)<br/>β’ Reverse Proxy & JWT Auth<br/>β’ Rate Limiting & Two-Tier Idempotency"]
end
subgraph CoreServices["Microservices (Modern Java 25 & Spring Boot 4.1)"]
InvoiceSvc["smartpay-invoice-service (Port 8083)<br/>β’ ePOD Signature Verification<br/>β’ Freight Pricing Engine (Base + Fuel + VAT)"]
RiskSvc["smartpay-risk-service (Port 8085 / gRPC 9095)<br/>β’ Carrier Credit Scoring<br/>β’ Fraud Propensity Evaluation"]
PayoutWorker["smartpay-payout-worker (Port 8087)<br/>β’ 2.5% Factoring Engine<br/>β’ Virtual Thread Background Worker<br/>β’ Resilience4j Circuit Breaker & Retry"]
PaymentSvc["smartpay-payment-service (Port 8082 / gRPC 9092)<br/>β’ Payment Orchestration<br/>β’ Transactional Outbox Engine"]
LedgerSvc["smartpay-ledger-service (Port 8081 / gRPC 9091)<br/>β’ Double-Entry Journal Engine<br/>β’ Pessimistic Locking & Balances"]
ReconSvc["smartpay-recon-service (Port 8084 / gRPC 9094)<br/>β’ CAMT.053 / MT940 Parser<br/>β’ Auto-Reconciliation Engine"]
NotificationSvc["smartpay-notification-service (Port 8086)<br/>β’ Multi-Channel Dispatcher (Email/SMS)<br/>β’ Consumer Idempotency"]
end
subgraph DataInfrastructure["Data & Messaging Infrastructure"]
Postgres[("π PostgreSQL 16 (Port 5432)<br/>β’ UUIDv7 B-Tree Primary Keys<br/>β’ Append-Only Journal Entries<br/>β’ SKIP LOCKED Outbox Tables")]
Redpanda{{"πΌ Redpanda / Kafka (Port 9092)<br/>β’ smartpay.events.invoice<br/>β’ smartpay.events.factoring<br/>β’ smartpay.events.payment"}}
end
%% External Connections β every external request enters via the gateway only
Shipper -->|HTTPS REST| Gateway
Carrier -->|HTTPS REST / ePOD| Gateway
Bank -->|Bank Statements / Payout Clearance| Gateway
Auditor -->|Audit / Recon Reports| Gateway
%% Gateway Routing (sole public entry; path passthrough)
Gateway -->|"/api/v1/invoices, /api/v1/epod"| InvoiceSvc
Gateway -->|"/api/v1/payments"| PaymentSvc
Gateway -->|"/api/v1/notifications"| NotificationSvc
Gateway -->|"/api/v1/recon"| ReconSvc
%% Core Service Interactions
InvoiceSvc -->|Publish EpodVerifiedEvent| Redpanda
InvoiceSvc -.-> Postgres
Redpanda -->|Consume EpodVerifiedEvent| PayoutWorker
PayoutWorker -->|1. REST Fetch Invoice| InvoiceSvc
PayoutWorker -->|2. gRPC EvaluateRisk| RiskSvc
PayoutWorker -->|3. gRPC InitiatePayment| PaymentSvc
PayoutWorker -->|4. REST Update Status| InvoiceSvc
PayoutWorker -->|5. Publish FactoringPayoutApprovedEvent| Redpanda
PaymentSvc -->|gRPC HoldFunds / ReleaseHold| LedgerSvc
PaymentSvc -->|Transactional Outbox Commit| Postgres
PaymentSvc -->|Publish PaymentEvents| Redpanda
LedgerSvc -.-> Postgres
ReconSvc -.-> Postgres
Redpanda -->|Consume Domain Events| NotificationSvc
Comprehensive architectural specifications, design decision records, and story cards are organized under docs/:
- πΊοΈ High-Level Architecture & Bounded Contexts: DDD bounded contexts, strategic domain boundaries, and integration protocols.
- βοΈ Low-Level Architecture & Algorithms: Concurrency control, pessimistic lock ordering, Luca Pacioli zero-sum balance algorithm, and UUIDv7 indexing.
- ποΈ C4 Architecture Models (Context, Container, Component, Code): Complete C4 model diagrams and container interactions.
- π Sequence Diagrams: End-to-end execution sequences for ePOD delivery, factoring advances, balance transfers, and bank reconciliations.
- π₯ Use Case Diagrams: Actor use case boundaries across Shippers, Carriers, Bank Rails, and Finance Ops.
- π gRPC & Protocol Buffers Technical Guide: Protobuf contract specifications, client stubs, deadlines, and error handling.
- βοΈ Containerization, Tooling & Kubernetes Tradeoffs: Deep-dive tradeoff matrix across container engines, JVM virtual thread tuning, database migrations, and testing topologies.
- π ADR Index & Architecture Governance
- ADR-001: Adoption of Modern Java 25 & Spring Boot 4.1
- ADR-002: UUIDv7 Primary Keys for Time-Ordered Database Performance
- ADR-003: Double-Entry Immutable General Ledger Engine
- ADR-004: gRPC over HTTP/2 for Internal Microservice Communication
- ADR-005: Transactional Outbox Pattern for At-Least-Once Delivery
- ADR-006: Two-Tier Distributed Idempotency with SHA-256 Fingerprinting
- ADR-007: Redpanda for C++20 Kafka-Compatible Event Streaming
- ADR-008: Event-Driven Kafka Consumer Groups for Kubernetes Concurrency
- ADR-009: Multi-Stage Distroless Containerization with Custom JRE
- ADR-010: Event-Driven Multi-Channel Notifications with Consumer Idempotency and DLQ
- ADR-011: Automated Multi-Stage Quality Gates & Test Partitioning
- π OpenAPI Specifications Overview
- πͺ API Gateway Public Ingress (OpenAPI 3.1)
- π Double-Entry General Ledger API (OpenAPI 3.1)
- π Freight Invoicing & ePOD Service API (OpenAPI 3.1)
- π³ Payment Orchestration Service API (OpenAPI 3.1)
- π¦ Bank Reconciliation Service API (OpenAPI 3.1)
- π Multi-Channel Notification Engine API (OpenAPI 3.1)
- π¦ Protocol Buffers Contracts (
smartpay-proto) (ledger.proto,payment.proto,risk.proto,common.proto)
- ποΈ Story Roadmap, Sequence & Dependency Matrix
- β STORY-001: Double-Entry Ledger & Atomic Transfer Engine
- β STORY-002: Freight Invoicing & ePOD Pricing Engine
- β STORY-003: Payment Initiation & Transactional Outbox
- β STORY-004: Carrier Factoring & Instant Payout Worker
- β STORY-005: Bank Statement & Auto-Reconciliation Engine
- β STORY-006: API Gateway & Distributed Idempotency Filter
- β STORY-007: Carrier Credit Risk & Fraud Engine
- β STORY-008: Event-Driven Multi-Channel Notification Engine
- β TECH-001: Containerization & K8s Kustomize Engine
- β TECH-002: Enterprise CI Pipeline Automation
- β TECH-003: KinD Cluster & E2E Testing Pipeline
- β³ TECH-004: Envoy Service Mesh & Zero-Trust mTLS
- ποΈ Agent & Architectural Coding Standards
β οΈ TD-001: Currency Master Definitions Tableβ οΈ TD-002: Test Directory Physical Partitioningβ οΈ TD-003: Wire Money asamount+currencyObject (not pence)
| Service | Module | HTTP Port | gRPC Port | Database (Schema) | Primary Responsibility |
|---|---|---|---|---|---|
| API Gateway | smartpay-gateway |
8080 |
β | smartpay_db (gateway) |
Sole public entry. Reverse proxy, JWT auth, rate limiting, two-tier SHA-256 idempotency. Routes (path passthrough): /api/v1/payments, /api/v1/invoices, /api/v1/epod, /api/v1/notifications, /api/v1/recon. Downstream targets injected in-cluster via SMARTPAY_PAYMENT_SERVICE_URL, SMARTPAY_INVOICE_SERVICE_URL, SMARTPAY_NOTIFICATION_SERVICE_URL, SMARTPAY_RECON_SERVICE_URL |
| Ledger Service | smartpay-ledger-service |
8081 |
9091 |
smartpay_db (ledger) |
Double-entry journal posting, balance transfers, hold/release lifecycle |
| Payment Service | smartpay-payment-service |
8082 |
9092 |
smartpay_db (payment) |
Faster Payments / VRP orchestration, Transactional Outbox (SKIP LOCKED) |
| Invoice Service | smartpay-invoice-service |
8083 |
9093 |
smartpay_db (invoice) |
ePOD signature verification, freight pricing (base + fuel + VAT) |
| Payout Worker | smartpay-payout-worker |
8084 |
β | Stateless | Virtual Thread factoring payout background worker with Resilience4j |
| Recon Service | smartpay-recon-service |
8085 |
9094 |
smartpay_db (recon) |
CAMT.053 XML / MT940 bank statement reconciliation engine |
| Risk Service | smartpay-risk-service |
8086 |
9095 |
smartpay_db (risk) |
Carrier credit scoring, exposure limits, fraud propensity evaluation |
| Notification Svc | smartpay-notification-service |
8087 |
β | smartpay_db (notification) |
Event-driven Email / SMS / Webhook notification engine |
| PostgreSQL 16 | postgres |
5432 |
β | smartpay_db |
Shared ACID database; each service owns an isolated PostgreSQL schema (ledger, invoice, payment, recon, β¦) with B-Tree UUIDv7 indexes |
| Redpanda Broker | redpanda |
9092 |
β | β | Lightweight C++20 event streaming broker (Kafka wire-compatible) |
| Redpanda Console | redpanda-console |
8090 |
β | β | Topic and message monitoring dashboard (http://localhost:8090) |
Public network access: only
smartpay-gateway(and ops tooling such as PostgreSQL/Redpanda in dev) is reachable externally. All business microservices are ClusterIP-only and communicate in-cluster via gRPC or Redpanda events; their HTTP ports above are internal service ports, never public.
- Java 25 (Project Loom Virtual Threads):
# Via SDKMAN: sdk install java 25-open # Verify: java -version # OpenJDK 25
- Apache Maven 3.9+:
mvn -version
- Docker & Docker Compose:
docker compose version
Launch PostgreSQL 16, Redpanda (Kafka API), and Redpanda Console:
docker compose up -d- PostgreSQL:
localhost:5432(smartpay_db, user:smartpay, pass:smartpay) - Redpanda:
localhost:9092 - Redpanda Console: Open
http://localhost:8090
Schema isolation: All services share one PostgreSQL database (
smartpay_db), but each microservice owns an isolated schema βledger,invoice,payment,recon,gateway. On first startup every service's Flyway run creates its own schema automatically (spring.flyway.create-schemas: true) and applies its per-service migrations (each service'sdb/migrationfolder restarts atV1), so no schema provisioning is required beforehand.
Compile Protocol Buffers and build all microservice modules:
# Compile protobuf contracts first
mvn compile -pl smartpay-proto
# Build all modules
mvn compileSmartPay strictly separates fast in-memory unit tests from containerized integration suites using JUnit 5 tags:
Executes the full quality pipeline across all 11 modules in
- In-memory unit tests across all domain models, pricing math, MapStruct mappers, and calculation engines.
-
ArchUnit architecture fitness tests across all microservices enforcing
.webpackaging, constructor injection, and Project Loom non-pinning. - Spotless code formatting & linting check.
-
JaCoCo code coverage generation producing HTML reports under
${module}/target/site/jacoco/index.html. -
Surefire test report generation producing HTML reports under
${module}/target/reports/surefire.html.
mvn verify -Punit
# Format codebase using Spotless:
mvn spotless:applyExecutes full-stack integration suites against Testcontainers PostgreSQL 16, WireMock HTTP endpoints, HTTP/2 gRPC channels on Virtual Threads, and Resilience4j circuit breakers:
mvn test -PintegrationSmartPay provides automated one-command provisioning and verification for local Kubernetes testing:
Provisions a 3-node KinD cluster (1 control-plane, 2 workers with port mappings 80/443), installs NGINX Ingress controller, deploys PostgreSQL 16 & Redpanda, applies Flyway migrations, seeds the demo ledger accounts, builds/loads distroless container images, rolls out microservices via Kustomize dev overlay, and executes the automated gateway-mediated E2E smoke suite:
chmod +x scripts/ci/kind-setup.sh
./scripts/ci/kind-setup.sh smartpay-clusterThe smoke suite (e2e-smoke-test.sh) and the full-lifecycle suite reach the platform only through the gateway (GATEWAY_URL, default http://localhost:8080); no business service port is called directly. Demo ledger accounts used by the suites are seeded by scripts/ci/seed-demo-data.sh.
Executes all 10 stages of the end-to-end commercial freight payment lifecycle:
chmod +x scripts/ci/e2e-full-lifecycle-test.sh
./scripts/ci/e2e-full-lifecycle-test.shInspects live event streams, consumer group offsets, and consumer lag directly on Redpanda:
chmod +x scripts/ci/inspect-kafka-topics.sh
# Summary of all topics and consumer groups:
./scripts/ci/inspect-kafka-topics.sh summary
# Consume recent settlement stream messages in JSON format:
./scripts/ci/inspect-kafka-topics.sh consume smartpay.events.payment 5
# Inspect consumer group lag (factoring workers & notification workers):
./scripts/ci/inspect-kafka-topics.sh lag
# Inspect Dead Letter Queue (DLQ):
./scripts/ci/inspect-kafka-topics.sh dlqServices can be launched independently using the Spring Boot Maven plugin. In production-like topologies every external request must go through the API Gateway β business services are ClusterIP-only. For local runs, either call the gateway last and point it at the other services, or invoke a service directly only for development:
# 1. Start Ledger Service (HTTP: 8081, gRPC: 9091)
mvn spring-boot:run -pl smartpay-ledger-service
# 2. Start Payment Service (HTTP: 8082, gRPC: 9092)
mvn spring-boot:run -pl smartpay-payment-service
# 3. Start Invoice & ePOD Service (HTTP: 8083)
mvn spring-boot:run -pl smartpay-invoice-service
# 4. Start Payout Factoring Worker (HTTP: 8084)
mvn spring-boot:run -pl smartpay-payout-worker
# 5. Start Bank Reconciliation Service (HTTP: 8085)
mvn spring-boot:run -pl smartpay-recon-service
# 6. Start Risk & Fraud Service (HTTP: 8086, gRPC: 9091)
mvn spring-boot:run -pl smartpay-risk-service
# 7. Start Notification Service (HTTP: 8087)
mvn spring-boot:run -pl smartpay-notification-service
# 8. Start API Gateway β the ONLY public entry point. Point its downstream
# routes at the locally running services (defaults are localhost:8082/8083/8087/8085):
SMARTPAY_PAYMENT_SERVICE_URL=http://localhost:8082 \
SMARTPAY_INVOICE_SERVICE_URL=http://localhost:8083 \
SMARTPAY_NOTIFICATION_SERVICE_URL=http://localhost:8087 \
SMARTPAY_RECON_SERVICE_URL=http://localhost:8085 \
SMARTPAY_GATEWAY_SECURITY_ENABLED=false \
mvn spring-boot:run -pl smartpay-gatewayRoute through the gateway for business calls, e.g. POST http://localhost:8080/api/v1/payments/initiate
with an Idempotency-Key and X-Tenant-Id header. The notification service additionally needs a
reachable REDPANDA_BOOTSTRAP_SERVERS broker (its dead-letter producer publishes there).