강의 서비스
이 페이지는 lumie-backend/modules/lecture를 다룹니다.
책임
lecture 모듈은 다음을 소유합니다.
- 강의 레코드와 메타데이터
- 강의 가시성 상태
- 학생 접근을 위한 강의-반 타기팅
- 학생에게 보이는 강의 목록과 watch payload
- 강의 ID 또는 수업 기준 강의 조회를 위한 소규모 내부 API
소스 경로
| 경로 | 역할 |
|---|---|
lumie-backend/modules/lecture/src/main/java/com/lumie/lecture/adapter/in/web | 공개 lecture 및 student lecture 컨트롤러 |
lumie-backend/modules/lecture/src/main/java/com/lumie/lecture/adapter/in/internal/LectureServiceAdapter.java | internal monolith API 구현 |
lumie-backend/modules/lecture/src/main/java/com/lumie/lecture/application/service | command 및 쿼리 service |
lumie-backend/modules/lecture/src/main/java/com/lumie/lecture/domain/entity | Lecture, LectureClassTarget |
lumie-backend/libs/internal-api/src/main/java/com/lumie/lecture/api/LectureService.java | internal lecture 조회 계약 |
lumie-backend/app/src/main/resources/db/migration/public/V18__rls_baseline.sql | 기준선 lectures table |
lumie-backend/app/src/main/resources/db/migration/public/V57__create_lecture_class_targets.sql | lecture_class_targets 도입 및 cross-module no-FK 경계 문서화 |
공개 인터페이스
| 인터페이스 | 진입점 |
|---|---|
| Lecture CRUD | POST /v1/lectures, GET /v1/lectures, GET /v1/lectures/{id}, PATCH /v1/lectures/{id}, DELETE /v1/lectures/{id} |
| Student listing | GET /v1/lectures/student/class/{classId} |
| Student watch payload | GET /v1/lectures/student/{id}/watch |
내부 인터페이스
LectureService는 다음을 내보냅니다.
- ID 기준 단일 lecture 조회
- 수업 기준 lecture의 page 조회
classId와classIds를 모두 포함하는 응답 형태
중복된 classId와 classIds field는 두 개의 별도 비즈니스 개념이 아니라,
모듈의 현재 저장 모델을 반영합니다.
집계와 테이블
| 집계 | 테이블 | 참고 |
|---|---|---|
Lecture | lectures | teacher, title, description, YouTube URL, visibility, lecture date, legacy primary class_id 저장 |
LectureClassTarget | lecture_class_targets | 강의의 학생 가시 수업 target 전체를 저장 |
V57__create_lecture_class_targets.sql의 migration comment가 핵심 schema
경계입니다. class_id는 의미상 수업 모듈을 참조하지만, lecture와 classroom은
별도 모듈 경계이므로 데이터베이스는 의도적으로 foreign key를 강제하지
않습니다.
런타임 흐름
학생에게 보이는 강의 접근
핵심 동작
- instructor 사용자는 자신에게 배정된 class의 lecture만 관리할 수 있습니다.
LectureVisibility.STUDENT는 최소 하나의 수업 target을 요구합니다.- 학생용 lecture 목록은
lectureRepository.findVisibleByTargetClassId(...)를 사용하므로, 단순한lectures.class_id가 아니라 target row가 가시성을 결정합니다. - 학생 watch 접근은 다음 둘 다를 확인합니다.
- lecture가 학생에게 공개되어 있는가
- 현재 student가 target 수업 중 하나 이상에 등록되어 있는가
- write 시
class_id는 primary 또는 대체 처리 class로 유지되고, 전체 집합은lecture_class_targets에 저장됩니다.
의존성과 경계
| 의존성 | 존재 이유 |
|---|---|
StaffService | 인증된 user에서 현재 instructor의 staff ID 해석 |
ClassService | 수업 target과 student enrollment visibility 검증 |
StudentService | watch 접근을 위한 현재 student ID 해석 |
실패 모드
- 존재하지 않는 lecture 또는 class는
LECTURE_NOT_FOUND,CLASS_NOT_FOUND로 실패합니다. - target이 없는 student visibility는
STUDENT_VISIBILITY_REQUIRES_CLASS로 실패합니다. - target 수업 집합 밖의 학생은
LECTURE_NOT_VISIBLE_TO_CLASS를 받습니다. - 배정되지 않은 class의 lecture를 관리하려는 instructor는
FORBIDDEN을 받습니다.
알아둘 계약상 미묘한 차이
lecture targeting은 의도적으로 migration 상태에 있습니다.
lectures.class_id는 여전히 존재하며 primary/대체 처리 class로 사용됩니다.lecture_class_targets는 학생 접근을 위한 authoritative multi-수업 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"
}
classId는 lectures에 저장되는 primary/대체 처리 class로 남고,
classIds는 lecture_class_targets에 저장되는 deduplicated 전체 target
집합입니다. 학생 watch 접근은 legacy classId column만이 아니라 이 target
집합을 기준으로 평가됩니다.
관측성
- command와 쿼리 service는 수명주기 이벤트를 로그하고 동기 검증에 의존합니다.
- 이 모듈에는 queue, retry loop, 워커 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 오류 없이 완료됩니다.