# API — Contract đề xuất — | | | |---|---| | **Version** | 1.0 | | **Date** | YYYY-MM-DD | | **Author** | (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/` — 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/` — 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ì | |---|---|---|---|---|