94 lines
4.1 KiB
Markdown
94 lines
4.1 KiB
Markdown
# ADR-0001: Chat Platform Boundaries (GraphQL + Hatchet)
|
|
|
|
Дата: 2026-03-08
|
|
Статус: accepted
|
|
|
|
## Контекст
|
|
|
|
Нужна минимальная и предсказуемая схема из 5 сервисов:
|
|
|
|
- `frontend`
|
|
- `backend`
|
|
- `telegram_backend`
|
|
- `telegram_worker`
|
|
- `hatchet`
|
|
|
|
Ключевые ограничения:
|
|
|
|
- основная Prisma/доменная БД только в `backend`;
|
|
- `telegram_backend` и `telegram_worker` не содержат CRM-домен и не пишут в основную БД;
|
|
- взаимодействие между сервисами только через GraphQL;
|
|
- асинхронность и ретраи централизованы в Hatchet.
|
|
|
|
## Решение
|
|
|
|
Принимаем архитектуру:
|
|
|
|
1. `backend`
|
|
- владеет доменной моделью чатов и единственной основной Prisma-базой;
|
|
- принимает inbound события от `telegram_worker` через GraphQL (`ingestTelegramInbound`);
|
|
- создает outbound задачи в `telegram_backend` через GraphQL (`requestTelegramOutbound`);
|
|
- принимает delivery-отчеты от `telegram_worker` через GraphQL (`reportTelegramOutbound`).
|
|
|
|
2. `telegram_backend`
|
|
- принимает webhook Telegram;
|
|
- нормализует payload в `OmniInboundEnvelopeV1`;
|
|
- ставит задачи в Hatchet (`process-telegram-inbound`, `process-telegram-outbound`);
|
|
- предоставляет GraphQL API для enqueue и отправки в Telegram API.
|
|
|
|
3. `telegram_worker`
|
|
- исполняет задачи Hatchet;
|
|
- для inbound вызывает `backend /graphql`;
|
|
- для outbound вызывает `telegram_backend /graphql` (`sendTelegramMessage`), затем `backend /graphql` (`reportTelegramOutbound`);
|
|
- не имеет собственной Prisma-базы.
|
|
|
|
4. `hatchet`
|
|
- единый оркестратор задач, ретраев и backoff-политик.
|
|
|
|
## Потоки
|
|
|
|
### Inbound (Telegram -> CRM)
|
|
|
|
1. Telegram webhook приходит в `telegram_backend`.
|
|
2. `telegram_backend` нормализует событие и enqueue в Hatchet `process-telegram-inbound`.
|
|
3. `telegram_worker` исполняет задачу и вызывает `backend.ingestTelegramInbound`.
|
|
4. `backend` сохраняет доменные изменения в своей БД.
|
|
|
|
### Outbound (CRM -> Telegram)
|
|
|
|
1. `backend` инициирует отправку (`requestTelegramOutbound`) в `telegram_backend`.
|
|
2. `telegram_backend` enqueue в Hatchet `process-telegram-outbound`.
|
|
3. `telegram_worker` вызывает `telegram_backend.sendTelegramMessage`.
|
|
4. `telegram_worker` репортит итог в `backend.reportTelegramOutbound`.
|
|
|
|
## Границы ответственности
|
|
|
|
`backend`:
|
|
- можно: вся бизнес-логика и состояние;
|
|
- нельзя: прямой вызов Telegram API.
|
|
|
|
`telegram_backend`:
|
|
- можно: webhook ingress, нормализация, enqueue, адаптер Telegram API;
|
|
- нельзя: доменные записи CRM.
|
|
|
|
`telegram_worker`:
|
|
- можно: исполнение задач, ретраи, orchestration шагов;
|
|
- нельзя: хранение CRM-состояния и прямой доступ к основной БД.
|
|
|
|
## Надежность
|
|
|
|
- webhook отвечает `200` только после успешной постановки задачи в Hatchet;
|
|
- при недоступности сервисов задача ретраится Hatchet;
|
|
- inbound обработка идемпотентна через `idempotencyKey` и provider identifiers в `backend`.
|
|
|
|
## Последствия
|
|
|
|
Плюсы:
|
|
- меньше сервисов и меньше скрытых связей;
|
|
- изоляция доменной БД в `backend`;
|
|
- единая точка ретраев/оркестрации (Hatchet).
|
|
|
|
Минусы:
|
|
- выше требования к стабильности GraphQL-контрактов между сервисами;
|
|
- нужна наблюдаемость по цепочке `telegram_backend -> hatchet -> telegram_worker -> backend`.
|