This commit is contained in:
Leonard-ThindPad-P50
2026-09-08 10:26:21 +07:00
commit c81f249920
169 changed files with 38726 additions and 0 deletions

View File

@@ -0,0 +1,133 @@
# ADR-<nnn> — <quyết định, viết ở thể khẳng định>
*Tên file: `adr/ADR-<nnn>_<slug-ngắn>.md` — ví dụ `ADR-007_chon-postgres-thay-mongo.md`*
| | |
|---|---|
| **Status** | `Proposed` / `Accepted` / `Rejected` / `Superseded by ADR-nnn` / `Deprecated` |
| **Date** | YYYY-MM-DD |
| **Người quyết** | *(ai ký — theo `decision-radar.md` §5)* |
| **Người đề xuất** | |
| **Điểm radar** | … /10 *(chấm theo `decision-radar.md` §2)* |
| **Supersedes** | — |
| **Superseded by** | — |
| **Liên quan** | `ASR-nnn` · `QAS-nnn` · `CON-nn` · `ADR-nnn` |
> ⚠️ **ADR bất biến sau khi `Accepted`.** Muốn đổi quyết định thì viết ADR mới có
> `Supersedes: ADR-<nnn>` và đổi trạng thái bản cũ thành `Superseded by`. Không sửa nội dung
> ADR đã Accepted, không xoá ADR đã Rejected.
---
## 1. Bối cảnh
*Tình huống buộc phải quyết. Viết ở **thì hiện tại**, mô tả sự thật đang có — không viết
"chúng tôi sẽ…". Người đọc sau 2 năm phải hiểu được vì sao lúc đó việc này là một vấn đề.*
**Ràng buộc đang chi phối:**
| Nguồn | Nội dung |
|---|---|
| `CON-nn` | |
| `QAS-nnn` | |
| `ASR-nnn` | |
**Cái đã biết chắc / cái còn là giả định:**
| Điều | 🟢 Đã kiểm chứng / 🔴 Giả định | Bằng chứng |
|---|---|---|
| | | POC-nn / bài đo / tài liệu … |
## 2. Phương án đã cân nhắc
*Bắt buộc ≥ 2 phương án (quy tắc `D3`). Một phương án duy nhất không phải quyết định.*
### PA-1 — <tên>
| | |
|---|---|
| **Mô tả** | |
| **Ưu** | |
| **Nhược** | |
| **Chi phí đảo ngược** | *(nếu sau này sai thì sửa mất bao lâu)* |
### PA-2 — <tên>
*(cùng cấu trúc)*
### Bảng so sánh
| Tiêu chí *(sinh từ `QAS`/`CON`)* | PA-1 | PA-2 |
|---|---|---|
| | | |
## 3. Quyết định
> **Chọn PA-…**
*Viết ở thể khẳng định, một câu, đủ cụ thể để kiểm chứng được là có tuân thủ hay không.*
**Vì sao:** *(gắn với `CON-nn` hoặc `QAS-nnn` cụ thể, không phải sở thích)*
**Phạm vi áp dụng:** *(toàn hệ thống / chỉ component nào / chỉ tới khi nào)*
## 4. Phương án bị loại và lý do
| Phương án | Loại vì | Gắn với | Điều kiện nào thì xét lại |
|---|---|---|---|
| PA-… | | `CON-nn` / `QAS-nnn` | |
*"Team quen công nghệ X" là lý do hợp lệ — nhưng phải viết thành `CON-nn` có tên, để sau này
biết quyết định gắn với con người chứ không phải với kỹ thuật.*
## 5. Hệ quả
*Phần quan trọng nhất và bị viết sơ sài nhất. Ghi cả hệ quả tốt lẫn xấu — ADR chỉ có hệ quả
tốt là ADR viết để hợp thức hoá.*
**Hệ quả tích cực**
-
**Hệ quả tiêu cực phải sống chung**
-
**Cái quyết định này khoá lại** *(chi phí đảo ngược sau này)*
| Muốn đổi về sau thì | Tốn |
|---|---|
**Việc phát sinh**
| Việc | Chủ | Hạn | Ghi ở đâu |
|---|---|---|---|
| Cập nhật `SAD` §… | | | |
| Thêm fitness function | | | `FIT-nn` |
| Đào tạo team về … | | | `TCO` §5 |
## 6. Cách kiểm chứng quyết định này được tuân thủ
*Quy tắc `D8`: không verify tự động được thì chỉ là khuyến nghị.*
| Cách kiểm | Công cụ | Chạy ở đâu | `FIT` |
|---|---|---|---|
| | ArchUnit / dependency-cruiser / lint / kiểm thử tải / kiểm tra hạ tầng | CI | `FIT-nn` |
Không kiểm tự động được ⇒ ghi thẳng: `⚠️ Khuyến nghị — không tự kiểm được`, và nêu cách kiểm
thủ công cùng tần suất.
## 7. Điều kiện xét lại
*ADR không vĩnh viễn. Ghi trước dấu hiệu nào thì phải mở lại quyết định này.*
| Dấu hiệu | Ngưỡng | Ai theo dõi |
|---|---|---|
| | *(ví dụ: thông lượng vượt … msg/s, chi phí vượt … /tháng, team vượt … người)* | |
## 8. Tham chiếu
- POC: `ARISK_… §6 POC-nn`
- Bài đo:
- Tài liệu ngoài:
- Thảo luận: *(link biên bản họp, ngày)*

View File

