31 KiB
Ordinis API — Quick Start
Practical guide to НСИ-ordinis REST API. Тут не справочник всех endpoint'ов (для этого есть OpenAPI / Swagger UI), а минимально-достаточный путь от «первый запрос» до «подписался на webhook».
Версия: v2.37.x (/api/v1)
Swagger UI: https://ordinis.k8s.265.nstart.cloud/swagger-ui/index.html
(staging — на prod env-flagged)
0. Принципы
- REST + JSON. UTF-8. Все datetime в ISO-8601 UTC (
Zsuffix). - Базовый префикс —
/api/v1. Версионирование URL (breaking changes →/v2). - Auth — Keycloak OIDC, Bearer-токен в
Authorization. Anon разрешён дляPUBLICscope. - Pagination — на records list не поддерживается, возвращается весь массив. Для больших dicts фильтруй на клиенте или через
?at=time-slice. - Ошибки —
application/jsonс{status, code, message, traceId, timestamp}.
1. Base URL и проверка живости
# Production
ORDINIS=https://ordinis.nstart.cloud # prod (public LE)
# ORDINIS=https://ordinis.k8s.265.nstart.cloud # staging
# Staging
# ORDINIS=https://ordinis.k8s.265.nstart.cloud
curl "$ORDINIS/api/v1/version"
Ответ:
{
"version": "0.1.0-SNAPSHOT",
"commit": "2ca8f053",
"branch": "main",
"tag": "v2.37.0",
"builtAt": "2026-05-17T08:18:07.437Z"
}
2. Аутентификация
Большинство read-эндпоинтов работают без авторизации в PUBLIC scope.
Mutations, INTERNAL/RESTRICTED data, workflow и /me/* требуют JWT.
2.1 Получение токена через Keycloak (password grant)
TOKEN=$(curl -s -X POST \
"https://altum.nstart.cloud/auth/realms/altum/protocol/openid-connect/token" \
-d "client_id=ordinis" \
-d "grant_type=password" \
-d "username=user@example.com" \
-d "password=...." \
-d "scope=openid profile email" \
| jq -r .access_token)
Password grant — для CLI/CI/тестов. В production — OIDC Authorization Code с PKCE через ваш BFF.
2.2 Использование токена
curl -H "Authorization: Bearer $TOKEN" \
"$ORDINIS/api/v1/me/notifications/settings"
2.3 Скоупы данных
PUBLIC— открыто всем, включая anonINTERNAL— только для авторизованных с рольюRESTRICTED— узкий круг, как правило admin
Sidebar и search автоматически фильтруют по scope текущей сессии.
3. Справочники (dictionaries)
3.1 Список всех справочников
curl "$ORDINIS/api/v1/dictionaries"
[
{
"id": "58ba2127-...",
"name": "spacecraft",
"displayName": "Космические аппараты",
"description": "Каталог КА (космических аппаратов) ДЗЗ-миссий",
"scope": "PUBLIC",
"schemaVersion": "1.0.0",
"bundle": "cuod",
"supportedLocales": ["ru-RU", "en-US"],
"defaultLocale": "ru-RU",
"createdAt": "2026-05-07T21:20:51.623195Z",
"updatedAt": "2026-05-07T21:20:51.623195Z"
},
...
]
3.2 Детали одного справочника (со схемой)
curl "$ORDINIS/api/v1/dictionaries/spacecraft"
schemaJson — полный JSON Schema draft-07 с x-расширениями:
{
"name": "spacecraft",
"scope": "PUBLIC",
"schemaJson": {
"$schema": "http://json-schema.org/draft-07/schema#",
"$id": "https://ordinis.nstart.cloud/schemas/cuod/spacecraft/1.0.0",
"type": "object",
"required": ["designator", "name", "satellite_type_code", "status"],
"properties": {
"name": {
"type": "object",
"required": ["ru-RU"],
"x-localized": true,
"patternProperties": { "^[a-z]{2}-[A-Z]{2}$": { "type": "string" } }
},
"satellite_type_code": {
"type": "string",
"x-references": "satellite_type.code"
}
}
}
}
3.3 Граф зависимостей (FK)
curl "$ORDINIS/api/v1/dictionaries/graph/outgoing"
{
"outgoing": {
"spacecraft": { "fkCount": 2, "targets": ["satellite_type", "spacecraft_status"] },
"antenna": { "fkCount": 1, "targets": ["ground_station"] }
}
}
4. Записи (records)
Внимание к URL: записи живут под
/api/v1/{dictName}/records(а не/api/v1/dictionaries/{name}/records— это путь для drafts schema'ы).
4.1 Список записей
curl "$ORDINIS/api/v1/spacecraft/records?as_scope=PUBLIC"
as_scope обязателен (CSV: PUBLIC,INTERNAL,RESTRICTED).
[
{
"id": "a211eb15-...",
"businessKey": "1999-068A",
"data": {
"name": "Terra (EOS AM-1)",
"orbit": { "type": "SSO", "inclination_deg": 98.2 },
"status": "OPERATIONAL",
"country": "US",
"operator": "НАСА",
"satellite_type_code": "OPT_MIDRES_MS"
},
"validFrom": "2026-05-08T00:00:00Z",
"validTo": null,
"dataScope": "PUBLIC"
}
]
4.2 Одна запись по business key
curl "$ORDINIS/api/v1/spacecraft/records/1999-068A?as_scope=PUBLIC"
4.3 Фильтры
# Locale — для x-localized полей (name, mission, operator etc).
# ⚠️ Сейчас работает ТОЛЬКО через Accept-Language header. ?locale= query
# param backend игнорирует — TODO в roadmap.
curl -H "Accept-Language: en-US" \
"$ORDINIS/api/v1/spacecraft/records/1999-068A?as_scope=PUBLIC"
# default ru-RU: "mission": "Глобальный мониторинг суши и атмосферы"
# с Accept-Language en-US: "mission": "Global land and atmosphere monitoring"
# Time-travel: состояние на конкретный момент (validFrom <= at < validTo)
curl "$ORDINIS/api/v1/spacecraft/records/1999-068A?as_scope=PUBLIC&at=2026-01-01T00:00:00Z"
# По scope (если есть права на INTERNAL/RESTRICTED)
curl -H "Authorization: Bearer $TOKEN" \
"$ORDINIS/api/v1/spacecraft/records?as_scope=PUBLIC,INTERNAL"
# Geo (для geo-dicts с PostGIS support)
curl "$ORDINIS/api/v1/ground_station/records?as_scope=PUBLIC&bbox=30,55,40,60"
⚠️ НЕ работает на records list endpoint: ?limit=, ?offset= (pagination отсутствует), ?status=...&country=... (нет ad-hoc filtering по schema полям). Фильтруй на клиенте.
4.4 Сводка по запланированным записям
curl "$ORDINIS/api/v1/spacecraft/records/scheduled-summary?as_scope=PUBLIC"
{
"count": 0,
"nearestValidFrom": null,
"upcomingValidFroms": [],
"scheduledBusinessKeys": []
}
5. Smart Search
Поиск по содержимому всех справочников. Использует trigram-индекс.
curl "$ORDINIS/api/v1/search?q=Sentinel&limit=10"
{
"query": "Sentinel",
"total": 12,
"groups": [
{
"dictName": "mission",
"dictDisplayName": "Миссии / программы",
"count": 2,
"items": [
{ "businessKey": "SENTINEL_1", "dataScope": "PUBLIC", "createdAt": "..." },
{ "businessKey": "SENTINEL_2", "dataScope": "PUBLIC", "createdAt": "..." }
]
},
{
"dictName": "instrument",
"dictDisplayName": "Инструменты съёмки",
"count": 2,
"items": [ ... ]
}
]
}
Минимальная длина запроса — 3 символа. Search ограничен текущим scope сессии.
6. Bitemporal queries (TimeTravel)
6.1 История изменений записи
curl "$ORDINIS/api/v1/spacecraft/records/1999-068A/history"
Возвращает все версии (по valid_from) и transaction history (system_time).
6.2 Snapshot справочника на дату
curl "$ORDINIS/api/v1/dictionaries/spacecraft/snapshots?from=2026-01-01T00:00:00Z&to=2026-05-01T00:00:00Z&granularity=day"
Точная реконструкция справочника на момент asOf. Все записи, которые
действовали (valid_from ≤ asOf < valid_to) и были известны системе
(system_time ≤ now()).
6.3 Changelog схемы (структурные изменения)
curl "$ORDINIS/api/v1/dictionaries/spacecraft/changelog"
{
"dictionary": "spacecraft",
"currentVersion": "1.0.0",
"entries": []
}
Диff между двумя версиями схемы:
curl "$ORDINIS/api/v1/dictionaries/spacecraft/changelog/{entryId}/diff"
7. Шаблоны схем
curl "$ORDINIS/api/v1/dictionaries/templates"
[
{
"id": "antenna",
"name": "Антенна",
"description": "Скелет: код, имя, диаметр, FK на наземную станцию.",
"icon": "WifiHighIcon",
"tags": ["space", "hardware", "cuod"]
},
{ "id": "blank", "name": "Пустой каркас", ... },
{ "id": "spacecraft", "name": "Космический аппарат", ... }
]
Детали шаблона:
curl "$ORDINIS/api/v1/dictionaries/templates/spacecraft"
Вернёт { id, name, description, schemaJson } со sample JSON Schema.
8. AI: suggest field (требует auth)
Проверка фичи:
curl "$ORDINIS/api/v1/ai/info"
# { "enabled": true }
Если enabled: false — endpoint /suggest-field отдаст 404.
curl -X POST -H "Authorization: Bearer $TOKEN" \
-H "Content-Type: application/json" \
"$ORDINIS/api/v1/ai/suggest-field" \
-d '{"prompt": "контактный email оператора"}'
{
"fieldName": "operator_contact_email",
"schema": {
"type": "string",
"format": "email",
"description": "Контактный email оператора",
"x-references": "operator.code"
}
}
Лимиты: 30 запросов/мин на IP. Circuit breaker открывается на 5 минут
после 10 ошибок за 60 секунд (503 circuit_open).
9. Workflow согласований (требует auth)
9.1 Создать draft записи
curl -X POST -H "Authorization: Bearer $TOKEN" \
-H "Content-Type: application/json" \
"$ORDINIS/api/v1/dictionaries/spacecraft/records/drafts" \
-d '{
"operation": "CREATE",
"businessKey": "2026-099X",
"data": { "name": "Новый-1", "status": "PLANNED", ... },
"validFrom": "2026-06-01T00:00:00Z"
}'
Если approvalRequired=true у справочника — draft уходит ревьюеру.
Иначе — record создаётся напрямую (если у тебя есть права).
9.2 Мои drafts
curl -H "Authorization: Bearer $TOKEN" \
"$ORDINIS/api/v1/drafts/me"
9.3 Очередь ревьюера
curl -H "Authorization: Bearer $TOKEN" \
"$ORDINIS/api/v1/admin/reviews/pending"
9.4 Approve / reject
# Approve
curl -X POST -H "Authorization: Bearer $TOKEN" \
"$ORDINIS/api/v1/drafts/{id}/approve" \
-d '{ "comment": "ok, merging" }'
# Reject
curl -X POST -H "Authorization: Bearer $TOKEN" \
"$ORDINIS/api/v1/drafts/{id}/reject" \
-d '{ "comment": "не хватает источника данных" }'
10. Webhooks (admin)
10.1 Создать подписку
curl -X POST -H "Authorization: Bearer $TOKEN" \
-H "Content-Type: application/json" \
"$ORDINIS/api/v1/admin/webhooks/subscriptions" \
-d '{
"name": "my-consumer",
"url": "https://my-app.example.com/ordinis-hook",
"eventTypes": ["RecordCreated", "RecordUpdated", "SchemaDraftPublished"],
"scopeFilter": ["PUBLIC", "INTERNAL"],
"dictionaries": null,
"textWrap": false
}'
Ответ содержит secret — HMAC-SHA256 ключ для верификации подписи.
Покажется один раз, сохрани.
10.2 Структура payload (события)
{
"eventId": "evt_01HXY...",
"eventType": "RecordCreated",
"occurredAt": "2026-05-17T13:00:00Z",
"dictionary": "spacecraft",
"businessKey": "2026-099X",
"actor": "user-uuid-...",
"scope": "PUBLIC",
"after": { ... }
}
Заголовки:
X-Ordinis-Event: RecordCreatedX-Ordinis-Signature: sha256=<hex>(HMAC-SHA256 от body)X-Ordinis-Delivery: del_01HXY...User-Agent: ordinis-alerts
10.3 Верификация подписи (Node.js)
import crypto from 'crypto'
function verify(body, signatureHeader, secret) {
const [algo, hex] = signatureHeader.split('=')
if (algo !== 'sha256') return false
const expected = crypto
.createHmac('sha256', secret)
.update(body)
.digest('hex')
return crypto.timingSafeEqual(Buffer.from(expected), Buffer.from(hex))
}
10.4 Retry + DLQ
Доставка ретраится с backoff (1m, 5m, 30m, 2h, 12h). После 5 неудач — в DLQ. Ручной retry:
curl -X POST -H "Authorization: Bearer $TOKEN" \
"$ORDINIS/api/v1/admin/webhooks/deliveries/{id}/retry"
11. Errors
Все ошибки — JSON одинаковой формы:
{
"status": 422,
"code": "validation_failed",
"message": "name.ru-RU is required",
"details": { "field": "data.name.ru-RU" },
"traceId": "abc123...",
"timestamp": "2026-05-17T13:00:00Z"
}
| HTTP | code | Когда |
|---|---|---|
| 400 | bad_request |
Невалидный JSON, отсутствует обязательный field |
| 401 | unauthorized |
Нет или просрочен токен |
| 403 | forbidden |
Недостаточно прав / scope |
| 404 | not_found |
Нет такого справочника / записи / endpoint |
| 409 | conflict |
Concurrent update / unique constraint |
| 422 | validation_failed |
Schema validation fail |
| 429 | rate_limited |
Превышен лимит запросов |
| 500 | internal_error |
Серверная ошибка (см. traceId) |
| 502 | llm_error |
AI suggest — LLM недоступен |
| 503 | circuit_open |
AI suggest — circuit breaker открыт |
12. Готовые сниппеты
curl + jq (CI/CD)
# Все записи операторов в PUBLIC scope; фильтрация на клиенте
curl -s "$ORDINIS/api/v1/operator/records?as_scope=PUBLIC" \
| jq '.[] | select(.data.status == "ACTIVE") | {key: .businessKey, name: .data.name}'
TypeScript / Fetch
const ORDINIS = 'https://ordinis.nstart.cloud'
type SpacecraftRecord = {
businessKey: string
data: { name: string; status: string; orbit: { type: string } }
validFrom: string
dataScope: 'PUBLIC' | 'INTERNAL' | 'RESTRICTED'
}
async function getSpacecraft(): Promise<SpacecraftRecord[]> {
const r = await fetch(
`${ORDINIS}/api/v1/spacecraft/records?as_scope=PUBLIC`,
{ headers: { Accept: 'application/json', 'Accept-Language': 'en-US' } },
)
if (!r.ok) throw new Error(`Ordinis ${r.status}`)
return r.json()
}
Python (requests)
import requests
ORDINIS = "https://ordinis.nstart.cloud"
def smart_search(query: str, limit: int = 10) -> dict:
r = requests.get(f"{ORDINIS}/api/v1/search",
params={"q": query, "limit": limit},
timeout=10)
r.raise_for_status()
return r.json()
result = smart_search("Sentinel")
for group in result["groups"]:
print(f'{group["dictDisplayName"]}: {group["count"]} hits')
Java (HttpClient)
HttpClient http = HttpClient.newHttpClient();
HttpRequest req = HttpRequest.newBuilder()
.uri(URI.create(ORDINIS + "/api/v1/dictionaries/spacecraft"))
.header("Accept", "application/json")
.GET()
.build();
HttpResponse<String> resp = http.send(req, BodyHandlers.ofString());
DictionaryDetail detail = mapper.readValue(resp.body(), DictionaryDetail.class);
13. Дальше
- Приложение A: Cheat Sheet — одностраничник со всеми endpoints, ниже в этом документе
- OpenAPI:
$ORDINIS/v3/api-docs(staging) / Swagger UI выше - Postman collection:
~/Desktop/Ordinis-Postman/(27 рабочих запросов + 10-шаговый demo flow) - Bundle spec (для интеграторов):
bundle-format-spec.md - CHANGELOG:
docs/changelog.md— что меняется по версиям - Webhooks deep-dive: в admin UI →
/webhooks→ Detail page показывает histogram доставок, DLQ, signature test
Приложение A · Cheat Sheet
Дублирует
api-cheatsheet.md— одностраничный quick-reference со всеми endpoints, query-params, error codes и реальными примерами для copy-paste. Дублирование осознанное: интегратор открывает quickstart один раз, далее живёт в приложении.
Одностраничный референс. Полный гайд — api-quickstart.md.
Base prod: https://ordinis.nstart.cloud/api/v1 (public LE-cert)
Base staging: https://ordinis.k8s.265.nstart.cloud/api/v1 (Swagger UI здесь)
Version: v2.37.x · OpenAPI: /v3/api-docs (только staging — на prod Swagger выключен)
Auth
# client_credentials (для service-to-service интеграторов)
TOKEN=$(curl -s -X POST https://altum.nstart.cloud/auth/realms/altum/protocol/openid-connect/token \
-d grant_type=client_credentials \
-d client_id=$KC_CLIENT_ID -d client_secret=$KC_CLIENT_SECRET | jq -r .access_token)
curl -H "Authorization: Bearer $TOKEN" $ORDINIS/api/v1/spacecraft/records?as_scope=PUBLIC,INTERNAL
Scopes: PUBLIC (anon ok) · INTERNAL (auth) · RESTRICTED (admin).
Read (no auth для PUBLIC)
| Verb | Path | Что |
|---|---|---|
GET |
/version |
Версия + commit + builtAt |
GET |
/dictionaries |
Список всех справочников |
GET |
/dictionaries/{name} |
Детали + JSON Schema |
GET |
/dictionaries/templates |
6 шаблонов схем |
GET |
/dictionaries/templates/{id} |
Один шаблон со schemaJson |
GET |
/dictionaries/graph/outgoing |
FK-граф между справочниками |
GET |
/dictionaries/{name}/dependents |
Кто ссылается на этот dict |
GET |
/dictionaries/{name}/changelog |
Список изменений схемы |
GET |
/dictionaries/{name}/changelog/{id}/diff |
Diff между версиями |
GET |
/dictionaries/{name}/snapshots?from=&to=&granularity= |
Bucket'ы изменений для TimeTravel slider (granularity: hour/day/week) |
GET |
/{name}/records?as_scope=PUBLIC |
Список записей (⚠️ БЕЗ /dictionaries/ префикса) |
GET |
/{name}/records/{businessKey}?as_scope=PUBLIC |
Одна запись |
GET |
/dictionaries/{name}/records/{businessKey}/history?as_scope=PUBLIC |
История версий записи (Envers) — с /dictionaries/ |
GET |
/dictionaries/{name}/records/{businessKey}/cascade-preview?as_scope=PUBLIC |
Preview каскада — с /dictionaries/ |
GET |
/{name}/records/scheduled-summary?as_scope=PUBLIC |
Будущие версии (count + nearestValidFrom) |
GET |
/search?q= |
Поиск по справочникам (records не индексируются) |
GET |
/ai/info |
{enabled: bool} AI feature flag |
⚠️ Корень частой путаницы: consumer endpoints (
/records/...) идут БЕЗ/dictionaries/префикса. Admin-style audit endpoints (history, cascade-preview, changelog, drafts, snapshots) — С/dictionaries/. См. api-quickstart.md § Topology.
Query params (records)
?as_scope=PUBLIC,INTERNAL (required) CSV scope filter
?at=2026-03-15T00:00:00Z bitemporal: запись на конкретный момент (validFrom <= at < validTo)
Accept-Language: en-US (header) локаль — единственный рабочий путь
⚠️ ?locale= query param backend сейчас игнорирует
⚠️ Работает ТОЛЬКО на records endpoints.
Schema endpoint (`/dictionaries/{name}`) всегда
возвращает schemaJson на defaultLocale.
?bbox=lon1,lat1,lon2,lat2 geo: bounding box (для geo-dicts)
?polygon=<GeoJSON> geo: polygon-фильтр
Что НЕ работает (на read-api endpoint):
?limit=,?offset=— pagination отсутствует, возвращается весь массив?status=ACTIVE&country=RU— нет ad-hoc filtering по schema полям; фильтруй на клиенте
Write (требует auth)
⚠️ Все write-endpoints — на writer сервисе, с /dictionaries/ префиксом.
| Verb | Path | Что |
|---|---|---|
POST |
/dictionaries/{name}/records |
Создать запись (если approval не нужен) |
PUT |
/dictionaries/{name}/records/{businessKey} |
Обновить |
DELETE |
/dictionaries/{name}/records/{businessKey} |
Soft-delete (tombstone) |
POST |
/dictionaries/{name}/records/bulk-close |
Массовое закрытие |
POST |
/dictionaries/{name}/records/{businessKey}/cascade-close |
Закрыть с зависимыми |
POST |
/dictionaries/{name}/records/export-selected.csv |
Bulk export (выборка по ids в body) |
PATCH |
/dictionaries/{name}/schema |
Изменить схему inline (non-breaking) |
PUT |
/dictionaries/{name} |
Полностью пересоздать (breaking) |
Workflow (drafts + approvals)
| Verb | Path | Что |
|---|---|---|
POST |
/dictionaries/{name}/records/drafts |
Создать record draft |
POST |
/dictionaries/{name}/drafts |
Создать schema draft |
GET |
/dictionaries/{name}/drafts |
Список schema drafts по dict |
GET |
/dictionaries/{name}/drafts/active |
Активный draft (200+null если нет) |
GET |
/dictionaries/{name}/drafts/{id} |
Один draft |
DELETE |
/dictionaries/{name}/drafts/{id} |
Withdraw |
POST |
/dictionaries/{name}/drafts/{id}/review |
Назначить ревью |
POST |
/dictionaries/{name}/drafts/{id}/decision |
Approve/reject schema draft |
POST |
/dictionaries/{name}/drafts/{id}/publish |
Опубликовать после approve |
GET |
/drafts/me |
Мои record-drafts (status filter) |
GET |
/drafts/{id} |
Один record draft |
DELETE |
/drafts/{id} |
Withdraw record draft |
POST |
/drafts/{id}/approve |
Одобрить (body: {comment}) |
POST |
/drafts/{id}/reject |
Отклонить (body: {comment}) |
GET |
/admin/reviews/pending |
Очередь ревьюера (records) |
GET |
/admin/schema-reviews/pending |
Очередь ревьюера (schemas) |
GET |
/admin/schema-drafts/me |
Мои schema drafts |
AI
curl -X POST -H "Authorization: Bearer $TOKEN" -H "Content-Type: application/json" \
$ORDINIS/api/v1/ai/suggest-field \
-d '{"prompt":"контактный email оператора"}'
Limits: 30 req/min на IP, circuit breaker 10 fails / 60s → open 5min (503 circuit_open).
Notifications (per-user, auth)
| Verb | Path | Что |
|---|---|---|
GET |
/me/notifications |
Bell-bar feed |
POST |
/me/notifications/{id}/read |
Mark as read |
POST |
/me/notifications/read-all |
Mark all as read |
GET |
/me/notifications/preferences |
Per-event matrix |
PUT |
/me/notifications/preferences |
Сохранить матрицу |
GET |
/me/notifications/settings |
Quiet hours config |
PUT |
/me/notifications/settings |
Сохранить quiet hours |
Webhooks (admin)
| Verb | Path | Что |
|---|---|---|
GET |
/admin/webhooks/subscriptions |
Список подписок |
POST |
/admin/webhooks/subscriptions |
Создать (secret в ответе, один раз) |
GET |
/admin/webhooks/subscriptions/{id} |
Детали |
PUT |
/admin/webhooks/subscriptions/{id} |
Обновить |
DELETE |
/admin/webhooks/subscriptions/{id} |
Удалить |
POST |
/admin/webhooks/subscriptions/{id}/rotate-secret |
Перевыпуск ключа |
POST |
/admin/webhooks/subscriptions/{id}/test |
Test delivery |
GET |
/admin/webhooks/subscriptions/{id}/stats |
Histogram (24h/7d) |
GET |
/admin/webhooks/subscriptions/{id}/deliveries |
Recent deliveries |
GET |
/admin/webhooks/deliveries/dlq |
DLQ list |
POST |
/admin/webhooks/deliveries/{id}/retry |
Manual retry |
Headers delivered
X-Ordinis-Event: RecordCreated
X-Ordinis-Signature: sha256=<hex> HMAC-SHA256(body, secret)
X-Ordinis-Delivery: del_01HXY...
User-Agent: ordinis-alerts
Event types
RecordCreated · RecordUpdated · RecordClosed · RecordRestored · BulkClosed · SchemaDraftSubmitted · SchemaDraftApproved · SchemaDraftRejected · SchemaDraftPublished · RecordDraftSubmitted · RecordDraftApproved
Audit (admin)
| Verb | Path | Что |
|---|---|---|
GET |
/admin/audit?dictionary=&action=&user=&dateFrom=&dateTo= |
Фильтрованный аудит |
GET |
/admin/audit/export.csv |
Полный экспорт |
GET |
/admin/audit/export-selected.csv |
Selected ids экспорт |
Action types (13): DICTIONARY_CREATED · SCHEMA_UPDATED · SCHEMA_PUBLISHED · RECORD_CREATED · RECORD_UPDATED · RECORD_CLOSED · RECORD_RESTORED · DRAFT_CREATED · DRAFT_SUBMITTED · DRAFT_APPROVED · DRAFT_REJECTED · DRAFT_WITHDRAWN · REVIEWER_ASSIGNED
Outbox (admin)
| Verb | Path | Что |
|---|---|---|
GET |
/admin/outbox/stats |
Pending/DLQ counters |
GET |
/admin/outbox/dlq |
DLQ events list |
Errors — единая форма
{ "status": 422, "code": "validation_failed", "message": "...",
"details": {}, "traceId": "...", "timestamp": "..." }
| HTTP | code | |
|---|---|---|
| 400 | bad_request |
Невалидный body |
| 401 | unauthorized |
Нет/просрочен токен |
| 403 | forbidden |
Scope/role не пускает |
| 404 | not_found |
Нет такого ресурса |
| 409 | conflict |
Concurrent update / unique violation |
| 422 | validation_failed |
Schema validation fail |
| 429 | rate_limited |
Лимит запросов |
| 500 | internal_error |
См. traceId |
| 502 | llm_error |
AI: LLM upstream |
| 503 | circuit_open |
AI: circuit breaker |
Реальные примеры (staging 265)
FK-зависимость: кто использует справочник
curl -s "$ORDINIS/api/v1/dictionaries/satellite_type/dependents" | jq
# [
# {
# "sourceDict": "spacecraft",
# "sourceDisplayName": "Космические аппараты",
# "sourceField": "satellite_type_code",
# "targetField": "code",
# "onClose": "BLOCK",
# "activeRecordsInSourceDict": 14
# }
# ]
Семантика: spacecraft.satellite_type_code ссылается на satellite_type.code. На staging 14 КА используют этот справочник, и onClose: BLOCK означает что нельзя удалить тип КА пока на него ссылаются записи (без cascade-close).
Другие живые FK на staging:
ground_station←antenna.ground_station(4 records, BLOCK)spacecraft_status←spacecraft.statuscountry←spacecraft.country
Локализация записи (Accept-Language)
# default ru-RU
curl -s "$ORDINIS/api/v1/spacecraft/records/1999-068A?as_scope=PUBLIC" | jq '.data | {mission, operator}'
# {"mission": "Глобальный мониторинг суши и атмосферы", "operator": "НАСА"}
# en-US
curl -sH "Accept-Language: en-US" \
"$ORDINIS/api/v1/spacecraft/records/1999-068A?as_scope=PUBLIC" | jq '.data | {mission, operator}'
# {"mission": "Global land and atmosphere monitoring", "operator": "NASA"}
⚠️ Только Accept-Language header. ?locale= query param backend сейчас игнорирует. Schema endpoint (/dictionaries/{name}) не локализуется вообще — всегда возвращает на defaultLocale.
Time-travel: запись на момент в прошлом
# Запись на 14.05.2026 12:00 UTC (точно после её validFrom = 11:34)
curl -s "$ORDINIS/api/v1/test1/records/Dima_record_test_1?as_scope=PUBLIC&at=2026-05-14T12:00:00Z" \
| jq '{businessKey, validFrom, validTo, data}'
# 200 OK — запись действительная на указанный момент
# До validFrom → 404 record_not_active (это ожидаемо)
curl -s "$ORDINIS/api/v1/test1/records/Dima_record_test_1?as_scope=PUBLIC&at=2026-05-01T00:00:00Z" | jq '.code'
# "record_not_active"
History — все ревизии записи
curl -s "$ORDINIS/api/v1/dictionaries/spacecraft/records/1999-068A/history?as_scope=PUBLIC" | jq '.[0] | {revisionNumber, revisionType, updatedAt}'
Schema time-travel (changelog diff)
# Список ревизий
curl -s "$ORDINIS/api/v1/dictionaries/test1/changelog" | jq '.currentVersion, (.entries | length)'
# Diff конкретной ревизии (before/after JSON-Schema)
curl -s "$ORDINIS/api/v1/dictionaries/test1/changelog/22/diff" | jq '{eventType, occurredAt, before: .before.properties | keys, after: .after.properties | keys}'
60-second smoke
ORDINIS=https://ordinis.nstart.cloud # prod (public LE)
# или: ORDINIS=https://ordinis.k8s.265.nstart.cloud # staging
curl -s $ORDINIS/api/v1/version | jq # alive
curl -s $ORDINIS/api/v1/dictionaries | jq 'length' # 37 на prod / 39 на staging
curl -s $ORDINIS/api/v1/dictionaries/spacecraft | jq '.scope' # "PUBLIC"
curl -s "$ORDINIS/api/v1/spacecraft/records?as_scope=PUBLIC" | jq '.[0].businessKey'
curl -s "$ORDINIS/api/v1/dictionaries/satellite_type/dependents" | jq 'length' # 1 (spacecraft зависит)
curl -s "$ORDINIS/api/v1/search?q=spacecraft" | jq '.total' # >0
curl -s $ORDINIS/api/v1/ai/info | jq '.enabled' # true / false
Постман collection (на случай если потерял ссылку из section 13)
27 рабочих запросов + 10-шаговый demo flow:
~/Desktop/Ordinis-Postman/(если генерировал локально)- docs/integration/postman/ — версионный snapshot
— конец приложения A —