Перейти к содержанию

Provisa

Подключите свои базы данных. Запрашивайте через GraphQL, gRPC, SQL или MCP — поверх любого API или протокола — за 5 минут.

Provisa обслуживает любую поверхность API (REST, GraphQL, SQL, gRPC, MCP и другие) поверх объединённого результата по всем вашим источникам. Она может это делать, потому что является активным семантическим слоем: единым определением вашего хозяйства данных — каждый домен, связь и политика по всем источникам, за исключением только самих систем-первоисточников, — которое и управляет этим хозяйством, и руководит им. Это определение не документация, к которой движок может обратиться; оно и есть движок. Зарегистрированные домены и связи — единственные легальные пути соединения, а политики доступа компилируются в каждый план запроса. Одна модель, три задачи:

  • Определение — Домены, столбцы и связи объявляются один раз. Это объявление и есть схема, которую видит каждый потребитель, и единственный набор путей соединения, доступный любому запросу.
  • Принуждение — Безопасность на уровне строк, маскирование столбцов, видимость столбцов и одобрение запросов применяются встроенно на пути выполнения. Ни один запрос не доходит до данных, минуя их, так что покрытие полно по построению, а не по прилежанию.
  • Аудит — Поскольку каждый запрос идёт по одному и тому же управляемому пути, кто, что, под какой ролью и против какой политики запросил, записывается единообразно. Распределённые трассы, метрики и журналы сами зарегистрированы как запрашиваемые таблицы рядом с вашими бизнес-данными.

Одно управляемое ядро обслуживает любой язык и транспорт. Запрашивайте через GraphQL, Cypher или SQL; потребляйте по pgwire, Bolt, gRPC, REST, Arrow Flight или JDBC. Каждый язык запросов понижается до единого промежуточного представления, куда управление внедряется однократно, — так что политика не может разойтись между языками, — и это IR перенацеливается на нативный диалект каждого источника на выходе. Добавление языка — это новый фронтенд к общему ядру, а не новый движок.

Хозяйство одновременно аналитическое и транзакционное. Межисточниковые чтения разлетаются через уровень федерации; записи и односточниковые чтения направляются напрямую в драйвер источника — управляются идентично, но транзакционно и менее чем за 100 мс. Колоночная потоковая передача Arrow Flight встроена.

Вся модель построена из горстки примитивов — домены, связи, роли и политики. Небольшой словарь, поэтому определение легко осмыслить и просто оценить и проверить: можно прочитать набор политик и понять, что он делает. Provisa — лёгкий компилятор запросов, а не среда выполнения, сидящая на пути данных. Она превращает запрос в нативные запросы, направляет их и уходит с дороги — поэтому хозяйство и работает быстро.

Такая конструкция поддерживает два способа применения, и они не исключают друг друга:

  • Как леса для модернизации — Смоделируйте хозяйство, дайте Provisa сгенерировать нативный SQL для каждого источника, затем захватите этот SQL и примите его прямо в целевой системе. Provisa — переходный слой, а не постоянная зависимость.
  • Как постоянная инфраструктура принуждения политик — Оставьте её на месте как управляемый путь, по которому идёт каждый запрос, чтобы определение, принуждение и аудит оставались едиными столько, сколько существует хозяйство.

Модель федерации

Вся модель сводится к двум контрактам и двум политикам: источники сводятся к двумерным таблицам поверх одной системы типов, запросы сводятся к одному SQL-подобному IR, достижимость решает, что запрашивается вживую, а что материализуется, и стратегия свежести управляет каждой материализованной копией и производным набором данных. Форма данных на входе, форма запроса на входе, управление в точке соединения, нативные запросы на выходе. Дальше в этом разделе разбирается каждая часть.

Модель опирается на одну редукцию: каждый источник выражается как набор двумерных таблиц поверх единой обобщённой системы типов. Это контракт, которому источник должен соответствовать, чтобы войти в хозяйство, и он один и тот же для всех. Некоторые источники подходят сразу — таблица MySQL или PostgreSQL и есть типизированное двумерное отношение. Некоторые подходят через проекцию: результат запроса GraphQL, будучи уплощённым, — это таблица. Некоторые чужды этой форме — хранилища триплетов SPARQL, Neo4j, — но остаются работоспособными, потому что пользователь задаёт запрос, чей результирующий набор табличен; запрос и есть адаптер. Каков бы ни был источник, хозяйство видит строки, столбцы и обобщённые типы, и ничего больше. Подключение нового вида источника — это выполнение того самого единственного контракта, иногда с шагом человеческого вмешательства, а не написание особой интеграции.