@@ -0,0 +1,153 @@
# DAT — Data Architecture — <PROJECT>
| | |
|---|---|
| **Version** | 1.0 |
| **Date** | YYYY-MM-DD |
| **Author** | <SA> (skill sa-2-architecture) |
| **Status** | 🟡 Draft |
| **Approved by** | Tech Lead: — · DBA: — · DPO/Legal: — |
| **Source** | SAD_… v1.0 · BR_… của BA · schema hiện tại |
| **Scope** | |
| **Confidence** | 🟡 |
## Change Log
| Version | Date | Người sửa | Thay đổi | ADR |
|---|---|---|---|---|
| 1.0 | | | Bản đầu | — |
---
## 1. Nguyên tắc: mỗi thực thể có đúng một chủ
*Quy tắc `D7`. Đồng bộ hai chiều không có chủ là cách sinh ra dữ liệu mâu thuẫn không ai gỡ được.*
| Thực thể | **Hệ thống chủ (SoT)** | Bản sao ở đâu | Cập nhật bằng cơ chế gì | Trễ tối đa cho phép | Lệch quá thì sao |
|---|---|---|---|---|---|
| | | | event / CDC / job / gọi trực tiếp | | cảnh báo `QAS-nnn` |
🔴 Thực thể có **hai** chủ ⇒ chưa quyết xong, không được qua AG2. Chọn một bên; bên kia thành
read model.
## 2. Mô hình dữ liệu mức khái niệm
*Thực thể và quan hệ, chưa phải schema. Schema chi tiết thuộc dev.*
```mermaid
erDiagram
```
| Thực thể | Ý nghĩa nghiệp vụ | Khoá tự nhiên | Ước lượng số bản ghi (năm 1 / năm 3) | Tăng trưởng |
|---|---|---|---|---|
## 3. Chọn công nghệ lưu trữ
| Kho | Loại | Chứa gì | Vì sao loại này | `ADR` |
|---|---|---|---|---|
| | quan hệ / tài liệu / khoá-giá trị / cột / tìm kiếm | | gắn với `QAS-nnn` | |
**Phương án bị loại:** *(quy tắc `D3`)*
| Loại | Loại vì | Xét lại khi |
|---|---|---|
## 4. Consistency
| Nhánh dữ liệu | Mức nhất quán | Trễ tối đa | Vì sao chấp nhận được | Ai chấp nhận | `ADR` |
|---|---|---|---|---|---|
| Số dư ví | Mạnh | 0 | `BR-0nn` không cho phép sai | PO | |
| Báo cáo tổng hợp | Eventual | ≤ 5 phút | Người dùng chấp nhận theo `QAS-nnn` | PO | |
🔴 **"Eventual consistency" không có con số trễ là câu nói suông.** Người dùng và QA cần biết
lệch bao lâu là bình thường, bao lâu là sự cố.
### 4.1 Giao dịch xuyên service
| Luồng nghiệp vụ | Cơ chế | Bù trừ khi lỗi giữa chừng | Ai phát hiện lệch | `ADR` |
|---|---|---|---|---|
| | saga / outbox / 2PC / không có | | job đối soát chạy … | |
**Nếu chọn "không có"** — ghi rõ hệ quả: luồng nào có thể để lại trạng thái nửa vời, ai dọn,
sau bao lâu.
## 5. Phân loại dữ liệu & tuân thủ
| Nhóm dữ liệu | Mức nhạy cảm | Ví dụ trường | Lưu ở đâu | Mã hoá at-rest | Che khi hiển thị | Retention | Cách xoá theo yêu cầu |
|---|---|---|---|---|---|---|---|
| | công khai / nội bộ / **PII** / nhạy cảm | | | | | | |
| Ràng buộc pháp lý | Nguồn | Hệ quả kiến trúc |
|---|---|---|
| Dữ liệu phải nằm trong lãnh thổ … | `CON-05` | Ràng buộc vùng cho mọi dịch vụ lưu trữ, kể cả backup và log |
| Quyền được xoá | | Xoá thật hay ẩn danh hoá? Ảnh hưởng tới báo cáo lịch sử? |
🔴 **Backup và log cũng chứa PII.** Ràng buộc lãnh thổ và retention áp dụng cho cả hai — đây là
chỗ bị bỏ sót nhiều nhất khi kiểm toán.
## 6. Vòng đời & lưu trữ dài hạn
| Thực thể | Dữ liệu nóng | Chuyển sang lạnh sau | Xoá sau | Ai duyệt |
|---|---|---|---|---|
## 7. Hiệu năng dữ liệu
| Truy vấn quan trọng | Tần suất | Khối lượng quét | Chỉ mục cần | `QAS` |
|---|---|---|---|---|
| Vấn đề | Quyết định | `ADR` |
|---|---|---|
| Phân mảnh (sharding/partitioning) | có/không · khoá: … | |
| Đọc/ghi tách nhau | | |
| Cache: cái gì, invalidate thế nào | | |
🔴 **Cache invalidation phải thiết kế cùng lúc với cache.** Cache không có chiến lược làm mới
là nguồn dữ liệu sai mà không ai nghi ngờ.
## 8. Migration dữ liệu legacy
*Bỏ mục này nếu hệ thống hoàn toàn mới — ghi rõ "không áp dụng", đừng để trống.*
| | |
|---|---|
| **Nguồn** | hệ thống · số bản ghi · chất lượng |
| **Cách chuyển** | một lần (big bang) / song song hai hệ thống / cuốn chiếu theo nhóm |
| **Ánh xạ trường** | *(bảng riêng bên dưới)* |
| **Cách đối chiếu sau khi chuyển** | *(truy vấn nào, ngưỡng chênh lệch chấp nhận được là bao nhiêu)* |
| **🔴 Cách rollback** | *(bắt buộc)* |
| **Dữ liệu phát sinh trong lúc chuyển** | *(xử lý thế nào)* |
| **Thời lượng cửa sổ cắt chuyển** | |
**Ánh xạ trường**
| Trường nguồn | Trường đích | Chuyển đổi | Xử lý giá trị thiếu/sai |
|---|---|---|---|
🔴 **Migration không có rollback là migration một chiều.** Phải trả lời được: sau 2 giờ phát
hiện sai thì quay lại thế nào, dữ liệu phát sinh trong 2 giờ đó xử lý ra sao. Chưa trả lời
được ⇒ chặn AG2.
## 9. Sao lưu & khôi phục
| | |
|---|---|
| Tần suất backup | |
| Giữ bao lâu | |
| **Lần khôi phục thử gần nhất** | *(chưa từng thử ⇒ `Confidence` 🔴 + `ARISK`)* |
| Thời gian khôi phục đo được | … *(khớp với RTO ở `INF`)* |
## 10. Giả định & Ngoài phạm vi
**Giả định:**
| ID | Giả định | Cách xác minh | Nếu sai |
|---|---|---|---|
**Ngoài phạm vi:**
-
## 11. Open Questions
| ID | Câu hỏi | Hỏi ai | Từ ngày | Chặn gì | Hệ quả nếu trả lời ngược |
|---|---|---|---|---|---|

View File

