Skip to Content
Living documentation — last reviewed 2026-05-28
FeaturesCoursesCourses — Code Map

Courses — Code Map

API — apps/api/src/courses/

  • courses.module.ts
  • courses.controller.ts — split routing:
    • Trainer-side: @Controller() with explicit organizations/:orgId/courses[/…] paths.
    • Buyer-side: me/courses[/…] paths (no org param).
    • Public: @Public() on public/courses/:id and public/courses/:id/checkout.
  • courses.service.tscreate | findAll | findById | update | publish | archive | setDay | setPrice | listMyEntitlements | getMyEntitlement | startCourse | restartCourse | markWorkoutComplete | unmarkWorkoutComplete | getCourseWorkout | listEnrollments | findPublicById | ensureEntitlementForCheckout | attachLeadForBuyer.
  • course-checkout.service.ts — orchestrates the buy flow (categories A/B), gates by published status + active plan, calls PaymentService.createCourseHostedPayment.
  • courses.service.unit.spec.ts — unit tests.
  • dto/courses.dto.tsCreateCourseDto, UpdateCourseDto, SetCourseDayDto, SetCoursePriceDto, StartCourseDto, CourseCheckoutDto.

API — adjacent

  • apps/api/src/payments/services/payment.service.ts:213createCourseHostedPayment (sets metadata.courseEntitlementId).
  • apps/api/src/payments/services/webhook-processing.service.ts:199 / :332 — handles metadata.courseEntitlementId on payment-completed / payment-failed. Owns the cross-org guard.
  • apps/api/src/leads/ — lead lifecycle (source='course_purchase').
  • apps/api/src/organization-leads/ — junction table for category-B linking.

Shared

  • libs/shared/src/lib/schemas/course.schema.ts — Zod schemas for CourseResponse, PublicCourseResponse, CourseEntitlementResponse.
  • libs/shared/src/lib/constants/course-errors.ts (or similar) — COURSE_ALREADY_OWNED constant exported.

DB

  • libs/db/src/lib/schema/courses.tscourse_configs, course_workouts, course_entitlements, course_workout_completions.
  • libs/db/src/lib/schema/enums.tscourseEntitlementStatus, coursePreviewType, publishStatus, planType (course value), deliveryMode (course value), leadSource (course_purchase value).
  • libs/db/src/lib/schema/scheduling.tsprograms table (the parent row).
  • libs/db/src/lib/schema/payments.tsplans table (course plans live here with type='course' and program_id set).

Web — apps/web/src/

  • app/[lang]/buy/courses/[id]/page.tsx — public checkout entry point. Clerk email-code sign-in/sign-up flow; POSTs /public/courses/:id/checkout once authed.
  • app/[lang]/(protected)/library/[id]/page.tsx — buyer’s player.
  • app/[lang]/(protected)/dashboard/courses/ — trainer-side CRUD + curriculum editor + enrollments view.
  • components/courses/course-dialog.tsx — trainer dialog for creating / editing the high-level course.
  • components/courses/course-dialog.driver.tsx, course-dialog.int.spec.tsx — driver + tests.
  • components/course-player/:
    • player-header.tsx
    • day-nav.tsx, day-tile.tsx
    • workout-view.tsx
    • full-program-sheet.tsx

Cross-references

  • apps/api/src/minisites/ — the public storefront link points at /buy/courses/:id on the gym’s minisite host.
  • apps/api/src/notifications/templates/payment-receipt.ts — email used by sendPaymentReceipt after a paid course purchase (only fires for category-A buyers today; see Gaps in README).
  • apps/api/src/tasks/cancellation_review and manual_refund task types are not specific to courses but apply when refunding a course purchase.

i18n keys

  • courses.buy.* — public checkout (email step, code step, signed-in confirm, redirect copy, error messages including errorAlreadyOwned).
  • courses.* — trainer dialog + player labels.