Kiến Trúc Hệ Thống — GovData: Nền Tảng Quản Lý, Quản Trị Dữ Liệu Thành Phố
Phiên bản: 1.0
Ngày tạo: 2026-04-08
Trạng thái: Draft — Chờ Tech Lead xác nhận
Nguồn: Phương Án Kỹ Thuật, ADRs, Business Understanding, TSD v1.3 (tham khảo)
Mục Lục
- Tổng Quan Kiến Trúc
- Sơ Đồ C4
- Mô Tả Thành Phần
- Luồng Dữ Liệu
- Failure Modes & Phục Hồi
- Kiến Trúc Bảo Mật
- Crosscutting Concerns
- Khả Năng Mở Rộng
- Triển Khai & Vận Hành
- Giám Sát & Observability
- Sao Lưu & Khắc Phục Sự Cố
- Mô Hình Chi Phí
- Sổ Rủi Ro
- Lộ Trình Phát Triển
- Giả Định & Ràng Buộc
- Kết Quả Validation Kiến Trúc
1. Tổng Quan Kiến Trúc
Mô Hình Kiến Trúc
Modular Monolith (ADR-002) — Một đơn vị deploy duy nhất (Spring Boot JAR) chứa các module có ranh giới rõ ràng. Matching Service (Python/FastAPI) là ngoại lệ duy nhất chạy như service riêng biệt.
Lý do:
- Đội 2 Senior Fullstack — cần đơn giản, không quá nhiều service
- On-premise, không có đội Ops riêng — Docker Compose đủ
- Ranh giới module cho phép tách service ở GĐ2 nếu cần
Architecture Drivers (từ Phương Án Kỹ Thuật)
| # |
Driver |
Ưu tiên |
Ảnh hưởng kiến trúc |
| D1 |
Bảo mật & Tuân thủ |
Thiết yếu |
Keycloak dual-mode, RBAC+ABAC, audit 100%, TLS |
| D2 |
Tính chính xác |
Thiết yếu |
Human-in-the-loop, DISPUTED guard, confident score |
| D3 |
Developer Experience |
Cao |
Modular Monolith, Spring Boot, Java 21 Virtual Threads |
| D4 |
Đơn giản vận hành |
Cao |
Docker Compose 2 VM, PostgreSQL thay ES, Redis thay RabbitMQ |
| D5 |
Độ tin cậy |
Cao |
PostgreSQL replication, health checks, retry patterns |
Tổng Hợp Công Nghệ
| Tầng |
Công nghệ |
Phiên bản |
ADR |
| Frontend |
Next.js (App Router) + shadcn/ui + Tailwind CSS 4 |
16.x |
ADR-006 |
| Backend chính |
Java 21 + Spring Boot 4.0.5 (Virtual Threads) |
4.0.5 |
ADR-002 |
| Matching Service |
Python 3.12 + FastAPI |
0.111.x |
ADR-010 |
| Auth Server |
Keycloak 24 (dual-mode) |
24.x |
ADR-001 |
| Database |
PostgreSQL 18.3 (Primary + Replica) |
18.3 |
ADR-004 |
| Cache + Queue |
Redis 8.6.2 |
8.6.2 |
ADR-009 |
| File Storage |
Local filesystem (Docker volume) |
— |
— |
| Reverse Proxy |
NGINX 1.25 |
1.25.x |
— |
| Giám sát |
Prometheus + Grafana + Loki |
latest |
— |
| CI/CD |
Jenkins |
latest |
— |
| Container |
Docker + Docker Compose |
25.x |
ADR-007 |
2. Sơ Đồ C4
2.1 System Context Diagram (Level 1)

Mô tả: Hệ thống GovData là trung tâm — phục vụ 5 loại người dùng. Keycloak xử lý xác thực (dual-mode). SSO IdP là hệ thống bên ngoài tùy thuộc vào hồ sơ pháp lý. Nền tảng phân tích DL là downstream consumer.
2.2 Container Diagram (Level 2)

Mô tả: NGINX là điểm vào duy nhất (port 443). Frontend (Next.js) phục vụ UI. Backend chính (Spring Boot) là Modular Monolith chứa 11 module. Matching Service (Python) chạy riêng biệt, giao tiếp qua REST nội bộ. PostgreSQL có Primary + Replica. Redis phục vụ cache và job queue.
2.3 Component Diagram (Level 3) — Backend Chính