@@ -0,0 +1,153 @@
# FAIL — Failure Mode & Resilience Design — <PROJECT>
| | |
|---|---|
| **Version** | 1.0 |
| **Date** | YYYY-MM-DD |
| **Author** | <SA> (skill sa-2-architecture) |
| **Status** | 🟡 Draft |
| **Approved by** | Tech Lead: — · SRE: — · QA: — |
| **Source** | SAD_… v1.0 · ICD_… v1.0 · QAS_… v1.0 |
| **Scope** | |
| **Confidence** | 🟡 |
## Change Log
| Version | Date | Người sửa | Thay đổi | ADR |
|---|---|---|---|---|
| 1.0 | | | Bản đầu | — |
> 🔴 **Đây là phần phân biệt SA giỏi và SA vẽ sơ đồ**, và là phần bị bỏ nhiều nhất. Phần lớn
> sự cố production đến từ những ô còn trống trong tài liệu này.
---
## 1. Bảng phụ thuộc — mọi lời gọi vượt ranh giới process
*HTTP, CSDL, cache, hàng đợi, file, hệ thống ngoài. Không sót cái nào.*
| ID | Phụ thuộc | Từ `CMP` | `IF-nnn` | Timeout | Retry | Idempotent | Hết retry thì sao | Người dùng thấy gì | `QAS` |
|---|---|---|---|---|---|---|---|---|---|
| `FM-01` | CSDL chính | `CMP-01` | — | … ms | 0 | — | trả lỗi 503 | "Hệ thống bận, thử lại sau" | `QAS-002` |
| `FM-02` | API POS ngoài | `CMP-03` | `IF-005` | … ms | 3 · backoff mũ + jitter | ✅ khoá: … | vào hàng đợi, xử lý sau | "Đã ghi nhận, đang xử lý" | `QAS-007` |
🔴 **Retry trên thao tác không idempotent là cách nhân đôi dữ liệu.** Cột "Idempotent" phải
được điền trước cột "Retry", không phải ngược lại.
## 2. Bốn câu hỏi cho mỗi phụ thuộc
*Quy tắc `D6`. Không được bỏ câu nào — đặc biệt câu 1 và câu 4.*
### `FM-01` — <tên phụ thuộc>
| # | Câu hỏi | Trả lời |
|---|---|---|
| 1 | **Nó chậm thì sao?** *(nguy hiểm hơn hỏng: giữ tài nguyên, lan ngược lên tầng trên)* | |
| 2 | **Nó hỏng thì sao?** *(degrade được không, hay chết cả luồng)* | |
| 3 | **Nó trả sai dữ liệu thì sao?** *(có phát hiện được không, bằng gì)* | |
| 4 | **Nó hồi phục thì sao?** *(retry storm, thundering herd, cần backpressure không)* | |
🔴 **Câu 1 là câu bị bỏ nhiều nhất.** Một phụ thuộc hỏng hẳn thì mạch ngắt nhanh; một phụ
thuộc trả lời sau 30 giây sẽ giữ hết connection pool và kéo sập cả hệ thống. Timeout luôn phải
nhỏ hơn nhiều so với timeout của tầng gọi nó.
**Ngân sách timeout theo tầng** *(timeout tầng ngoài phải > tổng timeout tầng trong)*
| Tầng | Timeout | Ghi chú |
|---|---|---|
| Trình duyệt → gateway | … s | |
| Gateway → service | … s | |
| Service → CSDL | … ms | |
| Service → API ngoài | … ms | × số lần retry phải vẫn < timeout tầng trên |
### `FM-02` — <tên phụ thuộc>
*(cùng cấu trúc)*
## 3. Cơ chế chống lan lỗi
*Ba cơ chế quyết định một lần cho toàn hệ thống, ghi thành `ADR`.*
### 3.1 Circuit breaker
| Áp dụng cho | Ngưỡng mở | Thời gian nửa mở | Điều kiện đóng lại | Hành vi khi mở |
|---|---|---|---|---|
| `IF-005` | … % lỗi trong … giây | … s | … lần thành công liên tiếp | trả fallback: … |
### 3.2 Backoff & jitter
| | Quyết định |
|---|---|
| Kiểu backoff | mũ / tuyến tính |
| Có jitter không | **phải có** — không jitter thì mọi client retry cùng lúc |
| Số lần tối đa | |
| Tổng thời gian tối đa | |
### 3.3 Bulkhead (tách pool tài nguyên)
| Nhóm | Pool riêng cho | Kích thước | Vì sao tách |
|---|---|---|---|
| | *(ví dụ: gọi API ngoài dùng pool riêng, để nó cạn không ảnh hưởng luồng nội bộ)* | | |
## 4. Suy giảm có kiểm soát (graceful degradation)
*Khi một phần hỏng, hệ thống làm được gì thay vì chết hẳn.*
| Thành phần hỏng | Chức năng mất | Chức năng vẫn chạy | Người dùng thấy gì | Ai quyết mức degrade |
|---|---|---|---|---|
| Cache | | | | |
| API gợi ý | | | | |
| Hệ thống báo cáo | | | | |
🔴 **Mức degrade là quyết định nghiệp vụ, không phải kỹ thuật.** PO phải chốt: thà hiển thị dữ
liệu cũ 10 phút hay thà báo lỗi? Hai lựa chọn khác nhau ở rủi ro nghiệp vụ, không ở kỹ thuật.
## 5. Kịch bản hỏng toàn hệ thống
| # | Kịch bản | Phát hiện bằng | Sau bao lâu phát hiện | Hệ quả | Cách xử lý | Runbook |
|---|---|---|---|---|---|---|
| 1 | Mất kết nối CSDL chính | | … phút | | | |
| 2 | Hàng đợi đầy | | | | | |
| 3 | Rò rỉ bộ nhớ, service khởi động lại liên tục | | | | | |
| 4 | Hệ thống ngoài trả 200 nhưng dữ liệu sai | | | | | |
| 5 | Tăng tải đột biến ×10 | | | | | |
| 6 | Deploy sai, phải rollback | | | | | `INF` §7 |
## 6. Dữ liệu trong lúc lỗi
| Câu hỏi | Trả lời |
|---|---|
| Giao dịch đang dở khi service chết ⇒ trạng thái nào còn lại | |
| Ai dọn trạng thái nửa vời, sau bao lâu | |
| Message đã nhận nhưng chưa xử lý xong ⇒ mất hay xử lý lại | |
| Poison message (xử lý mãi không được) ⇒ đi đâu | DLQ · giữ … · ai xử lý |
| Có mất dữ liệu nào chấp nhận được không | *(khớp RPO ở `INF` §5)* |
## 7. Diễn tập
*Failure mode chưa diễn tập là giả thuyết. AG3 yêu cầu ít nhất các `FM` mức cao đã được thử.*
| `FM` | Cách diễn tập | Môi trường | Lần gần nhất | Kết quả | Đúng như thiết kế? |
|---|---|---|---|---|---|
| `FM-01` | tắt CSDL replica | stg | | | ☐ |
| `FM-02` | chặn mạng tới API ngoài | stg | | | ☐ |
🔴 Diễn tập hay phát hiện: timeout cấu hình khác tài liệu, retry không có jitter, cảnh báo
không bắn, runbook viết cho hệ thống phiên bản cũ. Đó chính là giá trị của việc diễn tập.
## 8. Giả định & Ngoài phạm vi
**Giả định:**
| ID | Giả định | Cách xác minh | Nếu sai |
|---|---|---|---|
| `ASM-nn` | API ngoài giữ đúng SLA đã cam kết | theo dõi thực tế | |
**Ngoài phạm vi:**
- *(ví dụ: không xử lý trường hợp mất toàn bộ vùng cloud — thuộc DR ở `INF` §5)*
## 9. Open Questions
| ID | Câu hỏi | Hỏi ai | Từ ngày | Chặn gì | Hệ quả nếu trả lời ngược |
|---|---|---|---|---|---|

View File

