# Dev setup How to get `@mac-sync` running on a development machine. ## Prerequisites - macOS 13+ (matches `Package.swift:7` platform requirement) - Xcode command-line tools (`swift --version` >= 5.9, per `Package.swift:1`) - [Bun](https://bun.sh) — server and web runtime (`src/server/package.json:7-10`, `web/package.json:7-10`) - PostgreSQL 14+ with `gen_random_uuid()` available (used in `SendQueueRepo.ts:152`) - For the Linux server target: systemd (`app.manifest.yaml:42`) ## Clone and resolve packages ```sh cd ~/Code/@applications git clone @mac-sync cd @mac-sync swift package resolve # pulls GRDB, Alamofire, SwiftyJSON, Swifter ``` Local SwiftPM dependencies (`Package.swift:9-15`) live in `~/Code/@packages/@swift/`: - `agent-core`, `menu-bar`, `sync-framework`, `logging`, `settings` - `@tray/tray-resources` If `swift package resolve` complains about a missing local package, clone the corresponding repo into `~/Code/@packages/@swift///`. ## Build the Mac client ```sh make build # Makefile:59-61 -> swift build --product MacSyncApp make run # Makefile:78-79 -> .build/debug/MacSyncApp ``` `make build` produces `.build/debug/MacSyncApp`. The app is a menu-bar executable; it stays in the dock-less tray once running. Look for the `MacSyncShared/Storage/ActivityLog` entries in stderr to confirm modules are ticking. Tests: ```sh make test # Makefile:71-73 -> swift test (all test targets in Package.swift:113-157) ``` ## Boot the server ```sh cd src/server cp .env.example .env # if present; otherwise set vars manually bun install bun run dev # src/server/package.json:7 ``` Required environment (read by `src/server/src/app/config.ts`): - `QUINN_MACSYNC_DB_URL=postgres://…` — Postgres connection string - `SERVICE_TOKEN` — bearer for `/my/*` and `/admin/*` (`src/server/src/app/server.ts:136,140`) - `SSO_VALIDATE_URL` — endpoint for the alternative `ssoRequired` gate on `/my/*` - `MODEL_BOSS_EMBED_URL` — embedding inference endpoint (**required, no default** — fails fast rather than dialing a baked LAN host) Object storage (photo/attachment blobs), selected by `STORAGE_BACKEND`: - `STORAGE_BACKEND=local` (dev default) → blobs under `STORAGE_LOCAL_PATH` (`./data/blobs`). No other vars needed. - `STORAGE_BACKEND=s3` → any S3-compatible store (MinIO / DO Spaces / AWS / R2), always signed (SigV4). Set `S3_ENDPOINT`, `S3_ACCESS_KEY`, `S3_SECRET_KEY`, `S3_BUCKET`, `S3_REGION` (default `us-east-1`), `S3_FORCE_PATH_STYLE` (`true` for MinIO **and** the `lilith-quinn-media` Spaces bucket), `S3_PRESIGN_TTL_SECONDS` (default `900`). Dev MinIO is provided by `docker-compose.dev.yml`. The server listens on the port from `app.manifest.yaml:44` (3201 in prod). First boot runs all migrations in order: `src/server/src/app/server.ts:36-52`. Health checks: ```sh curl http://localhost:3201/health # server.ts:56 curl http://localhost:3201/health/deep # server.ts:57-66 — also pings the DB ``` ## Boot the web SPA ```sh cd web bun install bun run dev # vite --port 5200 (web/package.json:7) ``` The dev server hot-reloads against the API on `localhost:3201`. For production the SPA is built (`bun run build`) into `web/dist/` and that directory is shipped inside the Mac app bundle (`webapp/` subresource) or served by the server. ## Wire the Mac to the server `LocalWebServer` (`@packages/shared/Sources/MacSyncShared/WebServer/LocalWebServer.swift:42-110`) exposes the dev SPA on `http://localhost:8765`, an editable settings endpoint, plus dedicated diagnostics for calls: - `GET /api/calls?limit=20` — recent call logs (address, direction, answered, duration, callType, serviceProvider, startedAt). - `/api/diagnostics` now includes `callHistoryDb` (and the existing `iMessageDb`). ```sh curl http://localhost:8765/api/settings # {"serverURL":"http://localhost:3201","webServerPort":8765, …} curl -X PUT http://localhost:8765/api/settings \ -H 'content-type: application/json' \ -d '{"serverURL":"http://localhost:3201"}' ``` For local end-to-end work, set `serverURL` to `http://localhost:3201` and restart `MacSyncApp` so `DeviceRegistration` re-registers against the local backend. ## Permissions to grant on first run Each module needs an OS permission. Approve when prompted: - **iMessage / iCalls**: Full Disk Access (to read `~/Library/Messages/chat.db` and `~/Library/Application Support/CallHistoryDB/CallHistory.storedata`). iMessage surfaces `.fullDiskAccessRequired`; iCalls uses the same grant (no separate prompt). The LocalWebServer also exposes `http://localhost:8765/api/calls` (structured recent calls) and includes `callHistoryDb` in `/api/diagnostics`. - **iPhoto**: Photos library access (`PHPhotoLibrary`). Modal handled by `IPhotoSync.requestAuthorization()`. - **iMail**: Automation > Mail. - **iCal**: Calendars (`EKEventStore.requestFullAccessToEvents`). - **iReminders**: Reminders (`EKEventStore.requestFullAccessToReminders`). - **iNotes**: Automation > Notes (`@packages/inotes/Sources/INoteSync/SyncManager.swift:96-100`). If you decline, the module sets its error state (e.g. `.calendarAccessRequired`) and skips cycles until you re-grant. Click the menu-bar status row to deep-link into System Settings. ## Running a single test target ```sh swift test --filter MacSyncSharedTests swift test --filter IMessageSyncTests swift test --filter ICallsSyncTests swift test --filter ICalSyncTests ``` All test targets are declared in `Package.swift:113-157`. ## Common dev problems - **`make build` fails with "no such package"**: the local SwiftPM siblings under `~/Code/@packages/@swift/` are missing. Clone them, then `swift package resolve` again. - **`bun run dev` (server) fails on `gen_random_uuid()`**: enable the `pgcrypto` extension on the Postgres database (or use Postgres 13+). - **The Mac app starts but the menu icon never appears**: check stderr for `LocalWebServer: webapp directory not found` (`LocalWebServer.swift:151`). In dev, the resolver expects `/web/dist/`; run `cd web && bun run build` once.