본문으로 건너뛰기

강의 서비스

이 페이지는 lumie-backend/modules/lecture를 다룹니다.

책임

lecture 모듈은 다음을 소유합니다.

  • 강의 레코드와 메타데이터
  • 강의 가시성 상태
  • 학생 접근을 위한 강의-반 타기팅
  • 학생에게 보이는 강의 목록과 watch payload
  • 강의 ID 또는 class 기준 강의 조회를 위한 소규모 internal API

소스 경로

Path역할
lumie-backend/modules/lecture/src/main/java/com/lumie/lecture/adapter/in/web공개 lecture 및 student lecture controller
lumie-backend/modules/lecture/src/main/java/com/lumie/lecture/adapter/in/internal/LectureServiceAdapter.javainternal monolith API 구현
lumie-backend/modules/lecture/src/main/java/com/lumie/lecture/application/servicecommand 및 query service
lumie-backend/modules/lecture/src/main/java/com/lumie/lecture/domain/entityLecture, LectureClassTarget
lumie-backend/libs/internal-api/src/main/java/com/lumie/lecture/api/LectureService.javainternal lecture 조회 계약
lumie-backend/app/src/main/resources/db/migration/public/V18__rls_baseline.sqlbaseline lectures table
lumie-backend/app/src/main/resources/db/migration/public/V57__create_lecture_class_targets.sqllecture_class_targets 도입 및 cross-module no-FK 경계 문서화

공개 인터페이스

SurfaceEntrypoints
Lecture CRUDPOST /v1/lectures, GET /v1/lectures, GET /v1/lectures/{id}, PATCH /v1/lectures/{id}, DELETE /v1/lectures/{id}
Student listingGET /v1/lectures/student/class/{classId}
Student watch payloadGET /v1/lectures/student/{id}/watch

내부 인터페이스

LectureService는 다음을 export합니다.

  • ID 기준 단일 lecture 조회
  • class 기준 lecture의 page 조회
  • classIdclassIds를 모두 포함하는 응답 형태

중복된 classIdclassIds field는 두 개의 별도 비즈니스 개념이 아니라, 모듈의 현재 저장 모델을 반영합니다.

집계와 테이블

AggregateTable참고
Lecturelecturesteacher, title, description, YouTube URL, visibility, lecture date, legacy primary class_id 저장
LectureClassTargetlecture_class_targets강의의 학생 가시 class target 전체를 저장

V57__create_lecture_class_targets.sql의 migration comment가 핵심 schema 경계입니다. class_id는 의미상 class 모듈을 참조하지만, lecture와 classroom은 별도 모듈 경계이므로 데이터베이스는 의도적으로 foreign key를 강제하지 않습니다.

런타임 흐름

학생에게 보이는 강의 접근

핵심 동작

  • instructor 사용자는 자신에게 배정된 class의 lecture만 관리할 수 있습니다.
  • LectureVisibility.STUDENT는 최소 하나의 class target을 요구합니다.
  • 학생용 lecture 목록은 lectureRepository.findVisibleByTargetClassId(...)를 사용하므로, 단순한 lectures.class_id가 아니라 target row가 가시성을 결정합니다.
  • 학생 watch 접근은 다음 둘 다를 확인합니다.
  • lecture가 학생에게 공개되어 있는가
  • 현재 student가 target class 중 하나 이상에 등록되어 있는가
  • write 시 class_id는 primary 또는 fallback class로 유지되고, 전체 집합은 lecture_class_targets에 저장됩니다.

의존성과 경계

Dependency존재 이유
StaffService인증된 user에서 현재 instructor의 staff ID 해석
ClassServiceclass target과 student enrollment visibility 검증
StudentServicewatch 접근을 위한 현재 student ID 해석

실패 모드

  • 존재하지 않는 lecture 또는 class는 LECTURE_NOT_FOUND, CLASS_NOT_FOUND로 실패합니다.
  • target이 없는 student visibility는 STUDENT_VISIBILITY_REQUIRES_CLASS로 실패합니다.
  • target class 집합 밖의 학생은 LECTURE_NOT_VISIBLE_TO_CLASS를 받습니다.
  • 배정되지 않은 class의 lecture를 관리하려는 instructor는 FORBIDDEN을 받습니다.

알아둘 계약상 미묘한 차이

lecture targeting은 의도적으로 migration 상태에 있습니다.

  • lectures.class_id는 여전히 존재하며 primary/fallback class로 사용됩니다.
  • lecture_class_targets는 학생 접근을 위한 authoritative multi-class visibility table입니다.

현재 코드는 둘 다 읽고 쓰므로, 문서도 둘 다 설명합니다.

대표 계약 예시

이 예시는 CreateLectureRequest, LectureResponse, LectureCommandServiceTest.create_deduplicatesAndStoresClassTargets와 일치합니다.

POST /v1/lectures

{
"classId": 2,
"classIds": [2, 3],
"teacherId": 10,
"title": "수업 영상",
"description": null,
"youtubeUrl": "https://www.youtube.com/watch?v=abc123",
"visibility": "STUDENT",
"lectureDate": null
}
{
"id": 1,
"classId": 2,
"classIds": [2, 3],
"teacherId": 10,
"title": "수업 영상",
"description": null,
"youtubeUrl": "https://www.youtube.com/watch?v=abc123",
"visibility": "STUDENT",
"lectureDate": null,
"createdAt": "2026-06-14T09:00:00Z",
"updatedAt": "2026-06-14T09:00:00Z"
}

classIdlectures에 저장되는 primary/fallback class로 남고, classIdslecture_class_targets에 저장되는 deduplicated 전체 target 집합입니다. 학생 watch 접근은 legacy classId column만이 아니라 이 target 집합을 기준으로 평가됩니다.

관측성

  • command와 query service는 lifecycle event를 로그하고 동기 검증에 의존합니다.
  • 이 모듈에는 queue, retry loop, worker interaction이 없습니다.

검증

./gradlew :modules:lecture:test
./gradlew :app:test --tests '*Lecture*'
cd lumie-document/docusaurus && npm run build

예상 성공 신호:

  • Gradle이 BUILD SUCCESSFUL로 끝납니다.
  • LectureCommandServiceTest, LectureQueryServiceTest, LectureResponseTest가 실패 없이 통과합니다.
  • Docusaurus가 backend/lecture-svc에 대해 MDX 또는 broken-link 오류 없이 완료됩니다.

관련 페이지