a
This commit is contained in:
parent
a1f7ee057d
commit
baaae9f4fa
4 changed files with 815 additions and 0 deletions
685
Backend/agent_skills_backend.md
Normal file
685
Backend/agent_skills_backend.md
Normal file
|
|
@ -0,0 +1,685 @@
|
|||
# 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: <file>
|
||||
attachments[]: <file1>
|
||||
attachments[]: <file2>
|
||||
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
|
||||
126
Backend/compose.yaml
Normal file
126
Backend/compose.yaml
Normal file
|
|
@ -0,0 +1,126 @@
|
|||
services:
|
||||
# PostgreSQL Database
|
||||
postgres:
|
||||
image: postgres:16-alpine
|
||||
container_name: elearning-postgres
|
||||
restart: unless-stopped
|
||||
security_opt:
|
||||
- apparmor=unconfined
|
||||
ports:
|
||||
- "5432:5432"
|
||||
environment:
|
||||
POSTGRES_DB: elearning_dev
|
||||
POSTGRES_PASSWORD: 12345678
|
||||
volumes:
|
||||
- postgres_data:/var/lib/postgresql/data
|
||||
networks:
|
||||
- elearning-network
|
||||
healthcheck:
|
||||
test: [ "CMD-SHELL", "pg_isready -U elearning" ]
|
||||
interval: 10s
|
||||
timeout: 5s
|
||||
retries: 5
|
||||
|
||||
# MinIO - S3 Compatible Storage
|
||||
minio:
|
||||
image: minio/minio:latest
|
||||
deploy:
|
||||
resources:
|
||||
limits:
|
||||
memory: 1G
|
||||
container_name: elearning-minio
|
||||
restart: unless-stopped
|
||||
security_opt:
|
||||
- apparmor=unconfined
|
||||
ports:
|
||||
- "9000:9000" # API
|
||||
- "9001:9001" # Console
|
||||
environment:
|
||||
- TZ=Asia/Bangkok
|
||||
- MINIO_ROOT_USER=admin
|
||||
- MINIO_ROOT_PASSWORD=12345678
|
||||
volumes:
|
||||
- minio_data:/data
|
||||
command: server /data --console-address ":9001"
|
||||
networks:
|
||||
- elearning-network
|
||||
healthcheck:
|
||||
test: [ "CMD", "curl", "-f", "http://localhost:9000/minio/health/live" ]
|
||||
interval: 30s
|
||||
timeout: 20s
|
||||
retries: 3
|
||||
|
||||
# MinIO Client - Create buckets on startup
|
||||
minio-init:
|
||||
image: minio/mc:latest
|
||||
container_name: elearning-minio-init
|
||||
security_opt:
|
||||
- apparmor=unconfined
|
||||
depends_on:
|
||||
- minio
|
||||
entrypoint: >
|
||||
/bin/sh -c " sleep 5; /usr/bin/mc alias set myminio http://minio:9000 admin 12345678; /usr/bin/mc mb myminio/courses --ignore-existing; /usr/bin/mc mb myminio/videos --ignore-existing; /usr/bin/mc mb myminio/documents --ignore-existing; /usr/bin/mc mb myminio/images --ignore-existing; /usr/bin/mc mb myminio/attachments --ignore-existing; /usr/bin/mc anonymous set download myminio/images; echo 'MinIO buckets created successfully'; exit 0; "
|
||||
networks:
|
||||
- elearning-network
|
||||
|
||||
# Redis - Cache & Session Store
|
||||
redis:
|
||||
image: redis:7-alpine
|
||||
container_name: elearning-redis
|
||||
restart: unless-stopped
|
||||
security_opt:
|
||||
- apparmor=unconfined
|
||||
ports:
|
||||
- "6379:6379"
|
||||
command: redis-server --appendonly yes --requirepass dev_redis_password
|
||||
volumes:
|
||||
- redis_data:/data
|
||||
networks:
|
||||
- elearning-network
|
||||
healthcheck:
|
||||
test: [ "CMD", "redis-cli", "--raw", "incr", "ping" ]
|
||||
interval: 10s
|
||||
timeout: 3s
|
||||
retries: 5
|
||||
|
||||
# Mailhog - Email Testing
|
||||
mailhog:
|
||||
image: mailhog/mailhog:latest
|
||||
container_name: elearning-mailhog
|
||||
restart: unless-stopped
|
||||
security_opt:
|
||||
- apparmor=unconfined
|
||||
ports:
|
||||
- "1025:1025" # SMTP
|
||||
- "8025:8025" # Web UI
|
||||
networks:
|
||||
- elearning-network
|
||||
|
||||
# Adminer - Database Management UI
|
||||
adminer:
|
||||
image: adminer:latest
|
||||
container_name: elearning-adminer
|
||||
restart: unless-stopped
|
||||
security_opt:
|
||||
- apparmor=unconfined
|
||||
ports:
|
||||
- "8080:8080"
|
||||
environment:
|
||||
ADMINER_DEFAULT_SERVER: postgres
|
||||
ADMINER_DESIGN: dracula
|
||||
networks:
|
||||
- elearning-network
|
||||
depends_on:
|
||||
- postgres
|
||||
|
||||
volumes:
|
||||
postgres_data:
|
||||
driver: local
|
||||
minio_data:
|
||||
driver: local
|
||||
redis_data:
|
||||
driver: local
|
||||
|
||||
networks:
|
||||
elearning-network:
|
||||
driver: bridge
|
||||
Loading…
Add table
Add a link
Reference in a new issue