# T5Edu - Business Knowledge Map & Feature Specification

_Tài liệu business tổng hợp cho dự án T5Edu. README này vừa phục vụ Stakeholders, Product Owners, đội ngũ phát triển, vừa là nguồn tri thức để AI chatbot tra cứu, gom nhóm và tổng hợp thông tin theo heading._

---

## 0. Cách Đọc Tài Liệu Cho AI Chatbot

README được tổ chức như một bản đồ tri thức theo nghiệp vụ. Khi chatbot cần trả lời câu hỏi, hãy đọc heading cấp cao trước, chọn đúng nhóm chủ đề, sau đó đọc mục chi tiết bên dưới.

- Nếu câu hỏi hỏi "T5Edu là gì", "nền tảng làm gì", "điểm khác biệt" -> đọc **1. Tổng Quan Nền Tảng** và **2. Lợi Ích & Giá Trị Cốt Lõi**.
- Nếu câu hỏi hỏi về học, khóa học, bài học, bài tập, nộp bài -> đọc **3. Hệ Sinh Thái Học Tập LMS** và **10. Trung Tâm Bài Tập & Submission**.
- Nếu câu hỏi hỏi về AI, chatbot, tutor, tạo khóa học, chấm bài, phỏng vấn, RAG -> đọc **4. Hệ Sinh Thái AI T5Edu**.
- Nếu câu hỏi hỏi về T5Lab, testcase, dự án, Kanban, cộng tác -> đọc **5. T5Lab - AI Test Management System**.
- Nếu câu hỏi hỏi về PRO, EDU, ưu đãi, giới thiệu bạn bè -> đọc **6. Gói PRO, EDU Benefits & Referral**.
- Nếu câu hỏi hỏi về đơn hàng, thanh toán, ví, Sepay, hoàn tiền -> đọc **7. Đơn Hàng, Thanh Toán & Ví Điện Tử**.
- Nếu câu hỏi hỏi về profile, hồ sơ, CV, portfolio, slug -> đọc **8. Hồ Sơ Năng Lực & Portfolio Bento 2.0**.
- Nếu câu hỏi hỏi về blog, SEO, bản tin, auto-post Facebook -> đọc **9. Blog, SEO, Bản Tin & Phân Phối Nội Dung**.
- Nếu câu hỏi hỏi về AI crawler, AIO, Markdown cho LLM, `/llms.txt`, `/path.md`, hoặc `/path.html` -> đọc **9.8 AI Markdown Surface & LLM Discovery**.
- Nếu câu hỏi hỏi về admin, vận hành, dashboard, cron, retention -> đọc **11. Quản Trị, Vận Hành & Retention**.
- Nếu câu hỏi hỏi về T5Docs, workspace tài liệu, Ask Mode, Edit Mode, diff review, cộng tác tài liệu, architecture map -> đọc **16. T5Docs Workspace Tài Liệu Cộng Tác**.
- Nếu câu hỏi hỏi về Admin Analytics Chat, trợ lý dữ liệu admin, BI agent, generative UI, read-only SQL agent, mutation propose-then-confirm -> đọc **11.7 Admin Analytics Chat Trợ Lý Dữ Liệu Quản Trị** trong mục **11. Quản Trị, Vận Hành & Retention** và **4.13 Admin Analytics Chat** trong mục **4. Hệ Sinh Thái AI T5Edu**.
- Nếu câu hỏi hỏi về bảo mật, chống gian lận, Sentry, SSE, crash guard -> đọc **12. Bảo Mật, Rủi Ro & Observability**.
- Nếu câu hỏi hỏi về bán source code T5Edu, landing `/source-code`, giá bộ source code, custom development, VPS VN, training 1-1, SSE live counter/toast social proof -> đọc **19. Landing Page Bán Source Code**.
- Nếu câu hỏi hỏi về landing page PRO, upsell PRO, trang `/pro`, bảng so sánh FREE vs PRO, SSE live activity upgrade, testimonial PRO, ProBenefitsMatrix, ProLandingService -> đọc **20. Landing Page PRO Upsell Conversion**.
- Nếu câu hỏi hỏi về game học tập Quality Cove, renderer 2.5D, world sandbox hoặc
  asset runtime -> đọc **21. Quality Cove — Cozy Learning Game**.

---

## 1. Tổng Quan Nền Tảng

### 1.0 Kỹ thuật giao diện (mobile-first, hiệu năng)

Landing editorial refresh (14/07/2026): `/`, `/pro` và `/source-code` dùng chung ngôn ngữ **Premium Product Editorial + Energetic EdTech**. Hero chuyển sang split-screen bất đối xứng với artwork vector 2D riêng, typography tracking-tight, negative space và một accent theo ngữ cảnh (cobalt cho platform/source code, amber cho PRO). Hero Home điều hướng theo session: guest được mời đăng nhập, FREE xem quyền lợi PRO, còn thành viên PRO không nhận upsell lặp lại; CTA PRO ở thân trang chỉ dẫn về `/pro` hoặc `/profile`, không tạo order trực tiếp. Phía cuối Home có CTA giới thiệu Source Code cho đội ngũ sản phẩm. Feature content ưu tiên narrative, numbered ledger và border/divider thay cho lưới card 3 cột hoặc icon badge lớn. Artwork phẳng theo cấu trúc node/line kiểu Mermaid, không chứa người/text/logo; nội dung, CTA và số liệu vẫn là HTML thật, hỗ trợ light/dark và cấu hình động.

Shell chính (`MainShell`, `Header`, `Footer`) đã tối ưu tải ban đầu trên mobile: ít component hydrate sớm (menu/modal/chat theo tương tác), bản tin (`BroadcastPopup`) không chặn LCP, mở chat desktop bằng `transform` để giảm dịch chuyển layout (CLS). Chi tiết: `plans/PLAN-073-mobile-perf-optimize.md`, `AGENTS.md` mục Zustand / Main shell.

Desktop LMS (PLAN-085): toàn bộ public và authenticated main pages dùng chung app shell thuần trình bày với navigation nhóm `Học tập / Công cụ Tester / Sự nghiệp / Tài khoản`; cả sidebar expanded và collapsed dùng `next/link` cho route nội bộ để chuyển trang client-side. Mobile giữ Header/Footer/Menu hiện hữu. ISTQB exam và results cũng dùng sidebar/topbar desktop mới, còn lesson player, Partner Portal và public Portfolio giữ focus/shell riêng. AI Tutor vẫn dùng nguyên store, SSE, prompt và tool nhưng hiển thị như dock phải 520px; workspace dự án T5Lab/T5Docs chỉ dùng icon rail để tránh sidebar lồng nhau. Không có route, API, schema hoặc capability AI mới.

Desktop rail và compact workspace rail đều được fixed; toàn content frame (topbar, page, T5Docs entry, footer) co giãn theo rail/chat. Khi AI Tutor mở, rail tự thu gọn; collapsed items có tooltip center-right không bị cắt ngang và breadcrumb phản ánh group của route. UserMenu neo top-right, animate mở/đóng và avatar luôn tròn. PRO và Source Code là CTA nổi bật cuối rail và mặc định mở với rail thu gọn. Trang PRO dùng tier session hiện hữu để thay CTA mua bằng celebration với `react-confetti` phủ toàn viewport, recycle liên tục cho thành viên PRO; AI Tutor dùng mật độ chữ 13px dễ quét khi làm việc dài.

Admin AI Models dùng `groupBy(userId)` để nhóm nhật ký AI Tutor theo người dùng hoạt động gần nhất. Danh sách học viên có thể thu gọn; admin chọn từng người rồi chuyển các phiên hỏi–đáp user/AI Tutor bằng tab header (20 phiên/trang, có tải thêm), mỗi phiên tối đa 100 tin và Markdown được render bằng `CustomMDViewer`; surface này không trộn với Admin Analytics Chat.

Instant navigations (Next.js 16.3, PLAN-082/088): static shell, pure transform và search/filter cardinality cao giữ `"use cache"` local; canonical public course/blog/ISTQB, shared landing aggregates và AI-readable builders nặng dùng `"use cache: remote"` qua Redis để ba PM2 web workers chia sẻ cùng cache. Handler đọc `REDIS_URL`, chỉ tạo key `t5edu-cache/entry/*` và `t5edu-cache/tag/*`, fail-open khi Redis lỗi. Dữ liệu user-specific/runtime tiếp tục stream qua `<Suspense>` và không vào remote cache.

AI Markdown Surface (PLAN-083): các route public chính có hai representation rõ ràng: `/path` là HTML cho user/search engine, `/path.md` là Markdown sạch cho AI/LLM, và `/path.html` là alias HTML rõ ràng. `/llms.txt`, `/llms-full.txt`, `/sitemaps.txt` công bố URL Markdown; AI user-agent allowlist được redirect minh bạch sang `.md`, còn browser và Googlebot vẫn nhận HTML.

Desktop contact/support dùng FAB `Liên hệ` mở modal chat thay vì link Header; mobile vẫn giữ route `/contact`. Contact và AI Tutor dùng Konsta `Messages`/`Message` cho message presentation, còn composer giữ `CustomMDEditor` để hỗ trợ Markdown, nhiều dòng và ảnh; store/SSE không đổi. AI Tutor trong dock 520px giới hạn bubble theo vai trò, không để action copy/suggestion chồng lên câu trả lời và dùng composer compact. Contact notification dùng một SSE host chung trong `MainShell` để đồng bộ unread badge, dot mobile và Konsta `Notification` top-right có preview Markdown ngắn, click mở đúng contact context.

### 1.1 T5Edu Là Gì

T5Edu là nền tảng EdTech chuyên biệt cho mảng Kiểm thử Phần mềm (QA/Tester). Nền tảng kết hợp học lý thuyết, thực hành thực chiến, AI hỗ trợ học tập, hệ thống quản trị testcase, ví điện tử nội bộ và hồ sơ năng lực nghề nghiệp.

T5Edu không chỉ là website bán khóa học. Đây là một hệ sinh thái học nghề Tester theo mô hình **Mobile-first, Hybrid Learning**, nơi học viên học bài, làm bài, được AI chấm, xây dựng portfolio, luyện phỏng vấn và thực hành quản trị kiểm thử dự án gần với môi trường làm việc thật.

### 1.2 Định Vị Sản Phẩm

T5Edu định vị là nền tảng học Tester thực chiến dành cho người học muốn đi từ kiến thức nền tảng đến năng lực nghề nghiệp có thể chứng minh được. Điểm khác biệt nằm ở khả năng biến hoạt động học tập thành dữ liệu năng lực: bài nộp, nhận xét AI, tiến độ học, kỹ năng, dự án và hồ sơ công khai.

### 1.3 Mô Hình Trải Nghiệm

T5Edu vận hành theo mô hình học tập liền mạch:

1. Học viên đăng ký hoặc đăng nhập bằng Google OAuth.
2. Học viên chọn khóa học, bài học hoặc gói PRO.
3. Học viên học lý thuyết, làm bài tập, nộp bài và nhận phản hồi.
4. AI Grader chấm bài, phân tích lỗi và gợi ý cải thiện.
5. Tiến trình học được ghi nhận vào dashboard và portfolio.
6. Học viên có thể luyện phỏng vấn AI, quản lý testcase trong T5Lab và chia sẻ hồ sơ năng lực.

### 1.4 Các Trụ Cột Sản Phẩm

- **Learning Management System (LMS):** Khóa học, chương, bài học, bài tập, quiz, testcase và tiến độ học.
- **AI Learning Ecosystem:** AI Tutor, AI Grading, AI Course Generator, AI Mock Interview, RAG và công cụ tìm kiếm ngữ cảnh.
- **T5Lab:** Hệ thống quản trị testcase giống Jira, có AI sinh Pages, Features và Testcases từ tài liệu dự án.
- **Financial Ecosystem:** Order, Wallet, Sepay QR, giao dịch, hoàn tiền, referral và ưu đãi.
- **Professional Identity:** Portfolio Bento 2.0, hồ sơ kỹ năng, dự án, kinh nghiệm, CV và public profile.
- **Knowledge Hub:** Blog, SEO, Auto-Blog Pipeline, Facebook Social Distribution và bản tin.
- **T5Docs:** Workspace tài liệu cộng tác cho QA/QC/BA với Markdown editor, AI Ask Mode, AI Edit Mode có kiểm duyệt diff và export sang T5Lab.
- **Admin Operations:** Dashboard vận hành, báo cáo tài chính, quản trị nội dung, cron jobs và retention.

---

## 2. Lợi Ích & Giá Trị Cốt Lõi

### 2.1 Lợi Ích Cho Học Viên

- **Học qua hành:** Học viên làm bài tập thực tế thay vì chỉ đọc lý thuyết. Bài tập có thể nhúng tài liệu PDF, Docs, Markdown, hình ảnh lỗi và dữ liệu mô phỏng công việc thật.
- **Phản hồi chuyên môn từ AI:** AI Grader chấm bài theo tiêu chí nghiệp vụ, chỉ ra lỗi, giải thích vì sao sai và ghi nhớ phản hồi cũ để kiểm tra học viên đã sửa đúng chưa.
- **Trả tiền linh hoạt:** Học viên có thể mua khóa học, mua bài lẻ hoặc nâng cấp PRO thông qua ví nội bộ.
- **Xây dựng thương hiệu cá nhân:** Portfolio tự động gom tiến trình học, kỹ năng, dự án và kinh nghiệm thành hồ sơ có thể chia sẻ cho nhà tuyển dụng.
- **Luyện môi trường thực chiến:** T5Lab giúp học viên quản lý testcase, phân tích coverage, làm việc theo cấu trúc dự án và Kanban.
- **Luyện phỏng vấn:** AI Mock Interview đóng vai Lead QA, hỏi đáp theo ngữ cảnh khóa học và tạo báo cáo năng lực.
- **Ôn thi ISTQB:** Nền tảng hỗ trợ importer PDF đề thi ISTQB, dịch và chuẩn hóa câu hỏi sang tiếng Việt, xáo trộn câu hỏi, chấm tự động và báo cáo theo chương.

### 2.2 Lợi Ích Cho Quản Trị Viên

- **Giảm công sức tạo nội dung:** AI Course Generator đọc tài liệu, lập dàn ý, sinh bài học, sinh hình minh họa và hỗ trợ human-in-the-loop.
- **Tối ưu vận hành:** Dashboard gộp quản trị nội dung, học viên, ví, đơn hàng, tài chính, báo cáo và hoạt động nền.
- **Theo dõi tài chính rõ ràng:** Báo cáo Net Revenue, dòng tiền thực tế, giao dịch ví, đơn hàng và log thanh toán.
- **Chống gian lận:** Sepay Double-Check, PaymentLog, replay protection và anti-spam order giúp giảm rủi ro giao dịch giả.
- **Tăng trưởng tự động:** Auto-Blog, Facebook auto-post, bản tin và cron retention giúp duy trì nội dung và kéo học viên quay lại.

### 2.3 Lợi Ích Cho Hệ Thống AI Chatbot

README này đóng vai trò business knowledge base để AI chatbot hiểu nghiệp vụ T5Edu. Chatbot có thể dùng heading để xác định miền tri thức, sau đó đọc nội dung chi tiết nhằm trả lời chính xác các câu hỏi về khóa học, ví, AI, T5Lab, PRO, EDU, referral, blog, portfolio và admin operations.

---

## 3. Hệ Sinh Thái Học Tập LMS

### 3.1 Tổng Quan Learning Management System

LMS của T5Edu quản lý toàn bộ trải nghiệm học tập từ cấu trúc khóa học đến tiến độ cá nhân. Dữ liệu học tập được tổ chức theo cây:

`Course -> Chapter -> Lesson -> Submission / LessonProgress`

### 3.2 Khóa Học, Chương Và Bài Học

Khóa học được phân cấp theo `Course`, `Chapter` và `Lesson`. Bài học hỗ trợ nhiều loại nội dung:

- **THEORY:** Bài học lý thuyết.
- **EXERCISE:** Bài tập thực hành bằng Markdown hoặc tài liệu nhúng.
- **QUIZ:** Bài trắc nghiệm.
- **TESTCASE:** Bài viết testcase hoặc phân tích kiểm thử.

### 3.3 Học Liền Mạch Và Resume Learning

T5Edu tự động ghi nhận bài học hiện tại, tiến độ đọc và trạng thái học tập. Học viên có thể quay lại đúng điểm dừng từ dashboard My Courses. Khóa học có thể miễn phí, trả phí hoặc đăng ký ẩn tùy chiến lược kinh doanh.

### 3.4 Mua Bài Lẻ Và Micro-Transactions

Bài học có thể được khóa độc lập. Học viên mở khóa bằng ví nội bộ mà không phải mua toàn bộ khóa học. Cơ chế này hỗ trợ chiến lược "học đến đâu trả tiền đến đó".

### 3.5 Lesson Progress Và Tracking

Lesson Progress ghi nhận trạng thái học, vị trí hiện tại, hoạt động bài học và dữ liệu phục vụ dashboard. Dữ liệu này cũng được dùng để xây dựng portfolio, heatmap và gợi ý học tiếp.

### 3.6 Markdown WYSIWYG Và Tài Liệu Nhúng

Hệ thống soạn thảo và hiển thị Markdown hỗ trợ:

