featurebugfixperformanceinfrastructure

Changelog — March 11, 2026

Major performance overhaul for watermark delivery and image loading, a critical PDF generation crash fix, and a new background color picker in the media preview dialog. Three releases shipped: v1.11.4 → v1.11.5 → v1.12.0.

✨ New Features

  • Background Color Picker in Preview Dialog — Added a palette button next to the annotation toggle in the media preview dialog, allowing users to switch the background color (white, black, gray, transparent) while reviewing assets — mirroring the same control already available in annotation mode. Defaults to white. #PR-292

🐛 Bug Fixes

  • Annotation PDF Crash on High-Resolution Images — Generating annotation PDFs from large studio images caused Invalid string length errors in jsPDF due to oversized PNG data URLs. Images are now downscaled to a maximum of 2400px and exported as JPEG at 85% quality, reducing the data URL size by ~100×. #PR-290

  • Watermark Proxy ECONNRESET & API 502/503 Cascade — High concurrent watermark requests were exhausting sockets on the API server, triggering ECONNRESET errors that cascaded into GraphQL 500/502/503 failures. Three-layer fix applied: #PR-288 #PR-289

    • Concurrency semaphore (max 8 parallel R2 fetches) + request deduplication on the proxy endpoint.
    • Route-level load shedding: when more than 10 watermark requests are in-flight, excess requests are immediately redirected to the non-watermarked derivative URL.
    • Pre-generated watermark derivatives: the BullMQ asset-processing pipeline now generates watermarked thumbnail/preview WebP files at upload time and stores them in R2 (projects/{id}/watermarks/{assetId}/). GraphQL resolvers serve the static R2 URL when available, eliminating on-the-fly watermark generation for newly processed assets. The /images/watermark/ endpoint remains as a fallback for legacy assets.
  • Image Loading Performance & Fallback Pipeline — Optimized derivative sizing and loading strategy to reduce unnecessary fallbacks and simultaneous requests: #PR-287

    • Preview derivatives upsized to 1600px (was 800px) to avoid mid-dialog quality fallbacks.
    • Thumbnails reduced to 400px / 78% quality for lighter grid rendering.
    • Progressive fallback order differentiated between grid and dialog contexts.
    • Adjacent image prefetching enabled in the preview dialog.
    • TIFF files now served via transform URL instead of raw storage URL.
    • LRU cache eviction improved with progressive strategy.
    • Admin backfill endpoint added for retroactively generating watermark derivatives.

📦 Dependencies & Infrastructure

  • Backfill script (scripts/backfill-watermarks.mjs) added to enqueue asset-processing jobs for existing PHOTO assets without pre-generated watermark URLs. Supports --dry-run and --project <id> flags with cursor-based pagination (batch size 200). #PR-289
  • Prisma client and react-email build artifacts updated across multiple PRs.
  • Releases: v1.11.4 (image loading), v1.11.5 (watermark pipeline + PDF fix), v1.12.0 (background color picker).

By theodaguier