Marketing site launch + 30+ bug fixes across the engine

We shipped the public neuthek.com marketing site this week — the home page, features, hosting, developers, roadmap, compare-to-the-big-providers, and waitlist pages all went live. While building it we also chased down a long backlog of engine bugs across the gallery, upload pipeline, face recognition, and admin dashboard. Most fixes are invisible — they're the stuff that should have worked the first time.

Problems we found

What wasn't working as well as it should have.

  • Uploads crashed with a 'null value in column user_id' database error on every photo upload because the AI-tag insert was missing the owner column the recent multi-user migration required.
  • Animated GIFs flattened to a single frame on upload because the upload pipeline re-encoded them through Pillow's single-frame save.
  • Camera RAW files (Nikon NEF, Canon CR2, Sony ARW, Fuji RAF) showed up as soft thumbnails because we were re-encoding the embedded JPEG preview instead of decoding the actual sensor data.
  • Deleting a photo permanently removed it instead of moving it to Trash, so users had no way to undo.
  • The Photos / Videos / Documents sidebar pills showed counts for the current folder only, even though those views are conceptually 'all my videos across the library'.
  • Re-labelling a single face would rename the entire person row, dragging every other photo of that person along with the new name.
  • The admin dashboard took 25+ seconds to open because every poll walked every object in every storage bucket on the API event loop.
  • Code files from Google Drive (.py, .js, .md, etc.) had no viewer — they showed up as generic 'document' icons with no preview.
  • The Settings page showed mock 'face data' and 'location' stats with hard-coded numbers instead of your actual library counts.
  • The empty-gallery state told you 'No results' even when you had folders visible above (it only checked file count, not folders).

How we fixed them

What changed in this release to fix the issues above.

  • AI-tag insert now stamps user_id so every uploaded photo gets its CLIP tags without crashing.
  • Animated GIFs are passthrough end-to-end — no re-encode, no frame loss.
  • Added rawpy (LibRaw) to decode camera RAW into the full sensor image, then re-encoded at JPEG quality 95. NEF / CR2 / ARW / DNG / RAF / ORF / RW2 / PEF all work.
  • Delete is now soft by default — items go to Trash with deleted_at stamped. The Trash view shows them with a Restore button and a 'Delete forever' button for permanent removal.
  • Photos / Videos / Documents sidebar tabs are now cross-folder by definition. Counts come from a new /images/facets field that aggregates the entire library, not just the current folder.
  • Face re-labelling clones the underlying face row instead of mutating the shared Person — correcting one mis-grouped photo no longer renames everyone.
  • Admin dashboard's bucket-walk now lives behind a 60-second LRU cache + a worker thread + a 20,000-object iteration cap. Subsequent opens are ~330x faster (28 s → 86 ms).
  • Code-file preview opens in a syntax-highlighted PDF-style modal with line numbers (Prism, ~40 grammars eagerly loaded).
  • Settings → Privacy → Face data and Location panels now show real numbers pulled from /people/ and /images/geo, with copy that explains your embeddings stay on the server you control.
  • Empty-gallery state checks for folders too — if you have synced Drive folders at root, the gallery shows them instead of falling through to the 'drop files here' CTA.

New features

Brand-new capabilities that weren't there last week.

  • Public marketing site at neuthek.com — home, features, hosting, developers, roadmap, compare page, waitlist, privacy + terms.
  • Waitlist endpoint with Postgres or SQLite storage, admin viewer with Basic Auth, and rate limiting on the public form.
  • Roadmap page listing what's shipped, what's in progress, and what's planned through to public release.
  • Compare table showing neuthek next to Google Photos / iCloud / OneDrive / Dropbox on the dimensions that matter (privacy, search by meaning, self-host, compression, AI lock-in).
  • Drag-rectangle multi-select in the gallery: click empty space and drag to select cards.
  • Cross-folder Detect-Person workflow: select a batch of photos, type a name, neuthek runs face detection on each one and assigns every newly-found face to that person.

Why this matters

Two big motivations this week. First, neuthek needed a place on the public web where you could read what it is, decide if it's for you, and join the launch waitlist — without us having to slack you the elevator pitch. Second, every week we test the engine end-to-end and a stack of small bugs surfaces; we'd rather burn a week paying them down than let them compound into a system that feels unreliable. None of these individual fixes are dramatic, but together they're the difference between 'half-finished prototype' and 'something I'd actually trust my library with'.

What this means for you

How the changes actually show up when you use neuthek.

  • Visit neuthek.com to read about the product, see the roadmap, compare to the big providers, and join the waitlist.
  • Upload any photo — including animated GIFs, camera RAW (NEF / CR2 / ARW / etc), and HEIC — without the upload silently failing or losing data.
  • Delete a photo and see it show up in the Trash view. Restore it or delete it forever from there.
  • Click Photos / Videos / Documents in the sidebar to see your full library across every folder.
  • On a desktop, click and drag across the gallery to multi-select. Use the Detect person dropdown in the multi-select bar to tag a batch of photos at once.
  • Open the admin dashboard without waiting half a minute.
  • Open a code file synced from Drive and read it with syntax highlighting and line numbers.