글방 대개편 — Firebase Storage 버리고 Firestore 청크로 갈아탔다
배경
글방은 개인용 소설 리더다. 텍스트 파일을 업로드하면 책처럼 읽을 수 있게 해주는 앱인데, 업로드가 자꾸 터졌다. Firebase Storage를 쓰고 있었는데 권한 오류, CORS, 30MB 제한까지 겹치면서 결국 구조 자체를 바꾸기로 했다.
Firebase Storage 제거 → Firestore 청크 저장
핵심 결정은 단순했다. 파일을 통째로 Storage에 올리는 대신, 텍스트를 일정 크기로 잘라서 Firestore 서브컬렉션에 청크 단위로 저장하는 방식으로 전환했다.
chunks/{chunkId} 서브컬렉션에 zero-padded ID로 정렬을 보장하고, 읽을 때는 순서대로 이어 붙인다. Storage 권한 이슈가 완전히 사라졌다.
청크를 쓰는 방식도 한 번 바꿨다. 처음엔 Promise.all로 병렬로 올렸는데 Firestore write stream 한도를 초과해서 실패했다. writeBatch로 묶어봤더니 이번엔 batch 크기 제한에 걸렸다. 결국 5개씩 묶어서 병렬 처리하는 방식(청크 5개씩 배치)으로 낙착됐다. 순차 대비 약 5배 빠른 업로드 속도가 나왔다.
업로드 UX 전면 개선
업로드 피드백이 없으면 사용자는 버튼을 계속 누른다. 기존에 alert/confirm으로 하던 걸 전부 Toast와 인라인 UI로 교체했다.
- 업로드 단계별 상태 카드 (파일 파싱 → 청크 생성 → DB 저장 → 완료)
- 에러 코드별 한국어 메시지
- 삭제 확인도 브라우저 confirm 대신 카드 인라인 UI로
레이스 컨디션도 있었다. 청크 저장이 끝나기 전에 완료로 표시되는 케이스가 있었는데, chunksReady 플래그를 따로 두고 모든 청크 쓰기가 완료된 뒤에야 완료 상태로 전환하도록 수정했다.
서재 UX 개선 및 기능 추가
파일 저장 방식을 바꾸는 김에 UI도 대거 손봤다.
- 커버 이니셜 카드: 커버 이미지가 없어도 제목 이니셜로 시각적 식별 가능
- 정렬 드롭다운: 최신순 / 제목순
- 검색바: 서재 내 소설 제목 검색
- 스켈레톤 개선: 첫 방문 시 스켈레톤이 5초간 뜨다 사라지는 현상 수정. 로딩 타임아웃을 줄이고 Firestore 오프라인 캐시를 비활성화해 즉시 정상 화면이 표시되도록 개선
뷰어에는 줄간격과 좌우 여백 설정이 추가됐다. 스크롤 복원도 progressRatio 기반으로 바꿔서 어떤 화면 크기에서도 읽던 위치가 정확하게 복원된다.
소설 내 검색 + 북마크 + PWA 오프라인
마지막으로 기능 세 개를 한 번에 붙였다.
- 소설 내 검색: 현재 챕터 전체에서 키워드 검색, 매칭 위치로 스크롤
- 북마크: 현재 위치 저장/복원
- PWA 오프라인 지원: Service Worker 등록, 이전에 읽었던 소설은 오프라인에서도 접근 가능
PWA 추가 후에 Auth 무한 로딩이 생겼다. Service Worker가 Firebase Auth 내부 요청을 가로채서 캐시를 반환하는 간섭 문제였다. Auth 관련 URL 패턴을 SW 캐시 대상에서 제외하는 방식으로 해결했다.
인프라 (CI)
Firestore rules를 CI에서 배포하려고 했는데 서비스 계정에 권한이 없었다. rules 배포 단계를 CI에서 제거하고, Hosting만 CI에서 배포하는 방식으로 정리했다.