Интеграции
Поток аутентификации, владение БД, файловое хранилище, интеграция с 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-настройках. Действие на каждый запрос:
- Достать
Authorization: Bearer <jwt>. - Проверить подпись JWT публичным ключом Supabase.
- Проверить
exp. - Достать
sub→ найтиUser.supabase_uid. - Если пользователя нет — 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 → Supabase | http://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 — внешняя платформа для клиентского обслуживания. Интеграция работает в обе стороны.
Входящие сообщения (клиент → компания):
- Клиент пишет в Telegram-бот.
- Бот пересылает сообщение в Chatwoot через его API.
- Связь «клиент в Telegram ↔ контакт в Chatwoot» хранится в Django: модель
ChatwootContact(garden/modules/communication/models.py).
Исходящие ответы (оператор → клиент):
- Оператор пишет ответ в Chatwoot.
- Chatwoot отправляет webhook на бот (
POST /webhook/chatwoot/...). - Бот отправляет сообщение в Telegram.
В текущей конфигурации playbooks/prod/ng-metrics.yaml роль chatwoot закомментирована. Локально и на тестовых стендах работает.
Webhooks — кто куда
Сводная таблица всех вебхуков, которые Garden принимает или отправляет.
| Маршрут / провайдер | Кто шлёт | Кто принимает | Назначение |
|---|---|---|---|
POST /api/webhooks/telegram/<id> | Telegram-бот | Django | Статус доставки сообщения в Telegram. HMAC-SHA256. |
POST /api/report-deliveries/<id>/webhook | Telegram-бот | Django | Алиас предыдущего, для совместимости со старыми сборками бота. |
POST /api/webhooks/resend/ | Resend | Django | События email.* (sent / delivered / opened / bounced / complained). Подпись Svix. |
| Supabase Auth send-email hook | Supabase Auth | Edge Function send-email | Транзакционные письма (приглашение / сброс пароля / смена email). |
| Supabase Auth user hook | Supabase Auth | Edge Function auth-sync | USER_CREATED / USER_UPDATED → синхронизация в Django. |
| Webhook от Chatwoot | Chatwoot | Telegram-бот | Ответ оператора → отправка в Telegram. |