Files
clientsflow/docs/adr/0001-chat-platform-service-boundaries.md
2026-03-08 18:55:58 +07:00

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`.