Skip to content

Epic 01 Ledger

Tiana_ edited this page May 30, 2026 · 1 revision

Epic-01: Ledger Foundation

Target release: v0.1.0 Status: Active Use cases: UC-01, UC-02, UC-03, UC-04, UC-05

Goal

Ship a production-grade double-entry ledger service with mathematically enforced invariants. Cover account lifecycle, transaction posting (with reversal), balance retrieval (current + time-travel), entries listing.

Acceptance criteria

  • All 5 use cases (UC-01..UC-05) pass acceptance tests
  • Property test: 1000 random transaction sequences, invariant always holds
  • Concurrency test: 100 concurrent posters, no race condition violation
  • p99 latency: post transaction < 300ms, get balance < 50ms
  • Coverage: > 90% on domain layer
  • OpenAPI spec validated against implementation
  • Helm chart packages successfully
  • docker compose up brings ledger up healthy in < 30s

Features

F-01.1: Domain layer (pure Kotlin)

Tasks (each = GitHub Issue):

  • T-01.1.1: Define Account entity with invariants (~ 4h)
  • T-01.1.2: Define Transaction aggregate with SUM=0 constructor check (~ 4h)
  • T-01.1.3: Define Entry value object (~ 2h)
  • T-01.1.4: Define Money value type (libs/fincore-core) (~ 6h)
  • T-01.1.5: Define Currency value object (~ 2h)
  • T-01.1.6: Define AccountType / AccountStatus / TransactionStatus / EntryDirection enums (~ 1h)
  • T-01.1.7: Domain unit tests + 90% coverage (~ 8h)

F-01.2: Database schema (Liquibase)

  • T-01.2.1: Create ledger schema, base extensions (~ 2h)
  • T-01.2.2: accounts table + indexes (~ 2h)
  • T-01.2.3: transactions table + indexes (~ 2h)
  • T-01.2.4: entries table + indexes (~ 3h)
  • T-01.2.5: verify_double_entry_invariant() function + deferred trigger (~ 4h)
  • T-01.2.6: account_balances materialized view + refresh strategy (~ 4h)
  • T-01.2.7: idempotency_keys table (platform schema) (~ 2h)
  • T-01.2.8: outbox_events table (platform schema) (~ 2h)
  • T-01.2.9: Liquibase changelog tested against fresh + upgrade DB (~ 4h)

F-01.3: Application services (interface + impl)

  • T-01.3.1: AccountService interface + AccountServiceImpl (~ 6h)
  • T-01.3.2: TransactionService interface + TransactionServiceImpl (~ 8h)
  • T-01.3.3: BalanceService (with asOf time-travel) (~ 6h)
  • T-01.3.4: IdempotencyService (HTTP middleware + DB-backed) (~ 8h)
  • T-01.3.5: OutboxEventPublisher (writes outbox in same tx) (~ 4h)
  • T-01.3.6: Unit tests with MockK (~ 12h)

F-01.4: Infrastructure layer

  • T-01.4.1: JPA entities (AccountEntity, TransactionEntity, EntryEntity, OutboxEventEntity, IdempotencyKeyEntity) (~ 8h)
  • T-01.4.2: JPA repositories (AccountRepository, etc.) (~ 4h)
  • T-01.4.3: MapStruct mappers (entity ↔ domain, entity ↔ DTO) (~ 6h)
  • T-01.4.4: KSP setup for MapStruct (~ 2h)

F-01.5: REST API layer

  • T-01.5.1: AccountController (POST, GET, GET balance, GET entries, PATCH) (~ 8h)
  • T-01.5.2: TransactionController (POST, GET, POST reverse) (~ 8h)
  • T-01.5.3: API DTO classes (request, response) (~ 4h)
  • T-01.5.4: Bean Validation annotations (~ 3h)
  • T-01.5.5: Springdoc OpenAPI annotations (~ 4h)
  • T-01.5.6: Generated OpenAPI matches api/openapi.yaml (~ 2h)

F-01.6: Cross-cutting

  • T-01.6.1: IdempotencyFilter (HTTP middleware) (~ 6h)
  • T-01.6.2: CorrelationIdFilter + MDC propagation (~ 3h)
  • T-01.6.3: GlobalExceptionHandler (RFC 7807 problem details) (~ 6h)
  • T-01.6.4: Spring Security config (Keycloak JWT validation) (~ 4h)
  • T-01.6.5: Observability config (Micrometer + OTel + structured logging) (~ 6h)

F-01.7: Tests

  • T-01.7.1: Unit tests (target > 90% coverage on domain) (~ 16h)
  • T-01.7.2: Integration tests via @SpringBootTest + Testcontainers (~ 16h)
  • T-01.7.3: Property tests for invariants (Kotest property) (~ 12h)
  • T-01.7.4: Concurrency test (100 posters) (~ 8h)
  • T-01.7.5: Idempotency concurrency test (~ 6h)
  • T-01.7.6: Race condition test (optimistic lock retry) (~ 4h)

F-01.8: Operational

  • T-01.8.1: Dockerfile (multi-stage, distroless) (~ 4h)
  • T-01.8.2: application.yml + profiles (dev, test, prod) (~ 4h)
  • T-01.8.3: Helm chart deploy/helm/fincore-engine/templates/ledger-* (~ 8h)
  • T-01.8.4: Liveness + readiness probes (~ 2h)
  • T-01.8.5: Graceful shutdown (~ 3h)
  • T-01.8.6: README per-module (services/ledger/README.md) (~ 4h)

Effort estimate

~190 hours (~5 weeks @ 40h/week + buffer)

Dependencies

  • Blocks: E-02 Payments (which uses Ledger), E-03 Event-Bus (uses outbox tables we create), E-06 Sandbox
  • Blocked by: nothing (foundation epic)

Risks

  • R-1: Deferred trigger doesn't fire under all circumstances (e.g., COPY bypass) - mitigated by integration test with deliberate COPY attempt
  • R-2: account_balances MV refresh under concurrent load causes deadlocks - mitigated by CONCURRENTLY refresh
  • R-3: KSP / MapStruct integration breaks with Spring Boot 3.5 - mitigated by working examples in tests, fall back to kapt if blocked

Out of scope (explicit)

  • Multi-tenancy
  • Multi-region replication
  • TigerBeetle adapter (Y1 H2)
  • Soft delete
  • Bulk import APIs

References

Clone this wiki locally