Skip to main content

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

PathRole
lumie-backend/modules/class/src/main/java/com/lumie/classroom/adapter/in/webPublic class, enrollment, and statistics controllers
lumie-backend/modules/class/src/main/java/com/lumie/classroom/adapter/in/internal/ClassServiceAdapter.javaInternal monolith API implementation
lumie-backend/modules/class/src/main/java/com/lumie/classroom/application/serviceCommand, query, and statistics services
lumie-backend/modules/class/src/main/java/com/lumie/classroom/domain/entityClassEntity and ClassEnrollment
lumie-backend/modules/class/src/main/java/com/lumie/classroom/domain/vo/SchedulePattern.javaJSONB schedule model
lumie-backend/libs/internal-api/src/main/java/com/lumie/classroom/api/ClassService.javaInternal class contract
lumie-backend/app/src/main/resources/db/migration/public/V18__rls_baseline.sqlBaseline classes and class_enrollments tables

Public Surface

SurfaceEntrypoints
Class CRUDPOST /v1/classes, GET /v1/classes, GET /v1/classes/{id}, PATCH /v1/classes/{id}, DELETE /v1/classes/{id}
Role-oriented listsGET /v1/classes/teacher/{teacherId}, GET /v1/classes/student/{studentId}
Enrollment managementGET /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}
DashboardGET /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

AggregateTableNotes
ClassEntityclassesStores teacher_id, teacher_deleted, schedule_pattern, and description
ClassEnrollmentclass_enrollmentsUnique 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 ENROLLED class for that student.
  • teacher_deleted remains 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 -> DROPPED
    • ENROLLED -> 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

DependencyWhy it exists
StaffServiceValidate 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, or ENROLLMENT_NOT_FOUND.
  • Enrollment writes can fail with DUPLICATE_ENROLLMENT, SCHEDULE_OVERLAP, or STUDENT_SCHEDULE_OVERLAP.
  • JSON serialization or deserialization failures in schedule_pattern surface as JSON_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.
  • ClassEnrollmentControllerTest and ClassCommandServiceTest pass without failures.
  • Docusaurus finishes without MDX or broken-link errors for backend/class-svc.