У этой редукции есть двойник на стороне запроса. SQL — со всеми его диалектами и причудами — по сути язык анализа над двумерными наборами данных, что делает SQL-подобную форму естественной универсальной целью для запросов. Поэтому каждый запрос, на каком бы языке он ни пришёл, самым первым шагом понижается до этого промежуточного представления. Некоторые понижаются чисто — сам SQL и даже GraphQL; некоторые тяжело — семантика путей и графов в Cypher требует настоящей работы, — но все выполнимы. Пропуск каждого запроса через одно IR прежде всего остального и есть то, что позволяет применять управление ровно в одном месте, к одной форме, независимо от языка, на котором он пришёл.

Поверх этих двух однородных форм — табличных источников и единой формы запроса — федерация здесь означает и живой запрос, и складирование — тот же охват, который покрывает движок живых запросов вроде Trino, плюс материализация, на которую такие движки опираются. Понятие, объединяющее их, — достижимость: может ли движок для данного источника запросить его на месте, или его данные сперва должны быть материализованы где-то, где их можно запросить? Достижимость делит хозяйство на то, что запрашивается вживую, и то, что предварительно копируется.

Большинство баз данных уже несут некоторое понятие живой связи — DuckDB ATTACH, PostgreSQL postgres_fdw, внешние ссылки Databricks. Так что большинство баз данных в той или иной мере способны выступать федеративным движком. Ни один не всеобъемлющ: каждый достаёт до определённого набора источников и материализует остальные, без единого учёта того, что именно к чему относится. Модель закрывает этот пробел, делая достижимость явной: определённый набор методов на каждый источник, который говорит, до чего движок дотягивается вживую и, по исключению, что должно быть материализовано.

Остаётся свежесть: насколько актуальной должна быть материализованная копия каждого недостижимого источника? На практике это сводится к небольшому набору стратегий — по требованию, по расписанию, по сигналу изменения (CDC, водяной знак, снимок) или закреплённая. Выбор одной из них на источник — и есть вся политика свежести.

Аналитические наборы данных — производные таблицы, агрегаты, результаты преобразования — укладываются в ту же форму. Они тоже должны быть выражены в IR, и потому происхождение данных не является отдельной системой, которую надо поддерживать: путь от каждой системы-первоисточника до конечного результата и есть то IR, которое его породило, читаемое от начала до конца. Их построение поднимает вопрос свежести на шаг дальше: обновляется ли набор данных по расписанию, только по выполнении его предусловий, непрерывно в режиме, близком к реальному времени, или как закреплённый исторический снимок? Способы выразить, как и когда строить набор данных, — тот же небольшой перечислимый набор, так что производный набор данных несёт политику построения ровно в том же словаре, что и копия источника.

Размерностные модели — прямое применение этого. Таблицы фактов и измерений схемы «звезда» — такие же аналитические наборы данных, как любые другие: измерение — это согласованная, дедуплицированная проекция; таблица фактов — соединение и агрегат, сведённые к гранулярности, — каждая со своей политикой построения и свежести. Медленно меняющиеся измерения не требуют особой машинерии: закреплённый снимок — это история типа 2, плановая перестройка — тип 1. А поскольку схема определена в IR, а не физически привязана к таблицам одного хранилища, те же определения фактов и измерений перенацеливаются — материализуются в Oracle, в Databricks или остаются виртуальными поверх MPP-движка — без перемоделирования. Модель порождает схему «звезда»; она не привязывает её к движку.

Data Vault укладывается так же, одним слоем раньше. Его хабы — дедуплицированные наборы данных бизнес-ключей, его линки — зарегистрированные связи между ними, а его сателлиты — наборы данных атрибутов только на вставку с отметкой времени, то есть исторический учёт. Сателлит — это просто производный набор данных на стратегии свежести по сигналу изменения: дата загрузки плюс hashdiff — это CDC, применённый к описательным атрибутам, а история только на вставку — стратегия закреплённого снимка. Таблицы point-in-time и bridge — дальнейшие производные наборы данных, построенные ради производительности запросов. Так что сырое хранилище — набор аналитических наборов данных в IR, а схема «звезда» — проекция от него; оба порождены, оба переносимы между движками. Чего модель не делает, так это не решает за вас методологию: что становится хабом, гранулярность сателлита, стратегию разбиения. Это остаётся выбором моделирования; будучи сделанным, он живёт как переносимое IR, а не как ETL, приваренный к одному хранилищу.

Оба паттерна объявляются через два полноправных сокращения, а не через рукописные представления, — примитивы, из которых строится любая схема «звезда» и любой Data Vault, оставленные нейтральными к методологии:

  • entity — ключевая, дедуплицированная, опционально историзируемая проекция источника. Объявите ключ сущности, атрибуты и режим истории; Provisa понижает это до материализованного представления, а когда запрошена история — до битемпорального MV (scd2 → дельта, snapshot → снимок). Одна конструкция обслуживает измерение по Кимбаллу (SCD1/SCD2) и хаб + сателлит Data Vault.
  • fact — соединение по ключам сущностей, сведённое к объявленной гранулярности, с агрегированными мерами. Provisa понижает это до агрегирующего MV плюс зарегистрированных связей с сущностями. Одна конструкция обслуживает таблицу фактов звезды и линк Data Vault (факт без мер — чистый линк из множества ключей).

