Bookmark Deck
A calm, private home for your online life — and the life around it.
Overview
Five pillars share one roof: bookmarks, focus, habits, home inventory and filing. Everything is local-first — saves to your device instantly, works offline, installable as a PWA — and syncs to your own Google account when you sign in. No analytics, no ads.
The problem
Five parts of one life — the sites you use, the work you do, the consistency you build, the things you own, and the papers that prove any of it — each want their own app, their own account and their own privacy posture, and none of them know the others exist. The tools that do join them up tend to take the data as payment. Meanwhile the thing that would actually help is small and unglamorous: the policy in drawer two and the insurer's login page being one record rather than two apps you have to remember to open.
The approach
One roof, five removable pillars, local-first. Everything saves to the device immediately and the whole app works offline; the cloud copy goes to the user's own Google account rather than anyone else's server, and camera work — barcode, label OCR, receipt scan — never leaves the device at all. Auth is deliberately two layers: next-auth owns the session, Firebase Auth owns Firestore access, and a silent id_token bridge connects them so a single Google sign-in covers every pillar's sync instead of each one prompting separately. That bridge is best-effort by design, falling back to the interactive path, so failing costs one tap rather than the sync. The tradeoff is stated plainly: this leans on Google, and the answer is that the account it leans on is yours.
Outcome
- Firestore rules are proved against an emulator, deployed, then read back to confirm the release landed — 40 assertions covering owner access, cross-account denial, anonymous denial and no leak outside the user's own subtree
- 785 unit tests over the pure logic, with CI pinned to Node 22 for a reason: a local 22.22.2 ran all 785 while CI on Node 20 reached 773, so a green local run proved nothing until the runtimes matched
- Nothing the camera touches leaves the device, and there are no analytics, tracking or ad SDKs anywhere in the app
- Dependency ignores name specific versions rather than whole packages, so an ignore cannot silence the release that fixes the problem — the rule is applied to its own entries, and one was removed the day its stated cause disappeared
- Deletes across the app offer Undo and restore the record whole, photos and receipts included
What it does
Bookmarks that survive being a lot of bookmarks
Nestable folders with their own pages and subtree search, an app-shortcut launcher row, bulk move and delete with Undo, and a command palette over everything. Auto-organize proposes a categorization plan and waits for you to accept it rather than rearranging your library and telling you afterwards.
Focus, tied to the thing you are focusing on
A Pomodoro timer that stays timestamp-accurate in a background tab and fires even when the tab is closed, tasks separated from to-dos, a journal, and a hand-off that starts a session on the bookmark you were looking at.
Streaks that forgive
Not having done it yet today does not break a streak, and a planned skip is neutral rather than a failure. A tracker that punishes an ordinary Tuesday is a tracker people stop opening.
An inventory that knows what kind of thing it is holding
A barcode scan picks the right form: books take an author and a reading status, food takes a use-by date, subscriptions roll their renewal and total up per month. Prices carry their tax rate so every total is the number you actually paid. Things borrowed from other people stay out of your value totals while their fees still count as spend.
Filing that matches the furniture
Places, then folders, then papers, nested as deep as the real cabinet is. A drawer label like A-J or Taxes becomes a rule and not just a name — it suggests where a folder goes and flags one sitting in the wrong place. Retention runs from the end of the year the contents cover, not the day you filed, and nothing is ever deleted on a timer: it is a review queue.
One sign-in, every pillar
Two auth layers bridged silently, so signing in once lights up sync everywhere instead of each pillar asking in turn. All user data lives under a single owner-scoped path, which is what lets one recursive security rule cover every collection the app will ever add.
Ask about Bookmark Deck
Want something like this, or curious how a piece of it works? Send a note — it reaches me tagged with this project, so I have the context before I reply.