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

Provisa

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

Возможности

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

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

  • GraphQL — Схемы для каждой роли с видимостью на уровне полей, фильтрацией, постраничным выводом на основе курсора и агрегатными запросами (count, sum, avg, min, max). Ограничена схемой до зарегистрированных связей — структурно корректна по построению, самый быстрый путь к правильному простому запросу. Включена Apollo APQ: запросы хешируются и регистрируются на стороне сервера; последующие вызовы отправляют только хеш по HTTP GET, что делает ответы кешируемыми в CDN без изменений на стороне клиента. Таблицы-справочники ниже настраиваемого порога строк выставляются как типы enum.
  • SQL — Полный SQL над федеративными данными; неограниченный и более выразительный, чем GraphQL. Пишите стандартный SQL — включая коррелированные подзапросы — и он выполняется над источниками без изменений. Запросы к одному источнику полностью минуют слой федерации (менее 100 мс).
  • Cypher — Язык графовых запросов над той же федеративной схемой. Обходите связи как рёбра графа; объединяйте источники; используйте пути переменной длины. Governance применяется идентично GraphQL и SQL.
  • gRPC model API — Автогенерируемый .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) и сортировку. Не является языком запросов общего назначения — запрашивает по одной таблице за раз со стандартизированным синтаксисом фильтрации, а не произвольной строкой запроса.
  • Query Language Explorer — Напишите запрос GraphQL и увидите живые переводы в Semantic SQL и Cypher в боковых панелях; скопируйте любой из них или перейдите напрямую в редактор SQL или графа. Практичный рабочий процесс — набросать фрагменты запроса в GraphQL, затем встроить полученный SQL в сложные представления или отчёты.

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

Query Language Explorer

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

Graph Visualization

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

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

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

Natural Language Query

Протоколы передачи

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

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

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

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

Data Sources

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

Table Registration

Безопасность и Governance

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

Security Roles

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

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

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

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

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

Schema Voyager

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

Relationships

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

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

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

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

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

Уровень 1 — Публичный доступ

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

Уровень 2 — Доступ к домену

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

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

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

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

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

Уровень 5 — Защита предикатов

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

Governance связей

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


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

macOS

  1. Скачайте Provisa-macOS.dmg (всегда последний релиз)
  2. Перетащите Provisa.app в /Applications и запустите двойным щелчком
  3. Первый запуск выполняет единовременную настройку (~2 мин, интернет не требуется)
  4. Откройте Terminal:
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)

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

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

Provisa in DataGrip over pgwire

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

Bolt (протокол передачи Neo4j)

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

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

Provisa in Neo4j Browser over 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
Поддерживаемые типы источников docs/sources.md
Подписки SSE docs/subscriptions.md
JDBC, BI-инструменты, клиенты Arrow Flight, Apollo Federation docs/integrations.md
Python-клиент (provisa-client) docs/python-client.md
Admin 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, чтобы работать только в режиме координации (единый узел).

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

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

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

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

Лицензия

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

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