Supabase 2 — Bản thiết kế schema và phân quyền (Đợt 3A)
Ngày 12/10/2026. Đã triển khai schema/RLS/RPC trên Supabase 2 (3 migrations). Giao diện
/platform/nằm trong PR #4; chưa kiểm thử email E2E hay mở đăng ký công khai. Project đích:mhgsvxsjrzaeafvifydu(Tools_out, dự kiến vai trò APMATHS Platform). Projectyhfburffwzvcayjadskr(AI-CLO cá nhân) không thuộc phạm vi schema này. Không thực hiện Cloudinary, media, upload, thanh toán trong đợt hiện tại.
Cập nhật: bản blueprint dưới đây mô tả core v1, còn schema mở rộng về ngân hàng câu hỏi/đề thi/entitlement nằm trong các migration v4–v7. Xem Báo cáo tiến độ và Supabase 2 README.
1. Mục tiêu v1
Một Supabase chứa nhiều giáo viên ngoài và học sinh của họ; từng giáo viên sở hữu một workspace, được tạo lớp, ghi danh học sinh, xem dữ liệu của chính mình. Một học sinh có thể học với nhiều giáo viên. Giáo viên tự đăng ký nhưng không tự kích hoạt quyền teacher. Chưa tái hiện toàn bộ AI-CLO hiện có.
Phân tách Auth
Supabase 1 và 2 có hai auth.users và session/JWT riêng. Website phân biệt khu vực AI-CLO cá nhân và APMATHS Platform, không giả định SSO. User ở base 2 không tự động có quyền ở base 1. Khóa bí mật, tài khoản dịch vụ và JWT không chuyển qua dự án kia.
2. Schema tối thiểu đã triển khai v1
Bảng/khóa logic đã triển khai vào Supabase 2. SQL gốc được lưu tại thư mục migrations, gồm core, bảo vệ RPC và RLS profile.
| Bảng | Cột/khóa bắt buộc | Giới hạn và quan hệ |
|---|---|---|
profiles |
user_id uuid PK, full_name, account_type, status, created_at |
user_id -> auth.users.id; type do server cấp: student, teacher, platform_admin; pending teacher chưa là teacher thực tế |
teacher_applications |
id PK, user_id FK, organization, status, submitted_at, reviewed_at, reviewed_by |
Một hồ sơ mở của mỗi user; trạng thái pending/approved/rejected chỉ đổi ở backend; lưu audit |
teacher_application_events |
id PK, application_id FK, action, actor_id, created_at |
Audit chỉ server ghi, không sửa/xóa phía client |
workspaces |
id PK, owner_user_id FK, name, status, created_at |
Owner là teacher đã duyệt; ownership không do client tùy ý đặt |
workspace_members |
workspace_id FK, user_id FK, role, created_at |
Unique (workspace_id,user_id); role owner/teacher_assistant trước; tránh policy đệ quy |
classes |
id PK, workspace_id FK, name, status, created_at |
Workspace sở hữu lớp; không được đổi workspace qua UPDATE client |
class_enrollments |
class_id FK, student_user_id FK, status, joined_at |
Unique (class_id,student_user_id); ghi danh qua API xét mã mời/giáo viên duyệt |
class_invites |
id PK, class_id FK, code_hash, expires_at, max_uses, used_count |
Chỉ lưu hash mã mời, không trả hash mã mời qua Data API; kiểm tra rate limit ở backend |
Hoãn: question_banks, questions, exams, attempts, answers, subscriptions, orders, media_assets. Chỉ bổ sung khi vòng đời Auth → workspace → class → enrollments đã được kiểm thử.
3. Các invariants bắt buộc
- Không cho client tạo hoặc sửa
profiles.account_type,profiles.status,teacher_applications.status/reviewed_by. - Chỉ giáo viên đã duyệt mới có workspace; chủ sở hữu workspace chỉ đổi qua server admin có audit.
- Giáo viên có thể xem dữ liệu thuộc workspace được phân công, không xem được dữ liệu workspace khác.
- Học sinh chỉ xem lớp mình tham gia và dữ liệu của chính họ; không xem hồ sơ học sinh khác nếu không được cấp quyền.
- Lệnh tạo/sửa
classeskhông được gánworkspace_idcủa giáo viên khác; UPDATE kiểm tra cảUSINGvàWITH CHECK. teacher_application_eventsappend-only phía backend.- Không gộp student/teacher bằng email giữa hai Supabase; nếu một người đăng ký cả hai thì đó là hai tài khoản độc lập.
- Không dùng
user_metadatado user sửa được làm bằng chứng quyền teacher/admin. Server kiểm tra trạng thái từ database và danh sách admin được bảo vệ. - Schema trong
publicphải bật RLS; RLS chưa đủ nếu không có GRANT phù hợp, kiểm tra Data API exposure độc lập. - RLS helper cho
workspace_membersphải tránh tham chiếu đệ quy vào chính policy; đánh giá access qua server hoặc helper an toàn sau khi audit, không vội dùngSECURITY DEFINERcông khai.
4. Ma trận đọc/ghi mong muốn
| Tác vụ | Khách | Student | Teacher đã duyệt | Platform Admin |
|---|---|---|---|---|
| Đăng ký tài khoản/email | Auth signup có chống abuse | — | — | — |
| Xem hồ sơ của mình | Không | Có | Có | Có |
| Tự nâng role/duyệt đơn | Không | Không | Không | Chỉ backend |
| Xem trạng thái đơn của mình | Không | Có, nếu đã nộp | Có | Có |
| Tạo workspace | Không | Không | Thông qua backend sau duyệt | Có |
| Quản lý lớp workspace A | Không | Không | Chỉ thành viên đủ quyền của A | Có theo công vụ |
| Xem danh sách học sinh lớp A | Không | Không | Chỉ teacher A | Có theo công vụ |
| Học sinh xem bài/kết quả của mình | Không | Có nếu thuộc lớp và được công bố | Theo vai trò được giao | Có theo công vụ |
| Đọc lớp/đề/kết quả workspace B | Không | Chỉ những lớp B mà học sinh tham gia | Không nếu thuộc teacher A | Có theo công vụ |
5. Luồng triển khai từ đầu đến cuối
- Đăng ký trên Supabase 2, xác minh email, tạo
profilesgiới hạn quyền vàteacher_applicationsqua một backend an toàn (không dùng public role update). - Admin xét duyệt và ghi audit; backend cấp role teacher + workspace, không lấy role từ payload của client.
- Teacher đăng nhập, tạo lớp trong workspace; membership/phân quyền xác minh server & RLS.
- Student đăng ký / tham gia lớp theo lời mời; mã invite chỉ redeem ở endpoint có rate limit, chống brute force.
- Student xem đúng lớp và bài của mình. Giáo viên A/B thử truy cập chéo đều phải bị chặn.
- Chỉ sau kiểm thử và review mới mở đăng ký public.
6. Test SQL đã đạt và test E2E còn lại
- Anonymous: không xem được profiles/teacher applications/workspaces/private classes.
- Pending teacher: không thể tạo workspace hoặc chỉnh trạng thái duyệt.
- Teacher A: không thấy các lớp hoặc roster teacher B; thử sửa
workspace_idsang B bị từ chối. - Student A1: đọc được lớp đã tham gia nhưng không đọc roster/kết quả của A2.
- Student join: mã giả/hết hạn/quá số lần không ghi danh; chống dùng lại mã invite.
- Admin: chỉ admin backend có thể duyệt và ghi log; không dựa trên client metadata.
- Security: Supabase Advisors security/performance; kiểm tra
anon,authenticatedGRANT/RLS, RPC và Edge Functions; không lộ service role. - Scale: kiểm thử tải thực tế trước khi khẳng định đáp ứng 100+ người đồng thời; test giả lập 1.000 phiên trên frontend không phải benchmark backend.
7. Ranh giới với Supabase 1 và kế hoạch xử lý sau
Không thay đổi Supabase 1 trong bản schema này. Các tính năng mua lớp của bạn và thi thử miễn phí vẫn thuộc Supabase 1. Khi có yêu cầu riêng, thiết kế entitlement lớp của bạn, bảo vệ đáp án public vs confidential và hạn mức Guest, không để traffic guest ảnh hưởng bài kiểm tra lớp chính thức.
Đã PASS SQL integration giả lập Admin/teacher A/teacher B/student, rollback dữ liệu test. Vẫn cần test xác minh email và trang /platform/ bằng tài khoản thực cùng URL redirect trước khi public.
Phạm vi Đợt 3 hiện tại chỉ Supabase; media/Cloudinary hoãn đến khi người dùng yêu cầu.