-
Notifications
You must be signed in to change notification settings - Fork 0
Epic 01 Ledger
Tiana_ edited this page May 30, 2026
·
1 revision
Target release: v0.1.0 Status: Active Use cases: UC-01, UC-02, UC-03, UC-04, UC-05
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.
- 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 upbrings ledger up healthy in < 30s
Tasks (each = GitHub Issue):
- T-01.1.1: Define
Accountentity with invariants (~ 4h) - T-01.1.2: Define
Transactionaggregate withSUM=0constructor check (~ 4h) - T-01.1.3: Define
Entryvalue object (~ 2h) - T-01.1.4: Define
Moneyvalue type (libs/fincore-core) (~ 6h) - T-01.1.5: Define
Currencyvalue object (~ 2h) - T-01.1.6: Define
AccountType/AccountStatus/TransactionStatus/EntryDirectionenums (~ 1h) - T-01.1.7: Domain unit tests + 90% coverage (~ 8h)
- T-01.2.1: Create
ledgerschema, base extensions (~ 2h) - T-01.2.2:
accountstable + indexes (~ 2h) - T-01.2.3:
transactionstable + indexes (~ 2h) - T-01.2.4:
entriestable + indexes (~ 3h) - T-01.2.5:
verify_double_entry_invariant()function + deferred trigger (~ 4h) - T-01.2.6:
account_balancesmaterialized view + refresh strategy (~ 4h) - T-01.2.7:
idempotency_keystable (platformschema) (~ 2h) - T-01.2.8:
outbox_eventstable (platformschema) (~ 2h) - T-01.2.9: Liquibase changelog tested against fresh + upgrade DB (~ 4h)
- T-01.3.1:
AccountServiceinterface +AccountServiceImpl(~ 6h) - T-01.3.2:
TransactionServiceinterface +TransactionServiceImpl(~ 8h) - T-01.3.3:
BalanceService(withasOftime-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)
- 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)
- 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)
- 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)
- 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)
- 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)
~190 hours (~5 weeks @ 40h/week + buffer)
- Blocks: E-02 Payments (which uses Ledger), E-03 Event-Bus (uses outbox tables we create), E-06 Sandbox
- Blocked by: nothing (foundation epic)
- 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_balancesMV refresh under concurrent load causes deadlocks - mitigated byCONCURRENTLYrefresh - R-3: KSP / MapStruct integration breaks with Spring Boot 3.5 - mitigated by working examples in tests, fall back to kapt if blocked
- Multi-tenancy
- Multi-region replication
- TigerBeetle adapter (Y1 H2)
- Soft delete
- Bulk import APIs
- Overview
- Services
- Data Model
- Domain Model
- Event Flow
- Security
- Observability
- Resilience
- SLA / SLI / SLO