Skip to main content

Application Logic

:::info Source Sourced from services/enrollment-service/APPLICATION_LOGIC.md in the documentation repo. :::

1. Application Services

  • EnrollmentService — create, revoke, query.
  • LifecycleService — expire scheduler, completion handler.
  • AccessService — verify learner has active enrollment (used by delivery).

2. Commands

CommandTrigger
CreateEnrollmentEvent consumption or API
CompleteEnrollmentprogress.completion.recorded.v1
ExpireEnrollmentScheduled (expiresAt)
RevokeEnrollmentAdmin / marketplace.license.revoked.v1
RecordAccessdelivery.play_session.started.v1

3. Queries

  • getEnrollment(id), listByUser(userId), listByCourse(courseId), exists(userId, courseId).

4. Sagas

  • Purchase saga participant (marketplace saga step 4).
  • Assignment saga: enrollment creation bridges to compliance window.
  • GDPR erasure saga: delete enrollments for user (audit retained).

5. Policies

  • Idempotent on (tenantId, userId, courseId, source.ref).
  • Allow multiple enrollments per course only from different sources (e.g., assignment + purchase) with admin discretion.
  • Completion precedes certificate issuance (certification-service listens for enrollment.completed.v1 or progress.completion.recorded.v1).

6. Use Case Flows

6.1 Purchase-Driven

marketplace.license.granted.v1 ──▶ EnrollmentService.createFromLicense


Persist + emit enrollment.created.v1

├─▶ content-service (bundle creation)
├─▶ notification-service (welcome)
└─▶ marketplace saga (step 4 completion)

6.2 Assignment-Driven

assignment.window.opened.v1 ──▶ NOT yet enroll (defer until first play)
delivery.play_session.started.v1 (first time) ──▶ enrollment.create
(retroactively link to window)
emit enrollment.created.v1 + enrollment.accessed.v1

6.3 Manual Admin

Admin: POST /api/v1/enrollments { userId, courseId, courseVersionId }
Validate: courseVersion exists; user is in tenant; license (if needed) available.
Create + emit.

6.4 Self-Signup (free or entitled course)

Learner: POST /api/v1/self-enroll { courseId }
Check: course accessible by learner (via tenant plan or marketplace open listing).
If paid: redirect to marketplace purchase flow.
If free + entitled: create enrollment directly.

6.5 Completion

progress.completion.recorded.v1 ──▶ CompleteEnrollment(enrollmentId)
Update state='completed'; set completedAt.
Emit enrollment.completed.v1 → certification-service issues cert.

6.6 Expiration

Scheduler nightly: SELECT enrollments WHERE state='active' AND expiresAt < now.
For each: expire; emit enrollment.expired.v1.

6.7 Revocation

marketplace.license.revoked.v1 ──▶ revoke all enrollments from that license.
Admin action ──▶ explicit revoke API.
Emit enrollment.revoked.v1 → content-service revokes bundles; notification.