Đợt 3 — Hai Supabase độc lập của APMATHS
Quyết định cập nhật ngày 12/10/2026, thay thế phương án Auth tập trung ở Supabase 1 trong bản tài liệu đầu tiên. Phạm vi hiện tại: chỉ Supabase (database, Auth, RLS, API và luồng nghiệp vụ). Chưa tích hợp Cloudinary, R2, xử lý ảnh/âm thanh hoặc thanh toán thực tế. Tiến độ: đã triển khai 8 bảng, 3 migration, RLS/RPC Supabase 2 và trang thử nghiệm
/platform/trên PR #4. Đã PASS integration SQL có rollback. Chưa cấu hình xong Email Auth/Redirect hay kiểm thử giao diện với tài khoản thật; chưa mở công khai. Xem hướng dẫn vận hành.
Cập nhật thực thi 12/10/2026: Đã triển khai thêm migration 3C–4 (quản lý học sinh, ngân hàng câu hỏi, đề thi, gói miễn phí) và xác minh/cấp quyền Admin đầu tiên. Trang
/platform/exams/được thêm vào PR #4. Trạng thái đầy đủ tại Báo cáo Đợt 3B–5.
1. Ranh giới sản phẩm — đã thống nhất
| Supabase 1 — của bạn | Supabase 2 — nền tảng giáo viên | |
|---|---|---|
| Ref | yhfburffwzvcayjadskr |
mhgsvxsjrzaeafvifydu |
| Tên hiện tại | Apmaths-ai-clo | Tools_out (tên cũ, dự kiến APMATHS Platform) |
| Đối tượng | Học sinh/sinh viên của bạn | Giáo viên ngoài APMATHS và học sinh của họ |
| Lớp học có phí | Khóa học và lớp do bạn trực tiếp dạy, người mua và kết quả học ở base 1 | Lớp do giáo viên khác sở hữu, người học và kết quả ở base 2 |
| Công khai/traffic | Ngân hàng luyện tập, thi thử, công cụ miễn phí do bạn quản lý | Không lưu bộ thi thử công khai chung |
| AI-CLO | Ứng dụng cá nhân hiện có; không viết lại | Chỉ chọn module phù hợp để phát triển sản phẩm đa giáo viên |
| Auth | Auth của base 1, hiện có | Auth riêng của base 2 cho giáo viên/học sinh, chưa mở đăng ký |
| Thanh toán sau này | Đơn hàng và quyền học lớp của bạn | Gói dịch vụ giáo viên, lớp của giáo viên ngoài |
| Vận hành | Không thay đổi hoạt động hiện tại | Thiết kế mới từ database trống |
Quy tắc quyết định nơi lưu: Chủ thể cung cấp/đứng lớp. Nếu bạn dạy, dù miễn phí hay có phí, dùng base 1. Giáo viên ngoài đứng lớp dùng base 2. Thi thử công khai phục vụ SEO/traffic của APMATHS nằm trong hệ sinh thái base 1; đề tĩnh có thể phục vụ trực tiếp từ Jekyll/CDN không cần truy vấn database.
2. Auth không kết nối chéo ở giai đoạn này
- Mỗi Supabase có Auth độc lập: không chia sẻ Supabase JWT, password, bảng
auth.usershoặc gọi REST trực tiếp từ project này sang project kia. - Một người có thể có hai tài khoản ở hai project; giao diện APMATHS giải thích rõ ngữ cảnh đang đăng nhập. Chưa triển khai SSO/xác thực chéo.
- Không chuyển bảng điểm, đề thi bảo mật, danh sách học sinh, thông tin mua khóa học từ base 1 sang base 2.
- AI-CLO PTITHCM (
rraooqedkpyhokattwdz) hoàn toàn tách biệt, không thuộc hai project APMATHS. - Bảo toàn mọi đường dẫn legacy
apmaths.github.io/ai-clo/vàapmaths.github.io/tools/; không redirect hoặc sửa runtime AI-CLO hiện có trong đợt này.
3. Schema tối thiểu Supabase 2 (đã triển khai v1)
3.1. Auth & đăng ký
profiles(user_id, full_name, account_type, status, created_at): thuộc Auth base 2.account_typedo backend cấp (student, teacher, platform_admin); tài khoản đăng ký giáo viên ban đầu ở trạng thái pending, không có quyền teacher thực tế.teacher_applications(id, user_id, organization, status, submitted_at, decided_at, decided_by, notes): đơn xét duyệt, lịch sử trạng thái và người duyệt.- Xác minh email -> gửi đơn -> Admin xét duyệt -> cập nhật vai trò phía server -> tạo workspace của giáo viên. Không để người dùng tự viết
role = teacherbằnguser_metadatahay thay đổi qua Data API. - Chỉ API có kiểm tra quyền mới thay đổi trạng thái phê duyệt. Đơn có thể bị từ chối/tạm khóa, có audit.
- Học sinh có thể đăng ký riêng trong base 2 và tham gia nhiều lớp của các giáo viên khác nhau.
3.2. Tenant / lớp học
workspaces(id, owner_id, name, status): không gian dữ liệu của giáo viên; không tạo một Supabase project cho mỗi giáo viên.workspace_members(workspace_id, user_id, role): giáo viên chính/cộng tác nếu được mời; vai trò workspace không phải vai trò quản trị nền tảng.classes(id, workspace_id, name, status): lớp thuộc đúng workspace.class_enrollments(class_id, student_id, status, joined_at): một học sinh có thể ở nhiều lớp, cần tránh trùng ghi danh.- Về sau:
question_banks,questions,exams,exam_attemptsđều bắt buộc truy vết workspace/class ownership; không tinworkspace_iddo client tự gửi.
3.3. Quy tắc RLS/API
- Tất cả bảng nghiệp vụ exposed public đều bật RLS; chính sách theo
auth.uid()và membership thực tế của workspace/lớp, không chỉTO authenticated. - Student chỉ được xem lớp mình được nhận, bài được công bố, kết quả của chính mình.
- Teacher chỉ xem/sửa dữ liệu thuộc workspace có vai trò phù hợp; teacher A không thể xem lớp, học sinh, ngân hàng riêng hoặc kết quả của teacher B.
- Không cho client sửa
profiles.account_type/status,teacher_applications.status/decided_by,workspaces.owner_id,classes.workspace_id, các trạng tháipaid. - Không dùng
raw_user_meta_datađể cấp quyền; nếu dùng JWTapp_metadata, lưu ý độ trễ cập nhật JWT; nghiệp vụ quan trọng phải xác minh server. - Không cấp
service_role/secret key cho frontend. Chỉ backend dùng quyền cao để thực hiện thao tác đã xác thực và giới hạn chặt. - Join class: mã tham gia mời dùng một lần/giới hạn, kiểm tra qua backend, rate-limit, không cho tự chèn
class_enrollmentsvới class ID bất kỳ. - Cần kiểm thử RLS có tài khoản A/B/student/guest, UPDATE đổi chủ sở hữu, IDOR, tạo teacher giả, xem đáp án đề bảo mật trước khi mở đăng ký.
4. Supabase 1 — chỉ bổ sung các module cần thiết (chưa thay đổi)
Giữ nguyên profiles, subjects, subject_members, questions, question_banks, practice_*, exams, exam_attempts và Edge Function đang hoạt động.
- Thi thử hút traffic: tách
public_practicekhỏi bài/đề bảo mật bằng trạng thái xuất bản và allowlist API; có thể tận dụng frontend Guest đề tĩnh. Không chuyển thi thử sang base 2. - Lớp có phí của bạn: dự kiến
courses/classes,course_packages,orders/payment_events,enrollments/entitlements, nhưng chưa tạo bảng và chưa tích hợp cổng thanh toán. - Bảo vệ vận hành: giới hạn lượt rút đề, cache/CDN cho đề công khai, không trả đáp án bảo mật cho Guest, không lưu thông tin cá nhân Guest không cần thiết.
- Trước khi bổ sung bảng mới phải đối chiếu cấu trúc có sẵn, sao lưu và xác minh phụ thuộc; không đổi AI-CLO runtime của lớp đang sử dụng.
5. Không làm trong đợt này
- Không tích hợp Cloudinary, Cloudflare R2 hoặc API lưu ảnh/âm thanh; không tạo bucket/bảng
media_assetschỉ để đón trước. - Không chuyển file nghe/ảnh từ nơi hiện tại.
- Không mở đăng ký public, không deploy payment webhook, không đổi domain/DNS/redirect.
- Không sao chép toàn bộ schema AI-CLO sang base 2.
- Không tạo Auth dùng chung giữa hai Supabase.
6. Trình tự công việc
- Kiểm tra trước triển khai: base 1 có Auth + schema AI-CLO đang dùng; base 2 ban đầu trống.
- Chốt vai trò hai project và nguyên tắc lưu lớp mua có phí/thi thử công khai.
- Ghi thiết kế kiến trúc chỉ-Supabase trong PR #4.
- Áp dụng 3 migration cho Supabase 2 (ban đầu trống), bật RLS, phân quyền theo cột, các RPC và lớp bảo mật; kiểm thử transaction/rollback nhiều vai trò PASS.
- Triển khai giao diện đăng ký/đăng nhập và duyệt giáo viên tại
/platform/trên nhánh PR #4; SQL test chống tự nâng quyền PASS. - Cấu hình Supabase Auth (Email, Redirect URLs), tạo Admin đầu tiên và kiểm thử email/login qua trình duyệt với tài khoản thật.
- Phê duyệt tạo workspace; tạo lớp và mã mời; học sinh tham gia lớp, cách ly giáo viên A/B và hiển thị danh sách học sinh; SQL integration PASS.
- Rà soát endpoint public-practice base 1 (không lộ đáp án; giới hạn tải).
- Sau khi hệ thống nền chạy ổn mới thêm ngân hàng đề, thi, kết quả và sản phẩm thu phí của giáo viên.
- Media và thanh toán: hoãn, chỉ triển khai sau khi có yêu cầu mới.
Điều kiện trước khi mở đăng ký công khai
Migration đã áp dụng trên base 2; cần cấu hình Email Auth/Redirect, bootstrap Admin, bảo vệ spam/signup, kiểm thử E2E trình duyệt, rà Supabase Advisors và xác nhận quyền trẻ vị thành niên trước khi mở công khai. Không tự merge PR #4 khi chưa qua bước này.