@@ -0,0 +1,175 @@
# INF — Infrastructure & Deployment Design — <PROJECT>
| | |
|---|---|
| **Version** | 1.0 |
| **Date** | YYYY-MM-DD |
| **Author** | <SA> (skill sa-2-architecture) |
| **Status** | 🟡 Draft |
| **Approved by** | **SRE/Ops: —** · Tech Lead: — |
| **Source** | SAD_… v1.0 · QAS_… v1.0 · TCO_… v1.0 |
| **Scope** | |
| **Confidence** | 🟡 |
## Change Log
| Version | Date | Người sửa | Thay đổi | ADR |
|---|---|---|---|---|
| 1.0 | | | Bản đầu | — |
> 🔴 **Tài liệu này phải khớp số với `TCO`** (quy tắc `D9`). Lệch nhau ⇒ một trong hai sai,
> không có khả năng thứ ba.
---
## 1. Tóm tắt
| | |
|---|---|
| **Cloud / vùng** | · ràng buộc lãnh thổ: `CON-05` |
| **Mô hình chạy** | VM / container / K8s / PaaS / serverless · `ADR-nnn` |
| **Chịu được mất gì** | một node / một AZ / một vùng |
| **RTO / RPO** | … / … · **lần diễn tập gần nhất:** … |
| **Chi phí/tháng ở tải dự kiến** | … *(khớp `TCO` §3)* |
## 2. Môi trường
| Môi trường | Mục đích | Cấu hình so với prod | Dữ liệu | Ai truy cập được |
|---|---|---|---|---|
| dev | | | dữ liệu sinh | |
| stg | **đo `QAS`** | | ẩn danh hoá | |
| prod | | 100% | thật | |
🔴 **Câu hỏi bắt buộc trả lời:** stg khác prod ở chỗ nào, và **chỗ khác đó có làm sai lệch kết
quả đo `QAS` không?** Đo hiệu năng trên máy nhỏ hơn 4 lần rồi kết luận "đạt" là tự lừa mình.
| `QAS` cần đo | Đo được trên stg? | Nếu không, đo ở đâu | Sai số ước tính |
|---|---|---|---|
## 3. Sơ đồ triển khai
```mermaid
flowchart TB
```
**Legend:** *(bắt buộc — ranh giới mạng, ranh giới vùng/AZ, hướng lưu lượng)*
| Thành phần | Loại máy/dịch vụ | Số bản | Vùng/AZ | Tự động scale | Chi phí/tháng |
|---|---|---|---|---|---|
| | | | | ngưỡng: … | |
| **Cộng** | | | | | *(khớp `TCO` §3)* |
## 4. Tính sẵn sàng (HA)
| Thành phần | Chịu được mất | Cơ chế chuyển đổi | Thời gian chuyển | Tự động? | Đã thử chưa |
|---|---|---|---|---|---|
| Ứng dụng | 1 node | LB bỏ node lỗi | … s | ✅ | ☐ |
| CSDL | 1 AZ | failover replica | … s | | ☐ |
**Điểm hỏng đơn (SPOF) còn lại**
| Thành phần | Vì sao chưa dự phòng | Rủi ro | Kế hoạch |
|---|---|---|---|
🔴 Hệ thống nào cũng còn SPOF. Liệt kê ra là chuyên nghiệp; giả vờ không có mới là vấn đề.
## 5. Khôi phục thảm hoạ (DR)
| | |
|---|---|
| **Kịch bản thảm hoạ tính tới** | mất một vùng / hỏng dữ liệu / xoá nhầm / ransomware |
| **RTO mục tiêu** | … *(nguồn: `QAS-nnn`, PO chấp nhận ngày …)* |
| **RPO mục tiêu** | … |
| **Cách khôi phục** | *(các bước, ai làm, tài liệu runbook ở đâu)* |
| **RTO đo được thực tế** | … *(chưa đo ⇒ 🔴)* |
| **Lần diễn tập gần nhất** | … *(chưa từng ⇒ `Confidence` 🔴 + tạo `ARISK`)* |
| **Tần suất diễn tập** | |
🔴 **RTO/RPO chưa diễn tập là RTO/RPO trên giấy.** Con số duy nhất có giá trị là con số đo
được trong một lần diễn tập thật.
## 6. Khả năng mở rộng
| Thành phần | Scale kiểu gì | Ngưỡng kích hoạt | Giới hạn trên | Thời gian scale xong | Nút thắt kế tiếp |
|---|---|---|---|---|---|
| | ngang / dọc | CPU > …% trong … phút | … bản | … s | |
**Nút thắt khi tải × 3** *(kịch bản B của `TCO`)*
| Thứ tự | Thành phần nghẽn trước | Ở mức tải nào | Cách gỡ | Chi phí |
|---|---|---|---|---|
🔴 Scale ngang tầng ứng dụng thường đẩy nút thắt xuống CSDL. Ghi rõ nút thắt kế tiếp — nếu
không, việc scale sẽ tốn tiền mà không cải thiện gì.
## 7. Triển khai
| | Quyết định | `ADR` |
|---|---|---|
| Chiến lược | blue-green / canary / rolling | |
| Thời gian downtime cho phép | *(khớp ngân sách lỗi ở `QAS`)* | |
| **Cách rollback** | · rollback mất bao lâu | |
| Migration schema | tương thích ngược không? triển khai mấy bước? | |
| Cờ tính năng (feature flag) | có/không · nơi quản lý | |
| Ai được bấm deploy prod | | |
🔴 **Migration schema và deploy code phải tương thích ngược với nhau**, nếu không thì rollback
code sẽ gặp schema mới và hỏng. Quy tắc: đổi schema theo hai bước (thêm trước, bỏ sau).
## 8. Quan sát được (Observability)
| Loại | Công cụ | Ghi gì | Giữ bao lâu | Ai đọc | Chi phí/tháng |
|---|---|---|---|---|---|
| Log | | | | | |
| Metric | | | | | |
| Trace | | tỉ lệ lấy mẫu: … | | | |
| **Cộng** | | | | | *(khớp `TCO` §3)* |
**Cảnh báo**
| Cảnh báo | Điều kiện | Mức | Báo cho ai | `QAS` |
|---|---|---|---|---|
| | | trang/ngay · vé/giờ hành chính | | |
🔴 **Cảnh báo không ai xử lý là cảnh báo sẽ bị tắt tiếng.** Mỗi cảnh báo phải có người nhận và
một runbook — không có thì đừng tạo cảnh báo đó.
**Correlation id** — cách truyền xuyên hệ thống: *(khớp `SAD` §9)*
## 9. Vận hành thường ngày
| Việc | Ai làm | Tần suất | Tài liệu |
|---|---|---|---|
| Trực sự cố (on-call) | | | escalation: … |
| Vá bảo mật | | | |
| Kiểm tra backup khôi phục được | | | |
| Rà chi phí | | hàng tháng | |
**Năng lực đội vận hành** *(từ `CON-04`)*: … người · kỹ năng có · **kỹ năng còn thiếu:** …
⇒ chi phí đào tạo ghi ở `TCO` §5.
## 10. Đối chiếu với `TCO`
| Hạng mục | `INF` §3+§8 | `TCO` §3 | Khớp |
|---|---|---|---|
| Compute | | | ☐ |
| CSDL | | | ☐ |
| Observability | | | ☐ |
| Non-prod | | | ☐ |
| **Tổng/tháng** | | | ☐ |
## 11. Giả định & Ngoài phạm vi
**Giả định:**
| ID | Giả định | Cách xác minh | Nếu sai |
|---|---|---|---|
**Ngoài phạm vi:**
- *(ví dụ: không hỗ trợ multi-region active-active; DR dựa trên khôi phục backup, RTO 4 giờ)*
## 12. Open Questions
| ID | Câu hỏi | Hỏi ai | Từ ngày | Chặn gì | Hệ quả nếu trả lời ngược |
|---|---|---|---|---|---|

View File

