trails/openspec/changes/activity-photos/proposal.md
Ullrich Schäfer 0a330e4466
Break up route-features into focused specs, add new changes
Archive the monolithic route-features spec and replace with 9 focused
OpenSpec changes: multi-day-routes, waypoint-notes (with POI snapping),
undo-redo, local-dev-stack, route-sharing, route-discovery,
activity-photos, osm-overlays, plus the existing changelog and
komoot-import.

Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
2026-03-29 09:53:41 +02:00

2.8 KiB

Why

Activities are text-only. Users complete a hike or bike tour and want to share photos from the trip alongside their route and stats, but there is no way to attach images. This is the most basic social feature missing from the Journal -- without it, activities feel like spreadsheet rows rather than trip reports.

The infrastructure for photo storage (Garage, an S3-compatible self-hosted object store) is already planned and commented out in docker-compose.yml. This change enables it and builds the upload + display pipeline.

What Changes

  • Infrastructure: Enable the Garage container in docker-compose, create a bucket for activity photos, add S3 client utility to the Journal app.
  • Schema: New journal.activity_photos table linking photos to activities with metadata (S3 key, alt text, dimensions).
  • Upload flow: Server generates presigned PUT URLs, client uploads directly to Garage. Photos are resized and EXIF-stripped on the client before upload.
  • Display: Photo gallery grid on the activity detail page with lightbox view and lazy loading.
  • Deletion: Soft delete with background S3 cleanup.
  • Privacy: Photo storage documented in privacy manifest, EXIF stripping explained.

Capabilities

New Capabilities

  • activity-photos: Photo upload, storage, gallery display, and deletion on Journal activities

Modified Capabilities

  • infrastructure: Garage S3 container enabled, bucket provisioned
  • activity-management: Activity detail page gains photo gallery and upload UI
  • privacy-manifest: Documents photo storage, EXIF handling, S3 retention

Non-Goals

  • Video uploads: Photos only. Video adds transcoding complexity.
  • GPS-tagged photo mapping: Placing photos on the route map by GPS coordinates is a future enhancement, not part of this change.
  • Photo editing or filters: Upload as-is (after resize and EXIF strip).
  • CDN: Serve directly from Garage via presigned GET URLs. CDN layer is a future optimization.
  • Photo albums or collections: Photos belong to a single activity. No cross-activity albums.
  • Bulk import from external services: Manual upload only.

Impact

  • Infrastructure: Garage container added to docker-compose, new volume for object storage, Caddy config for S3 endpoint (internal only)
  • Database: New journal.activity_photos table
  • Dependencies: @aws-sdk/client-s3 and @aws-sdk/s3-request-presigner for presigned URL generation; client-side image resize library
  • Files: Activity detail page, new upload component, new gallery component, storage server utility, privacy page update
  • Environment variables: S3_ENDPOINT, S3_ACCESS_KEY, S3_SECRET_KEY, S3_BUCKET added to Journal service
  • Privacy: Photo storage and EXIF handling documented in manifest