macsync/docs/modules/icalls.md
Natalie 576496ca3e feat(deploy): video-projects FUSE mount over DO Spaces
Generalize the photos-originals rclone-mount pattern to a video-projects
prefix so the video studio (and imajin ETL, per storage-portability-plan
§2.3) can read/write multi-GB project sources/renders as local files while
only hot data stays resident on plum (bounded VFS LRU cache). Lets a
small-disk laptop work with large footage without filling APFS.

Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
2026-06-28 21:10:13 -04:00

2.5 KiB

iCalls (ICallsSync)

Purpose

Ingest macOS call history (Phone/FaceTime) into the server for timelines, recent activity, and correlation with messages/contacts/prospects.

Direction

Read-only. Call logs are append-only records emitted by the system; there is no Sender or send queue.

OS surface

~/Library/Application Support/CallHistoryDB/CallHistory.storedata (and legacy ~/Library/CallHistoryDB/CallHistory.storedata).

Direct readonly SQLite via GRDB (Core Data schema: ZCALLRECORD, ZUNIQUE_ID, ZDATE as Apple reference time, ZADDRESS, ZORIGINATED, ZANSWERED, ZDURATION, ZCALLTYPE, ZSERVICE_PROVIDER, ZNAME).

com.apple.security.files.all entitlement (already present for chat.db) is sufficient. No extra TCC prompt beyond Full Disk Access.

Files

  • Reader.swiftCallHistoryReader:
    • Tries current then legacy path.
    • fetchCalls(since: Date?) — filters on ZDATE > ref, oldest-first.
    • Timestamp conversion: Date(timeIntervalSinceReferenceDate:).
    • Basic CNContact enrichment for display names when ZNAME absent (best-effort).
    • Uses PhoneUtils.normalize.
  • APIClient.swift:
    • syncCalls(_:)POST /client/icalls/sync
    • getStats()GET /client/icalls/stats
  • SyncManager.swift — 120s read interval (per operator request), no send queue hooks. Batches of 200. Simple syncedThisSession + total from server.

Timing

  • Read interval: 120s (@packages/icalls/Sources/ICallsSync/SyncManager.swift).

Server

  • Entity: macsync.calls (dedicated table, not mixed into messages). Unique on (device_id, external_id).
  • Ingest: features/icalls/ingestCalls (dedup + upsert).
  • Queries: /my/calls (filter by deviceId, direction, callType) + /my/calls/stats.
  • Client ingest: /client/icalls/sync + /stats (wrapped in sync-history 'call').
  • Web tab: basic recent-calls list (no web writes).

Web

  • web/src/api/calls.ts
  • web/src/tabs/Calls/index.tsx
  • Registered under /calls in App + nav.

Known characteristics

  • First sync backfills available history (can be thousands of rows; rows are tiny).
  • ZUNIQUE_ID (or synthetic zpk:<Z_PK>) is the stable external id.
  • Multi-party FaceTime participants live in join tables (Z_2REMOTEPARTICIPANTHANDLES + ZHANDLE); v1 surfaces primary ZADDRESS only.
  • Duration 0 + unanswered often indicates missed/ringing-out attempts.

Adding / extending

Follow the read-only path in docs/adding-a-module.md (no send queue / Sender / admin send routes). Add columns or participant join expansion in a follow-up migration if needed.