Luồng cấp quyền: Chỉ ADMIN/OWNER của Circle mới được mời. Người được mời có quyền Accept (sẽ tạo member) hoặc Reject (chỉ đổi status).
| # | Task | Chi tiết | Status |
|---|---|---|---|
| 01 | Refactor Database Schema | Cập nhật Prisma Schema: thêm enum InvitationRequestStatus, map lại các relations cho CircleInvitation. | done |
| 02 | Cursor Pagination | Áp dụng `ICursorPagination` cho bảng CircleInvitation, dùng thư viện buildPagination. | done |
| 03 | Transaction Support | Thay thế prisma.$transaction bằng transactionService.doInTransaction trong Service layer để đảm bảo quy tắc Clean Architecture. | done |
| 04 | Circle Permission Check | Kiểm tra role (ADMIN/OWNER) trước khi cho phép tạo lời mời. Sử dụng guard clause hợp lý. | done |
| # | Severity | Issue | Chi tiết & Cách Fix | Status |
|---|---|---|---|---|
| C1 | fixed | Lỗ hổng Logic: REJECTED vẫn bị thêm vào nhóm circle.service.ts : acceptInvitation | Controller có truyền status xuống Service, nhưng Service hoàn toàn phớt lờ biến này. Nó luôn gọi circleRepository.acceptInvitation (hardcode status = ACCEPTED) và luôn tạo CircleMember. Nếu user Reject, họ vẫn bị thêm vào Circle! ✅ Đã fix — Service giờ rẽ nhánh if/else dựa trên status, reject chỉ update status, accept mới tạo CircleMember. | done |
| C2 | fixed | Thiếu return trong sendInvitationcircle.service.ts : sendInvitation | Block transactionService.doInTransaction có await create(...) nhưng thiếu chữ return đằng trước. Do đó API sẽ trả về dữ liệu undefined thay vì object invitation mới được tạo. ✅ Đã fix — upsert trả về giá trị qua return. | done |
| C3 | fixed | Sai Responsibility Layer (Kiến trúc) circle.repository.ts | Các hàm liên quan đến bảng Invitation (findInvitation, acceptInvitation) lại được định nghĩa trong circleRepository. Nên chuyển chúng sang circleInvitationRepository cho đúng domain. ✅ Đã tách — circleInvitationRepository giờ chứa toàn bộ logic invitation. | done |