Lộ trình xây dựng (Roadmap)
Tài liệu này là nguồn sự thật cho toàn bộ site — mọi trang khác đều bám theo nội dung ở đây. Mục tiêu: xây dựng 2 hệ thống mô phỏng nghiệp vụ ngân hàng lõi bằng Java/Spring, dựa trên tìm hiểu sâu về nghiệp vụ banking và các mẫu thiết kế hệ thống tài chính/phân tán liên quan.
Tổng quan
| Thời gian | 3–6 tháng |
| Cấu trúc | 2 sub-project song song, tách theo domain |
| Nguyên tắc | Đọc tài liệu gốc trước → hiểu bản chất → rồi mới code |
| Đầu ra | 2 repo GitHub + design doc + tài liệu này (public trên VitePress) |
Hai domain trong banking có tư duy thiết kế khác nhau khá rõ, nên được tách thành hai sub-project độc lập thay vì gộp chung:
- Sub-project B — Core Banking: domain "trạng thái" (state-centric). Trọng tâm là tính toàn vẹn dữ liệu, ACID, double-entry ledger.
- Sub-project A — Interbank Payment Gateway: domain "luồng đi" (flow-centric). Trọng tâm là messaging, orchestration, resilience.
Sơ đồ tổng quan
Giai đoạn 1 — Tháng 1–2: Core Banking (Sub-project B)
Bắt đầu từ đây vì đây là domain nền tảng, dễ tiếp cận hơn với người đã có nền Spring Boot/JPA, và lót đường tư duy cho phần Saga phức tạp hơn ở giai đoạn sau.
Đọc trước
- Double-entry bookkeeping — nguyên lý kế toán kép
- Spring Data JPA — query methods, relationships, transaction boundaries
- Transaction management:
@Transactional, isolation levels, propagation
Xây dựng
- Account Service — tạo/tra cứu tài khoản
- Ledger Service — sổ cái double-entry (mỗi giao dịch ghi Nợ/Có cân bằng)
- Transaction Service — xử lý giao dịch nội bộ, đảm bảo tính nhất quán số dư
Học sâu
- ACID và ý nghĩa thực tế trong hệ thống tài chính
- Optimistic vs pessimistic locking — khi nào dùng cái nào
- Audit trail design — vì sao ngân hàng không bao giờ "sửa" bản ghi, chỉ "thêm" bản ghi bù trừ
DDD Refactor — hoàn thành 2026-09-16
Refactor tầng domain của Core Banking theo hướng DDD, thực hiện qua 2 bước liên tiếp trong ngày:
- Money value object — bọc
BigDecimal+Currency,add()/subtract()throwCurrencyMismatchExceptionkhi lệch loại tiền;LedgerEntry/Accountchuyển sang dùngMoney/Currencythay vìBigDecimal/Stringthô, giúpLedgerService.validateBalanced()phát hiện ngay giao dịch trộn lẫn nhiều loại tiền tệ thay vì cộng sai lặng lẽ. - Transaction aggregate root — thêm entity
Transaction(implementsPersistable<UUID>) làm aggregate root cho nhómLedgerEntry, enforce bất biến Nợ=Có ngay tại tầng domain thay vì chỉ ở service; bổ sung migrationV4__create_transactions_table.sqlvà testTransactionTest.
Quyết định thiết kế đầy đủ: ADR-008. Nhật ký chi tiết từng bước: Devlog — Giai đoạn 1.
Outbox Pattern + Kafka Event Publishing — hoàn thành 2026-09-17
Thông báo sự kiện Transaction (mới/hoàn tác) cho các hệ thống khác qua Kafka, không đánh đổi rủi ro Dual Write giữa ghi DB và gửi message:
- Outbox Pattern —
Transactiontự raise domain event,LedgerServicelưu vào bảngoutbox_eventstrong cùng transaction DB với dữ liệu nghiệp vụ; tiến trìnhOutboxEventPublisher(@Scheduled) đọc và gửi lên Kafka sau, đảm bảo tính nguyên tử giữa ghi nghiệp vụ và ghi sự kiện. - Audit/Compliance Consumer — ghi 1 dòng
compliance_recordscho mỗiLedgerEntry, idempotent qua bảngprocessed_events(chống xử lý trùng do Kafka at-least-once delivery). - 3 PoC Consumer — Fraud Detection, Notification, Reporting, mỗi consumer 1
groupIdriêng trên cùng topictransaction-posted-topic, chứng minh kiến trúc publish/subscribe hoạt động cho nhiều hệ thống độc lập.
Quyết định thiết kế đầy đủ: ADR-009. Nhật ký chi tiết từng bước: Devlog — Giai đoạn 1.
Redis Cache cho Account Balance — hoàn thành 2026-09-17
Cache-aside cho AccountService.getBalance(), không đánh đổi invariant chống overdraft đã có ở Pessimistic Locking:
- Cache-aside —
AccountBalanceCache(StringRedisTemplate) cache balance theo account, TTL cấu hình được (mặc định 3600s);withdraw()luôn tính thẳng từ DB quacomputeBalanceFromDb(), không bao giờ đọc cache khi kiểm tra invariant. - Invalidation AFTER_COMMIT —
AccountBalanceCacheEvictionListenerevict cache qua@TransactionalEventListener(phase = AFTER_COMMIT), tái sử dụngTransactionPostedEvent/TransactionReversedEventđã có từ tính năng Kafka, thu hẹp cửa sổ race so với evict trước khi commit.
Quyết định thiết kế đầy đủ: ADR-010. Nhật ký chi tiết từng bước: Devlog — Giai đoạn 1.
Oracle Dual-Profile Support — hoàn thành 2026-09-17
Chứng minh khả năng vận hành trên hạ tầng CSDL doanh nghiệp (Oracle) song song với PostgreSQL, cùng 1 codebase:
- Dual-profile —
db/migration/postgresql/vàdb/migration/oracle/tách riêng hoàn toàn (V1-V7 mỗi bộ), Flywaylocationscấu hình theo Spring Profile (application.properties/application-oracle.properties); Oracle Database Free qua Docker, port 1522. - Viết lại 7 migration theo dialect Oracle — UUID →
RAW(16),UPDATE ... FROM→ correlated subquery /MERGE INTO,JSONB→JSON, partial index → function-based index. - Phát hiện & fix bug Money — chạy test trên Oracle lộ ra
Moneychưa tự chuẩn hóa scale (OracleNUMBERkhông giữ scale cố định như PostgresNUMERIC); cố địnhscale = 2cho mọi currency trongMoney.java. - Kết quả: 45/45 test pass nguyên vẹn trên cả 2 database, không cần sửa test theo profile.
Quyết định thiết kế đầy đủ: ADR-011 (dual-profile), ADR-012 (fix Money scale). Nhật ký chi tiết từng bước: Devlog — Giai đoạn 1.
Kubernetes Deployment — hoàn thành 2026-09-17
Verify Pessimistic Locking (chống overdraft) giữ vững khi nhiều instance ứng dụng chạy song song, qua deployment K8s thật:
- REST Controller — thêm
AccountController(trước đó không có endpoint HTTP nào), bắt buộc phải có để verify locking qua nhiều Pod (nhiều JVM riêng biệt) thay vì gọi thẳng service trong cùng JVM như test hiện có. - Dockerfile + fix Kafka listener — multi-stage build; thêm listener Kafka thứ 2 (
PLAINTEXT_HOST, quahost.docker.internal) vìlocalhostbên trong container không phải máy host. - Deploy K8s —
Namespace/ConfigMap/Secret/Deployment/Service(NodePort) trên Docker Desktop Kubernetes, data layer (Postgres/Oracle/Kafka/Redis) vẫn giữ ở docker-compose ngoài cluster. - Verify thực nghiệm: scale 3 replicas, bắn 5 request
withdrawđồng thời — 1 thành công, 4 bị từ chối HTTP 409, xác nhận quakubectl logsrằng request thực sự phân tán qua cả 3 Pod (không phải do K8s tình cờ route về 1 chỗ).
Quyết định thiết kế đầy đủ: ADR-013. Nhật ký chi tiết từng bước: Devlog — Giai đoạn 1.
Giai đoạn 2 — Tháng 3–4: Interbank Payment Gateway (Sub-project A)
Đọc trước
- ISO 20022 message structure —
pain.001(khởi tạo lệnh chuyển tiền),pacs.008(chuyển tiền liên ngân hàng) - Saga pattern — orchestration vs choreography
- Spring State Machine / Spring Batch docs
Xây dựng
- Message parsing & validation cho pain.001 / pacs.008
- Saga orchestration cho luồng thanh toán liên ngân hàng
- EOD (End-of-Day) batch settlement bằng Spring Batch
- Exception/ops handling — xử lý giao dịch lỗi, retry, dead-letter
Học sâu
- Distributed transaction problem — vì sao 2PC không hợp với hệ thống phân tán quy mô lớn
- Compensating transactions — "hoàn tác" trong hệ phân tán khác gì rollback thông thường
- Idempotency — vì sao một message bị gửi lại 2 lần không được phép tạo ra 2 giao dịch
Giai đoạn 3 — Tháng 5–6: Tích hợp & hoàn thiện
- Kết nối 2 sub-project: Payment Gateway gọi vào Core Banking để cập nhật số dư thực tế
- Bổ sung Spring Security cho API (authentication/authorization)
- Viết test kỹ: unit test + integration test
- Viết README / design doc — giải thích các quyết định kiến trúc
- Tổng hợp lý do đằng sau các quyết định kiến trúc chính: vì sao chọn Saga thay vì 2PC, vì sao thiết kế ledger theo kiểu double-entry, vì sao tách 2 sub-project...
Phương pháp học
- Học trước, code sau: mỗi module chính đều bắt đầu bằng việc đọc tài liệu gốc (Spring docs, ISO 20022 spec), không phải đọc để "biết" mà đọc để hiểu vì sao thiết kế như vậy.
- Ghi chép tay song song: dùng sổ tay chia 2 phần —
- Khái niệm học được: kiến thức tổng quát, có thể tái dùng về sau
- Nhật ký dự án: quyết định kiến trúc, vấn đề gặp phải, cách giải quyết — đây chính là nguyên liệu cho design doc
- Ưu tiên hiểu sâu hơn tốc độ: timeline 3–6 tháng là ước lượng, không phải deadline cứng.
Nhật ký tiến độ
Phần này sẽ được cập nhật theo thời gian khi triển khai từng giai đoạn. Chi tiết theo từng giai đoạn xem tại Devlog.
- [x] Giai đoạn 1: Core Banking
- [ ] Giai đoạn 2: Interbank Payment Gateway
- [ ] Giai đoạn 3: Tích hợp & hoàn thiện