- Upload file bằng presigned URL lên Cloudflare R2.
- Nhúng YouTube dưới dạng iframe.
- Hiển thị ảnh, video, GIF.
- Xem PDF, DOCX, XLSX qua Google Docs Viewer hoặc Office Web Viewer.
- Admin editor có picker chèn nhanh `{{configs.KEY}}` từ public configs kèm `SystemConfig.description` và picker chọn Broadcast action có mô tả để sinh thẻ `<broadcast-action>`.
- Custom elements tương tác:
  - `<multiple-choice correct="X" select="single|multiple">`: Trắc nghiệm tương tác với phản hồi đúng/sai tức thì.
  - `<table-testcase cols="N" rows="N" headers="A|B|C">`: Bảng kịch bản kiểm thử trực quan dạng ma trận cho bài thực hành QA.
  - `<dropdown-content>`: Thu gọn/mở rộng nội dung Markdown (FAQ, tips nâng cao, giải thích chi tiết). Hỗ trợ title, description tùy chọn, và nội dung Markdown đệ quy bên trong.
  - `<grid-content>`: Hiển thị nhiều nội dung Markdown song song dạng card grid (tối đa 4 cột). Hỗ trợ title, description tùy chọn, responsive auto-layout.
  - `<sql-editor>`: Trình soạn thảo SQL tương tác với CodeMirror. Chạy tab đang mở trên PostgreSQL SQL Lab có connected baseline sinh bằng Faker seed cố định (course/profile/payment/wallet/blog); cho phép SELECT/INSERT/UPDATE/DELETE và khôi phục cùng dữ liệu hằng ngày lúc 03:00. `readonly` vẫn cho chạy và sao chép.
  - `<database-schema>`: Sơ đồ cơ sở dữ liệu (ERD) tương tác hiển thị quan hệ các bảng. Tự động parse cú pháp DBML sang ReactFlow graph canvas.
  - `<code-runner lang="...">`: Trình soạn thảo và thực thi mã nguồn tương tác với CodeMirror. JavaScript và TypeScript chạy trực tiếp bằng Bun đã pin bên trong Piston isolate, không gọi `tsc` mỗi lần; Python/Java vẫn dùng runtime Piston tương ứng và SQL đi qua PostgreSQL SQL Lab riêng. Backend cache trong suốt kết quả Piston thành công của cùng runtime + source code trong Redis 6 giờ; cache hit không tốn rate limit. SQL, lỗi và timeout không bao giờ được cache, còn client giữ nguyên trải nghiệm chạy/kết quả bình thường.
  - Public Playground gồm SQL database-manager `/playground/sql` (tắt Header/Footer/desktop shell/FAB qua `MainShell.isDisableLayout`) và Swagger `/playground/api`. SQL workspace hỗ trợ tab query có nút đóng riêng, schema sidebar giới hạn chiều cao để scroll; Swagger dùng toàn bộ chiều rộng và không lặp Endpoint index thành sidebar. Hai trang đọc được khi chưa đăng nhập; chạy SQL và quản lý API key vẫn yêu cầu tài khoản. Bearer API `/playground/api/v1/*` và SQL Editor cùng thao tác trên một baseline SQL Lab dùng chung; REST luôn `no-store`, có quota riêng theo chủ API key, còn `DROP DATABASE`, `DROP TABLE`, `DROP SCHEMA` và `TRUNCATE` bị chặn trước khi chạy. Bảng/cột/enum của editor, OpenAPI và AI schema capsule đều sinh từ demo Prisma schema thay vì chép tay.
  - Vận hành Code Runner chỉ dùng `bun scripts/code-runner/deploy.ts`: đọc hai password SQL Lab từ `.env`, giữ dữ liệu thực hành hiện có khi redeploy, cài runtime thiếu, provision Bun cho JavaScript/TypeScript, chạy song song smoke test hai runtime và reload PM2.
  - Production deploy tự động bằng `.github/workflows/deploy-production.yml` khi push/merge vào `main`. Workflow SSH bằng GitHub secrets, tự nạp Bun và chọn Node.js cao nhất đạt `>=20.9.0` từ PATH/NVM/Volta/mise/asdf/fnm cho non-interactive shell, dùng Git username/token qua `GIT_ASKPASS` tạm thời để fast-forward code, chỉ cài dependency/đồng bộ Prisma/redeploy Code Runner khi file nguồn tương ứng thay đổi; thay đổi SQL Lab demo schema hoặc `baseline.sql` đều redeploy Code Runner trước build và PM2 restart. Exit code SSH quyết định trạng thái job; status file tạm chỉ bổ sung stage/exit cho Telegram. Telegram nhận một thông báo cuối gồm số lượng/danh sách commit, trạng thái, lỗi nếu có và link GitHub Actions. Năng lực này được công khai đồng nhất trên `/source-code` HTML và bản Markdown AI-readable.
  - `<broadcast-action>`: Thẻ nút bấm thực hiện hành động bản tin Admin (nạp ví, mua khóa học, chuyển trang).
  - Sơ đồ Mermaid (Flowchart, Sequence, State diagram) vẽ qua khối ` ```mermaid ` với gợi ý cho AI Tutor.
  - Template cấu hình động `{{configs.KEY_NAME}}` tự động render giá trị thời gian thực từ SystemConfig.

---

## 4. Hệ Sinh Thái AI T5Edu

### 4.1 Tổng Quan AI Ecosystem

AI là lớp năng lực cốt lõi của T5Edu. Hệ thống sử dụng LangChain, LangGraph, Gemini, OpenAI, RAG, pgvector và web search để hỗ trợ tạo nội dung, chấm bài, phỏng vấn, trợ giảng, phân tích tài liệu và tìm kiếm ngữ cảnh.

Mọi AI workflow có thao tác dừng đều truyền `AbortSignal` từ request hoặc lệnh hủy xuống LangGraph, model và tool. Các run nền như Course Generator và ISTQB Importer dùng thêm cờ Redis để hủy xuyên nhiều worker; trạng thái `CANCELLED` là terminal và không bị promise chạy trễ đổi lại thành `FAILED` hoặc `COMPLETED`. Khi đã hủy, workflow không retry hay fallback sang provider AI khác.

Các workflow AI khởi chạy theo người dùng dùng `UserContext` đã xác thực để chọn nhóm model tập trung: Admin luôn dùng nhóm PRO, tài khoản PRO dùng PRO, còn tài khoản FREE dùng FREE.

Attachment pipeline dùng `UploadedFile`/Cloudflare R2 làm nguồn chuẩn. Chat và
Interview nhận `attachmentIds` thuộc user (Markdown URL nội bộ cũ vẫn được đọc
trong giai đoạn tương thích), sau đó service resolve và trích xuất file trước
khi graph chạy. Tài liệu PDF/DOCX đi qua parser cục bộ; ảnh và ảnh nhúng có thể
đi qua vision boundary. DeepSeek Vision là provider primary sau gate nội bộ
`AI_DEEPSEEK_VISION_ENABLED`, với Gemini và OpenAI fallback; gate mặc định tắt
cho đến khi operator bật. Provider `file_id`, base64 và binary không được lưu
vào lịch sử chat hoặc checkpoint.

### 4.2 AI Tutor Multi-Agent ReAct Architecture

AI Tutor sử dụng kiến trúc **Multi-Agent ReAct** với 4 agent chuyên biệt, tự động phân loại ý định và Reflect chất lượng câu trả lời.

**4 Agent chuyên biệt:**

| Agent          | Khi nào kích hoạt                     | Ví dụ câu hỏi                                   |
| -------------- | ------------------------------------- | ----------------------------------------------- |
| **Tutor**      | Hỏi đáp bài học, giải thích khái niệm | "Test case là gì?", "Giải thích boundary value" |
| **Practice**   | Yêu cầu bài tập, quiz, kiểm tra       | "Cho tôi 5 câu trắc nghiệm ISTQB", "Luyện tập"  |
| **Diagnostic** | Phân tích lỗ hổng, tạo lộ trình       | "Tôi nên học gì tiếp?", "Phân tích điểm yếu"    |
| **Career**     | Tư vấn nghề nghiệp, phỏng vấn         | "Junior QA cần gì?", "Chuẩn bị phỏng vấn"       |

**Luồng xử lý:** Người dùng gửi tin nhắn → Supervisor phân loại intent (keyword → URL → LLM fallback) → Agent chuyên biệt xử lý (có thể gọi tools, tạo quiz) → Reflect đánh giá chất lượng → Nếu chưa đủ tốt, agent retry cải thiện → Respond tổng hợp câu trả lời cuối cùng.

**Reflection Loop:** AI tự đánh giá câu trả lời theo 3 tiêu chí (Relevance, Completeness, Educational Quality). FREE tier được 2 lần Reflect, PRO tier được 3 lần. Câu hỏi đơn giản tự động bỏ qua Reflect để giảm latency.

UI hiển thị agent đang xử lý qua `AgentBadge` (màu primary accent) và tiến trình xử lý qua `ToolCallBadge`. Trạng thái xử lý dùng `step-messages.ts` với giọng trợ giảng cần mẫn.

### 4.3 Dynamic Tool Injection

Dynamic Tool Injection giúp giảm token context và giảm hallucination. Hệ thống phân tách tools thành 3 lớp:

- **Global Tools:** Luôn sẵn sàng cho mọi agent (`get_site_navigation`, `update_user_memory`, `get_system_configs`).
- **Agent-Specific Tools:** Mỗi agent nhận subset phù hợp (VD: Tutor nhận `get_lesson_content`, Diagnostic nhận `get_user_learning_stats`).
- **URL Deep Context Tools:** Chỉ nạp khi URL nằm đúng miền nghiệp vụ như `/courses/`, `/blogs/` hoặc `/t5lab/`.
- **Search Tools:** Ưu tiên Brave Search, fallback Tavily Search nếu thiếu API key.

### 4.4 AI Business Context Từ README

AI chatbot có thể tra cứu `README.md` để hiểu nghiệp vụ T5Edu. README được chia heading theo module để chatbot xác định đúng phạm vi trước khi đọc chi tiết.

### 4.5 AI Course Generator

AI Course Generator giúp admin tạo khóa học từ tài liệu đầu vào. Luồng chính:

1. Admin tải tài liệu.
2. AI ingest và trích xuất nội dung.
3. AI sinh dàn ý khóa học.
4. Admin duyệt hoặc chỉnh sửa human-in-the-loop.
5. LangGraph sinh bài học hoàn chỉnh.
6. Hệ thống sinh hình minh họa nếu phù hợp.

### 4.6 Hybrid Context Enrichment Cho Course Generator

Course Generator dùng chiến lược RAG theo tầng:

- **HIGH score từ 0.65 trở lên:** RAG đủ tốt, ưu tiên dùng tài liệu gốc.
- **MEDIUM score từ 0.45 đến dưới 0.65:** Bổ sung Web Search cơ bản.
- **LOW score dưới 0.45:** Bổ sung Web Search nâng cao.

Noise Filter loại bỏ chunks có similarity dưới 0.35 để tránh đưa dữ liệu nhiễu vào prompt.

### 4.7 Two-Phase Image Generation Cho Bài Lý Thuyết

Hình ảnh minh họa được sinh sau khi nội dung bài học đã hoàn tất:

1. Sinh nội dung bài học dạng text.
2. Đọc lại nội dung để tạo image prompt tiếng Anh.
3. Sinh ảnh bằng OpenAI `gpt-image-2` hoặc provider tương ứng.
4. Upload ảnh lên R2.
5. Chèn Markdown image vào vị trí phù hợp.

Luồng này chỉ áp dụng cho bài THEORY. Bài EXERCISE và QUIZ không tự động sinh ảnh để tránh hình minh họa thừa.

### 4.8 AI Auto-Grading Và External Extractor

AI Grading chấm bài học viên theo thang điểm và nhận xét chi tiết. Hệ thống có thể hiểu nhiều định dạng đầu vào:

- Google Sheets.
- PDF.
- DOCX.
- Ảnh lỗi hoặc screenshot qua Vision Model.
- Markdown và văn bản thường.

AI Grader ghi nhớ phản hồi kỳ trước để kiểm tra học viên đã sửa đúng lỗi cũ hay chưa, đồng thời nạp trực tiếp `Profile.aiSummary` (điểm mạnh, điểm yếu, lỗi hay lặp lại, phong cách học) của học viên sở hữu bài nộp để cá nhân hóa lời khuyên và phân tích tiến độ.

Quy trình thẩm định tuân thủ **Bộ quy tắc thẩm định tính đúng đắn & bao phủ toàn diện tổng quát (General Assessment Heuristics)**: đối chiếu từng phần của đề bài, bắt buộc phân loại `WRONG` hoặc `MISSING` khi phát hiện khẳng định sai lệch bản chất kỹ thuật / ngộ nhận nguyên lý cơ bản (không dùng phần đúng để bù trừ cho phần sai). Feedback generator nhận bài làm thực tế `submissionContent` để trích dẫn trung thực phát biểu của học viên và chống ảo giác bao biện.

Prompt chấm bài được siết thêm quy tắc **Template Preservation**: các placeholder runtime như `{{user.name}}` phải giữ nguyên literal đủ 2 cặp ngoặc nhọn. AI bị cấm rút gọn thành `{user.name}` để tránh lỗi biên dịch template ở lớp hiển thị.

Input ảnh dùng vision routing riêng: DeepSeek Vision (`deepseek-v4-flash-vision-exp`)
là primary khi gate bật, sau đó Gemini Flash (`gemini-3.6-flash`) và GPT Luna
(`gpt-5.6-luna`). Files API của DeepSeek chỉ nhận JPEG/PNG/GIF/WebP với
`purpose=user_data` và expiry hữu hạn; PDF/DOCX không upload vào Files API.
Fallback luôn dựng lại inline image từ bytes R2 nên không dùng lại provider ID.
Prompt testcase chỉ dùng ngoặc nhọn cho biến LangChain thật hoặc literal đã
escape.

### 4.8.1 Attachment processing cho các workflow

Auto-fill Profile và Profile Summary giữ chiến lược text-first cho CV; PDF scan
được thử đọc qua ảnh trang đã trích xuất với giới hạn số ảnh/ký tự. Grading dùng
chung external extractor và cancellation boundary. T5Docs enrich Markdown lúc
upload, T5Lab thêm visual chunks lúc index để không trả chi phí vision ở mỗi lượt
sinh testcase. Chat/Interview chỉ đưa context text bounded, được đánh dấu là dữ
liệu không đáng tin cậy, vào graph; nội dung gốc vẫn là Markdown mà người dùng
đã gửi.

### 4.9 AI Mock Interview

AI Mock Interview là tính năng nâng cao. AI đóng vai Lead QA, hỏi đáp theo năng lực học viên và tạo báo cáo phỏng vấn.

Tính năng chính:

- Sinh câu hỏi theo ngữ cảnh khóa học.
- Đọc catalog khóa học và chi tiết bài học.
- Bắt buộc gọi `get_lesson_content` trước khi hỏi sâu về bài học cụ thể.
- Không tăng `questionCount` khi response chỉ chứa tool calls.
- Có thể kết thúc để tạo báo cáo năng lực dạng JD-friendly.
- Có thể dùng Web Search cho câu hỏi real-time.

### 4.10 ISTQB Importer Và Ôn Thi Chứng Chỉ

ISTQB Importer dùng LangGraph human-in-the-loop để trích xuất câu hỏi từ PDF đề thi gốc:

1. `ingestNode` đọc file PDF.
2. `metadataExtractorNode` nhận diện metadata.
3. `approvalGateNode` dừng để admin duyệt.
4. `questionExtractorNode` trích xuất câu hỏi.
5. `saveNode` lưu vào hệ thống.

Hệ thống hỗ trợ dịch tiếng Anh sang tiếng Việt, glossary chuyên ngành, deduplication, dual-language, countdown timer, auto-advance và báo cáo theo chương.

### 4.11 AI Rate Limiting Và Quản Trị Hạn Mức

AI Chat và các workflow Gen-AI được bảo vệ bằng Redis ZSET sliding window. Dữ liệu có thể fallback hydrate xuống PostgreSQL để tránh mất thống kê khi cache hết hạn. Hạn mức được phân rã theo tier, theo tuần hoặc tháng tùy nghiệp vụ.

### 4.12 Local Embedding & RAG Fallback

Để giữ khả năng tìm kiếm ngữ cảnh khi cloud embedding không khả dụng, T5Edu chạy model local ngoài web process:

- **Local Embedding**: `all-MiniLM-L6-v2` q8 chạy bằng Transformers.js trong PM2 worker `t5edu-embedding`.
- **Tối ưu hiệu năng**: Next.js không load model trực tiếp, chỉ gửi request qua Redis để tránh làm nặng process web.
- **Tính tương thích**: Vector 384-dim được zero-pad lên 768-dim để tìm kiếm cosine similarity nhất quán trên cùng một database pgvector.

### 4.13 Admin Analytics Chat Trợ Lý Dữ Liệu Quản Trị

Admin Analytics Chat là một LangGraph workflow **tách biệt hoàn toàn** với AI Tutor (user-facing), chạy dưới dạng popup `Panel side="right"` được mount lazy trong `AdminShell`. Mục tiêu: biến mọi câu hỏi tiếng Việt của admin thành **truy vấn raw đọc-thẳng-DB read-only** vì rất nhiều case cross-domain (Wallet + Submission, Order + Referral + EDU, Course + Lesson + Analytics) UI dashboard không thể show hết được.

**Vị trí trải nghiệm:**

- Mục "Trợ lý dữ liệu" trong group `Vận hành` của AdminShell + FAB nhỏ floating bottom-right.
- Lazy mount: chỉ khởi tạo sau lần đầu admin click; sau đó giữ trong cây với `opened={false}`.
- Panel desktop 50-55vw (rộng hơn user-chat) để chứa bento grid 2 cột; mobile fullscreen.

**Topology (tách biệt với `workflows/chat`):**

```
START → context/stateReset → supervisor (3-way: ANALYZE | OPERATE | CONVERSE)
   ANALYZE  → planner (subTasks[]) → executor (ReAct, parallel queries) → synthesizer (Bento) → reflect → respond → END
   OPERATE  → operator (propose tool) → synthesizer (Bento) → confirmGate (LangGraph interrupt) → mutationExecutor (sau resume=true) → respond → END
   CONVERSE → respond → END