Mô tả: Backend chính gồm 11 module với ranh giới rõ ràng. Mỗi module chỉ expose API qua interface trong package api/. Giao tiếp cross-module qua Spring ApplicationEvents. Module-shared chứa domain models chung và audit logging.
3. Mô Tả Thành Phần
3.1 Frontend (Next.js)
- Mục đích: Cung cấp giao diện web cho tất cả actors
- Công nghệ: Next.js 16 (App Router) + shadcn/ui + Tailwind CSS 4 + TanStack Query
- Trách nhiệm: SSR/SSG, routing, state management, gọi REST API
- Phụ thuộc: Backend chính (REST API), Keycloak (PKCE auth flow)
- Failure Impact: Nếu sập → user không truy cập được UI. Backend API vẫn hoạt động
- Data Owned: Không — chỉ là presentation layer
3.2 Backend Chính (Spring Boot Modular Monolith)
- Mục đích: Xử lý toàn bộ business logic, expose REST API
- Công nghệ: Java 21 (Virtual Threads) + Spring Boot 4.0.5 + Spring Data JPA + Hibernate
- Trách nhiệm: 11 module (xem Level 3 diagram), audit logging, event publishing
- Phụ thuộc: PostgreSQL, Redis, Keycloak, Matching Service
- Failure Impact: Nếu sập → toàn bộ nghiệp vụ dừng. Frontend hiển thị lỗi kết nối
- Data Owned: Toàn bộ business data (metadata, mappings, workflows, audit)
- API Surface:
/api/v1/* — RESTful, JWT auth, pagination, response wrapper
3.3 Matching Service (Python/FastAPI)
- Mục đích: Scoring engine cho AI matching — đối chiếu fields với Anchored Data
- Công nghệ: Python 3.12 + FastAPI + psycopg3
- Trách nhiệm: Rule-based scoring (synonym + trigram + levenshtein), data type compatibility check
- Phụ thuộc: PostgreSQL (read-only Anchored Data)
- Failure Impact: Nếu sập → matching không khả dụng. Các chức năng khác vẫn hoạt động bình thường
- Data Owned: Không — scoring results lưu qua Backend chính
- API Surface:
POST /match — nhận danh sách fields, trả kết quả scored
3.4 Keycloak
- Mục đích: Auth Server tập trung — dual-mode (local + SSO)
- Công nghệ: Keycloak 24 + PostgreSQL riêng
- Trách nhiệm: Xác thực user, phát hành JWT, quản lý realm, Protocol Mappers (org_id, unit_id)
- Phụ thuộc: PostgreSQL (DB riêng cho Keycloak), SSO IdP (khi sẵn sàng)
- Failure Impact: Nếu sập → không đăng nhập được. JWT hiện có vẫn hợp lệ đến khi hết hạn
- Data Owned: User credentials, realm configuration, SSO federation config
3.5 PostgreSQL (Primary + Replica)
- Mục đích: Single source of truth cho toàn bộ business data
- Công nghệ: PostgreSQL 18.3 + streaming replication + pg_trgm + fuzzystrmatch
- Trách nhiệm: Lưu trữ metadata, mappings, audit log, workflow state
- Failure Impact:
- Primary sập → không ghi được. Failover thủ công sang Replica (RTO < 4h)
- Replica sập → báo cáo chậm hơn (fallback sang Primary)
- Data Owned: Toàn bộ persistent data
3.6 Redis
- Mục đích: Cache + job queue
- Công nghệ: Redis 8.6.2
- Trách nhiệm: Session cache, lookup cache (cây tổ chức, Domain tree), matching job queue
- Failure Impact: Nếu sập → cache miss, phản hồi chậm hơn. Fallback DB trực tiếp. Không mất dữ liệu
- Data Owned: Không — chỉ là cache layer
3.7 File Storage (Local Filesystem)
- Mục đích: Lưu trữ file upload (CSV, DDL)
- Công nghệ: Local filesystem, Docker volume mount (
/data/uploads/)
- Trách nhiệm: Lưu file gốc Discovery
- Failure Impact: Nếu disk đầy → không upload file mới. File đã parse vào DB không ảnh hưởng
- Data Owned: File gốc đã upload
4. Luồng Dữ Liệu
4.1 Luồng Xác Thực (Happy Path)

4.2 Luồng Xác Thực (Error Path)

4.3 Luồng Discovery + Matching (Happy Path)

4.4 Luồng Discovery (Error Path)

5. Failure Modes & Phục Hồi
5.1 Phân Tích Failure Mode
| Thành phần |
Loại lỗi |
Ảnh hưởng |
Phát hiện |
Phản ứng |
Thời gian phục hồi |
| PostgreSQL Primary |
Sập node |
Không ghi được |
Health check 5s |
Failover thủ công sang Replica; promote Replica |
< 4 giờ (RTO) |
| PostgreSQL Replica |
Replication lag > 15 phút |
Dữ liệu đọc cũ cho báo cáo |
Prometheus metric |
Alert → DBA kiểm tra |
Tự động khi lag giảm |
| PostgreSQL Replica |
Sập node |
Báo cáo chậm hơn |
Health check 5s |
Route tất cả read sang Primary |
< 1 giờ (restart) |
| Matching Service |
Crash/timeout |
Matching không khả dụng |
Health check + timeout 60s |
Retry 3 lần, Circuit Breaker, queue retry |
< 5 phút (restart) |
| Matching Service |
Scoring sai |
Gợi ý không chính xác |
Human review phát hiện |
100% human review là safety net |
Không downtime |
| Redis |
Sập node |
Cache miss, matching queue mất |
Health check 5s |
Fallback DB trực tiếp; re-enqueue jobs |
< 5 phút (restart) |
| File storage (disk) |
Disk đầy / lỗi I/O |
Upload file thất bại |
Disk monitoring |
Dọn dẹp / mở rộng disk |
< 1 giờ |
| Keycloak |
Sập node |
Không đăng nhập mới |
Health check 5s |
JWT hiện có vẫn hợp lệ; restart Keycloak |
< 15 phút |
| NGINX |
Sập node |
Toàn bộ hệ thống không truy cập |
External monitoring |
Restart NGINX; nếu VM sập → khắc phục VM |
< 30 phút |
| Frontend (Next.js) |
Sập node |
UI không khả dụng |
Health check |
Restart; API vẫn hoạt động |
< 5 phút |
5.2 Resilience Patterns
| Pattern |
Áp dụng cho |
Cấu hình |
| Retry with Backoff |
Matching Service |
Tối đa 3 lần, exponential backoff (2s, 4s, 8s) |
| Circuit Breaker |
Matching Service |
Threshold: 3 failures liên tiếp, timeout 30s, half-open sau 60s |
| Idempotency Guard |
Matching worker |
WHERE suggested_de_id IS NULL — an toàn khi re-trigger |
| Per-item Error Handling |
Parse file, scoring |
Lỗi 1 field → log WARN, tiếp tục field tiếp theo |
| Timeout |
Tất cả external calls |
Matching: 60s; Keycloak: 5s |
| Append-only Audit |
Tất cả write operations |
REVOKE UPDATE, DELETE ON audit_log |
| Streaming Replication |
PostgreSQL Primary → Replica |
Async replication, lag < 15 phút |
| Connection Pool |
PostgreSQL, Redis |
HikariCP max 20 connections; Jedis pool max 10 |
5.3 Chiến Lược Graceful Degradation
| Phụ thuộc sập |
Tính năng ảnh hưởng |
Hành vi degradation |
Ảnh hưởng user |
| Matching Service |
Matching mới |
Queue job, retry sau. Các tính năng khác bình thường |
Trung bình — matching chậm |
| Redis |
Cache, matching queue |
Fallback truy vấn DB trực tiếp; jobs mất cần re-trigger |
Nhẹ — chậm hơn |
| PostgreSQL Replica |
Báo cáo, tra cứu |
Route sang Primary |
Nhẹ — latency tăng nhẹ |
| Disk đầy |
Upload file |
Báo lỗi, dọn dẹp disk |
Nhẹ — upload tạm dừng |
| Keycloak |
Đăng nhập mới |
JWT hiện có vẫn dùng được; đăng nhập mới chờ |
Trung bình — user mới chờ |
6. Kiến Trúc Bảo Mật
6.1 Xác Thực
Keycloak Dual-mode (ADR-001):
| Luồng |
Khi nào dùng |
Chi tiết |
| Local (username/password) |
GĐ0 demo, triển khai sớm, SSO chưa sẵn sàng |
User → Keycloak form → Xác thực local realm → JWT |
| SSO (SAML 2.0) |
Khi hồ sơ pháp lý được phê duyệt |
User → "Đăng nhập SSO" → SAML redirect → IdP xác thực → JWT |
JWT Claims structure:
{
"sub": "user-uuid",
"email": "owner@soyte.gov.vn",
"realm_access": { "roles": ["DATA_OWNER"] },
"org_id": "uuid-so-y-te",
"unit_id": "uuid-phong-nghiep-vu-y",
"exp": 1711234567
}
Custom claims org_id, unit_id được thêm qua Keycloak Protocol Mapper — hoạt động cả hai luồng.
6.2 Phân Quyền — PBAC (Policy-Based Access Control)
Hệ thống sử dụng PBAC — mỗi action được đánh giá bằng policy kết hợp nhiều yếu tố, không chỉ role mà còn data ownership, entity state, và business rules.
4 yếu tố đánh giá quyền:
| Yếu tố |
Loại |
Mô tả |
Ví dụ |
| Role |
RBAC |
Loại action được phép theo vai trò |
Manager được chạy matching; Staff chỉ tra cứu |
| Data Ownership |
ABAC |
Quyền phụ thuộc vào quan hệ sở hữu user ↔ dữ liệu |
Data Owner chỉ xác nhận ô Bảng C thuộc org_id mình |
| Entity State |
State Guard |
Quyền phụ thuộc trạng thái entity |
Approver chỉ phê duyệt Bảng C khi >70% confirmed AND 0 DISPUTED |
| Business Rules |
Policy |
Quy tắc nghiệp vụ đặc thù |
Đề xuất mở rộng chỉ trong Domain đã tồn tại; Admin không tự xóa |
Ví dụ policy phức hợp:
Policy: "Data Owner xác nhận ô Bảng C"
ALLOW IF:
user.role = DATA_OWNER -- Role
AND source_mapping.org_id = user.org_id -- Data Ownership
AND source_mapping.current_state IN -- State Guard
('AI_SUGGESTED', 'AI_HIGH_CONFIDENCE', 'DATABASE')
DENY OTHERWISE → 403
Policy: "Approver phê duyệt Bảng C tổng thể"
ALLOW IF:
user.role = APPROVER -- Role
AND confirmed_orgs_percent > 70% -- Business Rule (aggregate)
AND disputed_count = 0 -- State Guard (aggregate)
DENY OTHERWISE → 422 (precondition failed)
Luồng đánh giá (Defense in Depth — 5 lớp):
Request → [1] JWT Validation → [2] Role Check → [3] Data Ownership Check
↓
[5] Default Deny ← [4] State Guard + Business Rules
| Lớp |
Kiểm tra |
Kết quả khi fail |
| 1. JWT Validation |
Chữ ký + thời hạn JWT |
401 Unauthorized |
| 2. Role Check |
Vai trò có quyền thực hiện loại action này? |
403 Forbidden |
| 3. Data Ownership |
org_id/unit_id user khớp với resource? |
403 Forbidden |
| 4. State Guard + Business Rules |
Entity ở trạng thái cho phép? Điều kiện nghiệp vụ thỏa mãn? |
422 Unprocessable Entity |
| 5. Default Deny |
Không match policy nào |
403 Forbidden |
Implementation: Spring Security (lớp 1-2) + custom PolicyEvaluator ở Service layer (lớp 3-5). Không cần policy engine bên ngoài (OPA) cho GĐ1.
Ma trận vai trò × action (tóm tắt):
| Action |
Manager |
Data Owner |
Approver |
Staff |
Admin |
| CRUD Domain/SubDomain/DE |
✓ |
|
|
|
|
| Upload Discovery |
✓ |
|
|
|
|
| Chạy Matching |
✓ |
|
|
|
|
| Xem Bảng C (toàn bộ) |
✓ |
|
✓ |
|
|
| Xem Bảng C (đơn vị mình) |
|
✓ |
|
|
|
| Xác nhận/từ chối hiện trạng |
|
✓ |
|
|
|
| Đánh dấu DISPUTED |
✓ |
✓ |
|
|
|
| Giải quyết DISPUTED |
|
|
✓ |
|
|
| Phê duyệt Bảng C |
|
|
✓ |
|
|
| Chốt chủ quản (Bảng D) |
|
|
✓ |
|
|
| Ban hành Từ điển |
|
|
✓ |
|
|
| Tra cứu Từ điển |
✓ |
✓ |
|
✓ |
|
| Quản lý user/vai trò |
|
|
|
|
✓ |
| Quản lý cây tổ chức |
|
|
|
|
✓ |
6.3 Bảo Mật Mạng
| Lớp |
Biện pháp |
Chi tiết |
| Edge |
NGINX reverse proxy |
Port 443 duy nhất expose, TLS 1.2+ |
| Mạng |
Segmentation |
VM-App và VM-DB trên private network, không expose ra internet |
| Truyền tải |
TLS |
Tất cả traffic mã hóa TLS 1.2+ |
| Service-to-service |
Private network |
Backend → Matching, Backend → DB qua internal IP |
| Rate limiting |
NGINX |
Giới hạn request/phút cho auth endpoints |
6.4 Bảo Vệ Dữ Liệu
| Loại dữ liệu |
Phân loại |
Mã hóa lưu trữ |
Mã hóa truyền tải |
Kiểm soát truy cập |
| User credentials |
Bí mật |
Keycloak bcrypt hash |
TLS 1.2+ |
Keycloak only |
| Metadata nghiệp vụ |
Nội bộ |
Ổ đĩa mã hóa (OS-level) |
TLS 1.2+ |
RBAC theo vai trò |
| Audit logs |
Tuân thủ |
Append-only, ổ đĩa mã hóa |
TLS 1.2+ |
Read-only cho Admin |
| Discovery credentials |
Tạm thời |
Không lưu — chỉ dùng runtime |
TLS 1.2+ |
Xóa ngay sau sử dụng |
| File upload (CSV/DDL) |
Nội bộ |
Ổ đĩa mã hóa (OS-level) |
TLS 1.2+ |
Manager only |
6.5 Quản Lý Bí Mật
| Loại bí mật |
Lưu trữ |
Xoay vòng |
Truy cập |
| DB credentials |
Docker Secrets (GĐ1) / Vault (GĐ2) |
Thủ công / Tự động |
Environment variable |
| Keycloak admin |
Docker Secrets |
Thủ công |
Environment variable |
| JWT signing key |
Keycloak quản lý |
Tự động (Keycloak) |
Keycloak internal |
| AES key (GĐ2) |
Docker Secrets / Vault |
90 ngày |
/run/secrets/ mount |
| SMTP credentials |
Docker Secrets |
Thủ công |
Environment variable |
6.6 Threat Model (STRIDE)
| Mối đe dọa |
Mô tả |
Xác suất |
Ảnh hưởng |
Biện pháp |
Trạng thái |
| Spoofing |
Giả mạo danh tính |
Trung bình |
Cao |
Keycloak SSO/local auth, JWT validation |
Đã giảm thiểu |
| Tampering |
Chỉnh sửa dữ liệu trái phép |
Thấp |
Cao |
Input validation, audit log bất biến, RBAC |
Đã giảm thiểu |
| Repudiation |
Phủ nhận hành động |
Trung bình |
Trung bình |
Audit log 100% write operations, append-only |
Đã giảm thiểu |
| Information Disclosure |
Rò rỉ dữ liệu |
Trung bình |
Cao |
Org-scoped access, TLS, không lưu credentials |
Đã giảm thiểu |
| Denial of Service |
Quá tải hệ thống |
Thấp |
Cao |
Rate limiting NGINX, connection pool limits |
Giảm thiểu một phần |
| Elevation of Privilege |
Truy cập trái phép |
Thấp |
Thiết yếu |
Least privilege, RBAC+ABAC, Default Deny |
Đã giảm thiểu |
6.7 Checklist Kiểm Soát Bảo Mật
- [x] Tất cả endpoint yêu cầu xác thực (trừ public portal rõ ràng)
- [x] RBAC thực thi ở API level
- [x] Input validation trên mọi user input
- [x] Phòng chống SQL injection (parameterized queries — JPA/Hibernate)
- [x] Phòng chống XSS (output encoding — React tự xử lý)
- [x] CSRF protection (stateless JWT — không cần CSRF token)
- [x] Rate limiting trên auth endpoints (NGINX)
- [x] Bí mật không trong code hay file config (Docker Secrets)
- [x] Audit trail cho mọi data mutation
- [x] Quét lỗ hổng dependency trong CI (Trivy + OWASP ZAP)
- [x] Network segmentation (private subnets cho DB/Cache)
6.8 Kiểm Toán & Tuân Thủ
Audit Log Format:
{
"id": "uuid",
"action": "CONFIRM_SOURCE_MAPPING",
"entity_type": "SOURCE_MAPPING",
"entity_id": "uuid",
"user_id": "uuid",
"org_id": "uuid",
"before": {"current_state": "AI_SUGGESTED"},
"after": {"current_state": "CONFIRMED"},
"ip_address": "192.168.1.50",
"timestamp": "2026-04-08T14:30:00+07:00"
}
- Lưu trữ: Bảng
audit_log trong PostgreSQL
- Bảo vệ:
REVOKE UPDATE, DELETE ON audit_log FROM app_user ở DB level
- Retention: 5 năm (tuân thủ Luật DL 60/2024)
- Ghi: Trong cùng
@Transactional với business operation — đảm bảo consistency
7. Crosscutting Concerns
7.1 Xử Lý Lỗi
| Tầng |
Chiến lược |
Ví dụ |
| API Gateway (NGINX) |
HTTP error codes chuẩn |
502 Bad Gateway khi backend sập |
| Controller |
Validation errors → 400/422 |
Thiếu field bắt buộc → 422 |
| Service Layer |
Domain exceptions → HTTP mapping |
BusinessRuleViolation → 422, NotFoundException → 404 |
| Repository |
DB exceptions → Domain exceptions |
UniqueConstraintViolation → DuplicateEntityError |
| External Calls |
Circuit Breaker + Retry |
Matching Service timeout → retry 3 lần → Circuit Breaker |
| Background Jobs |
Per-item error handling |
Lỗi 1 field → log WARN, tiếp tục field tiếp theo |
API Error Response Format:
{
"success": false,
"error": {
"code": "DISPUTED_NOTE_TOO_SHORT",
"message": "Ghi chú tranh chấp phải ≥ 20 ký tự",
"field": "dispute_note"
},
"timestamp": "2026-04-08T14:30:00+07:00",
"traceId": "abc123"
}
7.2 Logging & Observability
| Khía cạnh |
Công cụ |
Chi tiết |
| Structured Logging |
Logback + JSON format |
Mỗi log entry có traceId, userId, orgId |
| Log Aggregation |
Loki |
Thu thập từ Docker containers, Grafana query |
| Metrics |
Prometheus + Spring Actuator |
Request rate, latency histogram, error rate, JVM metrics |
| Dashboards |
Grafana |
System overview, business metrics, infrastructure |
| Log Levels |
Chuẩn |
ERROR (sự cố), WARN (cần chú ý), INFO (business events), DEBUG (chi tiết kỹ thuật) |
| Retention |
30 ngày (info), 90 ngày (error/warn) |
Loki retention policy |
Correlation ID: Mỗi request nhận traceId duy nhất tại NGINX → propagate qua Backend → Matching Service → response. Giúp trace toàn bộ luồng xử lý.
7.3 Quản Lý Cấu Hình
| Loại cấu hình |
Lưu trữ |
Ví dụ |
| Application config |
Environment variables (Docker Compose) |
DATABASE_URL, REDIS_URL, KEYCLOAK_URL |
| Business rules |
Database (bảng config) |
Matching threshold (0.60), DISPUTED min chars (20) |
| Feature flags |
Database |
Enable/disable email notifications, auto-accept matching |
| Secrets |
Docker Secrets (GĐ1) / Vault (GĐ2) |
DB password, SMTP password, AES key |
7.4 Chiến Lược Kiểm Thử
| Cấp độ |
Mục tiêu |
Công cụ |
Phạm vi |
| Unit Tests |
> 95% |
JUnit 5, Mockito (Java); Pytest (Python) |
Business logic, scoring, parsers |
| Integration Tests |
Luồng chính |
Spring Boot Test + Testcontainers |
API endpoints, DB queries, module interactions |
| Contract Tests |
API contracts |
OpenAPI validation |
Frontend ↔ Backend contract |
| E2E Tests |
Luồng quan trọng |
Playwright |
Đăng nhập, Discovery, Matching, Xác nhận |
| Security Tests |
CI pipeline |
Trivy (container), OWASP ZAP (DAST) |
0 Critical, < 5 High |
| Module Boundary |
100% |
ArchUnit |
Không cross-module internal imports |
| Load Tests |
Peak scenarios |
Gatling |
> 200 req/s, P95 < 2s |
8. Khả Năng Mở Rộng
Chiến Lược Mở Rộng
| Thành phần |
GĐ1 |
GĐ2+ (khi cần) |
| Backend |
1 instance |
2+ instances sau NGINX load balancer |
| Matching Service |
1 instance |
Scale riêng theo matching queue depth |
| PostgreSQL |
Primary + 1 Replica |
Thêm Replica cho báo cáo nặng |
| Redis |
1 instance |
Redis Sentinel cho HA |
| Frontend |
1 instance |
Nhiều instances sau NGINX |
Caching
| Cache Layer |
Dữ liệu |
TTL |
Invalidation |
| Redis — lookup |
Cây tổ chức, Domain tree |
1 giờ |
Event-driven khi CRUD |
| Redis — session |
JWT session metadata |
Theo JWT expiry |
Tự hết hạn |
| Redis — search |
Kết quả search phổ biến |
5 phút |
Time-based |
| PostgreSQL — Materialized View |
Báo cáo tổng hợp |
Refresh hàng giờ |
Scheduled refresh |
Capacity Planning
| Tài nguyên |
GĐ1 |
Peak |
Tốc độ tăng |
Trigger hành động |
| Database |
< 5 GB |
10 GB |
~1 GB/năm |
Scale ổ đĩa khi đạt 70% |
| File storage |
< 10 GB |
50 GB |
Theo số Sở tham gia |
Mở rộng disk VM-App |
| User đồng thời |
200 |
500 |
Theo phase triển khai |
Thêm backend instance khi P95 > 3s |
9. Triển Khai & Vận Hành
9.1 Môi Trường
| Môi trường |
Mục đích |
Hạ tầng |
Dữ liệu |
| Development |
Phát triển tính năng |
Docker Compose local |
Seed data |
| Staging |
Kiểm thử trước production |
VM riêng hoặc chia sẻ |
Dữ liệu ẩn danh từ production |
| Production |
Hệ thống thực |
2 VM (VM-App + VM-DB) |
Dữ liệu thực |
9.2 CI/CD Pipeline

Quality Gates
| Gate |
Kiểm tra |
Hành động khi fail |
| Build |
Compilation, linting |
Block merge |
| Unit Test |
JUnit + Pytest (> 95% coverage) |
Block merge |
| Integration Test |
API + DB tests |
Block merge |
| Security Scan |
Trivy (container) + OWASP ZAP |
Block deploy nếu Critical |
| Module Boundary |
ArchUnit tests |
Block merge |
| Manual QA |
Kiểm thử trên Staging |
Block deploy production |
9.3 Chiến Lược Release
Rolling restart (đơn giản cho Docker Compose):
# Deploy production
docker compose pull
docker compose up -d --no-deps backend # Backend trước
docker compose up -d --no-deps matching # Matching Service
docker compose up -d --no-deps frontend # Frontend cuối
Downtime dự kiến: < 30 giây mỗi service restart. Chấp nhận được cho hệ thống nội bộ.
9.4 Runbooks
| Runbook |
Trigger |
Tóm tắt bước |
| Xử lý sự cố |
Alert Grafana |
Phân loại → Điều tra (xem Loki logs) → Giảm thiểu → Khắc phục → RCA (trong 48h) |
| Rollback |
Deploy lỗi |
docker compose up -d --no-deps {service} với image tag cũ |
| Scale backend |
P95 > 3s kéo dài |
Thêm backend instance, cập nhật NGINX upstream |
| DB Failover |
PostgreSQL Primary sập |
Promote Replica → cập nhật connection string → restart backend |
| DB Restore |
Mất dữ liệu |
Restore từ backup gần nhất → apply WAL → verify data |
| Keycloak Recovery |
Keycloak sập |
Restart container; nếu DB corrupt → restore Keycloak DB |
| Redis Recovery |
Redis sập |
Restart container; cache tự rebuild; re-enqueue matching jobs nếu cần |
9.5 Quy Trình Sự Cố
Alert → Phân loại (5 phút) → Điều tra (15 phút) → Giảm thiểu → Khắc phục → RCA (trong 48h)
| Mức nghiêm trọng |
Ví dụ |
Phản hồi |
| P1 — Thiết yếu |
Hệ thống sập hoàn toàn |
Xử lý ngay, thông báo stakeholders |
| P2 — Cao |
Matching Service sập |
Xử lý trong 1 giờ, các tính năng khác vẫn hoạt động |
| P3 — Trung bình |
Báo cáo chậm |
Xử lý trong ngày làm việc |
| P4 — Thấp |
UI glitch |
Fix trong sprint tiếp theo |
10. Giám Sát & Observability
10.1 SLI/SLO Framework
| Service |
SLI (đo gì) |
SLO (mục tiêu) |
Error Budget |
| NGINX (tổng thể) |
Tỷ lệ request thành công |
99.5% / tháng |
3.65 giờ / tháng |
| Search API |
Latency P95 |
< 2 giây |
N/A |
| Write API |
Latency P95 |
< 500ms |
N/A |
| Matching Worker |
Tỷ lệ job hoàn thành |
99.5% |
3.65 giờ / tháng |
| Matching Worker |
Thời gian mỗi field |
< 500ms |
N/A |
10.2 Dashboards
| Dashboard |
Đối tượng |
Metrics chính |
| Tổng quan hệ thống |
Ops / Tech Lead |
Request rate, error rate, latency P95/P99, uptime |
| Nghiệp vụ |
PM / Approver |
Số DE, sessions Discovery, % Sở đã xác nhận, DISPUTED count |
| Hạ tầng |
Ops |
CPU, RAM, disk, network, DB connections, replication lag |
| Matching |
Tech Lead |
Jobs/giờ, accuracy (manual override rate), avg confidence score |
10.3 Alerting
| Alert |
Điều kiện |
Mức |
Thông báo |
Escalation |
| Error rate cao |
> 5% 5xx trong 5 phút |
P1 |
Grafana → Email |
Tech Lead ngay lập tức |
| Latency cao |
P95 > 3s trong 10 phút |
P2 |
Grafana → Email |
Review trong ngày |
| DB replication lag |
> 15 phút |
P2 |
Grafana → Email |
DBA review |
| DB connection pool |
> 80% utilized |
P3 |
Grafana |
Review trong ngày |
| Matching session quá lâu |
> 60 giây |
P3 |
Loki log WARN |
Review trong ngày |
| Disk space |
> 80% |
P2 |
Grafana → Email |
Dọn dẹp / mở rộng |
| Keycloak sập |
Health check fail 3 lần |
P1 |
Grafana → Email |
Restart ngay |
10.4 Health Checks
| Endpoint |
Kiểm tra |
Tần suất |
Ngưỡng alert |
/actuator/health/liveness |
Backend đang chạy |
10s |
3 lần fail liên tiếp |
/actuator/health/readiness |
Backend sẵn sàng (DB + Redis OK) |
30s |
1 lần fail |
/api/v1/health |
Backend + dependencies |
60s |
2 lần fail liên tiếp |
Matching: /health |
Matching Service đang chạy |
30s |
3 lần fail liên tiếp |
Keycloak: /health |
Auth Server đang chạy |
30s |
1 lần fail |
11. Sao Lưu & Khắc Phục Sự Cố
Chiến Lược Sao Lưu
| Dữ liệu |
Phương pháp |
Tần suất |
Retention |
Lưu trữ |
| PostgreSQL (business DB) |
pg_dump -Fc -Z 6 |
Hàng ngày 01:00 |
30 ngày |
VM-DB /backup/ |
| PostgreSQL (WAL) |
Streaming replication |
Liên tục |
7 ngày |
Replica |
| Keycloak DB |
pg_dump riêng |
Hàng ngày 01:30 |
30 ngày |
VM-DB /backup/ |
| Upload files |
rsync /data/uploads/ |
Hàng ngày 02:00 |
30 ngày |
VM-DB /backup/ |
| Docker Compose config |
Git |
Mỗi thay đổi |
Vĩnh viễn |
Git repo |
Khắc Phục Sự Cố (Disaster Recovery)
| Chỉ số |
Mục tiêu |
Chiến lược |
| RTO (Recovery Time Objective) |
< 4 giờ |
Failover thủ công: promote Replica → cập nhật config → restart |
| RPO (Recovery Point Objective) |
< 15 phút |
WAL streaming replication lag < 15 phút |
Quy Trình DR
1. Phát hiện sự cố (monitoring alert)
2. Đánh giá mức độ: VM-App sập / VM-DB sập / cả hai
3. VM-App sập:
a. Khắc phục VM hoặc provision VM mới
b. Pull Docker images
c. docker compose up -d
d. Verify health checks
4. VM-DB sập:
a. Nếu Replica còn: promote Replica thành Primary
b. Cập nhật connection string trong Docker Compose
c. Restart backend
d. Thiết lập Replica mới từ Primary mới
5. Cả hai sập:
a. Provision VM mới
b. Restore PostgreSQL từ backup gần nhất
c. Restore upload files từ backup
d. Deploy applications
e. Verify toàn bộ health checks
6. Thông báo stakeholders
7. RCA trong 48 giờ
Lịch Diễn Tập
- Hàng tháng: Test restore PostgreSQL từ backup
- Hàng quý: Test DR procedure đầy đủ (simulate VM sập)
12. Mô Hình Chi Phí
| Khoản chi |
Chi tiết |
Ước tính GĐ1 |
Yếu tố scale |
| VM-App |
8 vCPU, 16GB RAM, 100GB SSD |
Phần cứng on-premise |
Thêm VM khi cần |
| VM-DB |
4 vCPU, 32GB RAM, 500GB SSD |
Phần cứng on-premise |
Tăng disk khi cần |
| Software |
Toàn bộ open-source |
$0 |
— |
| Mạng |
Mạng chính phủ hiện có |
$0 |
— |
| Nhân sự |
2 Senior Fullstack |
Chi phí chính |
Thêm người khi scale |
| Bảo trì |
Docker Compose, minimal |
Thấp |
— |
Chiến Lược Tối Ưu Chi Phí
- Open-source toàn bộ — không có license fee
- On-premise — không có cloud monthly cost
- Modular Monolith — 1 backend service, ít container, ít tài nguyên
- PostgreSQL thay Elasticsearch — bớt 1 JVM cluster
- Redis đa năng — cache + queue, bớt RabbitMQ
13. Sổ Rủi Ro
| # |
Rủi ro |
Ảnh hưởng |
Xác suất |
Biện pháp |
Trạng thái |
Chịu TN |
| R1 |
SSO pháp lý bị trễ > 6 tháng |
Thấp |
Rất cao |
Keycloak dual-mode |
Đã giải quyết |
Tech Lead |
| R2 |
AI matching accuracy thấp cho tiếng Việt |
Cao |
Trung bình |
Human review 100% + feedback log |
Chấp nhận |
Tech Lead |
| R3 |
Sở không xác nhận Bảng C đúng hạn |
Cao |
Cao |
Auto-reminder + Approver chốt đơn phương |
Đã giải quyết |
PM |
| R4 |
DISPUTED không giải quyết |
Cao |
Trung bình |
Hard guard + escalation |
Đã giải quyết |
PM |
| R5 |
PostgreSQL Primary sập |
Cao |
Thấp |
Streaming replication + backup hàng ngày |
Đã giảm thiểu |
Ops |
| R6 |
Team 2 người quá tải |
Cao |
Trung bình |
Ưu tiên MVP, defer non-essential |
Theo dõi |
PM |
| R7 |
Full-text search chậm ở quy mô lớn |
Thấp |
Thấp |
GIN indexes đủ < 50K; Elasticsearch option GĐ2 |
Chấp nhận |
Tech Lead |
Technical Debt Log
| # |
Nợ kỹ thuật |
Ảnh hưởng |
Ưu tiên |
Kế hoạch |
Xem lại khi |
| TD1 |
Elasticsearch cho search |
Nếu P95 > 3s |
Thấp |
Thêm ES, sync qua Change Data Capture |
DE > 10K |
| TD2 |
Kubernetes |
Nếu cần auto-scaling |
Thấp |
Migrate Docker Compose → K3s |
> 3 VM |
| TD3 |
Automated HA failover |
RTO hiện tại thủ công < 4h |
Thấp |
PostgreSQL Patroni |
Uptime > 99.9% |
| TD4 |
ML matching models |
Rule-based có thể thiếu chính xác |
Trung bình |
Train trên ai_feedback_log |
Đủ training data |
| TD5 |
Email notifications |
Chưa có, chỉ in-app (backlog) |
Trung bình |
SMTP integration |
GĐ1 nếu kịp |
14. Lộ Trình Phát Triển
Lộ Trình Kiến Trúc
| Phase |
Thay đổi kiến trúc |
Trigger |
| GĐ0 MVP |
Modular Monolith + Matching Service, Keycloak local, Docker Compose |
— |
| GĐ1 Đầy đủ |
+ SSO federation, + báo cáo nâng cao, + DISPUTED workflow |
SSO pháp lý sẵn sàng |
| GĐ1.5 |
+ Read replicas cho báo cáo, + caching nâng cao |
Performance metrics cho thấy cần |
| GĐ2 |
+ LDOP/PostgreSQL Direct Discovery, + ML matching, + Workflow Engine |
Scale requirements |
| GĐ3 |
+ NDOP sync, + Elasticsearch (nếu cần), + K8s (nếu cần) |
> 30 Sở, > 10K DE |
Dễ Thay Đổi
- UI components (shadcn/ui composable)
- Matching scoring algorithm (đóng gói trong Matching Service)
- Query báo cáo và layout dashboard
- Discovery parsers (thêm format mới)
- Caching strategy
Khó Thay Đổi
- PostgreSQL schema (migration cost)
- Keycloak realm configuration (user data migration)
- Modular Monolith → Microservices (refactoring lớn)
- Mã Data Element format (bất biến sau khi tạo)
- Audit log schema (append-only by design)
15. Giả Định & Ràng Buộc
Giả Định Kỹ Thuật
| # |
Giả định |
Ảnh hưởng nếu sai |
| TA1 |
PostgreSQL GIN đủ cho search < 50K records |
Cần Elasticsearch GĐ2 |
| TA2 |
Rule-based scoring đủ chính xác GĐ1 |
Cần ML sớm hơn |
| TA3 |
2 VM đủ cho GĐ1 |
Cần thêm VM |
| TA4 |
Redis Queue đủ cho matching jobs |
Cần RabbitMQ |
| TA5 |
Docker Compose đủ cho vận hành |
Cần K8s |
Ràng Buộc
| # |
Ràng buộc |
Nguồn |
| C1 |
On-premise — không cloud |
Chính sách chính phủ |
| C2 |
Đội 2 Senior Fullstack |
Nguồn lực |
| C3 |
Tuân thủ Luật DL 60/2024, NĐ 13/2023 |
Pháp lý |
| C4 |
Hỗ trợ tiếng Việt đầy đủ |
Nghiệp vụ |
| C5 |
SSO pháp lý có thể chưa sẵn sàng |
Quy trình hành chính |
16. Kết Quả Validation Kiến Trúc
Scenario Walkthrough
Scenario 1: Manager upload CSV và chạy matching
Path: Manager → Frontend → NGINX → Backend (module-discovery) → Local FS → Backend (module-matching) → Redis Queue → Worker → Matching Service → PostgreSQL → Frontend (SSE)
Happy path:
1. Manager upload file CSV → NGINX proxy → Backend parse file → Lưu local FS + DB ✅
2. Manager kích hoạt matching → Enqueue Redis → Worker dequeue ✅
3. Worker gọi Matching Service → Scoring → Trả kết quả ✅
4. Worker lưu results vào DB → SSE thông báo Frontend ✅
Failure scenarios:
- File CSV sai format → Parse fail → Trả lỗi rõ ràng cho user ✅
- Matching Service timeout → Retry 3 lần → Circuit Breaker → Trả lỗi ✅
- Scoring lỗi 1 field → Skip field, tiếp tục field tiếp → Log WARN ✅
Kết quả: ✅ PASS
Scenario 2: Data Owner xác nhận hiện trạng
Path: Data Owner → Frontend → Backend (module-confirm) → PostgreSQL → Audit Log
Happy path:
1. Data Owner đăng nhập → Keycloak JWT → Backend extract org_id ✅
2. GET Bảng C → Filter theo org_id (chỉ thấy đơn vị mình) ✅
3. Xác nhận → UPDATE source_mapping state = CONFIRMED → Audit log ✅
Failure scenarios:
- Data Owner cố xem đơn vị khác → RBAC org_id check → 403 Forbidden ✅
- JWT hết hạn → Refresh token → Retry request ✅
Kết quả: ✅ PASS
Scenario 3: Approver phê duyệt Bảng C
Path: Approver → Frontend → Backend (module-confirm) → PostgreSQL
Happy path:
1. Approver xem tổng hợp → GET Bảng C toàn bộ ✅
2. Phê duyệt → Guard check: > 70% Sở xác nhận VÀ 0 DISPUTED ✅
3. Nếu pass guard → Chốt Bảng C → Audit log ✅
Failure scenarios:
- Còn DISPUTED → Hard guard block → Trả lỗi rõ ràng ✅
- < 70% Sở xác nhận → Hard guard block → Hiển thị % hiện tại ✅
Kết quả: ✅ PASS
Load & Capacity Sanity Check
| Chỉ số |
Mục tiêu |
Hỗ trợ kiến trúc |
Gap |
| User đồng thời peak |
500 |
Spring Boot Virtual Threads + NGINX |
Không |
| Throughput |
> 200 req/s |
Virtual Threads, HikariCP pool 20, Redis cache |
Không |
| Lưu trữ DB (1 năm) |
< 10 GB |
500GB SSD provisioned |
Không |
| Search P95 |
< 2s |
GIN index + pg_trgm + Redis cache |
Không |
| Matching 300 fields |
< 30s |
Batch processing, per-field 500ms |
Không |
Security Review
- [x] Tất cả endpoint yêu cầu xác thực
- [x] RBAC + ABAC thực thi ở API level
- [x] Input validation (JPA/Hibernate parameterized queries)
- [x] Mã hóa truyền tải (TLS 1.2+)
- [x] Mã hóa lưu trữ (OS-level disk encryption)
- [x] Bí mật trong Docker Secrets
- [x] Audit logging cho mọi data mutation
- [x] Rate limiting trên auth endpoints
- [x] Network segmentation (private subnets)
- [x] Quét lỗ hổng trong CI (Trivy + OWASP ZAP)
- [x] Threat model STRIDE hoàn thành
Operational Readiness
- [x] Monitoring dashboards định nghĩa (4 dashboards)
- [x] SLI/SLO targets đặt và đo lường được
- [x] Alerting rules định nghĩa với escalation path
- [x] Health check endpoints thiết kế
- [x] Runbooks có (7 runbooks)
- [x] Chiến lược sao lưu với quy trình restore
- [x] DR plan với RTO/RPO targets
- [x] CI/CD pipeline với quality gates
- [x] Log aggregation và retention policy
Tóm Tắt Validation
| Kiểm tra |
Trạng thái |
Ghi chú |
| Scenario Walkthrough (3 journeys) |
✅ PASS |
Tất cả happy + error paths covered |
| Load & Capacity |
✅ PASS |
Kiến trúc đáp ứng mọi target |
| Security Review |
✅ PASS |
11/11 checks passed |
| Cost Review |
✅ PASS |
Open-source, on-premise, chi phí thấp |
| Operational Readiness |
✅ PASS |
9/9 checks passed |
Hạng Mục Mở Từ Validation
| # |
Hạng mục |
Mức |
Chịu TN |
Kế hoạch |
| V1 |
Automated HA failover chưa có (RTO thủ công) |
Thấp |
Ops |
Chấp nhận GĐ1; xem xét Patroni ở GĐ2 |
| V2 |
Email notification chưa triển khai |
Trung bình |
Dev |
Backlog GĐ1 |
| V3 |
Load test thực tế chưa chạy |
Trung bình |
Dev |
Chạy trước go-live |
Cập nhật lần cuối: 2026-04-08