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,163 @@
# API — Contract đề xuất — <US-id>
| | |
|---|---|
| **Version** | 1.0 |
| **Date** | YYYY-MM-DD |
| **Author** | <BA> (skill ba-3-specification) |
| **Status** | 🟡 Draft |
| **Nguồn contract** | ⚠️ **BA đề xuất — chờ BE xác nhận** / ✅ BE cung cấp |
| **Approved by** | BE Lead: — |
| **Source** | SRS_… v1.0 |
| **Scope** | US-0nn |
> 🔴 **Đọc dòng `Nguồn contract` trước.** Contract do BA đề xuất là **giả định**, không phải
> sự thật — dev phải đối chiếu với tài liệu BE trước khi code. Contract do BE cung cấp mới
> là ràng buộc.
---
## 1. Ba điểm phải chốt trước tiên
*Ba chỗ này gây bug nhiều nhất và thường không ai hỏi.*
| # | Vấn đề | Quyết định | Lý do |
|---|---|---|---|
| 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ố bị hỏng |
| 2 | **Thời gian** định dạng gì, múi giờ nào | ISO-8601 UTC / … | |
| 3 | **Phân trang** kiểu gì | offset (`page`,`size`) / cursor | Có trả `total` không? Có `hasNext` không? |
🔴 Điểm 3: nếu API kiểu offset mà **không trả `hasNext`**, giao diện không biết còn trang sau
hay không — nút "Trang sau" sẽ hỏng. Chốt ngay ở đây.
## 2. Quy ước chung
| | |
|---|---|
| **Base URL** | |
| **Xác thực** | |
| **Định dạng phản hồi** | `{ code, message, data }` / … |
| **Mã HTTP dùng** | 200 · 400 · 401 · 403 · 404 · 409 · 500 |
| **Ngôn ngữ thông điệp** | Trả mã lỗi (FE tự dịch) / Trả text đã dịch theo header |
🔴 **Lỗi nghiệp vụ phải trả mã HTTP 4xx, không phải 200 kèm cờ lỗi trong body.** Trả 200
khiến tầng gọi API coi là thành công và giao diện không hiện lỗi — bug im lặng, rất khó phát hiện.
---
## 3. Endpoint
### 3.1 `GET /api/v1/<resource>` — Lấy danh sách
| | |
|---|---|
| **Mục đích** | |
| **Màn hình** | SCR-01 |
| **Quyền** | ROLE-01 (🔶 chỉ cửa hàng phụ trách), ROLE-02, ROLE-04 |
**Query parameters**
| Tên | Kiểu | Bắt buộc | Mặc định | Ràng buộc | Ghi chú |
|---|---|---|---|---|---|
| `keyword` | string | ❌ | — | ≤ 100 ký tự | Tìm theo mã hoặc tên |
| `status` | enum | ❌ | tất cả | `DRAFT`\|`ACTIVE` | |
| `page` | int | ❌ | 0 | ≥ 0 | **0-based hay 1-based?** ← chốt rõ |
| `size` | int | ❌ | 20 | 1–100 | |
| `sort` | string | ❌ | `code,asc` | | |
**Response 200**
```json
{
"code": "SUCCESS",
"message": null,
"data": {
"items": [
{
"id": "1234567890123456789",
"code": "STR-001",
"name": "…",
"status": "ACTIVE",
"createdAt": "2026-08-30T07:05:00Z"
}
],
"page": { "page": 0, "size": 20, "total": 137, "hasNext": true }
}
}
```
**Từng trường**
| Trường | Kiểu | Có thể null | Nguồn | Ghi chú |
|---|---|---|---|---|
| `id` | string | ❌ | | **String vì là số 19 chữ số** |
| `createdAt` | string | ❌ | | ISO-8601, UTC |
**Response lỗi**
| HTTP | `code` | Khi nào | Mã lỗi SRS |
|---|---|---|---|
| 400 | `INVALID_PARAM` | Tham số sai định dạng | `E-STL-0010` |
| 403 | `FORBIDDEN` | Không đủ quyền | `E-STL-0403` |
---
### 3.2 `POST /api/v1/<resource>` — Tạo mới
**Request body**
```json
{ "code": "STR-001", "name": "…", "typeId": "12345" }
```
| Trường | Kiểu | Bắt buộc | Ràng buộc | Field SRS |
|---|---|---|---|---|
| `code` | string | ✅ | 3–20 ký tự, `^[A-Z0-9-]+$` | F01 |
🔴 **Ràng buộc ở API phải khớp với bảng field trong SRS.** Lệch nhau ⇒ giao diện chặn một
kiểu, backend chặn kiểu khác, người dùng gặp lỗi khó hiểu.
**Response 200 / lỗi**
| HTTP | `code` | Khi nào | Mã lỗi SRS |
|---|---|---|---|
| 409 | `DUPLICATE_CODE` | Mã đã tồn tại | `E-STL-0001` |
---
## 4. Bảng đối chiếu mã lỗi
*Mọi mã lỗi trong SRS §4.1 phải có một dòng ở đây, và ngược lại.*
| Mã lỗi SRS | Endpoint | HTTP | `code` của API | ☐ Khớp |
|---|---|---|---|---|
| `E-STL-0001` | POST /stores | 409 | `DUPLICATE_CODE` | ☐ |
Mã lỗi SRS không có endpoint nào sinh ra ⇒ hoặc lỗi chỉ ở giao diện (ghi rõ), hoặc bị bỏ sót.
## 5. Điểm cần BE xác nhận
*Chỉ dùng khi contract do BA đề xuất.*
| # | Điểm cần chốt | Đề xuất của BA | BE trả lời | Ngày |
|---|---|---|---|---|
| 1 | `id` trả string hay number | string | | |
| 2 | `page` 0-based hay 1-based | 0-based | | |
| 3 | Có trả `hasNext` không | Có | | |
| 4 | Lỗi nghiệp vụ trả 4xx hay 200 | 4xx | | |
## 6. Hành vi khi API lỗi *(giao diện phải làm gì)*
| Tình huống | Giao diện làm gì | 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 | AC-12 |
| 5xx / timeout | Hiện lỗi, cho thử lại, **giữ nguyên dữ liệu đã nhập** | AC-09 |
| Mạng chậm | Hiện trạng thái đang tải, khoá nút gửi để tránh gửi hai lần | |
🔴 **Khoá nút gửi khi đang xử lý** — không có nó thì người dùng bấm hai lần tạo ra hai bản ghi.
## 7. Open Questions
| ID | Câu hỏi | Hỏi ai | Từ ngày | Chặn gì |
|---|---|---|---|---|