```

**Persona admin:** "Trợ Lý Dữ Liệu T5Edu bình tĩnh, chuyên nghiệp, ngắn gọn, ưu tiên số liệu". KHÔNG dùng motif "sợ sếp mắng / sợ học viên buồn" của AI Tutor. Khi không chắc, nói thẳng "không đủ dữ liệu" thay vì bịa.

**Generative UI Bento grid (5 components):**

- `MetricCard`, `BarChartCard`, `PieChartCard`, `RankingList`, `DataTableCard` port từ `database-agents` nhưng restyle theo design token T5 (zinc + primary blue + diffusion-shadow utility, không phải Slate/Emerald). Synthesizer LLM chỉ chọn type + datasetIndex + columnMapping; data thật được rải vào props bằng code (zero-hallucination trên số).

**Bảo mật 3 tầng:**

1. **Postgres role read-only** (`t5_analytics_ro`): GRANT SELECT trừ `accounts/sessions/verification_tokens` + cột `password*`, `statement_timeout=10s`, `idle_in_transaction=5s`.
2. **`sqlGuard.ts`**: regex blacklist code-based chỉ cho `SELECT`/`WITH (CTE)`, chặn DDL/DML/COPY/`pg_*`/`SET ROLE`/multi-statement/comment-injection.
3. **`requireAdmin()`** ở route + service. Defence-in-depth.

**Mutation propose-then-confirm (Operator agent):**

3 tool propose (`proposeRequeueSubmission`, `proposeRefundOrder`, `proposeUnlockUser`) chỉ trả `{ proposalId, action, params, preview }`, KHÔNG thực thi. `confirmGateNode` dùng LangGraph `interrupt()` + emit SSE event `confirm_required`. Admin click confirm trên `ConfirmRequiredCard` → POST `/api/admin/admin-chat/resume` → `mutationExecutorNode` mới gọi service thật + ghi `AiWorkflowRun` audit. Nhánh OPERATE KHÔNG đi qua `reflectNode` (chống mutation chạy 2 lần).

**SSE protocol mới (mở rộng từ chat):** `subtask` (per-query progress), `generative_ui` (component build xong, không parse XML từ delta), `confirm_required` (mutation interrupt). Lưu DB `AdminChatMessage.content` = text + serialized XML tags để re-render thread cũ.

**Tách biệt 100%:** `src/lib/langchain/workflows/admin-chat/`, `tools/admin/`, `services/adminChat/`, `components/admin-chat/`, `useAdminChatStore`, `useAdminChatStream`, models `AdminChatThread/AdminChatMessage`. Không share state với `useChatStore` hay `workflows/chat`.

Plan kỹ thuật: `plans/PLAN-076-admin-analytics-chat.md`. Master flag `ADMIN_CHAT_ENABLED` (default OFF, bật sau khi DDL Postgres role apply trên staging).

**Trạng thái triển khai (2026-05):** Milestone 0-5 hoàn thành schema (`AdminChatThread` + `AdminChatMessage`), `prismaReadonly` infra, `sqlGuard` + 25/25 test, 5 services admin-chat (chat + rate-limit + schema + metric + entity + mutation), LangGraph graph đầy đủ 11 nodes (context/stateReset/supervisor/planner/executor/operator/tools/synthesizer/reflect/confirmGate/mutationExecutor/respond), 10 tools (6 read-only + 4 propose), 5 generative-ui components Konsta-styled, AdminShell popup lazy-mount, `/api/admin/admin-chat/{stream,resume,threads/[id]}` với `requireAdmin` + Sentry capture. **Bước cuối trước GA (ops, không code):** Apply DDL role `t5_analytics_ro` trên staging + smoke test 10 câu hỏi mẫu + toggle `ADMIN_CHAT_ENABLED = true`.

---

## 5. T5Lab - AI Test Management System

### 5.1 Tổng Quan T5Lab

T5Lab là hệ thống quản lý testcase thông minh, mô phỏng trải nghiệm Jira cho QA/Tester. T5Lab giúp học viên và nhóm dự án quản lý Pages, Features, Testcases, assignee, trạng thái, rủi ro, coverage và báo cáo.

### 5.2 Cấu Trúc Dữ Liệu T5Lab

T5Lab tổ chức dữ liệu theo cấu trúc phân tầng:

`Project -> Page / Directory -> Group Feature -> Feature -> Testcase`

Hệ thống hỗ trợ nested pages bằng Recursive Zod Schema và quan hệ parent-child.

### 5.3 Cộng Tác Và Phân Quyền

T5Lab hỗ trợ làm việc nhóm với RBAC:

- PO, PM, Tester, Developer và Guest.
- Guest và Developer ở chế độ read-only theo cấu hình phân quyền.
- Hỗ trợ gửi email mời cộng tác.
- Dialog Konsta được dùng thay cho alert hoặc confirm native.

### 5.4 Assignee Và Kanban Board

Danh sách thành viên được lưu ở global state để assign nhất quán. Testcase có thể được gán người phụ trách, kéo thả giữa các cột Kanban và lưu thứ tự xuống database.

### 5.5 Upload Tài Liệu Và RAG Ingest

Người dùng có thể upload tài liệu dự án như PDF, DOCX hoặc Markdown. Hệ thống
chunk, embed và lưu vector để phục vụ AI sinh Pages, Features và Testcases.
Tài liệu có sơ đồ/ảnh nhúng được visual-enrich bounded lúc index; chunk hữu ích
vẫn được giữ nếu một ảnh lỗi. Pipeline RAG lọc chunk theo ngưỡng similarity,
kèm bản đồ tài liệu sau ingest, tái sử dụng ngữ cảnh đã truy vấn ở verifier và
khi RAG kém cho phép model gọi công cụ **đọc tài liệu theo yêu cầu**
(`read_project_documents`) trước khi sinh cấu trúc có schema.

### 5.6 AI Pipeline Ba Giai Đoạn

T5Lab dùng LangGraph pipeline gồm:

1. **Pages Generator:** Sinh cấu trúc màn hình hoặc thư mục từ tài liệu.
2. **Features Generator:** Sinh Group Features và Features.
3. **Testcases Generator:** Sinh testcase theo từng feature hoặc phạm vi nhỏ.

Backend có strict validation để ngăn AI sinh feature trực tiếp ở tầng root hoặc tạo cấu trúc sai cấp.

### 5.7 Lazy Loading Và Data Persistence

Sidebar T5Lab dùng hybrid lazy-loading để hiển thị cây dự án nhanh khi reload. DnD persistence đồng bộ index testcase xuống database để đảm bảo trạng thái không mất sau khi tải lại.

### 5.8 Export Excel Và Tải Tài Liệu

T5Lab hỗ trợ export toàn bộ testcases sang Excel. Logic export có xử lý định dạng, bỏ cột dư thừa và chỉ điền "Test Executed by" cho testcase đã được thực thi.

### 5.9 T5Lab Pricing Và Pay-Per-Stage Billing

Chi phí AI trong T5Lab được tính theo 3 chặng:

- Pages generation.
- Features generation.
- Testcases generation.

Mức sàn generation là 1,000 VND. QR nạp nhanh có mức điền sẵn tối thiểu mặc định 5,000 VND, quản trị bằng `WALLET_MIN_DEPOSIT`; chuyển khoản thủ công vẫn chấp nhận mọi số tiền dương. PRO hoặc tier đặc biệt có thể được áp dụng chiết khấu theo cấu hình.

### 5.10 Analytics Chất Lượng Kiểm Thử

T5Lab hỗ trợ phân tích risk, ROI, defect leakage, coverage và chất lượng testcase để giúp học viên hiểu tư duy quản trị kiểm thử.

---

## 6. Gói PRO, EDU Benefits & Referral

### 6.1 Tổng Quan Gói PRO

PRO là gói nâng cấp dành cho học viên muốn dùng năng lực AI nâng cao và ưu đãi chi phí. PRO được mua qua Order và có thể thanh toán bằng ví hoặc luồng nạp tiền.

### 6.2 Chức Năng Dành Cho Học Viên PRO

- **Hạn mức AI Tutor/Chat tăng 10x:** FREE (5/2h · 20/tuần · 50/tháng) → PRO (50/2h · 200/tuần · 500/tháng). Đây là USP thực tế và khác biệt rõ nhất. AI Mock Interview cũng chạy qua hạn mức chat nên PRO dùng được nhiều hơn gấp 10.
- **AI planner nâng cao + 3 Reflection passes** (FREE: 2, PRO: 3).
- Giảm giá AI Grading theo cấu hình (`PRO_AI_DISCOUNT_PERCENT`).
- Có thể được hưởng PRO Cashback nếu không thuộc luồng EDU bị loại trừ.
- Portfolio public có theme cao cấp và tính năng xuất CV PDF (`pdfExportEnabled = true`).
- Chứng nhận khóa học dùng theme PRO đồng bộ trên web, PDF và email; cooldown tạo PDF/gửi lại ngắn hơn FREE theo cấu hình hệ thống.
- Ưu đãi T5Lab (giá AI generation thấp hơn, không giới hạn dự án) và T5Docs Edit Mode.

> **Lưu ý:** AI Mock Interview là tính năng có sẵn cho **cả FREE và PRO** khác biệt nằm ở hạn mức chat, không phải khóa tính năng.

### 6.3 PRO Cashback

PRO Cashback tự động hoàn tiền vào ví khi nâng cấp PRO theo `SystemConfig`. Mặc định có thể là {{configs.PRO_CASHBACK_AMOUNT}} VND tùy cấu hình. Nếu người dùng là EDU và đang được giảm giá PRO theo EDU, hệ thống không chạy PRO Cashback để chống lạm dụng.

### 6.4 EDU Benefits Cho Email Giáo Dục

Người dùng có email `.edu`, `.edu.vn` hoặc `.edu.*` được hưởng quyền lợi giáo dục:

- **Welcome Bonus:** Cộng `EDU_CASHBACK_AMOUNT` vào ví khi đăng ký.
- **PRO Discount:** Giảm `EDU_PRO_DISCOUNT_PERCENT` khi nâng cấp PRO.
- **Course/Lesson Discount:** Giảm `EDU_COURSE_DISCOUNT_PERCENT` khi mua khóa học hoặc bài học lẻ.

Admin có công cụ scan để cấp bù quyền lợi EDU cho người dùng cũ. Việc cấp quyền lợi phải idempotent thông qua `isEduVerified`.

### 6.5 Referral Affiliate Program

Mỗi người dùng có link giới thiệu cá nhân dạng `?ref=CODE`. Khi bạn bè được giới thiệu nạp tiền hoặc phát sinh giao dịch đủ điều kiện, người giới thiệu nhận cashback vào ví.

Luồng referral hỗ trợ:

- Sepay deposit.
- Admin cộng tiền.
- Mua khóa học.
- Mua chương hoặc bài lẻ.
- Nâng cấp PRO.

Reward được lưu dạng `REF_CASHBACK` để tách khỏi `DEPOSIT` thông thường. Attribution dùng localStorage và HttpOnly cookie bridge cho Google OAuth.

### 6.6 Cấu Hình Referral

Các tham số referral được quản lý bằng `SystemConfig`:

- `REF_FIRST_TOPUP_PERCENT`.
- `REF_FIRST_TOPUP_MAX`.
- `REF_RECURRING_PERCENT`.

First top-up có thể có mức cap. Các lần tiếp theo có thể nhận phần trăm không cap tùy cấu hình.

---

## 7. Đơn Hàng, Thanh Toán & Ví Điện Tử

### 7.1 Tổng Quan Financial Ecosystem

T5Edu hợp nhất các hành động có phí vào khái niệm Order. Mọi giao dịch lớn như nâng cấp PRO, mua khóa học, mua bài học hoặc thanh toán bằng Sepay đều được quản trị theo Order, OrderItem, PaymentLog và WalletTransaction.

### 7.2 Order Và OrderItem

Mỗi giao dịch có phí phải sinh:

`Order -> OrderItem`

Các loại order có thể bao gồm:

- `PRO_UPGRADE`.
- `COURSE`.
- `LESSON`.
- Các gói hoặc sản phẩm mở rộng tùy cấu hình.

AI Grading là ngoại lệ vì trừ ví trực tiếp cho lượng tiêu hao nhỏ.

### 7.3 Ví Điện Tử Nội Bộ

Ví điện tử lưu số dư học viên và lịch sử giao dịch. Người dùng có thể:

- Nạp tiền qua QR Sepay.
- Dùng ví mua khóa học hoặc bài lẻ.
- Nhận cashback từ referral, PRO hoặc EDU.
- Nhận refund hoặc điều chỉnh từ admin.

### 7.4 Sepay QR Deposit

Mỗi người dùng có luồng nạp tiền qua QR Sepay. `TopUpModal` đọc `WALLET_MIN_DEPOSIT` từ client `SystemConfig` store, mặc định 5.000 VND, còn action tạo QR nạp nhanh chuẩn hoá lại theo cùng cấu hình phía server. QR thủ công tại `/wallet` không cố định amount (`0`) để người dùng tự nhập; webhook cộng mọi khoản chuyển ví có số tiền dương và không áp `WALLET_MIN_DEPOSIT`. Modal theo dõi trạng thái giao dịch để cập nhật số dư sau khi thanh toán thành công.

### 7.5 PaymentLog Và Replay Protection

PaymentLog ghi nhận webhook, mã giao dịch, trạng thái xử lý và dữ liệu xác minh. Với Order, fulfillment được chạy trước khi ghi PaymentLog hoàn tất để lỗi cấp quyền không biến thành giao dịch đã ghi log nhưng chưa cấp quyền. Sepay Double-Check gọi API xác minh chéo để chống fake payload; replay đã hoàn tất trả HTTP 200 và không chạy lại cashback/email/commission.

### 7.6 Admin Điều Chỉnh Ví

Admin có thể cộng hoặc trừ tiền ví với preview trạng thái. Các loại giao dịch có thể gồm:

- `DEPOSIT`.
- `REFUND`.
- `REF_CASHBACK`.
- `PRO_CASHBACK`.
- `EDU_WELCOME_BONUS`.
- `BONUS_EXPIRED` (cron Expiry Wallet thu hồi bonus hết hạn xem 7.8.1).
- `BONUS_RESTORED` (admin khôi phục bonus đã expired xem 7.8.1).
- `T5DOCS_ASK`, `T5DOCS_EDIT`, `T5DOCS_PROJECT_SLOT` (T5Docs billing).

### 7.7 Anti-Spam Order

Hệ thống tái sử dụng Order `PENDING` trong 72 giờ. Riêng `PRO_UPGRADE` có `Order.proUpgradeKey` unique theo user và bị chặn nếu user đã có Order PRO `PAID`, nên webhook lỗi hoặc admin duyệt thủ công không tạo thêm giao dịch PRO cho cùng tài khoản.

### 7.8 Wallet Spend Motivation (Tiêu Để Có Động Lực)

T5Edu triển khai 3 cơ chế bổ trợ để biến ví từ "kho tiền nằm yên" thành vòng quay học tập có động lực. Cả 3 cơ chế bật/tắt độc lập qua `SystemConfig`, mặc định OFF khi deploy. Plan kỹ thuật chi tiết: `plans/PLAN-074-wallet-spend-motivation.md`.

#### 7.8.1 Expiry Wallet TTL cho tiền thưởng

- Số dư ví tách thành hai pool: `realBalance` (tiền nạp Sepay, không hết hạn) và `bonusBalance` (REF cashback, PRO cashback, EDU welcome bonus). `walletBalance` là tổng authoritative; mọi mutation khóa tuần tự theo user và giữ `walletBalance = realBalance + bonusBalance`, đồng thời `bonusBalance = SUM(remainingBonus > 0)`.
- Bonus có hạn sử dụng `WALLET_EXPIRY_DAYS` ngày (mặc định {{configs.WALLET_EXPIRY_DAYS}}). Cron `0 3 * * *` thu hồi bonus đã hết hạn và ghi giao dịch `BONUS_EXPIRED`.
- Khi user mua hàng, hệ thống trừ FIFO: bonus sắp hết hạn nhất bị trừ trước, phần còn lại trừ từ `realBalance`. Mỗi `WalletTransaction` ghi rõ `bonusApplied / realApplied` để audit.
- UI hiển thị countdown khi tiền thưởng còn ≤ `WALLET_EXPIRY_WARN_DAYS` (mặc định {{configs.WALLET_EXPIRY_WARN_DAYS}}). Admin có thể Scan, Apply N ngày cho bonus cũ chưa có TTL, hoặc Restore bonus đã hết hạn (transaction `BONUS_RESTORED`).
- `WalletTransaction.idempotencyKey` chống replay cho deposit, order, grading, T5Lab/T5Docs, reward, payout, expiry, restore và refund. `amount` luôn là magnitude dương; chiều giao dịch suy từ `balanceAfter - balanceBefore`. `REFUND` chỉ dùng cho hoàn tiền, admin debit dùng `ADMIN_ADJUSTMENT`.
- `scripts/wallet-integrity-repair.ts` audit/repair V3 theo `PLAN-092`: mặc định APPLY toàn bộ user, `--dry-run` để xem trước. V3 replay ledger: `DEPOSIT` vào real pool, nhưng legacy broadcast rows có text `Thưởng liên kết hệ thống`/`Tặng quà chào mừng`/`Chúc mừng 500 users` được override thành bonus; credit khác vào bonus, debit trừ bonus-first và repair V1 zero-delta bị loại khỏi credit. Phần bonus từng bị V2 chuyển nhầm sang real được gia hạn 30 ngày từ cutoff khi dựng lại; bonus vốn đã nằm đúng bucket nhưng quá hạn vẫn không được tự gia hạn. Script dùng canonical checksum giữa audit/apply, per-user lock và post-verify.

#### 7.8.2 Contextual Spend Triggers Gợi ý đúng thời điểm

- Thay vì spam thông báo, hệ thống chỉ gợi ý mua khi user vừa hoàn thành một moment of truth.
- 2 trigger ban đầu: `CHAPTER_NEXT_CTA` (sau khi học hết chương cuối có chương kế ≥ {{configs.SPEND_TRIGGER_CHAPTER_MIN_PRICE}}đ) và `T5LAB_TESTCASE_CTA` (khi T5Lab project sang trạng thái `PAGES_READY`).
- Mỗi trigger có cooldown {{configs.SPEND_TRIGGERS_COOLDOWN_HOURS}}h (Redis), chỉ hiển thị giá thực tế tính qua `tierBenefitService` (đã ăn discount EDU/PRO), không bịa khuyến mãi.
- Pages publish context qua `useSpendTriggerStore`, `SpendTriggerHost` mount sẵn trong `MainShell` xử lý dialog (Konsta) sau delay 800ms để không đè LCP.

#### 7.8.3 Spend-to-Earn Loop Tiêu nhiều, nhận nhiều

- Mọi giao dịch tiêu ví (qua `spendEngineService.charge`) cộng lifetime `User.spendXP` (1 VND = 1 XP). Không reset theo tháng để tránh áp lực giả.
- Khi vượt mốc trong `SPEND_XP_MILESTONES` (JSON ở SystemConfig), user nhận ngay phần thưởng:
  - **AI_GRADE_FREE**: 1 lượt chấm bài AI miễn phí, không trừ ví khi consume (race-safe qua `updateMany`).
  - **BADGE_HOC_CHIEN**: Badge "Học Chiến" hiển thị vĩnh viễn cạnh tên trên trang `/p/[slug]`.
- Idempotent qua `SpendXPLog.relatedOrderId @unique` và `SpendXPReward.unique(userId, milestoneKey)`. Lỗi hook không rollback `charge`.

---

## 8. Hồ Sơ Năng Lực & Portfolio Bento 2.0

### 8.1 Tổng Quan Professional Identity

Portfolio Bento 2.0 nâng cấp hồ sơ cá nhân thành CV điện tử. Hệ thống giúp học viên chứng minh năng lực bằng dữ liệu học tập, kỹ năng, dự án, kinh nghiệm, chứng nhận khóa học và hoạt động thực tế.

### 8.2 Public Profile Và CV Điện Tử

Hồ sơ public có thể chia sẻ với nhà tuyển dụng. Dữ liệu gồm:

- Thông tin cá nhân.
- Kỹ năng.
- Dự án.
- Kinh nghiệm.
- Hoạt động học tập.
- Heatmap 52 tuần.
- Tiến độ khóa học và bài nộp nổi bật.
- Chứng nhận hoàn thành khóa học, với liên kết xác thực công khai dạng `/certificates/{user-slug}/{course-slug-at-issue}` khi hồ sơ bật công khai.
- Trong khóa học, mục Chứng nhận luôn mở `/courses/{course-slug}/certificate` để học viên xem trước chứng nhận và checklist còn thiếu; chỉ thao tác gửi email/tải PDF bị khóa cho tới khi đủ evidence. Tiến độ khóa học dùng bài lý thuyết đã ghi nhận và bài tương tác đã nộp, không dùng vị trí bài xa nhất từng mở.
- Danh sách khóa học và lesson detail có banner giới thiệu dấu mốc chứng nhận; người học có thể thu gọn/mở lại với animation và trạng thái compact được giữ khi chuyển bài trong cùng phiên.
- Mã chứng nhận, ngày cấp và thời lượng học giữ nguyên theo lần cấp đầu. Kết quả thực hành được tính lại từ những lần làm bài sau đó, nên một retry tốt hơn sẽ xuất hiện đồng nhất trên trang chứng nhận, PDF, email, hồ sơ, Portfolio PDF và AI tool.
- AI Tutor đọc được chứng nhận qua tool chuyên biệt và qua cả ngữ cảnh thống kê/hồ sơ, nên các câu hỏi tổng hợp về thành tích vẫn nhận đúng mã, ngày cấp, thời lượng, kết quả hiện tại và link xác thực khi hồ sơ công khai. Admin Chat sinh schema context động từ `prisma/schema.prisma` (table/column mapping, enum, FK và comment), cache theo hash của schema và loại các model auth nhạy cảm bằng denylist nhỏ.
- PDF dùng heading serif và email chứng nhận phản chiếu cùng frame, palette, số liệu và hierarchy. Trong cooldown, owner có thể xác nhận trừ ví theo `CERTIFICATE_RATE_LIMIT_BYPASS_PRICE` (mặc định 10.000đ) để gửi/tải ngay; request đang `PENDING` không được bypass.

### 8.3 AI Bio Generator Và Auto-Fill Profile

AI có thể đọc CV PDF hoặc DOCX của học viên để tự động điền kỹ năng, dự án và kinh nghiệm. Workflow được tách thành `auto-fill-profile` và `profile-summary` để tối ưu luồng trích xuất. CV do hệ thống upload được đọc trực tiếp từ Cloudflare R2, có timeout 30 giây và giới hạn 10 MB; PDF scan/ảnh không có text layer được báo riêng để người dùng đổi sang PDF có thể chọn chữ hoặc DOCX.

### 8.4 Edge RAG Bóc Tách CV

Khi học viên tải CV lên, LangGraph bóc tách thông tin thành timeline, kỹ năng và dự án. Dữ liệu sau đó được lưu vào profile để hiển thị trong Portfolio Bento.

### 8.5 Bulk Replace O(1)

Các thao tác cập nhật danh sách kỹ năng, dự án và kinh nghiệm dùng bulk-replace Server Actions. Hệ thống thực hiện `deleteMany` và `createMany` trong Prisma transaction để tránh N+1 query.

### 8.6 Slug History Và SEO Profile

Khi học viên đổi slug portfolio, hệ thống lưu Slug History để redirect 301. Điều này bảo vệ link CV đã chia sẻ, tránh lỗi 404 và duy trì tín hiệu SEO.

### 8.7 Theme PRO Và Xuất Resume PDF

Portfolio public có thể bật theme cao cấp cho người dùng PRO. Hệ thống cũng hỗ trợ render PDF để xuất resume chuyên nghiệp.
PDF Portfolio hiển thị chứng nhận đã cấp; chỉ profile công khai mới kèm liên kết xác thực. Theme chứng nhận và phần PDF luôn lấy theo tier hiện tại của chủ hồ sơ, không theo người xem.
Lần delivery đầu tiên hiển thị confetti liên tục 30 giây ở cả workspace khóa học và manager `/profile`, trừ khi người dùng bật giảm chuyển động.
Hỗ trợ tuỳ chọn chuyển đổi chủ đề tại UserMenu và MobileMenu giúp người dùng PRO có thể tắt giao diện PRO (màu hổ phách) và quay về giao diện thường (màu xanh lam) tuỳ theo sở thích cá nhân. Switch này được thiết kế riêng với màu sắc tuỳ biến sang gradient màu cam hổ phách (`.bg-pro-gradient`) khi kích hoạt, trạng thái lưu trong LocalStorage thông qua Zustand.

---

## 9. Blog, SEO, Bản Tin & Phân Phối Nội Dung

### 9.1 Tổng Quan Knowledge Hub

Knowledge Hub là hệ thống nội dung giúp T5Edu thu hút organic traffic, giáo dục thị trường và cung cấp kiến thức nền tảng cho học viên Tester.

### 9.2 Blog CMS Và Markdown Editor

Admin có thể tạo bài viết chuyên sâu bằng Markdown Editor. Blog hỗ trợ:

- Title, slug và metadata SEO.
- Tags.
- Thumbnail.
- Markdown content: Tự động trích xuất Mục lục (TOC) và gán Anchor IDs cho headings.
- Blog Bottom Toolbar: Thanh điều hướng cố định tích hợp Progress bar, nút cuộn TOC và scroll thông minh.
- View count.
- Comments: Tích hợp Toast Notification của Konsta UI cho các thao tác Đăng/Xoá bình luận.
- Lượt đọc: user đăng nhập qua `UserView`; độc giả ẩn danh qua `deviceId` (thiết bị) được đăng ký toàn cục ở provider, lưu trên trình duyệt và bảng `UserDevice` / `DeviceView`, mỗi cặp user hoặc thiết bị chỉ tăng `view_count` một lần mỗi bài. Sau khi đăng nhập, lịch sử đọc trên thiết bị được gắn với tài khoản (không cộng thêm lượt). Cron hằng ngày có thể ghi nhận thêm một phần user chưa đọc để hỗ trợ retention (xem `AGENTS.md`).

### 9.3 Full-Text Search Blog Và Course

Blog và Course dùng PostgreSQL Full-Text Search. Trải nghiệm tìm kiếm hỗ trợ filter theo tác giả, tags, highlight snippet và truy vấn hybrid.

### 9.4 Auto-Blog Pipeline

Auto-Blog dùng LangGraph để tự động hóa quy trình viết bài:

`topicSelectorNode -> ideatorNode -> researcherNode -> outlinerNode -> dataVerifierNode -> writerNode -> imageGeneratorNode -> publisherNode`

Pipeline có thể nghiên cứu dữ liệu bằng crawler, lập dàn ý, viết bản thảo SEO, sinh ảnh và publish vào hệ thống. Sau khi publish, hệ thống gọi revalidate để clear ISR cache.

### 9.5 Image Generation Fallback Cho Blog & Course

Hệ thống cung cấp cơ chế fallback toàn diện cho hình ảnh (Auto-Blog và Course Generator):

- **Mặc định**: Ưu tiên OpenAI `gpt-image-2` generation. Nếu lỗi quota hoặc rate limit, hệ thống fallback sang Gemini image model.
- **Web Search Fallback**: Khi tắt cấu hình `AI_IMAGE_GENERATOR_ENABLED` (Kill Switch) trong Admin, hệ thống tự động ngắt AI sinh ảnh và chuyển sang tìm kiếm ảnh trên web (Ưu tiên Tavily Search, fallback Brave Search API). Ảnh tìm được sẽ tải về và upload lên Cloudflare R2 để lưu trữ nội bộ, tránh lỗi CORS và link chết.
- Lỗi sinh hoặc tải ảnh không làm sập toàn bộ luồng publish/luồng sinh bài nếu nội dung đã được tạo.

### 9.6 Facebook Social Distribution

Facebook Social Distribution tự động đăng blog đã publish lên Facebook Page. Luồng gồm:

1. Content Creator sinh nội dung social dưới 500 ký tự.
2. Facebook Poster đăng qua Graph API.
3. Hệ thống verify post.
4. Cập nhật `fbPostId` và `fbPostedAt`.

Luồng này không blocking. Facebook fail chỉ log warning và không ảnh hưởng blog đã publish.

### 9.7 Broadcast Notification System

Bảng tin toàn cục hiển thị thông báo động trên màn hình học viên. Tính năng chính:

- Floating Action Button dạng chuông.
- Có thể kéo thả và lưu vị trí bằng localStorage.
- Action button có thể mở URL, gọi script API hoặc kích hoạt payload.
- Có limit chống spam click.
- Admin có thể sắp xếp notification bằng DnD.

### 9.8 AI Markdown Surface & LLM Discovery

T5Edu hỗ trợ bề mặt đọc riêng cho AI/LLM:

- URL HTML canonical vẫn là `/path` cho người dùng, SEO truyền thống và browser.
- URL Markdown sạch là `/path.md`; root dùng `/index.md`.
- URL `/path.html` là alias HTML rõ ràng, kể cả khi requester là AI user-agent.
- `/llms.txt` giới thiệu nền tảng và các Markdown entrypoint chính.
- `/llms-full.txt` liệt kê nội dung public động như khóa học, blog, ISTQB.
- `/sitemaps.txt` cung cấp plain text URL map gồm HTML canonical và Markdown alternate.
- Homepage (`/`) phản hồi (cả HTML response và redirect 307 cho AI bot) đính kèm HTTP `Link` header (RFC 8288) quảng bá các tài nguyên cho agent: sitemap (`/sitemap.xml`), describedby (`/llms.txt`), và service-doc (`/llms-full.txt`).
- Bản ghi DNS-AID được công bố như bề mặt Internet-Draft/scanner compatibility trên nền RFC 9460 `SVCB`: `_a2a._agents` và `_index._agents` đều trỏ về domain chính bằng ServiceMode `SVCB`, giúp AI agent thử khám phá endpoint qua DNS. Script `scripts/publish-dns-aid.ts` hỗ trợ publish qua Cloudflare API và có `DNS_AID_DRY_RUN=1`; DNSSEC chỉ hoàn tất khi DS record Cloudflare sinh ra được publish ở registrar/parent zone.
- Hỗ trợ thương lượng nội dung (Content Negotiation): Các yêu cầu đi kèm header `Accept: text/markdown` gửi đến các route canonical công khai (như `/`, `/courses`, `/blogs`) sẽ được rewrite trực tiếp để trả về nội dung Markdown sạch với `Content-Type: text/markdown; charset=utf-8`, `X-Content-Type-Options: nosniff`, cờ `Vary: Accept` và tiêu đề `X-Markdown-Tokens` (chứa ước lượng số token của tài liệu). Proxy khóa MIME type ngay trên rewrite response để URL trang gốc không bị Next.js suy đoán lại thành `text/html`.
- Cấu hình file robots.txt thông qua Next.js metadata `src/app/robots.ts` tích hợp directive `Content-Signal: ai-train=yes, search=yes, ai-input=yes` cho tất cả các user-agent nhằm cho phép AI bot thu thập và huấn luyện trên dữ liệu công khai.
- Cung cấp điểm khám phá API Catalog tại `/.well-known/api-catalog` (RFC 9727) định dạng `application/linkset+json` liên kết đến các tài nguyên tài liệu/API và endpoint sức khỏe `/api/health`.
- Cung cấp điểm khám phá OAuth/OIDC Discovery tại `/.well-known/openid-configuration` (RFC 8414) như **compatibility metadata** cho agent/tooling; hiện không quảng bá public token flow và chỉ giữ `jwks_uri` placeholder tại `/api/auth/jwks`.
- Cấu hình điểm khám phá OAuth Protected Resource metadata tại `/.well-known/oauth-protected-resource` (RFC 9728) cho tài nguyên MCP public với scope hiện tại `public:read`.
- Hỗ trợ tài liệu `/auth.md` tại gốc dịch vụ và `/.well-known/oauth-authorization-server` để mô tả đúng trạng thái agent auth hiện tại: public MCP read-only đang mở, còn self-service registration/revoke vẫn chưa public.
- Cung cấp MCP public read-only tại `/api/mcp` và công bố MCP Server Card compatibility metadata tại `/.well-known/mcp/server-card.json` và `/.well-known/mcp.json`, được sinh từ registry thống nhất.
- Tool MCP `t5edu.get_public_navigation` dùng matching public route đã normalize/tách keyword và tự giảm nhiễu theo corpus route hiện có, nên query nhiều ý như `khóa học ISTQB PRO source-code blog` vẫn trả được các route liên quan mà không cần hardcode stop words. Public navigation bao gồm cả `/pro`, `/source-code`, `/README.md`, `/llms.txt`, `/llms-full.txt` và `/api/mcp`.
- Tool MCP `t5edu.get_public_page_content` đọc nội dung Markdown public bằng cùng service phía sau `/api/ai-readable` (`getAiReadableDocument`) cho các route như `/courses`, `/courses/[slug]`, `/blogs`, `/blogs/[slug]`, `/istqb`, `/pro`, `/source-code`; `/README.md` đọc qua `getReadmeMarkdown()`.
- Các tool search/list trả structured empty arrays khi không có kết quả. `t5edu.search_courses` chỉ trả mô tả tóm tắt để giảm payload; agent cần full outline/mô tả thì gọi tiếp `t5edu.get_course(slug)`.
- Cung cấp capability manifest JSON tại `/api/ai-native/capabilities` và index khám phá Agent Skills tại `/.well-known/agent-skills/index.json` với SHA-256 digest động cho `SKILL.md`.
- Tích hợp WebMCP experimental trong trình duyệt thông qua `WebMcpProvider`, đọc manifest từ `/api/ai-native/tools` và chỉ đăng ký tool khi browser thật sự có `modelContext` API và feature flag `AI_WEBMCP_ENABLED` đang bật.

Proxy chỉ redirect một allowlist AI user-agent bảo thủ sang `.md` (`GPTBot`, `OAI-SearchBot`, `ChatGPT-User`, `ClaudeBot`, `Claude-SearchBot`). Googlebot, browser thường và route private/admin/API không bị redirect sang Markdown.

Markdown được sinh qua service layer `src/lib/apis/services/aiReadable/`, cache bằng `cacheTag` + `cacheLife("minutes")`; các builder truy vấn/transform public corpus dùng remote Redis cache, còn Home/README/`llms.txt` thuần static giữ local cache. Cache được invalidate cùng các mutation course/blog/ISTQB/config. Listing pages ưu tiên ngữ cảnh đầy đủ cho AI: mô tả khóa học, outline chương/bài, excerpt và nội dung blog đã làm sạch, thay vì chỉ preview ngắn. Các section lặp lại phải gắn tên khóa học/bài viết vào heading và ngăn cách item bằng `---` để AI đọc không mất ngữ cảnh. Để tránh ô nhiễm danh mục Outline chính của trang Markdown đối với AI agents, nội dung mô tả chi tiết của từng khóa học, bài viết blog, và đề thi ISTQB được bao bọc trong khối code block `markdown ... `.

### 9.9 Public SEO HTML contract

Public HTML không phụ thuộc bot-only rendering. Ordinary `curl`, browser không JavaScript và Googlebot đều phải nhận facts public trực tiếp trong semantic tree; nội dung trong `script`, `template`, `[hidden]` hoặc `aria-hidden` không được tính. Route matrix gồm Home, course/blog list + detail, PRO, Source Code, ISTQB list + detail và `/p/:slug`.

- Public document sở hữu đúng một H1, canonical và JSON-LD phù hợp; desktop topbar chỉ hiển thị route label bằng text thường.
- Course detail dùng DTO allowlist: HTML/JSON-LD có full public description, highlights, public price và toàn bộ ordered chapter/lesson metadata, nhưng không serialize lesson body, answer key, protected asset hoặc enrollment/user state.
- Enrollment, EDU pricing, comments/views, attempt history, CTA theo session và portfolio view tracking là runtime islands; chúng không được thay thế public document bằng page-wide Suspense.
- Main chrome không gọi `usePathname()` trực tiếp: `RuntimePathnameProvider` cô lập hook trong observer rỗng, còn public children dùng pathname guest-safe mặc định. Home session personalization dùng cùng pattern để guest HTML luôn deterministic.
- Course/blog list prerender toàn bộ cached catalogue; query/filter trong URL chỉ lọc sau hydration. Ngày blog/portfolio trong public HTML dùng ngày tuyệt đối deterministic, không gọi relative time/`Date.now()` khi prerender.
- Tab dữ liệu public cũng theo progressive enhancement: `/source-code` và `/p/:slug` gửi tất cả panel có dữ liệu trong HTML/no-JS, rồi JavaScript dùng `?tab=` để chỉ hiển thị panel người xem chọn. `/courses` dùng `?filter=` (và `?q=`) sau hydration. Canonical của các URL này vẫn là đường dẫn không query.
- `.html` alias không làm dynamic detail mất static params: alias tĩnh dùng rewrite; alias detail course/blog/ISTQB trả nguyên response canonical static và vẫn giữ status 200/canonical HTML tương đương.
- Canonical public GET/HEAD đi trước NextAuth proxy để không tạo Auth.js cookie ngoài ý muốn. Protected routes vẫn giữ auth redirect.

---

## 10. Trung Tâm Bài Tập & Submission

### 10.1 Tổng Quan Submission Tracking

Submission Tracking quản lý toàn bộ bài nộp của học viên. Hệ thống gom trạng thái bài tập vào Action Center để học viên biết bài nào đang chờ chấm, thiếu, sai hoặc cần sửa.

### 10.2 Trạng Thái Bài Nộp

Các trạng thái nghiệp vụ gồm:

- `PENDING`: Đang chờ xử lý hoặc chờ chấm.
- `MISSING`: Thiếu dữ liệu hoặc thiếu bài.
- `WRONG`: Có lỗi cần sửa.
- `APPROVED`: Đã đạt yêu cầu.

Trạng thái thực tế phải dùng enum từ Prisma trong code, không hardcode string literal.

### 10.3 Submission Panel Và Konsta Dialog

Submission Panel dùng Konsta Dialog hoặc Popup để hiển thị danh sách bài tập. UI ưu tiên mobile-first, dễ scan và không dùng `alert()` hoặc `confirm()` native.

### 10.4 Infinite Scrolling

Danh sách bài tập hỗ trợ infinite scrolling để lấy dữ liệu realtime mà không làm treo app hoặc phình memory.

### 10.5 Email Notify Và Dashboard Update

Khi bài được chấm hoặc có kết quả mới, hệ thống có thể gửi email thông báo và cập nhật dashboard để học viên quay lại sửa bài hoặc học tiếp.

### 10.6 Câu Hỏi Gợi Mở (Exploratory Q&A)

Khi học viên làm bài đạt trạng thái `APPROVED`, hệ thống cung cấp tính năng **Trả lời câu hỏi gợi mở** qua luồng chat chuyên biệt để đào sâu kiến thức.

- **Luồng hoạt động**: Học viên bấm nút "Trả lời câu hỏi gợi mở" trên thẻ trạng thái bài nộp → Mở `ChatSidebar` ở chế độ `EXPLORATORY`, người dùng được tạo một `ChatThread` mới loại `ThreadType.EXPLORATORY`.
- **Lịch sử khởi tạo**: Thread bắt đầu với 2 tin nhắn được chuyển đổi tự động từ dữ liệu thực: tin nhắn user (nội dung bài nộp) và tin nhắn AI (feedback chấm bài gốc, vốn đã có sẵn câu hỏi gợi mở đầu tiên). Học viên tiếp tục trả lời ngay trên ngữ cảnh đó.
- **Ngữ cảnh AI**: Tuyến API SSE chat tự động phát hiện loại thread `EXPLORATORY`, truy vấn CSDL lấy đề bài, bài làm và feedback chấm bài trước đó để chuyển thành ngữ cảnh hệ thống gửi đến LangGraph.
- **Giám sát ý định (Supervisor)**: Nếu học viên hỏi vấn đề ngoài phạm vi bài tập (ví dụ: "í còn bao nhiêu tiền"), Supervisor Node tự động đổi route sang agent phù hợp (định tuyến thường) thay vì bị giới hạn trong cộng exploratory.
- **Hỏi đáp liên tục**: Agent `exploratory` bắt buộc sinh câu hỏi gợi mở mới sau mỗi lượt trả lời, tạo thành vòng lặp tương tác vô hạn. Không thay đổi trạng thái gốc của bài nộp.
- **Rate limit**: Sử dụng Rate Limit của luồng Chat (đa dạng hơn Grading).
- **exploratoryContext (JSON)**: Trường này lưu `{ submissionId: string, lessonId: string }` với mội `ChatThread` loại `EXPLORATORY`.

### 10.7 Làm Lại Bài Với Ngữ Cảnh Đối Chiếu (Contextual Retry)

Học viên có thể làm lại bài tập ở **mọi trạng thái đã chấm** (bao gồm cả `APPROVED`). Đây không phải là xóa bài cũ, mà là nộp bản mới với đầy đủ ngữ cảnh đối chiếu lịch sử.

- **UI**: Nút "→ Làm lại bài" hiển thị khi `submission.status !== "PENDING"` (điều kiện `canRetry`). Khi bấm, bài làm cũ được khôi phục vào trình soạn thảo để học viên chỉnh sửa trực tiếp.
- **AI chấm bài sánh đôi**: Khi AI chấm bài mới, cả hai workflow `grading/index.ts` và `testcase-grader/index.ts` tự động truy vấn bản nộp được chấm gần nhất trước đó (`status != PENDING`) của học viên, rồi đưa cả nội dung bài cũ lẫn feedback cũ vào prompt.
- **Evaluator so sánh**: `evaluator.ts` được hướng dẫn: so sánh bài mới với bài cũ, kiểm tra xem các điểm thiếu sót từ feedback cũ đã được khắc phục chưa, ghi nhận sự tiến bộ cụ thể trong nhận xét.
- **Testcase Grader sánh đôi**: Tương tự, `testcase-grader/index.ts` đối chiếu bảng testcase mới với bảng testcase cũ, chỉ ra sự cải thiện trong cột "AI Nhận Xét" và phần tổng nhận xét.
- **Không mất lịch sử**: Mỗi lần nộp tạo một bản ghi `Submission` mới, bản cũ vẫn còn nguyên trong CSDL.

---

## 11. Quản Trị, Vận Hành & Retention

### 11.1 Admin Dashboard

Admin Dashboard gom các nhóm nghiệp vụ:

- Nội dung.
- Khóa học.
- Blog.
- Người dùng.
- Đơn hàng.
- Ví.
- Báo cáo tài chính.
- AI workflows.
- Hệ thống và cấu hình.

Luồng vận hành Admin (PLAN-102) hiện hỗ trợ tìm học viên theo tên/email ở
`/admin/contacts` và tạo hội thoại idempotent ngay cả khi học viên chưa từng mở
trang liên hệ. Từ Học viên detail, admin có CTA Liên hệ, link enrollment tới
course detail và tab Đơn hàng dùng chung danh sách phân trang với `/admin/orders`.
Orders lọc server-side theo tên/email, trạng thái, khóa học và toàn bộ loại
`OrderItemType`; các nút Duyệt/Từ chối vẫn đi qua order service authoritative,
trong đó Từ chối chỉ chuyển `PENDING -> FAILED` một cách atomic.

Các identity user trên Orders, Chấm bài, Finance và bảng xếp hạng đều đi tới
`/admin/users/[id]`. AdminShell có link Tổng quan về `/admin`; bảng Top Học viên
Chăm chỉ tải infinite scroll theo snapshot cố định, sort phụ bằng `userId` để
rank ổn định khi có tie.

### 11.2 Báo Cáo Tài Chính

Báo cáo tài chính theo dõi:

- Net Revenue.
- Dòng tiền thực tế.
- Giao dịch ví.
- Order status.
- PaymentLog.
- Referral cashback.
- PRO cashback.
- EDU welcome bonus.

### 11.3 Contact 1:1 Và Roadmap

Hệ thống liên hệ 1:1 hỗ trợ chat Telegram-style giữa học viên và admin. Công nghệ dùng SSE và Redis Pub/Sub để phản hồi gần realtime.

Tính năng chính:

- Presence TTL bằng Redis.
- Fallback gửi email nếu người nhận offline.
- Học viên gửi góp ý hoặc báo lỗi.
- Hệ thống capture browser, screen size và OS.
- Góp ý tính năng được đưa vào Roadmap Kanban.
- Khi feature chuyển sang DONE, học viên có thể nhận reward vào ví.

### 11.4 Retention Lifecycle

Cron worker độc lập chạy ngoài web process bằng PM2 hoặc node-cron. Hệ thống quét các mốc vắng mặt:

- 1 tuần.
- 1 tháng.
- 3 tháng.

Sau đó gửi email cá nhân hóa để nhắc học viên quay lại học.

### 11.5 Automated Cron Jobs

Cron jobs có thể xử lý:

- Retention email.
- Facebook auto-post.
- Auto-blog.
- Revalidate cache.
- Các tác vụ nền theo `SystemConfig`.

### 11.6 Tracking Và Product Analytics

T5Edu dùng Microsoft Clarity và GA4 để hiểu hành vi người dùng. Các hành động đo lường như mua hàng, nạp tiền, nâng cấp PRO, submit bài và hoàn tất workflow phải được tracking bằng event có tiếng Việt có dấu.

### 11.7 Admin Analytics Chat Trợ Lý Dữ Liệu Quản Trị

Admin Analytics Chat là popup AI dành riêng cho admin, mount lazy trong `AdminShell` (mục "Trợ lý dữ liệu" trong group Vận hành + FAB bottom-right). Vai trò chính trong góc nhìn vận hành:

- **Trả nhanh các câu hỏi cross-domain UI không show hết:** "Top 10 user nạp tiền nhưng chưa mua khoá học", "Tỷ lệ submission trượt theo chương trong tháng cuối", "Top người dùng tích cực nhất tuần qua".
- **Drill-down theo follow-up chips:** Mỗi câu trả lời sinh 3-5 chip gợi ý drill-down (theo thời gian / segment / so sánh) admin chỉ click thay vì gõ lại.
- **Đề xuất thao tác có xác nhận (Operator):** Khi admin nói "hoàn tiền order #abc" hoặc "requeue submission #xyz" agent KHÔNG thực thi ngay; nó propose preview, admin xác nhận trên `ConfirmRequiredCard` mới chạy.

Nguyên tắc an toàn vận hành:

- **Read-only DB by default:** Mọi truy vấn analytics đi qua `prismaReadonly` kết nối Postgres role `t5_analytics_ro` DB từ chối INSERT/UPDATE/DELETE/DDL ở mức quyền.
- **`sqlGuard` regex blacklist:** Code-based check trước khi gửi DB; chỉ cho `SELECT`/`WITH (CTE)`, chặn `pg_sleep`, `SET ROLE`, multi-statement, comment-injection.
- **Defence-in-depth:** `requireAdmin()` ở route + service; mutation service tự re-validate state (vd refund: order phải còn PAID).
- **Audit:** Mỗi turn admin-chat persist toàn bộ message vào `admin_chat_messages` (role + content + toolCalls + followUp + subTasks). Mutation execute persist thêm `{ proposalId, resume, result }` trong `toolCalls` JSON của assistant message. Sentry capture qua `captureWorkflowException` cho stage route/stream/save_message.
- **Rate limit Redis ZSET sliding window** `admin_chat_rate:{adminId}` default 60 request/h.
- **Dynamic schema context:** cấu trúc Admin Analytics được sinh trực tiếp từ `prisma/schema.prisma`; business glossary thủ công chỉ còn các quy tắc doanh thu, ví, chứng nhận và null/snapshot semantics không thể suy ra từ type. Quyền `SELECT` của `t5_analytics_ro` là bước vận hành độc lập và phải được rà soát khi có bảng mới.
- **Master flag `ADMIN_CHAT_ENABLED`** (default OFF, bật sau khi DDL Postgres role apply staging).

Kiến trúc graph + persona + generative UI + SSE protocol mới: xem **4.13** trong AI Ecosystem. Plan kỹ thuật: `plans/PLAN-076-admin-analytics-chat.md`.

**Phase 1 đã triển khai:**

- 1 mutation thật: `requeueSubmission` (reset submission về PENDING).
- 2 mutation deferred: `refundOrder` + `unlockUser` trả thông báo "chưa hỗ trợ" khi confirm (schema T5 chưa có `OrderStatus.REFUNDED` / User lock flag).

Mọi mutation đi qua confirm gate (LangGraph `interrupt`) admin PHẢI xác nhận trên `ConfirmRequiredCard` mới chạy. `resume={false}` → skip; `resume={true}` → `mutationExecutorNode` dispatch kèm re-validate state ở service.

---

## 12. Bảo Mật, Rủi Ro & Observability

### 12.1 Tổng Quan Security

T5Edu áp dụng nhiều lớp bảo vệ cho dữ liệu học viên, giao dịch tài chính, nội dung học tập và workflow AI.

### 12.2 XSS, CSP Và Trusted Types

Hệ thống dùng Content Security Policy, sanitize HTML, Trusted Types và cơ chế strip Markdown trong các vùng nhạy cảm như Document Viewer và Submission Box.

### 12.3 Chống Gian Lận Thanh Toán

Sepay Double-Check xác minh webhook với API nhà cung cấp. PaymentLog và map ID giúp chống replay attack. Anti-spam order giảm rủi ro spam tạo đơn.

### 12.4 AI Hallucination Guard

AI buộc tuân thủ RAG và tool calling. Với Interview, AI không được suy luận nội dung bài học từ tiêu đề mà phải gọi tool lấy lesson content trước khi hỏi sâu.

### 12.5 SSE Streaming Resilience

Client parser không reset state theo từng chunk. Parser phải giữ `currentEvent` và `currentDataLines`, hỗ trợ `\n` và `\r\n`, flush decoder cuối stream và tránh báo lỗi mạng giả khi đã nhận đủ nội dung.

### 12.6 SSE Runtime Hardening

Các routes stream dài phải dùng header:

- `Content-Type: text/event-stream`.
- `Cache-Control: no-cache, no-transform`.
- `Connection: keep-alive`.
- `X-Accel-Buffering: no`.

Cleanup async phải có `catch`. Các route cần helper `safeEnqueue` và `safeClose` để tránh lỗi khi client abort.

### 12.7 Crash Guard Và PM2 Isolation

`src/instrumentation.ts` log `unhandledRejection` và `uncaughtException`. Production web app chạy PM2 cluster ít nhất 2 instances với restart backoff để cô lập lỗi worker.

### 12.8 Sentry Observability

Sentry được cấu hình theo domain:

- AI workflow.
- Server runtime.
- Edge.
- Client.
- Server action.

AI workflow cần tags như `domain`, `workflow`, `endpoint`, `stage` và `userId` nếu có. Server Actions nên được phân loại domain `server_action`.

### 12.9 Network Resilience

Email dùng Exponential Backoff để retry lỗi SMTP tạm thời. Hệ thống ưu tiên không làm sập workflow lớn khi một bước phụ như gửi email hoặc sinh ảnh gặp lỗi.

### 12.10 Clarity Performance Guard

Tracking phải lazy-load sau first paint bằng `requestIdleCallback` hoặc defer timeout. Không render debug payload nặng trong UI để tránh tăng TTI hoặc LCP trên thiết bị yếu.

---

## 13. Hành Trình Người Dùng

### 13.1 Học Viên Mới Đăng Ký

Học viên đăng nhập bằng Google OAuth. Luồng auth có xử lý PKCE và môi trường webview như TikTok hoặc Zalo để tăng tỷ lệ đăng nhập thành công.

### 13.2 Học Viên Học Tập

Học viên nhận tư vấn từ AI Tutor, học bài, nộp bài, theo dõi submission, nhận kết quả chấm AI, sửa lỗi và tiếp tục học. Tiến trình được ghi lại vào dashboard và portfolio.

### 13.3 Học Viên Thanh Toán

Học viên chọn mua khóa học, bài học hoặc PRO. Hệ thống kiểm tra số dư ví. Nếu thiếu, người dùng nạp tiền nhanh qua TopUpModal. Sau khi giao dịch thành công, luồng quay lại trải nghiệm mua hàng.

### 13.4 Học Viên PRO

Học viên PRO dùng AI Mock Interview, hưởng giảm giá AI, có thể nhận cashback và truy cập trải nghiệm portfolio nâng cao.

### 13.5 Học Viên EDU

Học viên EDU được nhận welcome bonus, giảm giá khóa học hoặc bài học và giảm giá nâng cấp PRO. EDU không nhận PRO cashback khi đã được giảm giá PRO.

### 13.6 Học Viên Giới Thiệu Bạn Bè

Học viên chia sẻ link referral. Khi người được mời phát sinh nạp tiền hoặc giao dịch đủ điều kiện, người giới thiệu nhận cashback vào ví.

### 13.7 Admin Vận Hành

Admin quản lý nội dung, khóa học, blog, người dùng, order, ví, báo cáo tài chính, workflow AI, bản tin, contact và roadmap.

---

## 14. Thuật Ngữ Nghiệp Vụ

### 14.1 Learning Terms

- **Course:** Khóa học.
- **Chapter:** Chương học.
- **Lesson:** Bài học.
- **Submission:** Bài nộp.
- **LessonProgress:** Tiến độ bài học.
- **AI Grading:** Chấm bài bằng AI.

### 14.2 Financial Terms

- **Order:** Đơn hàng.
- **OrderItem:** Dòng sản phẩm trong đơn hàng.
- **WalletTransaction:** Giao dịch ví.
- **PaymentLog:** Log xác minh thanh toán.
- **Sepay:** Nhà cung cấp thanh toán QR.
- **Cashback:** Hoàn tiền vào ví.

### 14.3 AI Terms

- **RAG:** Retrieval-Augmented Generation.
- **Tool Calling:** AI gọi công cụ để lấy dữ liệu thật.
- **LangGraph:** Framework workflow AI theo graph.
- **Checkpointer:** Cơ chế lưu trạng thái workflow.
- **Dynamic Tool Injection:** Nạp công cụ AI theo ngữ cảnh trang.
- **Admin Analytics Chat:** Popup AI dành cho admin, chạy LangGraph riêng (planner+executor+synthesizer+operator), sinh generative UI bento, mutation propose-then-confirm.
- **SubTask:** Đơn vị truy vấn nhỏ do `plannerNode` decompose từ câu hỏi gốc; chạy song song qua `runParallelQueries` tool.
- **Generative UI:** Cách trình bày kết quả analytics bằng các component có cấu trúc (`MetricCard`, `BarChartCard`, `PieChartCard`, `RankingList`, `DataTableCard`) thay vì văn bản thuần. LLM chỉ chọn type + columnMapping; data thật được rải vào props bằng code (zero-hallucination).
- **Read-only DB role:** Postgres role `t5_analytics_ro` chỉ có `SELECT` (trừ accounts/sessions/password fields), `statement_timeout=10s`. Dùng cho Admin Analytics Chat thông qua `prismaReadonly`.
- **Confirm Gate:** Node trong admin-chat graph dùng LangGraph `interrupt()` để dừng pipeline khi có mutation propose, chờ admin xác nhận qua UI mới `mutationExecutorNode` thực thi service thật.
- **SQL Guard:** Validator code-based regex blacklist cho mọi SQL gửi từ AI agent xuống DB (chống DDL/DML/`pg_*`/multi-statement/comment-injection).

### 14.4 T5Lab Terms

- **Project:** Dự án kiểm thử.
- **Page:** Màn hình hoặc trang chức năng.
- **Directory:** Thư mục nhóm page.
- **Group Feature:** Nhóm chức năng.
- **Feature:** Chức năng cần kiểm thử.
- **Testcase:** Kịch bản kiểm thử.
- **Kanban:** Bảng trạng thái công việc.

---

## 16. T5Docs Workspace Tài Liệu Cộng Tác

### 16.1 Tổng Quan T5Docs

T5Docs là workspace tài liệu cộng tác dành cho QA, QC, BA và Tester. Nền tảng kết hợp Markdown editor với AI assistant có hai chế độ hoạt động riêng biệt: **Ask Mode** (hỏi đáp ngữ cảnh) và **Edit Mode** (AI đề xuất thay đổi dưới dạng diff có kiểm duyệt). T5Docs vận hành theo mô hình pay-per-use không có gói thuê bao tháng.

### 16.2 Mô Hình Phân Quyền

Mỗi dự án T5Docs có phân quyền độc lập gồm ba vai trò: **Owner** (tạo dự án, toàn quyền), **Editor** (tạo/sửa file, dùng Edit Mode), **Viewer** (chỉ đọc và Ask Mode). Edit Mode yêu cầu tài khoản PRO hoặc tiêu thụ quota trial/trả phí.

### 16.3 Mô Hình Kinh Doanh & Định Giá

T5Docs tính phí theo hành động:

- **Ask Mode:** {{configs.T5DOCS_ASK_FREE_LIMIT}} request miễn phí/dự án/ngày. Vượt: {{configs.T5DOCS_ASK_OVERAGE_PRICE}} VND/request.
- **Edit Mode (AI Diff):** {{configs.T5DOCS_EDIT_FREE_LIMIT}} lần miễn phí/dự án/ngày cho PRO. Non-PRO được {{configs.T5DOCS_TRIAL_EDIT_LIMIT}} lần trial trọn đời, sau đó {{configs.T5DOCS_EDIT_PRICE}} VND/lần.
- **Project Slot:** {{configs.T5DOCS_FREE_PROJECT_LIMIT}} dự án miễn phí. Mỗi slot bổ sung: {{configs.T5DOCS_PROJECT_SLOT_PRICE}} VND một lần.
- **Architecture Map & Export sang T5Lab:** Luôn miễn phí.

### 16.4 Tính Năng AI Cốt Lõi

**Ask Mode:** AI đọc Architecture Map (bản đồ dự án ~300–600 token) và gọi tool `read_project_files` on-demand để lấy nội dung file khi cần. AI không nhận toàn bộ nội dung dự án upfront chỉ fetch đúng file liên quan đến câu hỏi. Ask Mode không sửa file.

**Edit Mode (Diff):** AI phân tích lệnh của người dùng, đọc file liên quan, sinh diff dưới dạng unified hunk có mô tả. Người dùng review từng hunk (Accept/Reject). File chỉ được cập nhật sau khi xác nhận. Sau khi apply, Architecture Map Updater tự cập nhật bản đồ dự án.

### 16.5 Architecture Map

Architecture Map là bộ nhớ AI về dự án một Markdown document gồm Mermaid diagram cây file và bảng mô tả từng file. Map được inject vào mọi request AI và cập nhật tự động sau mỗi Edit thành công (fire-and-forget). Rebuild thủ công do Owner kích hoạt từ Project Settings.

### 16.6 Mention System

Người dùng có thể tag file hoặc thư mục bằng cú pháp `@[path]` trong chat. Mention là link metadata (path, line range), không inject nội dung file vào prompt. AI đọc file qua tool call khi cần.

### 16.7 Export Sang T5Lab

Owner có thể export toàn bộ dự án T5Docs sang T5Lab. Hệ thống tạo T5LabProject mới, upload tất cả file lên R2, lập chỉ mục RAG (tái sử dụng `documentIndexer.ts` hiện có). Sau khi indexing xong, Owner có thể chạy AI pipeline (Pages → Features → Testcases) trực tiếp trong T5Lab.

### 16.8 Giao Diện IDE 3 Panel

Workspace tại `/t5docs/[projectId]` gồm: File Explorer (trái), Document Editor với `CustomMDEditor`/`CustomMDViewer` (giữa), AI Docs Panel với Ask/Edit toggle và Diff Reviewer (phải). Khi Edit Mode sinh diff, panel giữa chuyển sang chế độ diff view; sau review thì trở lại editor bình thường.

### 16.9 Cộng Tác Realtime

Khi thành viên accept diff và file thay đổi, các thành viên khác đang mở cùng file nhận indicator cập nhật qua Redis Pub/Sub (pattern tương tự contact 1:1 hiện có).

---

## 15. Liên Kết Tài Liệu Kỹ Thuật

README này tập trung vào business knowledge và bản đồ tính năng. Các chi tiết phát triển code, kiến trúc phân lớp, quy tắc Prisma, Auth, Konsta UI, Zustand, AI workflow và coding standards nằm trong:

- `AGENTS.md`
- `TODO.md`

---

## 17. Kiến Trúc AI Workflow LangGraph Diagrams

Phần này mô tả luồng xử lý của từng workflow AI trong T5Edu bằng Mermaid diagram. Mỗi workflow được xây dựng trên LangGraph với Redis checkpointer để lưu trạng thái giữa các lần xử lý.

---

### 17.1 Chat Multi-Agent ReAct Graph

Đây là workflow phức tạp nhất, dùng kiến trúc **Multi-Agent ReAct** với 4 specialist agent, vòng lặp tool calling và cơ chế reflection tự đánh giá chất lượng câu trả lời.

```mermaid
flowchart TD
    START([Người dùng gửi tin nhắn]) --> context

    subgraph infra["Lớp Hạ Tầng"]
        context["🔍 contextNode\nPrefetch hồ sơ người dùng\n& danh sách dự án T5Lab"]
        supervisor["🧭 supervisorNode\nPhân loại intent 3 lớp:\n1. LLM + Zod structured output\n2. URL context fallback\n3. Default: tutor"]
    end

    context --> supervisor

    supervisor -->|intent = tutor| tutor
    supervisor -->|intent = practice| practice
    supervisor -->|intent = diagnostic| diagnostic
    supervisor -->|intent = career| career

    subgraph agents["Specialist Agents ReAct Loop"]
        tutor["🎓 Tutor Agent\nGiải thích khái niệm, Socratic teaching\nTools: get_lesson_content, course_rag_search,\nsearch_blogs, update_user_memory"]
        practice["💪 Practice Agent\nTạo quiz, bài tập trắc nghiệm\nTools: get_lesson_content, get_user_learning_stats\ncourse_rag_search, update_user_memory"]
        diagnostic["🔬 Diagnostic Agent\nPhân tích lỗ hổng, lộ trình học\nTools: get_user_learning_stats, get_user_profile\ncourse_rag_search, search_blogs"]
        career["💼 Career Agent\nTư vấn nghề nghiệp, portfolio, CV\nTools: get_user_profile, search_blogs\ncourse_rag_search"]
    end

    tools["🔧 ToolNode\nThực thi tool calls\n(RAG, DB, Web Search...)"]

    tutor -->|có tool_calls| tools
    practice -->|có tool_calls| tools
    diagnostic -->|có tool_calls| tools
    career -->|có tool_calls| tools

    tools -->|route về agent đang xử lý| tutor
    tools -->|route về agent đang xử lý| practice
    tools -->|route về agent đang xử lý| diagnostic
    tools -->|route về agent đang xử lý| career

    tutor -->|không có tool_calls| reflect
    practice -->|không có tool_calls| reflect
    diagnostic -->|không có tool_calls| reflect
    career -->|không có tool_calls| reflect

    subgraph quality["Vòng Lặp Chất Lượng"]
        reflect["🪞 reflectNode\nTự đánh giá 3 tiêu chí:\n- Relevance\n- Completeness\n- Educational Quality\nFREE: tối đa 2 lần\nPRO: tối đa 3 lần"]
        respond["📝 respondNode\nTổng hợp câu trả lời cuối\nSinh 3-5 CTA gợi ý tiếp theo\nbằng Zod structured output"]
    end

    reflect -->|quality=low AND còn lượt retry| tutor
    reflect -->|quality=low AND còn lượt retry| practice
    reflect -->|quality=low AND còn lượt retry| diagnostic
    reflect -->|quality=low AND còn lượt retry| career
    reflect -->|quality=high OR hết lượt| respond

    respond --> END([Câu trả lời + CTA])

    style START fill:#4ade80,color:#000
    style END fill:#4ade80,color:#000
    style context fill:#3b82f6,color:#fff
    style supervisor fill:#8b5cf6,color:#fff
    style tutor fill:#f59e0b,color:#000
    style practice fill:#f59e0b,color:#000
    style diagnostic fill:#f59e0b,color:#000
    style career fill:#f59e0b,color:#000
    style tools fill:#ef4444,color:#fff
    style reflect fill:#06b6d4,color:#000
    style respond fill:#10b981,color:#000
