fix: 중단된 면접의 문답을 다시 볼 수 없던 문제 + 답변 시퀀스 경합 - #175
Merged
Conversation
## A-5 — 중단 세션에 진입 경로 자체가 없었다 히스토리 카드(`SessionCard`)가 **COMPLETED 일 때만** `<Link>` 였다. 중단된 면접은 눌리지도 않고, 피드백은 애초에 생성되지 않으므로(INTERRUPTED 는 `SessionEndedEvent` 미발행) 사용자가 말한 내용에 도달할 방법이 하나도 없었다. 진행 중이던 면접도 마찬가지로 눌리지 않아서, 탭을 닫거나 다른 화면으로 나가면 **돌아갈 길이 없었다**. - `SessionCard` — 상태별 목적지를 표로 정리: COMPLETED→피드백, INTERRUPTED→세션 화면(기록), IN_PROGRESS→세션 화면(이어서), READY→로비. CANCELLED 는 시작 전 취소라 볼 게 없어 그대로 둔다 - `SessionEndedPanel` — COMPLETED·INTERRUPTED 면 `InterviewTranscript` 를 함께 렌더. 이 컴포넌트는 이미 있었고 피드백 화면에서만 쓰이고 있었다(= 피드백이 있어야만 볼 수 있었다) `InterviewTranscript` 는 자체적으로 `useSessionMessages(sessionId)` 를 켜므로, `useLiveInterview` 가 종료 세션에서 메시지 조회를 끄고 있어도 기록은 정상적으로 뜬다. ## A-6 — 동시 제출이 500 으로 나가던 문제 `submitAnswer`/`createVoicePlaceholder` 가 `latest.getSequenceNumber() + 1` 로 seq 를 계산한다. 같은 턴에 두 요청이 동시에 들어오면 둘 다 같은 값을 잡고, `(session_id, sequence_number)` UNIQUE 가 한쪽을 막아 정체불명의 500 이 됐다. 실제 의미는 '이 턴은 이미 답변됐다' 이므로 그렇게 알린다 — `saveAndFlush` 로 INSERT 를 메서드 안에서 터뜨리고 `DataIntegrityViolationException` 을 `SESSION_INVALID_STATE`(422)로 변환. 제약 자체가 최종 방어선이라 사전 체크로 대체하지 않았다. ## 테스트 - `SessionCard.test.tsx` 신설 (5) — 상태별 목적지 + 취소 세션은 링크 없음 - `InterviewMessageServiceTest` / `VoiceAnswerUploadServiceTest` 에 시퀀스 충돌 → 422 변환 케이스 추가. 기존 스텁은 `save`→`saveAndFlush` 로 정정 (꼬리질문 placeholder 경로는 `save` 그대로다 — `MessageSequenceAssignmentTest` 무변경) backend `test` 통과, frontend vitest 81/81 · eslint 0 · tsc 통과.
This was referenced Aug 18, 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.
변경 사항
감사 백로그 A-5, A-6.
A-5 — 중단 세션에 진입 경로 자체가 없었다
보고했던 것보다 나쁜 상태였다.
SessionCard가 COMPLETED 일 때만<Link>였다:중단된 면접은 히스토리에서 눌리지도 않고, 피드백은 애초에 생성되지 않는다(INTERRUPTED 는
SessionEndedEvent미발행). 즉 사용자가 말한 내용에 도달할 방법이 하나도 없었다. URL 을 직접 쳐서/sessions/:id로 가도SessionEndedPanel이 "면접이 중단되었습니다" 한 줄만 보여주고,/sessions/:id/feedback은 폴링 40회(약 2분)를 다 쓴 뒤 INTERRUPTED 세션에는 통하지도 않는 "피드백 다시 생성" 버튼을 내민다.진행 중이던 면접도 같은 이유로 눌리지 않아서, 탭을 닫거나 다른 화면으로 나가면 돌아갈 길이 없었다.
SessionEndedPanel은 COMPLETED·INTERRUPTED 에서InterviewTranscript를 함께 렌더한다. 이 컴포넌트는 이미 있었고 피드백 화면에서만 쓰이고 있었다 — 즉 피드백이 있어야만 볼 수 있는 상태였다.InterviewTranscript가 자체적으로useSessionMessages(sessionId)를 켜므로,useLiveInterview가 종료 세션에서 메시지 조회를 끄고 있어도 기록은 정상적으로 뜬다.A-6 — 동시 제출이 500 으로 나가던 문제
submitAnswer/createVoicePlaceholder가latest.getSequenceNumber() + 1로 seq 를 계산한다. 같은 턴에 두 요청이 동시에 들어오면 둘 다 같은 값을 잡고,(session_id, sequence_number)UNIQUE 가 한쪽을 막아 정체불명의 500 이 됐다.실제 의미는 '이 턴은 이미 답변됐다' 이므로 그렇게 알린다 —
saveAndFlush로 INSERT 를 메서드 안에서 터뜨리고(커밋까지 미루면 트랜잭션 밖에서 500 으로 샌다)DataIntegrityViolationException을SESSION_INVALID_STATE(422)로 변환했다.사전 조회로 대체하지 않은 이유: 사전 체크도 같은 경합에 노출된다. UNIQUE 제약이 최종 방어선이고, 여기서는 그 결과를 사용자에게 정확한 의미로 옮기는 것만 한다.
테스트
SessionCard.test.tsx신설 (5) — 상태별 목적지 4종 + 취소 세션은 링크 없음InterviewMessageServiceTest·VoiceAnswerUploadServiceTest에 시퀀스 충돌 → 422 변환 케이스 추가save→saveAndFlush정정. 꼬리질문 placeholder 경로는save그대로라MessageSequenceAssignmentTest는 건드리지 않았다backend
test통과 (ArchUnit 포함), frontend vitest 81/81 · eslint 0 · tsc 통과.영향 범위
리뷰어 체크포인트