feat: 중단된 면접 이어하기 (B-5) - #180
Merged
Merged
Conversation
`PATCH /api/sessions/{id}/resume` — INTERRUPTED 세션을 다시 진행 가능한 상태로 되돌린다.
완료·취소 세션은 이어할 수 없다(422). 새로 하려면 기존 `/retry` 를 쓴다.
## 핵심은 상태 전이가 아니라 끊긴 턴 복구다
중단은 보통 **턴 한가운데**에서 일어난다(탭 종료·네트워크 끊김·수동 중단). 그동안 도착한
콜백은 terminal 가드가 전부 드롭했으므로, 상태만 IN_PROGRESS 로 되돌리면 사용자는
답할 질문이 없거나 "(생성 중)" 에 멈춘 화면을 본다.
`SessionResumeService.recoverTurn` 이 마지막 메시지로 분기한다:
| 마지막 메시지 | 조치 |
|---|---|
| 정상 질문 | 없음 — 그 질문에 답하면 된다 |
| "(생성 중)" placeholder | `failFollowup` + 다음 일반질문 (그 꼬리질문은 영영 안 온다) |
| 자기소개 답변 + 풀 0건 | `SelfIntroAnsweredEvent` 재발행 (풀 생성 요청이 유실된 것) |
| 그 외 답변 | 다음 일반질문 |
자기소개 분기가 중요하다. 풀이 없는데 `advanceToNextGeneral` 로 넘기면 POOL_EXHAUSTED 로
세션이 그대로 끝나버린다.
## 시간 한도
`max_duration_minutes` 를 `started_at` 기준으로 재고 있어서, 한참 뒤에 재개하면 스위퍼가
즉시 다시 중단시킨다. V27 로 `resumed_at` 을 추가하고 스위퍼가
`durationAnchor()`(= resumedAt ?? startedAt) 기준으로 재도록 했다 — 이어하기마다 그 자리의
시간이 새로 시작된다. `started_at` 은 '처음 시작한 시각'으로 보존된다(히스토리 표시).
이어하기를 반복하면 총 시간이 늘어난다. 연습 도구라 제한하지 않았다.
## 전이
`resumeIfInterrupted` 조건부 UPDATE 로 전이를 차지하고 `ended_at` 을 지운다. 다른 전이
(start/cancel/finish)와 같은 패턴이라 중복 요청 중 하나만 1을 받는다.
## 테스트
`SessionResumeServiceTest` 신설 (8) — 완료 세션 거부, 타인 세션 거부, 전이 경합,
그리고 복구 분기 5종(정상 질문 무개입, placeholder 실패 처리, 답변 후 다음 질문,
자기소개+풀 없음 → 재요청, 자기소개+풀 있음 → 다음 질문).
- 종료 패널: 중단 세션에 '이어서 진행하기' 를 primary 로. 하던 대화가 그대로 남아 있으니 새로 만드는 것보다 이어가는 게 먼저다. '같은 설정으로 다시' 는 secondary 로 내렸다 - 히스토리 카드: 중단 세션 CTA 를 '기록 보기 →' 에서 '이어하기 →' 로 - `useResumeSession` — 서버가 끊긴 턴까지 복구하므로(다음 질문 발행 등) 세션과 메시지를 모두 무효화해야 화면이 살아난다 테스트: `SessionEndedPanel.test.tsx` +2(중단 세션의 이어하기 호출, 완료 세션엔 미노출), `SessionCard.test.tsx` CTA 문구 갱신. vitest 113/113 · eslint 0 · tsc · build 통과.
This was referenced Aug 19, 2026
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment
Add this suggestion to a batch that can be applied as a single commit.This suggestion is invalid because no changes were made to the code.Suggestions cannot be applied while the pull request is closed.Suggestions cannot be applied while viewing a subset of changes.Only one suggestion per line can be applied in a batch.Add this suggestion to a batch that can be applied as a single commit.Applying suggestions on deleted lines is not supported.You must change the existing code in this line in order to create a valid suggestion.Outdated suggestions cannot be applied.This suggestion has been applied or marked resolved.Suggestions cannot be applied from pending reviews.Suggestions cannot be applied on multi-line comments.Suggestions cannot be applied while the pull request is queued to merge.Suggestion cannot be applied right now. Please check back later.
변경 사항
감사 백로그 B-5. 마지막 남은 항목이다.
PATCH /api/sessions/{id}/resume로 INTERRUPTED 세션을 다시 진행 가능한 상태로 되돌린다.완료·취소 세션은 이어할 수 없다(422). 완료는 피드백이 이미 나갔고, 취소는 시작한 적이 없다 — 둘 다 기존
/retry로 새 세션을 만드는 게 맞다.핵심은 상태 전이가 아니라 끊긴 턴 복구다
INTERRUPTED → IN_PROGRESS만 열면 되는 줄 알았는데 아니었다. 중단은 보통 턴 한가운데에서 일어나고(탭 종료·네트워크 끊김·수동 중단), 그동안 도착한 콜백은isTerminal()가드가 전부 드롭했다. 상태만 되돌리면 사용자는 답할 질문이 없거나 "(생성 중)" 에 멈춘 화면을 본다.SessionResumeService.recoverTurn이 마지막 메시지로 분기한다:"(생성 중)"placeholderfailFollowup+ 다음 일반질문SelfIntroAnsweredEvent재발행POOL_EXHAUSTED로 세션이 그대로 끝남자기소개 분기가 특히 중요하다. 자기소개만 답하고 끊긴 경우 질문 풀 생성 요청이 유실됐을 수 있는데, 이때
advanceToNextGeneral로 넘기면 풀이 비어 있어 세션이 즉시 종료된다.시간 한도 —
resumed_at(V27)max_duration_minutes를started_at기준으로 재고 있어서, 한참 뒤에 재개하면 스위퍼가 즉시 다시 중단시킨다. 어제 중단한 면접을 오늘 이어가면 재개하자마자 끝난다.resumed_at을 추가하고 스위퍼가durationAnchor()(=resumedAt ?? startedAt) 기준으로 재도록 했다. 이어하기마다 그 자리(sitting)의 시간이 새로 시작되고,started_at은 '처음 시작한 시각'으로 보존된다(히스토리 표시용).트레이드오프: 이어하기를 반복하면 총 시간이 늘어난다. 대안은 누적 활동시간 추적(컬럼 추가 + 모든 종료 경로에서 갱신)인데, 연습 도구에서 총 시간을 엄격히 제한할 이유가 약해서 단순한 쪽을 골랐다. 필요하면 나중에 바꿀 수 있다.
전이
resumeIfInterrupted조건부 UPDATE 로 전이를 차지하고ended_at을 지운다. 다른 전이(startIfReady/cancelIfReady/finishIfInProgress)와 같은 패턴이라 중복 요청(더블클릭·재전송) 중 하나만 1을 받는다.프론트
테스트
SessionResumeServiceTest신설 (8) — 완료 세션 거부, 타인 세션 거부, 전이 경합, 복구 분기 5종(정상 질문 무개입 / placeholder 실패 처리 / 답변 후 다음 질문 / 자기소개+풀 없음 → 재요청 / 자기소개+풀 있음 → 다음 질문)SessionEndedPanel.test.tsx+2 — 중단 세션의 이어하기 호출, 완료 세션엔 미노출SessionCard.test.tsx— CTA 문구 갱신backend
test통과(ArchUnit 포함) · frontend vitest 113/113 · eslint 0 · tsc · build.영향 범위
resumed_at컬럼 추가만. 기존 행은 NULL = 기존과 동일 동작)PATCH /api/sessions/{id}/resume)started_at→COALESCE(resumed_at, started_at). 재개한 적 없는 세션은 그대로다리뷰어 체크포인트
INTERRUPTED가isTerminal()에 남아 있다 — 재개하면 IN_PROGRESS 라 가드를 정상 통과하므로 그대로 뒀다. 중단 상태에서 늦게 오는 콜백은 여전히 드롭되는 게 맞다