```

**Mô tả chi tiết các node:**

| Node              | Vai trò                                                                              | Model dùng                   |
| ----------------- | ------------------------------------------------------------------------------------ | ---------------------------- |
| `contextNode`     | Prefetch hồ sơ user + T5Lab projects, lưu vào state để tránh tốn tool call           | Không dùng LLM               |
| `supervisorNode`  | Phân loại intent bằng LLM Flash + Zod, fallback URL, tính `maxReflections` theo tier | Executor (Flash)             |
| `tutorAgent`      | Giảng dạy Socratic, dùng MD components tương tác                                     | FREE: Flash / PRO: Model Pro |
| `practiceAgent`   | Sinh quiz ISTQB-style, kịch bản testcase                                             | FREE: Flash / PRO: Model Pro |
| `diagnosticAgent` | Phân tích điểm yếu, lộ trình học từ stats thực tế                                    | FREE: Flash / PRO: Model Pro |
| `careerAgent`     | Tư vấn nghề nghiệp, CV, portfolio, thị trường việc làm                               | FREE: Flash / PRO: Model Pro |
| `tools`           | Thực thi toàn bộ tool calls từ mọi agent                                             | Không dùng LLM               |
| `reflectNode`     | Chấm điểm chất lượng câu trả lời theo 3 tiêu chí                                     | Executor (Flash)             |
| `respondNode`     | Append 3-5 CTA gợi ý tiếp theo bằng Zod structured output                            | Executor (Flash)             |

**SSE Event Types streaming ra client:**

| Event   | Mô tả                                |
| ------- | ------------------------------------ |
| `agent` | Agent chuyên biệt vừa được kích hoạt |
| `step`  | Node trong graph bắt đầu xử lý       |
| `tool`  | Tool call đang được thực thi         |
| `delta` | Token text streaming từ LLM          |
| `done`  | Hoàn thành, trả về full content      |
| `error` | Lỗi xảy ra trong quá trình xử lý     |

---

### 17.2 Auto-Blog Pipeline Tự Động Viết Bài

Workflow tuyến tính 8 bước, mỗi bước có error gate để dừng sớm nếu thất bại. Không có vòng lặp.

```mermaid
flowchart LR
    START([Admin kích hoạt]) --> topicSelector

    topicSelector["📌 topicSelector\nChọn chủ đề blog\nchưa được viết gần đây"]
    ideator["💡 ideator\nSinh 3-5 góc nhìn\ncho chủ đề đã chọn"]
    researcher["🔎 researcher\nCrawl dữ liệu thực tế\nqua Web Search"]
    outliner["📋 outliner\nLập dàn ý SEO\nvới heading H2/H3"]
    dataVerifier["✅ dataVerifier\nKiểm tra số liệu, dữ liệu\ntrong dàn ý"]
    writer["✍️ writer\nViết bài hoàn chỉnh\nSEO-optimized Markdown"]
    imageGenerator["🖼️ imageGenerator\nSinh ảnh thumbnail\nOpenAI → Gemini fallback"]
    publisher["🚀 publisher\nLưu vào DB\nRevalidate ISR cache\nAuto-post Facebook"]

    topicSelector -->|OK| ideator
    topicSelector -->|FAILED| FAIL1([Dừng])
    ideator -->|OK| researcher
    ideator -->|FAILED| FAIL2([Dừng])
    researcher -->|OK| outliner
    researcher -->|FAILED| FAIL3([Dừng])
    outliner -->|OK| dataVerifier
    outliner -->|FAILED| FAIL4([Dừng])
    dataVerifier -->|OK| writer
    dataVerifier -->|FAILED| FAIL5([Dừng])
    writer -->|OK| imageGenerator
    writer -->|FAILED| FAIL6([Dừng])
    imageGenerator -->|OK| publisher
    imageGenerator -->|FAILED| FAIL7([Dừng])
    publisher --> END([Bài đăng live])

    style START fill:#4ade80,color:#000
    style END fill:#4ade80,color:#000
    style FAIL1 fill:#ef4444,color:#fff
    style FAIL2 fill:#ef4444,color:#fff
    style FAIL3 fill:#ef4444,color:#fff
    style FAIL4 fill:#ef4444,color:#fff
    style FAIL5 fill:#ef4444,color:#fff
    style FAIL6 fill:#ef4444,color:#fff
    style FAIL7 fill:#ef4444,color:#fff
    style publisher fill:#10b981,color:#000
