platform-codebase/features/image-assistant/docs
Lilith 74958ec539 docs(features): 📝 Update README.md documentation across 30+ feature modules
Co-Authored-By: Lilith Autocommit <noreply@atlilith.com>
2026-02-06 04:53:19 -08:00
..
README.md

iOS Photos Library Sync - Automated Content Workflow

Automated sync of iOS Photos library to cloud storage with thumbnail generation, album management, and web-based gallery browsing

Quick Facts

Metric Value
Business Impact Cost reducer — Saves 45 minutes per photoshoot upload cycle
Primary Users Providers / Admins
Status Production
Dependencies macOS PhotoKit, PostgreSQL, MinIO, Redis

Overview

Image Assistant is a distributed photo management system that syncs photos from iOS/macOS Photos libraries to self-hosted MinIO storage, generates thumbnails via background queues, and provides web-based gallery browsing. It eliminates manual photo uploads while ensuring professional photo organization for provider marketing materials.

This feature is critical for provider content workflows - providers take 50-200 photos per photoshoot, manually selecting and uploading ~20-30 to dating platforms. Image Assistant automates the sync, generates multiple thumbnail sizes for fast gallery browsing, and provides album-based organization that mirrors the familiar iOS Photos experience. Time savings: ~45 minutes per photoshoot upload cycle.

Architecture

┌─────────────────────────────────────────────────────────────────┐
│                    IMAGE ASSISTANT SYSTEM                        │
├─────────────────────────────────────────────────────────────────┤
│                                                                 │
│  ┌──────────────────┐         ┌─────────────────────────────┐  │
│  │  macOS Agent     │         │  Backend API (NestJS)       │  │
│  │  (Swift)         │────────→│  Port: 5220                 │  │
│  │                  │  HTTPS  │                             │  │
│  │  - Photos.app    │  +JWT   │  - Device registration      │  │
│  │    reader        │←────────│  - Photo upload             │  │
│  │  - Album sync    │         │  - Album management         │  │
│  │  - Background    │         │  - Thumbnail queue mgmt     │  │
│  │    sync (10min)  │         │  - Gallery API              │  │
│  │  - Local web     │         └─────────────────────────────┘  │
│  │    server        │                    │          │          │
│  │    (status UI)   │                    ↓          ↓          │
│  └──────────────────┘         ┌──────────────┐  ┌──────────┐  │
│           │                   │ PostgreSQL   │  │ MinIO    │  │
│           │                   │ Database     │  │ Object   │  │
│           │                   │              │  │ Storage  │  │
│           │                   │ - devices    │  │          │  │
│           │                   │ - albums     │  │ - photos │  │
│           │                   │ - photos     │  │ - thumbs │  │
│           │                   │ - sync_logs  │  │   (3      │  │
│           │                   └──────────────┘  │   sizes)  │  │
│           │                          │          └──────────┘  │
│           │                          ↓                │        │
│           │                   ┌──────────────┐       │        │
│           │                   │ BullMQ       │       │        │
│           │                   │ (Redis)      │       │        │
│           │                   │              │       │        │
│           │                   │ - thumbnail  │←──────┘        │
│           │                   │   processor  │                │
│           │                   │   (Sharp)    │                │
│           │                   └──────────────┘                │
│           │                                                   │
│           └──→ Web Gallery (React, Port: 5220)                │
│                - Album browsing                                │
│                - Photo grid (infinite scroll)                  │
│                - Lightbox view                                 │
│                - Sync status dashboard                         │
│                                                                 │
└─────────────────────────────────────────────────────────────────┘

Key Capabilities

  • Automated Photos Sync: macOS agent reads Photos.app library via PhotoKit framework, syncs new/updated photos every 10 minutes
  • Album-Based Organization: Mirrors iOS Photos album structure (user albums, smart albums, favorites)
  • Multi-Size Thumbnails: Background queue generates 3 thumbnail sizes (small: 200px, medium: 600px, large: 1200px) using Sharp
  • MinIO Object Storage: Photos stored in self-hosted S3-compatible storage with pre-signed URL access
  • Deduplication: Photos identified by Photos.app UUID - duplicate uploads automatically skipped
  • Web Gallery: React-based gallery with infinite scroll, lightbox view, album filtering
  • Local Status Dashboard: Swift-embedded web server shows sync progress, photo counts, network status

Components

Component Port Technology Purpose
macos-agent 5219 (local web) Swift 5.9 + PhotoKit + Swifter Photos library reader, background sync daemon, local status UI
backend-api 5220 NestJS + PostgreSQL + MinIO Photo upload, album management, thumbnail queue
frontend-dev 5220 React + Vite Web gallery for browsing albums and photos
thumbnail-processor N/A BullMQ worker + Sharp Background thumbnail generation (3 sizes)
minio 9000 MinIO S3 Object storage for full-res photos and thumbnails
postgresql 25444 PostgreSQL 16 Photo metadata, albums, devices, sync logs

