SDD-005 — Interaction & Conversation System
Horizontal platform capability (như Identity, Notification, Evidence) — một Interaction Service dùng chung; cấm mỗi school/module tự xây comment riêng.
2. Entities & Targets (REQ-INX-01)
Interaction: Comment · Reply · Reaction · Mention · Annotation · Activity.
Comment: comment_id · author_id · target_type · target_id · parent_comment_id
· content · created_at · edited_at · visibility · statustarget_type + target_id áp cho gần như mọi object: Learning Experience, Assessment (vd assessment_result/asr_28392), Lab, Question, Recommendation, Learner Report, Learning Package, Goal, Evidence, Mentor Session, Community Post, Media. Ví dụ luồng chuẩn: Parent comment dưới Recommendation → Mentor reply → Learner react/hỏi tiếp — conversation gắn với đúng object đó (REQ-PAR-07).
3. Threading (REQ-INX-02)
Data model hỗ trợ nesting đệ quy; UI giới hạn 1–2 cấp.
4. Visibility & Permission (REQ-INX-03, REQ-MEN-02)
Levels: private · learner_parent · mentor_team · school · community · internal_staff. Mentor note "có dấu hiệu đoán đáp án" = internal_staff, learner không thấy. Authorization ở backend theo relationship user↔learner (family, assignment).
5. Mentions & Notifications (REQ-INX-04)
@mentor @parent @learner → events CommentCreated, MentionCreated, ReplyCreated, ReactionAdded → Queue nemo12-events → Notification module → in-app, email, push (mobile-ready).
5.1 Kênh email — Cloudflare Email Service (SRC-602)
Thư rời hệ thống qua binding EMAIL của Cloudflare Email Service, không qua nhà cung cấp ngoài. Chủ dự án chốt 2026-08-26, thay Resend của SRC-452.
Đây là binding chứ không phải secret, nên không còn khoá API nào để lộ hay phải xoay vòng — bớt đúng một thứ trong danh sách bí mật phải quản (REQ-SEC-06, RISK-013).
Điều kiện để thư thật sự đi được, và trạng thái khi chưa đủ:
| Điều kiện | Chưa đủ thì sao |
|---|---|
| Tên miền gửi đã onboard vào Email Service | send ném E_SENDER_DOMAIN_NOT_CONFIGURED; digest ghi failed, cron không chết |
| Người nhận là địa chỉ đích đã xác minh (giới hạn beta) | send ném E_RECIPIENT_NOT_ALLOWED |
Worker có binding EMAIL | sendEmail trả skipped; cron vẫn chạy, vẫn ghi log |
Trạng thái đã dựng (2026-08-26, SRC-602): nemo12.com đã onboard — Status Enabled, DNS Configured (MX/SPF/DKIM đều nằm trên cf-bounce.*, không đụng email tên miền gốc); dac2205@gmail.com là địa chỉ đích Verified; đã gửi thư thử thành công qua binding thật (wrangler dev --remote, không deploy). Nghĩa là: chừng nào còn trong beta, thư chỉ tới được các địa chỉ đã xác minh — với giai đoạn DIGEST_TEST_RECIPIENT thì vậy là đủ, còn muốn gửi cho bố mẹ thật thì phải chờ mở hạn chế này hoặc xác minh từng địa chỉ.
Ba trạng thái ok · skipped · failed là cố ý tách: gộp "chưa cấu hình xong" vào "lỗi" sẽ làm mọi ngày trước khi bật kênh trông như một sự cố, và người trực sẽ học cách bỏ qua cảnh báo.
Nhà cung cấp được gói trong đúng một hàm (modules/email/channel.ts), nên lần đổi này chỉ phải sửa hàm đó cộng khai báo binding — hợp đồng SendResult giữ nguyên, run.ts và test không phải biết ai đang chuyển thư.
5.2 Template thư — modules/email/templates.ts (SRC-605)
Chủ dự án 2026-08-26: mọi thư gửi đi phải là HTML đẹp cùng ngôn ngữ biển sâu. Một layout chung (renderLayout) + 5 template: báo cáo tuần theo từng con (weeklyReport — template đầu bảng), xác nhận đăng ký sự kiện, nhắc buổi học thử, con nghỉ học nhiều ngày, chào mừng bố mẹ mới.
Ba luật của mọi thư (kiểm bằng test, không kiểm pixel): tiêu đề + câu mở tự đứng được; không chấm điểm con, không màu đỏ (REQ-UX-03) — "cần để mắt" là hổ phách; đúng một nút hành động mỗi thư. Kỹ thuật: style inline 100%, layout bằng <table>, không ảnh ngoài, không webfont — Gmail cắt <style>, Outlook render bằng Word engine, nên file này không import gì từ design system mà là bản dịch tay của cùng bảng màu. Dãy ô mức vững (masteryCells) giữ đúng ẩn dụ MasteryBar của web. Đã gửi thử cả 5 thư với dữ liệu giả định, nhận đủ trong Inbox (2026-08-26).
Nợ này đã trả: modules/email/digestContent.ts (thư tổng kết hằng ngày) nay đi qua cùng renderLayout, và weeklyReport chạy trên truy vấn thật chứ không còn dữ liệu giả định. Từ SRC-744 mọi file thư nằm trong một thư mục duy nhất — xem bản đồ trong ref.emails.
6. Moderation — K12 bắt buộc (REQ-INX-05)
Profanity/abuse/spam/inappropriate detection (AI classify qua AI Gateway) + report/hide/block + moderation queue + audit log. Quyết định nghiêm trọng: lưu evidence + human review. Pattern hidden_at (soft-hide) kế thừa sutucon.
7. Activity Stream (REQ-INX-06)
Mọi interaction tạo Activity Event → Learner Activity Timeline (Parent commented, Mentor replied, Learner completed lab, Recommendation acknowledged…) — feed cho Learner Model & Parent Model (SDD-002), và telemetry (login/page_view/course_open — FEAT-050) nhập cùng dòng behavior evidence.
8. Forum (REQ-COM-03) — specialization của Interaction
Forum là hiện thân đầu tiên của Interaction System (kế thừa lab_topics/replies/votes chuyenchon):
forum_topics (id, scope_type[subject|school|general], scope_id, title, body,
author_user_id, author_role, status[open|hidden|locked], reply_count,
vote_score, created_at, last_activity_at)
interactions (id, target_type, target_id, parent_id, author_user_id, author_role,
content, visibility, status[visible|hidden|blocked], hidden_at, created_at)
interaction_votes (interaction_target, user_id, value[-1|1]) -- upvote/downvote- Topic = target (
target_type='forum_topic'); reply = interaction trên topic. Threading 1 cấp (SDD-005 §3). - Vote up/down trên topic và reply (
vote_score), sắp xếp theo mới nhất / nhiều vote. - Visibility mặc định
community(mọi user Nemo12); scope theo subject (Toán/Anh/Văn) hoặc school để đúng ngữ cảnh học. - Moderation K12 (SDD-005 §6): lọc từ cấm cơ bản khi tạo; report → moderation queue; author/staff
hide; audit. AI classify qua AI Gateway là nâng cấp sau. - Authz: mọi authenticated learner/parent tạo được; chỉ author hoặc staff
hide/lock.
Vote + mentor-featured exemplars trên submissions (REQ-INX-07) dùng chung interaction_votes.
Trace
| REQ | Mục |
|---|---|
| REQ-INX-01..06 | §2–§7 |
| REQ-PAR-07 | §2 |
| REQ-MEN-02 | §4 |