출석 서비스
이 페이지는 lumie-backend/modules/attendance를 다룹니다.
책임
attendance 모듈은 다음을 소유합니다.
- 날짜별 또는 class별 attendance session
- 학생별 attendance record
- 코드 기반 학생 체크인
- class, student, dashboard 출결 통계
- 출결 이력 CSV export
class 모듈과 student 모듈과 달리, attendance는 현재 internal
libs/internal-api 계약 을 노출하지 않습니다. 다른 모듈은 attendance 측
service API가 아니라 class 조회와 공유 tenant 범위 table을 통해 통합합니다.
소스 경로
| Path | 역할 |
|---|---|
lumie-backend/modules/attendance/src/main/java/com/lumie/attendance/adapter/in/web | 공개 HTTP controller |
lumie-backend/modules/attendance/src/main/java/com/lumie/attendance/application/service | session, record, statistics, export service |
lumie-backend/modules/attendance/src/main/java/com/lumie/attendance/domain/entity | AttendanceSession, AttendanceRecord, StudentReadModel |
lumie-backend/modules/attendance/src/main/java/com/lumie/attendance/domain/repository | session, record, student read repository |
lumie-backend/app/src/main/resources/db/migration/public/V18__rls_baseline.sql | baseline attendance_sessions, attendance_records table |
lumie-backend/app/src/main/resources/db/migration/public/V20__rename_qna_is_it_answered.sql | attendance table에 optimistic-lock version column 추가 |
공개 인터페이스
| Surface | Entrypoints |
|---|---|
| Session CRUD | POST /v1/attendance/sessions, GET /v1/attendance/sessions, GET /v1/attendance/sessions/{id}, POST /v1/attendance/sessions/{id}/regenerate-code, DELETE /v1/attendance/sessions/{id} |
| Session records | GET /v1/attendance/sessions/{sessionId}/records, PATCH /v1/attendance/sessions/{sessionId}/records/{recordId}, POST /v1/attendance/sessions/{sessionId}/records/bulk-update |
| Class-oriented helpers | POST /v1/attendance/classes/{classId}/sessions/ensure, GET /v1/attendance/classes/{classId}/statistics, GET /v1/attendance/classes/{classId}/students |
| Student self check-in | POST /v1/attendance/check-in |
| Student history | GET /v1/attendance/students/{studentId}/records, GET /v1/attendance/students/{studentId}/statistics |
| Dashboard and export | GET /v1/attendance/statistics/dashboard, GET /v1/attendance/records/export.csv |
집계와 읽기 모델
| Type | Table | 참고 |
|---|---|---|
AttendanceSession | attendance_sessions | session date, 선택적 class 연결, attendance code, 지각 기준, record collection 저장 |
AttendanceRecord | attendance_records | (session_id, student_id) unique |
StudentReadModel | students | 변경 불가능한 read-only student projection |
StudentReadModel은 의도적인 cross-module read model입니다. attendance
모듈은 자체 student cache를 두는 대신, 불변에 가까운 이름과 user 연결을 위해
students table을 직접 읽습니다.
런타임 흐름
반 세션 보장 흐름
학생 체크인 흐름
핵심 동작
ensureSessionForClass(...)는(classId, KST 기준 오늘)에 대해 idempotent하며, 이미 존재하면 기존 session을 반환합니다.- class용 session 생성은
ClassService.getEnrolledStudentIds(...)를 이용해 현재 등록 학생 수만큼 record를 미리 만듭니다. - class가 없는 단독 session 생성은
StudentReadRepository.findByIsActiveTrue()의 모든 활성 학생을 사용합니다. - check-in은 payload의 student ID가 아니라 인증된
userId로 학생을 해석합니다. - dashboard 통계는 미결정 row가 출석률을 희석하지 않도록
PENDINGrecord를 제외합니다. - CSV export는 session을 페이지 단위로 읽고, 각 페이지별로 record와 student 이름을 메모리에서 join합니다.
대표 계약 예시
이 예시는 ClassAttendanceController, StudentCheckInController,
AttendanceSessionResponse, CheckInResponse,
AttendanceSessionCommandService, AttendanceRecordCommandService, 관련
controller/service test와 일치합니다.
오늘의 반 세션 보장
POST /v1/attendance/classes/9/sessions/ensure
{
"id": 77,
"name": "수학반 A",
"sessionDate": "2026-06-14",
"classId": 9,
"className": "수학반 A",
"attendanceCode": "654321",
"codeExpiresAt": null,
"lateThresholdMinutes": 10,
"createdAt": "2026-06-14T00:00:00Z",
"updatedAt": "2026-06-14T00:00:00Z",
"presentCount": 0,
"absentCount": 0,
"lateCount": 0,
"excusedCount": 0,
"totalStudents": 0
}