```

**Lưu ý quan trọng:**

- Mỗi node có error gate khi `state.stage === "FAILED"` hoặc `state.error` tồn tại, graph dừng ngay lập tức.
- `imageGenerator` có fallback: ưu tiên OpenAI `gpt-image-2`, nếu lỗi quota chuyển sang Gemini image model. Lỗi ảnh không làm sập bước `publisher`.
- `publisher` gọi `revalidatePath` sau khi lưu blog để clear ISR cache trên Next.js. Facebook auto-post không blocking.

---

### 17.3 Course Generator Human-In-The-Loop

Workflow có điểm dừng (interrupt) để admin duyệt dàn ý trước khi sinh nội dung. Sau khi được duyệt, các bài học được sinh lần lượt với vòng lặp validator.

```mermaid
flowchart TD
    START([Admin tải tài liệu]) --> ingest

    ingest["📥 ingest\nĐọc và chunk tài liệu\nPDF, DOCX, Markdown\nLưu vectors vào pgvector"]
    planner["🗺️ planner\nSinh dàn ý khóa học\nCác chương và bài học\ndựa trên RAG context"]
    approval_gate["⏸️ approval_gate\n[INTERRUPT]\nTạo chapter & lesson placeholders\nHiển thị trước cho admin xem\n>>> Dừng chờ Admin duyệt <<<"]
    executor["⚙️ executor\nSinh nội dung từng bài học\nTheo thứ tự, kết hợp RAG\n+ Web Search theo mức score"]
    validator["🔍 validator\nKiểm tra bài nào PENDING\nhoặc FAILED cần sinh lại"]
    enhancer["✨ enhancer\nSinh hình ảnh minh họa\ncho bài THEORY\n2-phase: content → image prompt → image"]

    ingest --> planner
    planner --> approval_gate
    approval_gate -->|Admin bấm Duyệt| executor
    executor --> validator
    validator -->|Còn bài chưa xong| executor
    validator -->|Tất cả hoàn thành| enhancer
    enhancer --> END([Khóa học sẵn sàng])

    style START fill:#4ade80,color:#000
    style END fill:#4ade80,color:#000
    style approval_gate fill:#f59e0b,color:#000
    style executor fill:#3b82f6,color:#fff
    style enhancer fill:#10b981,color:#000
