# iPhoto (`IPhotoSync`)

## Purpose

Sync the user's Photos library metadata to the server and upload binaries on
demand.

## Direction

Read-only Mac to server. There is no Sender; the web cannot push photos back.
See the rationale in [known-limitations](../known-limitations.md#iphoto-has-no-sender).

## OS surface

PhotoKit (`PhotosUI`/`Photos.framework`). Requires Photos library access
prompted by `IPhotoSync.requestAuthorization()`
(`@packages/iphoto/Sources/IPhotoSync/SyncManager.swift:118-120, 122-124`).

## Files

- `Reader.swift` — `PhotosLibraryReader.shared`; enumerates assets and albums
  via `PHAsset` / `PHAssetCollection`.
- `APIClient.swift` — metadata sync, binary upload, stats
  (`@packages/iphoto/Sources/IPhotoSync/APIClient.swift:129-240`):
  - `syncPhotos`, `syncAlbums`
  - `getPendingUploads` -> `uploadPhoto` (data-in-memory) or `uploadPhotoFromURL` (streamed)
  - `getStats`
- `SyncManager.swift` — orchestrates metadata sync, then a bounded-concurrency
  upload pass: `metadataBatchSize = 100`, `maxConcurrentUploads = 4`
  (`@packages/iphoto/Sources/IPhotoSync/SyncManager.swift:90-92`).
- No `Sender.swift`.

## Timing

- Read interval: **300s**
  (`@packages/iphoto/Sources/IPhotoSync/SyncManager.swift:99`).
- Metadata batch size: 100.
- Max concurrent uploads: 4.

## Server surface

- Entity tables: `icloud.albums`, `icloud.photos`
  (`src/server/src/app/server.ts:42-43`).
- Client routes (`src/server/src/surfaces/client/iphoto.ts`):
  - `GET /client/iphoto/stats` (line 53)
  - `GET /client/iphoto/upload/pending` (line 58)
  - `POST /client/iphoto/sync` (line 63)
  - `POST /client/iphoto/albums` (line 69)
  - `POST /client/iphoto/upload/:localIdentifier` (line 75)
- Web routes (`src/server/src/surfaces/my/photos.ts`):
  - `GET /my/photos/` (line 12)
  - `GET /my/photos/albums` (line 18)
  - `GET /my/photos/albums/:albumId` (line 22)
- No admin send-queue surface.

## Web surface

- Tab: `/photos` (`web/src/App.tsx:58`).
- API helpers: `web/src/api/photos.ts`.

## Known limitations

- No outbound path; web cannot add to the library. See
  [known-limitations](../known-limitations.md#iphoto-has-no-sender).
- `uploadRate` / `bytesUploaded` statistics reset on every cold start; per
  [known-limitations](../known-limitations.md#iphotostatsuploadrate-is-per-session-only).
- No facial recognition or content-type extraction; the server stores the
  asset and basic metadata only.

## Tests (`@packages/iphoto/Tests/IPhotoSyncTests/`)

- `ReaderTests.swift` — exercises `PhotosLibraryReader` helpers that don't
  need a populated library.
- `SyncStatsTests.swift` — `uploadRate`/`eta` formulas
  (`@packages/iphoto/Sources/IPhotoSync/SyncManager.swift:22-46`).

Not covered: actual PhotoKit enumeration, binary upload (both need the OS).
