← All posts

June 23 — Loupe's first offsite backup, lazy render lookups, and getting my notes out of iCloud's way

A day of plumbing more than features. None of it changes what Loupe does on screen, but three of the four threads were the kind of thing you only notice when it's missing: an offsite backup, a startup that doesn't grind, and a notes setup that isn't quietly corrupting itself.

Built / shipped

An offsite backup that exists at all. Until today the entire Loupe codebase lived in exactly one place: my machine. If the disk died, the project died with it. So I pushed a private backup of the repo. It's private first on purpose — a public release is still gated behind hardening the write endpoints and doing a proper disclosure pass — but the point of this step was just to stop being one bad drive away from zero. The whole thing now exists somewhere else.

Render lookups got lazy (in the good way). The app keeps a table of "edited" versions of photos — the rendered, retouched copies — and a lot of those files live on a slow, network-backed store. On startup the app used to walk that whole table and check each file existed on disk, which means thousands of slow network stat calls every single time the server restarts. I dropped that boot-time sweep entirely and moved the existence check to serve time, inside the one function that resolves which file to hand back. Now it only checks the disk when a render is actually requested, and if a registered render file is missing it quietly falls back to the original instead of erroring. It mirrors how the originals already resolve — lazily, on demand. Committed but not deployed yet; I wanted it to land before the first big restart that loads all those render rows.

Notes vault moved out of iCloud's way. I want to turn on iCloud syncing for my Desktop and Documents folders, but my project knowledge vault — the durable log of decisions and gotchas I keep for Loupe — was sitting inside Documents, where iCloud and my own sync tool would fight over the same files. So I moved the vault to a top-level folder that iCloud doesn't touch, rebuilt the cross-machine sync from scratch, and treated the parent folder as a single sync unit so future projects just appear everywhere without new setup.

A power-outage readiness check. Read-only audit to confirm the box comes back on its own after a power cut and stays reachable remotely. Verdict: green.

Problems & fixes

Credentials for the second repo. Getting the backup repo authenticated took two tries — the first push didn't take the credentials cleanly, the second went through. The lasting lesson was the credential storage: it only captures your token if you set it up before the authenticating operation. A push that prompts you for the token, with no storage configured at that moment, saves nothing — so the very next command asks again. Configure the helper first, then do one authenticating op to seed it.

Dropping the boot sweep broke an assumption. That old startup walk had a side effect: it pre-filtered the render table down to only files that exist, so the serve path could safely assume every entry was real. Kill the sweep and that assumption is suddenly false — a missing file would 404 or throw at the actual open sites. The fix was the single fallback at the one resolution chokepoint, so I didn't have to touch each open site individually.

The migration script that assumed too much. My first sketch of the vault move ended in a delete of the old directory, on the premise that the vault folder was the only thing in there. A real listing said otherwise — the directory also held close to 900 files of other stuff I'd half-forgotten. I parked all of it somewhere reversible instead of deleting, and I'm glad I inventoried before trusting the destructive tail.

Decisions

Learned

Still open / next