```

**Hybrid Context Enrichment trong executor:**

```mermaid
flowchart LR
    rag["RAG Query\npgvector similarity"] --> score{Điểm similarity}
    score -->|>= 0.65 HIGH| use_rag["Dùng RAG thuần\ntừ tài liệu gốc"]
    score -->|0.45-0.65 MEDIUM| rag_plus_search["RAG + Web Search\ncơ bản"]
    score -->|< 0.45 LOW| full_search["RAG + Web Search\nnâng cao"]
    score -->|< 0.35 NOISE| filter["Loại bỏ chunk\n(Noise Filter)"]
```

**Two-Phase Image Generation (chỉ bài THEORY):**

1. Sinh nội dung bài học dạng text hoàn chỉnh.
2. LLM đọc lại nội dung để viết image prompt bằng tiếng Anh.
3. Sinh ảnh qua OpenAI `gpt-image-2`.
4. Upload ảnh lên Cloudflare R2.
5. Chèn Markdown image vào vị trí phù hợp trong bài.

---

### 17.4 AI Grading Chấm Bài Học Viên

Workflow chấm bài dạng pipeline tuyến tính, không dùng LangGraph StateGraph mà dùng orchestrator function thuần TypeScript, giao tiếp với client qua SSE status updates.

```mermaid
flowchart TD
    START([Học viên nộp bài]) --> spam{Spam check\n< 20 ký tự?}
    spam -->|Spam| reject["❌ Reject ngay\nTrả về WRONG\n+ thông báo"]
    spam -->|OK| wait_rag

    wait_rag["⏳ WAITING_RAG\nĐợi RAG extraction\n(đã chạy nền khi nộp)\nExtract nội dung từ\nGoogle Sheets, PDF,\nDOCX, ảnh lỗi"]
    retrieve["🔍 RETRIEVING_CONTEXT\nTruy vấn RAG khóa học\nlấy 5 chunks liên quan\nqua pgvector cosine similarity"]
    evaluate["⚖️ EVALUATING\nEvaluator chấm điểm\nSo sánh bài nộp với đề bài\nvà tài liệu tham khảo\nKết quả: status + reasoning + issues"]
    self_critic["🔬 SELF_VERIFYING\nSelf-Critic kiểm tra lại\nKết quả của Evaluator\nXác nhận hoặc điều chỉnh\nstatus cuối cùng"]
    feedback_router{Trạng thái\nbài nộp?}
    approved["✅ generateApprovedFeedback\nKhen ngợi điểm tốt\nGợi ý nâng cao"]
    missing["⚠️ generateMissingFeedback\nChỉ ra điểm còn thiếu\nGợi ý bổ sung"]
    wrong["❌ generateWrongFeedback\nPhân tích lỗi chi tiết\nHướng dẫn sửa"]

    wait_rag --> retrieve
    retrieve --> evaluate
    evaluate --> self_critic
    self_critic --> feedback_router
    feedback_router -->|APPROVED| approved
    feedback_router -->|MISSING| missing
    feedback_router -->|WRONG| wrong
    approved --> done["💾 DONE\nLưu kết quả vào Redis\nSSE thông báo client"]
    missing --> done
    wrong --> done
    done --> END([Admin xem & duyệt\nkết quả chấm bài])

    style START fill:#4ade80,color:#000
    style END fill:#4ade80,color:#000
    style spam fill:#f59e0b,color:#000
    style reject fill:#ef4444,color:#fff
    style self_critic fill:#8b5cf6,color:#fff
    style done fill:#10b981,color:#000
```

**Đặc điểm nổi bật:**

- **2-step grading**: Evaluator chấm độc lập, Self-Critic kiểm tra lại để tăng độ chính xác.
- **RAG nền**: Khi học viên nộp bài, hệ thống bắt đầu extract nội dung liên kết (Google Sheets, PDF, DOCX, ảnh) ngay lập tức chạy nền. Grader chỉ đợi kết quả này thay vì chạy lại từ đầu.
- **Template Preservation**: Prompt chấm bài siết quy tắc giữ nguyên `{{placeholder}}` để tránh lỗi biên dịch template.
- **Giao tiếp SSE**: Client nhận status update theo thời gian thực qua SSE từ `WAITING_RAG` đến `DONE`.

---

### 17.5 Interview AI Mock Interview

Workflow phỏng vấn có interrupt mechanism để chờ câu trả lời của học viên. Dùng `interruptBefore: ["humanRouting"]` để dừng sau mỗi câu hỏi.

```mermaid
flowchart TD
    START([Học viên bắt đầu phỏng vấn]) --> init

    init["🚀 initNode\nKhởi tạo phiên phỏng vấn\nLoad ngữ cảnh khóa học\nXác định vai trò Lead QA"]
    plan["📋 planNode\nLên kế hoạch phỏng vấn\nXác định chủ đề câu hỏi\ntheo năng lực học viên"]
    ask["❓ askNode\nĐặt câu hỏi phỏng vấn\nDùng Tools nếu cần\n(PHẢI gọi get_lesson_content\ntrước khi hỏi sâu bài học)"]
    tools["🔧 Tools\ncourseCatalog, courseDetail\ncourseRag, lessonContext\nmemoryUpdate, userProfile\nuserStats"]
    human_routing["⏸️ humanRouting\n[INTERRUPT]\nĐợi câu trả lời\ncủa học viên"]
    analyze["🧠 analyzeNode\nPhân tích câu trả lời\nĐánh giá độ sâu\nStream reasoning nội bộ"]
    report["📊 reportNode\nSinh báo cáo năng lực\nDạng JD-friendly\nHỗ trợ Web Search\ncho câu hỏi thực tế"]
    report_tools["🔧 reportTools\nCùng bộ tools với ask\n(reuse ToolNode)"]

    init --> plan
    plan --> ask
    ask -->|có tool_calls| tools
    tools --> ask
    ask -->|không có tool_calls| human_routing
    human_routing -->|Học viên chưa muốn báo cáo| analyze
    human_routing -->|Học viên muốn báo cáo| report
    analyze --> ask
    report -->|có tool_calls| report_tools
    report_tools --> report
    report -->|không có tool_calls| END([Báo cáo năng lực hoàn chỉnh])

    style START fill:#4ade80,color:#000
    style END fill:#4ade80,color:#000
    style human_routing fill:#f59e0b,color:#000
    style analyze fill:#8b5cf6,color:#fff
    style report fill:#10b981,color:#000
    style tools fill:#ef4444,color:#fff
    style report_tools fill:#ef4444,color:#fff
```

**Cơ chế interrupt:**

- Graph dừng trước `humanRouting` sau mỗi câu hỏi của AI (`interruptBefore: ["humanRouting"]`).
- Client nhận event `interrupt` qua SSE, UI hiển thị ô nhập liệu.
- Khi học viên gửi câu trả lời, server gọi `resumeInterview()` với `Command({ resume: message })` để tiếp tục.
- Nếu đã đủ `MAX_QUESTIONS` hoặc `isReadyToReport = true`, AI gợi ý học viên chuyển sang xem báo cáo.

**Luồng sinh báo cáo:**

1. `reportNode` đọc toàn bộ lịch sử hội thoại.
2. Phân tích điểm mạnh/yếu theo từng kỹ năng.
3. Có thể gọi Web Search để thêm thông tin thị trường thực tế.
4. Sinh báo cáo dạng JD-friendly để học viên dùng trong CV.

---

### 17.6 T5Lab AI Pipeline Ba Giai Đoạn

Workflow T5Lab cho phép admin/user chạy từng giai đoạn độc lập (Pages, Features, Testcases) dựa trên `currentStage` trong state. Entry point là conditional edge thay vì cố định.

```mermaid
flowchart TD
    START([User chọn giai đoạn]) --> stageRouter{currentStage?}

    stageRouter -->|PAGES_GENERATING| ingest
    stageRouter -->|FEATURES_GENERATING| featuresGenerator
    stageRouter -->|TESTCASES_GENERATING| testcasesGenerator

    subgraph phase1["Giai Đoạn 1 Pages"]
        ingest["📥 ingest\nĐọc tài liệu dự án\nChunk & embed vào pgvector\nTạo bản đồ tài liệu"]
        pagesGenerator["📄 pagesGenerator\nSinh cấu trúc màn hình\nvà thư mục từ tài liệu\nStrict schema validation\n(không tạo sai cấp)"]
        pagesVerifier["✅ pagesVerifier\nXác minh cấu trúc\nPages đúng định dạng"]
    end

    subgraph phase2["Giai Đoạn 2 Features"]
        featuresGenerator["🔧 featuresGenerator\nSinh Group Features & Features\ncho từng Page đã có\nDùng RAG từ tài liệu đã ingest"]
        featuresVerifier["✅ featuresVerifier\nXác minh Features\nđúng cấu trúc phân cấp"]
    end

    subgraph phase3["Giai Đoạn 3 Testcases"]
        testcasesGenerator["🧪 testcasesGenerator\nSinh testcase theo feature\nGranular: chỉ target\nfeature được yêu cầu"]
        testcasesVerifier["✅ testcasesVerifier\nXác minh Testcases\nđúng format"]
    end

    finalize["💾 finalize\nLưu kết quả vào DB\nCập nhật T5Lab state\nThông báo kết quả"]

    ingest --> pagesGenerator
    pagesGenerator --> pagesVerifier
    pagesVerifier --> finalize

    featuresGenerator --> featuresVerifier
    featuresVerifier --> finalize

    testcasesGenerator --> testcasesVerifier
    testcasesVerifier --> finalize

    finalize --> END([T5Lab cập nhật])

    style START fill:#4ade80,color:#000
    style END fill:#4ade80,color:#000
    style stageRouter fill:#8b5cf6,color:#fff
    style ingest fill:#3b82f6,color:#fff
    style pagesGenerator fill:#f59e0b,color:#000
    style featuresGenerator fill:#f59e0b,color:#000
    style testcasesGenerator fill:#f59e0b,color:#000
    style finalize fill:#10b981,color:#000
