Catlg
One catalog for books, games, music, film and TV, with forkable collections, Club tier lists and recommendations that name their source.
- Status
- In development
- Stack
- Web App · Full-Stack · Media · Recommendations
- Live demo
- catlg.app
- Studio
- Published by KnownBetter Studios; this page is the engineering case study.
At a glance
- Outcome: Puts books, games, music, film and TV in one catalog, with forkable collections, Club tier lists and recommendations that name their source. Product page at KnownBetter Studios.
- Status: Web app live at catlg.app; the latest release reached staging and production on October 15, 2026. The iOS and Android apps are in an active internal beta, on TestFlight and Google Play’s internal track.
- Dates: 2023–present. The current codebase dates from March 2026; KnownBetter Studios, LLC formed in 2026.
- History: Began in August 2023 as Tastebuds, a Next.js/Supabase search and library app over TMDB, IGDB and Last.fm. Rebuilt in December 2025 as a Dockerized FastAPI/PostgreSQL catalog with normalized ingestion and an OpenAPI contract. Rewritten in March 2026 on Vite and Fastify to drop the Next.js features it never used, and renamed Catlg.
- Role: Solo: product, data model, API, web and native apps, relay daemon and deployment.
- Contribution: I write the product spec, the 59 architecture decision records and the dependency-graph plans that break each feature into reviewable nodes. AI agents implement those nodes; I review each diff, debug failures and mark a node landed only after its verify command passes. Those gates draw on unit, integration, contract and Playwright suites and an OpenAPI drift check.
- Validation: An October 2026 security review found seven high-severity flaws; each now has a test that attacks it and was re-attacked on staging. About 60 race tests cover the concurrency fixes. The October 5 scale checks use a 10× synthetic fixture, with budgets of 200 ms per database probe and HTTP p95 of 500 ms at 20 clients. Broad search, Discover ranking and very large collections have recorded budget breaches. All six staging races held; staging load checks passed on a smaller dataset. October 7 signed-out production checks confirmed the branding, collection, Discover and Clubs pages and a 1200 × 630 share image. The October 15 release passed 6,853 unit, 2,581 integration, 427 contract and 612 browser tests before promotion.
- Stack & libraries: TypeScript, React, TanStack Start/Router/Query, Fastify, PostgreSQL/Drizzle, pg-boss, Expo/React Native, shared design tokens, Satori, Sharp, Dokku.
- Source: Private while the product takes shape; the demo is public.
Catlg is one library for movies, TV, games, books and music. It covers what Letterboxd, Trakt, Backloggd and StoryGraph each do for one kind of media. You track every kind of media the same way. Collections can mix media types. Recommendations say why they showed up.
Once you connect services like Steam, Spotify, Plex or Jellyfin (23 library connectors), your history imports automatically. Exports from services like Letterboxd and Libby import as files. Copying someone else’s collection keeps a permanent link to whoever made the original. Clubs let a group build a collection together, rank items by vote and work through it week by week, with a Discord bot keeping the schedule. Every recommendation points back to the items and people it came from. If Catlg can’t explain a suggestion, it doesn’t show it.
Catlg never invents data or overwrites what you entered. It stores a title’s shared details, where those details came from and your own progress separately, so refreshing a title can’t erase your notes. Items are matched by their ID numbers from services like IMDb before their titles, because two different things can share a name. Anything uncertain goes on a list for you to sort out. For a media server on your home network, a small helper program at home checks in with Catlg. It runs only read-only requests that Catlg has signed and sends back the results, so your server’s password never leaves the house. The website and the phone apps share one back end.
The first two real imports, on September 17, 2026, left many items unmatched. My Steam library left 89 of 344 games unmatched. My Jellyfin server left all 197 items unmatched, even though each one carried its IMDb and other IDs. The matcher only searched Catlg’s own catalog, which didn’t have those items yet. It never asked the outside services. I didn’t use fuzzier title matching, because it would have missed the same 197 items and put a confident-looking score on every wrong guess. Now a miss gets three tries: look up the ID with the outside service, then an exact title-and-year match, then retries on a 1, 3, 7 and 30-day schedule. An exact title match can link an item in your own library, which you can fix. It never adds an ID to the shared catalog, where a mistake would affect everyone and be hard to undo. The next day, unmatched Steam games dropped from 89 to 6 and unmatched Jellyfin items from 197 to 0.
In October 2026 a security review tried to break Catlg’s own rules, such as a private library staying private and a blocked user staying blocked. Each flaw it found got a failing test first, then a fix. The app now connects to the database with an account that cannot change the table structure. A second pass covered two requests arriving at once: two sign-ins from one code, two imports of one title, or two votes moving one ranking. Each of those now takes a lock or a conditional write, and race tests send the requests at the same moment.
Staging from production
I automated production-to-staging database copies so release tests can use current data. Staging deploys refresh by default; an explicit skip is recorded and does not prove a fresh-data test. The copy never leaves the server. Before anything stops, the script refuses to run unless the source and target are provably different databases with matching app settings. After the import it clears sessions, tokens, passkeys, sign-in codes and queued jobs. It disconnects linked services and replaces email addresses and identity subjects with staging values. Library, collection and activity rows stay. The scrub removes credentials and rewrites identities; it does not remove all personal content. Staging also writes to its own storage bucket. It reads production images through a read-only key, and a check confirms it cannot overwrite or delete a production file. The first run, on October 14, copied 2,098 catalog items and 1,075 library entries and confirmed all 20 scrubbed tables were empty.
Public API and link previews
Developers can now read the catalog and their own data through a keyed API, or let other apps connect through OAuth with a consent page. A production check on October 11 confirmed the rate limit and that a disabled key is refused. Item, collection, profile and Club pages now render on the server, so a link pasted into a chat shows that page’s own preview card.
The refreshed brand now runs on production. The header uses the catlg. wordmark; compact navigation uses c., with ink lettering and a red period. Shared design values keep web and native colors, spacing and motion consistent. Rules divide sections; solid blocks mark selected actions. Shadows remain on raised controls and solid buttons. Reduced motion limits animation to short fades. Collection share buttons now produce links with a preview image assembled from the title, author and cover art. The API checks visibility before generating a card. Changing a collection to private stops new previews, although previously cached images can persist.
The website is live at catlg.app. The iPhone and Android apps are in an active internal beta, on TestFlight and Google Play’s internal track. The home helper is published as a container image. A browser extension for Chrome and Firefox is packaged but not yet listed in either store. Next up: the extension’s store listings.
LIVE PRODUCTION · OCTOBER 7, 2026