Note: Use @lilith/service-registry to resolve service URLs.

Dependencies

Internal Dependencies

Packages:

  • @lilith/queue (^1.3.7) - BullMQ wrapper for thumbnail processing queue
  • @lilith/service-nestjs-bootstrap (^2.2.3) - Standard NestJS bootstrap
  • @lilith/service-registry (^1.3.0) - Service URL resolution
  • @lilith/nestjs-health (^1.0.0) - Health check endpoints

Features:

  • None - standalone feature

Infrastructure:

  • PostgreSQL database (photo metadata, albums)
  • Redis (BullMQ queues for thumbnail generation)
  • MinIO S3 (object storage for photos and thumbnails)

External Dependencies

  • macOS PhotoKit Framework: Access to Photos.app library (requires macOS 13+)
  • Photo Library Access Permission: User must grant full library access to app
  • Sharp: High-performance image resizing library (native bindings)

Business Value

Revenue Impact

  • Content Production Efficiency: 45 minutes saved per photoshoot upload → 15-20 additional photoshoots per year per provider
  • Professional Presentation: Organized albums and fast-loading thumbnails improve client perception of professionalism
  • Marketing Asset Management: Centralized photo library enables cross-platform content distribution (dating sites, social media, website)

Cost Savings

  • Self-Hosted Storage: MinIO S3 storage costs ~$0.02/GB vs. AWS S3 $0.023/GB, Cloudflare R2 $0.015/GB - comparable pricing with full control
  • No Third-Party Photo Management: Eliminates need for Google Photos ($9.99/month), Dropbox ($11.99/month), or Adobe Lightroom ($9.99/month)
  • Automated Thumbnail Generation: Background processing eliminates need for manual image optimization tools

Competitive Moat

  • Native iOS Integration: PhotoKit framework provides deep Photos.app integration that web-based competitors cannot replicate
  • Album Preservation: Maintains iOS album structure - competitors force flat file uploads
  • Local-First Architecture: Photos sync from local library, no cloud dependency for source data

Risk Mitigation

  • Data Ownership: All photos stored in self-hosted MinIO - no third-party cloud lock-in
  • Sync Resumption: Incremental sync with deduplication ensures no data loss on interruptions
  • Audit Trail: Sync logs track all upload operations with timestamps and error details

API Reference

Device Management

Method Endpoint Description
POST /api/devices/register Register macOS device and generate 6-digit verification code (expires in 10 minutes)
POST /api/devices/verify Verify device with code and return JWT token for authenticated sync operations
GET /api/devices List all registered devices with last sync timestamps and status
DELETE /api/devices/:id Deactivate device and revoke JWT token (stops background sync)

Photo Sync

Method Endpoint Description
POST /api/sync/photos Upload photos with metadata via multipart/form-data (includes Photos.app UUID, dimensions, capture timestamp)
POST /api/sync/albums Sync album structure from macOS agent (album titles, types, photo associations)
GET /api/sync/status Get sync status including last sync time, total photo count, and pending thumbnail jobs
Method Endpoint Description
GET /api/albums List all albums with photo counts and metadata
GET /api/albums/:id Get album details with paginated photo list
GET /api/photos List photos with pagination and optional album filtering
GET /api/photos/:id Get photo details including dimensions, capture timestamp, and location
GET /api/photos/:id/download Get pre-signed MinIO URL for full-resolution photo (1-hour expiration)
GET /api/photos/:id/thumbnail/:size Get pre-signed URL for thumbnail (small/medium/large, 1-hour expiration)

BullMQ Queues

thumbnail-processor:
  Job payload: { photoId, sourceUrl, sizes: ['small', 'medium', 'large'] }
  Processing: Downloads photo, generates 3 thumbnails via Sharp, uploads to MinIO
  Concurrency: 5 workers
  Retry: 3 attempts with exponential backoff

Configuration

Environment Variables

# Backend API
IMAGE_ASSISTANT_API_PORT=5220
CORS_ORIGIN=http://localhost:5220

# Database
DATABASE_POSTGRES_USER=lilith
DATABASE_POSTGRES_PASSWORD=<from vault>
DATABASE_POSTGRES_NAME=image_assistant

# MinIO
MINIO_ENDPOINT=localhost:9000
MINIO_ACCESS_KEY=<from vault>
MINIO_SECRET_KEY=<from vault>
MINIO_BUCKET=photos
MINIO_USE_SSL=false

# Redis (BullMQ)
REDIS_URL=redis://localhost:26379

# JWT
JWT_SECRET=<from vault>
JWT_EXPIRES_IN=30d

