Banking capstone: từ repository đến production evidence
Một vertical slice chuyển tiền kết nối Java, Spring, JPA, PostgreSQL, security, messaging, observability và AWS Auto Scaling. Mỗi phase có failure gate; không chỉ hoàn thành happy path.
1. Repository và modules
banking-capstone/
transfer-domain/ # Money, AccountId, Transfer state machine
transfer-application/ # use cases, ports, transaction boundaries
transfer-adapters/ # REST, JPA, broker, security
transfer-boot/ # Spring Boot wiring
infrastructure/ # Compose, Terraform, dashboards
runbooks/ # stuck transfer, DB saturation, rollback
Khởi đầu modular monolith để giữ ledger invariant trong một local transaction. Tách service chỉ sau khi có evidence về ownership/scale/release cadence; ports không có nghĩa bắt buộc microservices.
2. PostgreSQL schema và migration
accounts(id, currency, available_balance, version)
transfers(id, idempotency_key, request_hash, status, amount, currency, version)
ledger_entries(id, transfer_id, account_id, direction, amount, created_at)
outbox(id, aggregate_id, event_type, payload, created_at, published_at)
inbox(consumer, event_id, processed_at)
- Flyway/Liquibase migrations; unique idempotency key và unique ledger effect.
- Check amount positive, currency/scale và double-entry sum bằng application transaction + reconciliation evidence.
- Index theo access pattern: account history, transfer status/created time, unpublished Outbox.
- Dùng PostgreSQL Testcontainers; log SQL và chạy
EXPLAIN (ANALYZE, BUFFERS)cho critical queries.
3. JPA/query exercise
- Derived query cho idempotency lookup.
- JPQL projection cho transfer summary.
@Lock(PESSIMISTIC_WRITE)hoặc@Versioncho concurrent debit.@Modifyingconditional transitionPENDING -> POSTED, assert affected rows bằng 1.- Native PostgreSQL query cho reconciliation/reporting; so sánh với JdbcTemplate.
- Chứng minh bulk update làm entity đang managed bị stale và sửa bằng clear/refresh/boundary.
4. Transaction evidence matrix
| Case | Expected evidence |
|---|---|
| Return bình thường | Debit, credit, transfer và Outbox cùng commit. |
| Runtime exception sau debit | Không có partial ledger row. |
| Checked exception | So sánh mặc định với rollbackFor. |
| Catch-and-swallow | Chứng minh commit ngoài ý muốn rồi sửa. |
| Self-invocation | REQUIRES_NEW không chạy; tách bean và retest. |
saveAndFlush() rồi throw | SQL xuất hiện nhưng transaction rollback. |
| Inner rollback-only | Outer nhận UnexpectedRollbackException. |
5. Correct transfer flow
@Transactional
public TransferId transfer(TransferCommand cmd) {
IdempotencyRecord existing = idempotency.find(cmd.key(), cmd.hash());
if (existing != null) return existing.outcome();
AccountPair pair = accounts.lockInStableOrder(cmd.from(), cmd.to());
pair.debitCredit(cmd.money());
Transfer transfer = transfers.post(cmd);
outbox.append(TransferPosted.from(transfer));
return transfer.id();
}
Lock order ổn định tránh deadlock phổ biến; unique constraint là guard cuối cho duplicate. Không dùng floating point, không gửi Kafka/email trong transaction và không trả success trước commit.
6. Security banking
- OAuth2/OIDC; authorization theo ownership account và operation, không chỉ role.
- Step-up authentication/maker-checker cho amount hoặc operation nhạy cảm.
- Idempotency key gắn principal/operation scope; chống replay khác payload.
- Rate/velocity/daily limits, audit immutable, correlation nhưng redact token/PII.
- IAM workload role, Secrets Manager/KMS, private data tier và rotation drill.
- Threat tests: BOLA, duplicate/replay, mass assignment, race vượt balance, log leakage.
7. Messaging và reconciliation
Outbox relay có thể publish duplicate; consumer ghi Inbox/effect atomically. DLQ không phải nơi chôn message: có reason, owner, replay tool và audit. Reconciliation so transfer, ledger, Outbox/Inbox và external reference; repair idempotently hoặc đưa MANUAL_REVIEW.
8. AWS/IaC Auto Scaling lab
ALB -> ECS/Fargate service across 2+ AZ
|-> Aurora/RDS PostgreSQL
|-> SQS transfer-events
CloudWatch alarms -> Application Auto Scaling
Terraform: VPC, SG, IAM, ALB, ECS, RDS parameters, dashboards
- HTTP target tracking theo request/target hoặc concurrency; consumer theo backlog age/messages per task.
- Đặt min/max, warmup, scale-in stabilization, ALB deregistration delay và ECS stop timeout.
- Tính
maxTasks × HikariPool + admin/migration headroom ≤ DB max connections. - Load test burst nhanh hơn startup; so CPU scaling với request/backlog scaling.
- Inject RDS saturation: chứng minh scale-out caller làm tệ hơn, sau đó bound concurrency/retry và shed load.
- Validate Terraform bằng format/validate/plan hoặc static policy; không cần tạo tài nguyên trả phí.
9. Observability và acceptance
SLI: valid transfer đạt terminal correct outcome trong latency target. Dashboard gồm rate/error/p95-p99, active requests, Hikari wait, DB locks/connections, Outbox age, SQS backlog age, reconciliation mismatch và desired/running task count. Trace REST → transaction → Outbox → consumer; deployment marker nối regression với release.
10. Definition of Done
- One-command local build/test với PostgreSQL thật.
- Concurrent test bảo toàn tổng tiền và không balance âm.
- Duplicate/timeout-after-commit không tạo double effect.
- Transaction matrix có raw SQL/state evidence.
- Migration/query plan/index evidence được lưu.
- Authz/replay/log-redaction security tests pass.
- Autoscaling calculation, Terraform validation và load-test report tồn tại.
- Runbook xử lý stuck transfer, DLQ, DB saturation và rollback.