Overview
CoursesService.create() in src/courses/courses.service.ts saves the Course, then separately saves a CourseVersion snapshot, then emits COURSE_CREATED — with no transaction spanning the two writes. update() follows the same pattern. If the version insert fails (constraint violation, connection drop, deploy restart between the two statements) the course exists with no version-1 record, permanently breaking the version history the publishing workflow and rollback features depend on. The cache invalidation event is also emitted before the writes are durable, so a listener can repopulate the cache from a state that is subsequently rolled back.
Specifications
Features:
- A course and its version snapshot are created atomically.
- Cache invalidation events are emitted only after commit.
Tasks:
- Wrap the course save and version save in
dataSource.transaction, using the transactional manager for both repositories, in create, update, and the review-decision path.
- Move
eventEmitter.emit(CACHE_EVENTS.*) to after the transaction commits.
- Add a data-repair migration or script that backfills a version-1 row for any course currently missing one.
- Add a test that forces the version insert to fail and asserts no course row is left behind.
Impacted Files:
src/courses/courses.service.ts
Acceptance Criteria
- A failure during version insertion rolls back the course insert.
- Every course has at least one version row.
- Cache events fire only after a successful commit.
Overview
CoursesService.create()insrc/courses/courses.service.tssaves theCourse, then separately saves aCourseVersionsnapshot, then emitsCOURSE_CREATED— with no transaction spanning the two writes.update()follows the same pattern. If the version insert fails (constraint violation, connection drop, deploy restart between the two statements) the course exists with no version-1 record, permanently breaking the version history the publishing workflow and rollback features depend on. The cache invalidation event is also emitted before the writes are durable, so a listener can repopulate the cache from a state that is subsequently rolled back.Specifications
Features:
Tasks:
dataSource.transaction, using the transactional manager for both repositories, increate,update, and the review-decision path.eventEmitter.emit(CACHE_EVENTS.*)to after the transaction commits.Impacted Files:
src/courses/courses.service.tsAcceptance Criteria