Class Service
This page covers lumie-backend/modules/class. The Gradle module is named class, while the Java package and internal API use classroom.
Responsibility
The class module owns:
- class records;
- class schedule patterns;
- student enrollments and enrollment status;
- teacher- and student-oriented class listings;
- class dashboard metrics;
- the internal classroom lookup contract used by attendance, lecture, assignment, and student deletion flows.
Source Paths
| Path | Role |
|---|---|
lumie-backend/modules/class/src/main/java/com/lumie/classroom/adapter/in/web | Public class, enrollment, and statistics controllers |
lumie-backend/modules/class/src/main/java/com/lumie/classroom/adapter/in/internal/ClassServiceAdapter.java | Internal monolith API implementation |
lumie-backend/modules/class/src/main/java/com/lumie/classroom/application/service | Command, query, and statistics services |
lumie-backend/modules/class/src/main/java/com/lumie/classroom/domain/entity | ClassEntity and ClassEnrollment |
lumie-backend/modules/class/src/main/java/com/lumie/classroom/domain/vo/SchedulePattern.java | JSONB schedule model |
lumie-backend/libs/internal-api/src/main/java/com/lumie/classroom/api/ClassService.java | Internal class contract |
lumie-backend/app/src/main/resources/db/migration/public/V18__rls_baseline.sql | Baseline classes and class_enrollments tables |
Public Surface
| 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 |
Internal Surface
ClassService exports:
- class lookup by ID;
- pagination over teacher, student, or all classes;
- enrolled student IDs for a class;
- enrolled class rows for a set of students;
- student enrollment checks;
- active enrollment checks and bulk drop of active enrollments;
- assigned-class checks for a staff member.
This is one of the broadest internal APIs in the backend because multiple modules depend on class ownership and enrollment state.
Aggregates And Tables
| Aggregate | Table | Notes |
|---|---|---|
ClassEntity | classes | Stores teacher_id, teacher_deleted, schedule_pattern, and description |
ClassEnrollment | class_enrollments | Unique on (class_id, student_id) and tracks drop or completion timestamps |
ClassEntity.schedulePattern is stored as JSONB through a custom attribute converter. The class module is therefore the source of truth for teaching schedule overlap validation.
Runtime Flow
Enrollment flow with schedule checks
Key Behaviors
- Teacher IDs are validated through
StaffService.getStaff(...)before class creation. - Teacher schedule overlap is checked against every existing class for that teacher.
- Student schedule overlap is checked before enrollment against every currently
ENROLLEDclass for that student. teacher_deletedremains on the class row so the class can still render a deleted-teacher placeholder after the staff row is gone.- Enrollment status transitions are implemented inside the aggregate:
ENROLLED -> DROPPEDENROLLED -> COMPLETED
- Student deletion relies on
dropActiveEnrollmentsForStudent(...)through the internal API.
Representative Contract Example
This example matches EnrollStudentsRequest, ClassEnrollmentResponse, ClassEnrollmentControllerTest.enrollStudents_returns201, and the overlap guards in ClassCommandService.
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"
}
]
If one student already has another ENROLLED class with an overlapping session, the same endpoint fails with 409 Conflict and the RFC 7807 body from GlobalExceptionHandler:
{
"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"
}
Dependencies And Boundaries
| Dependency | Why it exists |
|---|---|
StaffService | Validate and resolve teacher records |
The class module does not own teacher or student data. It stores only IDs and consults the staff module when it needs teacher names or teacher validity.
Failure Modes
- Unknown classes, teachers, or enrollments fail with
CLASS_NOT_FOUND,TEACHER_NOT_FOUND, orENROLLMENT_NOT_FOUND. - Enrollment writes can fail with
DUPLICATE_ENROLLMENT,SCHEDULE_OVERLAP, orSTUDENT_SCHEDULE_OVERLAP. - JSON serialization or deserialization failures in
schedule_patternsurface asJSON_SERIALIZATION_FAILED.
Observability
- Command services log create, update, delete, enroll, and drop operations.
- Query services resolve missing teachers to the
"삭제된 강사"fallback rather than failing the entire response. - The module is synchronous only. There are no events, queues, or scheduled repair loops in the current class write surface.
Verification
./gradlew :modules:class:test
./gradlew :app:test --tests '*Class*'
cd lumie-document/docusaurus && npm run build
Expected success signals:
- Gradle finishes with
BUILD SUCCESSFUL. ClassEnrollmentControllerTestandClassCommandServiceTestpass without failures.- Docusaurus finishes without MDX or broken-link errors for
backend/class-svc.