Поскольку понижение чистое — спецификация entity/fact становится ровно теми определениями MV, битемпоральности и связей, которые моделировщик иначе написал бы вручную, — хранилище есть IR до самого низа и перенацеливается между движками без перемоделирования. Объявите хранилище в административном интерфейсе (форма Model для сущностей и фактов) или через административный API (registerEntity / registerFact); модель порождает звезду Кимбалла или Data Vault, а не навязывает какой-то один.

Путешествие во времени

Путешествие во времени — простая идея: хранить каждую версию строки вместо её перезаписи, чтобы можно было спросить, какими данные были в любой прошлый момент. Различается лишь то, насколько эффективно это может сделать каждый движок, и именно поэтому Provisa делает это свойством определения материализованного представления, а не свойством движка хранения (REQ-1162). Объявите один раз; это работает на любом материализующем бэкенде.

Правило, которое сохраняет переносимость, — только добавление: однажды записанная версия никогда не обновляется и не удаляется. Вывод строки из обращения записью даты «действительно по» — обычный битемпоральный приём — требует UPDATE, который многие движки не могут выполнить дёшево (или вообще) поверх федеративного хранилища, поэтому Provisa так не делает. Вместо этого каждое обновление добавляет, а «какая версия действовала в момент T» выводится при чтении из неизменяемого журнала. Способов добавления ровно два:

  • Снимок — добавить весь свежий набор данных, отмеченный системным временем этого обновления. Никакого вычисления разниц; корректно на каждом движке; объём растёт на полную копию за обновление.
  • Дельта — добавить только изменившееся плюс метки-надгробия для удалённых ключей. Дельта вычисляется движком (антисоединения внутри INSERT … SELECT), а не сворачивается построчно в Provisa. Компактнее, и требует ключа сущности.

Системное время (когда Provisa записала версию) управляется этим способом; действительное время (когда факт истинен в бизнесе) поставляется собственным SELECT представления и сохраняется. Движки, предлагающие больше — нативные снимки Iceberg, MERGE, поддерживающий меньше строк, — могут быть выбраны ради эффективности за тем же объявлением; путь «только добавление» — это нижняя планка, корректная везде.

Чтение прозрачно. Обычный запрос к битемпоральному MV по умолчанию восстанавливает текущее состояние из журнала добавлений; чтобы отправиться во времени, пришлите заголовок X-Provisa-As-Of: <timestamp>, и весь запрос будет отвечен так, каким хозяйство было в тот момент, — идентичная семантика на любой подложке. Включите это для любого материализованного представления в административном интерфейсе (элемент Time Travel: выкл. / снимок / дельта плюс ключ сущности) или через административный API.

Достижимость плюс свежесть — это общая модель федерации данных: определение, которое говорит, что живое, что материализовано и насколько свежей остаётся каждая копия, — независимо от охвата какого-либо одного движка. Итог — свобода от проприетарной привязки. Модель переносима; хозяйство не в плену у того вендора, чья федерация сегодня дотягивается до наибольшего числа источников.

Возможности

Интерфейсы запросов

Это языки и структурированные API, на которых вы пишете запросы. У каждого свой синтаксис и семантика; управление (RLS, маскирование, видимость столбцов, принуждение связей) применяется одинаково ко всем из них, независимо от того, каким проводным протоколом они доставлены.

  • GraphQL — Схемы на роль с видимостью на уровне полей, фильтрацией, курсорной пагинацией и агрегирующими запросами (count, sum, avg, min, max). Ограничена схемой до зарегистрированных связей — структурно корректна по построению, самый быстрый путь к правильному простому запросу. Apollo APQ включён: запросы хешируются и регистрируются на сервере; последующие вызовы шлют только хеш по HTTP GET, что делает ответы кешируемыми на CDN без единого изменения на клиенте. Справочные таблицы ниже настраиваемого порога числа строк выставляются как перечисляемые типы.
  • SQL — Полноценный SQL поверх федеративных данных; неограниченный и более выразительный, чем GraphQL. Пишите стандартный SQL — со всеми коррелированными подзапросами — и он выполняется по источникам без изменений. Односточниковые запросы полностью минуют уровень федерации (менее 100 мс).
  • Cypher — Язык графовых запросов поверх той же федеративной схемы. Обходите связи как рёбра графа; объединяйте источники; пути переменной длины. Управление применяется так же, как в GraphQL и SQL.
  • Модельный API gRPC — Автоматически порождаемый .proto из зарегистрированной схемы; типизированные RPC запроса и вставки на таблицу, потоковые ответы. Управляется схемой в том же смысле, что и GraphQL, — модель регистрации есть контракт, protobuf — проводная кодировка. В отличие от Arrow Flight (который является колоночным потоковым транспортом), это полноценный интерфейс запросов на каждую таблицу.
  • JSON:API — Структурированный API запросов по адресу /data/jsonapi/{table}, только по HTTP по замыслу. Поддерживает JSON:API 1.1: разрежённые наборы полей (fields[table]=col1,col2), выражения фильтров (filter[field][op]=value), составные документы (include=relation) и сортировку. Не язык запросов общего назначения — запрашивает по одной таблице за раз стандартизованным синтаксисом фильтров, а не произвольной строкой запроса.
  • Обозреватель языков запросов — Напишите запрос GraphQL и смотрите живые переводы в Semantic SQL и Cypher в боковых панелях; скопируйте любой из них или перейдите прямо в редактор SQL или графа. Практичный приём — набросать фрагменты запроса на GraphQL, а затем сшить полученный SQL в сложные представления или отчёты.

