마지막 업데이트 2026-07-22
한 수업이 시작되어 아동이 입장하고 종료되기까지의 오케스트레이션. 입장 가능 검증(can-enter) → SFU 소켓 연결(인스턴스 고정) → 입장 승인(리소스 캐싱) → LessonSession 레코드 생성·종료(누적시간 기반). 실제 AI 세션 제어는 세션 릴레이(#6).
{userId}_{lessonIndex}. LessonSession은 "한 번의 접속"을 나타내는 DynamoDB 레코드로, 재접속마다 새로 생기고 종료 시 duration이 누적된다 → 모니터 누적시간(#13)의 원천 데이터.
GET /api/lessons/:userId/:index/can-enter → canEnterLesson(userId, lessonIndex). 수업 스케줄/상태로 입장 가능 여부를 게이트한다(시간·중복 등). 게스트 입장 플로우(#25)의 진입 조건.
instanceId를 setTargetInstance()로 저장 → 자동 재연결 시 auth: cb({ targetInstance })로 같은 인스턴스에 복귀(room pin #5와 짝). 다른 인스턴스면 서버가 WRONG_INSTANCE redirect.reconnect 시 앱이 re-join/re-auth 처리.navigator online 이벤트로 수동 재연결(단, reconnection(false)로 영구 차단된 소켓은 제외).guest-request-entry emit → 호스트 handleRequest가 pendingGuest 설정(UI에 승인 대기 표시).resourceFileNames)를 cacheResources로 IndexedDB에 미리 받음(cachingProgress로 진척 표시). 다운로드 실패 시 입장 차단(#22 연계).onForceKick)서버측 승인 이벤트 중계는 SFU room-handlers(#2: GUEST_REQUEST_ENTRY → HOST_APPROVE_ENTRY2 / host-deny-entry).
LessonSession { userId(PK), sessionId(SK = `${lessonIndex}#${enteredAt}`), lessonIndex, roomId, enteredAt, exitedAt?, duration?, // 접속 시간 start/endActivityIndex, start/endStepIndex, // 진행 위치 스냅샷 disconnectReason? // socket-disconnect | auto-closed-on-new-session | test-inject }
| 메서드 | 동작 |
|---|---|
createSession | 새 접속 레코드 생성. 먼저 미종료(pending) 세션을 endPendingSessions로 정리(중복 라이브 방지) 후 생성 |
endSession | exitedAt 기록 + duration 계산·totalDuration 누적 |
endPendingSessions | 미종료 세션 일괄 종료(backstop). disconnect/재접속 시 호출(#2 connection-handlers) |
getSessions/getSession | 조회 |
endSession이 단독 담당. createSession의 auto-close나 disconnect backstop이 중복 종료하면 이중 가산 위험(→ 누적시간 이중 가산 분석). disconnect 시각 기준으로 clamp.endPendingSessions(disconnectReason="socket-disconnect") 예약. grace 내 재접속이면 취소하되 이전 세션은 disconnect 시각으로 종료(idle gap 누적 방지, PPI-900).LESSON_SESSION_EXPIRED → 클라이언트가 새 세션 생성.{lessonIndex}#{enteredAt}라 같은 수업 재접속마다 새 SK. 조회/집계 시 lessonIndex prefix로 묶어야 함.| 파일 | 역할 |
|---|---|
| app/main/meet/[roomId]/page.tsx | 호스트 수업 진행 페이지 |
| socketSfu.ts | SFU 소켓·targetInstance·재연결 |
| hooks/use-host-entry-socket.ts | 입장 요청 수신·리소스 프리캐싱·승인 |
| lib/api/services/lesson-session.service.ts | LessonSession create/end/endPending |
| types/db/lesson-session.types.ts | LessonSession 모델 |
| api/lessons/[userId]/[index]/{can-enter,sessions}/route.ts | 입장 검증·세션 API |