본문으로 이동
뒤로 가기

Haechi v0.2.3 — 데이터 영속성 수정, 서버 검색, 소소한 개선

작성일:  at  09:00 AM

v0.2.0에서 인증과 서버 데이터베이스를 도입한 후, 실제로 사용하면서 발견된 문제들을 수정하고 기능을 보강한 세 번의 릴리스가 있었다.

v0.2.1 — 푸터와 체인지로그

작은 릴리스. 앱에 푸터가 없었다.

푸터. 문법 항목 수, 저작권, 체인지로그 페이지로 연결되는 버전 배지를 표시한다. 버전을 클릭하면 지금까지의 변경 내역을 볼 수 있다.

체인지로그 페이지. /changelog 경로에서 CHANGELOG.md를 렌더링한다. 로그인 없이 누구나 볼 수 있는 공개 페이지.

복습 카드 텍스트 확대. 카드 뒷면의 답안 가독성을 높였다.

v0.2.2 — 서버 사이드 검색과 페이지네이션

v0.1.1에서 추가한 문법 검색은 클라이언트 측에서 전체 데이터를 받아 필터링하는 방식이었다. 문법 항목이 늘어나면 확장되지 않는 구조였다.

서버 사이드 검색. 검색어를 입력하면 300ms 디바운스 후 서버에서 필터링된 결과를 반환한다. 제목과 정의 모두 검색 가능.

레벨 필터 상시 노출. 이전에는 항목이 5개 이상일 때만 보였는데, 이제 항상 표시된다. 초급/중급/고급 필터로 빠르게 좁힐 수 있다.

페이지네이션. 페이지당 20개 항목으로 나눈다. 이전/다음 컨트롤이 추가되었다.

API 엔드포인트. /api/grammar/list에 검색, 레벨 필터, 페이지네이션 쿼리 파라미터를 받는 새 엔드포인트를 만들었다. 잘못된 파라미터에는 400 에러를 반환한다.

URL 상태 보존. 검색어, 필터, 페이지 번호가 URL에 반영된다. 필터링된 뷰를 북마크하거나 공유하고, 새로고침해도 유지된다.

SSR → 클라이언트 하이드레이션. 첫 페이지는 서버에서 렌더링해 SEO를 확보하고, 하이드레이션 이후 클라이언트가 이어받는다.

v0.2.3 — 데이터 영속성 수정

이번 릴리스의 핵심이다. 서버 데이터베이스를 도입했는데 실제로 데이터가 서버에 저장되지 않고 있었다.

원인

better-auth의 세션 쿠키가 HttpOnly로 설정되어 있었다. HttpOnly 쿠키는 JavaScript에서 읽을 수 없다. 클라이언트의 DataProvider 선택 로직이 document.cookie에서 세션 쿠키를 찾았는데, 당연히 찾을 수 없었다. 결과적으로 로그인한 사용자도 항상 LocalDataProvider(IndexedDB)를 사용하게 되었다. 서버에는 아무것도 저장되지 않았다.

해결

서버 사이드에서 인증 상태를 감지하도록 변경했다. Astro 미들웨어가 세션 쿠키를 확인하고, 인증된 사용자에게는 window.__AUTH__ 객체를 주입한다. 클라이언트는 이 객체를 읽어서 SyncingDataProvider를 선택한다.

기타 수정

Dexie 업그레이드 에러 처리. v1 IndexedDB 스키마를 가진 기존 사용자가 업그레이드할 때 “Not yet support for changing primary key” 에러가 발생했다. IndexedDB는 오프라인 캐시에 불과하므로, 업그레이드 실패 시 데이터베이스를 자동 재생성하도록 변경했다.

카드 ID에 userId 포함. 이전에는 문법 슬러그만으로 카드 ID를 생성했다. 여러 사용자가 같은 문법을 공부하면 카드 ID가 충돌했다. 이제 userId를 포함해서 각 사용자가 독립적인 FSRS 상태를 갖는다.

즉각적인 피드백. 카드를 평가하면 다음 카드로 즉시 넘어간다. 서버 호출은 백그라운드에서 실행한다. 이전에는 카드 간 1.6초 대기가 있었다. Study 버튼도 누르면 바로 “Studying”으로 전환되고, 카드 생성(이전 5.5초)은 백그라운드에서 처리한다.

카드 생성 4배 빠르게. 카드별 개별 INSERT 대신 배치 INSERT로 한 번의 데이터베이스 호출로 전체 카드를 삽입한다.

API 실패 로깅. 카드 생성과 리뷰 제출이 서버에 실패할 때 콘솔에 경고를 남긴다. 이전에는 조용히 로컬 저장소로 폴백했다.

교훈

HttpOnly 쿠키 문제는 인증 시스템을 통합할 때 놓치기 쉬운 부분이다. better-auth가 보안을 위해 HttpOnly를 기본으로 설정하는 것은 올바르지만, 클라이언트 코드가 쿠키를 읽어서 분기하는 패턴과는 충돌한다. 서버 사이드에서 인증 상태를 주입하는 것이 맞는 패턴이었다.

데이터가 실제로 서버에 도달하는지 확인하지 않고 “동작한다”고 판단한 것은 실수였다. SyncingDataProvider가 LocalDataProvider로 조용히 폴백하는 설계가 문제를 감추었다. 이번에 추가한 콘솔 경고가 앞으로는 이런 문제를 더 빨리 드러낼 것이다.


이 글 공유하기:

이전 글
밀기 (PPL W6D4)
다음 글
하체 (PPL W6D3)