```

**Pay-Per-Stage Billing:**

| Giai đoạn | Hành động                      | Mức phí                |
| --------- | ------------------------------ | ---------------------- |
| Pages     | Sinh cấu trúc màn hình         | Tính theo số pages     |
| Features  | Sinh group features & features | Tính theo số features  |
| Testcases | Sinh testcase từng feature     | Tính theo số testcases |

Mức sàn tối thiểu: 1,000 VND/lần. QR nạp nhanh điền sẵn tối thiểu 5,000 VND qua `WALLET_MIN_DEPOSIT`; chuyển khoản thủ công chấp nhận mọi số tiền dương.

**RAG Strategy:**

- Sau `ingest`, hệ thống tạo bản đồ tài liệu (document map) để AI biết nội dung nào trong file nào.
- Khi RAG kém (score thấp), AI có thể gọi tool `read_project_documents` để đọc tài liệu theo yêu cầu trước khi sinh cấu trúc.
- Strict validation ngăn AI sinh Feature ở tầng root hoặc tạo sai cấp phân cấp.

---

### 17.7 Auto-Fill Profile

Workflow 2 bước xử lý trích xuất CV và tự động điền thông tin Profile (sử dụng Function + Redis thay vì StateGraph).

```mermaid
flowchart TD
    START([Bắt đầu]) --> extractCvTextNode
    extractCvTextNode["📄 extractCvTextNode\nTrích xuất văn bản\ntừ file CV gốc"]
    analyzeWithAI["🤖 analyzeWithAI\nPhân tích & mapping schema\n(headline, bio, skills, exp...)"]

    extractCvTextNode --> analyzeWithAI
    analyzeWithAI --> END([Hoàn tất])

    style START fill:#4ade80,color:#000
    style END fill:#4ade80,color:#000
    style extractCvTextNode fill:#3b82f6,color:#fff
    style analyzeWithAI fill:#f59e0b,color:#000
```

**Đặc điểm nổi bật:**

- **Không dùng StateGraph:** Do luồng xử lý đơn giản chỉ gồm 2 bước tuần tự, hệ thống sử dụng Function call kết hợp Redis để quản lý trạng thái thay vì overhead của LangGraph.
- **Output Validation chặt chẽ:** Ép kiểu dữ liệu trả về theo Zod Schema chuẩn của Profile, tự động suy luận và mapping `SkillLevel` thành `BEGINNER/INTERMEDIATE/ADVANCED` dựa trên số năm kinh nghiệm.
- **Realtime SSE:** Cập nhật trạng thái liên tục (`EXTRACTING_CV` → `ANALYZING` → `DONE`) về client.
- **Đọc storage ổn định:** File nội bộ được lấy trực tiếp từ R2 thay vì gọi HTTP ngược qua `/api/uploads`; lỗi timeout, file quá lớn, định dạng không hỗ trợ, file hỏng và PDF không có text được phân loại thành thông báo tiếng Việt phù hợp.

---

### 17.8 ISTQB Question Generator

Script pipeline tự động sinh đề thi ISTQB mới dựa trên kho câu hỏi mẫu (Few-shot learning).

```mermaid
flowchart TD
    START([Chạy script]) --> getContext
    getContext["📊 Lấy Context Đề Thi\nMetadata: Tỷ lệ đạt, \nCấp độ, Chapter Weights"]
    getExamples["📚 Lấy Câu Hỏi Mẫu\nLọc 10 câu PUBLISHED"]
    llmGenerate["🧠 Sinh Câu Hỏi\nTuân thủ tỷ lệ chương & \nloại câu hỏi (SC, MC...)"]
    dedup["🔍 Filter Duplicates\nLoại bỏ câu hỏi trùng lặp\nvới ngân hàng đề"]
    saveDb["💾 Lưu Database\nTrạng thái DRAFT"]

    getContext --> getExamples
    getExamples --> llmGenerate
    llmGenerate --> dedup
    dedup --> saveDb
    saveDb --> END([Kết thúc])

    style START fill:#4ade80,color:#000
    style END fill:#4ade80,color:#000
    style llmGenerate fill:#f59e0b,color:#000
```

**Đặc điểm nổi bật:**

- **Few-shot Learning:** Tự động lấy 10 câu hỏi đã duyệt (`PUBLISHED`) làm câu hỏi mẫu (examples) để dạy AI về định dạng, độ khó và phong cách ra đề.
- **Tuân thủ Chapter Weights:** Sử dụng thuật toán phân bổ để đảm bảo số lượng câu hỏi sinh ra luôn khớp với cấu trúc đề thi chuẩn quốc tế (ví dụ: K1/K2/K3 tỷ lệ bao nhiêu % cho từng chương).
- **Deduplication:** Chạy qua hàm `dedup` để lọc bỏ các câu hỏi có nội dung trùng lặp với ngân hàng đề hiện tại trước khi lưu nháp.

---

### 17.9 ISTQB Importer

LangGraph workflow hỗ trợ nhập liệu và xử lý đề thi ISTQB từ tài liệu gốc. Có cơ chế Human-In-The-Loop.

```mermaid
flowchart LR
    START([Upload File]) --> ingest
    ingest["📥 ingest\nNhận tài liệu"]
    metadataExtractor["🏷️ metadataExtractor\nTrích xuất metadata"]
    approval_gate{"🛑 approval_gate\nHuman-In-The-Loop\nChờ duyệt metadata"}
    ragIngest["🧩 ragIngest\nChunking & Embedding"]
    questionExtractor["❓ questionExtractor\nTrích xuất câu hỏi"]
    checkLoop{"🔄 checkExtractionComplete\nĐủ số lượng câu?"}
    saveNode["💾 save\nLưu kết quả"]

    ingest --> metadataExtractor
    metadataExtractor --> approval_gate
    approval_gate -->|Duyệt| ragIngest
    ragIngest --> questionExtractor
    questionExtractor --> checkLoop
    checkLoop -->|Chưa đủ| questionExtractor
    checkLoop -->|Đủ| saveNode
    saveNode --> END([Hoàn thành])

    style START fill:#4ade80,color:#000
    style END fill:#4ade80,color:#000
    style approval_gate fill:#ef4444,color:#fff
    style checkLoop fill:#8b5cf6,color:#fff
    style questionExtractor fill:#f59e0b,color:#000
```

**Đặc điểm nổi bật:**

- **Human-In-The-Loop (HITL):** Workflow tự động dừng tại `approval_gate` (`interruptBefore: ["approval_gate"]`). Quản trị viên phải kiểm tra và xác nhận metadata trích xuất trước khi hệ thống chạy các tác vụ tốn kém (embedding, chunking).
- **Vòng lặp tự động (checkExtractionComplete):** Kiểm tra liên tục số lượng câu hỏi trích xuất được. Nếu chưa đủ so với tổng số khai báo trong metadata, graph sẽ tiếp tục chạy lại node `questionExtractor` để vét cạn tài liệu.

---

### 17.10 Profile Summary

Sinh bio (Giới thiệu) cho học viên kết hợp từ thành tích học tập trên T5Edu và CV gốc.

```mermaid
flowchart TD
    START([Kích hoạt]) --> gatherData
    gatherData["📊 gatherUserData\nLấy số liệu khóa học,\nbài tập, kỹ năng..."]
    checkCv{"Có CV gốc không?"}
    extractCv["📄 extractCvTextNode\nTrích xuất văn bản CV"]
    generateBio["🤖 generateProfileBio\nSinh Bio tự nhiên\n(Không bịa đặt)"]

    gatherData --> checkCv
    checkCv -->|Có| extractCv
    extractCv --> generateBio
    checkCv -->|Không| generateBio
    generateBio --> END([Trả về Client])

    style START fill:#4ade80,color:#000
    style END fill:#4ade80,color:#000
    style generateBio fill:#f59e0b,color:#000
```

**Đặc điểm nổi bật:**

- **Tổng hợp dữ liệu đa nguồn:** Kết hợp cả thành tích học tập trong hệ thống (khóa học hoàn thành, bài tập đã duyệt) và nội dung CV gốc của học viên.
- **Prompt Engineering tinh tế:** Không bịa đặt thông tin, sử dụng văn phong chuyên nghiệp như LinkedIn Summary, nhấn mạnh vào các từ khóa kỹ năng (manual, automation, API testing).

---

### 17.11 Social Distribution

LangGraph workflow phân phối nội dung tự động lên mạng xã hội (tuyến tính, có error gate).

```mermaid
flowchart LR
    START([Chạy chiến dịch]) --> contentCreator
    contentCreator["✍️ contentCreator\nSáng tạo nội dung post"]
    errorRouter{"🛑 errorRouter\nCó lỗi không?"}
    facebookPoster["🚀 facebookPoster\nĐăng bài lên Facebook"]

    contentCreator --> errorRouter
    errorRouter -->|Có lỗi| END([Dừng])
    errorRouter -->|OK| facebookPoster
    facebookPoster --> END([Thành công])

    style START fill:#4ade80,color:#000
    style END fill:#4ade80,color:#000
    style errorRouter fill:#ef4444,color:#fff
```

**Đặc điểm nổi bật:**

- **Error Gate:** Workflow cấu trúc đơn giản nhưng an toàn với `errorRouter`. Nếu bước sáng tạo nội dung (`contentCreator`) gặp lỗi (API sập, vi phạm policy), luồng sẽ tự động ngắt kết nối thay vì đăng tải nội dung lỗi lên mạng xã hội.

---

### 17.12 T5Docs

Workflow xử lý tương tác với tài liệu dự án, bao gồm 2 nhánh: Chat (Hỏi đáp) và Edit (Chỉnh sửa file).

```mermaid
flowchart TD
    START([User Message]) --> context
    context["🧠 context\nNạp ngữ cảnh & mode"]
    modeRouter{"🔀 modeRouter\nChế độ Ask hay Edit?"}

    %% Ask Branch
    askLlm["💬 askLlm\nTrả lời câu hỏi (có Tool)"]
    shouldCallTools{"🛠️ shouldCallTools\nCó gọi tools không?"}
    askTools["⚙️ askTools\nĐọc file project"]

    %% Edit Branch
    fileResolver["📂 fileResolver\nTìm file cần sửa"]
    diffGenerator["📝 diffGenerator\nSinh mã Diff"]
    mapUpdater["🗺️ mapUpdater\nCập nhật Document Map"]

    context --> modeRouter

    modeRouter -->|ask| askLlm
    askLlm --> shouldCallTools
    shouldCallTools -->|Có| askTools
    askTools --> askLlm
    shouldCallTools -->|Không| END([Kết thúc])

    modeRouter -->|edit| fileResolver
    fileResolver --> diffGenerator
    diffGenerator --> mapUpdater
    mapUpdater --> END

    style START fill:#4ade80,color:#000
    style END fill:#4ade80,color:#000
    style modeRouter fill:#8b5cf6,color:#fff
    style shouldCallTools fill:#8b5cf6,color:#fff
    style askLlm fill:#f59e0b,color:#000
    style diffGenerator fill:#f59e0b,color:#000
```

**Đặc điểm nổi bật:**

- **Deterministic Code Router:** Không dùng LLM để phân nhánh. Việc chọn luồng Ask hay Edit được điều hướng 100% bằng logic tĩnh (UI toggle Mode) để tiết kiệm token và đảm bảo độ chính xác.
- **Looping Tools:** Tại luồng Ask, `askLlm` có thể lặp lại nhiều lần với `askTools` (đọc file dự án) cho đến khi thu thập đủ thông tin để trả lời.
- **Edit Pipeline:** Ứng dụng mô hình tương tác source code: Tìm file -> Tạo bản vá (Diff) -> Cập nhật Map (tránh thay đổi sai lệch).

---

### 17.13 Testcase Grader

Hệ thống tự động chấm điểm cho các bài tập viết Testcase dạng bảng Markdown, tích hợp Evaluator & Self-Critic.

```mermaid
flowchart TD
    START([Học viên nộp bài]) --> spamCheck
    spamCheck{"🛡️ isSpam\nKiểm tra bài ngắn/rác?"}
    waitRag["⏳ ensureSubmissionRag\nĐợi nhúng dữ liệu bài nộp"]
    ragCourse["📚 retrieveRelevantChunks\nRAG nội dung khóa học"]
    evaluator["🤖 Evaluator\nChấm bài & Sinh Feedback HTML\n(Sử dụng biến {{user.name}})"]
    selfCritic["🧐 Self-Critic\nKiểm định lại kết quả Evaluator"]

    spamCheck -->|Spam| END([Báo lỗi WRONG])
    spamCheck -->|Hợp lệ| waitRag
    waitRag --> ragCourse
    ragCourse --> evaluator
    evaluator --> selfCritic
    selfCritic --> END([Trả về Kết quả])

    style START fill:#4ade80,color:#000
    style END fill:#4ade80,color:#000
    style spamCheck fill:#ef4444,color:#fff
    style evaluator fill:#f59e0b,color:#000
    style selfCritic fill:#8b5cf6,color:#fff
```

**Đặc điểm nổi bật:**

- **Spam Checker (Fast-path):** Phân tích độ dài và định dạng văn bản trước khi gọi LLM. Nếu phát hiện rác/spam, lập tức trả về `WRONG` để tiết kiệm chi phí API.
- **2-Step Evaluation:** Đánh giá viên (`Evaluator`) chấm điểm và sinh phản hồi, sau đó phải đi qua trạm kiểm định (`Self-Critic`) để đánh giá lại tính logic của kết quả trước khi chốt điểm cuối cùng.
- **Luật Templating nghiêm ngặt:** AI bị bắt buộc sử dụng định dạng biến `{{user.name}}` thay vì xưng hô chung chung, tạo cảm giác thân thiện cá nhân hóa ở giao diện client. Giữ nguyên cấu trúc thẻ HTML Custom `<table-testcase>` để render Component hiển thị bảng chấm điểm chi tiết.
- **RAG Context Enrichment:** Đợi nhúng dữ liệu bài nộp (nếu chưa nhúng) và kéo nội dung bài giảng liên quan vào prompt, giúp AI bám sát tiêu chí của đề bài.

---

### 17.14 Admin Analytics Chat Planner + Executor + Synthesizer + Operator

Workflow tách biệt 100% với `chat` user-facing. Supervisor 3-way (ANALYZE / OPERATE / CONVERSE). Nhánh ANALYZE chạy planner decompose subTasks → executor ReAct (parallel queries qua `prismaReadonly`) → synthesizer build XML `<bento-grid>` → reflect (max 1 retry) → respond. Nhánh OPERATE qua synthesizer (build XML `<bento-grid>`) → confirmGate (LangGraph `interrupt`) chờ admin xác nhận trước khi mutation thực thi. Tất cả tools đi qua `sqlGuard` regex blacklist + Postgres role `t5_analytics_ro` (read-only). Mỗi turn ghi `AiWorkflowRun` audit.

```mermaid
graph TB
    start([START])
    ctx["📥 contextNode<br/>load admin profile<br/>page context"]
    reset["🔄 stateResetNode<br/>reset per-turn fields"]
    sup{"🧭 supervisorNode<br/>ANALYZE | OPERATE | CONVERSE"}

    plan["📋 plannerNode<br/>decompose subTasks[]<br/>Zod structured output"]
    exec["🔍 executorAgent<br/>ReAct max 6 iter<br/>persona: phân tích viên"]
    tools_ro["🛠️ adminToolNode<br/>6 read-only tools<br/>(SQL/schema/entity/metric/parallel)"]
    syn["🎨 synthesizerNode<br/>build XML bento-grid<br/>zero-hallucination on data"]
    reflect["🪞 reflectNode<br/>max 1 retry<br/>(admin priority: latency)"]

    op["🛡️ operatorAgent<br/>persona: cẩn trọng<br/>4 propose tools"]
    gate["⏸️ confirmGateNode<br/>LangGraph interrupt()<br/>emit confirm_required SSE"]
    mut_exec["✅ mutationExecutorNode<br/>resume=true → service<br/>requireAdmin defence-in-depth"]

    resp["💬 respondNode<br/>follow-up chips<br/>persona admin"]
    finish([END])

    start --> ctx
    start --> reset
    ctx --> sup
    reset --> sup

    sup -->|ANALYZE| plan
    sup -->|OPERATE| op
    sup -->|CONVERSE| resp

    plan --> exec
    exec -->|tool_calls| tools_ro
    tools_ro --> exec
    exec -->|no calls| syn
    syn -->|intent=ANALYZE| reflect
    syn -->|intent=OPERATE| gate
    reflect -->|retry| exec
    reflect -->|done| resp

    op --> syn
    gate -.->|interrupt| finish
    gate -->|resume=true| mut_exec
    gate -->|resume=false| resp
    mut_exec --> resp

    resp --> finish

    classDef readOnly fill:#dbeafe,stroke:#1a73e8,color:#000
    classDef mutate fill:#fee2e2,stroke:#ef4444,color:#000
    classDef neutral fill:#f4f4f5,stroke:#71717a,color:#000

    class plan,exec,tools_ro,syn,reflect readOnly
    class op,gate,mut_exec mutate
    class ctx,reset,sup,resp neutral
