Tài liệu này tổng hợp toàn bộ thông tin về dự án PhiloMind — từ mục tiêu sản phẩm, đối tượng người dùng, nội dung học thuật, đến kiến trúc kỹ thuật, mô hình dữ liệu và quy trình vận hành. Đây là bản đặc tả tổng hợp (master spec); với chi tiết kỹ thuật sâu hơn từng mảng, xem thêm các tài liệu chuyên biệt liệt kê ở Tài liệu liên quan.
Cập nhật lần cuối: 2026-07-24.
- Tổng quan sản phẩm
- Đối tượng người dùng & vai trò
- Nội dung học thuật (chương trình học)
- Tính năng theo góc nhìn người dùng
- Kiến trúc hệ thống
- Stack công nghệ
- Cấu trúc thư mục monorepo
- Mô hình dữ liệu (Prisma/PostgreSQL)
- Hệ thống Lesson Flow (bài học dạng component)
- Backend API
- Frontend học viên (Learner)
- Admin Portal
- AI, TTS & tích hợp bên thứ ba
- Xác thực & phân quyền
- Thiết kế UI/UX
- Vận hành & triển khai (DevOps)
- Kiểm thử & chất lượng
- Quy trình phát triển & cộng tác
- Giới hạn hiện tại & định hướng
- Tài liệu liên quan
PhiloMind là một nền tảng học tập được hỗ trợ bởi AI, chuyển đổi một giáo trình triết học truyền thống (dạng văn bản tuyến tính, khô khan) thành một hành trình học tập có hướng dẫn (guided journey), giàu tính tương tác và đa giác quan.
Nội dung học thuật hiện tại của hệ thống là "Triết học Mác – Lênin" — môn học đại cương bắt buộc trong chương trình giáo dục đại học tại Việt Nam. Toàn bộ kiến trúc component/kỹ thuật, tuy vậy, được thiết kế trung lập theo môn học (subject-agnostic): bất kỳ giáo trình nào cũng có thể được số hoá theo cùng một mô hình Course → Chapter → ConceptNode → lessonFlow.
- Giáo trình triết học lý luận truyền thống thường dài, trừu tượng, khó tạo động lực tự học.
- Người học khó tự đánh giá mình đã hiểu đúng khái niệm hay chưa, thiếu phản hồi tức thời.
- Ôn tập ngắn hạn trước kỳ thi thường không tạo trí nhớ dài hạn.
- Thiếu môi trường để rèn tư duy phản biện (một kỹ năng cốt lõi của triết học) ngoài lớp học truyền thống.
- Hành trình học có cấu trúc: giáo trình được chẻ nhỏ thành các
ConceptNode(đơn vị học tập nguyên tử), sắp xếp theoChapter, hiển thị dưới dạng sơ đồ tư duy (mindmap) trực quan hoá lộ trình. - Bài học tương tác đa dạng component: mỗi
ConceptNodekhông phải một trang văn bản, mà là một chuỗi (lessonFlow) gồm nhiều loại hoạt động — hội thoại dẫn truyện, video, trắc nghiệm, kéo-thả phân loại, ghép cặp, lắp ráp chuỗi nhân quả, mảnh ghép kiến thức, dòng thời gian, mini-game trí nhớ... — giữ người học chủ động thay vì đọc thụ động. - Tranh luận Socratic với AI: học viên luyện phản biện tư duy bằng cách tranh luận trực tiếp với AI đóng vai người phản biện.
- Thẻ ghi nhớ ngắt quãng (Spaced Repetition/SM-2): hệ thống flashcard tự tính lịch ôn tập tối ưu để kiến thức đi vào trí nhớ dài hạn.
- Podcast hội thoại do AI tổng hợp: học viên có thể nghe lại nội dung dưới dạng audio (text-to-speech) khi không tiện đọc.
- PhilosoFUN: nội dung giải trí nhẹ nhàng (video) liên quan triết học, giảm áp lực học thuật.
| Vai trò | Mô tả | Quyền hạn chính |
|---|---|---|
| Học viên (student) | Người dùng cuối, thường là sinh viên đang học môn Triết học Mác – Lênin | Học bài, làm quiz, ôn flashcard, tranh luận với AI, nghe podcast, bình luận, gửi phản hồi (feedback) |
| Quản trị viên (admin) | Ban giảng huấn/vận hành nội dung | Toàn quyền CRUD: khoá học, chương, node bài học (soạn lessonFlow dạng JSON), flashcard, quiz, chủ đề tranh luận, video PhilosoFUN, quản lý người dùng, xem toàn bộ phản hồi/feedback |
Vai trò được lưu trong field User.role ("student" mặc định, "admin" cho quản trị), gán quyền qua RolesGuard + decorator @Roles("admin") ở backend.
Khoá học seed mặc định: "Triết học Mác – Lênin", chia thành các chương (Chapter), mỗi chương chứa nhiều node khái niệm (ConceptNode):
- Khái niệm triết học
- Nguồn gốc của triết học (nhận thức + xã hội)
- Đối tượng của triết học trong lịch sử
- Triết học — hạt nhân lý luận của thế giới quan
- Vấn đề cơ bản của triết học
- Biện chứng và siêu hình
- Sự ra đời và phát triển (của triết học Mác – Lênin)
- Đối tượng và chức năng
- Vai trò trong đời sống xã hội
- Vật chất và ý thức
- Phép biện chứng duy vật
- Lý luận nhận thức
- Quan niệm về phạm trù vật chất & Cuộc cách mạng khoa học tự nhiên (khủng hoảng vật lý)
- Phương thức tồn tại của vật chất & Tính thống nhất vật chất
- Nguồn gốc, bản chất và kết cấu của ý thức
- Mối quan hệ giữa vật chất và ý thức
- Hai loại hình biện chứng và phép biện chứng duy vật
- Hai nguyên lý cơ bản của phép biện chứng duy vật
- Các cặp phạm trù cơ bản
- Ba quy luật cơ bản
- Quan niệm về nhận thức trong lịch sử triết học
- Nguồn gốc, bản chất và các giai đoạn nhận thức
- Thực tiễn và vai trò của thực tiễn đối với nhận thức
- Quan điểm của CNDVBC về chân lý
- Hình thái kinh tế – xã hội
- Sản xuất vật chất; biện chứng lực lượng sản xuất – quan hệ sản xuất
- Cơ sở hạ tầng và kiến trúc thượng tầng
- Nguồn gốc giai cấp; đấu tranh giai cấp
- Nhà nước và cách mạng xã hội
- Bản chất con người; quần chúng và lãnh tụ
- Trắc nghiệm tổng hợp theo từng chương (
Quiz) + đề thi thử tổng hợp. - Tài liệu PDF: giáo trình đầy đủ, giáo trình từng chương, bản tóm tắt chi tiết từng chương (
Document). - Chủ đề tranh luận Socratic có sẵn (
DebateTopic): "Chủ nghĩa Duy vật vs Chủ nghĩa Duy tâm", "Giá trị thặng dư trong kỷ nguyên số & AI", "Ý thức và Trí tuệ nhân tạo (AI)"... - Mini-game khởi động (
Warmup) gắn theo từng node: "Kính lọc cuộc đời" (phân loại thế giới quan), "Từ sấm sét đến quy luật", "Hai mảnh ghép khai sinh triết học", "Nhìn hình đoán khái niệm", "Mẩu chuyện triết học kinh điển".
Dữ liệu bài học đã chuyển đổi sang dạng component được lưu ở data/lesson_components/*.json (nguồn seed cho các lesson đã publish); script backend/prisma/reseed_lessons.ts dùng để nạp lại DB từ các file này.
Dashboard tổng quan: banner giới thiệu, các tính năng cốt lõi, mốc lịch sử triết học, lối vào nhanh các mục chính.
- Hiển thị toàn bộ khoá học dưới dạng sơ đồ tư duy tương tác (mindmap, dùng React Flow), thể hiện quan hệ chương → node.
- Node bị khoá (
locked) cho đến khi node trước hoàn thành; mở khoá tuần tự (available→in_progress→completed). - Mở một node sẽ chuyển sang trình phát bài học toàn màn hình (Flow Lesson Player).
Bố cục 2 cột khoá cứng 50/50:
- Cột trái: media trung tâm (video/hình ảnh) + thanh milestone.
- Cột phải: nội dung tương tác hiện tại (component đang active trong
lessonFlow). - Thanh tiến trình phía trên: các bước trong bài học dưới dạng pill có thể bấm để nhảy tới (nếu đã mở khoá), cuộn ngang mượt, nhãn tự động rút gọn.
- Nút "Học lại bài này từ đầu" để reset tiến trình.
- Nhiều loại component tương tác khác nhau xen kẽ nhau trong một bài học (xem mục 9).
- Flashcard ôn tập: thuật toán lặp ngắt quãng kiểu SM-2 (
ease1-4, tính lạiinterval/nextReview), ôn theo "đến hạn hôm nay" hoặc theo từng chương. - Ghép cặp (Shinkei): mini-game trí nhớ lật thẻ ghép cặp khái niệm.
- Quiz tổng hợp: trắc nghiệm/ghép cặp/tự luận/phân tích/theo hình ảnh theo từng chương hoặc đề thi thử.
- Tranh luận Socratic với AI theo kịch bản có sẵn (
DebateTopic) hoặc theo khái niệm bài học (ConceptNode). - AI đóng vai người phản biện, đặt câu hỏi truy vấn sâu để thử thách lập luận của học viên (throttle 5 request/phút để chống lạm dụng).
- Lịch sử tranh luận được lưu trọn vẹn (
Debate.transcript).
Thư viện video giải trí/minh hoạ triết học ngắn, không gắn với tiến trình học chính thức.
Kho tài liệu PDF tham khảo (giáo trình đầy đủ, tóm tắt từng chương) do admin tải lên.
Tuỳ chỉnh cá nhân (theme sáng/tối, tuỳ chọn mở khoá toàn bộ nội dung ở chế độ dev cho việc kiểm thử).
- Học viên có thể bình luận trực tiếp trên từng node bài học (
Comment). - Gửi phản hồi chung về sản phẩm qua form khảo sát (
Feedback), admin xem toàn bộ danh sách.
Monorepo 4 dịch vụ độc lập, giao tiếp qua REST API:
flowchart LR
Learner["Learner frontend\nReact + Vite"] --> API["Backend API\nNestJS"]
Admin["Admin portal\nReact + Vite"] --> API
API --> DB["PostgreSQL\n(qua Prisma)"]
API --> Supabase["Supabase\nAuth + Storage"]
API --> LLM["LLM tương thích OpenAI\n(mặc định OpenRouter)"]
API --> TTS["TTS worker\nFastAPI + Kokoro ONNX"]
TTS --> API
- PostgreSQL (qua Prisma) là nguồn dữ liệu chính thức (system of record).
- Supabase dùng cho Auth (đăng nhập bên thứ ba) và Storage (lưu file/ảnh/video); có cơ chế fallback lưu local/mock khi chưa cấu hình Supabase.
- LLM (mặc định qua OpenRouter, tương thích chuẩn OpenAI) phục vụ tính năng tranh luận Socratic; có nội dung fallback khi chưa cấu hình API key thật, để demo local vẫn chạy được.
- TTS worker (FastAPI + Kokoro ONNX) tổng hợp giọng đọc cho podcast, tách thành dịch vụ riêng để không chặn backend chính khi xử lý audio.
| Thành phần | Công nghệ chính | Phiên bản tiêu biểu |
|---|---|---|
| Backend API | NestJS, TypeScript, Prisma ORM | NestJS ^11, Prisma ^5.7, TypeScript ^5.1 |
| Database | PostgreSQL (image có pgvector cho local dev) | PostgreSQL 15 |
| Learner frontend | React, Vite, Tailwind CSS, TanStack Query (React Query), React Router | React ^18.3, Vite ^7.3, Tailwind ^3.4 |
| Admin frontend | React, Vite, Tailwind CSS | React ^18.3, Vite ^7.3 |
| Kéo-thả tương tác | @dnd-kit/core + @dnd-kit/sortable |
^6.3 |
| Sơ đồ tư duy | React Flow | — |
| TTS worker | FastAPI, Kokoro ONNX (onnxruntime), soundfile | FastAPI ≥0.109 |
| Auth | JWT (Passport), Google ID token, Supabase JWT | Passport ^0.7 |
| Rate limiting | @nestjs/throttler |
^6.5 |
| Testing | Vitest (frontend/admin), Jest/NestJS test runner (backend) | — |
| CI/CD | GitHub Actions | — |
| Container hoá | Docker, docker-compose.yml cho local stack |
— |
| Hosting production | Hugging Face Spaces (backend + TTS worker), Vercel (frontend học viên, dựa theo domain philo-mind-tau.vercel.app quan sát trong quá trình vận hành) |
— |
PhiloMind/
├── backend/ NestJS REST API, Prisma schema, seed scripts, tích hợp AI/TTS/storage
│ ├── prisma/ schema.prisma, seed.ts, sql/reseed_lessons_manual.sql
│ └── src/
│ ├── auth/ JWT strategy, guard, role guard/decorator
│ ├── users/ đăng nhập local/Google/Supabase, CRUD user, feedback
│ ├── courses/ course, chapter, concept node, journey, lesson flow, progress, comment, document, podcast, upload
│ ├── flashcards/ due card, review SM-2, CRUD, bulk import
│ ├── quizzes/ CRUD quiz, lọc theo node
│ ├── debate/ phiên tranh luận Socratic (theo topic hoặc theo node) qua AIService
│ ├── philosofun/ CRUD video giải trí
│ ├── ai/ client tương thích OpenAI, có fallback khi không có API key
│ ├── tts/ proxy sang TTS worker + upload Supabase/local
│ ├── supabase/ client Supabase + storage helper (có mock fallback)
│ └── database/ Prisma client wrapper (chuẩn hoá URL pooler, giới hạn concurrency)
├── frontend/ Learner React app (journey mindmap, lesson player, quiz, debate, flashcard, settings)
│ └── src/pages/lesson/ Toàn bộ hệ thống chơi bài học dạng flow + component
├── admin/ Admin React app (CRUD nội dung & người dùng)
├── tts_worker/ FastAPI speech worker trả về audio WAV
├── data/lesson_components/ File JSON nội dung bài học đã chuyển đổi (nguồn seed)
├── docs/ Tài liệu kỹ thuật hiện hành (file này + các tài liệu chuyên biệt)
├── scripts/ Tiện ích kiểm tra sức khoẻ hệ thống/tích hợp
└── .github/workflows/ CI + workflow deploy Hugging Face (backend, TTS worker)
User 1---* Course 1---* Chapter 1---* ConceptNode 1---* Flashcard
| | (tự tham chiếu: |---1 Podcast
| | parentChapter/subChapters) |---* Warmup
|---* Progress *---1 ConceptNode |---* Comment
|---* Debate *---1 ConceptNode (hoặc *---1 DebateTopic) |---* Quiz
|---* FlashcardReview *---1 Flashcard |---* Debate
|---* Comment |---* Progress
|---* Feedback
| Model | Vai trò | Trường đáng chú ý |
|---|---|---|
User |
Định danh học viên/admin | role (student/admin), streak, quan hệ tới progress/debates/reviews/feedbacks/comments/courses |
Course |
Container chứa chương và tài liệu | title, description, thuộc về 1 User (chủ sở hữu nội dung) |
Chapter |
Cấu trúc phân cấp có thứ tự | orderIndex, parentChapterId (tự tham chiếu để hỗ trợ chương con) |
ConceptNode |
Đơn vị học tập trung tâm | lessonFlow (JSON), lessonMedia (JSON), lessonType (mặc định "flow"), contentReady, lessonStatus (draft/published/archived), difficulty, timeToRead, videoUrl, orderIndex |
Progress |
Trạng thái học của từng user với từng node | status, lessonCompleted, activeComponentId, currentComponentIndex, completedComponentIds (JSON), componentResults (JSON) — unique theo (userId, nodeId) |
Flashcard / FlashcardReview |
Nội dung thẻ ghi nhớ + lịch sử ôn tập | ease (1-4), interval (ngày), nextReview |
Podcast |
Audio + transcript cho 1 node | audioUrl, transcript (JSON mảng {time, speaker, text}) — quan hệ 1-1 với ConceptNode |
DebateTopic / Debate |
Chủ đề tranh luận tái sử dụng + phiên tranh luận của user | transcript (JSON mảng tin nhắn); Debate có thể gắn với nodeId hoặc topicId |
Warmup |
Hoạt động khởi động ngắn trước bài học | type (image-guess/story), blanks, answer, options, correctIndex |
Quiz |
Nội dung quiz/game độc lập | type (mcq/matching/essay/image/analysis), questions (JSON) |
Comment |
Bình luận theo node | role để phân biệt bình luận của học viên/admin |
Document |
Tham chiếu file PDF/tài liệu | status (parsing/completed/failed) |
Feedback |
Phản hồi sản phẩm từ người dùng | content |
Philosofun |
Metadata video giải trí | videoUrl |
Chi tiết đầy đủ từng field: xem backend/prisma/schema.prisma.
Đây là phần lõi khác biệt nhất của sản phẩm: mỗi ConceptNode không chứa văn bản tĩnh mà chứa lessonFlow — một mảng JSON có thứ tự các "component" (bước học), mỗi bước là một loại hoạt động tương tác riêng biệt.
lessonFlow: mảng JSON các bước học cấp cao nhất; mỗi bước cóid(duy nhất toàn flow, kể cả bên trong nhóm),type,config, tuỳ chọntitle,linkedMediaId,completionRule.lessonMedia: mảng media tuỳ chọn cho cột giữa (video/hình ảnh), độc lập vớilessonFlownhưng có thể liên kết qualinkedMediaId.- Bài học chỉ mở được cho học viên khi đồng thời
contentReady === truevàlessonStatus === "published"— cả ở UI lẫn API backend (chặn cứng, không chỉ ẩn UI). component_group: gom nhiều component con (ví dụ hội thoại + câu hỏi) thành một hoạt động học liền mạch về mặt trải nghiệm người dùng — không hiển thị khái niệm kỹ thuật "group" cho học viên.
| Loại | Trải nghiệm học viên |
|---|---|
component_group |
Nhóm nhiều component con thành một hoạt động liền mạch |
dialogue |
Hội thoại dẫn truyện giữa các nhân vật (bong bóng chat kiểu đám mây) |
media |
Xác nhận đã xem/đọc media (video/ảnh) |
markdown |
Đọc nội dung văn bản định dạng |
target_matching / map_target_matching |
Kéo-thả khớp mục vào đích (kể cả đích có toạ độ trên bản đồ/hình ảnh) |
category_sorting |
Phân loại thẻ vào đúng nhóm |
mindmap_reveal |
Mở khoá dần các thẻ khái niệm trên bản đồ tư duy toả tia |
mcq |
Trắc nghiệm 1 câu, phản hồi sai chỉ chớp đỏ tạm thời rồi tự reset |
quiz_sequence |
Chuỗi nhiều câu trắc nghiệm |
multi_select |
Câu hỏi nhiều đáp án đúng |
matching_columns |
Ghép cột trái–phải (hỗ trợ nhiều-tới-một) |
true_false |
Câu hỏi đúng/sai |
sequence_sorting / chain_sorting |
Sắp xếp thứ tự/chuỗi nhân quả (chọn theo số thứ tự, kiểm tra trực tiếp, không lộ đáp án) |
knowledge_piece |
Thẻ "mảnh ghép kiến thức" ngắn, hiệu ứng bay vào milestone khi thu thập |
progression_spiral |
Mở dần các mốc trên một mặt xoắn ốc/tiến trình |
timeline_explorer |
Khám phá các giai đoạn lịch sử, có trạng thái đã xem lưu lại |
hotspot_gallery |
Mở các điểm nóng trên ảnh/thẻ để đọc chi tiết |
shinkei_matching |
Mini-game trí nhớ lật thẻ ghép cặp 2 cột |
final_summary |
Màn hình tổng kết hoàn thành bài học |
fill_in_blanks |
Điền/chọn từ khoá còn thiếu trong đoạn văn |
- Admin soạn/sửa
lessonFlow(dạng JSON) trong/nodescủa admin portal. - Backend validate cấu trúc bằng
NodeSchemaValidatortrước khi lưu. - Học viên mở
/lessons?lesson=<slug>→useJourneytải lộ trình →useNodeDetailstải chi tiết node. FlowLessonPlayerchuẩn hoá flow, dựng danh sách media, chọn vị trí tiếp tục (resume), render layout 2 cột.RightInteractivechọn renderer tương ứng từcomponentRegistrytheotype.- Hoàn thành mỗi component gọi
PATCH /api/courses/nodes/:nodeId/component-progress. - Hoàn thành component cuối cùng gọi
POST /api/courses/nodes/:nodeId/complete→ backend đánh dấu hoàn thành node và mở khoá node tiếp theo.
Đặc tả chi tiết từng loại component, cấu trúc JSON, quy tắc ảnh inline, ví dụ mẫu: xem LESSON_COMPONENTS.md.
Base URL local: http://localhost:3001/api (health check / và /health nằm ngoài prefix /api). Swagger sống tại /docs khi NODE_ENV !== "production" hoặc ENABLE_SWAGGER=true.
| Nhóm | Mô tả |
|---|---|
| Auth & Users | Đăng ký/đăng nhập local, Google, Supabase; CRUD user (admin); feedback |
| Courses/Chapters/Nodes/Documents/Files | CRUD khoá học/chương/node; roadmap hành trình; chi tiết node; tiến trình cấp node & cấp component; upload file/ảnh/video |
| Warmups & Comments | CRUD warmup theo node; bình luận theo node |
| Podcasts & TTS | CRUD podcast; tổng hợp audio preview (throttled) |
| Flashcards | Thẻ đến hạn, submit review, CRUD, bulk import |
| Quizzes | CRUD quiz, lọc theo node |
| Debate | Chủ đề tranh luận, gửi tin nhắn tranh luận (throttled), quản trị phiên tranh luận |
| Philosofun | CRUD video |
Quy tắc xác thực: endpoint công khai chỉ có các entrypoint auth; phần lớn API yêu cầu JWT; thao tác tạo/sửa/xoá và một số danh sách/chi tiết yêu cầu vai trò admin. Endpoint gửi tin nhắn tranh luận và tổng hợp podcast bị giới hạn 5 request/phút/route để chống lạm dụng.
Danh sách endpoint đầy đủ theo method/path/auth: xem API.md.
| Route | Chức năng |
|---|---|
/ |
Dashboard trang chủ |
/practice |
Khu luyện tập (flashcard/ghép cặp/quiz) |
/practice/shinkei/:id |
Mini-game trí nhớ ghép cặp |
/debate |
Góc tranh luận Socratic |
/lessons |
Sơ đồ hành trình + trình phát bài học |
/philosofun |
Video giải trí |
/docs |
Tài liệu tham khảo trong app |
/settings |
Cài đặt người dùng |
/login, /register |
Xác thực |
/quiz/matching/:id, /quiz/analysis/:id, /quiz/essay/:id, /quiz/mcq/:id, /image-quiz/:id |
Các route quiz chuyên biệt |
Các thành phần dữ liệu quan trọng: services/api.js (fetch wrapper gắn JWT), services/queryKeys.js (khoá React Query tập trung), hooks/useJourney.js, hooks/useNodeDetails.js, hooks/useMutations.js.
| Route | Chức năng |
|---|---|
/login |
Đăng nhập admin |
/ |
Dashboard |
/users |
Quản lý người dùng |
/courses |
Quản lý khoá học |
/nodes |
Soạn chương/node, lessonFlow (JSON), upload media, warmup, flashcard, quiz, podcast, tài liệu |
/practice |
Quản lý nội dung luyện tập |
/debates |
Quản lý chủ đề/phiên tranh luận |
/philosofun |
Quản lý video |
/nodes (admin/src/pages/Nodes.jsx) là khu vực thao tác phức tạp nhất: lessonFlow hiện được soạn trực tiếp dưới dạng JSON thô — validation phía backend là hàng rào chính ngăn dữ liệu sai cấu trúc được lưu.
- AI (tranh luận Socratic):
AIServicegọi một LLM tương thích chuẩn OpenAI (mặc định trỏ tới OpenRouter, model mặc địnhmeta-llama/llama-3-70b-instruct:free). Khi không cấu hìnhOPENAI_API_KEY, hệ thống dùng nội dung fallback để demo local vẫn hoạt động được. - TTS (podcast): backend
TTSServicegọi sangtts_worker(FastAPI + Kokoro ONNX) để tổng hợp giọng đọc từ văn bản, kết quả audio được lưu qua Supabase Storage hoặc local/mock storage. - Supabase: dùng cho Auth (đăng nhập bên thứ ba, đối chiếu JWT) và Storage (ảnh, video, audio). Có cơ chế mock/local fallback khi chưa cấu hình để không chặn phát triển local.
- Google OAuth: đăng nhập bằng Google ID token, backend xác thực và map vào
Usernội bộ.
- 3 phương thức đăng nhập: local (email/mật khẩu), Google ID token, Supabase JWT — tất cả quy về một JWT nội bộ do backend phát hành.
JwtAuthGuardbảo vệ phần lớn endpoint;RolesGuard+@Roles("admin")bảo vệ thao tác quản trị.- Một số endpoint cho phép chủ sở hữu (owner) hoặc admin (ví dụ xem thông tin user).
- Học viên không thể truy cập nội dung
draft/chưacontentReadydù có JWT hợp lệ — chặn ở cả tầng API, không chỉ tầng UI.
Nguyên tắc sản phẩm:
- Làm cho triết học "có cấu trúc, dễ điều hướng, dễ thảo luận" — giảm tải nhận thức thay vì thêm chi tiết trang trí.
- Luôn cho học viên thấy ngữ cảnh học tập trước khi vào nội dung sâu.
- Ưu tiên hành động tiếp theo rõ ràng, tránh tiến trình ẩn.
- Không để lộ thuật ngữ schema kỹ thuật (như "component group") cho học viên.
- Màn hình admin: dày đặc thao tác, tối ưu vận hành; màn hình học viên: dẫn dắt, phản chiếu.
- Bố cục trình phát bài học: khoá cứng 2 cột 50/50 (không cho kéo–thả resize, tránh vỡ layout), media bên trái, hoạt động học bên phải.
- Bảng màu chính: tông teal-blue sáng (
primarypalette trong Tailwind config), hỗ trợ đầy đủ sáng/tối (darkclass + biến CSS).
Chi tiết & quy ước UI đầy đủ: xem DESIGN_SYSTEM.md.
cp .env.example .env
docker compose up --buildCổng mặc định: Frontend 3000, Backend 3001, Admin 3002, TTS worker 8000, PostgreSQL 5432.
DATABASE_URL, JWT_SECRET, GOOGLE_CLIENT_ID, ALLOWED_ORIGINS, ENABLE_SWAGGER, SUPABASE_URL/SUPABASE_ANON_KEY/SUPABASE_SERVICE_ROLE_KEY, OPENAI_API_KEY/OPENAI_API_BASE_URL/LLM_MODEL, TTS_WORKER_URL, cùng nhóm biến pool Prisma (PRISMA_CONNECTION_LIMIT, DB_QUERY_CONCURRENCY...).
| Workflow | Trigger | Đích |
|---|---|---|
ci.yml |
Push/PR vào main/master |
Test + build backend/frontend/admin |
deploy_backend.yml |
Thay đổi trong backend/ |
Hugging Face Space Cuong2004/PhiloMind |
deploy_tts.yml |
Thay đổi trong tts_worker/ |
Hugging Face Space Cuong2004/PhiloMind_TTSworker |
Backend lắng nghe cổng 7860 khi chạy trên Hugging Face Spaces (biến SPACE_ID), ngược lại dùng PORT/3001. Frontend học viên deploy qua Vercel.
Lưu ý vận hành đã rút ra thực tế: dự án dùng prisma db push (không dùng migration lịch sử) — mỗi khi schema.prisma thay đổi (thêm cột), cần chạy db push lên DB production, nếu không backend sẽ lỗi P2022 (cột không tồn tại) và toàn bộ API trả về lỗi, gây cảm giác "mất kết nối database" dù bản chất là lệch schema.
Checklist bảo mật & smoke-test sau deploy đầy đủ: xem OPERATIONS.md.
cd backend && npm run test -- --runInBand
cd frontend && npm run test -- --run && npm run build
cd admin && npm run test -- --run && npm run buildCI (GitHub Actions) chạy test + build verification cho cả 3 app con ở mỗi push/PR vào main/master.
- Quy trình chuẩn cho mọi thay đổi code: Issue → Pull Request → Review/Merge trên GitHub, kèm build + test xanh trước khi merge.
- Nhánh chính:
main. - Author commit chuẩn hoá theo tài khoản GitHub thật của người thực hiện thay đổi (không dùng AI co-author trên các commit hướng tới lịch sử đóng góp công khai).
- Nội dung bài học được author bởi ban giảng huấn qua admin portal (JSON
lessonFlow) hoặc qua các file JSON trongdata/lesson_components/rồi reseed vào DB.
Những điểm hạn chế/nợ kỹ thuật đã biết tại thời điểm viết tài liệu:
- Soạn bài học vẫn ở dạng JSON thô trong admin portal (
Nodes.jsx) — chưa có trình soạn thảo trực quan (visual editor) cholessonFlow; rủi ro nhập sai cấu trúc phụ thuộc hoàn toàn vào validator backend. - Không có lịch sử migration Prisma (dùng
db pushtrực tiếp) — thuận tiện cho tốc độ phát triển nhưng đòi hỏi kỷ luật vận hành cao khi đổi schema trên production để tránh lệch schema DB thực. - Biến môi trường frontend vẫn giữ tiền tố
REACT_APP_*dù runtime đã chuyển sang Vite (kế thừa từ giai đoạn dùng Create React App). lessonMediacấp node được backend/player hỗ trợ nhưng admin UI hiện chủ yếu vẫn nhúng media như componentmediabên tronglessonFlowthay vì dùng field riêng.- Một số component bài học (đặc biệt các loại tương tác kéo-thả/scale cao) từng gặp lỗi hiển thị ở tỉ lệ scale màn hình lớn do CSS
overflow-hiddenlồng sai vị trí — đã rà soát và vá, nhưng cần lưu ý khi thêm component mới.
| Tài liệu | Nội dung |
|---|---|
PROJECT_OVERVIEW.md |
Kiến trúc, module, mô hình dữ liệu, luồng chính (bản gốc, tiếng Anh) |
API.md |
Danh mục endpoint đầy đủ theo method/path/auth |
LESSON_COMPONENTS.md |
Đặc tả chi tiết lessonFlow/lessonMedia, từng loại component, ví dụ JSON |
OPERATIONS.md |
Biến môi trường, setup local, pooling Supabase/Postgres, deploy, bảo mật, smoke-test |
DESIGN_SYSTEM.md |
Nguyên tắc UX/UI, quy ước layout, accessibility |
PROPOSED_COMPONENTS.md |
Đề xuất loại component mới đang xem xét |
backend/README.md, frontend/README.md, admin/README.md, tts_worker/README.md |
Tài liệu riêng từng service |