Skip to content

feat(academy): learner progress tracking and certificates (BE-038) - #889

Merged
MaryammAli merged 2 commits into
BlockDash-Studios:mainfrom
abiolatousin-design:feat/be-038-progress-tracking
Sep 26, 2026
Merged

MaryammAli merged 2 commits into
BlockDash-Studios:mainfrom
abiolatousin-design:feat/be-038-progress-tracking

Conversation

@abiolatousin-design

Copy link
Copy Markdown
Contributor

Overview

Adds per-learner progress tracking to BackendAcademy: lesson and task
completion counts and percentages, XP earned per course, an aggregate endpoint
for the dashboard, and the transition that marks a course complete — which is
what makes the learner eligible for a certificate.

The new ProgressService follows the academy's existing service pattern
(in-memory state, like XpService and FollowService) and reuses the
DomainEventBus / XpService that already exist in GamificationModule
instead of pricing XP itself: finishing a task publishes task.passed and
completing a course publishes course.completed, so XP stays in one place.
xpEarned per course is read back from that ledger by courseId.

Related Issue

Implements the per-learner progress tracking described in #791 (BE-038), under
the Learning Academy backlog area and the BackendAcademy scope.

Changes

  • [ADD] BackendAcademy/src/progress/progress.types.ts

    • CourseContent (lesson/task manifest), CourseCompletion,
      CertificateEligibility, LearnerCourseProgress and LearnerDashboard.
  • [ADD] BackendAcademy/src/progress/progress.service.ts

    • Registers a course's lesson and task manifest (rejects a manifest with no
      lessons or no tasks, since it could never be completed).
    • completeLesson() / completeTask() record completion and return refreshed
      course progress; a repeated completion is rejected with BadRequestException.
    • evaluateCompletion() flips the course to complete exactly once, when every
      lesson and task is done, then publishes course.completed and records a
      CertificateEligibility.
    • getCourseProgress() returns completion counts, rounded percentages and
      per-course xpEarned; getDashboard() aggregates courses, total XP and
      certificates for a learner; listCertificates() / getCertificate() expose
      certificate eligibility.
  • [ADD] BackendAcademy/src/progress/progress.controller.ts

    • POST /api/v1/progress/courses — register a course manifest.
    • POST /api/v1/progress/lessons/complete — mark a lesson complete.
    • POST /api/v1/progress/tasks/complete — mark a task complete (awards XP).
    • GET /api/v1/progress/users/:userId/courses/:courseId — one course.
    • GET /api/v1/progress/users/:userId/dashboard — aggregate dashboard payload.
    • GET /api/v1/progress/users/:userId/certificates — certificate eligibility.
  • [ADD] BackendAcademy/src/progress/dto/{register-course,complete-lesson,complete-task}.dto.ts

    • Validated request bodies, matching forbidNonWhitelisted global validation.
  • [ADD] BackendAcademy/src/progress/progress.module.ts

    • Imports GamificationModule so completions publish on the shared event bus.
  • [ADD] BackendAcademy/src/progress/progress.service.spec.ts

    • Unit tests for percentages, the completion → certificate transition,
      single-award idempotency, dashboard aggregation and error cases.
  • [ADD] BackendAcademy/test/progress.e2e-spec.ts

    • Exercises the REST surface end to end through ProgressModule.
  • [MODIFY] BackendAcademy/src/app.module.ts

    • Registers ProgressModule.
  • [MODIFY] BackendAcademy/README.md

    • Lists the progress module.

Verification Results

No local checkout: the repository was inspected and changed through the GitHub
Contents/Git Data API, so `pnpm build` / `test` / `test:e2e` could NOT be run here.

What was verified:
✅ tsc --noEmit over the new and changed TypeScript files (dependencies mapped to
   local stubs, since node_modules is not present): 0 errors; the only
   diagnostics were the stubbed external module names.
✅ The assertions in progress.service.spec.ts were compiled and executed against
   a Node harness with test-double implementations of @nestjs/common and rxjs
   (jest is not installed here): 5 passed, 0 failed — covering lesson/task
   percentages, completion only after all lessons+tasks, certificate issued
   exactly once with the 110 XP total, cross-course dashboard aggregation, and
   the NotFound/Conflict/BadRequest paths.
⚠️ Not executed here: the real Jest unit run and the Supertest e2e run. A
   maintainer should run:
     pnpm --filter @rustacademy/backend-academy build
     pnpm --filter @rustacademy/backend-academy test
     pnpm --filter @rustacademy/backend-academy test:e2e
Acceptance Criteria Status
Per-learner lesson completion % ✅ lessonCompletionPercent on LearnerCourseProgress
Task completion ✅ tasksCompleted / tasksTotal / taskCompletionPercent
XP earned per course ✅ xpEarned, read from the existing XP ledger by courseId
Aggregate endpoint for the dashboard ✅ GET /api/v1/progress/users/:userId/dashboard
Completing all lessons + tasks marks the course complete ✅ Single evaluateCompletion() transition sets completed / completedAt
Completion triggers certificate eligibility ✅ CertificateEligibility issued in the same transition and exposed via the API

Closes #791

Add ProgressModule/ProgressService for per-learner lesson and task completion,
per-course XP and dashboard aggregation, and the completion transition that
issues certificate eligibility. Reuses the existing DomainEventBus/XpService
so task.passed and course.completed XP are priced in one place.
@drips-wave

drips-wave Bot commented Sep 26, 2026

Copy link
Copy Markdown

@abiolatousin-design Great news! 🎉 Based on an automated assessment of this PR, the linked Wave issue(s) no longer count against your application limits.

You can now already apply to more issues while waiting for a review of this PR. Keep up the great work! 🚀

Learn more about application limits

@MaryammAli
MaryammAli merged commit 85d5b24 into BlockDash-Studios:main Sep 26, 2026
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

BE-038 — Progress tracking

2 participants