Обозреватель показывает запрос GraphQL рядом с его живыми переводами в SQL и Cypher:

Обозреватель языков запросов

Ту же федеративную схему можно исследовать как живой граф — метки доменов и узлов, типы связей и обходы переменной длины:

Визуализация графа

Инструменты составления запросов

Эти инструменты помогают писать запросы на перечисленных выше языках — сами они языками запросов не являются.

  • Запрос на естественном языке — Конвейер NL→SQL/Cypher/GraphQL на базе Claude. Опишите желаемое обычным языком; конвейер выдаст запрос на выбранном вами языке с интерактивным циклом проверки перед выполнением.

Запрос на естественном языке

Проводные протоколы

Это протоколы соединения. SQL, GraphQL и Cypher едут поверх них — выбор проводного протокола не меняет ни интерфейс запросов, ни поведение управления.

  • pgwire — Любой клиент PostgreSQL (psql, DBeaver, DataGrip, asyncpg, SQLAlchemy, pandas read_sql) подключается по порту 5439 так, будто это сервер Postgres. Принимает только SQL. Применяется полный конвейер управления. pg_catalog и information_schema отвечаются из каталога в памяти, так что обозреватели схем работают без обращения к федерации. TLS по желанию.
  • Bolt (Neo4j) — Любой клиент Neo4j (Neo4j Browser, Bloom, официальные драйверы) подключается по протоколу Bolt и выполняет Cypher по федеративному графу. Каждая роль, которой обладает пользователь, проявляется как база данных provisa_<role>. То же управление, что и на любом другом транспорте. TLS по желанию.
  • Arrow Flight — Высокопроизводительная колоночная потоковая передача поверх gRPC; принимает на вход GraphQL или SQL. Неограниченные результирующие наборы, без материализации на сервере, без отдельной инфраструктуры.
  • JDBC — Интеграция с BI-инструментами (Tableau, Power BI, DBeaver) в режиме approved или catalog.
  • WebSocket / SSE — Подписки: события изменений в режиме, близком к реальному времени; бэкенды: нативный PG, нативный MongoDB, CDC, опрос. Также выставляются через Kafka.

