Yimaru-BackEnd/docs/LEARNER_PROGRESS_TRACKER_ADMIN_INTEGRATION.md

168 lines
4.3 KiB
Markdown

# Learner Progress Tracker Admin Integration Guide
This guide explains how to integrate learner sub-course progress tracking into the admin panel using the backend endpoint implemented for admin usage.
## Scope
- Track a specific learner's progress across all sub-courses inside a course.
- Show lock state, progress percentage, and completion timestamps.
- Integrate as a read-focused admin experience.
## New Admin Endpoint
- **Method:** `GET`
- **Path:** `/api/v1/admin/users/:userId/progress/courses/:courseId`
- **Auth:** Bearer token
- **Required permission:** `progress.get_any_user`
### Path Parameters
- `userId` (number): target learner user ID
- `courseId` (number): course ID
### Success Response (`200`)
```json
{
"message": "Learner course progress retrieved successfully",
"data": [
{
"sub_course_id": 11,
"title": "Beginner Conversation Basics",
"description": "Foundational speaking patterns",
"thumbnail": "https://cdn.example.com/sc-11.png",
"display_order": 1,
"level": "BEGINNER",
"progress_status": "IN_PROGRESS",
"progress_percentage": 45,
"started_at": "2026-03-07T09:10:11Z",
"completed_at": null,
"is_locked": false
},
{
"sub_course_id": 12,
"title": "Beginner Listening Drills",
"description": "Daily listening practice",
"thumbnail": null,
"display_order": 2,
"level": "BEGINNER",
"progress_status": "NOT_STARTED",
"progress_percentage": 0,
"started_at": null,
"completed_at": null,
"is_locked": true
}
]
}
```
### Error Responses
- `400`: invalid `userId` or `courseId`
- `401`: missing/invalid token
- `403`: missing `progress.get_any_user`
- `500`: server/database issue
## Data Semantics
- `progress_status` values:
- `NOT_STARTED`
- `IN_PROGRESS`
- `COMPLETED`
- `progress_percentage` is `0..100`
- `is_locked` is computed from unmet sub-course prerequisites for that learner
- list is ordered by `display_order`
- only active sub-courses are included
## Backend Rollout Steps
After pulling this backend change:
1. Restart backend service.
2. Sync permissions:
- `POST /api/v1/rbac/permissions/sync`
3. Ensure admin role includes `progress.get_any_user`.
- If your system uses explicit role-permission assignment, update role permissions after sync.
## Admin Panel Integration Flow
1. User opens learner progress screen.
2. Admin selects learner and course.
3. Frontend requests:
- `GET /api/v1/admin/users/{userId}/progress/courses/{courseId}`
4. Render returned `data` as ordered progress items.
## Recommended UI Sections
- Header:
- learner identity
- selected course
- Metrics row:
- total sub-courses
- completed count
- in-progress count
- locked count
- average progress percentage
- Ordered list/table:
- sub-course title
- level
- status badge
- progress bar
- locked icon
- started/completed timestamps
## Frontend Mapping Example
For each item:
- `statusLabel = progress_status`
- `isCompleted = progress_status === "COMPLETED"`
- `isInProgress = progress_status === "IN_PROGRESS"`
- `isNotStarted = progress_status === "NOT_STARTED"`
- `canOpenDetails = !is_locked`
## Suggested API Client Contract
```ts
type LearnerCourseProgressItem = {
sub_course_id: number;
title: string;
description?: string | null;
thumbnail?: string | null;
display_order: number;
level: string;
progress_status: "NOT_STARTED" | "IN_PROGRESS" | "COMPLETED";
progress_percentage: number;
started_at?: string | null;
completed_at?: string | null;
is_locked: boolean;
};
type LearnerCourseProgressResponse = {
message: string;
data: LearnerCourseProgressItem[];
};
```
## Example Request
```bash
curl -X GET "http://localhost:8432/api/v1/admin/users/7/progress/courses/3" \
-H "Authorization: Bearer <ACCESS_TOKEN>"
```
## Operational Notes
- This endpoint is intended for admin/super-admin workflows.
- Existing learner self endpoint remains available:
- `GET /api/v1/progress/courses/:courseId`
- Do not expose `progress.get_any_user` to learner-facing roles.
## QA Checklist
- valid admin token + permission returns `200`
- token without permission returns `403`
- invalid `userId` or `courseId` returns `400`
- locked sub-courses correctly show `is_locked: true`
- ordering in UI follows `display_order`