# 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 ภาษา: ```javascript { "title": { "th": "Python สำหรับผู้เริ่มต้น", "en": "Python for Beginners" } } ``` ### 2. Role-Based Access Control (RBAC) ```javascript // 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 ```javascript { 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 ```javascript { 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 ```javascript { 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 ในครั้งเดียว: ```http POST /api/instructor/courses/:courseId/chapters/:chapterId/lessons Content-Type: multipart/form-data title_th: "บทที่ 1" title_en: "Lesson 1" type: "video" video: attachments[]: attachments[]: descriptions[0][th]: "สไลด์" descriptions[0][en]: "Slides" ``` ### Lesson Prerequisites ```javascript { 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 ```javascript { 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 ```javascript { 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 ```javascript { 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 ```javascript 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):** ```javascript { can_access: false, reason: "incomplete_prerequisites", required_lessons: [1, 2], missing_lessons: [2], next_available_lesson: { id: 2, title: "..." } } ``` ### Ownership Validation ```javascript // 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 ```javascript // ใช้ flag แทนการลบจริง { isDeleted: true, deletedAt: "..." } ``` ### 2. Concurrent Video Progress ```javascript // ใช้ last_watched_at ตัดสินว่า session ไหนล่าสุด if (newProgress.last_watched_at > currentProgress.last_watched_at) { updateProgress(newProgress); } ``` ### 3. Quiz Attempt Validation ```javascript // ตรวจสอบก่อนให้ทำแบบทดสอบ if (attempts >= maxAttempts) return error; if (lastAttempt + cooldown > now) return error; ``` ### 4. Lesson Lock Check ```javascript // ตรวจสอบที่ Backend เสมอ if (!allPreviousCompleted) { return { access: false, nextAvailableLesson }; } ``` ### 5. Multi-Instructor Constraints ```javascript // ห้ามลบ instructor คนสุดท้าย if (instructors.length === 1) { return error("Cannot remove last instructor"); } ``` --- ## 🗄️ Database Schema (Prisma) ### Key Models ```prisma 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) ```javascript // 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 ```javascript // Frontend: Save ทุก 5 วินาที setInterval(() => { if (!video.paused) { saveProgress(video.currentTime, video.duration); } }, 5000); ``` ### JWT Middleware ```javascript 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 ```javascript 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 --- ## 📚 Related Documentation - [API Endpoints Reference](../docs/api-docs/api_endpoints.md) - [API Usage Examples](../docs/api-docs/api_usage_examples.md) - [Edge Cases Quick Reference](../docs/api-docs/edge_cases_quick_reference.md) - [Development Setup](../docs/development_setup.md) --- ## 🚀 Quick Start Commands ```bash # 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