Источники данных

  • 53 типа источников — PostgreSQL, MySQL, MongoDB, Cassandra, Elasticsearch, Neo4j, хранилища триплетов SPARQL, Kafka, Google Sheets и другие через единый API; графовые и RDF-источники полноправны, а не приделаны адаптерами
  • Умная маршрутизация — Односточниковые запросы минуют федерацию (менее 100 мс); многоисточниковые направляются через уровень федерации — используйте собственный кластер или встроенные рабочие процессы
  • Источники API — Регистрируйте конечные точки REST, GraphQL, gRPC, WebSocket или RSS как запрашиваемые таблицы; вспомогательные средства SPARQL включены; федеративные соединения между источниками API и реляционными источниками работают прозрачно
  • Интроспекция удалённых схем — Укажите на любую конечную точку GraphQL, OpenAPI или gRPC; документированные операции автоматически выставляются как запрашиваемые таблицы, узлы и рёбра графа с полным управлением поверх
  • Файловые источники — Файлы CSV, Parquet и SQLite как запрашиваемые таблицы; поддерживаются локальные пути и удалённые объектные хранилища (s3://, ftp://, sftp://)
  • Интеграция с Kafka — Топики как таблицы только для чтения; результаты запросов как приёмники Kafka
  • Планируемые триггеры — Триггеры по расписанию cron и по интервалу (APScheduler), запускающие веб-хуки, мутации или публикации в приёмник Kafka
  • Подсказки производительности федерации — Подсказки маршрутизации в комментариях SQL переопределяют автоматические решения о маршрутизации

Источники данных

Источники, файлы и удалённые конечные точки регистрируются как управляемые таблицы из интерфейса:

Регистрация таблицы

Безопасность и управление

  • Безопасность на уровне строк — Подстановка предложения WHERE на таблицу и на роль
  • Маскирование столбцов — Маскирование на столбец (регулярное выражение, константа, усечение) с обходом по роли
  • Предустановки столбцов — Серверные статические значения или значения переменных сессии, подставляемые при вставке/обновлении; не выставляются во входных типах мутаций
  • Права на запись — Контроль доступа к мутациям на уровне столбца (writable_by)
  • Наследуемые роли — Роли рекурсивно наследуют RLS, видимость и маскирование от родительской роли
  • Учтённые функции и веб-хуки — Функции БД и исходящие веб-хуки, выставленные как мутации GraphQL с типизированными формами возврата
  • Хук одобрения ABAC — Хук авторизации перед выполнением; транспорт webhook, gRPC или unix_socket; область на таблицу, на источник или глобальная; настраиваемая запасная политика
  • Подключаемая аутентификация — Firebase, Keycloak, OAuth 2.0, простая (для тестирования)

Роли безопасности

Доставка и производительность

  • Материализованные представления как записанные преобразования — MV фиксирует преобразование, которое его породило: форму соединения или SQL, входные сигналы каждого источника (снимок Iceberg, водяной знак РБД), из которых оно построено, и проверку детерминизма при регистрации. Поскольку преобразование записано, запросы (или подвыражения) прозрачно переписываются на свежее MV — структурное сопоставление шаблона соединения с поддержкой частичного совпадения, так что MV, покрывающее подмножество соединений, всё равно применяется, а оставшиеся соединения сохраняются
  • Встраивание горячих таблиц — Небольшие часто соединяемые справочные таблицы встраиваются как CTE со списком VALUES прямо в план запроса, устраняя межисточниковые обращения за данными измерений
  • Кеширование запросов — Кеш результатов в Redis, разделённый по роли и RLS; кеш хешей APQ включён
  • Наблюдаемость как данные — Распределённые трассы, метрики и журналы собираются через OpenTelemetry, уплотняются в Iceberg на S3 и автоматически регистрируются как запрашиваемые таблицы (traces, metrics, logs, queries) в федеративной схеме; запрашивайте их через SQL, GraphQL или Cypher рядом с бизнес-данными — соедините таблицу customers с таблицей queries, чтобы увидеть, кто что выполнял и сколько это заняло

Администрирование и интеграция

  • Административный API — GraphQL по адресу /admin/graphql; выгрузка и загрузка конфигурации, редактирование связей, одобрение запросов
  • Просмотр отчётов/admin/reports перечисляет встроенные управленческие представления домена эксплуатации и любые зарегистрированные пользовательские отчёты; требует возможности observability
  • Предпросмотр таблицы — у каждой зарегистрированной таблицы есть управляемый просмотрщик данных с серверной постраничной выдачей, проталкиваемыми фильтрами, многоуровневой группировкой и экспортом в CSV
  • GraphQL Voyager — Интерактивная визуализация схемы в области видимости роли в виде диаграммы «сущность — связь»
  • Обнаружение связей с помощью LLM — Предложения кандидатов во внешние ключи на базе Claude
  • Клиент Pythonpip install provisa-client; GraphQL/SQL → DataFrame, Arrow Flight → таблицы pyarrow, диалект SQLAlchemy, поддержка ADBC
  • Приём данных — Конечные точки HTTP для отправки событий в формате JSON на платформу
  • Импорт из Hasura v2 / DDN — Преобразование метаданных Hasura v2 или YAML суперграфа DDN в конфигурацию Provisa
  • Apollo Federation — Выставление Provisa как подграфа Apollo Federation v2

Схема в области видимости роли, представленная как диаграмма «сущность — связь» (GraphQL Voyager):

Схема в Voyager

Связи регистрируются, одобряются и принуждаются как единственные легальные пути JOIN:

Связи

Модель безопасности

Здесь фраза «на пути, по которому каждый запрос и так идёт» перестаёт быть лозунгом. Provisa принуждает многослойную модель безопасности во всех языках запросов (GraphQL, SQL, Cypher) и на всех транспортах (REST, gRPC, Arrow Flight, JDBC, pgwire, Bolt, WebSocket). Управление применяется единообразно — пути запроса, который его обходит, не существует. Покрытие полно по построению, а не по прилежанию: добавьте источник, столбец или связь — и каждый слой применится к нему автоматически, и не надо ничего помнить и регистрировать.

Слои применяются по порядку. Запрос должен пройти каждый слой, прежде чем оценивается следующий.

Слой 0 — Фильтрация интроспекции

Схема и каталог, представленные роли, содержат только таблицы из её списка domain_access и столбцы, проходящие правила visible_to для каждого столбца. Объекты вне доступа роли невидимы во время обнаружения — их нельзя запросить, автодополнить или вывести об их существовании. Это относится к схеме GraphQL, каталогу SQL и обозревателю схем в редакторе запросов.

Слой 1 — Публичный доступ

Таблицы в доменах без ограничения domain_access видны всем аутентифицированным идентичностям без дополнительной настройки. Никакого трения для действительно публичных данных.

Слой 2 — Доступ к домену

Каждая роль несёт список domain_access из идентификаторов доменов. Запрос, затрагивающий таблицу вне этих доменов, отклоняется до выполнения. Это грубая граница владения — роль отдела кадров не дотянется до финансовых таблиц, как бы ни был написан SQL.

Слой 3 — Безопасность на уровне строк

После подтверждения доступа к домену предикаты WHERE, заданные на таблицу и на роль, подставляются в каждый SELECT во время выполнения. Предикаты вычисляются по сырым данным. Региональный руководитель, запрашивающий общую таблицу заказов, видит только строки своего региона, даже при SELECT *.

Слой 4 — Видимость и маскирование столбцов

Столбцы, чей список visible_to исключает запрашивающую роль, вырезаются из вывода запроса. У столбцов с правилом маскирования значения заменяются — сокрытие по регулярному выражению, замена константой или усечение — до того, как результаты покинут сервер. Маскирование применяется во всех языках запросов и форматах вывода.

Слой 5 — Защита предикатов

Маскированные столбцы отклоняются в предложениях WHERE и HAVING. Без этого вызывающий мог бы вывести немаскированное значение двоичным поиском по фильтру, даже если вывод замаскирован. Отклонение принуждается на этапе разбора запроса, до выполнения.

Управление связями

Условия JOIN в SQL должны соответствовать зарегистрированной, одобренной связи между таблицами. Неодобренные соединения отклоняются. Каждая связь несёт понятные человеку обоснование и описание — ориентир и для пользователей, и для автономных агентов, зачем существует этот путь обхода. Это политика управления, а не жёсткая граница безопасности: слои 2–5 держатся независимо от структуры соединения, поэтому намеренный обход не откроет данных, до которых роль не смогла бы дотянуться двумя отдельными запросами. Попытки обхода журналируются и поддаются аудиту.


Эти слои складываются. У роли с доступом к домену, RLS и маскированными столбцами все пять ограничений действуют одновременно. Добавление нового источника данных, столбца или связи не требует обновлять каждое правило — каждый слой настраивается независимо и применяется автоматически к любому запросу, затрагивающему управляемые объекты.

macOS

  1. Скачайте Provisa-macOS.dmg (всегда последний выпуск)
  2. Перетащите Provisa.app в /Applications и запустите двойным щелчком
  3. Первый запуск выполняет разовую настройку (~2 мин, интернет не нужен)
  4. Откройте Терминал:
provisa start   # start all services
provisa open    # open the UI in your browser

Linux

  1. Скачайте Provisa-linux-x86_64.AppImage (всегда последний выпуск)
  2. Сделайте файл исполняемым и запустите — первый запуск выполняет разовую настройку (интернет не нужен):
chmod +x Provisa-*-linux-x86_64.AppImage
./Provisa-*-linux-x86_64.AppImage
provisa start && provisa open

Windows

  1. Скачайте Provisa-windows-x64.exe (всегда последний выпуск)
  2. Запустите установщик — права администратора не нужны
  3. Откройте Provisa First Launch из меню «Пуск» — выполняется разовая настройка (~5 мин, интернет не нужен)
  4. Откройте новый терминал:
provisa start

Первый запрос

В локальной разработке (PROVISA_MODE=test) учётные данные не нужны. В продуктивной среде аутентифицируйтесь токеном Bearer — роль извлекается из него автоматически.

# Local dev — no auth required, role defaults to admin
curl -X POST http://localhost:8001/data/graphql \
  -H "Content-Type: application/json" \
  -d '{"query": "{ orders { id amount region } }"}'

# Ad-hoc SQL works the same way
curl -X POST http://localhost:8001/data/graphql \
  -H "Content-Type: application/json" \
  -d '{"query": "SELECT id, amount, region FROM orders"}'

# Production — authenticate with a Bearer token; role is derived from the token
curl -X POST https://provisa.example.com/data/graphql \
  -H "Authorization: Bearer <token>" \
  -H "Content-Type: application/json" \
  -d '{"query": "{ orders { id amount region } }"}'

JDBC (Tableau, DBeaver, Power BI)

Скачайте provisa-jdbc.jar (всегда последний выпуск) и добавьте его в путь к драйверам вашего BI-инструмента.

jdbc:provisa://localhost:8815

Аутентифицируйтесь именем пользователя и паролем Provisa — сервер назначит вашу роль.

  • Режим catalog — видна вся схема; используйте с каталожными инструментами (Collibra, Atlan, DBeaver)

Шаги настройки Tableau и Power BI см. в docs/integrations.md.

Проводной протокол PostgreSQL (pgwire)

Provisa говорит на проводном протоколе PostgreSQL по порту 5439. Любой клиент, умеющий подключаться к Postgres, подключается к Provisa — без драйвера, без адаптера, без изменений в существующем инструментарии.

Имя пользователя PostgreSQL выбирает роль Provisa. При provider: none (режим доверия) пароль игнорируется, и любое настроенное имя роли принимается как имя пользователя — подключитесь как analyst, admin или любая роль, чтобы увидеть управляемое представление данных для этой роли. При provider: simple пароль проверяется по bcrypt. Другие провайдеры (firebase, keycloak, oauth) по pgwire не поддерживаются.

# psql — connect as analyst role
psql -h localhost -p 5439 -U analyst

# psql — connect as admin role
psql -h localhost -p 5439 -U admin

# asyncpg (Python) — role = username, password ignored in trust mode
conn = await asyncpg.connect(host="localhost", port=5439, user="analyst", password="x")
rows = await conn.fetch("SELECT id, amount FROM orders WHERE region = 'west'")

# SQLAlchemy
engine = create_engine("postgresql+psycopg2://analyst:x@localhost:5439/provisa")

# pandas
df = pd.read_sql("SELECT * FROM orders", engine)

Все запросы проходят полный конвейер управления — доступ к домену, RLS, маскирование и защита предикатов применяются ровно так же, как для GraphQL и REST. Обозреватели схем (DBeaver, DataGrip, pgAdmin) работают сразу: запросы к pg_catalog и information_schema отвечаются из каталога в памяти, ограниченного доступом роли к доменам, так что пользователи видят только те таблицы и столбцы, которые им разрешено запрашивать.

DataGrip просматривает управляемую схему и её диаграмму внешних ключей по pgwire — без драйвера, без адаптера:

Provisa в DataGrip по pgwire

TLS включается заданием PROVISA_PGWIRE_CERT и PROVISA_PGWIRE_KEY. Порт настраивается через PROVISA_PGWIRE_PORT (по умолчанию 5439).

Bolt (проводной протокол Neo4j)

Provisa также говорит на протоколе Neo4j Bolt, так что графовые инструменты подключаются напрямую и выполняют Cypher по федеративному графу — без экспорта, без отдельной графовой базы данных. Направьте Neo4j Browser или Bloom на Provisa и обходите связи между источниками с тем же управлением (доступ к домену, RLS, маскирование).

Neo4j Browser выполняет Cypher к Provisa — метки узлов, типы связей и ключи свойств берутся прямо из зарегистрированной схемы:

Provisa в Neo4j Browser по Bolt

Включите это заданием PROVISA_BOLT_PORT (по умолчанию у Neo4j — 7687). TLS включается через PROVISA_BOLT_CERT и PROVISA_BOLT_KEY. Каждая роль Provisa, которой обладает аутентифицированный пользователь, проявляется как выбираемая база данных provisa_<role> (селектор provisa_admin выше) — выбор одной сужает сессию до прав этой роли на домены; пользователь никогда не может выйти за пределы своих ролей.

Клиент Python

pip install provisa-client                       # core
pip install "provisa-client[pandas]"             # + DataFrame support
pip install "provisa-client[sqlalchemy]"         # + SQLAlchemy dialect
pip install "provisa-client[adbc]"               # + ADBC over Arrow Flight
from provisa_client import ProvisaClient, connect

# GraphQL → DataFrame
client = ProvisaClient("http://localhost:8001", username="alice", password="secret")
df = client.query_df("{ orders { id amount region } }")

# SQL → DataFrame
df = client.query_df("SELECT id, amount, region FROM orders WHERE region = 'west'")

# Arrow Flight → pyarrow Table (high-throughput columnar)
table = client.flight("{ orders { id amount region } }")

# DB-API 2.0 (PEP 249) — GraphQL or SQL, detected automatically
with connect("http://localhost:8001", username="alice", password="secret") as conn:
    cur = conn.cursor()

    # GraphQL
    cur.execute("{ orders { id amount region } }")
    rows = cur.fetchall()

    # SQL (routed through governance engine — RLS and masking applied)
    cur.execute("SELECT id, amount FROM orders WHERE region = %s", ("west",))
    rows = cur.fetchall()

# SQLAlchemy dialect — provisa+http:// or provisa+https://
from sqlalchemy import create_engine, text
import pandas as pd

engine = create_engine("provisa+http://alice:secret@localhost:8001")

# pandas read_sql — GraphQL or SQL
df = pd.read_sql("{ orders { id amount region } }", engine)
df = pd.read_sql("SELECT id, amount, region FROM orders WHERE region = 'west'", engine)

# raw execute
with engine.connect() as conn:
    rows = conn.execute(text("SELECT id, amount FROM orders")).fetchall()

# role + mode URL parameters (mode=catalog for arbitrary SQL)
engine = create_engine(
    "provisa+http://alice:secret@localhost:8001?role=analyst&mode=catalog"
)

# ADBC — Arrow-native streaming via Flight
from provisa_client.adbc import adbc_connect
with adbc_connect("http://localhost:8001", user="alice", password="secret") as conn:
    with conn.cursor() as cur:
        cur.execute("{ orders { id amount } }")
        table = cur.fetch_arrow_table()

Полный справочник см. в docs/python-client.md.

Документация

Тема Документ
Быстрый старт для разработчика (запуск из исходников) docs/quickstart.md
Полный справочник по конфигурации YAML docs/configuration.md
Справочник конечных точек (GraphQL, REST, Flight, gRPC) docs/api-reference.md
Проектирование системы и карта компонентов docs/architecture.md
Модель безопасности (RLS, маскирование, аутентификация) docs/security.md
Хранение секретов и ссылки ${secret:NAME} docs/secrets.md
Бизнес-глоссарий и курирование терминов docs/glossary.md
Окружения (dev / staging / prod) docs/environments.md
Поддерживаемые типы источников docs/sources.md
Подписки SSE docs/subscriptions.md
JDBC, BI-инструменты, клиенты Arrow Flight, Apollo Federation docs/integrations.md
Клиент Python (provisa-client) docs/python-client.md
Административный API docs/admin.md
Развёртывание (Docker Compose, Kubernetes, macOS) docs/deployment.md
Импорт из Hasura v2 / DDN docs/import.md
Процесс выпуска (теги alpha/beta/stable) docs/releasing.md

Подбор мощности

В состав Provisa входит встроенный федеративный движок для многоисточниковых запросов. При первом запуске вы выбираете бюджет оперативной памяти; Provisa автоматически выводит число локальных рабочих процессов федерации.

ОЗУ узла Рабочие процессы Типичная нагрузка
< 24 ГБ 0 Разработка, односточниковые запросы, небольшие команды
24–47 ГБ 1 Небольшая команда, умеренные межисточниковые запросы
48–95 ГБ 2 Развёртывание уровня отдела, смешанное использование BI и блокнотов
96 ГБ+ 4 Крупный отдел, интенсивная параллельная федерация

Число рабочих процессов можно изменить в любой момент, отредактировав ~/.provisa/config.yaml (federation_workers: N) и выполнив provisa restart. Значение 0 запускает только координацию (один узел).

Масштабирование за пределы одной машины

Горизонтальное масштабирование — Запустите несколько экземпляров Provisa за балансировщиком нагрузки. Каждый экземпляр — полностью работоспособная система. Все экземпляры должны указывать на одну и ту же БД конфигурации (задайте CONFIG_DB_HOST на вторичных машинах) и, по желанию, на общий экземпляр Redis (REDIS_URL) ради единого кеша. Большинство запросов распределяются прозрачно; очень крупные межисточниковые соединения могут превысить ресурсы одного экземпляра и потребовать более мощной машины или внешнего федеративного кластера.

Общий Redis — Задайте REDIS_URL на каждом экземпляре, указав на внешний Redis. Общий Redis означает, что записи кеша с одного экземпляра доступны всем, что повышает долю попаданий по кластеру.

Собственный федеративный кластер — Направьте Provisa на существующий внешний федеративный кластер вместо встроенных рабочих процессов. Рекомендуется для крупномасштабных или облачных развёртываний; о настройке см. docs/deployment.md.

Лицензия

Business Source License 1.1 (без изменений, согласно обязательствам лицензиара MariaDB). Каждая выпущенная версия переходит под изменённую лицензию (GPL v2.0 или новее) на 4-ю годовщину своего публичного выпуска; текущий и недавний код остаётся под BSL. Продуктивное использование сверх порогов дополнительного разрешения на использование (менее 100 сотрудников/подрядчиков и менее $1 млн выручки за предыдущий год) требует коммерческой лицензии. См. LICENSE.

Лицензиар не даёт согласия на использование этой работы для обучения моделей ИИ/машинного обучения. См. NOTICE, ai.txt и robots.txt. По вопросам коммерческих лицензий или лицензий на обучение ИИ: kennethstott@gmail.com