Skip to content
Go back

Haechi v0.2.3 — Data Persistence Fix, Server Search, Small Improvements

Published:  at  09:00 AM
This post was automatically translated from Korean using AI (source updated 2026-04-02). Read the original →

After introducing authentication and the server database in v0.2.0, three releases followed — fixing issues discovered through actual use and adding missing functionality.

A small release. The app had no footer.

Footer. Shows grammar point count, copyright, and a version badge linking to the changelog page. Click the version to see the full history.

Changelog page. Renders CHANGELOG.md at /changelog. A public page, no login required.

Larger review card text. Improved answer readability on the card backside.

v0.2.2 — Server-Side Search and Pagination

The grammar search added in v0.1.1 worked by sending all data to the client and filtering there. It wouldn’t scale as the grammar collection grows.

Server-side search. Type a query, results filter after a 300ms debounce. Searches both title and definition on the server.

Level filters always visible. Previously hidden unless there were 5+ entries. Now always shown. Quick filtering by beginner, intermediate, or advanced.

Pagination. 20 entries per page with prev/next controls.

API endpoint. New endpoint at /api/grammar/list accepting search, level filter, and pagination query params. Returns 400 on invalid input.

URL state preservation. Search term, filter, and page number are reflected in the URL. Bookmark a filtered view, share it, reload — it persists.

SSR to client hydration. The first page renders server-side for SEO, then the client takes over after hydration.

v0.2.3 — Data Persistence Fix

This is the important one. The server database was introduced in v0.2.0, but data wasn’t actually reaching the server.

The Cause

better-auth sets its session cookie as HttpOnly by default. HttpOnly cookies are invisible to JavaScript. The client-side DataProvider selection logic looked for the session cookie in document.cookie — and never found it. Every logged-in user was silently using LocalDataProvider (IndexedDB). Nothing was saved to the server.

The Fix

Auth state detection moved server-side. Astro middleware checks the session cookie (which it can read, since middleware runs on the server), and injects a window.__AUTH__ object for authenticated users. The client reads this object to select SyncingDataProvider.

Other Fixes

Dexie upgrade error handling. Existing users with the v1 IndexedDB schema got “Not yet support for changing primary key” on upgrade. IndexedDB is just an offline cache, so the database now auto-recreates on upgrade failure.

Card IDs include userId. Previously, card IDs were generated from the grammar slug alone. Multiple users studying the same grammar would have colliding card IDs and share FSRS state. Each user now gets independent cards.

Instant feedback. Rating a card advances to the next one immediately. The server call runs in the background. Previously there was a 1.6-second wait between cards. The Study button also switches to “Studying” instantly, with card generation (previously 5.5 seconds) running in the background.

4x faster card generation. Batch INSERT sends all cards in one database call instead of one per card.

API failure logging. Card generation and review submission now log console warnings when the server call fails. Previously they fell back to local storage silently.

Lessons

The HttpOnly cookie issue is easy to miss when integrating an auth system. better-auth defaulting to HttpOnly is correct for security, but it conflicts with client code that branches on cookie presence. Injecting auth state from the server was the right pattern.

Assuming “it works” without verifying data actually reached the server was the mistake. SyncingDataProvider’s silent fallback to LocalDataProvider masked the problem. The console warnings added in this release should surface this kind of failure faster in the future.


Share this post on:

Previous Post
Push Day (PPL W6D4)
Next Post
Lower Body (PPL W6D3)