운영 저널
실제 사용 실패 뒤에 바꾼 것
사용자가 보는 한 문장—‘PC는 열리는데 휴대폰은 안 된다’—뒤에는 여러 경계가 있었습니다. 증상, 코드 변경, 아직 남은 위험을 commit 단위로 연결했습니다.
근거 범위 운영자 장애 기록과 public-domain, R2, metadata, canonical 관련 commit history
Vibe Share는 처음부터 한 번에 안정된 서비스가 아니었습니다. PC 정적 화면, mobile join route, API, Socket.IO, Postgres, Redis, R2, 커스텀 도메인이 따로 움직입니다. 그래서 한 부분의 성공이 전체 성공처럼 보이는 실패가 반복되었습니다.
이 글은 가상의 사용자 후기나 전송 횟수를 만들지 않습니다. 운영자가 남긴 증상과 저장소에서 실제로 바뀐 파일을 기준으로, 무엇을 관찰했고 무엇을 수정했는지 순서대로 적습니다.
문제와 변경의 연대기
- mobile은 연결되지 않는데 desktop 화면은 열렸습니다.공개 web host와 API host가 분리되어 있음을 장애 화면에서 다시 확인했습니다. d14ed26에서 public runtime URL 선택, QR route, 서버가 제공하는 mobile-facing URL 처리를 강화했습니다.
- API에서
Application not found가 보였습니다.Railway 체험 종료 뒤 서비스가 오프라인이 된 운영 기록을 따라 Postgres·Redis·API와 custom domain을 순서대로 복구했습니다. 이 사건은 UI 배포 성공을 API 정상의 증거로 쓰지 않게 만든 계기였습니다. - R2 서명과 브라우저 업로드 경계가 맞지 않았습니다.f23db14에서 R2 endpoint 형식, signature 처리, 브라우저 resumable 흐름과 CORS 관련 검증을 보강했습니다. R2 custom domain을 S3 API endpoint처럼 사용하지 않는 규칙을 문서에 남겼습니다.
- upload 시작과 metadata 저장 순서가 일관되지 않았습니다.cc0f80d에서 transfer와 upload-session metadata를 먼저 transaction으로 저장한 뒤 in-memory 상태에 노출하고, 저장 실패 시 provider multipart upload를 abort하도록 바꿨습니다. 빠른 응답보다 복구 가능한 시작 상태를 우선한 결정입니다.
- canonical 보고와 실제 redirect가 달랐습니다.395f36e에서 slashless canonical, www, sitemap URL의 첫 응답을 테스트하도록 smoke를 강화했습니다. 보고서가 아니라 public edge 응답을 기준으로 정책을 정했습니다.
What we observed — 우리가 관찰한 것
사용자 증상은 아키텍처 용어를 포함하지 않습니다. ‘QR이 안 돼요’는 API가 죽은 상황일 수도 있고, mobile route가 localhost를 가진 상황일 수도 있고, 이전 세션을 Safari가 복원한 상황일 수도 있습니다. 오류 문구만 분류하는 대신 공개 URL과 데이터 경계를 위에서 아래로 확인해야 했습니다.
canonical 문제도 브라우저가 최종 페이지를 열어 준다는 이유로 놓치기 쉬웠습니다. 두 번 redirect되어도 사용자 눈에는 같은 페이지지만, sitemap·canonical·내부 링크가 서로 다른 주소를 가리키면 crawler에게는 관리되지 않는 사이트처럼 보일 수 있습니다.
What we changed — 우리가 바꾼 것
클라이언트가 임의의 이전 URL을 재사용하지 않도록 public host와 QR route의 우선순위를 정했습니다. Socket.IO client는 websocket을 우선하고 polling도 허용하며, page hide/show 뒤 현재 route와 session을 재검증합니다. resumable upload 시작은 transfer와 upload-session metadata 저장이 성공한 뒤 in-memory 상태에 노출되도록 경계를 명확히 했습니다.
공식 사이트는 apex·slashless 정책을 코드와 smoke에 함께 적었습니다. sitemap에 넣은 URL은 첫 응답 200이어야 하고, slash와 www는 최종 canonical로 한 번만 301해야 하며, 내부 링크는 redirect를 거치지 않는다는 조건입니다.
What remains limited — 아직 제한되는 것
이 변경들은 장애 종류를 줄였지만 mobile browser가 백그라운드에서 중단되는 문제, 외부 인프라가 동시에 오프라인이 되는 문제, 모든 파일 크기와 형식의 호환성을 없애지 못합니다. 자동화된 실제 iPhone 브라우저 테스트와 다중 리전 failover도 현재 범위에 없습니다.
또한 이 사이트에는 실제 사용자의 이름이나 testimonial을 넣지 않았습니다. 다음 변경 기록은 owner가 확인 가능한 재현 절차, 날짜, 기기 환경, 안전한 화면 캡처를 제공했을 때만 추가합니다. ‘사용자가 좋아했다’ 같은 근거 없는 결론은 changelog가 아닙니다.