Skip to content
Alvaro Sarria
Menu
← All work

Wordsmith Retreat

A personal book shelf that merges the read-only Open Library catalogue with your own Supabase-backed books and bookmarks into one list.

Problem

Personal book collections are easy to lose track of — what you own, what you’ve read, what’s worth re-reading. I wanted a proper catalog, not another spreadsheet.

Approach

The app reads from two sources at once and merges them onto a single shelf: Open Library supplies weekly trending books and title search across the public catalogue but is read-only, while Supabase holds the books you create and the books you bookmark. Your own books are listed first, then catalogue results. If one source is down the shelf still renders the other and says so.

Architecture

  • Client: React 19 + Vite. Each route-level page owns its own fetching and page state; components below are driven entirely by props
  • Data layer: a utils/ layer that talks to Supabase and Open Library and normalizes both into one book shape, so nothing downstream has to know which source a book came from
  • Database: Supabase Postgres with two tables — books for what you create, favorites for the bookmark shelf — and row level security policies, without which every insert fails and the UI silently does nothing
  • Styling: design tokens in styles/tokens.css; no hard-coded colours, spacing or type anywhere else

Key decisions

  • favorites is a separate table that snapshots the book rather than a flag on books, so the bookmarks page renders in one query instead of one Open Library request per bookmark. A CHECK constraint enforces that each row points at exactly one source — an Open Library work key or a local book
  • Open Library rate-limits browser clients to roughly one request per second (the higher tier needs a custom User-Agent, which browsers don’t allow), so searches are debounced and superseded requests are aborted
  • Book records are fetched rather than typed in, so adding a catalogue book is a search, not a form

Results

A working shelf with full CRUD over your own books, bookmarking across both sources, a details modal that fetches the full synopsis on demand, inline validation and duplicate detection when adding a book, light and dark themes, and distinct loading, empty, error and partial-outage states throughout.

What I’d do differently

The app has no login: its publishable key ships in the browser bundle and the row level security policies grant that key full access, which is fine for a demo and wrong for real user data — adding Supabase Auth and scoping the policies to auth.uid() is the fix. I’d also reconcile the bookmark snapshots, since editing one of your own books currently leaves an existing bookmark showing the old record, and add a test suite: right now npm run lint && npm run build is the whole definition of “not broken”.