Skip to content

Changelog

All notable changes to the Payflow API project will be documented in this file.

The format is based on Keep a Changelog, and this project adheres to Semantic Versioning.


[Unreleased]

Added - Documentation Modernization & D2 Engine Migration

  • Replaced legacy Docsify single-page app with Material for MkDocs static site generator (mkdocs-material 9.5+) featuring instantaneous client search, dark/light theme switching, and responsive design.
  • Redrew and modernized all 12 architectural topology, sequence, and data flow diagrams across docs/ARCHITECTURE.md, README.md, and docs/index.md using the declarative D2 diagramming engine (docs/diagrams/*.d2) with offline vector icons and Eclipse Layout Kernel (ELK) collision-free routing.
  • Implemented Option 1 Hybrid Pre-rendered SVG + Collapsible D2 Source pattern: pre-rendered self-contained SVGs (docs/assets/diagrams/*.svg) with embedded <details><summary>📐 View Declarative D2 Diagram Source</summary>... blocks, guaranteeing crisp, zero-flicker rendering across GitHub web, IDE previewers, and the documentation portal.
  • Authored automated compilation script scripts/generate-diagrams.sh with dual light/dark theme compilation (--theme=0 --dark-theme=200) and --check drift detection.
  • Configured enterprise CI/CD quality gates in .github/workflows/ci.yml:
  • Enforced zero diagram drift on PR and push via ./scripts/generate-diagrams.sh --check.
  • Enforced strict documentation compilation on PR and push via mkdocs build --strict.
  • Automated deployment of the documentation portal alongside JaCoCo test coverage reports to GitHub Pages on main merge.
  • Created .github/workflows/generate-diagrams.yml enabling 1-click manual workflow dispatch to recompile D2 diagrams and automatically commit changes without requiring local D2 installation.
  • Created requirements.txt specifying deterministic Python dependencies (mkdocs>=1.6.1, mkdocs-material>=9.5.0, mkdocs-d2-plugin>=1.6.0).
  • Created offline SVG icon library under docs/assets/icons/ (16 scalable vector icons) for zero-dependency compilation.
  • Eliminated redundant documentation files and deduplicated governance markdowns (CHANGELOG.md, CONTRIBUTING.md, SECURITY.md, LICENSE) via single-source relative symlinks in docs/.
  • Hardened .gitignore to prevent committing build artifacts (site/, .cache/, .venv/, Python bytecode).
  • Corrected API endpoint routes and verified complete parity with Java 25 & Spring Boot 4.1.0 codebase (191 tests, 90% line / 73% branch coverage).

Added - Phase 11A (Multi-Stage Containerization & Full-Stack Docker Compose)

  • Created hardened multi-stage Dockerfile:
  • Stage 1: Build stage utilizing OpenJDK 25 (eclipse-temurin:25-jdk) and Maven layer caching.
  • Stage 2: Minimal runtime utilizing eclipse-temurin:25-jre executing under unprivileged non-root user payflow:10001.
  • Configured native container HEALTHCHECK targeting Spring Boot Actuator readiness probe (/actuator/health/readiness).
  • Tuned production container JVM flags: -XX:+UseZGC -XX:+ZGenerational -XX:MaxRAMPercentage=75.0 -Djava.security.egd=file:/dev/./urandom.
  • Created .dockerignore strictly filtering target/, git metadata, local scripts, and markdown documentation.
  • Created production-ready docker-compose.yml orchestrating PostgreSQL 17, Redis 7, Apache Kafka (KRaft), Ollama Gen-AI, Prometheus, and Grafana with volume persistence and healthcheck dependency ordering (condition: service_healthy).
  • Created telemetry infrastructure:
  • monitoring/prometheus/prometheus.yml scraping app:8080/actuator/prometheus.
  • monitoring/grafana/provisioning/datasources/prometheus.yml auto-provisioning Prometheus datasource.
  • monitoring/grafana/provisioning/dashboards/dashboard-provider.yml registering dashboard providers.
  • monitoring/grafana/provisioning/dashboards/payflow.json telemetry dashboard covering JVM memory, HTTP throughput/latency (p95/p99), HikariCP pool metrics, and virtual thread metrics.
  • Authored ADR-028 (Multi-Stage Containerization and Full-Stack Docker Compose Orchestration).

Added - Phase 11B (Cloud-Native Kubernetes Deployment Topology & Graceful Shutdown)

  • Created declarative Kubernetes manifest suite in k8s/:
  • k8s/configmap.yaml and k8s/secret.yaml separating non-sensitive environment configuration from cryptographic credentials.
  • k8s/deployment.yaml defining 2 replicas, zero-downtime RollingUpdate (maxSurge: 1, maxUnavailable: 0), non-root security context (runAsUser: 10001), CPU/memory requests and limits, Actuator liveness/readiness probes, and coordinated graceful shutdown pre-stop hook (sleep 10).
  • k8s/service.yaml exposing internal ClusterIP on port 8080.
  • k8s/hpa.yaml HorizontalPodAutoscaler scaling between 2 and 10 replicas based on 75% CPU and 80% memory utilization.
  • k8s/pdb.yaml PodDisruptionBudget enforcing minAvailable: 1 during node maintenance.
  • Configured coordinated graceful shutdown by adding spring.lifecycle.timeout-per-shutdown-phase: 30s alongside server.shutdown: graceful in application-prod.yml and application-prod-light.yml.
  • Authored ADR-029 (Cloud-Native Kubernetes Deployment Topology and Horizontal Pod Autoscaling).

Added - Phase 11C (CI/CD Pipeline Hardening & Automated Quality Gates)

  • Integrated spotbugs-maven-plugin:4.10.4.1 with spotbugs-exclude.xml for Java 25 static bytecode auditing; achieved 0 bugs and 0 errors.
  • Refactored JwtTokenProvider, Transaction, SecurityUtils, and RequestIdFilter to resolve constructor leaks, serialization warnings, and HTTP header sanitization.
  • Integrated jacoco-maven-plugin:0.8.15 enforcing minimum 80% line coverage and 70% branch coverage across core business and security packages; achieved 90% line coverage and 73% branch coverage across 191 unit tests with 0 missed classes.
  • Created comprehensive unit test suites: JwtAccessDeniedHandlerTest, JwtAuthenticationEntryPointTest, JwtAuthenticationFilterTest, SecurityUtilsTest, and IdempotencyCleanupServiceTest.
  • Hardened .github/workflows/ci.yml executing mvn clean verify -B with automated artifact upload for JaCoCo coverage reports and SpotBugs analysis (14-day retention).
  • Added automated GitHub Pages deployment for the Material for MkDocs public documentation portal (https://shashankch.github.io/payflow-api/), Code Coverage Quality Gate summary (https://shashankch.github.io/payflow-api/coverage/), and live interactive JaCoCo coverage reports (https://shashankch.github.io/payflow-api/coverage-report/).
  • Authored ADR-030 (Automated CI/CD Quality Gates, JaCoCo Coverage Enforcement, and SpotBugs Static Analysis).
  • Added spring-modulith-events-kafka, spring-kafka, spring-kafka-test, and Testcontainers kafka dependencies to pom.xml.
  • Marked domain event TransferCompletedEvent with @Externalized and configured programmatic dynamic routing via EventExternalizationConfiguration in KafkaConfig.java, routing to ${payflow.kafka.transfers-topic} partitioned by senderUpi for strict chronological delivery per account.
  • Created KafkaConfig.java (@Profile({"prod", "kafka"})) registering NewTopic bean with configurable partitions and replication factor (PAYFLOW_KAFKA_REPLICAS:3 in production for high availability, 1 in dev/test).
  • Created dedicated application-kafka.yml enabling Spring Modulith externalization (enabled: true) and configuring Kafka endpoints for the kafka profile.
  • Configured resilient Kafka producer properties in application-prod.yml and application-kafka.yml with acks: all, enable.idempotence: true (producer retry deduplication), and at-least-once end-to-end delivery via the transactional outbox.
  • Configured default profile isolation (spring.modulith.events.externalization.enabled: false in application.yml), enabling zero-broker in-process execution in local, test, and prod-light profiles.
  • Created unit tests KafkaConfigTest.java (verifying conditional bean wiring, custom topic resolution, and replication factors) and TransferCompletedEventTest.java (verifying annotation and accessors).
  • Created full-stack integration test KafkaOutboxIT.java against Testcontainers Kafka (KRaft mode) verifying transfer execution, outbox persistence, and externalized record consumption.
  • Added ADR-024 (Kafka Event Streaming via Spring Modulith Event Externalization) to docs/adr/.

Added / Hardened - Phase 9B (Production Hardening & Architecture Audit Remediation)

  • Security Hardening (SEC-01, SEC-02, SEC-03, SEC-04):
  • Added startup validation in JwtTokenProvider.java requiring external PAYFLOW_SECURITY_JWT_SECRET of >= 256 bits (32 chars) when running in prod profile, failing fast on default or weak keys.
  • Enforced ROLE_ADMIN check in UserController.java for GET /api/v1/users and GET /api/v1/users/balance/{amount}, preventing unauthorized balance enumeration and BOLA vulnerabilities.
  • Hardened CORS configuration in SecurityConfig.java to disallow credentials when wildcard origin (*) is present.
  • Configured clickjacking defense via frameOptions().sameOrigin() in SecurityConfig.java.
  • Architecture & Resilience (ARCH-02, ARCH-03, ARCH-04):
  • Handled Spring 6.1+ / Spring 7 HandlerMethodValidationException, ConstraintViolationException, and MethodArgumentTypeMismatchException in GlobalExceptionHandler.java returning RFC 9457 ProblemDetail responses.
  • Enforced boundary validation for Idempotency-Key header in IdempotencyFilter.java (max 255 chars, pattern ^[A-Za-z0-9_.:-]+$).
  • Implemented scheduled OutboxCleanupService.java leveraging Spring Modulith 2.0 CompletedEventPublications.deletePublicationsOlderThan(Duration) to purge completed outbox events older than 7 days.
  • Enhanced Flyway migration V6__create_event_publication_registry.sql with event_publication_archive table and indexes, and aligned User.phoneNumber length (10 chars) and Transaction join column nullability (nullable = false) to satisfy Hibernate schema validation on PostgreSQL.
  • Performance & Scalability (PERF-01):
  • Replaced global cache invalidation (allEntries = true) in TransactionService.java with targeted cache eviction, invalidating only affected sender and receiver keys (upi, refId, id, and user ledgers).
  • Quality, Verification & Build Lifecycle (TEST-01, TEST-02, TEST-03):
  • Added maven-failsafe-plugin 3.5.6 bound to integration-test and verify goals in pom.xml, separating unit tests (*Test.java) from integration tests (*IT.java).
  • Added DataJpaTest repository slice tests TransactionRepositoryTest.java and IdempotencyRepositoryTest.java.
  • Added unit test coverage for OutboxCleanupServiceTest, IdempotencyFilterTest, UserControllerTest, and JwtTokenProviderTest.
  • Documentation & Configuration Consistency (DOC-01, DOC-02):
  • Synchronized docs/ARCHITECTURE.md (Resilience4j vs Bucket4j, Virtual Threads scheduling for Phase 10B, Redisson lock topology).
  • Aligned docker-compose.yml to use SPRING_PROFILES_ACTIVE: local.
  • Updated docs/CONVENTIONS.md testing standards for Surefire and Failsafe phases.
  • Added ADR-025 (Production Hardening and Architecture Audit Remediation) to docs/adr/.
  • Integration Testing & Container Pipeline Stabilization:
  • Implemented Testcontainers Singleton Container pattern in AbstractIntegrationTest, eliminating premature container stops across test classes.
  • Added spring-boot-restclient and @AutoConfigureTestRestTemplate for Spring Boot 4.1 test client autowiring.
  • Resolved Kafka event externalization routing, static singleton container startup, and consumer assignment warmup in KafkaOutboxIT.java and KafkaConfig.java.
  • Configured ByteArraySerializer in application-kafka.yml ensuring raw serialized event bytes on Kafka topics for Spring Modulith externalization.
  • Bound TaggedRateLimiterMetrics and TaggedCircuitBreakerMetrics as MeterBinder beans in Resilience4jConfig.java to export resilience metrics to Micrometer and Prometheus.
  • Configured Resilience4j configs templates in application.yml / application-test.yml and dynamic instance config fallback in UserRateLimiterService.java.
  • Normalized phone number generation in ConcurrentTransferIT and aligned BOLA authorization headers in TransferLifecycleIT.
  • Aligned ResilienceIT transaction status assertion with TransactionStatus enum and corrected SpEL key expression in @Externalized("payflow.transfers::#{senderUpi()}").

Added - Phase 10A (Gen-AI Spend Categorization & Financial Insights)

  • Integrated Spring AI 2.0.1 GA (spring-ai-starter-model-openai) via BOM dependency management in pom.xml.
  • Created immutable Java 25 record SpendInsightResponse with OpenAPI schemas and Jackson serialization for category, amount, summary, budgetingTip, confidenceScore, and source.
  • Implemented AiConfig.java providing a @ConditionalOnBean(ChatClient.Builder.class) ChatClient bean.
  • Implemented LlmInsightClient.java utilizing Spring AI fluent ChatClient entity extraction, guarded by Resilience4j @CircuitBreaker(name = "aiCircuitBreaker", fallbackMethod = "ruleBasedFallback") and 8-category deterministic keyword heuristic fallback.
  • Implemented SpendInsightsService and SpendInsightsServiceImpl with principal transaction verification and payflow.ai.enabled feature flag enforcement.
  • Created FeatureDisabledException with centralized RFC 9457 HTTP 503 ProblemDetail handler in GlobalExceptionHandler.
  • Added endpoint POST /api/v1/transactions/{id}/insights to TransactionController with multi-party principal authorization.
  • Added comprehensive unit tests in SpendInsightsServiceTest.java and TransactionControllerTest.java.
  • Documented ADR-026 (Gen-AI Spend Categorization with Spring AI and Circuit Breaker Fallback).

Added - Phase 10B (Virtual Threads & Resource Optimization)

  • Enabled Java 25 Project Loom Virtual Threads globally (spring.threads.virtual.enabled: true in application.yml).
  • Tuned HikariCP connection pool parameters (idle-timeout: 300000ms, max-lifetime: 1800000ms, connection-timeout: 30000ms) in application-prod.yml to prevent database connection saturation.
  • Introduced lightweight single-node production profile application-prod-light.yml designed for <= 1 GiB RAM deployments with local Caffeine caching, bounded HikariCP pool (max 5), and in-process Modulith event publication.
  • Extended strict production JWT secret entropy verification in JwtTokenProvider to cover the prod-light profile.
  • Restricted TransferEventListener execution to @Profile({"local", "test", "prod-light"}) ensuring zero duplicate processing when Kafka externalization is active.
  • Documented ADR-027 (Java 25 Virtual Threads and Bounded HikariCP Connection Pool Optimization).

[0.8.0] - 2026-09-09

Added - Phase 8D (Redis Distributed Locking with Redisson & Fail-Safe Fallback)

  • Added org.redisson:redisson (version 4.7.0) dependency to pom.xml, aligning with Netty 4.2.15.Final in Spring Boot 4.1.0.
  • Created DistributedLockService.java interface defining tryLock(key, waitTime, leaseTime), fail-fast tryLock(key, leaseTime), unlock(key), and isLocked(key).
  • Created RedissonDistributedLockService.java (@Profile("prod")) implementing distributed locking with Redisson RLock:
  • Safely verifies lock.isHeldByCurrentThread() before calling unlock() to eliminate IllegalMonitorStateException.
  • Restores thread interrupt status on InterruptedException.
  • Created NoOpDistributedLockService.java (@Profile("!prod")) providing an in-memory pass-through for local, test, and prod-light profiles.
  • Created DistributedLockConfig.java (@Profile("prod")) configuring RedissonClient bean with connection pool (20), idle connections (5), and timeout (3000ms).
  • Configured externalized lock properties under payflow.lock (wait-time: 2s, lease-time: 10s) in application.yml.
  • Enhanced IdempotencyFilter.java with distributed locking:
  • Acquires distributed lock on payflow:lock:idemp:<key> before inspecting database records.
  • Automatically releases lock in finally block across all execution paths (success, conflict, error, and exception).
  • Returns HTTP 409 Conflict with Lock Contention ProblemDetail when lock acquisition fails within the 2-second wait window.
  • Defensively defaults to NoOpDistributedLockService when DistributedLockService bean is omitted in slice tests (@WebMvcTest).
  • Created comprehensive unit tests:
  • NoOpDistributedLockServiceTest.java verifying pass-through behavior.
  • RedissonDistributedLockServiceTest.java verifying lock acquisition, contention timeout, interrupt handling, thread-bound unlocking, and exception safety.
  • DistributedLockConfigTest.java verifying profile-conditional bean wiring.
  • Updated IdempotencyFilterTest.java verifying lock acquisition, contention rejection, and guaranteed unlock in finally.
  • Added ADR-023 (Redis Distributed Locking with Redisson and Fail-Safe Local Fallback) to docs/adr/.

Added - Phase 8C (Redis Distributed Caching & Caffeine Local Fallback)

  • Added spring-boot-starter-cache, spring-boot-starter-data-redis, and caffeine (version 3.2.0) dependencies to pom.xml.
  • Created CacheConfig.java enabling @EnableCaching with profile-conditional CacheManager resolution:
  • Redis CacheManager in prod profile with RedisSerializer.string() keys, modern non-deprecated RedisSerializer.json() values, and granular TTL configurations (10 minutes default and users, 1 minute for user_ledgers).
  • Caffeine CacheManager in !prod (local, test, prod-light) using spec maximumSize=1000,expireAfterWrite=600s.
  • Created RedisConfig.java (@Profile("prod")) configuring LettuceConnectionFactory with standalone configuration and generic RedisTemplate<String, Object>.
  • Annotated UserService.java query operations with @Cacheable:
  • getUserById(Long id) -> @Cacheable(value = "users", key = "#id", unless = "#result == null").
  • getUserByReferenceId(UUID referenceId) -> @Cacheable(value = "users", key = "#referenceId", unless = "#result == null").
  • findByUpiId(String upiId) -> @Cacheable(value = "users", key = "#upiId", unless = "#result == null").
  • getUserByUpiId(String upiId) -> @Cacheable(value = "users", key = "#upiId", unless = "#result == null").
  • getUserLedger(UUID userReferenceId, Pageable pageable) -> @Cacheable(value = "user_ledgers", key = "#userReferenceId + '_' + #pageable.pageNumber", unless = "#result == null").
  • Annotated mutation operations with @CacheEvict:
  • UserService.registerUser() -> @CacheEvict(value = "users", allEntries = true).
  • TransactionService.sendMoney() -> @CacheEvict(value = {"users", "user_ledgers"}, allEntries = true) upon successful transfer execution.
  • Hardened domain entities for distributed JSON caching:
  • User.java: Added implements Serializable and serialVersionUID = 1L.
  • BalanceLedgerEntry.java: Added implements Serializable, serialVersionUID = 1L, @JsonIgnoreProperties({"hibernateLazyInitializer", "handler"}) to ignore Hibernate proxy fields, and @JsonIgnore on lazy associations (user, transaction) to prevent circular serialization graphs.
  • Externalized cache TTL configurations in application.yml (payflow.cache.*) and Redis connection parameters in application-prod.yml.
  • Created unit and slice tests:
  • CacheConfigTest.java verifying Caffeine CacheManager bean creation, cache operations, and profile-conditional activation.
  • UserServiceCacheTest.java verifying cache hits on reference ID, UPI, and ledger queries, and @CacheEvict on registerUser().
  • TransactionServiceCacheTest.java verifying multi-cache eviction on sendMoney().
  • Created full-stack integration test CacheIT.java against Testcontainers PostgreSQL verifying caching and eviction mechanics.
  • Added ADR-022 (Redis Distributed Caching and Caffeine Local Fallback Strategy) to docs/adr/.

Added - Phase 8B (Resilience4j Fault Tolerance, Dynamic Rate Limiting & Circuit Breakers)

  • Added resilience4j-spring-boot3 and resilience4j-micrometer (version 2.4.0) dependencies to pom.xml.
  • Created @PerUserRateLimiter custom annotation and PerUserRateLimiterAspect for declarative, principal-partitioned rate limiting with optional fallback handling.
  • Created RateLimiterKeyResolver interface and SecurityContextRateLimiterKeyResolver resolving partition keys by authenticated principal (UPI handle) or remote client IP as fallback.
  • Created UserRateLimiterService managing dynamic per-user Resilience4j RateLimiter instances with automated memory leak eviction (evictInactiveLimiters()) every 15 minutes.
  • Enforced per-user rate limiting (10 req/s) on TransactionService.sendMoney() via @PerUserRateLimiter(name = "transferLimiter").
  • Protected downstream UPI validation in UpiValidationService.executeValidationWithRetry() using Resilience4j @CircuitBreaker(name = "upiValidation", fallbackMethod = "recoverFromValidationFailure").
  • Enhanced GlobalExceptionHandler.java with centralized RFC 7807 / RFC 6585 error handling:
  • RequestNotPermitted -> HTTP 429 Too Many Requests (https://api.payflow.com/errors/rate-limit-exceeded) with Retry-After: 1 header.
  • CallNotPermittedException -> HTTP 503 Service Unavailable (https://api.payflow.com/errors/service-unavailable).
  • Configured externalized Resilience4j settings in application.yml for circuit breaker (COUNT_BASED sliding window 10, min calls 5, 50% threshold, wait duration 5s, ignores InvalidUpiException), rate limiter (10 req/s, 0 timeout), and time limiter (5s timeout).
  • Enabled Actuator health contributors (management.health.circuitbreakers.enabled, management.health.ratelimiters.enabled) and Micrometer/Prometheus metric exports (resilience4j_circuitbreaker_*, resilience4j_ratelimiter_*).
  • Created unit tests RateLimiterTest.java, CircuitBreakerTest.java, PerUserRateLimiterAspectTest.java, and enhanced GlobalExceptionHandlerTest.java and UpiValidationServiceTest.java.
  • Created full-stack integration test ResilienceIT.java on Testcontainers PostgreSQL verifying 10-call rate limit rejection with HTTP 429 and Retry-After: 1, and circuit breaker transitions.
  • Added ADR-021 (Resilience4j Circuit Breaker, Dynamic Per-User Rate Limiting & Timeout Policies) to docs/adr/.

Added - Phase 8A (Structured Logging, Prometheus Metrics & OpenTelemetry Tracing)

  • Added spring-boot-starter-actuator, micrometer-registry-prometheus, micrometer-tracing-bridge-otel, and opentelemetry-exporter-otlp dependencies to pom.xml.
  • Created MetricsConfig.java configuring ObservedAspect for @Observed annotation support and registering custom business meters:
  • payflow.transfers.total (Counter tagged by status: COMPLETED, FAILED, INSUFFICIENT_BALANCE, FORBIDDEN).
  • payflow.transfers.amount (DistributionSummary with p50/p95/p99 SLA percentiles).
  • payflow.transfers.duration (Timer with p50/p95/p99 SLA percentiles).
  • Created RequestLoggingFilter.java logging incoming HTTP requests, status codes, execution duration (ms), and MDC tags (http.status, http.method, http.uri, http.latency_ms).
  • Enhanced RequestIdFilter.java with @Order(Ordered.HIGHEST_PRECEDENCE + 1).
  • Enhanced TransactionService.java with @Observed and recording business metrics on transfer completion and failure.
  • Configured native ECS structured logging (logging.structured.format.console: ecs) in application-prod.yml and console trace pattern with traceId/spanId in application.yml.
  • Configured HikariCP connection pool monitoring (PayflowHikariPool) in application.yml and application-prod.yml.
  • Updated SecurityConfig.java to permit /actuator/prometheus and /actuator/metrics/** endpoints.
  • Created unit tests MetricsConfigTest.java and RequestLoggingFilterTest.java.
  • Created full-stack integration test ObservabilityIT.java against Testcontainers PostgreSQL verifying /actuator/health, /actuator/prometheus, custom metrics, and HikariCP connection metrics.
  • Added ADR-020 (Structured Logging, Prometheus Metrics & OpenTelemetry Observability Architecture) to docs/adr/.

[0.7.0] - 2026-08-28

Added - Phase 7C (RestClient, Declarative HTTP Interface Client & External UPI Validation)

  • Added spring-retry dependency to pom.xml for declarative retry management.
  • Created UpiVerificationResponse.java record representing third-party UPI verification response payloads.
  • Created UpiValidationClient.java declarative HTTP Interface Client interface with @HttpExchange and @GetExchange annotations.
  • Created RestClientConfig.java configuring RestClient, connection/read timeouts, @EnableRetry, and HttpServiceProxyFactory proxy generation.
  • Created InvalidUpiException.java domain exception and mapped to RFC 7807 422 Unprocessable Entity in GlobalExceptionHandler.java.
  • Created UpiValidationService.java implementing @Retryable outbound calls with exponential backoff and randomized jitter (delay = 500ms, multiplier = 2.0, random = true) and @Recover graceful degradation fallback on downstream service outages.
  • Integrated UPI validation into UserService.registerUser() during client onboarding.
  • Created UpiValidationClientTest.java verifying HTTP Interface Client serialization and deserialization via MockRestServiceServer.
  • Created UpiValidationServiceTest.java unit tests verifying validation pass, invalid UPI rejection, retry, and recover fallback.
  • Created UpiValidationIT.java Testcontainers PostgreSQL integration test verifying end-to-end user onboarding with upstream validation and failure handling.
  • Added ADR-019 (Declarative HTTP Interface Client (RestClient) & Resilient External Service Integration) to docs/adr/.

Added - Phase 7B (Authorization & Sender Verification)

  • Created ForbiddenOperationException.java domain exception extending PayflowException.
  • Created SecurityUtils.java static helper to retrieve the authenticated principal's UPI handle from SecurityContextHolder.
  • Created JwtAccessDeniedHandler.java implementing Spring Security's AccessDeniedHandler, emitting standardized RFC 7807 403 Forbidden (application/problem+json) problem details on access denial.
  • Enhanced SecurityConfig.java to register JwtAccessDeniedHandler in the security filter chain.
  • Enhanced GlobalExceptionHandler.java with @ExceptionHandler for ForbiddenOperationException and AccessDeniedException mapping to 403 Forbidden.
  • Enforced strict sender authorization in TransactionService.sendMoney(): rejecting transfer requests when the authenticated subject does not match senderUpiId with 403 Forbidden before acquiring database locks or mutating balances.
  • Enforced multi-party transaction visibility in TransactionService.getTransactionByReferenceId() and getUserTransactions(): ensuring only transaction participants (sender/receiver) or the account owner can view records.
  • Enforced balance ledger privacy in UserService.getUserLedger(): preventing users from inspecting other users' double-entry balance ledger audit entries.
  • Enforced profile ownership in UserController.getUserById() and getUserByUpiId().
  • Created full-stack integration test AuthorizationIT.java against Testcontainers PostgreSQL verifying all 403 Forbidden boundaries and authorized user flows.
  • Added ADR-018 (Principal-Bound Resource Access Control & Sender Verification) to docs/adr/.

Added - Phase 7A (Spring Security & Stateless JWT Authentication)

  • Added spring-boot-starter-security, spring-security-test, and JJWT 0.13.0 (jjwt-api, jjwt-impl, jjwt-jackson) dependencies to pom.xml.
  • Created JwtTokenProvider.java for HMAC-SHA256 (HS256) token generation, signature validation, expiration checking, and user claims extraction (upiId, referenceId, roles).
  • Created JwtAuthenticationFilter.java (OncePerRequestFilter) to parse Bearer tokens from Authorization header and populate SecurityContextHolder.
  • Created JwtAuthenticationEntryPoint.java rendering standardized RFC 7807 401 Unauthorized problem details (application/problem+json) on unauthenticated requests to protected endpoints.
  • Created SecurityConfig.java configuring stateless SecurityFilterChain, CORS policy with configurable origins/methods/headers, CSRF disabled, public route permit rules (POST /api/v1/auth/login, POST /api/v1/users, /swagger-ui/**, /v3/api-docs/**, /actuator/health/**), and protected route authentication requirements (anyRequest().authenticated()).
  • Created AuthController.java with POST /api/v1/auth/login endpoint issuing JWT tokens with 1-hour expiration and user reference metadata.
  • Created DTOs LoginRequest.java and AuthResponse.java.
  • Created unit tests JwtTokenProviderTest.java and AuthControllerTest.java.
  • Created full-stack integration test AuthenticationIT.java against Testcontainers PostgreSQL verifying 401 unauthorized rejection, login token acquisition, and authenticated transaction execution.
  • Added ADR-017 (Stateless JWT Authentication & Spring Security Architecture) to docs/adr/.

[0.6.0] - 2026-08-16

Added - Phase 6B (Spring Modulith Events & Transactional Outbox)

  • Integrated Spring Modulith 2.0 (spring-modulith-starter-jpa, spring-modulith-starter-test, and spring-modulith-bom).
  • Created Flyway migration V6__create_event_publication_registry.sql creating event_publication table with completion and publication date indexes.
  • Created TransferCompletedEvent domain event record containing transaction reference UUID, sender/receiver UPI IDs, amount, status, and post-transfer balances.
  • Updated TransactionService.java to publish TransferCompletedEvent via ApplicationEventPublisher within the @Transactional boundary, achieving transactional outbox persistence to PostgreSQL with zero dual-write vulnerability.
  • Created TransferEventListener.java annotated with @ApplicationModuleListener for asynchronous post-commit event consumption.
  • Created ModulithStructureTest.java verifying architectural boundaries and package encapsulation with ApplicationModules.of(PayflowApiApplication.class).verify().
  • Created OutboxIT.java full-stack integration test verifying atomic event publication to event_publication table against Testcontainers PostgreSQL.
  • Hardened IdempotencyFilter.java with in-flight lease timeout (2 min) for automatic recovery from crashed worker nodes, and catch for DataIntegrityViolationException to gracefully handle concurrent insert collisions as 409 Conflict.
  • Enhanced GlobalExceptionHandler.java with structured error logging (LOG.error) for unhandled server exceptions and data integrity violations.
  • Standardized deterministic alphabetical lock acquisition in TransactionService.java with String.CASE_INSENSITIVE_ORDER.
  • Added ADR-016 (Spring Modulith Event Publication Registry & Transactional Outbox Pattern) to docs/adr/.

Added - Phase 6A (Durable Idempotency Engine)

  • Created IdempotencyFilter.java (OncePerRequestFilter) with CachedBodyHttpServletRequest wrapper to intercept POST /api/v1/transactions, enforcing mandatory Idempotency-Key header with SHA-256 request payload hashing.
  • Added database persistence via idempotency_registry table and IdempotencyRecord entity with lifecycle states (PROCESSING, SUCCESS, FAILED).
  • Created Flyway migration V5__create_idempotency_registry.sql with performance index idx_idemp_created.
  • Implemented cached HTTP response replay: repeated identical requests immediately return cached 201 Created response without triggering backend transfer logic or double-debiting user balances.
  • Implemented validation and conflict handling: rejecting missing Idempotency-Key headers or key reuse with mismatched payloads with 400 Bad Request, and concurrent in-flight requests with 409 Conflict (RFC 7807 problem details).
  • Created IdempotencyCleanupService.java with @Scheduled purge job for removing expired idempotency records past configured TTL (payflow.idempotency.ttl-hours, default 24h).
  • Added unit test suite IdempotencyFilterTest.java and integration test suite IdempotencyIT.java against Testcontainers PostgreSQL.
  • Added ADR-015 (SHA-256 Request Payload Hashing & Durable Database-Backed Idempotency Engine) to docs/adr/.

[0.5.0] - 2026-08-15

Added - Phase 5B (Integration & Concurrency Test Suites)

  • Created TransferLifecycleIT.java full-stack integration test verifying end-to-end user registration, money transfers, updated balances, and double-entry ledger audit verification against Testcontainers PostgreSQL.
  • Created ConcurrentTransferIT.java high-concurrency race condition test with 10 synchronized threads (CountDownLatch), asserting that simultaneous withdrawals from an account with insufficient balance for all result in exactly 1 success, 9 failures, zero double-spending, and balance invariance (balance never goes negative).
  • Created MutualTransferDeadlockIT.java verifying deadlock avoidance under concurrent mutual cross-transfers ($A \rightarrow B$ and $B \rightarrow A$) via deterministic alphabetical lock ordering.
  • Added spring-boot-resttestclient dependency to pom.xml for Spring Boot 4.x TestRestTemplate autoconfiguration.
  • Added structured SLF4J logging across TransactionService and UserService for enhanced transaction lifecycle observability.

Added - Phase 5A (Comprehensive Unit & Slice Test Suite)

  • Created UserServiceTest.java verifying user registration, duplicate UPI prevention, UUID reference lookups, and pagination.
  • Created UserRepositoryTest.java data JPA slice test verifying custom query compilation, UUID lookups, and pessimistic locking (SELECT FOR UPDATE).
  • Created BalanceLedgerRepositoryTest.java data JPA slice test verifying aggregate balance reconciliation JPQL queries (SUM(CREDIT) - SUM(DEBIT)) and paginated audit retrieval.
  • Enhanced UserControllerTest.java and TransactionControllerTest.java WebMvc slice tests verifying HTTP contracts, input validation (422 Unprocessable Entity), RFC 7807 problem details, and paginated ledger endpoints (GET /api/v1/users/{id}/ledger).
  • Added modular test starters spring-boot-starter-data-jpa-test and spring-boot-starter-flyway to pom.xml.

[0.4.0] - 2026-08-11

Added - Phase 4B (Spring Profiles & Testcontainers Integration)

  • Profile-specific YAML configuration structure (application.yml, application-local.yml, application-test.yml, application-prod.yml).
  • Integrated Testcontainers PostgreSQL (org.testcontainers:postgresql) and spring-boot-testcontainers BOM.
  • Abstract base class AbstractIntegrationTest.java with @Testcontainers(disabledWithoutDocker = true) and @DynamicPropertySource for 100% production-parity integration testing.
  • Created PostgreSQLIntegrationTest.java verifying real PostgreSQL container startup, Flyway schema migration execution, and Hibernate ddl-auto=validate verification.
  • Added ADR-014 (Spring Environment Profiles and Testcontainers Integration Testing Strategy) to docs/adr/.

Added - Phase 4A (Flyway Migrations & PostgreSQL Integration)

  • Version-controlled Flyway DDL migration scripts (V1__create_users_table.sql, V2__create_transactions_table.sql, V3__create_balance_ledger_table.sql, V4__add_performance_indexes.sql).
  • Performance indexes added to database schema for UPI lookups (idx_users_upi_id), UUID reference lookups (idx_users_reference_id, idx_tx_reference_id), transaction history statements (idx_tx_sender_created, idx_tx_receiver_created), and balance ledger audits (idx_ledger_user_created).
  • Added PostgreSQL driver (postgresql), flyway-core, and flyway-database-postgresql dependencies.
  • Converted monolithic application.properties configuration to structured application.yml setting spring.jpa.hibernate.ddl-auto=validate.
  • Added ADR-013 (Flyway Database Migrations over DDL Auto-Generation) to docs/adr/.

[0.3.0] - 2026-08-09

Added - Phase 3C (Balance Ledger & Reconciliation)

  • Double-entry balance ledger (balance_ledger table & BalanceLedgerEntry entity) writing atomic DEBIT (sender) and CREDIT (receiver) records on money transfers.
  • Balance audit tracking capturing amount, balanceBefore, and balanceAfter state transitions for complete financial auditability.
  • Balance reconciliation aggregate SQL query calculateReconciledBalanceByUserId() in BalanceLedgerRepository allowing reconstruction of authoritative balance state from ledger rows.
  • GET /api/v1/users/{id}/ledger endpoint returning paginated balance ledger history for a user by UUID reference ID.
  • Added ADR-012 (Double-Entry Balance Ledger as Immutable Audit Trail) to docs/adr/.

Added - Phase 3B (Pessimistic Locking & Deadlock Avoidance)

  • Pessimistic write locking (@Lock(LockModeType.PESSIMISTIC_WRITE)) on UserRepository.findByUpiIdWithLock() generating SELECT ... FOR UPDATE SQL statements to prevent race conditions during high-concurrency balance mutations.
  • Deterministic alphabetical lock acquisition ordering by UPI ID in TransactionService.sendMoney() to prevent database deadlock cycles during concurrent reciprocal transfers.
  • JPA N+1 query optimization via @EntityGraph(attributePaths = {"sender", "receiver"}) on TransactionRepository query methods.
  • Added ADR-010 (Pessimistic Locking for High-Concurrency Balance Operations) and ADR-011 (Deterministic Lock Ordering for Deadlock Prevention) to docs/adr/.

Added - Phase 3A (Money Transfer Implementation)

  • Money transfer orchestration service (TransactionService.sendMoney()) executed under @Transactional(isolation = Isolation.READ_COMMITTED, rollbackFor = Exception.class, timeout = 5).
  • Domain level validation for self-transfer rejection (SelfTransferException), user verification (UserNotFoundException), and balance adequacy (InsufficientBalanceException).
  • GET /api/v1/transactions/{id} endpoint to fetch transaction details by UUID reference ID.
  • GET /api/v1/transactions/user/{upiId} endpoint to retrieve paginated transfer history for a given UPI ID.
  • Comprehensive unit tests (TransactionServiceTest) and mock controller tests (TransactionControllerTest) covering transfer orchestration and transaction queries.

[0.2.0] - 2026-08-06

Added - Phase 2E (Model Refinements & Service Hardening)

  • Added non-enumerable UUID referenceId to User entity to insulate REST APIs from auto-increment primary keys (userId).
  • Added @Transactional(readOnly = true) annotations across all UserService read methods for Hibernate dirty-checking optimization.
  • Consolidated balance check validation directly inside User.debit() throwing InsufficientBalanceException.
  • Enforced transfer upper bound cap (@DecimalMax("1000000.00")) on TransferMoneyRequest.
  • Added MDC %X{requestId} tracking pattern to application console logger.
  • Removed obsolete static fromEntity() factories from response DTO records.
  • Added ADR-007 (UUID Reference IDs over Auto-Increment Primary Keys in APIs) to docs/adr/.

Added - Phase 2D (Error Handling & RFC 7807 Exception Framework)

  • Implemented custom domain exception hierarchy (PayflowException, UserNotFoundException, TransactionNotFoundException, InsufficientBalanceException, DuplicateUpiIdException, SelfTransferException).
  • Implemented global exception handling via @RestControllerAdvice (GlobalExceptionHandler) producing standardized RFC 7807 ProblemDetail responses.
  • Implemented RequestIdFilter (OncePerRequestFilter) for X-Request-Id MDC logging and response header correlation tracking.
  • Updated domain services (UserService, TransactionService) and controllers to throw domain exceptions for clean, centralized handling.
  • Added unit test suites for GlobalExceptionHandlerTest and RequestIdFilterTest.
  • Added ADR-006 (RFC 7807 ProblemDetail & Centralized Exception Handling) to docs/adr/.

Added - Phase 2C (Mapper Layer & API Documentation)

  • Integrated MapStruct 1.6.3 compile-time mappers (UserMapper, TransactionMapper) for type-safe DTO <-> Entity conversions.
  • Integrated Springdoc OpenAPI 3.0.3 (springdoc-openapi-starter-webmvc-ui) for live interactive Swagger UI (/swagger-ui.html) and OpenAPI JSON specs (/v3/api-docs).
  • Added OpenAPI configuration bean (OpenApiConfig) and controller OpenAPI annotations (@Tag, @Operation, @ApiResponse).
  • Added MapStruct mapper unit test suite (UserMapperTest, TransactionMapperTest).
  • Added ADR-005 (MapStruct for compile-time type-safe DTO mapping) to docs/adr/.

Added - Phase 2B (DTO Layer, Input Validation & API Versioning)

  • Versioned REST controllers under /api/v1/users and /api/v1/transactions.
  • Added spring-boot-starter-validation dependency for Jakarta Validation (@Valid, @NotBlank, @Pattern, @DecimalMin, @Size, @Min, @Max).
  • Implemented request DTOs: CreateUserRequest and TransferMoneyRequest with strict validation rules.
  • Implemented response DTO records: UserResponse, TransactionResponse, and generic PagedResponse<T> pagination wrapper.
  • Added controller web slice tests (UserControllerTest, TransactionControllerTest) verifying HTTP status codes and input validation enforcement.
  • Added ADR-004 (URI-based API Versioning and DTO Isolation Layer) to docs/adr/.

Added - Phase 2A (Entity Model Hardening & Rich Domain)

  • Replaced Double primitives with BigDecimal (precision = 19, scale = 4) across User and Transaction entities.
  • Implemented Rich Domain methods (User.debit(), User.credit()) encapsulating balance invariants and state validation.
  • Added audit timestamps (createdAt, updatedAt) and optimistic locking (@Version version) support to User.
  • Added TransactionStatus (INITIATED, COMPLETED, FAILED, REFUNDED) and TransactionType (TRANSFER, REFUND) enums.
  • Added JPA @ManyToOne foreign key relationships between Transaction and User entities with denormalized UPI strings.
  • Added UUID referenceId auto-generation (@PrePersist) on Transaction.
  • Refactored all services (UserService, TransactionService) and controllers (UserController, TransactionController) to use constructor injection.
  • Unit test suite for User domain logic and Transaction reference ID auto-generation (UserTest, TransactionTest).
  • Architectural Decision Records: ADR-001 (BigDecimal), ADR-002 (Constructor injection), ADR-003 (Rich Domain Model).

[0.1.0] - 2026-07-27

Added

  • Baseline Phase 0/1 implementation.
  • Basic User (/users) and Transaction (/transactions) REST endpoints.
  • Spring Data JPA entities (User, Transaction) and repositories.
  • In-memory H2 database persistence for local development builds.
  • Initial Spring Boot 4.1.0 project configuration with Java 25.
  • System Architecture documentation (docs/ARCHITECTURE.md), API Specification (docs/API_SPECIFICATION.md), and Phased Roadmap (docs/ROADMAP.md).
  • Project scaffolding: MIT LICENSE, CHANGELOG.md, .editorconfig.
  • Architectural Decision Records log (docs/adr/) and engineering standards guide (docs/CONVENTIONS.md).
  • Spotless code formatting plugin (com.diffplug.spotless:spotless-maven-plugin) integrated into Maven build.
  • Checkstyle static analysis (checkstyle.xml) plugin (maven-checkstyle-plugin) enforcing coding rules on validate phase.
  • GitHub Actions CI pipeline (.github/workflows/ci.yml) for automated build, linting, formatting, and test execution on Java 25.
  • Repository contribution guidelines and branch protection rules (CONTRIBUTING.md).
  • GitHub status badges in README.md.

Fixed

  • Dockerfile JDK version mismatch: eclipse-temurin:21-jre → eclipse-temurin:25-jre to align with project's java.version.
  • Broken GraalVM native profile in pom.xml: removed invalid dependency declaration with undefined property reference.
  • Removed System.out.println debug statement from UserController.
  • README updated to accurately reflect current project status.