@@ -0,0 +1,176 @@
# ICD — Integration & Interface Catalog — <PROJECT>
| | |
|---|---|
| **Version** | 1.0 |
| **Date** | YYYY-MM-DD |
| **Author** | <SA> (skill sa-2-architecture) |
| **Status** | 🟡 Draft |
| **Approved by** | Tech Lead: — · BE Lead: — |
| **Source** | SAD_… v1.0 · API_… của BA · tài liệu API của … |
| **Scope** | |
| **Confidence** | 🟡 |
## Change Log
| Version | Date | Người sửa | Thay đổi | ADR |
|---|---|---|---|---|
| 1.0 | | | Bản đầu | — |
> 🔴 **Tài liệu này thắng `API` contract của bộ BA khi hai bên lệch.** BA viết contract đề
> xuất và đánh dấu *"chờ BE xác nhận"* — đây là chỗ xác nhận. Mọi chỗ lệch phải báo lại để BA
> cập nhật SRS.
---
## 1. Ba quy ước chốt một lần cho toàn hệ thống
*Ba chỗ này gây bug nhiều nhất và thường không ai hỏi. Chốt ở đây, ghi thành `ADR`.*
| # | Vấn đề | Quyết định | `ADR` | Vì sao |
|---|---|---|---|---|
| 1 | **Số lớn** (id, số tiền) truyền dạng gì | `string` / `number` | | Vượt `2^53` thì JavaScript làm tròn sai ⇒ id 19 chữ số hỏng **im lặng** |
| 2 | **Thời gian** định dạng gì, múi giờ nào | ISO-8601 UTC / … | | Trộn local time và UTC là bug không ai tìm ra |
| 3 | **Phân trang** kiểu gì | offset (`page`,`size`) / cursor | | Offset không trả `hasNext` ⇒ nút "trang sau" hỏng |
Bổ sung khi áp dụng:
| # | Vấn đề | Quyết định | `ADR` |
|---|---|---|---|
| 4 | Định dạng phản hồi chung | `{ code, message, data }` / … | |
| 5 | Lỗi nghiệp vụ trả HTTP nào | **4xx**, không phải 200 kèm cờ lỗi | |
| 6 | Ngôn ngữ thông điệp lỗi | trả mã (client tự dịch) / trả text theo header | |
| 7 | Khoá idempotency | tên header, cách sinh, giữ bao lâu | |
| 8 | Correlation id | tên header, truyền xuyên suốt thế nào | |
🔴 **Lỗi nghiệp vụ trả 200 kèm cờ lỗi là bug im lặng**: tầng gọi API coi là thành công và giao
diện không hiện lỗi. Chốt 4xx ngay ở đây.
---
## 2. Danh mục interface — `IF-nnn`
*Mọi lời gọi vượt ranh giới container phải có một dòng.*
| ID | Từ | Đến | Giao thức | Sync/Async | **Ai sở hữu contract** | Contract ở đâu | Versioning | Đầu kia hỏng thì sao | `FAIL` |
|---|---|---|---|---|---|---|---|---|---|
| `IF-001` | `CMP-01` | `CMP-03` | HTTP/JSON | sync | team … | `openapi/orders.yaml` | URL path `/v1` | degrade: … | `FM-03` |
| `IF-002` | `CMP-03` | Kafka | AsyncAPI | async | team … | `asyncapi/settlement.yaml` | schema registry, backward | buffer + retry | `FM-05` |
🔴 **Interface không biết ai sở hữu là interface sẽ bị đổi mà không ai báo.** Cột này không
được để trống, kể cả với hệ thống nội bộ.
### 2.1 Interface với hệ thống ngoài
| ID | Hệ thống | Ai liên hệ được | **SLA của họ** | Giới hạn tốc độ | Cơ chế xác thực | Môi trường thử | Đã gọi thử chưa |
|---|---|---|---|---|---|---|---|
| `IF-0nn` | | tên + kênh | uptime … · p95 … | … req/phút | | có/không | ☐ |
🔴 Hệ thống ngoài **không có SLA** ⇒ thiết kế như thể nó có thể hỏng bất cứ lúc nào, và ghi
`ARISK`.
---
## 3. Chi tiết từng interface
### 3.1 `IF-001` — <tên>
| | |
|---|---|
| **Mục đích** | |
| **Từ → Đến** | `CMP-01` → `CMP-03` |
| **Giao thức** | |
| **Đồng bộ?** | sync · timeout … ms |
| **Quyền** | `ROLE-nn` *(map ở `SEC` §3)* |
| **Idempotent** | có/không · khoá: … |
| **Tần suất dự kiến** | … req/s trung bình, … đỉnh · nguồn: `QAS-nnn` |
**Contract**
Nguồn sự thật: `<đường dẫn file OpenAPI/AsyncAPI/proto>` — **không chép nội dung contract vào
đây**, chỉ ghi những điểm cần chú ý:
| Điểm cần chú ý | Quyết định |
|---|---|
| Trường nào là số lớn ⇒ string | |
| Trường nào có thể null và ý nghĩa của null | |
| Enum có mở rộng về sau không ⇒ client xử lý giá trị lạ thế nào | |
**Mã lỗi**
| HTTP | `code` | Khi nào | Client làm gì | Mã lỗi SRS của BA |
|---|---|---|---|---|
| 400 | `INVALID_PARAM` | | hiện lỗi tại field | `E-…-0010` |
| 403 | `FORBIDDEN` | | không xoá dữ liệu đã nhập | `E-…-0403` |
| 409 | | | | |
| 5xx | | | cho thử lại, **giữ nguyên dữ liệu đã nhập** | |
**Chính sách phiên bản**
| | |
|---|---|
| Cách đánh phiên bản | URL path / header / schema registry |
| Thay đổi nào là breaking | *(bỏ trường, đổi kiểu, thêm trường bắt buộc, thu hẹp enum)* |
| Hỗ trợ bản cũ bao lâu | |
| Cách báo trước | |
### 3.2 `IF-002` — <tên>
*(cùng cấu trúc)*
---
## 4. Hợp đồng sự kiện *(nếu có async)*
| Sự kiện | Nhà phát | Người nhận | Schema | Thứ tự có quan trọng | At-least-once? | Trùng thì sao |
|---|---|---|---|---|---|---|
| | | | | | | khoá khử trùng: … |
🔴 **Hầu hết message broker đảm bảo at-least-once, không phải exactly-once.** Mọi người nhận
phải khử trùng được. Ghi rõ khoá khử trùng và cửa sổ thời gian.
| Vấn đề | Quyết định |
|---|---|
| Message hỏng (poison message) xử lý thế nào | DLQ · giữ bao lâu · ai xử lý |
| Đọc lại từ đầu (replay) có được không | |
| Thứ tự đảm bảo trong phạm vi nào | *(partition key là gì)* |
---
## 5. Đối chiếu với `API` của bộ BA
| Endpoint trong `API` của BA | `IF-nnn` | Khớp | Lệch ở đâu | Hành động |
|---|---|---|---|---|
| `GET /api/v1/…` | `IF-001` | ✅ | | |
| `POST /api/v1/…` | `IF-003` | ❌ | BA đề xuất `id: number`, `ICD` chốt `string` | BA cập nhật SRS §… |
Endpoint trong `API` không có `IF-nnn` ⇒ hoặc BA đề xuất một endpoint không tồn tại, hoặc `ICD`
bỏ sót. Phải xử lý, không để treo.
## 6. Hành vi giao diện khi API lỗi
| Tình huống | Giao diện làm gì | `QAS`/`AC` |
|---|---|---|
| 401 hết phiên | Chuyển về đăng nhập, giữ đường dẫn để quay lại | |
| 403 | Hiện thông báo không đủ quyền, **không xoá dữ liệu đã nhập** | |
| 5xx / timeout | Hiện lỗi, cho thử lại, **giữ nguyên dữ liệu đã nhập** | |
| Mạng chậm | Trạng thái đang tải, **khoá nút gửi** để tránh gửi hai lần | |
🔴 Không khoá nút gửi ⇒ người dùng bấm hai lần tạo hai bản ghi. Đây là bug xuất hiện ở gần như
mọi hệ thống không chốt điểm này từ đầu.
## 7. Giả định & Ngoài phạm vi
**Giả định:**
| ID | Giả định | Cách xác minh | Nếu sai |
|---|---|---|---|
**Ngoài phạm vi:**
-
## 8. Open Questions
| ID | Câu hỏi | Hỏi ai | Từ ngày | Chặn gì | Hệ quả nếu trả lời ngược |
|---|---|---|---|---|---|

View File

