docs: Add Forgejo and development setup guides, and refactor API documentation structure.

This commit is contained in:
JakkrapartXD 2025-12-23 16:02:17 +07:00
parent 7b1ed6f6cc
commit a6427b2083
9 changed files with 2446 additions and 7 deletions

View file

@ -0,0 +1,438 @@
# API Usage Examples - Lesson Prerequisites
## New Endpoints Usage Examples
---
## 1. Check Lesson Access (Student)
### GET `/students/courses/:courseId/lessons/:lessonId/access-check`
**Purpose**: ตรวจสอบว่าสามารถเข้าถึง lesson ได้หรือไม่ โดยไม่ต้อง load content
#### Request:
```http
GET /api/students/courses/1/lessons/3/access-check
Authorization: Bearer eyJhbGciOiJIUzI1NiIsInR5cCI6IkpXVCJ9...
```
#### Response 200 (Can Access):
```json
{
"can_access": true,
"lesson": {
"id": 3,
"title": "แบบทดสอบท้ายบท",
"type": "quiz",
"sort_order": 3
}
}
```
#### Response 200 (Locked - Incomplete Prerequisites):
```json
{
"can_access": false,
"reason": "incomplete_prerequisites",
"message": "กรุณาเรียนบทเรียนก่อนหน้าให้เสร็จก่อน",
"required_lessons": [
{
"id": 1,
"title": "บทที่ 1: แนะนำ",
"type": "video",
"is_completed": true
},
{
"id": 2,
"title": "บทที่ 2: ตัวแปร",
"type": "video",
"is_completed": false
}
],
"missing_lessons": [2],
"next_available_lesson": {
"id": 2,
"title": "บทที่ 2: ตัวแปร"
}
}
```
#### Response 200 (Locked - Quiz Not Passed):
```json
{
"can_access": false,
"reason": "quiz_not_passed",
"message": "กรุณาทำแบบทดสอบให้ผ่านก่อน",
"required_quiz": {
"lesson_id": 3,
"title": "แบบทดสอบท้ายบท",
"passing_score": 70,
"your_best_score": 55,
"attempts_used": 2,
"max_attempts": 3
}
}
```
---
## 2. Get Learning Page with Lock Status (Student)
### GET `/students/courses/:courseId/learn`
**Changes**: เพิ่ม `is_locked` และ `lock_reason` ในแต่ละ lesson
#### Request:
```http
GET /api/students/courses/1/learn
Authorization: Bearer eyJhbGciOiJIUzI1NiIsInR5cCI6IkpXVCJ9...
```
#### Response 200:
```json
{
"course": {
"id": 1,
"title": "Python สำหรับผู้เริ่มต้น"
},
"enrollment": {
"status": "enrolled",
"progress_percentage": 35
},
"chapters": [
{
"id": 1,
"title": "บทที่ 1: พื้นฐาน",
"sort_order": 1,
"lessons": [
{
"id": 1,
"title": "1.1 แนะนำ Python",
"type": "video",
"duration": "00:15:30",
"is_completed": true,
"is_locked": false,
"completed_at": "2024-12-23T10:00:00Z"
},
{
"id": 2,
"title": "1.2 ตัวแปร",
"type": "video",
"duration": "00:20:00",
"is_completed": false,
"is_locked": false
},
{
"id": 3,
"title": "1.3 แบบทดสอบ",
"type": "quiz",
"is_completed": false,
"is_locked": true,
"lock_reason": "incomplete_prerequisites",
"required_lessons": [1, 2]
},
{
"id": 4,
"title": "1.4 ขั้นสูง",
"type": "video",
"duration": "00:25:00",
"is_completed": false,
"is_locked": true,
"lock_reason": "quiz_not_passed",
"required_quiz": 3
}
]
}
]
}
```
---
## 3. Get Lesson Content with Prerequisites Check (Student)
### GET `/students/courses/:courseId/lessons/:lessonId`
**Changes**: ตรวจสอบ prerequisites ก่อน return content
#### Request:
```http
GET /api/students/courses/1/lessons/3
Authorization: Bearer eyJhbGciOiJIUzI1NiIsInR5cCI6IkpXVCJ9...
```
#### Response 403 (Locked):
```json
{
"error": {
"code": "LESSON_LOCKED",
"message": "Cannot access this lesson",
"reason": "incomplete_prerequisites",
"required_lessons": [1, 2],
"completed_lessons": [1],
"missing_lessons": [2],
"next_available_lesson": {
"id": 2,
"title": "บทที่ 2: ตัวแปร",
"type": "video"
}
}
}
```
---
## 4. Create Lesson with Prerequisites (Instructor)
### POST `/instructor/courses/:courseId/chapters/:chapterId/lessons`
**Changes**: เพิ่ม fields สำหรับ prerequisites
#### Request:
```http
POST /api/instructor/courses/1/chapters/1/lessons
Authorization: Bearer eyJhbGciOiJIUzI1NiIsInR5cCI6IkpXVCJ9...
Content-Type: application/json
{
"title": {
"th": "แบบทดสอบท้ายบท",
"en": "Chapter Quiz"
},
"content": {
"th": "<p>ทดสอบความเข้าใจ</p>",
"en": "<p>Test your understanding</p>"
},
"type": "quiz",
"sort_order": 3,
"is_sequential": true,
"prerequisite_lesson_ids": [1, 2],
"require_pass_quiz": true
}
```
#### Response 201:
```json
{
"id": 3,
"chapter_id": 1,
"title": {
"th": "แบบทดสอบท้ายบท",
"en": "Chapter Quiz"
},
"type": "quiz",
"sort_order": 3,
"is_sequential": true,
"prerequisite_lesson_ids": [1, 2],
"require_pass_quiz": true,
"created_at": "2024-12-23T14:00:00Z"
}
```
#### Response 422 (Validation Error):
```json
{
"error": {
"code": "VALIDATION_ERROR",
"message": "Invalid prerequisites",
"details": [
{
"field": "prerequisite_lesson_ids",
"message": "Lesson ID 99 does not exist"
}
]
}
}
```
---
## 5. View Lesson Prerequisites (Instructor)
### GET `/instructor/courses/:courseId/lessons/:lessonId/prerequisites`
#### Request:
```http
GET /api/instructor/courses/1/lessons/4/prerequisites
Authorization: Bearer eyJhbGciOiJIUzI1NiIsInR5cCI6IkpXVCJ9...
```
#### Response 200:
```json
{
"lesson": {
"id": 4,
"title": "บทที่ 3: ขั้นสูง",
"type": "video",
"sort_order": 4
},
"is_sequential": true,
"prerequisites": [
{
"id": 3,
"title": "แบบทดสอบท้ายบท",
"type": "quiz",
"require_pass": true,
"passing_score": 70
}
],
"affected_students": {
"total_enrolled": 150,
"can_access": 85,
"locked": 65,
"breakdown": {
"incomplete_prerequisites": 45,
"quiz_not_passed": 20
}
}
}
```
---
## 6. Update Lesson Prerequisites (Instructor)
### POST `/instructor/courses/:courseId/lessons/:lessonId/prerequisites`
#### Request:
```http
POST /api/instructor/courses/1/lessons/4/prerequisites
Authorization: Bearer eyJhbGciOiJIUzI1NiIsInR5cCI6IkpXVCJ9...
Content-Type: application/json
{
"is_sequential": true,
"prerequisite_lesson_ids": [3],
"require_pass_quiz": false
}
```
#### Response 200:
```json
{
"lesson_id": 4,
"is_sequential": true,
"prerequisites": [
{
"id": 3,
"title": "แบบทดสอบท้ายบท",
"type": "quiz",
"require_pass": false
}
],
"message": "Prerequisites updated successfully",
"affected_students": {
"newly_unlocked": 20,
"still_locked": 45
}
}
```
---
## Error Codes
### New Error Codes for Prerequisites
| Code | Description |
|------|-------------|
| `LESSON_LOCKED` | Cannot access lesson due to prerequisites |
| `INCOMPLETE_PREREQUISITES` | Required lessons not completed |
| `QUIZ_NOT_PASSED` | Required quiz not passed |
| `INVALID_PREREQUISITES` | Invalid prerequisite configuration |
| `CIRCULAR_DEPENDENCY` | Circular dependency detected |
---
## Frontend Integration Examples
### 1. Display Locked Lesson
```javascript
function LessonItem({ lesson }) {
if (lesson.is_locked) {
return (
<div className="lesson-item locked">
<LockIcon />
<span className="lesson-title">{lesson.title}</span>
{lesson.lock_reason === 'incomplete_prerequisites' && (
<Tooltip>
กรุณาเรียนบทเรียนก่อนหน้าให้เสร็จก่อน
<ul>
{lesson.required_lessons.map(id => (
<li key={id}>Lesson {id}</li>
))}
</ul>
</Tooltip>
)}
{lesson.lock_reason === 'quiz_not_passed' && (
<Tooltip>
กรุณาทำแบบทดสอบให้ผ่านก่อน (ต้องได้ 70% ขึ้นไป)
</Tooltip>
)}
</div>
);
}
return (
<Link to={`/lessons/${lesson.id}`} className="lesson-item">
{lesson.is_completed ? <CheckIcon /> : <PlayIcon />}
<span>{lesson.title}</span>
</Link>
);
}
```
### 2. Check Access Before Navigation
```javascript
async function navigateToLesson(courseId, lessonId) {
try {
const response = await fetch(
`/api/students/courses/${courseId}/lessons/${lessonId}/access-check`,
{
headers: {
'Authorization': `Bearer ${token}`
}
}
);
const data = await response.json();
if (data.can_access) {
// Navigate to lesson
router.push(`/courses/${courseId}/lessons/${lessonId}`);
} else {
// Show lock message
if (data.reason === 'incomplete_prerequisites') {
showAlert(`กรุณาเรียนบทเรียนก่อนหน้าให้เสร็จก่อน`);
// Highlight next available lesson
highlightLesson(data.next_available_lesson.id);
} else if (data.reason === 'quiz_not_passed') {
showAlert(`กรุณาทำแบบทดสอบให้ผ่านก่อน`);
// Navigate to quiz
router.push(`/courses/${courseId}/lessons/${data.required_quiz.lesson_id}`);
}
}
} catch (error) {
console.error('Error checking lesson access:', error);
}
}
```
---
## Summary
**New Endpoints**: 3
- `GET /students/courses/:courseId/lessons/:lessonId/access-check`
- `GET /instructor/courses/:courseId/lessons/:lessonId/prerequisites`
- `POST /instructor/courses/:courseId/lessons/:lessonId/prerequisites`
**Modified Endpoints**: 4
- `GET /students/courses/:courseId/learn` - เพิ่ม lock status
- `GET /students/courses/:courseId/lessons/:lessonId` - เช็ค prerequisites
- `POST /instructor/courses/:courseId/chapters/:chapterId/lessons` - รองรับ prerequisites
- `PUT /instructor/courses/:courseId/lessons/:lessonId` - รองรับ prerequisites