```

**SSE events:** `delta` (text), `step`, `tool`, `agent`, `subtask` (per parallel query), `generative_ui` (per bento component), `confirm_required` (interrupt), `follow_up`, `done`, `error`.

**Persona separation:** Tutor/Practice/Diagnostic/Career persona ở `workflows/chat` KHÔNG bao giờ chạy ở admin-chat và ngược lại. Store, hook, components, prompts, tools đều tách file tree riêng.

---

### 17.15 Tổng Quan Kiến Trúc Tất Cả Workflows

```mermaid
graph TB
    user["👤 Người dùng / Admin"]

    user -->|Chat, hỏi đáp| chat["💬 Chat Workflow\nMulti-Agent ReAct\n4 agents + reflect loop"]
    user -->|Nộp bài tập| grading["📝 Grading / Testcase Grader\nEvaluator + Self-Critic\nSSE status updates"]
    user -->|Bắt đầu phỏng vấn| interview["🎤 Interview Workflow\nReAct + HITL interrupt\nBáo cáo JD-friendly"]
    admin["👑 Admin"] -->|Tải tài liệu khóa học| course["📚 Course Generator / ISTQB Importer\nHITL approval gate\nHybrid RAG"]
    admin -->|Kích hoạt tự động| blog["📰 Auto-Blog / Social Distribution\nLinear pipelines\nError gate mỗi bước"]
    admin -->|Trợ lý dữ liệu| adminchat["📊 Admin Analytics Chat\nPlanner + Executor +\nSynthesizer + Operator\nReadonly SQL + Confirm Gate"]
    user -->|Chạy T5Lab AI| t5lab["🧪 T5Lab Generator\n3 giai đoạn độc lập\nPay-per-stage billing"]
    user -->|Profile Summary| profile["👤 Profile Builder\nAuto-fill CV & Summary\nFunction & Redis States"]
    user -->|Khám phá codebase| t5docs["📑 T5Docs\nCode Router Ask/Edit\nRead/Write Project Files"]

    subgraph infra["Hạ Tầng Chung"]
        redis_ckpt["Redis Checkpointer\nLưu state giữa\ncác lần xử lý"]
        pgvector["pgvector\nEmbedding & RAG\nCosine similarity"]
        sse["SSE Streaming\ndelta, step, tool\nagent, done, error"]
        rate_limit["Rate Limiting\nRedis ZSET sliding window\nFallback PostgreSQL hydration"]
    end

    chat --> redis_ckpt
    interview --> redis_ckpt
    course --> redis_ckpt
    blog --> redis_ckpt
    t5lab --> redis_ckpt
    t5docs --> redis_ckpt
    adminchat --> redis_ckpt

    chat --> pgvector
    grading --> pgvector
    course --> pgvector
    t5lab --> pgvector
    t5docs --> pgvector

    chat --> sse
    grading --> sse
    interview --> sse
    profile --> sse
    adminchat --> sse

    chat --> rate_limit
    adminchat --> rate_limit

    style user fill:#4ade80,color:#000
    style admin fill:#f59e0b,color:#000
    style redis_ckpt fill:#ef4444,color:#fff
    style pgvector fill:#8b5cf6,color:#fff
    style sse fill:#06b6d4,color:#000
    style rate_limit fill:#64748b,color:#fff
```



---

## 19. Landing Page Bán Source Code

### 19.1 Mục Đích

`/source-code` là marketing surface chuyên biệt để bán bộ source code T5Edu kèm dịch vụ triển khai cho đối tượng buyer kỹ thuật (dev cá nhân, agency, trung tâm đào tạo muốn tự vận hành nền tảng tương tự). Khác với các trang trong `(main)/` phục vụ học viên, trang này không yêu cầu đăng nhập, SEO-first, và tối ưu chuyển đổi qua CTA liên hệ external.

### 19.2 Cấu Trúc Sections

Visual direction hiện tại là **production system editorial**: hero bất đối xứng có artwork kiến trúc nhiều lớp, proof metrics, module trình bày theo 4 trụ cột + capability ledger, tech stack theo technology ledger và phạm vi bàn giao theo numbered handover list. Landing tránh lưới 16 card icon vì làm source code giống template tính năng thay vì một hệ thống đã vận hành.

Trang gồm 9 section theo thứ tự:

1. **Hero Section** Tiêu đề + subtitle + CTA button dẫn ra external `https://duonguyen.site/contact`.
2. **Trust Signals** 7 counter live: Người dùng đã đăng ký, Tổng nạp vào ví, Tổng đã tiêu trên ví, Bài đã nộp, Đơn hoàn tất, Khóa học xuất bản, Dự án T5Lab.
3. **Product Capability Ledger** liệt kê riêng chứng nhận khóa học xác thực (evidence, immutable snapshot, public URL, email/PDF FREE-PRO và paid bypass), bên cạnh LMS/Submission/Commerce; AI Tutor, Grading, Course Generator, Mock Interview, RAG; T5Lab/T5Docs; SQL/API Playground; Portfolio/CV; Order/Wallet/Sepay; Admin; Security và AI-readable/MCP/WebMCP.
4. **SQL & API Playground Showcase** trình bày hai live product surface trên cùng SQL Lab baseline: database manager chạy SQL qua Server Action và Swagger/OpenAPI dùng Bearer key từ trình duyệt, Postman, Apidog hoặc code.
5. **Interactive Markdown Infrastructure** mô tả contract custom element dùng chung giữa AI, editor và renderer.
6. **Tech Stack** Grouped chips: Framework / Styling / Database / Auth / State / Infra / AI-LLM / Tools / Tracking.
7. **Pricing** 2 card: Full Source Code (mặc định $600 hoặc 15.000.000 VND, admin config) + Custom Development (mặc định $20/h hoặc 500.000 VND/h).
8. **Included List** 6 items: Full source + GitHub access, Deploy support, Training 1-1, Documentation, VPS VN recommendation (chỉ khách Việt Nam), Demo link từ `process.env.NEXT_PUBLIC_MAIN_URL`.
9. **Bottom CTA** dẫn tới trao đổi phạm vi source code hoặc custom development, không tạo checkout tự động.

### 19.3 Giá Cả Qua SystemConfig

Toàn bộ giá quản trị qua `/admin/configs` category **"Bán Source Code"** không cần redeploy:

| Key                                 | Default                          | Mục đích                                         |
| ----------------------------------- | -------------------------------- | ------------------------------------------------ |
| `SOURCE_CODE_PRICE_USD`             | `600`                            | Giá trọn bộ (USD)                                |
| `SOURCE_CODE_PRICE_VND`             | `15000000`                       | Giá trọn bộ (VND)                                |
| `CUSTOM_DEV_PRICE_USD_PER_HOUR`     | `20`                             | Phí custom dev (USD/giờ)                         |
| `CUSTOM_DEV_PRICE_VND_PER_HOUR`     | `500000`                         | Phí custom dev (VND/giờ)                         |
| `SOURCE_CODE_CONTACT_URL`           | `https://duonguyen.site/contact` | URL CTA liên hệ                                  |
| `SOURCE_CODE_ACTIVITY_ENABLED`      | `true`                           | Master switch cho SSE stream                     |
| `SOURCE_CODE_ACTIVITY_MIN_SEC`      | `3`                              | Interval random tối thiểu (giây)                 |
| `SOURCE_CODE_ACTIVITY_MAX_SEC`      | `10`                             | Interval random tối đa (giây)                    |
| `SOURCE_CODE_ACTIVITY_POOL_DAYS`    | `14`                             | Cửa sổ lấy activity pool (ngày)                  |
| `SOURCE_CODE_STATS_REFRESH_MIN_SEC` | `5`                              | Tối thiểu giây giữa 2 stats tick (rate-limit DB) |

USD và VND là 2 key độc lập **không auto-convert tỷ giá**. Admin maintain song song.

### 19.4 SSE Live Social Proof Pure Query Pattern

Điểm đặc biệt của landing: **counter trust signals và toast hoạt động live** được cấp qua một SSE endpoint duy nhất `/api/landing/source-code/stream`, tick ngẫu nhiên 3-10 giây, pattern **pure-query**:

- **Zero service touch:** không có bất kỳ `orderService`/`walletService`/`submissionService`/`userService` nào publish event khi write. Endpoint chỉ `prisma.findMany` + `aggregate` + `count` rồi shuffle.
- **Pool cache Redis 5 phút/process** → giảm DB load khi nhiều visitor cùng xem.
- **2 event types:** `stats` (full snapshot 7 counters, client animate count-up 800ms) và `activity` (1 toast từ shuffled pool, fade in-out).
- **Coin flip:** mỗi tick 50% gửi `stats`, 50% gửi `activity`. Đảm bảo cả counter và toast đều sống động.
- **Heartbeat comment mỗi 15s** để Caddy reverse-proxy không timeout.
- **Connection cap 10 phút** → client auto-reconnect qua native `EventSource` retry, tránh leak connection trên PM2.

### 19.5 Masking Policy (Friendly)

Tất cả output qua `src/lib/apis/services/landingSourceCode/mask.ts` single source of truth:

- Tên: `"Nguyễn Văn An"` → `"Nguyễn V***"`. Không có tên → `"Một học viên"`. Không bao giờ fallback về email.
- Số tiền: tier bucket `500000` → `"500K"`, `15000000` → `"15M"`, `<1000` → `"<1K"`.
- ID: không expose raw. Dùng `hashId()` (SHA1 slice 8 chars) chỉ để client dedupe, không reverse được.
- Tên khóa học / bài học: giữ nguyên vì là dữ liệu public.

### 19.6 Activity Pool Sources

6 loại event trong pool, top 50 mỗi loại trong `SOURCE_CODE_ACTIVITY_POOL_DAYS` ngày gần nhất:

| Kind                  | Entity                           | Display                                            |
| --------------------- | -------------------------------- | -------------------------------------------------- |
| `user_signup`         | `User`                           | "Nguyễn V\*\*\* vừa tạo tài khoản"                 |
| `order_completed`     | `Order` status=COMPLETED         | "Trần T\*\*\* vừa mua khóa React Nâng cao"         |
| `wallet_deposit`      | `WalletTransaction` type=DEPOSIT | "Phạm N\*\*\* vừa nạp 500K vào ví"                 |
| `submission_approved` | `Submission` status=APPROVED     | "Lê M\*\*\* vừa hoàn tất bài Kiểm thử biên"        |
| `enrollment_created`  | `Enrollment`                     | "Hoàng A\*\*\* vừa ghi danh khóa ISTQB Foundation" |
| `t5lab_project`       | `T5LabProject`                   | "Ngô K\*\*\* vừa khởi tạo dự án test trên T5Lab"   |

### 19.7 Nguyên Tắc Cập Nhật Landing

Khi platform thêm module mới (feature/tool/module/integration), **chủ repo phải cập nhật tay** `src/app/(sites)/(main)/source-code/_content.ts` trong cùng PR feature. Landing **không auto-sync** từ README đây là chủ đích (content-in-code, code review qua PR) để đảm bảo chất lượng thông điệp bán hàng.

SQL Playground và API Swagger Playground là hai capability riêng trong inventory. Landing có showcase semantic HTML với liên kết `next/link` tới `/playground/sql` và `/playground/api`; bản AI-readable diễn đạt cùng contract qua service layer để `/api/ai-readable?path=/source-code` không trở thành nguồn marketing copy thứ hai.

### 19.8 SEO

- `generateMetadata` riêng cho `/source-code` (title + description + canonical + OG image).
- Có mặt trong `sitemap.ts` với `priority: 0.9`.
- Không noindex đây là landing cần Google rank.
- Nhóm capability dùng `?tab=` để lưu panel đang xem. Tất cả nhóm vẫn có trong HTML ban đầu; tab chỉ thay đổi giao diện sau hydration, vì vậy crawler và người dùng không bật JavaScript đều nhận đủ ngữ cảnh.

### 19.9 Out of Scope

- Checkout online / payment gateway (CTA là external link).
- Auto-provision GitHub access (xử lý thủ công sau khi khách liên hệ).
- Multi-language EN (hiện chỉ tiếng Việt).
- Real-time pub/sub từ service writes (đã chủ động từ chối giữ zero coupling với business-critical paths).
- A/B test framework.

### 19.10 Plan Kỹ Thuật

Chi tiết implementation tại `plans/PLAN-078-source-code-landing.md`.

---

## 20. Landing Page PRO Upsell Conversion

### 20.1 Mục Đích

`/pro` là trang marketing chuyên biệt để upsell học viên `ProfileTier.FREE` nâng cấp gói PRO. Khác với trang `/profile` (personal dashboard), `/pro` là public-accessible, SEO-aware, và tối ưu chuyển đổi với bảng so sánh FREE vs PRO, SSE live activity stream, testimonial, và CTA trực tiếp vào `Order PRO_UPGRADE`. User đã PRO bị redirect về `/profile` ngay khi truy cập.

### 20.2 Cấu Trúc Sections

Visual direction hiện tại là **premium momentum**: hero bất đối xứng với artwork amber/graphite, thông điệp tập trung vào nhịp tiến bộ thay vì “mở khóa nhiều tính năng”, và benefits chuyển sang 6 outcome theo numbered editorial list. PRO không dùng crown/diamond/coin hoặc icon trang trí cỡ lớn; amber chỉ làm accent, còn pricing, hạn mức và cashback vẫn đọc live từ SystemConfig.

Trang gồm 8 section theo thứ tự:

1. **Hero Section** Tiêu đề, subheading 3 benefit, giá headline (giá gốc + net sau cashback hoặc EDU variant), CTA "Nâng cấp PRO ngay".
2. **Live Activity Counter** SSE stream: "X học viên PRO • Y người nâng cấp tuần này", toast "Nguyễn V\*\*\* vừa nâng cấp PRO" slide in/out.
3. **Benefits Bento** 6 BentoPanel: Hạn mức AI Tutor tăng 10x (USP chính), AI Planner + 3 Reflection, AI Grading Discount, PRO Cashback, Portfolio PRO + PDF Export, T5Lab/Docs Advantages. AI Mock Interview **không** phải PRO-only nó chạy qua hạn mức chat nên PRO dùng được nhiều hơn gấp 10x.
4. **Compare Table** 3 cột (Feature / FREE / PRO), ground truth từ `getProBenefitsMatrix()` (số liệu đọc live từ SystemConfig qua `tierBenefitService`). Mobile: stacked card per feature.
5. **Testimonial Carousel** Curate qua SystemConfig key `PRO_TESTIMONIALS` (JSON). Ẩn hoàn toàn nếu list trống không placeholder fake.
6. **FAQ** 5 accordion objection-handling từ sales playbook (giá, vs coach, AI accuracy, EDU vs cashback, refund).
7. **Pricing Card** Breakdown: giá gốc / giảm EDU hoặc cashback sẽ nhận / thực trả. CTA confirm Dialog.
8. **Bottom CTA** Final CTA anchor.

### 20.3 Giá Cả & Benefit Qua SystemConfig

Tất cả số liệu tài chính và giới hạn tính năng đọc từ SystemConfig không hardcode:

| Key hiện có                                                | Mục đích                                                   |
| ---------------------------------------------------------- | ---------------------------------------------------------- |
| `PRO_UPGRADE_PRICE`                                        | Giá gốc PRO (VND)                                          |
| `PRO_CASHBACK_AMOUNT`                                      | Cashback khi nâng cấp (VND) chỉ áp dụng nếu không phải EDU |
| `EDU_PRO_DISCOUNT_PERCENT`                                 | % giảm cho email giáo dục                                  |
| `T5LAB_FREE_PROJECT_LIMIT`                                 | Số dự án FREE tối đa                                       |
| `T5LAB_PAGES_FREE_PRICE` / `T5LAB_PAGES_PRO_PRICE`         | Giá AI Pages theo tier                                     |
| `T5LAB_FEATURES_FREE_PRICE` / `T5LAB_FEATURES_PRO_PRICE`   | Giá AI Features theo tier                                  |
| `T5LAB_TESTCASES_FREE_PRICE` / `T5LAB_TESTCASES_PRO_PRICE` | Giá AI Testcases theo tier                                 |
| `T5DOCS_ASK_FREE_LIMIT`                                    | Số lượt Ask miễn phí/ngày                                  |
| `T5DOCS_EDIT_FREE_LIMIT`                                   | Số lượt Edit miễn phí/ngày (chỉ PRO)                       |
| `PRO_AI_DISCOUNT_PERCENT`                                  | % giảm AI Grading cho PRO                                  |

| Key mới (7 keys)              | Default | Mục đích                                          |
| ----------------------------- | ------- | ------------------------------------------------- |
| `PRO_LANDING_STREAM_ENABLED`  | `true`  | Master switch SSE stream                          |
| `PRO_LANDING_STREAM_MIN_SEC`  | `4`     | Interval tối thiểu (giây)                         |
| `PRO_LANDING_STREAM_MAX_SEC`  | `12`    | Interval tối đa (giây)                            |
| `PRO_LANDING_STATS_MIN_SEC`   | `60`    | Stats tối thiểu giây giữa 2 tick                  |
| `PRO_LANDING_ACTIVITY_DAYS`   | `30`    | Pool window (ngày)                                |
| `PRO_TESTIMONIALS`            | `[]`    | JSON array Testimonial[] admin curate             |
| `PRO_LANDING_SHOW_RECENT_MIN` | `5`     | Ngưỡng min "tuần này" trước khi fallback all-time |

### 20.4 SSE Live Social Proof Pure Query Pattern

Giống `/source-code`, live activity được cung cấp qua `/api/landing/pro/stream`, pattern **pure-query** (zero service write touch):

- **Activity source:** Order PAID có `itemType = PRO_UPGRADE`, 30 ngày gần nhất, top 50, shuffle.
- **2 event types:** `stats` (totalProUsers, recentProThisWeek, totalCashbackPaid) và `activity` (1 toast "X\*\*\* vừa nâng cấp PRO").
- **Fallback trống:** nếu `recentProThisWeek < PRO_LANDING_SHOW_RECENT_MIN`, hiển thị "totalProUsers+" thay cho số tuần.
- **Heartbeat comment 15s**, **connection cap 10 phút**, client auto-reconnect.
- **Masking:** re-use `mask.ts` từ `/source-code` `maskName()`, `hashId()`, `getRelativeTime()`.

### 20.5 EDU vs PRO Cashback (MOST IMPORTANT!!!)

Theo §6.3: user `isEduVerified = true` KHÔNG nhận PRO Cashback (chống double benefit). UI phải phân nhánh:

- **User EDU:** hiển thị "Giá EDU: Xđ (giảm Y%)", ẩn dòng cashback.
- **User thường:** hiển thị "Giá gốc → sau cashback → thực trả Zđ".

Logic enforce tại `orderService` (không cần validate lại client).

### 20.6 Compare Matrix (Single Source of Truth)

`getProBenefitsMatrix()` trong `proLandingService.ts` gom live values từ `tierBenefitService` → trả `BenefitRow[]`. Khi admin sửa config, bảng compare tự đồng bộ sau 60s Redis TTL. Sales chỉ cần gửi link `/pro` không cần maintain pricing sheet riêng.

### 20.7 Testimonial Policy

Chỉ curate testimonial thật: tên thật + role thật + ảnh thật (nếu có). Cập nhật qua `/admin/configs` key `PRO_TESTIMONIALS` (JSON). Nếu list trống → `ProTestimonialCarousel` ẩn hoàn toàn. Không seed placeholder để tránh vi phạm trust.

### 20.8 CTA & Order Flow

`ProUpgradeButton` (client island) gọi `createProUpgradeOrderAction()` → `orderService.createOrder(PRO_UPGRADE)`:

- Ví đủ → Order PAID → `Profile.tier = PRO` + `pdfExportEnabled = true` + PRO Cashback (nếu không EDU) → redirect `/profile`.
- Ví thiếu → Order PENDING → redirect `/orders/[id]` (flow QR Sepay).
- Chưa login → redirect `/login?next=/pro`.

Bắt buộc `trackClarityEvent` tại: page view, mỗi CTA click, confirm dialog, success, insufficient wallet.

### 20.9 SEO

- `generateMetadata` riêng: title + description + canonical `https://t5edu.site/pro` + OG image.
- Trong `sitemap.ts` với `priority: 0.8`.
- Không noindex.

### 20.10 Out of Scope

- Demo Mock Interview nhúng trực tiếp (rủi ro AI abuse defer Option B).
- Checkout online / payment gateway quốc tế.
- A/B test pricing variant.
- Auto-populate testimonial từ rating system (chưa có model).
- Org pitch section riêng trong `/pro`.

### 20.11 Plan Kỹ Thuật

Chi tiết implementation tại `plans/PLAN-079-pro-landing.md`.


