Аудит Supabase backend для онлайн-заявок
Дата актуализации: 13 июля 2026 года.
Итоговый статус
Рабочий приём заявок сейчас обеспечивается Web3Forms. Supabase backend v2 подготовлен в репозитории как будущий второй канал, но не считается введённым в эксплуатацию.
Текущая конфигурация:
lead_capture:
mode: "web3forms"
endpoint: ""
Это означает:
- клиентская форма работает независимо от Supabase;
- Web3Forms должен отправлять email-копию;
- после технического успеха открывается
/spasibo/; - SMS, MAX, ВКонтакте, Web Share и копирование остаются fallback;
- Supabase Edge Function не вызывается браузером;
- наличие исходников не подтверждает применённую миграцию, деплой или Telegram-уведомление.
Проверенные файлы
supabase/migrations/202607070001_create_broker_leads.sql— базовая legacy-схема;supabase/migrations/202607130002_broker_leads_v2.sql— совместимое расширение backend v2;supabase/functions/broker-public-lead/index.ts— Edge Function v2;scripts/audit-supabase-backend.py— source-аудит backend;assets/js/online-application.js— клиентский payload и hybrid-транспорт;_config.yml— рабочий режим и пустой дополнительный endpoint;docs/lead-endpoint-contract.md— контракт и порядок запуска.
Что уже подготовлено в исходниках
Вложенный контракт формы
Edge Function принимает фактический payload:
{
"schema_version": 1,
"request_id": "UUID",
"form_version": "2",
"client": {},
"mortgage": {},
"tracking": {},
"qualification": {},
"spam_check": {},
"personal_data_consent": "yes",
"consent": true
}
Старый плоский контракт больше не используется новой версией функции.
Совместимая миграция
Новая миграция не удаляет существующую broker_leads и не переписывает базовую миграцию. Она добавляет:
request_id;- частичный уникальный индекс;
- версии контракта и формы;
- нормализованный телефон;
- исходные текстовые значения стоимости и взноса;
- способ связи, доход и банковскую историю;
tracking,qualification,spam_check,raw_payload;- технический приоритет и статус уведомления;
- таблицу
broker_lead_events; - таблицу
broker_lead_rate_limits; - атомарную RPC-функцию rate limit;
- функцию очистки старых технических счётчиков;
- RLS для новых таблиц.
Денежные значения сохраняются и как исходный текст. Это важно для вариантов маткапитал, пока нет, частично и других значений, которые нельзя безусловно преобразовать в число.
Идемпотентность
request_id используется до вставки и на уровне уникального индекса.
Edge Function:
- ищет существующую заявку;
- возвращает прежний
lead_idпри повторе; - обрабатывает конкурентную ошибку уникальности;
- возвращает
duplicate: trueбез создания второй записи.
Серверный rate limit
Rate limit выполняется атомарной RPC-функцией consume_broker_lead_rate_limit.
Fingerprint строится как SHA-256 от:
- серверно определённого IP;
- User-Agent;
- последних четырёх цифр нормализованного телефона.
Таблица ограничений не хранит:
- исходный IP;
- полный номер телефона;
- полный payload заявки.
При отсутствии миграции или RPC Edge Function возвращает backend_migration_required и не продолжает приём. Это fail-closed поведение защищает от частичного запуска.
CORS и входной запрос
Подготовлены:
- точное сравнение нормализованного Origin;
- запрет проверки через
startsWith; - отдельная обработка
OPTIONS; - запрет неизвестного Origin;
- запрет originless-запросов по умолчанию;
- проверка
Content-Type; - ограничение размера JSON;
- проверка объектной структуры payload;
- безопасные ответы без stack trace и секретов.
Серверная валидация
Функция повторно проверяет:
schema_version;request_id;- имя;
- российский номер телефона;
- город;
- ипотечный сценарий;
- согласие;
- honeypot;
- минимальное время заполнения;
- длину текстовых полей;
- URL и квалификацию.
Клиентская маска телефона не считается доверенным источником.
События и Telegram
После записи создаётся событие created.
При наличии серверных секретов функция может отправить Telegram-уведомление. Результат отражается в:
notification_status;- событии
notification_sent; - событии
notification_failed.
Ошибка Telegram не удаляет уже сохранённую заявку.
Source-аудит
scripts/audit-supabase-backend.py проверяет:
- наличие миграции и Edge Function;
- уникальный
request_id; - таблицы событий и rate limit;
- атомарную RPC;
- RLS;
- отсутствие полного payload в rate-limit таблице;
- точное сравнение Origin;
- ограничение размера запроса;
lead_idи duplicate-ответы;- Telegram-маркеры;
- режим
web3forms; - пустой
endpoint; - актуальность серверного контракта.
Проверка запускается в GitHub Pages workflow до Jekyll-сборки.
Что пока не подтверждено
GitHub-репозиторий не подтверждает:
- какой Supabase-проект является целевым;
- применена ли новая миграция;
- развёрнута ли актуальная Edge Function;
- настроен ли публичный браузерный вызов;
- какие Origin заданы в живом окружении;
- установлены ли
SUPABASE_SERVICE_ROLE_KEY, Telegram token и chat ID; - куда фактически приходит Telegram-уведомление;
- кто имеет доступ к таблице заявок;
- кто отвечает за обработку новых записей;
- какой срок хранения заявок утверждён;
- как выполняется удаление данных по запросу клиента;
- проходит ли success, duplicate, CORS, spam и rate-limit smoke-тест.
Безопасная последовательность запуска
- Подтвердить целевой Supabase-проект.
- Применить базовую и v2-миграции штатным migration workflow.
- Проверить созданные столбцы, индексы, таблицы, RLS и RPC.
- Развернуть актуальную
broker-public-lead. - Настроить secrets только в окружении Edge Function.
- Задать точные production и проверенные dev-origin.
- Проверить публичный браузерный вызов согласно политике проекта.
- Выполнить тесты invalid JSON, размер payload, validation и CORS.
- Выполнить success и duplicate-тест с одним
request_id. - Проверить почасовой rate limit и очистку счётчиков.
- Проверить строку заявки и событие
createdнепосредственно в базе. - Подключить тестовый Telegram-чат и проверить
sent/failed. - Утвердить роли доступа, срок хранения и удаление персональных данных.
- Обновить политику сайта под фактическое серверное хранение.
- Указать публичный HTTPS endpoint в
_config.yml. - Перевести
lead_capture.modeвhybrid. - Провести сквозной тест Web3Forms + Supabase +
/spasibo/.
Решение на текущем этапе
- Web3Forms остаётся рабочим основным каналом.
- Supabase v2 считается подготовленным только на уровне исходников.
lead_capture.endpointостаётся пустым.- Режим
hybridне включается до полной серверной приёмки. - Issue №7 остаётся открытым до применения миграции, деплоя и smoke-теста.
- Issue №8 остаётся открытым до подтверждения фактического email-получателя Web3Forms.