diff --git a/docs/ERD v.1.txt b/docs/api-docs/ERD v.1.txt similarity index 100% rename from docs/ERD v.1.txt rename to docs/api-docs/ERD v.1.txt diff --git a/docs/ERD_v2_improved.txt b/docs/api-docs/ERD_v2_improved.txt similarity index 96% rename from docs/ERD_v2_improved.txt rename to docs/api-docs/ERD_v2_improved.txt index 03d6d546..026bc6f9 100644 --- a/docs/ERD_v2_improved.txt +++ b/docs/api-docs/ERD_v2_improved.txt @@ -153,6 +153,10 @@ Table lesson_progress { lesson_id int [not null, ref: > lessons.id] is_completed boolean [not null, default: false] completed_at datetime + video_progress_seconds int [default: 0, note: 'current playback position in seconds'] + video_duration_seconds int [note: 'total video duration in seconds'] + video_progress_percentage decimal(5,2) [note: 'calculated: (progress/duration)*100'] + last_watched_at datetime [note: 'last time user watched this video'] created_at datetime [not null, default: `now()`] updated_at datetime [not null, default: `now()`] @@ -160,6 +164,7 @@ Table lesson_progress { (user_id, lesson_id) [unique] user_id lesson_id + last_watched_at } } diff --git a/docs/api-docs/api_endpoints.md b/docs/api-docs/api_endpoints.md index 5703d818..32a75214 100644 --- a/docs/api-docs/api_endpoints.md +++ b/docs/api-docs/api_endpoints.md @@ -70,6 +70,8 @@ Authorization: Bearer | GET | `/students/courses/:courseId/learn` | 👨‍🎓 Student | Get course learning page (with lock status) | | GET | `/students/courses/:courseId/lessons/:lessonId` | 👨‍🎓 Student | Get lesson content (checks prerequisites) | | GET | `/students/courses/:courseId/lessons/:lessonId/access-check` | 👨‍🎓 Student | Check lesson access without loading content | +| POST | `/students/lessons/:lessonId/progress` | 👨‍🎓 Student | Save video progress | +| GET | `/students/lessons/:lessonId/progress` | 👨‍🎓 Student | Get video progress | | POST | `/students/courses/:courseId/lessons/:lessonId/complete` | 👨‍🎓 Student | Mark lesson as complete | ### Instructor Endpoints @@ -303,13 +305,13 @@ Authorization: Bearer --- -## Total Endpoints: **93+** +## Total Endpoints: **95+** - Authentication: 6 - User Management: 4 - Categories: 5 -- Courses: 12 -- Chapters & Lessons: 16 (-1) +- Courses: 14 (+2) +- Chapters & Lessons: 16 - Quizzes: 10 - Announcements: 6 - Reports: 11 diff --git a/docs/api-docs/api_video_progress.md b/docs/api-docs/api_video_progress.md new file mode 100644 index 00000000..d15933a7 --- /dev/null +++ b/docs/api-docs/api_video_progress.md @@ -0,0 +1,191 @@ +# Video Progress Tracking - API Usage Examples + +## Save Video Progress + +### POST `/students/lessons/:lessonId/progress` + +**Purpose**: บันทึกตำแหน่งการดูวีดีโอ (เรียกทุก 5 วินาที) + +#### Request: +```http +POST /api/students/lessons/5/progress +Authorization: Bearer +Content-Type: application/json + +{ + "progress_seconds": 450, + "duration_seconds": 900 +} +``` + +#### Response 200: +```json +{ + "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" +} +``` + +#### Auto-Complete (90%+): +```json +{ + "progress_seconds": 810, + "duration_seconds": 900 +} +``` + +**Response**: +```json +{ + "lesson_id": 5, + "video_progress_seconds": 810, + "video_duration_seconds": 900, + "video_progress_percentage": 90.00, + "is_completed": true, + "completed_at": "2024-12-24T14:05:00Z" +} +``` + +--- + +## Get Video Progress + +### GET `/students/lessons/:lessonId/progress` + +**Purpose**: ดึงตำแหน่งการดูวีดีโอเพื่อเล่นต่อ + +#### Request: +```http +GET /api/students/lessons/5/progress +Authorization: Bearer +``` + +#### Response 200 (Has Progress): +```json +{ + "lesson_id": 5, + "video_progress_seconds": 450, + "video_duration_seconds": 900, + "video_progress_percentage": 50.00, + "is_completed": false, + "last_watched_at": "2024-12-24T13:30:00Z" +} +``` + +#### Response 200 (No Progress): +```json +{ + "lesson_id": 5, + "video_progress_seconds": 0, + "video_duration_seconds": null, + "video_progress_percentage": 0, + "is_completed": false, + "last_watched_at": null +} +``` + +--- + +## Frontend Integration + +```javascript +const VideoPlayer = ({ lessonId, videoUrl }) => { + const videoRef = useRef(null); + + // Load saved progress + useEffect(() => { + async function loadProgress() { + const res = await fetch(`/api/students/lessons/${lessonId}/progress`); + const data = await res.json(); + + if (data.video_progress_seconds > 0) { + videoRef.current.currentTime = data.video_progress_seconds; + } + } + loadProgress(); + }, [lessonId]); + + // Save progress every 5 seconds + useEffect(() => { + const interval = setInterval(() => { + if (videoRef.current && !videoRef.current.paused) { + saveProgress( + Math.floor(videoRef.current.currentTime), + Math.floor(videoRef.current.duration) + ); + } + }, 5000); + + return () => clearInterval(interval); + }, []); + + async function saveProgress(currentTime, duration) { + await fetch(`/api/students/lessons/${lessonId}/progress`, { + method: 'POST', + headers: { + 'Authorization': `Bearer ${token}`, + 'Content-Type': 'application/json' + }, + body: JSON.stringify({ + progress_seconds: currentTime, + duration_seconds: duration + }) + }); + } + + return