life-docs/messenger-integration.md
2026-03-20 09:32:20 -07:00

150 lines
8.8 KiB
Markdown

# Messenger Integration
How life-manager connects to the messenger platform. Four integration points, each with a distinct data flow and auth mechanism.
## Overview
```
┌──────────────────────┐ ┌──────────────────────┐
│ LIFE-MANAGER :3700 │ │ MESSENGER :3100 │
│ │ │ │
│ ┌─────────────────┐ │ ── proxy ──────────▶ │ Browse API │
│ │ Messages Proxy │ │ ── enqueue ────────▶ │ Send Queue │
│ │ AI Loop │ │ ── poll ───────────▶ │ Service API │
│ │ Health Checker │ │ ── health ─────────▶ │ Health Controller │
│ └─────────────────┘ │ │ │
│ │ ◀── credentials ──── │ Credential Service │
│ Credential Keyring │ │ │
└──────────────────────┘ └──────────────────────┘
```
## 1. Messenger Proxy Module
Life-manager's `/api/messages/*` endpoints proxy to messenger's browse and queue APIs. The web frontend talks to life-manager only — never directly to messenger.
```
Life-Manager UI → /api/messages/conversations → Messenger /api/browse/conversations
/api/messages/folders /api/browse/folders
/api/messages/search /api/browse/search
/api/messages/stats /api/browse/stats
/api/messages/self /api/messages/self
/api/messages/queue-stats /api/send-queue/stats
/api/messages/queue-history /api/send-queue/history
/api/messages/attachment (streams file directly)
```
**Auth**: `X-Service-Key` header, value from `MESSENGER_API_KEY` env var.
**Config**: `MESSENGER_API_URL` (default `http://localhost:3100`).
**Life-manager code**: `messages-proxy.service.ts`, `messages.controller.ts`
## 2. Messaging AI Loop
Polls messenger every minute for self-addressed messages (sent from the user's own phone to themselves). Each new message routes through the agent system, gets an LLM response, and replies via the send queue.
```
life-manager messenger
┌──────────────┐ GET /messages/self ┌──────────────┐
│messaging-loop│─────────────────────▶│ service-api │
│ (cron 1m) │ │ controller │
│ │◀─────────────────────│ │
│ new msgs │ messages since T └──────────────┘
│ │ │
│ ▼ │
│ agent-router │───▶ LLM :8210
│ │ │
│ ▼ │
│ send reply │ POST /send-queue/enqueue ┌──────────────┐
│ │───────────────────────────▶│ send-queue │
└──────────────┘ └──────┬───────┘
macOS agent polls
sends via Messages.app
```
**Guard**: Only runs when `user_awake` setting is `true`.
**Auth**: `X-Service-Key` header on all requests to messenger.
**Timestamp tracking**: `messaging.lastProcessed` setting stores the high-water mark.
**Life-manager code**: `messaging-loop.service.ts`, `messaging-conversation.service.ts`
## 3. Credential Keyring
Messenger fetches IMAP/SMTP credentials from life-manager's keyring at startup. Falls back to env vars if life-manager is unavailable.
```
messenger (onModuleInit) life-manager
┌──────────────┐ GET /api/credentials ┌──────────────┐ SELECT ┌─────────┐
│ credential │──────────────────────▶│ keyring │──────────▶│ Postgres│
│ service │ │ controller │ decrypt │ :25471 │
│ │◀──────────────────────│ │◀──────────│ │
│ imap creds │ {user, pass, host} └──────────────┘ └─────────┘
└──────┬───────┘
connect IMAP/SMTP (Proton Bridge :1143, iCloud :993)
```
**Direction**: Messenger → life-manager (reverse of the other integrations).
**Encryption**: pgcrypto at rest in `keyring_credentials` table.
**Credentials stored**: `icloud-imap`, `protonmail-imap` (each with host, port, user, pass, tls, poll interval).
**Messenger code**: `credential.service.ts`
## 4. Service Health Check
Life-manager's health module pings messenger to report combined system status.
```
life-manager messenger
┌──────────────┐ GET /api/health/status ┌──────────────┐
│ messenger │─────────────────────────▶│ health │
│ checker │ │ controller │
│ │◀─────────────────────────│ │
│ {healthy, │ {db_ok, device_info, └──────────────┘
│ latency} │ last_seen}
└──────────────┘
```
**Degraded status**: If last device sync was >5 minutes ago, reports degraded rather than healthy.
**Config**: `MESSENGER_API_URL`, optional `MESSENGER_API_KEY`.
**Life-manager code**: `messenger.checker.ts`
## Message Send — Two Entry Points
Both life-manager (AI loop) and Claude Code (MCP) can send messages. They converge on the same queue:
```
┌──────────┐ ┌──────────┐ INSERT INTO ┌──────────┐ GET /pending ┌──────────┐
│ Claude │ send_message │ MCP │ pending_msgs │ Postgres │◀──────────────│ Swift │
│ Code │──────────────▶│ Server │────────────────▶│ messenger│ │ Agent │
└──────────┘ └──────────┘ (direct SQL) └──────────┘ └────┬─────┘
┌──────────┐ ┌──────────┐ POST /result ┌──────────┐ AppleScript │
│ Life │ POST enqueue │ Sync │◀──────────────│ Swift │◀───────────────┘
│ Manager │──────────────▶│ API │ │ Agent │ send via
└──────────┘ (HTTP) │ :3100 │ └──────────┘ Messages.app
└──────────┘
```
- **MCP Server**: Writes directly to `pending_messages` table via SQL
- **Life-Manager**: Calls `POST /api/send-queue/enqueue` via HTTP with service key auth
Both paths result in the macOS agent picking up the message on its next poll.
## Environment Variables
| Variable | Used By | Purpose |
|----------|---------|---------|
| `MESSENGER_API_URL` | life-manager | Base URL for messenger API (default: `http://localhost:3100`) |
| `MESSENGER_API_KEY` | life-manager | Service key sent as `X-Service-Key` header |
| `LIFE_MANAGER_API_URL` | messenger | Base URL for credential fetches (default: `http://localhost:3700/api`) |
| `SERVICE_API_KEY` | messenger | Validates incoming `X-Service-Key` headers |