@@ -0,0 +1,186 @@
# QAS + ASR — Quality Attribute Scenarios & Architecturally Significant Requirements — <PROJECT>
| | |
|---|---|
| **Version** | 1.0 |
| **Date** | YYYY-MM-DD |
| **Author** | <SA> (skill sa-2-architecture) |
| **Status** | 🟡 Draft |
| **Approved by** | Tech Lead: — · QA: — · SRE: — |
| **Source** | CTX_… v1.0 · OPT_… v1.0 · BRIEF §NFR của BA |
| **Scope** | |
| **Confidence** | 🟡 |
## Change Log
| Version | Date | Người sửa | Thay đổi | ADR/DEC |
|---|---|---|---|---|
| 1.0 | | | Bản đầu | — |
> 🔴 **Tài liệu này là nền của cả GĐ2.** Sơ đồ vẽ trước khi có con số ở đây sẽ được bảo vệ
> bằng mọi giá về sau, kể cả khi con số nói nó sai.
---
# PHẦN A — Quality Attribute Scenarios
## A1. Tóm tắt
| Nhóm thuộc tính | Số `QAS` | Must | Đã có cách đo | Đã đo thật |
|---|---|---|---|---|
| Hiệu năng | | | | |
| Thông lượng | | | | |
| Sẵn sàng | | | | |
| Mở rộng | | | | |
| Bảo mật | | | | |
| Bảo trì | | | | |
| Quan sát được | | | | |
**Nhóm không áp dụng:** *(ghi rõ nhóm nào và vì sao — không được bỏ trống)*
## A2. Mẫu một `QAS`
*Sáu phần, thiếu phần nào cũng làm `QAS` không dùng được ở AG3.*
```
QAS-nnn | <tên ngắn> [Must|Should|Could]
Nguồn kích thích : ai/cái gì gây ra
Kích thích : sự kiện gì, với khối lượng bao nhiêu
Môi trường : trạng thái hệ thống lúc đó (bình thường / cao điểm / đang lỗi một phần)
Phản hồi : hệ thống phải làm gì
Đo lường : con số + phân vị + đơn vị
Đo bằng cách nào : tên bài đo · môi trường · bộ dữ liệu · tần suất chạy
Ai đo : vai trò
Nguồn : DRV-nn / CON-nn / BR-nnn / NFR-nn của BA
```
## A3. Danh sách `QAS`
### Hiệu năng
| ID | Tên | Kích thích + môi trường | Đo lường | Đo bằng cách nào | Ai đo | Mức | Nguồn |
|---|---|---|---|---|---|---|---|
| `QAS-001` | | | p95 ≤ … ms | | QA | Must | `DRV-01` |
🔴 Luôn ghi **phân vị**, không ghi trung bình. Trung bình che giấu đuôi, và người dùng khó
chịu nằm ở đuôi.
### Thông lượng
| ID | Tên | Kích thích + môi trường | Đo lường | Đo bằng cách nào | Ai đo | Mức | Nguồn |
|---|---|---|---|---|---|---|---|
🔴 Ghi cả **trung bình và đỉnh**. Đỉnh mới là thứ định hình kiến trúc.
### Sẵn sàng
| ID | Mục tiêu | Ngân sách lỗi | Phạm vi tính | Không tính vào | Đo bằng cách nào | Mức |
|---|---|---|---|---|---|---|
| `QAS-0nn` | 99.9%/tháng | **43 phút/tháng** | API công khai | bảo trì có báo trước ≤ 2h/tháng | uptime check … | Must |
🔴 **Quy % ra phút.** 99.9% và 99.99% nghe giống nhau nhưng chênh 10× về chi phí. Hỏi PO bằng
hệ quả: *"Hệ thống dừng 43 phút vào ngày chốt sổ thì chuyện gì xảy ra?"*
### Mở rộng
| ID | Tải hôm nay | Tải mục tiêu | Trong bao lâu | Scale bằng cách nào | Giới hạn trên | Mức |
|---|---|---|---|---|---|---|
### Bảo mật
| ID | Mối đe doạ | Yêu cầu | Kiểm chứng bằng cách nào | `THR-nn` liên quan | Mức |
|---|---|---|---|---|---|
*Không ghi "bảo mật" như một mục. Mỗi dòng phải nêu một mối đe doạ cụ thể và cách kiểm chứng.*
### Bảo trì
| ID | Kịch bản | Đo lường | Đo bằng cách nào | Mức |
|---|---|---|---|---|
| `QAS-0nn` | Dev mới onboard | Sửa được một bug thật ≤ 3 ngày | Đo trên người thật, lần tuyển gần nhất | Should |
*Không đo được ⇒ bỏ hẳn, đừng ghi định tính. Một `QAS` không đo được làm loãng cả danh sách.*
### Quan sát được
| ID | Kịch bản | Đo lường | Đo bằng cách nào | Mức |
|---|---|---|---|---|
| `QAS-0nn` | Sự cố 5xx tăng đột biến | Cảnh báo trong ≤ 3 phút | Diễn tập inject lỗi trên stg | Must |
*Nhóm này bị quên nhiều nhất, và là nhóm quyết định thời gian khôi phục khi có sự cố thật.*
## A4. `QAS` xung đột nhau
*Thuộc tính chất lượng luôn đánh đổi. Chỗ xung đột phải được nêu và **PO chọn**, không phải SA
âm thầm cân bằng.*
| `QAS` A | `QAS` B | Xung đột ở đâu | Phương án cân bằng | Ai quyết | `ADR` |
|---|---|---|---|---|---|
| QAS-005 độ chính xác tuyệt đối | QAS-001 p95 ≤ 300ms | Kiểm tra đồng bộ làm chậm ghi | | PO | `ADR-nnn` |
---
# PHẦN B — Architecturally Significant Requirements
## B1. Tiêu chí một yêu cầu là `ASR`
Có ≥ 1 điều sau:
- Ép một **cấu trúc** (buộc phải có hàng đợi, cache, service riêng…)
- Ép một **ràng buộc không đảo ngược** (lãnh thổ dữ liệu, vendor, mô hình license)
- Ép một **đánh đổi** (loại bỏ eventual consistency ở một nhánh)
- Có `QAS` mức **Must** đứng sau
Thường 8–15 mục cho một hệ thống trung bình. Danh sách 200 mục nghĩa là chưa lọc.
## B2. Danh sách `ASR`
| ID | Phát biểu | Nguồn | Ép ra cấu trúc gì | `ADR` hiện thực hoá | Trạng thái |
|---|---|---|---|---|---|
| `ASR-001` | Hệ thống phải tiếp tục nhận giao dịch khi POS ngoài mất kết nối ≤ 4 giờ | `DRV-01`, `QAS-007` | Hàng đợi bền + cơ chế phát lại | `ADR-005` | Đã thiết kế |
| `ASR-002` | Dữ liệu cá nhân phải lưu trong lãnh thổ … | `CON-05` (pháp lý) | Ràng buộc vùng cho mọi dịch vụ lưu trữ | `ADR-003` | Đã thiết kế |
**Trạng thái:** Đã ghi nhận · Đã thiết kế (`ADR` tồn tại) · Đã kiểm chứng (có bài đo/`FIT`)
🔴 `ASR` không có `ADR` nào hiện thực hoá ⇒ **chặn AG2**. Đó là yêu cầu định hình kiến trúc mà
không ai quyết định gì về nó.
## B3. Ma trận `ASR` × `CMP`
*Điền sau khi có `SAD`. Ô đánh dấu = component này tồn tại (một phần) vì `ASR` đó.*
| | `CMP-01` | `CMP-02` | `CMP-03` |
|---|---|---|---|
| `ASR-001` | ● | | ● |
| `ASR-002` | | ● | |
Component không phục vụ `ASR` nào ⇒ hỏi lại: nó tồn tại vì lý do gì? Có thể hợp lệ (nhu cầu
chức năng thuần), nhưng phải trả lời được.
---
## C. Đối chiếu với `NFR` của bộ BA
| `NFR` của BA | Nội dung gốc | `QAS` tương ứng | Đã lượng hoá | Hành động |
|---|---|---|---|---|
| `NFR-01` | "màn hình phải nhanh" | `QAS-001` | ✅ | BA cập nhật SRS tham chiếu `QAS-001` |
| `NFR-05` | "dễ bảo trì" | — | ❌ | Đề xuất bỏ hoặc đổi thành `QAS-0nn` đo được |
*`QAS` thắng khi lệch (quy tắc ở `../../sa-lifecycle/references/artifact-map.md` §7). Mọi dòng
lệch phải báo lại cho BA cập nhật SRS.*
## D. Giả định & Ngoài phạm vi
**Giả định:**
| ID | Giả định | Cách xác minh | Nếu sai thì `QAS` nào đổi |
|---|---|---|---|
**Ngoài phạm vi:**
- *(ví dụ: kiến trúc này không nhắm tới tải × 100; ngưỡng phải xét lại là … giao dịch/giờ)*
## E. Open Questions
| ID | Câu hỏi | Hỏi ai | Từ ngày | Chặn gì | Hệ quả nếu trả lời ngược |
|---|---|---|---|---|---|

View File

