Skip to content

Error Catalog ​

Hợp đồng phản hồi ​

jsonc
// thành công
{ "data": … }

// lỗi
{ "error": { "code": "VALIDATION_ERROR", "message": "…" } }

Client luôn đọc error.code để rẽ nhánh, và hiển thị error.message cho người dùng. message viết bằng tiếng Việt, cho người đọc — không bao giờ nhét stack trace hay tên bảng vào đó.

15 mã lỗi ​

Định nghĩa duy nhất tại workers/api/src/shared/errors.ts. Không thêm mã mới mà không sửa file này — enum là hợp đồng.

CodeHTTPNghĩaClient nên làm
VALIDATION_ERROR400Đầu vào sai (zod) hoặc thiếu ngữ cảnh bắt buộcSửa dữ liệu, đừng retry
AUTHORIZATION_ERROR401Chưa đăng nhập, phiên hết hạn, Origin sai, thiếu roleĐăng nhập lại hoặc báo không có quyền
NOT_FOUND404Không có tài nguyênKhông retry
LESSON_LOCKED403Bài nằm ngoài phần học thử, learner chưa có quyền học khoáMời ghi danh, đừng bắt đăng nhập lại
HOST_ONLY403Người trong phòng nói nhưng không phải host bấm Record/Pause/Stop hoặc chuyển host (SRC-1166)Ẩn nút điều khiển, đừng bắt đăng nhập lại
SCOPE_REQUIRED403Mentor đã xác nhận vai nhưng thiếu phạm vi cho việc này: phát hành nội dung AI Teen (SRC-1284; sửa bản nháp không cần phạm vi từ SRC-1291)Hiện chế độ chỉ đọc, đừng bắt đăng nhập lại
NOT_LEARNER403Phụ huynh, mentor hay staff đọc được learner nhưng ghi thứ chỉ chính learner được ghi: tick bước AI Teen (SRC-1283)Ẩn ô tick, đừng bắt đăng nhập lại
UNKNOWN_STEP400Id bước không có trong bản kê nội dung (gõ sai, bước đã nghỉ) (SRC-1283)Tải lại nội dung, đừng retry
STEP_NOT_TICKABLE422Bước có thật nhưng máy chấm: phần đọc có cổng, câu kiểm (SRC-1283)Không cho tick tay; bước tự xong khi qua cổng / đúng câu
CONFLICT409Xung đột trạng thái (trùng, đã xử lý)Đọc lại rồi thử lại
STALE_DRAFT409Lưu bản nháp với rev cũ: người khác vừa lưu trước (SDD-056 §5)Tải lại bản mới rồi sửa tiếp
RATE_LIMITED429Chạm hạn mứcĐợi theo Retry-After rồi thử lại
TEMPORARY_FAILURE503Lỗi tạm của chính taRetry có backoff
DEPENDENCY_FAILURE503Phụ thuộc ngoài hỏng (AI Gateway, dịch vụ ngoài)Retry hoặc suy giảm dịch vụ
INTERNAL_ERROR500Lỗi không lường trướcBáo lỗi, không retry mù

Quy ước ​

401 chứ không 403. Cả "chưa đăng nhập" lẫn "đăng nhập rồi nhưng không có quyền" đều trả 401 AUTHORIZATION_ERROR. Có chủ ý: 403 tiết lộ rằng tài nguyên tồn tại và người này chỉ thiếu quyền — với dữ liệu trẻ em, đó đã là rò rỉ thông tin.

Ngoại lệ thứ hai: HOST_ONLY trả 403 (30.09.2026, SRC-1166): chỉ trả SAU khi đã xác nhận người gọi ở trong phòng, nên không lộ gì họ chưa thấy trên màn hình.

Ngoại lệ thứ ba: SCOPE_REQUIRED trả 403 (07.10.2026, SRC-1284): chỉ trả SAU khi đã xác nhận người gọi là mentor, về nội dung AI Teen vốn công khai, nên không lộ gì; trả 401 thì Dolphin hiểu là phiên hết hạn và đẩy một mentor được quyền xem đi đăng nhập lại.

Ngoại lệ thứ tư: NOT_LEARNER trả 403 (07.10.2026, SRC-1283): chỉ trả SAU khi canAccessLearner đã cho người gọi ĐỌC learner ấy, nên không lộ gì họ chưa thấy; trả 401 thì phụ huynh bị bảo đăng nhập lại mà vẫn không tick được.

Ngoại lệ đầu tiên: LESSON_LOCKED trả 403 (2026-09-05). Lý do của luật trên không áp được ở đây — sự tồn tại của mọi bài học đã công khai tại /v1/public/ielts/catalog cho ielts.nemo12.com, nên 403 không nói thêm điều gì. Còn trả 401 thì gây hại thật: client hiểu là phiên hết hạn và bảo learner đăng nhập lại, làm lại, rồi vẫn không mở được bài.

503 tách làm hai. TEMPORARY_FAILURE là lỗi của ta, DEPENDENCY_FAILURE là lỗi bên ngoài. Phân biệt được thì dashboard mới trả lời được câu "ai đang hỏng".

Suy giảm ≠ lỗi. Có những thứ hỏng mà không trả lỗi, vì nghiệp vụ chính vẫn đúng:

Sự cốHành viLog
Model update hỏng sau khi nộp bàiHọc sinh vẫn nộp đượcmodel_update_degraded
Ghi run log hỏngNghiệp vụ chạy tiếpRUNLOG_DEGRADED
Publish event hỏngNghiệp vụ chạy tiếpEVENT_PUBLISH_FAILED

Ba dòng log này là tín hiệu quan sát chính của hệ thống — thấy chúng tăng nghĩa là có thứ đang hỏng dù người dùng chưa kêu.

Tương thích ngược ​

Trong /v1: không bỏ mã lỗi, không đổi HTTP status của mã đã có, không đổi ý nghĩa. Thêm mã mới là thay đổi tương thích; đổi mã cũ thì phải lên /v2 (QG-003).

Trace ​

  • REQ-NFR-09 (error taxonomy), REQ-PLT-04 (OpenAPI sinh từ router).
  • Thiết kế: SDD-006 §11.
  • Kiểm chứng: QG-003, QG-009.