How I Built My Reading Companion App, And How I Went Around The Storage Layer.

How I Built My Reading Companion App, And How I Went Around The Storage Layer.

Leader ●1 ●6 ●16
calendar_today • schedule4 min read

Building tools for yourself is arguably the most effective way to level up as a software engineer. There is no product manager handing down arbitrary specs, no artificial constraints, and most importantly, no room to ignore bugs when you are the primary end user.

Recently, I shipped the working version of my book review and jotting system. What started as a personal fix for passive reading evolved into a full development sprint involving branding pivots, state management headaches, and deep dives into browser persistence.

Here is the technical breakdown of how the build came together, the naming hurdle, and the architectural issues I ran into while handling local storage and book rendering.

  1. The Core Problem: Passive Reading

Most reading workflows in tech are broken. We buy books, skim through hundreds of pages, bookmark a few passages, and two weeks later struggle to articulate a single foundational concept from the text.

Highlighters and generic note applications scatter thoughts across disconnected interfaces. I needed a focused, low-latency workspace that forced active retention—a structured workflow to capture raw notes, link chapters, synthesize main arguments, and track reading velocity without friction.

  1. The Naming Conflict: Pivoting Early

In early development, the working title for the project ran straight into a trademark and existing namespace collision. An established tool in the developer/reading productivity space was already operating under the same name.

It is easy to get emotionally attached to a project name and stall progress. But early on, engineering priorities need to override branding.

I decoupled the product identity from the codebase:

Focused 100% of the compute on getting the core MVP functional.

Rebranded cleanly once the interaction architecture stabilized.

Code functionality first. Marketing and branding second.

  1. The MVP Architecture: Why Local Storage First?

Before wiring up a remote database and authentication layer, I wanted an ultra-fast, offline-first client build to validate the reading UX immediately. I opted for local client storage to achieve zero-latency read/write operations during testing.

However, treating browser localStorage as a makeshift application database quickly revealed several classic pitfalls.

Trap 1: The Serialization and Deserialization Overhead

In a document-heavy application, notes are not just flat strings; they are structured data trees containing chapter indices, timestamps, nested quotes, and tags, because localStorage only accepts DOMString values, every update required parsing and serializing massive JSON strings.
As notes accumulated across multiple books, calling JSON.stringify(libraryState) on every keystroke in auto-saving note inputs led to noticeable UI thread stuttering.

The Fix:
I debounced the persistence logic and separated the global library state from the active note editor state. Instead of writing the entire collection on every character entry, updates were held in component state and flushed to storage only after a specified inactivity threshold:

  1. The Boss Fight: Displaying the Book and Syncing State

The most frustrating technical challenge was rendering the selected book dynamically alongside its associated notes and progress tracking without desynchronizing the view.

The Problem: Ghost Renders and Stale Data

When selecting a book from the shelf to open in the active reading workspace, the app frequently displayed stale metadata or threw runtime exceptions:

Hydration Mismatches: If the user refreshed the page while viewing a specific book ID, the reader route loaded before localStorage had re-hydrated the global state, causing empty display cards or TypeError: Cannot read properties of undefined.

Key Synchronization in Component Trees: Modifying notes inside a sub-component wasn't reflecting back in the parent book shelf overview without a manual page reload.

How I Resolved It:

  1. Resilient Lookup and Fallback Boundaries

Instead of relying on fragile index lookups (books[index]), I switched to unique hash keys (UUID) and wrapped the book viewer in strict boundary guards:

  1. Atomic Storage Updates via Custom Hooks

To solve the stale data synchronization bug across decoupled views, I centralized all storage read/write operations inside a custom hook (usePersistentStorage). This hook acts as a single source of truth, synchronizing local React state with native browser storage events. This clean abstraction eliminated direct, uncontrolled calls to localStorage across nested components and fixed the book display rendering bugs once and for all.

  1. What’s Next: Migrating to the Relational Cloud

Building and battle-testing the client MVP using local storage achieved its primary goal: it validated the user experience under heavy daily reading sessions. I finished one full book using the tool and am actively managing three more on the platform.

However, local storage is inherently limited:

It is locked to a single browser profile and device.

It caps out around 5MB.

It offers zero data durability if browser data is cleared.

The next engineering phase is migrating this data model into a scalable backend. I have opted for Supabase (PostgreSQL) to handle user authentication, relational table modeling for book-to-note foreign key relationships, and row-level security.

Key Takeaways

Don't let vanity blockers halt development: If your project name is taken, decouple your logic and keep shipping.

Treat local storage with respect: Avoid raw JSON parsing on hot render paths; debounce writes and structure your schema early.

Dogfood your software: You find the nastiest UI and state bugs only when you use your own build under realistic daily pressure.

The live version is up, stable, and actively handling notes. Now, onto the data layer.
This is the live link: https://sovari.netlify.app/

4 Comments

1 vote
0
1 vote
1
🔥 Join developers growing publicly
Share your knowledge, build in public, and grow your developer presence with a global community.

More Posts

I’m a Senior Dev and I’ve Forgotten How to Think Without a Prompt

Karol Modelski - Mar 19

TypeScript Complexity Has Finally Reached the Point of Total Absurdity

Karol Modelski - Apr 23

How I Built a React Portfolio in 7 Days That Landed ₹1.2L in Freelance Work

Dharanidharan - Feb 9

Frameworks Are Institutional Memory

Ken W. Algerverified - Sep 17

Three Design-to-Code Rules Most Developers Ignore (That Will Make You a Better Engineer)

Joemetry - Sep 26
chevron_left
1.3k Points • 23 Badges
6Posts
4Comments
10Connections
LASU CS student & Frontend Dev blending clean UI with AI workflows. Founder at BukahDev Agency & tec... Show more

Related Jobs

View all jobs →

Commenters (This Week)

10 comments
8 comments
5 comments

Contribute meaningful comments to climb the leaderboard and earn badges!