elearning/Backend/agent_skills_backend.md
JakkrapartXD baaae9f4fa a
2026-01-08 03:58:29 +00:00

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 lang query parameter
  • Return appropriate language
  • Fallback to default language
  • Validate both languages exist


🚀 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