164 lines
5.4 KiB
Markdown
164 lines
5.4 KiB
Markdown
# 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ì |
|
||
|---|---|---|---|---|
|