반 서비스
이 페이지는 lumie-backend/modules/class를 다룹니다. Gradle 모듈 이름은
class이지만, Java package와 internal API는 classroom을 사용합니다.
책임
class 모듈은 다음을 소유합니다.
- 반(class) 레코드
- 반 시간표 패턴
- 학생 enrollment와 enrollment 상태
- 교사용 및 학생용 반 목록
- 반 dashboard 지표
- attendance, lecture, assignment, student deletion 흐름이 사용하는 internal classroom lookup 계약
소스 경로
| Path | 역할 |
|---|---|
lumie-backend/modules/class/src/main/java/com/lumie/classroom/adapter/in/web | 공개 class, enrollment, statistics controller |
lumie-backend/modules/class/src/main/java/com/lumie/classroom/adapter/in/internal/ClassServiceAdapter.java | internal monolith API 구현 |
lumie-backend/modules/class/src/main/java/com/lumie/classroom/application/service | command, query, statistics service |
lumie-backend/modules/class/src/main/java/com/lumie/classroom/domain/entity | ClassEntity, ClassEnrollment |
lumie-backend/modules/class/src/main/java/com/lumie/classroom/domain/vo/SchedulePattern.java | JSONB schedule 모델 |
lumie-backend/libs/internal-api/src/main/java/com/lumie/classroom/api/ClassService.java | internal class 계약 |
lumie-backend/app/src/main/resources/db/migration/public/V18__rls_baseline.sql | baseline classes, class_enrollments table |
공개 인터페이스
| Surface | Entrypoints |
|---|---|
| Class CRUD | POST /v1/classes, GET /v1/classes, GET /v1/classes/{id}, PATCH /v1/classes/{id}, DELETE /v1/classes/{id} |
| Role-oriented lists | GET /v1/classes/teacher/{teacherId}, GET /v1/classes/student/{studentId} |
| Enrollment management | GET /v1/classes/{classId}/enrollments, POST /v1/classes/{classId}/enrollments, PATCH /v1/classes/{classId}/enrollments/{enrollmentId}, DELETE /v1/classes/{classId}/enrollments/{enrollmentId}, DELETE /v1/classes/{classId}/enrollments/student/{studentId} |
| Dashboard | GET /v1/classes/statistics/dashboard |
내부 인터페이스
ClassService는 다음을 export합니다.
- ID 기준 class 조회
- teacher, student, 전체 class에 대한 pagination
- class의 enrolled student ID
- 주어진 student 집합의 enrolled class row
- student enrollment 여부 확인
- 활성 enrollment 여부 확인과 활성 enrollment 일괄 drop
- 특정 staff의 assigned class 여부 확인
여러 모듈이 class 소유권과 enrollment 상태에 의존하기 때문에, 이 internal API는 백엔드에서 가장 넓은 범위의 API 중 하나입니다.
집계와 테이블
| Aggregate | Table | 참고 |
|---|---|---|
ClassEntity | classes | teacher_id, teacher_deleted, schedule_pattern, description 저장 |
ClassEnrollment | class_enrollments | (class_id, student_id) unique 제약과 drop/completion timestamp 추적 |
ClassEntity.schedulePattern은 custom attribute converter를 통해 JSONB로
저장됩니다. 따라서 class 모듈이 teaching schedule overlap 검증의 source of
truth입니다.
런타임 흐름
일정 확인이 포함된 등록 흐름
핵심 동작
- teacher ID는 class 생성 전에
StaffService.getStaff(...)로 검증합니다. - teacher schedule overlap은 해당 teacher의 기존 모든 class를 기준으로 검사합니다.
- student schedule overlap은 enrollment 전에 그 student의 현재
ENROLLEDclass 전부와 비교합니다. teacher_deleted는 staff row가 사라진 뒤에도 삭제된 teacher placeholder를 렌더링할 수 있도록 class row에 남아 있습니다.- enrollment 상태 전이는 aggregate 내부에서 구현됩니다.
ENROLLED -> DROPPEDENROLLED -> COMPLETED- student 삭제는 internal API의
dropActiveEnrollmentsForStudent(...)에 의존합니다.
대표 계약 예시
이 예시는 EnrollStudentsRequest, ClassEnrollmentResponse,
ClassEnrollmentControllerTest.enrollStudents_returns201,
ClassCommandService의 overlap guard와 일치합니다.
POST /v1/classes/1/enrollments
{
"studentIds": [42, 43]
}
[
{
"id": 10,
"classId": 1,
"studentId": 42,
"enrolledAt": "2026-06-14T09:00:00Z",
"droppedAt": null,
"status": "ENROLLED",
"createdAt": "2026-06-14T09:00:00Z",
"updatedAt": "2026-06-14T09:00:00Z"
},
{
"id": 11,
"classId": 1,
"studentId": 43,
"enrolledAt": "2026-06-14T09:00:00Z",
"droppedAt": null,
"status": "ENROLLED",
"createdAt": "2026-06-14T09:00:00Z",
"updatedAt": "2026-06-14T09:00:00Z"
}
]
한 학생이 이미 시간이 겹치는 다른 ENROLLED class를 갖고 있으면,
같은 endpoint는 409 Conflict와 함께 GlobalExceptionHandler의 RFC 7807
body를 반환합니다.
{
"type": "urn:lumie:error:class-011",
"title": "Student already has a class at the overlapping time",
"status": 409,
"detail": "Student 42 already has class '수학 심화반' at overlapping time",
"instance": "/v1/classes/1/enrollments",
"code": "CLASS_011"
}
의존성과 경계
| Dependency | 존재 이유 |
|---|---|
StaffService | teacher record를 검증하고 해석 |
class 모듈은 teacher나 student 데이터를 소유하지 않습니다. ID만 저장하고, teacher 이름이나 유효성을 확인해야 할 때 staff 모듈에 질의합니다.
실패 모드
- 존재하지 않는 class, teacher, enrollment는 각각
CLASS_NOT_FOUND,TEACHER_NOT_FOUND,ENROLLMENT_NOT_FOUND로 실패합니다. - enrollment 쓰기는
DUPLICATE_ENROLLMENT,SCHEDULE_OVERLAP,STUDENT_SCHEDULE_OVERLAP로 실패할 수 있습니다. schedule_pattern의 JSON 직렬화/역직렬화 실패는JSON_SERIALIZATION_FAILED로 surface됩니다.
관측성
- command service는 create, update, delete, enroll, drop 작업을 로그합니다.
- query service는 teacher가 없을 때 전체 응답을 실패시키지 않고
"삭제된 강사"fallback으로 해석합니다. - 이 모듈은 동기식 בלבד입니다. 현재 class 쓰기 surface에는 event, queue, scheduled repair loop가 없습니다.
검증
./gradlew :modules:class:test
./gradlew :app:test --tests '*Class*'
cd lumie-document/docusaurus && npm run build
예상 성공 신호:
- Gradle이
BUILD SUCCESSFUL로 끝납니다. ClassEnrollmentControllerTest와ClassCommandServiceTest가 실패 없이 통과합니다.- Docusaurus가
backend/class-svc에 대해 MDX 또는 broken-link 오류 없이 완료됩니다.