Files
sena_db_api_layer/CONTENT_MANAGEMENT_GUIDE.md
silverpro89 97e2e8402e update
2026-01-19 20:32:23 +07:00

736 lines
19 KiB
Markdown

# 📚 Hướng Dẫn Quản Lý Nội Dung Giảng Dạy và Game
## Tổng Quan Kiến Trúc
Hệ thống nội dung của bạn được xây dựng theo mô hình phân cấp:
```
Subject (Môn học/Giáo trình)
└─ Chapter (Chương)
└─ Lesson (Bài học)
├─ JSON Content → Game Engine render
└─ URL Content → Video/PDF player
```
---
## 📊 Cấu Trúc Models
### 1. Subject (Môn học)
**File**: `models/Subject.js`
**Table**: `subjects`
```javascript
{
id: UUID,
subject_code: 'MATH_G1', // Mã môn học (unique)
subject_name: 'Toán lớp 1', // Tên tiếng Việt
subject_name_en: 'Math Grade 1', // Tên tiếng Anh
description: TEXT, // Mô tả
is_active: true, // Đang hoạt động
is_premium: false, // Nội dung premium
is_training: false, // Đào tạo nhân sự
is_public: false, // Tự học công khai
required_role: 'student', // Role yêu cầu
min_subscription_tier: 'basic' // Gói tối thiểu
}
```
### 2. Chapter (Chương học)
**File**: `models/Chapter.js`
**Table**: `chapters`
```javascript
{
id: UUID,
subject_id: UUID, // FK → subjects
chapter_number: 1, // Số thứ tự chương
chapter_title: 'Số và chữ số', // Tiêu đề
chapter_description: TEXT, // Mô tả
duration_minutes: 180, // Thời lượng (phút)
is_published: true, // Đã xuất bản
display_order: 1 // Thứ tự hiển thị
}
```
### 3. Lesson (Bài học)
**File**: `models/Lesson.js`
**Table**: `lessons`
```javascript
{
id: UUID,
chapter_id: UUID, // FK → chapters
lesson_number: 1, // Số thứ tự bài học
lesson_title: 'Đếm từ 1 đến 5', // Tiêu đề
lesson_type: 'json_content', // hoặc 'url_content'
lesson_description: TEXT,
// Dạng 1: JSON Content (tương tác)
content_json: {
type: 'counting_quiz', // PHẢI khớp với Game.type
questions: [...],
instructions: '...',
pass_score: 70
},
// Dạng 2: URL Content (video/PDF/link)
content_url: 'https://youtube.com/...',
content_type: 'youtube', // video, audio, pdf, external_link
duration_minutes: 15,
is_published: true,
is_free: true, // Học thử miễn phí
display_order: 1,
thumbnail_url: '...'
}
```
### 4. Game (Game Engine/Template)
**File**: `models/Game.js`
**Table**: `games`
```javascript
{
id: UUID,
title: 'Trò chơi đếm số',
description: TEXT,
url: 'https://games.senaai.tech/counting-game/', // HTML5/Unity WebGL
thumbnail: '...',
type: 'counting_quiz', // PHẢI khớp với Lesson.content_json.type
config: {
engine: 'phaser3',
features: ['sound', 'animation'],
controls: ['touch', 'mouse'],
max_time: 300
},
is_active: true,
is_premium: false,
min_grade: 1, // Cấp lớp tối thiểu
max_grade: 3, // Cấp lớp tối đa
difficulty_level: 'easy', // easy, medium, hard
play_count: 0,
rating: 4.5
}
```
---
## 🎯 Cách 1: Thêm Nội Dung Giảng Dạy
### Bước 1: Tạo Subject (Môn học)
```javascript
const { Subject, Chapter, Lesson } = require('./models');
// Tạo môn Toán lớp 1
const mathSubject = await Subject.create({
subject_code: 'MATH_G1',
subject_name: 'Toán lớp 1',
subject_name_en: 'Math Grade 1',
description: 'Chương trình Toán học lớp 1 theo SGK mới',
is_active: true,
is_premium: false,
is_public: true,
min_subscription_tier: 'basic'
});
```
### Bước 2: Tạo Chapter (Chương)
```javascript
const chapter1 = await Chapter.create({
subject_id: mathSubject.id,
chapter_number: 1,
chapter_title: 'Số và chữ số',
chapter_description: 'Làm quen với các số từ 1 đến 10',
duration_minutes: 180,
is_published: true,
display_order: 1
});
const chapter2 = await Chapter.create({
subject_id: mathSubject.id,
chapter_number: 2,
chapter_title: 'Phép cộng trong phạm vi 10',
chapter_description: 'Học cộng các số từ 1 đến 10',
duration_minutes: 240,
is_published: true,
display_order: 2
});
```
### Bước 3a: Tạo Lesson với JSON Content (Tương tác)
```javascript
const lesson1 = await Lesson.create({
chapter_id: chapter1.id,
lesson_number: 1,
lesson_title: 'Đếm từ 1 đến 5',
lesson_type: 'json_content',
lesson_description: 'Học đếm các số từ 1 đến 5 qua trò chơi',
content_json: {
type: 'counting_quiz', // Khớp với Game có type='counting_quiz'
theme: 'fruits',
questions: [
{
id: 1,
question: 'Có bao nhiêu quả táo?',
image: 'https://cdn.senaai.tech/images/apples-3.png',
correct_answer: 3,
options: [2, 3, 4, 5]
},
{
id: 2,
question: 'Có bao nhiêu quả cam?',
image: 'https://cdn.senaai.tech/images/oranges-5.png',
correct_answer: 5,
options: [3, 4, 5, 6]
}
],
instructions: 'Nhìn vào hình và đếm số lượng vật, sau đó chọn đáp án đúng',
pass_score: 70,
max_attempts: 3,
show_hints: true
},
duration_minutes: 15,
is_published: true,
is_free: true,
display_order: 1,
thumbnail_url: 'https://cdn.senaai.tech/thumbnails/lesson-counting.jpg'
});
```
### Bước 3b: Tạo Lesson với URL Content (Video/PDF)
```javascript
// Video YouTube
const lesson2 = await Lesson.create({
chapter_id: chapter1.id,
lesson_number: 2,
lesson_title: 'Video: Hướng dẫn đếm số',
lesson_type: 'url_content',
lesson_description: 'Video hướng dẫn cách đếm số từ 1 đến 10',
content_url: 'https://www.youtube.com/watch?v=abc123xyz',
content_type: 'youtube',
duration_minutes: 10,
is_published: true,
is_free: false,
display_order: 2
});
// PDF Document
const lesson3 = await Lesson.create({
chapter_id: chapter1.id,
lesson_number: 3,
lesson_title: 'Tài liệu: Bảng số từ 1-10',
lesson_type: 'url_content',
content_url: 'https://cdn.senaai.tech/docs/number-chart-1-10.pdf',
content_type: 'pdf',
duration_minutes: 5,
is_published: true,
is_free: true,
display_order: 3
});
// Audio
const lesson4 = await Lesson.create({
chapter_id: chapter1.id,
lesson_number: 4,
lesson_title: 'Nghe: Phát âm các số',
lesson_type: 'url_content',
content_url: 'https://cdn.senaai.tech/audio/numbers-pronunciation.mp3',
content_type: 'audio',
duration_minutes: 8,
is_published: true,
display_order: 4
});
```
### Bước 3c: Các loại Content JSON khác
```javascript
// Quiz trắc nghiệm
const quizLesson = await Lesson.create({
chapter_id: chapter2.id,
lesson_number: 1,
lesson_title: 'Bài kiểm tra: Phép cộng',
lesson_type: 'json_content',
content_json: {
type: 'multiple_choice_quiz',
time_limit: 600, // 10 phút
questions: [
{
id: 1,
question: '2 + 3 = ?',
options: ['4', '5', '6', '7'],
correct_answer: '5',
explanation: 'Hai cộng ba bằng năm'
},
{
id: 2,
question: '4 + 5 = ?',
options: ['7', '8', '9', '10'],
correct_answer: '9'
}
],
pass_score: 80
},
duration_minutes: 10,
is_published: true
});
// Bài tập tương tác
const interactiveLesson = await Lesson.create({
chapter_id: chapter2.id,
lesson_number: 2,
lesson_title: 'Thực hành: Giải toán cộng',
lesson_type: 'json_content',
content_json: {
type: 'math_practice',
difficulty: 'easy',
operations: ['addition'],
range: { min: 1, max: 10 },
question_count: 20,
show_solution_steps: true,
allow_calculator: false
},
duration_minutes: 20,
is_published: true
});
// Assignment (Bài tập về nhà)
const assignmentLesson = await Lesson.create({
chapter_id: chapter2.id,
lesson_number: 3,
lesson_title: 'Bài tập về nhà: Tuần 1',
lesson_type: 'json_content',
content_json: {
type: 'assignment',
deadline_days: 7,
tasks: [
{
task_id: 1,
title: 'Làm bài tập SGK trang 15',
description: 'Hoàn thành các bài từ 1 đến 5',
points: 10
},
{
task_id: 2,
title: 'Vẽ 5 quả táo và đếm',
description: 'Vẽ hình và viết số',
points: 5,
requires_upload: true
}
],
total_points: 15,
submission_type: 'photo' // photo, pdf, text
},
duration_minutes: 30,
is_published: true
});
```
---
## 🎮 Cách 2: Thêm Game Engine
### Tạo Game Template
```javascript
const { Game } = require('./models');
// Game 1: Đếm số
const countingGame = await Game.create({
title: 'Trò chơi đếm số',
description: 'Game tương tác giúp trẻ học đếm các vật thể',
url: 'https://games.senaai.tech/counting-game/index.html',
thumbnail: 'https://cdn.senaai.tech/game-thumbs/counting.jpg',
type: 'counting_quiz', // Khớp với Lesson.content_json.type
config: {
engine: 'phaser3',
version: '1.0.0',
features: ['sound', 'animation', 'reward_stars'],
controls: ['touch', 'mouse', 'keyboard'],
responsive: true,
max_time_per_question: 60,
hints_enabled: true,
save_progress: true
},
is_active: true,
is_premium: false,
min_grade: 1,
max_grade: 2,
difficulty_level: 'easy',
play_count: 0,
rating: 0,
display_order: 1
});
// Game 2: Quiz trắc nghiệm
const quizGame = await Game.create({
title: 'Trả lời nhanh',
description: 'Trò chơi trắc nghiệm với giới hạn thời gian',
url: 'https://games.senaai.tech/quiz-game/index.html',
thumbnail: 'https://cdn.senaai.tech/game-thumbs/quiz.jpg',
type: 'multiple_choice_quiz',
config: {
engine: 'react',
features: ['timer', 'leaderboard', 'achievements'],
sound_effects: true,
show_correct_answer: true,
retry_allowed: true
},
is_active: true,
is_premium: false,
min_grade: 1,
max_grade: 12,
difficulty_level: 'medium',
display_order: 2
});
// Game 3: Thực hành Toán
const mathPracticeGame = await Game.create({
title: 'Luyện tập Toán',
description: 'Game luyện toán với nhiều cấp độ khó',
url: 'https://games.senaai.tech/math-practice/index.html',
thumbnail: 'https://cdn.senaai.tech/game-thumbs/math.jpg',
type: 'math_practice',
config: {
engine: 'unity_webgl',
features: ['adaptive_difficulty', 'step_by_step_solution', 'scratch_pad'],
controls: ['touch', 'mouse'],
performance_tracking: true
},
is_active: true,
is_premium: true,
min_grade: 1,
max_grade: 6,
difficulty_level: 'medium',
display_order: 3
});
// Game 4: Word Puzzle
const wordPuzzleGame = await Game.create({
title: 'Ghép chữ',
description: 'Trò chơi ghép chữ và học từ vựng',
url: 'https://games.senaai.tech/word-puzzle/index.html',
thumbnail: 'https://cdn.senaai.tech/game-thumbs/word.jpg',
type: 'word_puzzle',
config: {
engine: 'phaser3',
features: ['drag_drop', 'text_to_speech', 'pronunciation'],
languages: ['vi', 'en'],
difficulty_levels: ['easy', 'medium', 'hard']
},
is_active: true,
is_premium: false,
min_grade: 1,
max_grade: 5,
difficulty_level: 'easy',
display_order: 4
});
```
---
## 🔄 Luồng Hoạt Động
### Frontend Flow
```javascript
// 1. Học viên chọn môn học
GET /api/subjects/:subject_id
Trả về thông tin Subject
// 2. Xem danh sách chương
GET /api/subjects/:subject_id/chapters
Trả về danh sách Chapter
// 3. Xem danh sách bài học trong chương
GET /api/chapters/:chapter_id/lessons
Trả về danh sách Lesson
// 4. Học một bài cụ thể
GET /api/lessons/:lesson_id
Trả về chi tiết Lesson
// 5a. Nếu lesson_type = 'json_content'
const lessonType = lesson.content_json.type; // vd: 'counting_quiz'
// Tìm game engine phù hợp
GET /api/games?type=counting_quiz
Trả về Game type khớp
// Load game và truyền content vào
<iframe
src={game.url}
data-content={JSON.stringify(lesson.content_json)}
/>
// 5b. Nếu lesson_type = 'url_content'
if (lesson.content_type === 'youtube') {
<YouTubePlayer url={lesson.content_url} />
} else if (lesson.content_type === 'pdf') {
<PDFViewer url={lesson.content_url} />
} else if (lesson.content_type === 'audio') {
<AudioPlayer url={lesson.content_url} />
}
```
### Game Engine Integration
```javascript
// Trong game engine (ví dụ: counting-game/index.html)
window.addEventListener('message', (event) => {
if (event.data.type === 'LOAD_CONTENT') {
const content = event.data.content; // Lesson.content_json
// Render game với nội dung từ lesson
renderGame({
questions: content.questions,
theme: content.theme,
instructions: content.instructions,
passScore: content.pass_score
});
}
});
// Khi học viên hoàn thành
window.parent.postMessage({
type: 'GAME_COMPLETE',
score: 85,
time_spent: 300,
answers: [...]
}, '*');
```
---
## 📋 API Endpoints Cần Thiết
### Subject Routes (Đã có: `routes/subjectRoutes.js`)
```
GET /api/subjects - Danh sách môn học
GET /api/subjects/:id - Chi tiết môn học
POST /api/subjects - Tạo môn học mới
PUT /api/subjects/:id - Cập nhật môn học
DELETE /api/subjects/:id - Xóa môn học
```
### Chapter Routes (Đã có: `routes/chapterRoutes.js`)
```
GET /api/chapters - Danh sách chương
GET /api/chapters/:id - Chi tiết chương
GET /api/subjects/:id/chapters - Chương của môn học
POST /api/chapters - Tạo chương mới
PUT /api/chapters/:id - Cập nhật chương
DELETE /api/chapters/:id - Xóa chương
```
### Lesson Routes (CẦN TẠO)
```
GET /api/lessons - Danh sách bài học
GET /api/lessons/:id - Chi tiết bài học
GET /api/chapters/:id/lessons - Bài học của chương
POST /api/lessons - Tạo bài học mới
PUT /api/lessons/:id - Cập nhật bài học
DELETE /api/lessons/:id - Xóa bài học
POST /api/lessons/:id/complete - Đánh dấu hoàn thành
```
### Game Routes (Đã có: `routes/gameRoutes.js`)
```
GET /api/games - Danh sách game
GET /api/games/:id - Chi tiết game
GET /api/games?type=xxx - Lọc theo type
POST /api/games - Tạo game mới
PUT /api/games/:id - Cập nhật game
DELETE /api/games/:id - Xóa game
POST /api/games/:id/play - Tăng play_count
POST /api/games/:id/rate - Đánh giá game
```
---
## ✅ Checklist Triển Khai
### Bước 1: Tạo Lesson Routes & Controller
- [ ] Tạo `routes/lessonRoutes.js`
- [ ] Tạo `controllers/lessonController.js`
- [ ] Đăng ký route trong `app.js`
### Bước 2: Tạo Sample Data
- [ ] Tạo script `scripts/seed-sample-content.js`
- [ ] Tạo Subject mẫu (Toán, Tiếng Việt, Tiếng Anh)
- [ ] Tạo Chapter mẫu (3-5 chương mỗi môn)
- [ ] Tạo Lesson mẫu (5-10 bài mỗi chương)
- [ ] Tạo Game template mẫu (3-5 game)
### Bước 3: Update Relations
```javascript
// Trong models/index.js
Subject.hasMany(Chapter, { foreignKey: 'subject_id' });
Chapter.belongsTo(Subject, { foreignKey: 'subject_id' });
Chapter.hasMany(Lesson, { foreignKey: 'chapter_id' });
Lesson.belongsTo(Chapter, { foreignKey: 'chapter_id' });
```
### Bước 4: Thêm Swagger Documentation
- [ ] Thêm Swagger cho Lesson routes
- [ ] Cập nhật schemas trong `config/swagger.js`
### Bước 5: Test
- [ ] Test tạo Subject → Chapter → Lesson
- [ ] Test query lessons theo chapter
- [ ] Test match Game với Lesson.content_json.type
- [ ] Test các loại content khác nhau
---
## 💡 Best Practices
### 1. Lesson Type Naming Convention
```javascript
// Đặt tên theo format: <category>_<action>
'counting_quiz' // Đếm số - Quiz
'multiple_choice_quiz' // Trắc nghiệm
'math_practice' // Luyện toán
'word_puzzle' // Ghép chữ
'reading_comprehension' // Đọc hiểu
'listening_exercise' // Nghe
'speaking_practice' // Luyện nói
'writing_assignment' // Bài tập viết
'project_based' // Dự án
```
### 2. Content JSON Structure
```javascript
{
type: 'xxx', // REQUIRED: Phải khớp với Game.type
version: '1.0', // Version của schema
metadata: { // Optional: Thông tin thêm
author: 'Nguyễn Văn A',
created_at: '2026-01-19',
tags: ['counting', 'basic', 'grade1']
},
config: {}, // Cấu hình riêng của lesson
data: {} // Dữ liệu chính (questions, tasks, etc.)
}
```
### 3. Game Config Structure
```javascript
{
engine: 'phaser3', // Game engine sử dụng
version: '1.0.0',
features: [], // Các tính năng: sound, animation, etc.
controls: [], // touch, mouse, keyboard
responsive: true,
settings: {
max_time: 300,
hints_allowed: true,
retry_count: 3
}
}
```
### 4. Error Handling
```javascript
// Khi student học lesson
if (lesson.lesson_type === 'json_content') {
const lessonType = lesson.content_json.type;
const game = await Game.findOne({
where: {
type: lessonType,
is_active: true
}
});
if (!game) {
// Fallback: Hiển thị content JSON dạng text/list
console.warn(`No game found for type: ${lessonType}`);
return renderStaticContent(lesson.content_json);
}
return renderGameWithContent(game, lesson.content_json);
}
```
---
## 🚀 Quick Start Script
Chạy script này để tạo sample data:
```javascript
// scripts/seed-sample-content.js
const { Subject, Chapter, Lesson, Game } = require('../models');
async function seedSampleContent() {
// 1. Tạo Subject
const math = await Subject.create({
subject_code: 'MATH_G1',
subject_name: 'Toán lớp 1',
is_active: true,
is_public: true
});
// 2. Tạo Chapter
const chapter = await Chapter.create({
subject_id: math.id,
chapter_number: 1,
chapter_title: 'Số và chữ số',
is_published: true
});
// 3. Tạo Lesson
const lesson = await Lesson.create({
chapter_id: chapter.id,
lesson_number: 1,
lesson_title: 'Đếm từ 1 đến 5',
lesson_type: 'json_content',
content_json: {
type: 'counting_quiz',
questions: [
{
question: 'Có bao nhiêu quả táo?',
image: '/images/apples-3.png',
answer: 3,
options: [2, 3, 4, 5]
}
]
},
is_published: true,
is_free: true
});
// 4. Tạo Game
const game = await Game.create({
title: 'Trò chơi đếm số',
url: 'https://games.senaai.tech/counting/',
type: 'counting_quiz',
is_active: true
});
console.log('✅ Sample content created successfully!');
}
seedSampleContent();
```
Chạy: `node scripts/seed-sample-content.js`
---
## 📞 Support
Nếu cần hỗ trợ thêm:
1. Tạo Lesson Routes & Controller
2. Tạo script seed data mẫu
3. Cập nhật Swagger documentation
4. Tạo frontend component để render lesson
Hãy cho tôi biết bạn muốn tôi implement phần nào! 🚀