운영 저널
QR 파일 전송 세션은 왜 실패하는가
QR은 연결 정보를 전달할 뿐입니다. 스캔 뒤에는 API 요청, 역할별 trust, Socket.IO 참가, 브라우저 생명주기가 이어지므로 화면에 보이는 실패 지점과 실제 원인은 다를 수 있습니다.
근거 범위 웹 클라이언트의 세션·소켓·페이지 생명주기 코드, 서버 join 처리, 통합 테스트
Vibe Share의 QR에는 파일 바이트가 들어 있지 않습니다. 휴대폰 브라우저가 /j/6자리코드 경로를 열도록 안내하고, 그 코드로 API에 join한 뒤 같은 Socket.IO room에 들어가게 합니다. 따라서 QR이 선명하게 스캔되었다는 사실은 카메라 단계만 통과했다는 뜻입니다.
실제 구현에서 PC는 먼저 POST /api/sessions로 세션을 만들고 QR과 수동 코드를 표시합니다. 휴대폰은 POST /api/sessions/join으로 세션을 찾고 mobile 역할의 trust 정보를 받은 뒤 소켓에 참가합니다. 어느 한 단계라도 오래된 호스트, 만료된 코드, 중단된 API를 바라보면 같은 ‘연결 안 됨’처럼 보일 수 있습니다.
실제 진단 순서
- API가 응답하는지 봅니다.PC 페이지가 열린다는 이유로 API를 건너뛰지 않습니다.
/health가 실패하면 QR을 새로 만들어도 세션은 생성되지 않습니다. - PC가 새 세션을 실제로 받았는지 봅니다.6자리 코드와 만료 시간이 새로 표시되는지, 브라우저 Network에서
/api/sessions가 성공했는지 확인합니다. QR 렌더링 오류와 세션 생성 오류를 여기서 나눕니다. - 휴대폰 주소를 확인합니다.공개 환경은
app.getvibeshare.com/j/코드와 공개 API를 사용해야 합니다. 휴대폰의localhost는 PC가 아니라 휴대폰 자신이므로 로컬 개발 주소가 섞이면 join할 수 없습니다. - Socket.IO 참가를 확인합니다.클라이언트는
websocket과polling을 모두 허용합니다. 연결 자체와session:join승인 응답은 별개이므로 소켓이 열렸다는 사실만으로 paired 상태를 판단하지 않습니다. - 페이지가 백그라운드로 내려갔는지 봅니다.모바일 브라우저는
visibilitychange,pagehide,pageshow사이에 연결을 정리할 수 있습니다. 돌아왔을 때 저장된 세션이 아직 유효한지 재검증합니다. - 오래된 상태를 구분해 재현합니다.자동 join이 15초 이상 멈추면 클라이언트는 진행 중 표시와 타이머를 stale 상태로 보고 같은 코드의 재시도를 허용합니다. 세션 자체가 만료되었거나 코드가 일치하지 않을 때만 PC에서 새 세션과 QR을 만들고 작은 파일로 다시 확인합니다.
What we observed — 우리가 관찰한 것
모바일 연결 실패는 한 가지 오류가 아닙니다. API 자체가 없는 경우, 세션은 만들어졌지만 QR route가 잘못된 host를 가리키는 경우, join은 성공했지만 Socket.IO 참가가 끊긴 경우, 브라우저가 복귀하면서 이전 상태를 복원한 경우가 UI에서는 모두 비슷한 ‘연결 실패’로 보일 수 있습니다.
또한 transport 이름 하나만으로 pairing 성공 여부를 판단할 수 없습니다. 현재 클라이언트는 websocket을 우선하고 polling도 허용하지만, 실제로 선택된 transport와 별개로 session:join 승인과 두 역할의 paired 상태를 확인해야 합니다.
What we changed — 우리가 바꾼 것
공개 도메인에서는 모바일에 노출되는 URL에 localhost, loopback, 비어 있는 host가 섞이지 않도록 정규화했습니다. QR route를 열 때 오래된 mobile 세션을 그대로 재사용하지 않고 현재 6자리 코드를 우선하며, 자동 join에는 단계와 마지막 오류를 기록합니다.
브라우저 생명주기 이벤트를 받아 숨김·복귀 상태를 구분하고, 돌아온 페이지에서는 route와 세션 만료를 다시 확인합니다. 소켓은 websocket과 polling을 함께 허용하고, join 요청은 제한 시간 안에 승인 응답을 받지 못하면 사용자에게 재연결 경로를 보여 줍니다.
What remains limited — 아직 제한되는 것
모바일 운영체제가 브라우저 탭을 강제로 중단하는 동작을 웹 코드가 막을 수는 없습니다. 큰 파일을 전송하는 동안 다른 앱으로 오래 이동하면 업로드나 다운로드가 중단될 수 있습니다. 최근 업로드 manifest를 이용한 일부 재개 경로는 있지만, 모든 브라우저와 모든 relay 전송의 무중단 복구를 약속하지 않습니다.
세션 기본 만료는 저장소 설정상 30분이지만 운영 환경에서 값이 달라질 수 있습니다. 만료된 세션은 복원 대상이 아니라 새 QR을 만들어야 하는 상태입니다. 브라우저에 보이는 이전 6자리 코드는 영구적인 기기 pairing 코드가 아닙니다.