Перейти к содержимому

Путь данных

Кабинет устроен по стандартной схеме хранилищ данных «загрузить, потом преобразовать» (ELT), как сервисы приёма данных Airbyte и Fivetran: сначала данные сохраняются как пришли, потом раскладываются по столбцам.

У источника три канала:

  • адрес приёма — сайт, форма или сервис присылают данные сами;
  • файл — история из CSV, Excel или буфера обмена;
  • опрос по адресу — платформа сама по расписанию забирает JSON или CSV.

Что бы ни пришло, оно ложится событием в сырые данные — таблицу raw.events: тело, разобранное из JSON или формы в jsonb без столбцов и типов, плюс канал, время и пометки. Приём не предъявляет к данным требований: нет обязательных полей, нет типов, нет схемы. Заявка ложится всегда — даже пустая или с битым JSON, служебными ключами: потерять обращение хуже, чем принять его с дырой.

Дальше канал никого не интересует: таблица, вебхуки и API различают его только меткой (_channel в таблице, channel в API).

Следом платформа раскладывает событие строкой в таблицу источника sources.<имя>: поле верхнего уровня — столбец, новое поле — новый столбец, у прежних строк в нём пусто. Вложенный объект или массив — значением столбца jsonb: разбирать структуру за вас платформа не берётся, но и не теряет — достанете своим SQL:

select a->>'q' as vopros, (a->>'points')::int as bally
from sources.kviz, lateral jsonb_array_elements(result -> 'answers') a;

Если вы держите таблицу своим долгим запросом, строка дождётся и ляжет позже — заявка уже в сырых данных и не теряется.

Строка рождается из события один раз и дальше принадлежит вам. Платформа не строит таблицу заново из сырых данных — ни сама, ни кнопкой. Поэтому:

  • ваша правка (UPDATE) живёт, но необратима: прежнее значение остаётся только в событии в raw.events;
  • удалённую строку не воскресит новое событие — её возвращают из корзины;
  • смена типа столбца идёт по значениям таблицы, а не по сырым данным.

Двойной щелчок по кнопке формы шлёт два одинаковых события. Кабинет сохраняет оба — события не выбрасываются, — но второе, пришедшее в течение 5 минут с тем же телом, помечает повторной отправкой (repeat_of). Это тот же факт: строкой оно не становится, вебхук по нему не уходит, а в корзину, обратно и насовсем оно идёт вслед за своим событием.

Загрузка файла и первый запуск опроса — история: прошлое, а не новые обращения. Строки таблицы они дают как обычно, а вебхуки по ним молчат — ваша CRM не получит тысячу «новых заявок» из старой выгрузки. Следующее живое событие уйдёт вебхуком, как всегда.

Всё, что вы строите на данных, — обычные объекты Postgres в вашей схеме public: представления, таблицы, материализованные представления, функции. Реестра у платформы нет — зависимости между объектами ведёт сам Postgres. Кнопка «Дедупликация» создаёт такое же обычное представление.