Yimaru-BackEnd/docs/LEARNER_PROGRESS_TRACKER_ADMIN_INTEGRATION.md

5.7 KiB

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

Course-level Summary Endpoint

  • Method: GET
  • Path: /api/v1/admin/users/:userId/progress/courses/:courseId/summary
  • Auth: Bearer token
  • Required permission: progress.get_any_user

Success Response (200)

{
  "message": "Learner course progress summary retrieved successfully",
  "data": {
    "course_id": 1,
    "learner_user_id": 10,
    "overall_progress_percentage": 40,
    "total_sub_courses": 5,
    "completed_sub_courses": 2,
    "in_progress_sub_courses": 1,
    "not_started_sub_courses": 2,
    "locked_sub_courses": 2
  }
}

Path Parameters

  • userId (number): target learner user ID
  • courseId (number): course ID

Success Response (200)

{
  "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

Progress Calculation Model

Sub-course progress is automatically aggregated from completion records:

  • completed published videos in the sub-course (user_sub_course_video_progress)
  • completed published practices in the sub-course (user_practice_progress)

Formula:

  • total_items = published_videos + published_practices
  • completed_items = completed_videos + completed_practices
  • progress_percentage = round((completed_items / total_items) * 100)
  • if total_items = 0, progress_percentage = 0

Status transitions:

  • NOT_STARTED when completed_items = 0
  • IN_PROGRESS when 0 < completed_items < total_items
  • COMPLETED when completed_items >= total_items and total_items > 0

Auto-recalculation triggers:

  • POST /api/v1/progress/videos/:id/complete
  • POST /api/v1/progress/practices/:id/complete

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}
    • GET /api/v1/admin/users/{userId}/progress/courses/{courseId}/summary
  4. Render returned data as ordered progress items.
  • 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

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

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