ADR-008: Channel service abstraction
- Статус: прийнято
- Дата: 2026-04-16
- Автор: CTO Agent (KALA-151)
Контекст
Канальні плагіни Telegram і WhatsApp спочатку читали env-змінні напряму. Це працює для одного Telegram-бота та одного WhatsApp-номера, але не масштабується на multi-tenant або multi-namespace-деплої, де різним відділам може бути потрібна різна канальна конфігурація.
Канальний шар також потребує стабільного контракту, щоб майбутні канали (web, Slack, email, db-backed) можна було додавати без переписування кожного плагіна.
Рішення
Впроваджуємо інтерфейс ChannelService:
export interface ChannelService {
getActiveChannel(type: ChannelType): Promise<ChannelConfig | null>;
listActive(type?: ChannelType): Promise<ChannelConfig[]>;
findByRoutingKey?(key: string): Promise<ChannelConfig | null>;
}
Поточний EnvChannelService читає існуючий config-обʼєкт і віддає один активний Telegram-канал і один активний WhatsApp-канал. Непідтримувані типи повертають null або порожній список.
Fastify експонує сервіс як app.channelService, щоб плагіни залежали від інтерфейсу, а не читали env напряму.
Розглянуті альтернативи
Лишити пряме читання env у плагінах
Відхилено. Робить перший деплой простішим, але ускладнює multi-channel routing і тестування.
Одразу перейти на db-backed канали
Відхилено на цій фазі. Продукт спочатку потребує абстракції; db-моделі та management-UI можна додати пізніше без зміни контрактів плагінів.
Plugin-specific config-сервіси
Відхилено. Telegram і WhatsApp потребують однакової форми: type, id, department, namespace, enabled-прапорець і config-мапа.
Наслідки
Позитивні
- Канальні плагіни працюють через стабільний інтерфейс.
- Тести можуть конструювати
EnvChannelServiceз невеликим config-стабом. - Майбутня db-backed маршрутизація підтримуватиме множинні канали кожного типу.
- Department і namespace scope — first-class поля на
ChannelConfig.
Негативні
- Env-backed реалізація поки експонує лише один канал кожного типу.
- Секрети лишаються у process-config, поки не зʼявиться db-backed secret store.
findByRoutingKey()лишається опційним, поки не знадобиться для inbound routing.
Нотатки про реалізацію
src/lib/channels/channel-service.tsвизначає інтерфейс і env-backed реалізацію.- Сервіс наразі підтримує
telegramіwhatsapp. ChannelTypeуже включаєslack,emailіwebпід майбутні реалізації.