Commit Graph

20 Commits

Author SHA1 Message Date
Jeff Emmett 021b939241 fix: send Clear-Site-Data on /__reset for full browser nuke
caches.delete() only clears service-worker managed caches — the
browser's own HTTP cache can still serve stale or corrupted chunk
responses. Setting Clear-Site-Data tells the browser itself to drop
cookies, cached responses, storage, and service worker registrations
for the origin, which is what's actually needed to unstick a PWA
with a bad cached chunk.

Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
2026-04-17 13:09:36 -04:00
Jeff Emmett 76f8816b82 feat: /__reset recovery page + no-store on 5xx responses
/__reset returns a self-contained page that unregisters every service
worker, clears every cache, drops the heatmap API key, and reloads.
Use when a PWA is stuck on a bad cached chunk or SW state — visiting
photos.jeffemmett.com/__reset (even inside the broken PWA) fixes it.

Also mark any upstream 5xx response as no-store so a transient error
during a container restart can't get pinned into a browser or CDN
cache and brick the PWA long-term.

Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
2026-04-17 13:05:43 -04:00
Jeff Emmett af3468e0d5 fix: include Immich chunk manifest hash in inject-version
After an Immich upgrade, Svelte chunk filenames rotate but the cached
PWA shell still imports old ones — dynamic imports 500 or 404. Our
auto-update mechanism only caught changes to our injected script, not
upstream changes, so the stuck PWA never self-healed.

Now /api/custom/inject-version returns a hash of
(custom script || Immich chunk manifest fingerprint), so any upgrade
bumps the version, the PWA detects it on next poll, unregisters the
service worker, clears caches, and reloads with fresh chunks.

We extract only the /_app/immutable/... references from the HTML to
avoid hashing server-rendered per-user state (CSRF tokens etc) that
would cause spurious version churn.

Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
2026-04-17 12:56:37 -04:00
Jeff Emmett 4cb479404a feat: map view stacks top/bottom + sorts photos by distance to center
Column layout: map on top, photos on bottom — applies on desktop and
mobile. Bounds-filtered photo list is now sorted by distance from the
current map center, so photos closest to where you're looking show up
first and the list re-sorts automatically as you pan or zoom.

Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
2026-04-17 12:53:49 -04:00
Jeff Emmett e55703ea6e fix: grant heatmap API key ['all'] permissions + add Reset button
A narrow (asset.read, asset.view) key was insufficient for the
heatmap's /api/search/metadata call — the server returned an error.
Request ['all'] so the key covers every endpoint the heatmap touches.

Also add a Reset button next to the Collapse toggle so a stale or
under-permissioned cached key can be regenerated without site-data
surgery.

Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
2026-04-17 12:52:41 -04:00
Jeff Emmett 96d9a6971c feat: split map view into 50/50 map + bounds-filtered photo grid
On map view the body container now shows the Leaflet map on one half
and a photo grid on the other half. The grid renders only photos
whose GPS falls inside the map's current bounds, and re-renders on
moveend/zoomend so panning and zooming filters the visible photo set
live. Stacks vertically on narrow viewports.

Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
2026-04-17 12:49:25 -04:00
Jeff Emmett b4e801e17f feat: auto-provision heatmap API key + move banner below sections
The heatmap iframe now requests an Immich API key via /api/api-keys
(asset.read, asset.view) on first load, caches it in localStorage,
and passes it via ?apiKey= so the user doesn't have to paste one.

Banner moved to the bottom of the /explore scroll container, below
People and Places.

Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
2026-04-17 12:47:18 -04:00
Jeff Emmett 7be768e2db feat: pinch-zoom, heatmap iframe, and scroll strips on /explore
- Enable native mobile pinch-zoom by rewriting the viewport meta.
- Strip Content-Security-Policy / X-Frame-Options from HTML responses
  so heatmap.jeffemmett.com can be iframed in.
- On /explore: inject a collapsible heatmap iframe at the top, and
  replace People + Places sections (truncated grid with 'view more')
  with horizontally-scrollable strips fetched from /api/people and
  /api/search/cities.
- Re-run injection on history pushState + MutationObserver to cover
  Svelte SPA route changes.

Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
2026-04-17 12:41:14 -04:00
Jeff Emmett 2418298d77 feat: PWA auto-update detection for injected script
server.js: hash live-search.js into INJECT_VERSION, expose
/api/custom/inject-version, set no-store on HTML so inline version
tag stays fresh.

