KNOTTA research & development

Интеграции

Поток аутентификации, владение БД, файловое хранилище, интеграция с Chatwoot и Resend.

Интеграции

Поток аутентификации

Загрузка диаграммы…

Ключевая связьUser.supabase_uid = JWT sub. Это единственная привязка между записью в Supabase Auth и записью пользователя в Django.

Роль (User.role) живёт в Django, но дублируется в app_metadata.role в Supabase Auth (через Edge Function set-role) — фронт читает её из JWT, чтобы не дёргать Django ради проверки доступа к маршруту.

Класс SupabaseAuthentication

Лежит в garden/modules/shared/auth/rest.py. Подключается через DEFAULT_AUTHENTICATION_CLASSES в DRF-настройках. Действие на каждый запрос:

  1. Достать Authorization: Bearer <jwt>.
  2. Проверить подпись JWT публичным ключом Supabase.
  3. Проверить exp.
  4. Достать sub → найти User.supabase_uid.
  5. Если пользователя нет — 401.

Failsafe для авто-создания пользователя (когда auth-sync ещё не успел сработать) реализован в auth-sync Edge Function — Django сам ничего не создаёт по запросу.

Владение базой данных

Schema owner — Django. Все миграции живут в garden/modules/*/migrations/. PostgreSQL запущен в Supabase (это просто контейнер). Когда Django применяет миграцию — таблица появляется в той же БД, к которой ходят и Supabase Auth, и SQLAlchemy-зеркала бота.

КтоЧто делает с БД
Django (Garden)Создаёт миграции, применяет их, читает и пишет
Supabase AuthСоздаёт и владеет таблицами auth.* (схема auth)
Supabase StorageСоздаёт и владеет таблицами storage.*
Telegram-ботТолько чтение через SQLAlchemy. Зеркальные модели в bot/app/models/sql/. Никогда не создаёт миграций.

Когда нужна новая модель: создать в Django → python manage.py makemigrations && migrateобновить SQLAlchemy-модели в боте в режиме read-only.

Файловое хранилище

Файлы (фотографии работ, документы) хранятся в Supabase Storage. Это S3-совместимое хранилище.

Два URL-контекста.

ПеременнаяНазначениеПример
SUPABASE_URLВнутренний Docker URL для Backend → Supabasehttp://supabase-kong:8000
SUPABASE_EXTERNAL_URLПубличный URL для подписанных ссылок клиентуhttps://service-knotta.ru.tuna.am (туннель) или прод-домен

Метаданные файла лежат в Django (модель FileAttachment):

  • bucket, object_key — где лежит файл в Storage.
  • original_filename, content_type, size, checksum_sha256, width, height — метаданные.

URL не хранится — генерируется на лету через FileAttachment.build_presigned_url(expires_seconds=3600). Это даёт короткоживущие подписанные ссылки без раздачи прямого доступа к bucket.

Email через Resend

Платформа использует Resend API (HTTP) как единственного email-провайдера. Письма отправляются из двух мест.

Загрузка диаграммы…

Транзакционные письма (приглашение клиента, сброс пароля, смена email) идут через Edge Function send-email. Шаблоны написаны на React Email (TSX) и лежат в supabase/functions/send-email/templates/.

Бизнес-уведомления (work_started, work_completed, report_*) идут напрямую из Django. Транспорт — EmailBackend в garden/modules/notification/backends/email.py. Шаблоны — MJML, лежат в garden/modules/notification/templates/notification/email/.

Webhook от Resend (POST /api/webhooks/resend/) принимает события доставки (email.sent, email.delivered, email.opened, email.bounced, email.complained) и обновляет статус соответствующего ReportDelivery через DeliveryStatusService.

Telegram → Garden → Telegram

Двусторонняя интеграция реализована через Redis Stream и webhook.

Загрузка диаграммы…

Бот никогда не лезет в Django напрямую — он только читает БД (для зеркальных моделей) и постит webhook о статусе доставки. Решение «куда отправить» принимает Django.

Chatwoot

Chatwoot — внешняя платформа для клиентского обслуживания. Интеграция работает в обе стороны.

Входящие сообщения (клиент → компания):

  1. Клиент пишет в Telegram-бот.
  2. Бот пересылает сообщение в Chatwoot через его API.
  3. Связь «клиент в Telegram ↔ контакт в Chatwoot» хранится в Django: модель ChatwootContact (garden/modules/communication/models.py).

Исходящие ответы (оператор → клиент):

  1. Оператор пишет ответ в Chatwoot.
  2. Chatwoot отправляет webhook на бот (POST /webhook/chatwoot/...).
  3. Бот отправляет сообщение в Telegram.

Webhooks — кто куда

Сводная таблица всех вебхуков, которые Garden принимает или отправляет.

Маршрут / провайдерКто шлётКто принимаетНазначение
POST /api/webhooks/telegram/<id>Telegram-ботDjangoСтатус доставки сообщения в Telegram. HMAC-SHA256.
POST /api/report-deliveries/<id>/webhookTelegram-ботDjangoАлиас предыдущего, для совместимости со старыми сборками бота.
POST /api/webhooks/resend/ResendDjangoСобытия email.* (sent / delivered / opened / bounced / complained). Подпись Svix.
Supabase Auth send-email hookSupabase AuthEdge Function send-emailТранзакционные письма (приглашение / сброс пароля / смена email).
Supabase Auth user hookSupabase AuthEdge Function auth-syncUSER_CREATED / USER_UPDATED → синхронизация в Django.
Webhook от ChatwootChatwootTelegram-ботОтвет оператора → отправка в Telegram.
На странице