Административный API¶
Административный API — это конечная точка Strawberry GraphQL по адресу POST /admin/graphql. Она требует роли суперпользователя или администратора и отделена от конечной точки GraphQL для данных.
Аутентификация¶
Передавайте учётные данные в заголовке Authorization, используя штатный провайдер аутентификации Provisa:
Административный доступ управляется возможностью admin, назначенной роли.
Персональные токены доступа¶
Персональный токен доступа принимается везде, где принимается токен bearer, включая эту конечную точку. Вы сами выпускаете и отзываете свои токены, потому что токен является собственными учётными данными владельца. Поэтому он находится в вашем профиле в интерфейсе администрирования, рядом с выходом из организации и удалением учётной записи, а не на странице администратора. Администратор никогда не выпускает токен от имени другого человека.
| Маршрут | Действие |
|---|---|
POST /auth/tokens |
Выпускает токен для вызывающей стороны. Тело: name, необязательные role_id, scopes, expires_in_days (1–366). Ответ — единственное место, где вообще появляется секрет |
GET /auth/tokens |
Активные токены вызывающей стороны в этой организации — отображаемый префикс, имя, отметки времени жизненного цикла и хеш, идентифицирующий токен при отзыве. Никогда не рабочие учётные данные |
DELETE /auth/tokens/{token_hash} |
Отзывает один из токенов вызывающей стороны. 404, если токен не принадлежит ей или уже отозван |
Если role_id не указан, токен разрешается в ту роль, которой владеет его владелец; указание роли сужает токен относительно его владельца. Отзыв происходит и неявно: удаление членства пользователя в организации отзывает его токены для этой организации. О самих учётных данных см. Модель безопасности.
Возможности¶
Управление конфигурацией¶
Скачать текущую работающую конфигурацию:
Возвращает полный config.yaml в виде YAML-файла. Загрузить новую конфигурацию:
Provisa проверяет YAML, перезагружает каталоги и заново генерирует схемы. Перезапуск не требуется.
Настройки времени выполнения¶
Чтение и запись настроек платформы времени выполнения без правки файла конфигурации:
Поверхность настроек охватывает перенаправление больших результатов, выборку и лимит строк по умолчанию, TTL кеша ответов, соглашение об именовании, автоотслеживание FK для связей, DSN хранилища материализации, память федеративного движка (jvm_heap_gb, query_max_memory, query_max_memory_per_node, query_max_total_memory, fault_tolerant_execution, fault_tolerant_task_memory, exchange_spool_dir) и всю поверхность тонкой настройки конвейера трассировки OpenTelemetry. Также доступны лимиты обхода удалённого GraphQL и настройки тёплого уровня и кеша чтения.
Карточка Серверы коннекторов задаёт для каждого коннектора, имеющего встроенный сервер (File Crawler, SharePoint, Salesforce, ServiceNow, Cloud Inventory, Splunk, AskAmerica), папку с серверным пакетом, собранным для этого хоста (connectors.<connector>.bundle_dir, переменная окружения PROVISA_PGWIRE_BUNDLE_<CONNECTOR>). Пустая — сервер коннектора загружается из закреплённого релиза kenstott/calcite. Заданная — папка используется как есть: лаунчер должен находиться по пути bin/pgwire-<connector>; папка без него останавливает запуск сервера коннектора с ошибкой, в которой указана настройка, — релиз в этом случае не загружается. Настройка читается при каждом запуске сервера коннектора.
Режим безопасности security.mode (standard | high) применяется при перезапуске:
Назначения моделей ИИ, реестр моделей эмбеддингов и векторов и ограничение частоты NL действуют со следующего запроса, без перезапуска:
Вкладка шифрования в административном интерфейсе получает список провайдеров вживую из реестра шифрования; недоступные провайдеры отображаются, но выбрать их нельзя.
GET/HEAD /health и GET /setup/status никогда не требуют аутентификации. Они обходят требование Authorization: Bearer, даже когда настроен провайдер аутентификации.
Федеративный движок¶
Прочитать или изменить, какой движок использует развёртывание:
GET возвращает ключ активного движка и нужные ему поля конфигурации. PUT принимает тело с engine (ключ) и любыми полями, специфичными для движка; выбор сохраняется в конфигурации платформы и вступает в силу при следующем перезапуске службы.
Редактор связей¶
Получить список связей:
query {
relationships {
id
sourceTableId
targetTableId
sourceColumn
targetColumn
cardinality
materialize
}
}
Создать связь. Уже существующий id отклоняется; связь изменяется через updateRelationship, который принимает тот же ввод:
mutation {
createRelationship(input: {
id: "orders-to-customers"
sourceTableId: "orders"
targetTableId: "customers"
sourceColumn: "customer_id"
targetColumn: "id"
cardinality: "many_to_one"
}) {
success
}
}
Объявить связь через junction:
mutation {
createRelationship(input: {
id: "pets-bonded-pair"
sourceTableId: "pets"
targetTableId: "pets"
sourceColumn: "id"
targetColumn: "id"
cardinality: "one-to-many"
viaTable: "pet_companions"
viaSourceColumn: "pet_id"
viaTargetColumn: "companion_pet_id"
viaTypeColumn: "companion_type"
viaTypeValue: "bonded pair"
viaLabelSource: "column"
}) {
success
}
}
Ассоциативную таблицу вы объявляете ребром; Provisa никогда не обнаруживает её сам. viaTable называет зарегистрированную таблицу. Два её ключевых столбца несут ребро, а каждый остальной столбец становится атрибутом связи, по которому можно фильтровать, как по любому полю. viaTypeColumn / viaTypeValue делят одну связующую таблицу на несколько типов рёбер. Например, строки pet_companions с companion_type, равным bonded pair, littermate или shares enclosure, дают три разные связи между одной и той же парой таблиц.
viaLabelSource указывает, откуда берётся открытое имя, и Cypher получает каждую форму в верхнем регистре с подчёркиваниями. column берёт viaTypeValue (BONDED_PAIR), table берёт собственное имя связующей таблицы (PET_COMPANIONS), а fixed берёт объявленный alias. Объявленная так связующая таблица является ребром. Provisa убирает её из меток узлов, поэтому в интерфейсе графа она никогда не появляется как плашка узла.
Обнаружение связей с помощью ИИ¶
Запросить у Claude кандидатов во внешние ключи через REST:
curl -X POST http://localhost:8001/admin/discover/relationships \
-H "Content-Type: application/json" \
-d '{"scope": "domain", "domain_id": "sales"}'
Возвращает кандидатов на внешние ключи, ранжированных по уверенности. Принять кандидата:
curl -X POST http://localhost:8001/admin/discover/candidates/{id}/accept \
-H "Content-Type: application/json" \
-d '{"name": "orders_to_customers"}'
Интроспекция схемы¶
Просмотр опубликованных таблиц по всем источникам:
query {
tables {
id
sourceId
columns {
columnName
unmaskedTo
}
writeGrants {
role
operation
columns
rows
check
presets { column source name value }
}
}
}
Проверка зависимостей колонки¶
Прежде чем сохранить правку таблицы, которая переименовывает SQL-псевдоним колонки или удаляет колонку, спросите, что ещё на неё ссылается:
query {
columnDependents(tableId: "42", renamed: ["order_total"], removed: ["legacy_code"]) {
columnName
dependents { kind name detail breaksOn }
}
}
Переименование псевдонима ломает каждый артефакт, написанный против открытого имени: представления, MV, выражения метрик, предикаты RLS и контракты DQ. Удаление столбца ломает их тоже, а также артефакты, которые хранят физический column_name: связи, привязки глоссария и назначения тегов. breaksOn указывает, что именно. Страница таблиц выполняет эту проверку при сохранении и показывает результат в предупреждающем диалоге. В разделе Происхождение данных описано, что охватывает запрос и чего он охватить не может.
Управление представлениями¶
Зарегистрировать материализованное представление:
mutation {
registerTable(input: {
viewSql: "SELECT o.id, o.amount, c.name FROM orders o JOIN customers c ON o.customer_id = c.id"
mvRefreshInterval: 300
materialize: true
}) {
success
}
}
Запустить обновление вручную:
Регистрация графовых источников¶
Источники Neo4j и SPARQL регистрируются через REST-эндпоинты (не через административный API GraphQL):
Neo4j:
# 1. Register the Neo4j source
curl -X POST http://localhost:8001/admin/sources/neo4j \
-H "Content-Type: application/json" \
-d '{"source_id": "graph", "host": "neo4j", "port": 7474, "database": "neo4j"}'
# 2. Preview a Cypher query (validates scalar projections)
curl -X POST http://localhost:8001/admin/sources/neo4j/graph/preview \
-H "Content-Type: application/json" \
-d '{"cypher": "MATCH (p:Person) RETURN p.name AS name, p.age AS age"}'
# 3. Register a table (runs preview+validate automatically)
curl -X POST http://localhost:8001/admin/sources/neo4j/graph/tables \
-H "Content-Type: application/json" \
-d '{"table_name": "people", "cypher": "MATCH (p:Person) RETURN p.name AS name, p.age AS age", "ttl": 300}'
SPARQL:
# 1. Register the SPARQL source
curl -X POST http://localhost:8001/admin/sources/sparql \
-H "Content-Type: application/json" \
-d '{"source_id": "kg", "endpoint_url": "http://fuseki:3030/ds/sparql"}'
# 2. Register a table (probes endpoint and infers columns)
curl -X POST http://localhost:8001/admin/sources/sparql/kg/tables \
-H "Content-Type: application/json" \
-d '{"table_name": "products", "sparql_query": "SELECT ?name ?category WHERE { ?p a :Product ; :name ?name ; :category ?category . }", "ttl": 600}'
После регистрации таблицы появляются в схеме GraphQL и доступны для запросов, как любой другой источник.
Импорт из Hasura / DDN¶
Преобразуйте существующий проект Hasura v2 или Hasura DDN в конфигурацию Provisa через административный интерфейс или API — ничего не будет записано, пока вы это не утвердите.
Предпросмотр преобразует загруженный архив и возвращает предлагаемый config_yaml, список предупреждений и сводку найденного (количество источников, доменов, таблиц, колонок, ролей, связей и правил RLS). В базу данных арендатора ничего не записывается. Тело запроса:
{
"filename": "my-hasura-project.zip",
"content_b64": "<base64-encoded archive>",
"flavor": "auto",
"domain_map": {"public": "sales"},
"source_overrides": {}
}
flavor принимает значения "auto" (определяется по структуре архива), "hasura_v2" или "ddn".
Применение загружает проверенный вами YAML, при желании отредактированный, в действующую организацию. Оно идёт тем же путём горячей перезагрузки, что и PUT /admin/config. Тело запроса: {"config_yaml": "<yaml string>"}.
Предпросмотр никогда не кеширует преобразованный YAML на сервере; применение берёт тот YAML, который вы передали, поэтому применяется ровно то, что было проверено.
Обмен через Apache Ossie¶
Provisa взаимодействует с Apache Ossie (incubating) как граница импорта и экспорта.
Экспорт (GET /admin/ossie) строит YAML-документ Ossie из живой управляемой модели при каждом запросе. Ничего не кэшируется, поэтому документ никогда не устаревает. Ответ имеет тип text/yaml с заголовком Content-Disposition: attachment. Документ представляет одну модель с version, name, datasets, relationships и metrics в корне. Таблицы становятся объектами dataset, столбцы объектами field, а связи отображаются на объекты Ossie relationship. Модель без таблиц отклоняется с кодом 422.
Импорт (POST /admin/ossie/import) принимает документ Ossie в YAML или JSON и сам определяет формат. Он разбирает документ и возвращает объект JSON с предлагаемыми регистрациями таблиц, связей и метрик. Ничего не регистрируется. Он читает только плоскую форму документа, а документ, оборачивающий модель в semantic_model, отклоняется с указанием имени. В интерфейсе администрирования экран проверки позволяет принять или сократить предложения до каких-либо изменений.
Объектное хранилище¶
Прочитать или настроить хранилище материализации организации:
GET сообщает, какую часть выделенного платформой объёма хранилища использует организация. PUT регистрирует собственный DSN хранилища организации (шифруется при хранении; никогда не возвращается методом GET). После настройки материализации организации попадают в её собственный бакет и больше не учитываются в платформенной квоте. Отправка storage_url: null очищает настройку и возвращает организацию в платформенное хранилище.
Шифрование организации¶
Задать или сменить ключ шифрования организации при хранении:
GET возвращает отпечаток, id и происхождение ключа и никогда сам ключевой материал. PUT задаёт или ротирует ключ. Передайте key_b64 (32 сырых байта в base64), чтобы использовать свой ключ, или опустите его, и Provisa сгенерирует ключ сам. Удаления нет: вывод последнего ключа из употребления сделал бы нечитаемым каждый обёрнутый им пакет.
GraphiQL¶
Административный API поставляется с GraphiQL по адресу GET /admin/graphql в браузере. В нём можно просмотреть всю административную схему и попробовать вызовы.
Управленческие представления домена ops¶
Каждая установка создаёт восемь SQL-представлений во встроенном домене ops. Они открывают журнал аудита запросов как управляемые таблицы. Вы запрашиваете их через SQL (pgwire), GraphQL и Cypher по тем же правилам доступа к домену, RLS и маскирования, что и любую бизнес-таблицу.
org_admin назначается ответственным за домен ops при создании, поэтому домен никогда не появляется как пробел в управлении в stale_metadata.
| Представление | На какой вопрос отвечает |
|---|---|
usage_ranking |
Количество запросов и число уникальных пользователей по каждой зарегистрированной таблице; таблицы с нулём обращений всплывают как кандидаты на вывод из эксплуатации |
deprecated_usage |
Каждое обращение к таблице или колонке с тегом deprecated — активные потребители, мешающие безопасному удалению |
pii_access |
Каждое обращение к таблице или колонке с тегом pii: кто запрашивал, под какой ролью, через какую поверхность |
policy_denials |
Все попытки доступа, отклонённые управлением (HTTP 401/403) |
surface_mix |
Ежедневное количество запросов и число уникальных пользователей по каждой протокольной поверхности (SQL, GraphQL, Cypher, gRPC и т. д.) |
query_health |
Ежедневное количество ошибок и средняя и максимальная задержка по каждой поверхности |
stale_metadata |
Таблицы и колонки без описаний; домены без ответственного |
join_hotspots |
Пары таблиц, которые запрашиваются вместе чаще всего, — кандидаты на материализацию или кеширование |
Детализация заканчивается на уровне таблицы. Журнал аудита записывает table_ids, а отдельные прочитанные запросом столбцы не записываются. Текст запросов зашифрован и не входит ни в одно из этих представлений; прочитать его можно только через авторизованный путь расшифровки для администраторов.
Роли нужен доступ к домену ops, чтобы эти представления были видны. Выдайте его так же, как доступ к любому другому домену.
-- Which tables have never been queried?
SELECT table_name, domain_id
FROM ops.usage_ranking
WHERE query_count = 0;
-- Who accessed PII-tagged data in the last 7 days?
SELECT user_id, role_id, source, pii_column, logged_at
FROM ops.pii_access
WHERE logged_at >= CURRENT_DATE - INTERVAL '7 days'
ORDER BY logged_at DESC;
-- Where does traffic originate by protocol?
SELECT source, day, query_count, distinct_users
FROM ops.surface_mix
ORDER BY day DESC, query_count DESC;
Поскольку представления являются управляемыми таблицами, те же запросы можно написать на GraphQL или Cypher.
Просмотр отчётов¶
Просмотр отчётов находится по адресу /admin/reports. Роли без возможности observability не могут его открыть.
Левая панель перечисляет каждую зарегистрированную таблицу домена ops, отсортированную по псевдониму. Восемь предустановленных управленческих представлений появляются там автоматически. Щёлкните любой отчёт, чтобы загрузить его в средстве просмотра управляемых данных справа.
Добавление собственного отчёта. Кнопка «Add report» открывает диалог, где вы указываете имя, необязательное описание и оператор SELECT. При сохранении представление регистрируется как управляемая производная таблица в домене ops. Оно попадает в каталог, подчиняется контролю доступа и запрашивается через любую поверхность, рядом с предустановленными представлениями.
Удаление. Значок корзины появляется только у собственных отчётов. Предустановленные управленческие представления нельзя удалить из этого интерфейса.
Предпросмотр таблицы¶
Разверните любую строку таблицы на странице таблиц. Кнопка Preview открывает модальное окно шириной 90% с живыми управляемыми данными таблицы.
Таблицы, основанные на API с обязательными параметрами пути, блокируют предпросмотр, пока эти значения не заданы. Встроенная форма собирает каждый обязательный параметр до первого запроса; необязательные параметры запроса появляются в той же форме.
Средство просмотра управляемых данных¶
Один и тот же компонент просмотра работает и в модальном окне предпросмотра, и в просмотре отчётов. Его поведение в обоих случаях одинаково.
Постраничная навигация на сервере. Каждая страница — это отдельный управляемый SELECT * с LIMIT 101 OFFSET n. На странице отображается 100 строк; 101-я показывает, есть ли ещё. Полный набор данных никогда не загружается в браузер.
Проталкиваемые фильтры и сортировки. В заголовке каждого столбца есть поле фильтра. Условие фильтра становится предикатом WHERE LOWER(CAST(col AS VARCHAR)) LIKE LOWER('%term%'), а щелчок сортировки создаёт предложение ORDER BY. Оба выполняются в базе данных. Фильтр по таблице в миллиард строк просматривает источник, и его действие никогда не ограничено страницей из 100 строк перед вами.
Многоуровневая группировка. Значок «Layers» в заголовке любой колонки включает эту колонку в группировку. Колонки группировки идут первыми в ORDER BY, чтобы члены группы попадали на ту же страницу, что и их заголовок, через границы страниц. Колонки первичного ключа добавляются в конец как устойчивый разделитель. Строки-заголовки групп сворачиваются; сворачивание скрывает члены группы без нового запроса.
Сохранение выбора. Настройки фильтра, сортировки и группировки сохраняются в localStorage под ключом provisa.grid.table:<domain>.<table> и восстанавливаются при следующем посещении.
Экспорт. Скачайте текущую страницу как CSV или скопируйте её в буфер обмена как текст с разделителями-табуляциями. Экспорт охватывает только видимую страницу.