@@ -0,0 +1,186 @@
# SAD — Solution Architecture Document — <PROJECT>
| | |
|---|---|
| **Version** | 1.0 |
| **Date** | YYYY-MM-DD |
| **Author** | <SA> (skill sa-2-architecture) |
| **Status** | 🟡 Draft |
| **Approved by** | Tech Lead: — · Security: — · SRE: — |
| **Source** | CTX_… v1.0 · OPT_… v1.0 · QAS_… v1.0 |
| **Scope** | |
| **Confidence** | 🟡 |
## Change Log
| Version | Date | Người sửa | Thay đổi | ADR |
|---|---|---|---|---|
| 1.0 | | | Bản đầu | — |
> **Thẩm quyền khi mâu thuẫn:** sơ đồ thắng về **quan hệ và luồng** (ai gọi ai, thứ tự nào);
> bảng/văn bản thắng về **ràng buộc và con số** (timeout, quyền, định dạng, giới hạn).
> Mâu thuẫn ngoài hai loại trên là lỗi tài liệu, phải sửa chứ không phải chọn bên.
---
## 1. Tóm tắt cho người quyết định
*Năm câu. Đọc xong biết hệ thống gồm mấy khối, khối nào rủi ro nhất, quyết định lớn nhất là gì.*
| | |
|---|---|
| **Kiểu kiến trúc** | *(modular monolith / service theo bounded context / event-driven / hybrid)* |
| **Quyết định lớn nhất** | `ADR-nnn` — |
| **Rủi ro kiến trúc lớn nhất** | `ARISK-nn` — |
| **Cái này KHÔNG làm được** | *(giới hạn đã biết trước, ghi ra để không ai kỳ vọng sai)* |
## 2. Kiểu kiến trúc và lý do
Quyết định ở `ADR-001`. Tóm tắt lý do gắn với `ASR` và `CON`:
| Tín hiệu trong dự án này | Nghiêng về | Kết luận |
|---|---|---|
| `CON-04`: … team, ai release độc lập với ai | | |
| `ASR-…`: tải lệch giữa các phần | | |
| `CON-04`: năng lực đội vận hành | | |
🔴 **Modular monolith là mặc định hợp lý** cho ≤ 2 team và ranh giới nghiệp vụ chưa ổn định.
Tách service là quyết định phải *thắng* một lập luận, không phải điểm khởi đầu.
---
## 3. C4 — Mức 1: System Context
*Ai dùng hệ thống, hệ thống nói chuyện với cái gì bên ngoài. Không có chi tiết bên trong.*
```mermaid
flowchart LR
```
**Legend:** ▭ hệ thống của ta · ▱ hệ thống ngoài · ○ người dùng ·
──▶ đồng bộ (ghi giao thức trên mũi tên) · ┄▶ bất đồng bộ
| Thực thể ngoài | Vai trò | Ai sở hữu | Giao thức | SLA của họ | `IF-nnn` |
|---|---|---|---|---|---|
---
## 4. C4 — Mức 2: Container
*Các khối chạy được và triển khai được (ứng dụng, CSDL, hàng đợi, job). Đây là sơ đồ dev dùng
nhiều nhất.*
```mermaid
flowchart TB
```
**Legend:** *(bắt buộc — mũi tên không nhãn giao thức và không phân biệt sync/async là mũi tên
trang trí)*
### 4.1 Bảng container/component — `CMP-nn`
| ID | Tên | Trách nhiệm *(một câu)* | **Cái nó KHÔNG làm** | Dữ liệu sở hữu | Interface vào | Interface ra | Team | `ASR` ép ra |
|---|---|---|---|---|---|---|---|---|
| `CMP-01` | | | | | `IF-001` | `IF-004` | | `ASR-001` |
🔴 **Cột "cái nó KHÔNG làm" là cột ngăn phình chức năng.** Component không có ranh giới viết
ra sẽ nuốt dần mọi thứ trong 6 tháng.
🔴 Component không phục vụ `ASR` nào và không có nhu cầu chức năng rõ ⇒ hỏi lại vì sao nó tồn tại.
### 4.2 Ranh giới thay đổi
*Thay đổi loại nào chỉ chạm một container? Loại nào chạm nhiều? Đây là thước đo chất lượng
của cách phân rã.*
| Loại thay đổi hay xảy ra | Chạm những container nào | Có chấp nhận được không |
|---|---|---|
| Thêm một loại báo cáo | | |
| Thêm một kênh thanh toán | | |
| Đổi quy tắc tính phí | | |
Một loại thay đổi thường xuyên mà chạm ≥ 3 container ⇒ phân rã đang cắt sai chỗ.
---
## 5. C4 — Mức 3: Component *(chỉ cho container phức tạp nhất)*
*Không vẽ mức này cho mọi container. Vẽ cho cái khó nhất, để dev có mẫu.*
```mermaid
flowchart TB
```
---
## 6. Luồng chính
*Sequence diagram cho 2–4 luồng quan trọng nhất. Mỗi luồng ghi rõ: đồng bộ hay bất đồng bộ,
timeout ở đâu, giao dịch bắt đầu và kết thúc ở đâu.*
### 6.1 <tên luồng>
```mermaid
sequenceDiagram
```
| Bước | Thành phần | Đồng bộ? | Timeout | Lỗi thì sao | `FAIL` |
|---|---|---|---|---|---|
---
## 7. Deployment view
*Cái gì chạy ở đâu, mấy bản, ranh giới mạng, ranh giới tin cậy.*
```mermaid
flowchart TB
```
| Thành phần | Môi trường | Số bản | Cấu hình | Vùng/AZ | Ranh giới tin cậy |
|---|---|---|---|---|---|
**Ranh giới tin cậy** — nơi dữ liệu đi từ vùng ít tin cậy sang vùng tin cậy hơn. Mỗi ranh giới
phải có kiểm tra đầu vào; liệt kê ở `SEC`.
---
## 8. Quyết định kiến trúc đã ghi
| `ADR` | Quyết định | Trạng thái | Điểm radar | Có POC |
|---|---|---|---|---|
| `ADR-001` | Kiểu kiến trúc | Accepted | 9 | POC-01 ✅ |
*Sổ đầy đủ: `../00-index/ADL_<PROJECT>.md`*
## 9. Mối quan tâm xuyên suốt
*Những thứ mọi component đều phải làm giống nhau — không thống nhất ở đây thì mỗi dev một kiểu.*
| Mối quan tâm | Quyết định | Ở đâu | `ADR` |
|---|---|---|---|
| Định dạng log & correlation id | | `AGD` | |
| Xử lý lỗi & mã lỗi | | `ICD` | |
| Xác thực & phân quyền | | `SEC` | |
| Cấu hình & secret | | `SEC`, `INF` | |
| Múi giờ & định dạng thời gian | | `ICD` | |
| Số lớn (id/tiền) | | `ICD` | |
| Đa ngôn ngữ | | | |
| Idempotency | | `ICD`, `FAIL` | |
## 10. Giả định & Ngoài phạm vi
**Giả định:**
| ID | Giả định | Cách xác minh | Nếu sai |
|---|---|---|---|
**Ngoài phạm vi** *(quy tắc `D11` — những thứ người đọc có thể tưởng là có)*:
- *(ví dụ: không hỗ trợ đa vùng; DR dựa trên khôi phục từ backup, RTO 4 giờ)*
- *(ví dụ: không nhắm tới tải × 100 — ngưỡng xét lại: … giao dịch/giờ)*
## 11. Open Questions
| ID | Câu hỏi | Hỏi ai | Từ ngày | Chặn gì | Hệ quả nếu trả lời ngược |
|---|---|---|---|---|---|

View File