live-search.js: compare baked window.__LS_VERSION vs server version
every 2 min + on visibility change; show banner, auto-unregister
service worker, clear caches, and reload when a new version ships.

Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
2026-04-17 12:26:04 -04:00
Jeff Emmett 40dd22e3ad feat: replace Place dropdowns with search input + forced map view
Hijacks #location-selection in Immich's search filter modal: hides
country/state/city comboboxes, injects a text input that opens the
live-search overlay directly in map view for pan/zoom exploration.

Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
2026-04-17 12:14:47 -04:00
Jeff Emmett 38bdcf25dc feat: add search-app proxy with WebSocket support and upload buffering
Adds immich-proxy (search-app) with live search injection, WebSocket
proxying for socket.io, and 10GB upload buffering via Traefik middleware.
Moves Traefik routing from immich-server to proxy. Updates valkey 8→9.
Adds backlog tasks for drone sync and Syncthing reconnection.

Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
2026-04-14 12:47:53 -04:00
Jeff Emmett 9281400c61 chore: add backlog-notify onStatusChange hook
Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
2026-03-10 15:31:04 -07:00
Jeff Emmett 6ba1462db3 chore: remove CLAUDE.md from git tracking
CLAUDE.md may contain project context with credentials and is now
covered by global gitignore to prevent accidental secret commits.

Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
2026-02-25 14:41:16 -08:00
Jeff Emmett 7b37556621 feat: add demo.rphotos.online subdomain to Traefik routing
Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
2026-02-25 14:35:25 -08:00
Jeff Emmett 5aabaa662d feat: Add Immich favicon to heatmap app
🤖 Generated with [Claude Code](https://claude.com/claude-code)

Co-Authored-By: Claude Opus 4.5 <noreply@anthropic.com>
2026-01-02 18:43:35 +01:00
Jeff Emmett f14c5fdaf9 feat: Add custom heatmap visualization for photo locations
- Add heatmap-app with Node.js server and Leaflet.js frontend
- Implement API proxy to handle CORS for internal Immich server
- Add pagination support for fetching all geotagged photos (84k+)
- Support click-to-view photos in selected area with gallery sidebar
- Integrate with docker-compose and Traefik for heatmap.jeffemmett.com
- Add backlog tasks for heatmap work and Power Tools v2.4 tracking

🤖 Generated with [Claude Code](https://claude.com/claude-code)

Co-Authored-By: Claude Opus 4.5 <noreply@anthropic.com>
2026-01-02 18:32:02 +01:00
Jeff Emmett 189fde225d feat: Complete Google Takeout upload task (004-009)
Uploaded 272GB of photos/videos to Immich:
- 100,205 images + 5,238 videos
- 89,188 metadata updates
- Used direct connection (bypass Cloudflare 100MB limit)

🤖 Generated with [Claude Code](https://claude.com/claude-code)

Co-Authored-By: Claude Opus 4.5 <noreply@anthropic.com>
2025-12-19 11:15:56 -05:00
Jeff Emmett f7888072c3 feat: Initialize backlog with completed Google Takeout upload task
All 3 zip files (51GB each) successfully uploaded to Immich with 0 errors.

🤖 Generated with [Claude Code](https://claude.com/claude-code)

Co-Authored-By: Claude <noreply@anthropic.com>
2025-12-04 11:17:47 -08:00
Jeff Emmett 3b279f7b6e Replace CLAUDE.md symlink with actual file for Docker compatibility
🤖 Generated with [Claude Code](https://claude.com/claude-code)

Co-Authored-By: Claude <noreply@anthropic.com>
2025-12-04 02:29:24 -08:00
Jeff Emmett f1999a7813 Initial commit: Immich Docker setup
- Add docker-compose.yml with Immich v2 configuration
- Include all required services (server, ML, postgres, redis)
- Add .env.example with secure defaults
- Create comprehensive README with setup instructions
- Add backup and health check scripts
- Configure .gitignore for data directories

Deployed and tested on Netcup VPS at photos.jeffemmett.com

Generated with Claude Code (https://claude.com/claude-code)

Co-Authored-By: Claude <noreply@anthropic.com>
2025-11-25 12:33:30 -08:00