Skip to content

Course Workflow Hardening Task

Agent workflow: follow README.md for Audit -> Investigate -> Code -> Test -> Fix; keep this pack's writable scope and verification commands authoritative.

Dispatch type: orchestrator

Owner: course-service.

Goal:

Strengthen course-service behavior and tests before public course/student-course route promotion.

Legacy source evidence:

  • /Users/velikho/Desktop/WORKING/HOCTAPAZ/node-platform/apps/api/src/modules/courses/**
  • /Users/velikho/Desktop/WORKING/HOCTAPAZ/node-platform/apps/api/prisma/schema.prisma
  • course/student-course frontend callers under /Users/velikho/Desktop/WORKING/HOCTAPAZ/node-platform/apps/web.

Writable files:

  • services/course-service/**
  • contracts/openapi/services/course-service.yaml
  • docs/api/course-service.md
  • docs/agents/service-tasks/course-workflow-hardening.md

Orchestrator-owned files:

  • Gateway route tables, billing/wallet/usage integration contracts, file-service media adapters, and frontend/browser smoke artifacts.

Tasks:

  • [x] Add usecase tests for authoring, archive/delete guards, sections, lessons, enrollments, material refs, lesson progress, video progress, and material views.
  • [x] Add management-only lesson-question and quiz reference persistence without making course-service the question or exam source of truth. References are IDs, placement metadata, and optional copied display titles only; public, Gateway/BFF, owner-API validation, and learner delivery remain deferred.
  • [x] Add mastery/recommendation/report projection hooks as a bounded cross-service read-model task in analytics-course-learning-projection.md. The task requires a trusted course-attempt context, Course-owned catalog events, and a local Analytics materializer; no public/default route is implied.
  • [x] Keep purchase/paid access legacy until a dedicated billing/wallet integration has owner-source and route proof.

Current state:

  • Added services/course-service/internal/usecase/course_test.go with manager authorization, section/lesson/material cleanup, enrollment expiry, progress completion, material view counting, and public preview coverage.
  • Student/public material projections now hide lesson-attached materials when the owning lesson is not visible in that projection. Course-level materials still follow their own published/preview flags.
  • 000004_course_question_exam_references.sql adds local lesson-question and quiz reference tables. Duplicate (lesson,question) and (course,exam) saves update placement metadata rather than duplicate rows; lesson deletion cascades question links and unbinds quiz lesson placement, while section deletion unbinds quiz section placement.
  • Course reads and copied search outbox events now carry aggregate reference counts only. The events exclude external ids and copied titles. Isolated Postgres coverage verifies both count updates and cleanup behavior.
  • analytics-course-learning-projection.md records the only acceptable native mastery/recommendation/report direction: Course produces catalog/progress snapshots, Attempt persists a Course-validated context and publishes a v2 graded event, and Analytics owns replayable read models. An examId alone must never attach an attempt to a course.
  • 000006_course_learning_catalog_outbox.sql gives the Course catalog feed an opt-in durable transport boundary. It is a lease/retry/dead-letter worker outside request latency, preserves Course ownership of delivery state, and only writes Analytics input events; it is not a materialization or route promotion mechanism.

Acceptance:

  • Course-service owns course/progress state only.
  • File bytes remain in file-service.
  • Question/exam references are IDs/snapshots/contracts, not DB joins.
  • Public course/student-course route promotion requires named route coverage, browser or live smoke for the changed workflow, and rollback evidence. If the target does not exist yet, the agent must add it before promotion.

Verification:

  • GOTOOLCHAIN=go1.25.11 go test ./services/course-service/... (passing)
  • GOTOOLCHAIN=go1.25.11 go test ./services/course-service/internal/usecase -run 'TestCourseReferences|TestCourseReferenceValidation' -count=1 -v
  • GOTOOLCHAIN=go1.25.11 go test ./services/course-service/internal/http -run TestCourseReferenceRoutes -count=1 -v
  • COURSE_SEARCH_PROJECTION_OUTBOX_POSTGRES_CONFIRM=disposable-postgres make test-course-search-projection-outbox-postgres
  • COURSE_SEARCH_PROJECTION_OUTBOX_POSTGRES_CONFIRM=disposable-postgres make test-course-learning-catalog-delivery-postgres
  • COURSE_SEARCH_PROJECTION_OUTBOX_POSTGRES_CONFIRM=disposable-postgres make test-course-learning-progress-delivery-postgres
  • make test-student-course-routes test-student-course-progress-routes
  • Add/run a named browser/live smoke for any default public course promotion.

Go-platform documentation is generated from repository Markdown.