Overview
Manage photos got a proper library filter bar (persisted locally and applied on the server), batch edit endpoints for titles/tags/albums and for capture metadata, and a much richer capture-details flow for one or many photos. GPS can be set with a Leaflet map and address search instead of typing coordinates. Global search surfaces gear and camera pages. Supabase fetch errors read more clearly in the UI. Coolify/nginx docs and scripts were updated for Supabase database hosts behind the proxy.
Photo library filters
Problem: The manage grid only had coarse visibility toggles; finding “photos with this lens in that challenge” meant scrolling or exporting mentally.
Solution: FilterPhotosModal drives a PhotoLibraryFilters object (camera, lens, tags, albums, challenges, license, visibility, title text, upload presets, challenge status, sort). Values are stored in localStorage via photoLibraryFiltersStorage.ts. managePhotosFetch.ts and photoQueryCache pass the filter into list queries so pagination and deep links stay consistent. The photos page shows an active filter label and opens the modal from a filter control (public/icons/filter.svg).
Batch photo and capture details
Problem: Multi-select could bulk-delete but not bulk-edit metadata the way the single-photo EXIF modal already worked.
Solution:
POST /api/photos/batchand sharedbatchUpdatePhotoDetails*handle titles, tags, license, visibility, etc., callingbatch_update_photoswhere appropriate.POST /api/albums/photos/batchupdates album membership/sort viabatch_update_album_photos.- EXIF uses
batchUpdatePhotoExif→batch_update_photo_exifwith partial merge rules insrc/utils/exif.ts(mergeExifEditsPartial,getCommonExifFormValues). PhotoExifModalaccepts multiple photos: empty fields mean “leave each photo’s value”, withbulkExifSaveConfirmsummarizing changes before save.- Footer adds Remove all data; success shows a short Saved state with a check icon.
Input/AutocompleteInputfilledprop makes populated fields easier to scan.
ManageLoadMoreSentinel.tsx was removed; load-more behavior lives in the consolidated fetch path.
Choose on map (GPS)
Problem: Google embed maps on the site are read-only; they cannot return the center after panning.
Solution: LocationMapPickerModal is a stacked <dialog> above the capture modal (z-[70]). Leaflet + OSM tiles, fixed center pin (map-pin-solid.svg), live coordinates under the map. Defaults: Rotterdam center, zoom 12 without GPS / 16 with existing coords. Authenticated GET /api/location/search proxies Nominatim (searchPlaces.ts) for address suggestions. Choosing a result flies the map; Choose writes lat/lng into the form (six decimal places). Spinner sits beside the search field without remounting the input (addon toggle was causing the text to vanish).
Search, gear, and errors
global_searchwiring insrc/lib/data/search.tsand UI inSearchResultItem/SearchResultsinclude gear entities;/members/camera/[name]benefits fromsearchGearPages.fetchWithFriendlyErrorswraps Supabasefetchon browser and server clients so rate limits and gateway errors map to short user copy viauserFacingHttpError.
Infra
infra/nginx-db-production.confsample and staging nginx buffer tweaks;fix-nginx-proxy-headers.shcan discover DB vhosts.docs/deployment/coolify.mdtroubleshooting for 502s on Supabase hosts.
All Modified Files
New:
changelog/2026-10-22/sha.txtchangelog/2026-10-22/commit-message.txtchangelog/2026-10-22/files-changed.mdpublic/icons/filter.svgpublic/icons/map-pin-solid.svgsrc/app/api/albums/photos/batch/route.tssrc/app/api/location/search/route.tssrc/app/api/photos/batch/route.tssrc/components/manage/FilterPhotosModal.tsxsrc/components/manage/LocationMapPickerModal.tsxsrc/components/manage/bulkExifSaveConfirm.test.tssrc/components/manage/bulkExifSaveConfirm.tsxsrc/hooks/photoLibraryFilters.tssrc/hooks/photoLibraryFiltersStorage.tssrc/hooks/usePhotoLibraryFilterOptions.tssrc/lib/gear/searchGearPages.test.tssrc/lib/gear/searchGearPages.tssrc/lib/location/mapDefaults.test.tssrc/lib/location/mapDefaults.tssrc/lib/location/mapTileLayer.tssrc/lib/location/searchPlaces.tssrc/lib/photos/batchUpdateAlbumPhotos.tssrc/lib/photos/batchUpdatePhotoDetails.tssrc/lib/photos/batchUpdatePhotoDetailsClient.tssrc/lib/photos/batchUpdatePhotoDetailsSchema.tssrc/lib/photos/batchUpdatePhotoExif.tssrc/lib/photos/exifFormSchema.tssrc/lib/photos/photoTagSync.test.tssrc/lib/photos/photoTagSync.tssrc/utils/supabase/fetchWithFriendlyErrors.tssrc/utils/userFacingHttpError.test.tssrc/utils/userFacingHttpError.tsinfra/nginx-db-production.conf
Modified:
package.jsonpnpm-lock.yamlAGENTS.mdCHANGELOG.md.release-please-manifest.jsondocs/deployment/coolify.mdinfra/coolify/fix-nginx-proxy-headers.shinfra/supabase-staging/nginx-db-staging.confsrc/app/account/(manage)/photos/page.tsxsrc/app/api/search/route.tssrc/app/members/camera/[name]/page.tsxsrc/app/providers/ConfirmProvider.tsxsrc/components/manage/PhotoExifModal.tsxsrc/components/manage/index.tssrc/components/search/SearchResultItem.tsxsrc/components/search/SearchResults.tsxsrc/components/shared/AutocompleteInput.tsxsrc/components/shared/ConfirmModal.tsxsrc/components/shared/Input.tsxsrc/components/shared/Select.tsxsrc/hooks/managePhotosFetch.tssrc/hooks/photoQueryCache.tssrc/hooks/useAlbumPhotoMutations.tssrc/hooks/useManagePhotoDeepLink.tssrc/hooks/usePhotoMutations.tssrc/hooks/usePhotoUpload.tssrc/hooks/usePhotos.tssrc/lib/data/search.tssrc/lib/gear/ingestFromExif.tssrc/lib/gear/normalizeExifBrand.tssrc/proxy.tssrc/tours/photosFirstRunTour.tssrc/types/search.tssrc/utils/exif.test.tssrc/utils/exif.tssrc/utils/supabase/admin.tssrc/utils/supabase/client.tssrc/utils/supabase/server.ts
Deleted:
src/components/manage/ManageLoadMoreSentinel.tsx