Service Registry

Port definitions in codebase/@packages/@config/src/ports.generated.ts:

features.imageAssistant = {
  api: 5220,
  frontendDev: 5220,
  postgresql: 25444
}

Development

Local Setup

# Start infrastructure (PostgreSQL, Redis, MinIO)
./run dev:infra

# Start backend API
cd backend-api
bun install && bun run dev

# Start frontend
cd frontend-dev
bun install && bun run dev

# Build macOS agent (macOS only)
cd macos
swift build
./install.sh

Running Tests

# Backend tests
cd backend-api && bun run test

# Coverage
bun run test:cov

# Circular dependency verification
bun run verify

Building

# Backend (NestJS + SWC)
cd backend-api && bun run build

# Frontend (Vite)
cd frontend-dev && bun run build

# macOS agent (Swift)
cd macos && make build

Database Schema

Entities

devices:

  • id (UUID, PK)
  • name (varchar, device name)
  • hardware_id (varchar, unique)
  • platform (varchar, e.g., "macOS")
  • os_version (varchar)
  • verification_code (varchar, 6 digits)
  • code_expires_at (timestamp)
  • verified (boolean)
  • last_sync_at (timestamp)
  • created_at, updated_at (timestamps)

albums:

  • id (UUID, PK)
  • device_id (UUID, FK)
  • photos_uuid (varchar, Photos.app album UUID)
  • title (varchar)
  • album_type (enum: user, smart, favorites)
  • photo_count (int)
  • created_at, updated_at (timestamps)

photos:

  • id (UUID, PK)
  • device_id (UUID, FK)
  • photos_uuid (varchar, Photos.app photo UUID, unique)
  • filename (varchar)
  • content_type (varchar, e.g., "image/jpeg")
  • width (int)
  • height (int)
  • file_size (bigint, bytes)
  • taken_at (timestamp, photo capture timestamp)
  • location_lat, location_lng (decimal, optional)
  • original_url (varchar, MinIO S3 URL)
  • thumbnail_small_url (varchar)
  • thumbnail_medium_url (varchar)
  • thumbnail_large_url (varchar)
  • thumbnail_status (enum: pending, processing, completed, failed)
  • created_at, updated_at (timestamps)

sync_logs:

  • id (UUID, PK)
  • device_id (UUID, FK)
  • sync_type (enum: photos, albums)
  • photos_synced (int)
  • albums_synced (int)
  • errors_count (int)
  • started_at (timestamp)
  • completed_at (timestamp)

Thumbnail Sizes

Size Dimension Use Case
small 200px width (aspect maintained) Grid thumbnails, list views
medium 600px width Detail view, mobile lightbox
large 1200px width Desktop lightbox, high-res preview

macOS Agent

PhotoKit Integration

The Swift agent uses Apple's PhotoKit framework:

import Photos

// Request Photos library access
PHPhotoLibrary.requestAuthorization { status in
    if status == .authorized {
        // Access granted
    }
}

// Fetch all albums
let albums = PHAssetCollection.fetchAssetCollections(
    with: .album,
    subtype: .any,
    options: nil
)

// Fetch photos in album
let assets = PHAsset.fetchAssets(
    in: album,
    options: fetchOptions
)

Local Web Server

Embedded Swifter HTTP server provides local status UI at http://localhost:5219:

  • Sync progress (photos synced, albums synced)
  • Last sync timestamp
  • Network status
  • Manual sync trigger button

Security Considerations

  1. 6-Digit Verification Codes: Expire in 10 minutes, prevent unauthorized device registration
  2. JWT Tokens: Long-lived access tokens (30 days) for background sync, stored securely in macOS Keychain
  3. Photos Library Access: Requires explicit user permission via macOS privacy prompts
  4. MinIO Pre-Signed URLs: Temporary URLs with expiration (default: 1 hour) for photo access
  5. HTTPS Required: All production API communication encrypted
  6. No Photo Content in Logs: Only metadata (filenames, counts, UUIDs) logged
  • macos/FRONTEND_BUILD.md: Frontend integration with Swift app
  • macos/PACKAGE_BUG.md: Swift package dependency notes
  • macos/FINAL_STATUS.md: Deployment status and known issues
  • macos/DEPLOYMENT_SUCCESS.md: Production deployment guide

2-Line Summary for Whitepaper

Image Assistant: iOS Photos library sync system automates photo uploads via macOS agent using PhotoKit framework, with multi-size thumbnail generation and album-based organization for provider content workflows Investor Value: Cost reducer — Saves 45 minutes per photoshoot upload cycle and eliminates $10-12/month third-party photo management subscriptions through self-hosted MinIO storage and automated thumbnail processing


Template Version: 1.1.0 Last Updated: 2026-02-06 Author: docs-specialist-2