Shelvanize app icon

Native iOS & Android · In development

Shelvanize

An app that catalogs the physical books you already own and then tells you the order to put them back on the shelf. My second product, built on the first one's playbook, from the Swift and Kotlin clients down to the catalog index and the pipelines that ship them.

It's here early on purpose. The interesting part is the engineering.

What it does

Most book apps track what you've read. This one tracks what you own, and where it goes.

Get the book in

Scan the barcode, point the camera at the cover, or type it in. It comes back titled, with its author and its classification, from an index I run.

Then it says where it goes

The arrangement engine takes your collection, a shelf, and one of four schemes, and outputs the physical order to re-shelve it. Same collection, same scheme, same engine version, identical order on both platforms.

The books stay yours

No account, no sync, nothing to sign into. The collection lives on the device, and CSV and JSON export are never behind the paywall.

The calls that shaped it

Six decisions, and the reason each one went the way it did

Offline-first, and the device is the system of record

SwiftData on iOS · Room on Android

The local store owns everything the user creates, so this is not a client for a server that has to stay up. A total backend outage blocks exactly one thing, turning a never-before-seen ISBN into a titled book. The collection, the shelves, and the arrangement passes all keep working with the radio off.

I host the catalog, because the terms require it

Open Library monthly dump · PostgreSQL · Cloud Run

Open Library's terms rule out pointing a high-traffic app at their live API, so the monthly dump is ingested into an index I run instead. That is also what keeps every third-party key out of both clients. The backend exists for those two reasons and no others, which is why it can be down without mattering.

Library of Congress Classification, not the obvious one

A licensing call, not a technical one

OCLC's copyright claim on the Dewey system reaches the numbers, not just the name, and LibraryThing renamed their own version of the feature and said plainly it was for legal reasons. LCC is a US Government work with free published schedules, so it ships and the other one waits on a quoted price.

Reuse the first product's playbook deliberately

Same repo topology · same CI shape

Umbrella repo for the design docs, a separate repo per component, per-repo CI scoping and secrets, and independent release cadence. Every trap the first build paid for is written down in a register that gets read before anyone touches git, CI, or a build. Reuse with a document behind it, not a shortcut.

Cut the two features everyone asks for

Scope discipline, on evidence

The social layer is out because it cost more than it earned at the competitor it shut down, and reviving it buys a moderation and compliance bill I priced before cutting it. Price tracking is out because Amazon's affiliate policy forbids it outright, so there is no legal feed at an indie budget.

Diagnostics that cannot leak a book

Crash reporting only · no analytics

Every crash report goes through one sealed wrapper whose API accepts a closed diagnostic vocabulary, so no title, author, ISBN, shelf, or borrower string can compile into a crash key. Dependency-graph guards fail the build if a version bump drags analytics back in behind it.

What measuring caught that review did not

The suite was green. The numbers were not.

The catalog is 113,500,501 rows, made of 56,615,822 editions, 41,504,065 works, and 15,380,614 authors. The spec that planned for it said over 20 million editions, so the real corpus is nearly three times the number the design was reasoning about.

One generation of that index measures about 130 GiB against a budget of 30 to 40 GB, which moved the hosting line from an assumed $35-50 a month to $134-168 before a single user exists. The trigram index the design had flagged as the risk came in at 884 MiB on the sampled run, so the thing I was watching was fine and the thing I had assumed was 4.3x off.

That run found eight defects a green 549-test suite had not. The worst was a resolve step that bloated the largest table 6.13x across three update passes, and its first rewrite was correct and unrunnable, a correlated subquery with a planner cost of 1.7e9 that was still going seventeen minutes in. Correctness was never the problem in either case, which is exactly why only running it at full size caught them.

None of that shows up in a demo, and all of it decides whether the thing can be operated. More on where I think this goes wrong for teams over on AI Smells.

Why it's on my consulting site

Most of my portfolio is work I did inside someone else's constraints. Brickanize is the one where every call was mine. Shelvanize is the second one, and it's early enough that the reasoning is still on the surface instead of buried under a year of shipping.

So this page is the part clients actually buy. Reading a licence before writing the feature, measuring the corpus before provisioning the database, and knowing which two things to cut before they cost anything. That work happens long before there's a product to show, and it decides whether the product is worth showing.

Bibliographic data comes from Open Library, a project of the Internet Archive, which does not sponsor, authorize, or endorse this app.