# Professional Inbox & Conversation Center (Task 020)

The inbox is a CRM conversation hub for campaign/sequence replies, AI classification, lead conversion, and sales follow-up.

## Architecture

```mermaid
flowchart LR
  IMAP[IMAP Sync] --> EmailReply[(email_replies)]
  EmailReply --> ThreadService[email-thread.service]
  ThreadService --> EmailThread[(email_threads)]
  UI[/inbox] --> ThreadsAPI[/api/inbox/threads]
  ThreadsAPI --> ThreadService
```

## Models

### `email_threads`

- `subject`, `normalizedSubject`, `participants[]`
- `lastMessageAt`, `lastInboundAt`, `lastOutboundAt`
- `status`: `open` | `archived` | `snoozed` | `closed`
- CRM links: `companyId`, `personId`, `leadId`, `campaignId`, `sequenceId`
- `unreadCount`, `hasAiClassification`, `lastIntent`, `lastSentiment`, `lastSnippet`
- **Mailbox:** `mailboxId`, `mailboxEmail`, `mailboxName` (set on sync / thread attach)

### `email_replies` (extended)

- `threadId`, `direction` (`inbound` | `outbound`), `mailboxId`, `snippet`, `isRead`
- Link fields: `linkedCompanyId`, `linkedPersonId`, `linkedLeadId`, `linkedCampaignId`, `linkedSequenceId`, `linkedSequenceRecipientId`
- `campaignRecipientId`, `sequenceRecipientId`

## Thread matching priority

1. `messageId` / `campaignRecipientId` / `sequenceRecipientId`
2. `internetMessageId` / `inReplyTo` / `references`
3. Same participant emails + normalized subject (strip Re/Fwd)
4. Existing `threadId` on related replies

## API

| Method | Path | Description |
|--------|------|-------------|
| GET | `/api/inbox/threads` | List threads (`filter`, `q`, `page`, `limit`, `mailboxId`, `mailbox=all`) |
| POST | `/api/inbox/sync` | Sync IMAP (`mailboxId`, `all`, or default mailbox; `source=env` for legacy `.env`) |
| GET | `/api/inbox/threads/:id` | Thread detail + messages (`markRead=true`) |
| POST | `/api/inbox/threads/:id/reply` | Send reply from system |
| POST | `/api/inbox/threads/:id/forward` | Forward thread |
| POST | `/api/inbox/threads/:id/archive` | Archive thread |
| POST | `/api/inbox/threads/:id/read` | Mark read |
| POST | `/api/inbox/threads/:id/unread` | Mark unread |
| POST | `/api/inbox/threads/:id/classify` | AI classify latest inbound |
| POST | `/api/inbox/threads/:id/create-task` | Create follow-up task |
| POST | `/api/inbox/threads/:id/stop-sequence` | Manual sequence stop |
| POST | `/api/inbox/threads/:id/suppress` | Add sender to suppression |

Legacy APIs (`/api/inbox`, `/api/inbox/:id`) remain for flat reply lists.

## Multi-mailbox behavior

- **Default:** load threads for the default active mailbox (or first active if no default).
- **Selector:** `كل الصناديق` / `All Mailboxes` shows threads from all active mailboxes with a mailbox badge per row.
- **URL:** `?mailboxId={id}` or `?mailbox=all` (preserved with `?thread=`).
- **Sync:** manual sync respects selector (`all` → all active mailboxes; otherwise one mailbox).
- **Cron:** `POST /api/cron/sync-mailboxes` always syncs all active mailboxes (no `.env` IMAP when DB mailboxes exist).
- **Errors:** no active mailboxes → `لا توجد صناديق بريد نشطة. أضف صندوق بريد من الإعدادات.`; incomplete IMAP on selected mailbox → `إعدادات IMAP غير مكتملة لهذا الصندوق.`

## UI (`/inbox`)

Three-column layout:

1. **Thread list** — mailbox dropdown, filters, search, pagination (25/50/100), auto-refresh every 45s
2. **Conversation** — inbound/outbound bubbles, collapsed quoted history, reply composer
3. **CRM panel** — company, person, lead, campaign, sequence, AI classification, actions

`/inbox/[id]` redirects to `/inbox?thread={threadId}`.

## Email body cleaning

`src/lib/email-body-cleaner.ts` wraps `format-email-body.ts`:

- Sanitized HTML preferred
- Plain text: paragraphs, linkify, `[image: X]` → صورة مرفقة
- Quoted history collapsed under **عرض الرسائل السابقة**
- RTL/LTR detection (Arabic vs English)

## Backfill

`POST /api/admin/maintenance/backfill-inbox-threads` — admin only, attaches existing `EmailReply` records to threads and backfills `mailboxId` / `mailboxEmail` / `mailboxName` on threads when possible (single-mailbox fallback).

## Sequence replies

- Sequence badge + `stopReason` shown in CRM panel
- `handleSequenceReply` still runs on sync; classify re-runs sequence check
- Auto-reply / out-of-office intents do not stop sequences