@@ -0,0 +1,168 @@
# SEC — Security Architecture & Threat Model — <PROJECT>
| | |
|---|---|
| **Version** | 1.0 |
| **Date** | YYYY-MM-DD |
| **Author** | <SA> (skill sa-2-architecture) |
| **Status** | 🟡 Draft |
| **Approved by** | **Security: —** · Tech Lead: — |
| **Source** | SAD_… v1.0 · DAT_… v1.0 · RBAC_… của BA · chính sách bảo mật … |
| **Scope** | |
| **Confidence** | 🟡 |
## Change Log
| Version | Date | Người sửa | Thay đổi | ADR |
|---|---|---|---|---|
| 1.0 | | | Bản đầu | — |
> 🔴 **Security có quyền phủ quyết AG2.** Tài liệu này phải được làm **cùng** người của
> Security, không phải trình cho họ xem lúc cuối. Phát hiện muộn nhất và đau nhất luôn đến từ đây.
---
## 1. Ranh giới tin cậy
*Nơi dữ liệu đi từ vùng ít tin cậy sang vùng tin cậy hơn. Mỗi ranh giới phải có kiểm tra đầu vào.*
```mermaid
flowchart LR
```
| # | Ranh giới | Từ vùng | Sang vùng | Kiểm tra gì tại đây | `CMP` chịu trách nhiệm |
|---|---|---|---|---|---|
| 1 | Internet → hệ thống | không tin cậy | | xác thực, giới hạn tốc độ, kích thước payload, kiểm tra định dạng | |
| 2 | Service → CSDL | | | | |
## 2. Xác thực
| | Quyết định | `ADR` |
|---|---|---|
| **Cơ chế** | session / JWT / OAuth2 + OIDC / mTLS | |
| **Nơi giữ trạng thái** | server-side / stateless token | |
| **Thời hạn access token** | | |
| **Refresh token** | có/không · thời hạn · xoay vòng không | |
| **Cách thu hồi ngay lập tức** | *(bắt buộc trả lời — token stateless thu hồi bằng gì)* | |
| **Đa yếu tố (MFA)** | với vai trò nào | |
| **Nơi ký/xác minh chữ ký** | khoá ở đâu, xoay bao lâu một lần | |
🔴 **JWT stateless không thu hồi được ngay** trừ khi có danh sách chặn. Nhân viên nghỉ việc
lúc 9h mà token còn hiệu lực tới 10h là rủi ro thật — quyết định ở đây, không để dev tự xử lý.
## 3. Phân quyền
| | Quyết định | `ADR` |
|---|---|---|
| **Mô hình** | RBAC / ABAC / kết hợp | |
| **Chỗ ra quyết định** | gateway / từng service / thư viện chung | |
| **Nguồn sự thật của vai trò** | | |
| **Ràng buộc dữ liệu (row-level)** | có/không · cơ chế | |
🔴 **Phân quyền ở gateway không đủ khi có ràng buộc dữ liệu.** "Chỉ xem cửa hàng mình phụ
trách" là điều kiện trên dữ liệu — gateway không biết. Phải quyết ở service, và phải nhất quán.
### 3.1 Map `RBAC` của bộ BA xuống quyền kỹ thuật
| `ROLE-nn` (BA) | Vai trò kỹ thuật | Quyền trên `IF-nnn` | Ràng buộc dữ liệu | Ai gán vai trò này |
|---|---|---|---|---|
| `ROLE-01` | | `IF-001` đọc | 🔶 chỉ cửa hàng phụ trách | |
Mỗi `ROLE-nn` trong `RBAC` của BA phải có đúng một dòng ở đây. Thiếu ⇒ chặn AG2.
### 3.2 Phân tách nhiệm vụ (SoD)
*Cho các hành động phê duyệt / chốt sổ / chuyển tiền.*
| Hành động | Người thực hiện không được đồng thời là | Cơ chế cưỡng chế |
|---|---|---|
## 4. Threat model — STRIDE
*Làm cho mỗi luồng nhạy cảm: đăng nhập, thanh toán, dữ liệu cá nhân, thao tác quản trị, xuất dữ liệu.*
### 4.1 Luồng: <tên>
| ID | Loại (STRIDE) | Mối đe doạ | Thành phần bị nhắm | Mức | Biện pháp | **Cách kiểm chứng biện pháp có hiệu lực** | `FIT`/`QAS` |
|---|---|---|---|---|---|---|---|
| `THR-01` | Spoofing | | | 🔴 | | pentest / kiểm thử tự động / review thủ công định kỳ | |
| `THR-02` | Tampering | | | | | | |
| `THR-03` | Repudiation | | | | audit log ghi … | | |
| `THR-04` | Information disclosure | | | | | | |
| `THR-05` | Denial of service | | | | giới hạn tốc độ … | | |
| `THR-06` | Elevation of privilege | | | | | | |
🔴 **Cột "cách kiểm chứng" không được để trống.** Biện pháp không kiểm chứng được là biện pháp
tồn tại trên giấy — đúng theo quy tắc `D8`.
### 4.2 Mối đe doạ đã chấp nhận
| `THR` | Vì sao chấp nhận | Ai ký · ngày | Dấu hiệu cảnh báo | Kế hoạch nếu xảy ra |
|---|---|---|---|---|
## 5. Bảo vệ dữ liệu
| | Quyết định |
|---|---|
| Mã hoá in-transit | TLS … · nội bộ có mã hoá không |
| Mã hoá at-rest | cấp nào (đĩa / CSDL / trường) · khoá quản lý ở đâu |
| Trường nào mã hoá ở mức trường | *(tham chiếu `DAT` §5)* |
| Che dữ liệu khi hiển thị / khi log | quy tắc cụ thể |
| Dữ liệu ở môi trường non-prod | ẩn danh hoá / dữ liệu sinh / **cấm dùng dữ liệu thật** |
🔴 **Dữ liệu production trên môi trường dev là vi phạm phổ biến nhất và dễ tránh nhất.** Chốt
rõ ở đây và cưỡng chế bằng `FIT`.
## 6. Quản lý secret
| | Quyết định |
|---|---|
| Nơi lưu | |
| Cách ứng dụng lấy | |
| Xoay khoá: tần suất, tự động hay thủ công | |
| **Cấm tuyệt đối** | secret trong mã nguồn, trong biến môi trường ghi vào log, trong ảnh container |
| Cách phát hiện rò rỉ | quét mã nguồn: … · `FIT-nn` |
## 7. Audit log
| Hành động phải ghi | Ghi những trường gì | Ai đọc được | Giữ bao lâu | Chống sửa bằng cách nào |
|---|---|---|---|---|
| Đăng nhập / thất bại | | | | |
| Thay đổi quyền | | | | |
| Truy cập dữ liệu nhạy cảm | | | | |
| Phê duyệt / chốt sổ | | | | |
🔴 **Audit log mà người bị audit sửa được thì không phải audit log.** Ghi rõ cơ chế chống sửa
(append-only, tài khoản riêng, hệ thống tách biệt).
## 8. Tuân thủ
| Yêu cầu | Nguồn | Cách đáp ứng | Bằng chứng cho kiểm toán | Ai xác nhận |
|---|---|---|---|---|
| | GDPR / PCI-DSS / K-ISMS / nội bộ | | | |
## 9. Phụ thuộc & chuỗi cung ứng
| | Quyết định |
|---|---|
| Quét lỗ hổng thư viện | công cụ · tần suất · ngưỡng chặn build |
| Quét ảnh container | |
| Chính sách vá lỗ hổng nghiêm trọng | trong bao lâu |
| Ai duyệt thư viện mới | |
## 10. Giả định & Ngoài phạm vi
**Giả định:**
| ID | Giả định | Cách xác minh | Nếu sai |
|---|---|---|---|
**Ngoài phạm vi:**
- *(ví dụ: không chống được kẻ tấn công có quyền quản trị hạ tầng — rủi ro này do quy trình
nhân sự và kiểm soát truy cập cloud xử lý, không do kiến trúc ứng dụng)*
## 11. Open Questions
| ID | Câu hỏi | Hỏi ai | Từ ngày | Chặn gì | Hệ quả nếu trả lời ngược |
|---|---|---|---|---|---|