Концепции, ценность и типичные сценарии клонирования — меньше кода.
Концепции, ценность и типичные сценарии клонирования — меньше кода.
Preparing Ring content
Preparing Ring content
Preparing Ring content
Все маршруты /api/admin/email/* требуют аутентифицированной сессии platform admin (роль admin или superadmin).
Интерфейс обзора: /admin/crm/* (CrmAdminShell). API остаются на /api/admin/email/* — см. Email AI-CRM.
/api/cron/* и /api/webhooks/email/inbound используют CRON_SECRET или WEBHOOK_EMAIL_SECRET — не user session. Без секрета закрываются по умолчанию.
Отправка черновика использует EmailSenderService + SMTP канала (CRM_CHANNEL_*). Auth OTP использует lib/mailer.ts / SMTP_*. Не путайте их в операционных процедурах.
GET /api/admin/email/channelsТолько для чтения: статус CRM-каналов (без паролей). Используется для фильтрации почтовых ящиков во UI.
Ответ:
{
"channels": [
{
"id": "primary",
"name": "Primary",
"flow": "standard",
"mailbox": "INBOX",
"imapHost": "mail.ringdom.org",
"imapUser": "info@ringdom.org",
"smtpHost": "mail.ringdom.org",
"smtpUser": "info@ringdom.org",
"hasImapPassword": true,
"hasSmtpPassword": true
}
],
"validation": { "ok": true, "errors": [] }
}Реализация: loadCrmChannels() и validateCrmChannels() из features/email-crm/pipeline/imap/config.ts.
GET /api/admin/email/threadsСписок тредов переписки.
| Query | Type | Описание |
|---|---|---|
status | string | Фильтр: new, ongoing, waiting, resolved или все |
sourceChannel | string | Фильтровать по id/name канала (многопочтовый ящик) |
Ответ: { threads: EmailThreadRecord[] }
PATCH /api/admin/email/threadsОбновить статус треда.
Тело: { "id": "<threadId>", "status": "resolved" }
GET /api/admin/email/threads/[id]Детали треда с сообщениями, черновиками и открытыми задачами.
Ответ: { thread, messages, drafts, tasks }
GET /api/admin/email/draftsОжидающие черновики (status: pending), отсортированы по времени (новые выше).
POST /api/admin/email/drafts/[id]/approveУтвердить черновик к отправке. В reviewer сохраняется id текущего пользователя-сессии.
POST /api/admin/email/drafts/[id]/rejectТело: { "reason": "опциональная строка" }
POST /api/admin/email/drafts/[id]/sendОтправка утверждённого черновика через CRM SMTP-канал (EmailSenderService).
Тело (опционально): { "toEmail": "...", "subject": "..." } — по умолчанию из треда.
Ответ: { "success": true, "messageId": "<smtp-message-id>" }
Запись сохраняется в email_messages, статус треда обновляется на waiting.
GET /api/admin/email/contacts| Query | Описание |
|---|---|
email, name, company, type | Фильтры поиска |
POST /api/admin/email/contactsТело: { "email": "обяз.", "name?", "company?", "type?" }
GET /api/admin/email/tasks| Query | Описание |
|---|---|
status | open, in_progress, overdue, completed и др. |
POST /api/admin/email/tasksТело: { "threadId", "title", "taskType", ... } — см. TaskCreateInput из task-service.ts.
POST /api/admin/email/tasks/[id]/completeТело: { "completionNotes?": "string" }
GET /api/admin/email/analytics| Query | Значения |
|---|---|
range | 7d (по умолч.), 30d, 90d |
Ответ: распределение intent/sentiment, costStats из email_api_usage, dailyStats, черновики/задачи.
POST или GET /api/cron/email-processorАутентификация: Authorization: Bearer $CRON_SECRET (без секрета — отказ)
Тело запроса или query-параметр action:
| Action | Действие |
|---|---|
poll (по умолч.) | pollInboundBatch() — загрузка UNSEEN на каждом канале, обработка, disconnect |
status | Статус обработчика и IMAP (getEmailProcessor()) |
stop | Остановить IDLE слушатель |
start | Запустить IDLE (EMAIL_PROCESSOR_ALLOW_HTTP_START=true) |
mark-overdue-tasks | Запуск EmailTaskService.processOverdueTasks() |
На каждый action создаётся новый обработчик (Processor), нет постоянно работающего глобального экземпляра.
Пример:
GET /api/cron/email-analytics7-дневный срез дашборда (структура — как admin analytics). Только по cron-авторизации.
GET/POST /api/cron/cleanup-email-tokens — чистка просроченных email_login_tokens. Такой же fail-closed по CRON_SECRET. Документировано в Ring Mailer, не относится к Email CRM напрямую.
POST /api/webhooks/email/inboundАвторизация: Authorization: Bearer $WEBHOOK_EMAIL_SECRET или HMAC-SHA256 hex в X-Email-Webhook-Signature по сырому телу.
Тело запроса (JSON):
Вызывает EmailProcessor.ingestEvent() c uid: 0 (IMAP-пометка как “прочитано” не ставится).
Предпосылки: настройка операторов, секреты каналов, Auth vs CRM SMTP.
Детальный разбор: EmailProcessor и persistance через jsonb-collection.
Использование: локальный poll + smoke-тест отправки черновика.
См. также: Auth cleanup-email-tokens cron и SMTP_* плоскость.
Все маршруты /api/admin/email/* требуют аутентифицированной сессии platform admin (роль admin или superadmin).
Интерфейс обзора: /admin/crm/* (CrmAdminShell). API остаются на /api/admin/email/* — см. Email AI-CRM.
/api/cron/* и /api/webhooks/email/inbound используют CRON_SECRET или WEBHOOK_EMAIL_SECRET — не user session. Без секрета закрываются по умолчанию.
Отправка черновика использует EmailSenderService + SMTP канала (CRM_CHANNEL_*). Auth OTP использует lib/mailer.ts / SMTP_*. Не путайте их в операционных процедурах.
GET /api/admin/email/channelsТолько для чтения: статус CRM-каналов (без паролей). Используется для фильтрации почтовых ящиков во UI.
Ответ:
{
"channels": [
{
"id": "primary",
"name": "Primary",
"flow": "standard",
"mailbox": "INBOX",
"imapHost": "mail.ringdom.org",
"imapUser": "info@ringdom.org",
"smtpHost": "mail.ringdom.org",
"smtpUser": "info@ringdom.org",
"hasImapPassword": true,
"hasSmtpPassword": true
}
],
"validation": { "ok": true, "errors": [] }
}Реализация: loadCrmChannels() и validateCrmChannels() из features/email-crm/pipeline/imap/config.ts.
GET /api/admin/email/threadsСписок тредов переписки.
| Query | Type | Описание |
|---|---|---|
status | string | Фильтр: new, ongoing, waiting, resolved или все |
sourceChannel | string | Фильтровать по id/name канала (многопочтовый ящик) |
Ответ: { threads: EmailThreadRecord[] }
PATCH /api/admin/email/threadsОбновить статус треда.
Тело: { "id": "<threadId>", "status": "resolved" }
GET /api/admin/email/threads/[id]Детали треда с сообщениями, черновиками и открытыми задачами.
Ответ: { thread, messages, drafts, tasks }
GET /api/admin/email/draftsОжидающие черновики (status: pending), отсортированы по времени (новые выше).
POST /api/admin/email/drafts/[id]/approveУтвердить черновик к отправке. В reviewer сохраняется id текущего пользователя-сессии.
POST /api/admin/email/drafts/[id]/rejectТело: { "reason": "опциональная строка" }
POST /api/admin/email/drafts/[id]/sendОтправка утверждённого черновика через CRM SMTP-канал (EmailSenderService).
Тело (опционально): { "toEmail": "...", "subject": "..." } — по умолчанию из треда.
Ответ: { "success": true, "messageId": "<smtp-message-id>" }
Запись сохраняется в email_messages, статус треда обновляется на waiting.
GET /api/admin/email/contacts| Query | Описание |
|---|---|
email, name, company, type | Фильтры поиска |
POST /api/admin/email/contactsТело: { "email": "обяз.", "name?", "company?", "type?" }
GET /api/admin/email/tasks| Query | Описание |
|---|---|
status | open, in_progress, overdue, completed и др. |
POST /api/admin/email/tasksТело: { "threadId", "title", "taskType", ... } — см. TaskCreateInput из task-service.ts.
POST /api/admin/email/tasks/[id]/completeТело: { "completionNotes?": "string" }
GET /api/admin/email/analytics| Query | Значения |
|---|---|
range | 7d (по умолч.), 30d, 90d |
Ответ: распределение intent/sentiment, costStats из email_api_usage, dailyStats, черновики/задачи.
POST или GET /api/cron/email-processorАутентификация: Authorization: Bearer $CRON_SECRET (без секрета — отказ)
Тело запроса или query-параметр action:
| Action | Действие |
|---|---|
poll (по умолч.) | pollInboundBatch() — загрузка UNSEEN на каждом канале, обработка, disconnect |
status | Статус обработчика и IMAP (getEmailProcessor()) |
stop | Остановить IDLE слушатель |
start | Запустить IDLE (EMAIL_PROCESSOR_ALLOW_HTTP_START=true) |
mark-overdue-tasks | Запуск EmailTaskService.processOverdueTasks() |
На каждый action создаётся новый обработчик (Processor), нет постоянно работающего глобального экземпляра.
Пример:
GET /api/cron/email-analytics7-дневный срез дашборда (структура — как admin analytics). Только по cron-авторизации.
GET/POST /api/cron/cleanup-email-tokens — чистка просроченных email_login_tokens. Такой же fail-closed по CRON_SECRET. Документировано в Ring Mailer, не относится к Email CRM напрямую.
POST /api/webhooks/email/inboundАвторизация: Authorization: Bearer $WEBHOOK_EMAIL_SECRET или HMAC-SHA256 hex в X-Email-Webhook-Signature по сырому телу.
Тело запроса (JSON):
Вызывает EmailProcessor.ingestEvent() c uid: 0 (IMAP-пометка как “прочитано” не ставится).
Предпосылки: настройка операторов, секреты каналов, Auth vs CRM SMTP.
Детальный разбор: EmailProcessor и persistance через jsonb-collection.
Использование: локальный poll + smoke-тест отправки черновика.
См. также: Auth cleanup-email-tokens cron и SMTP_* плоскость.
Все маршруты /api/admin/email/* требуют аутентифицированной сессии platform admin (роль admin или superadmin).
Интерфейс обзора: /admin/crm/* (CrmAdminShell). API остаются на /api/admin/email/* — см. Email AI-CRM.
/api/cron/* и /api/webhooks/email/inbound используют CRON_SECRET или WEBHOOK_EMAIL_SECRET — не user session. Без секрета закрываются по умолчанию.
Отправка черновика использует EmailSenderService + SMTP канала (CRM_CHANNEL_*). Auth OTP использует lib/mailer.ts / SMTP_*. Не путайте их в операционных процедурах.
GET /api/admin/email/channelsТолько для чтения: статус CRM-каналов (без паролей). Используется для фильтрации почтовых ящиков во UI.
Ответ:
{
"channels": [
{
"id": "primary",
"name": "Primary",
"flow": "standard",
"mailbox": "INBOX",
"imapHost": "mail.ringdom.org",
"imapUser": "info@ringdom.org",
"smtpHost": "mail.ringdom.org",
"smtpUser": "info@ringdom.org",
"hasImapPassword": true,
"hasSmtpPassword": true
}
],
"validation": { "ok": true, "errors": [] }
}Реализация: loadCrmChannels() и validateCrmChannels() из features/email-crm/pipeline/imap/config.ts.
GET /api/admin/email/threadsСписок тредов переписки.
| Query | Type | Описание |
|---|---|---|
status | string | Фильтр: new, ongoing, waiting, resolved или все |
sourceChannel | string | Фильтровать по id/name канала (многопочтовый ящик) |
Ответ: { threads: EmailThreadRecord[] }
PATCH /api/admin/email/threadsОбновить статус треда.
Тело: { "id": "<threadId>", "status": "resolved" }
GET /api/admin/email/threads/[id]Детали треда с сообщениями, черновиками и открытыми задачами.
Ответ: { thread, messages, drafts, tasks }
GET /api/admin/email/draftsОжидающие черновики (status: pending), отсортированы по времени (новые выше).
POST /api/admin/email/drafts/[id]/approveУтвердить черновик к отправке. В reviewer сохраняется id текущего пользователя-сессии.
POST /api/admin/email/drafts/[id]/rejectТело: { "reason": "опциональная строка" }
POST /api/admin/email/drafts/[id]/sendОтправка утверждённого черновика через CRM SMTP-канал (EmailSenderService).
Тело (опционально): { "toEmail": "...", "subject": "..." } — по умолчанию из треда.
Ответ: { "success": true, "messageId": "<smtp-message-id>" }
Запись сохраняется в email_messages, статус треда обновляется на waiting.
GET /api/admin/email/contacts| Query | Описание |
|---|---|
email, name, company, type | Фильтры поиска |
POST /api/admin/email/contactsТело: { "email": "обяз.", "name?", "company?", "type?" }
GET /api/admin/email/tasks| Query | Описание |
|---|---|
status | open, in_progress, overdue, completed и др. |
POST /api/admin/email/tasksТело: { "threadId", "title", "taskType", ... } — см. TaskCreateInput из task-service.ts.
POST /api/admin/email/tasks/[id]/completeТело: { "completionNotes?": "string" }
GET /api/admin/email/analytics| Query | Значения |
|---|---|
range | 7d (по умолч.), 30d, 90d |
Ответ: распределение intent/sentiment, costStats из email_api_usage, dailyStats, черновики/задачи.
POST или GET /api/cron/email-processorАутентификация: Authorization: Bearer $CRON_SECRET (без секрета — отказ)
Тело запроса или query-параметр action:
| Action | Действие |
|---|---|
poll (по умолч.) | pollInboundBatch() — загрузка UNSEEN на каждом канале, обработка, disconnect |
status | Статус обработчика и IMAP (getEmailProcessor()) |
stop | Остановить IDLE слушатель |
start | Запустить IDLE (EMAIL_PROCESSOR_ALLOW_HTTP_START=true) |
mark-overdue-tasks | Запуск EmailTaskService.processOverdueTasks() |
На каждый action создаётся новый обработчик (Processor), нет постоянно работающего глобального экземпляра.
Пример:
GET /api/cron/email-analytics7-дневный срез дашборда (структура — как admin analytics). Только по cron-авторизации.
GET/POST /api/cron/cleanup-email-tokens — чистка просроченных email_login_tokens. Такой же fail-closed по CRON_SECRET. Документировано в Ring Mailer, не относится к Email CRM напрямую.
POST /api/webhooks/email/inboundАвторизация: Authorization: Bearer $WEBHOOK_EMAIL_SECRET или HMAC-SHA256 hex в X-Email-Webhook-Signature по сырому телу.
Тело запроса (JSON):
Вызывает EmailProcessor.ingestEvent() c uid: 0 (IMAP-пометка как “прочитано” не ставится).
Предпосылки: настройка операторов, секреты каналов, Auth vs CRM SMTP.
Детальный разбор: EmailProcessor и persistance через jsonb-collection.
Использование: локальный poll + smoke-тест отправки черновика.
См. также: Auth cleanup-email-tokens cron и SMTP_* плоскость.
См. также: CRM orders desk, использующий тот же admin shell.
curl -X POST "$BASE_URL/api/cron/email-processor" \
-H "Authorization: Bearer $CRON_SECRET" \
-H "Content-Type: application/json" \
-d '{"action":"poll"}'
{
"messageId": "<rfc5322-message-id>",
"from": "sender@example.com",
"fromName": "Опциональное имя",
"to": "info@example.com",
"subject": "Тема письма",
"bodyText": "Текстовое тело",
"bodyHtml": "<div>опционально</div>",
"date": "2026-06-10T12:00:00.000Z",
"inReplyTo": "<parent-message-id>",
"references": ["<ref1>", "<ref2>"]
}См. также: CRM orders desk, использующий тот же admin shell.
curl -X POST "$BASE_URL/api/cron/email-processor" \
-H "Authorization: Bearer $CRON_SECRET" \
-H "Content-Type: application/json" \
-d '{"action":"poll"}'
{
"messageId": "<rfc5322-message-id>",
"from": "sender@example.com",
"fromName": "Опциональное имя",
"to": "info@example.com",
"subject": "Тема письма",
"bodyText": "Текстовое тело",
"bodyHtml": "<div>опционально</div>",
"date": "2026-06-10T12:00:00.000Z",
"inReplyTo": "<parent-message-id>",
"references": ["<ref1>", "<ref2>"]
}См. также: CRM orders desk, использующий тот же admin shell.
curl -X POST "$BASE_URL/api/cron/email-processor" \
-H "Authorization: Bearer $CRON_SECRET" \
-H "Content-Type: application/json" \
-d '{"action":"poll"}'
{
"messageId": "<rfc5322-message-id>",
"from": "sender@example.com",
"fromName": "Опциональное имя",
"to": "info@example.com",
"subject": "Тема письма",
"bodyText": "Текстовое тело",
"bodyHtml": "<div>опционально</div>",
"date": "2026-06-10T12:00:00.000Z",
"inReplyTo": "<parent-message-id>",
"references": ["<ref1>", "<ref2>"]
}