17 KiB
17 KiB
Agent Skills - E-Learning Backend Development
คู่มือสำหรับ AI Agent ในการพัฒนา Backend ของระบบ E-Learning Platform
Tech Stack: Node.js + Express + Prisma + PostgreSQL + Redis + MinIO (S3)
🎯 Overview
ระบบ E-Learning Platform เป็น REST API ที่รองรับ:
- 3 บทบาทหลัก: Admin, Instructor, Student
- 107+ endpoints ครอบคลุมการจัดการคอร์ส, บทเรียน, แบบทดสอบ, ประกาศ, รายงาน
- Multi-language support: Thai (th) และ English (en)
- File management: Video streaming, attachments, certificates
- Real-time features: Video progress tracking, quiz attempts
📚 Core Concepts
1. Multi-Language Data Structure
ข้อมูลที่แสดงผลต้องรองรับ 2 ภาษา:
{
"title": {
"th": "Python สำหรับผู้เริ่มต้น",
"en": "Python for Beginners"
}
}
2. Role-Based Access Control (RBAC)
// 3 บทบาทหลัก
- ADMIN: จัดการระบบทั้งหมด
- INSTRUCTOR: สร้างและจัดการคอร์สของตนเอง
- STUDENT: ลงทะเบียนและเรียนคอร์ส
3. Course Hierarchy
Course
└─ Chapters (บท)
└─ Lessons (บทเรียน)
├─ Video (optional)
├─ Attachments (0-10 files)
└─ Quiz (optional)
4. Lesson Prerequisites
- Sequential lessons: ต้องเรียนตามลำดับ
- Prerequisite lessons: ระบุบทเรียนที่ต้องจบก่อน
- Quiz requirements: ต้องผ่านแบบทดสอบก่อน
🔐 Authentication & Authorization
JWT Token Structure
{
userId: 123,
username: "john_doe",
email: "john@example.com",
role: "STUDENT",
iat: 1234567890,
exp: 1234654290
}
Login Methods
- Username + Password
- Email + Password
Key Endpoints
POST /api/auth/register
POST /api/auth/login
POST /api/auth/logout
POST /api/auth/refresh
POST /api/auth/password/reset-request
POST /api/auth/password/reset
👥 User Management
User Profile Structure
{
id: 1,
username: "john_doe",
email: "john@example.com",
role: { code: "STUDENT", name: {...} },
profile: {
prefix: "Mr.",
first_name: "John",
last_name: "Doe",
phone: "0812345678",
avatar_url: "https://..."
}
}
Key Endpoints
GET /api/users/me
GET /api/users/me/profile
PUT /api/users/me/profile
PUT /api/users/me/password
📚 Course Management
Course Status Flow
DRAFT → PENDING → APPROVED/REJECTED → PUBLISHED
Course Structure
{
id: 1,
title: { th: "...", en: "..." },
description: { th: "...", en: "..." },
thumbnail: "https://...",
price: 990,
is_free: false,
have_certificate: true,
status: "APPROVED",
category_id: 1,
instructors: [
{ user_id: 5, is_primary: true },
{ user_id: 10, is_primary: false }
]
}
Multi-Instructor Support
- Primary Instructor: สามารถจัดการทุกอย่างในคอร์ส
- Co-Instructors: ช่วยสอนและจัดการเนื้อหา
- ห้ามลบ instructor คนสุดท้าย
Key Endpoints
Public:
GET /api/courses
GET /api/courses/:courseId
Student:
POST /api/students/courses/:courseId/enroll
GET /api/students/courses
GET /api/students/courses/:courseId/learn
Instructor:
POST /api/instructor/courses
GET /api/instructor/courses
PUT /api/instructor/courses/:courseId
DELETE /api/instructor/courses/:courseId
POST /api/instructor/courses/:courseId/submit
POST /api/instructor/courses/:courseId/clone
Instructors Management:
GET /api/instructor/courses/:courseId/instructors
POST /api/instructor/courses/:courseId/instructors
DELETE /api/instructor/courses/:courseId/instructors/:userId
PUT /api/instructor/courses/:courseId/instructors/:userId/primary
📖 Chapters & Lessons
Lesson Types
- video: วีดีโอบทเรียน
- text: เนื้อหาข้อความ
- pdf: เอกสาร PDF
- quiz: แบบทดสอบ
Create Lesson (One Request)
สามารถสร้าง lesson พร้อม video และ attachments ในครั้งเดียว:
POST /api/instructor/courses/:courseId/chapters/:chapterId/lessons
Content-Type: multipart/form-data
title_th: "บทที่ 1"
title_en: "Lesson 1"
type: "video"
video: <file>
attachments[]: <file1>
attachments[]: <file2>
descriptions[0][th]: "สไลด์"
descriptions[0][en]: "Slides"
Lesson Prerequisites
{
is_sequential: true, // ต้องเรียนตามลำดับ
prerequisite_lesson_ids: [1, 2], // ต้องจบบทเรียนนี้ก่อน
require_pass_quiz: true // ต้องผ่านแบบทดสอบ
}
Key Endpoints
Chapters:
POST /api/instructor/courses/:courseId/chapters
PUT /api/instructor/courses/:courseId/chapters/:chapterId
DELETE /api/instructor/courses/:courseId/chapters/:chapterId
PUT /api/instructor/courses/:courseId/chapters/reorder
Lessons:
POST /api/instructor/courses/:courseId/chapters/:chapterId/lessons
PUT /api/instructor/courses/:courseId/lessons/:lessonId
DELETE /api/instructor/courses/:courseId/lessons/:lessonId
PUT /api/instructor/courses/:courseId/lessons/reorder
Prerequisites:
GET /api/instructor/courses/:courseId/lessons/:lessonId/prerequisites
POST /api/instructor/courses/:courseId/lessons/:lessonId/prerequisites
📎 Attachments
File Limits
- Max file size: 100 MB per file
- Max attachments: 10 files per lesson
- Total size: 500 MB per lesson
Allowed File Types
- Documents: PDF, DOC, DOCX, XLS, XLSX, PPT, PPTX
- Archives: ZIP, RAR, 7Z
- Images: JPG, PNG, GIF
- Text: TXT, CSV
Key Endpoints
POST /api/instructor/courses/:courseId/lessons/:lessonId/attachments
GET /api/instructor/courses/:courseId/lessons/:lessonId/attachments
PUT /api/instructor/courses/:courseId/lessons/:lessonId/attachments/:attachmentId
DELETE /api/instructor/courses/:courseId/lessons/:lessonId/attachments/:attachmentId
PUT /api/instructor/courses/:courseId/lessons/:lessonId/attachments/reorder
GET /api/students/lessons/:lessonId/attachments/:attachmentId/download
📹 Video Progress Tracking
Auto-Save Progress
- บันทึกทุก 5 วินาที ขณะดูวีดีโอ
- Auto-complete เมื่อดู ≥ 90%
- Resume จากตำแหน่งล่าสุด
Data Structure
{
lesson_id: 5,
video_progress_seconds: 450,
video_duration_seconds: 900,
video_progress_percentage: 50.00,
is_completed: false,
last_watched_at: "2024-12-24T14:00:00Z"
}
Key Endpoints
POST /api/students/lessons/:lessonId/progress
GET /api/students/lessons/:lessonId/progress
🎯 Quizzes & Assessments
Quiz Configuration
{
title: { th: "...", en: "..." },
passing_score: 70, // คะแนนผ่าน (%)
time_limit: 30, // นาที
max_attempts: 3, // จำนวนครั้งที่ทำได้
cooldown_minutes: 60, // ระยะเวลารอระหว่างครั้ง
score_policy: "HIGHEST", // HIGHEST, LATEST, FIRST, AVERAGE
shuffle_questions: true,
shuffle_choices: true,
show_answers_after_completion: true
}
Question Types
- multiple_choice: เลือกตอบ (1 คำตอบ)
- true_false: จริง/เท็จ
- multiple_select: เลือกหลายคำตอบ
Key Endpoints
Instructor:
POST /api/instructor/courses/:courseId/lessons/:lessonId/quiz
PUT /api/instructor/quizzes/:quizId
DELETE /api/instructor/quizzes/:quizId
POST /api/instructor/quizzes/:quizId/questions
PUT /api/instructor/quizzes/:quizId/questions/:questionId
DELETE /api/instructor/quizzes/:quizId/questions/:questionId
Student:
GET /api/students/quizzes/:quizId
POST /api/students/quizzes/:quizId/submit
GET /api/students/quizzes/:quizId/attempts
GET /api/students/quizzes/:quizId/attempts/:attemptId
📢 Announcements
Announcement Structure
{
id: 1,
course_id: 1,
title: { th: "...", en: "..." },
content: { th: "...", en: "..." },
is_pinned: true,
attachments: [...],
created_at: "2024-12-23T10:00:00Z"
}
Key Endpoints
Student:
GET /api/students/courses/:courseId/announcements
GET /api/students/courses/:courseId/announcements/:announcementId
Instructor:
GET /api/instructor/courses/:courseId/announcements
POST /api/instructor/courses/:courseId/announcements
PUT /api/instructor/courses/:courseId/announcements/:announcementId
DELETE /api/instructor/courses/:courseId/announcements/:announcementId
📊 Progress & Certificates
Course Progress Calculation
progress_percentage = (completed_lessons / total_lessons) * 100
Certificate Issuance
- ออกอัตโนมัติเมื่อจบคอร์ส 100%
- เฉพาะคอร์สที่
have_certificate = true - เก็บไฟล์ PDF ใน S3
Key Endpoints
GET /api/students/progress
GET /api/students/courses/:courseId/progress
GET /api/students/courses/:courseId/certificate
GET /api/students/certificates
🔄 Course Cloning
What Gets Cloned
✅ Copied:
- Course info (title, description, price)
- All chapters and lessons
- All quizzes and questions
- All attachments (files copied to new location)
- Lesson prerequisites
- Sort orders
❌ NOT Copied:
- Enrollments
- Student progress
- Reviews/ratings
- Approval status (new course = DRAFT)
Key Endpoint
POST /api/instructor/courses/:courseId/clone
🔒 Access Control & Permissions
Lesson Access Check
GET /api/students/courses/:courseId/lessons/:lessonId/access-check
Response (Locked):
{
can_access: false,
reason: "incomplete_prerequisites",
required_lessons: [1, 2],
missing_lessons: [2],
next_available_lesson: { id: 2, title: "..." }
}
Ownership Validation
// Middleware ตรวจสอบ
if (role === 'INSTRUCTOR' && course.instructorId !== userId) {
return 403;
}
📈 Reports & Analytics
Student Reports
GET /api/students/progress
GET /api/students/courses/:courseId/progress
Instructor Reports
GET /api/instructor/courses/:courseId/statistics
GET /api/instructor/courses/:courseId/students
GET /api/instructor/courses/:courseId/students/export
GET /api/instructor/dashboard
Admin Dashboard
GET /api/admin/statistics
GET /api/admin/reports/revenue
GET /api/admin/reports/users
GET /api/admin/reports/courses
⚠️ Edge Cases & Best Practices
1. Soft Delete > Hard Delete
// ใช้ flag แทนการลบจริง
{ isDeleted: true, deletedAt: "..." }
2. Concurrent Video Progress
// ใช้ last_watched_at ตัดสินว่า session ไหนล่าสุด
if (newProgress.last_watched_at > currentProgress.last_watched_at) {
updateProgress(newProgress);
}
3. Quiz Attempt Validation
// ตรวจสอบก่อนให้ทำแบบทดสอบ
if (attempts >= maxAttempts) return error;
if (lastAttempt + cooldown > now) return error;
4. Lesson Lock Check
// ตรวจสอบที่ Backend เสมอ
if (!allPreviousCompleted) {
return { access: false, nextAvailableLesson };
}
5. Multi-Instructor Constraints
// ห้ามลบ instructor คนสุดท้าย
if (instructors.length === 1) {
return error("Cannot remove last instructor");
}
🗄️ Database Schema (Prisma)
Key Models
model User {
id Int @id @default(autoincrement())
username String @unique
email String @unique
password String
role Role @relation(...)
profile Profile?
}
model Course {
id Int @id @default(autoincrement())
title Json // { th: "", en: "" }
description Json
price Decimal
is_free Boolean
have_certificate Boolean
status CourseStatus
chapters Chapter[]
instructors CourseInstructor[]
}
model Lesson {
id Int @id @default(autoincrement())
title Json
content Json
type LessonType
video_url String?
is_sequential Boolean
prerequisite_lessons LessonPrerequisite[]
attachments Attachment[]
quiz Quiz?
}
model Quiz {
id Int @id @default(autoincrement())
title Json
passing_score Int
time_limit Int?
max_attempts Int?
cooldown_minutes Int?
score_policy ScorePolicy
show_answers_after_completion Boolean
questions Question[]
}
🔧 Technical Implementation
File Upload (MinIO/S3)
// Video upload
const videoPath = `courses/${courseId}/lessons/${lessonId}/video.mp4`;
await s3.upload(videoPath, videoFile);
// Attachment upload
const attachmentPath = `lessons/${lessonId}/attachments/${filename}`;
await s3.upload(attachmentPath, file);
Video Progress Auto-Save
// Frontend: Save ทุก 5 วินาที
setInterval(() => {
if (!video.paused) {
saveProgress(video.currentTime, video.duration);
}
}, 5000);
JWT Middleware
const authMiddleware = async (req, res, next) => {
const token = req.headers.authorization?.split(' ')[1];
const decoded = jwt.verify(token, JWT_SECRET);
req.user = await prisma.user.findUnique({ where: { id: decoded.userId } });
next();
};
Role-Based Middleware
const requireRole = (roles) => (req, res, next) => {
if (!roles.includes(req.user.role.code)) {
return res.status(403).json({ error: "Forbidden" });
}
next();
};
📋 Error Codes
| Code | Description |
|---|---|
INVALID_CREDENTIALS |
อีเมล/รหัสผ่านไม่ถูกต้อง |
ALREADY_ENROLLED |
ลงทะเบียนซ้ำ |
LESSON_LOCKED |
บทเรียนถูกล็อค |
INCOMPLETE_PREREQUISITES |
ยังไม่จบบทเรียนที่ต้องเรียนก่อน |
QUIZ_NOT_PASSED |
ยังไม่ผ่านแบบทดสอบ |
MAX_ATTEMPTS_EXCEEDED |
ทำแบบทดสอบเกินจำนวนครั้ง |
COOLDOWN_ACTIVE |
ต้องรอก่อนทำแบบทดสอบอีกครั้ง |
FILE_TOO_LARGE |
ไฟล์ใหญ่เกินไป |
INVALID_FILE_TYPE |
ประเภทไฟล์ไม่รองรับ |
COURSE_NOT_FOUND |
ไม่พบคอร์ส |
UNAUTHORIZED |
ไม่มีสิทธิ์เข้าถึง |
🎯 Development Checklist
สำหรับทุก Endpoint
- Validate input data (Joi/Zod)
- Check authentication (JWT)
- Check authorization (Role/Ownership)
- Handle errors properly
- Return consistent response format
- Log important actions
- Add rate limiting
สำหรับ File Upload
- Validate file type
- Validate file size
- Generate unique filename
- Upload to S3/MinIO
- Save metadata to database
- Handle upload errors
สำหรับ Multi-Language
- Accept
langquery parameter - Return appropriate language
- Fallback to default language
- Validate both languages exist
📚 Related Documentation
🚀 Quick Start Commands
# Install dependencies
npm install
# Setup database
npx prisma migrate dev
# Seed database
npx prisma db seed
# Start development server
npm run dev
# Run tests
npm test
Last Updated: 2026-01-07
Version: 1.0.0