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
| Command | Trigger |
|---|---|
CreateEnrollment | Event consumption or API |
CompleteEnrollment | progress.completion.recorded.v1 |
ExpireEnrollment | Scheduled (expiresAt) |
RevokeEnrollment | Admin / marketplace.license.revoked.v1 |
RecordAccess | delivery.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.v1orprogress.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.