Skip to content

Latest commit

 

History

History
202 lines (160 loc) · 64.5 KB

API_MAP.md

File metadata and controls

202 lines (160 loc) · 64.5 KB

Карта API Arkvory

Модули установки (ADR 0079, ADR 0078): GET/HEAD /api/v1/system/modules — версия API расширений, отпечатки плана (полный fingerprint и compatibilityFingerprint, который сравнивают процессы установки) и каждый модуль (версия, точка расширения, источник, core, enabled, роли, состояние в ответившем процессе); установленные подписанные модули, которые загрузчик отклонил, перечислены там же с running: false и health.status failed, revoked или unavailable и кодом (ADR 0079, X4). Surface discovery, глобальный administrator, без настроек и путей. SDK: client.system.modules(). GET /api/v1/capabilities дополнительно возвращает modules: [{id, kind}] — включённые модули ответившего шлюза (выключенный в ARKVORY_MODULES_FILE протокол отсутствует, его маршруты отвечают 404 not_found).

Лицензии установки (ADR 0078, Р2): GET/HEAD /api/v1/system/license — id установки, записанный процессом записи, эффективное время (максимум из времени БД, наибольшего наблюдённого времени и наибольшего issuedAt принятых документов), clockRollback, число ожидающих запросов офлайн-активации и каждая активация (licenseId, activationId, licensee, licenseType, activation, features, limits десятичными строками, notAfter, graceUntil, offlineGraceUntil, lastRefreshAt, refreshFailing, state и reason). Сохранённые документы проверяются заново при каждом запросе; документ, не ведущий к встроенному корню, — invalid. Без ключа лицензии, секрета активации и байтов подписи; ответ не ждёт хаб. Глобальный administrator. SDK: client.system.license().

Управление установленным кодом: GET/HEAD /api/v1/system/updates и POST /api/v1/system/updates/requests. Surface administration, глобальный administrator, команды check/configure/apply с revision и UUID. SDK: client.updates. Контракт, права и восстановление.

Резервные копии экземпляра (B2, ADR 0056): /api/v1/backup/*, surface administration, системные права backup.read/backup.manage (администратор учётных записей или файловый ключ владельца/bootstrap; ключи репозиториев — 403). Подробности — раздел 1a. Схема БД введена в 26; в ядре 0.6.3 актуальная — 52 (SCHEMA_VERSION).

Области ответственности, уровни видимости, каталог операций текущего credential и SDK для удалённых клиентов реализованы: API_SURFACES. GET/HEAD /api/v1/operations — authenticated, контекст repository необязателен, pagination до 100, advisory conditions. GET/HEAD /api/v1/openapi.json?surface=… — документационное представление. Версия схемы определяется packages/infrastructure/src/schema-version.ts; для выпущенного ядра 0.6.3 это 52.

Текущие версии и границы реализации: CURRENT_STATE. Это точка входа для интеграторов: реализованные маршруты ниже отделены от проектируемых расширений. Детальные JSON-схемы текущего сервера: GET /api/v1/openapi.json с действующим Bearer. OpenAPI сейчас 3.0.3; новую модель доступа описывает API_ACCESS, порядок внедрения — API_EVOLUTION.

Физическая очистка: GET/HEAD R/storage/cleanup (storage.read), PUT того же пути и POST R/storage/cleanup/run (storage.manage). Настройки с CAS, динамическая пауза, ограниченный проход и результат последнего выполнения: ONLINE_CLEANUP. Выполняется в фоне без остановки HTTP; 200 при запросе прохода не означает завершение удаления.

Размещение новых загрузок: GET/HEAD R/storage/placement (storage.read) и PUT того же пути (storage.manage, CAS по expectedRevision) — правила выбора хранилища и состояние каждого хранилища ответившего процесса; ненастроенное хранилище — 400 backend_unknown. Ответы upload-маршрутов содержат storageBackend; новая часть upload хранилища, переставшего принимать данные, — 409 backend_read_only (ADR 0083, N11).

Обозначения и общие правила

R = /api/v1/repositories/{repository}. read, write, administrator — реальные сегодняшние проверки; own означает того же principal, не просто любой ключ с write. Пользовательская сессия также допустима. Администратор не обходит read/write. В таблице «целевое право» permissions репозиторных операций разделов 2–3 уже действуют для managed keys; глобальные identity/policy permissions пока проектные. Service administration выполняется file bootstrap либо делегатом с отдельными действиями на точные аккаунты, см. текущий контракт ключей. Несколько прав через + обязательны одновременно.

У reader доступны только GET/HEAD, кроме инфраструктурного CORS preflight; изменяющие методы получают 405 даже при наличии права. /console/ размещается только на writer. Автоматические HEAD у Fastify GET могут присутствовать; ниже перечислены контрактные методы, для bytes HEAD указан явно.

Сейчас размеры JSON — десятичные строки, revision — ограниченное целое; timestamps UTC. JSON body по умолчанию до 64 KiB (больше — 413), upload content передаётся отдельным бинарным stream. Ошибка native: {code,message,requestId} и необязательные reason, details, retryAfterSeconds (ошибки). Неизвестный путь — 404 до аутентификации, иной метод известного пути — 405 с Allow, неподдерживаемый тип тела — 415. Нет/неверный/истёкший credential — 401 с причиной; недостаточно права — 403; чужой upload/job скрывается 404; конфликт — 409; hash mismatch — 422; исчерпанная ёмкость и ENOSPC/EDQUOT — 507; busy/unavailable, включая потерю соединения с PostgreSQL и drain при остановке, — 503 с Retry-After; непредвиденная ошибка сервера — 500 internal без Retry-After, её нельзя повторять автоматически. Не считать любой POST безопасным для автоматического retry.

1. Система и identity — реализовано

Метод и путь Текущий доступ Результат / важное условие Целевое право
GET /health/live Без ключа 200, минимальная liveness Публичный минимум
GET /health/status Без ключа 200 ready / 503 unavailable, draining; без подробностей, вне бюджета запросов Публичный минимум для балансировщика
GET /health/ready Любой действующий ключ/сессия 200/503, writable, role, агрегаты admission/bandwidth; вне бюджета запросов Совместимый прежний доступ; подробная диагностика отдельно system.observe
GET /health/metrics Любой действующий ключ/сессия 200 Prometheus text 0.0.4; шаблон маршрута, метод, класс; вне бюджета Как readiness; подробная диагностика отдельно system.observe
GET /api/v1/openapi.json Любой действующий ключ/сессия Рабочая спецификация Аутентифицированный доступ
POST /api/v1/auth/login Без предварительного ключа 200, token/expiresAt/account; password gate Учётные данные пользователя
GET /api/v1/auth/me Любой действующий ключ/сессия ID, administrator, точные repository grants Своя identity
POST /api/v1/auth/logout Действующая авторизация 204; отзыв текущей пользовательской сессии. Не отзывает file-based service key Своя сессия
POST /api/v1/auth/password Пользовательская сессия 204; currentPassword + newPassword, отзывает все сессии и PAT Своя учётная запись
POST /api/v1/auth/register Без предварительного ключа 201, сессия; при выключенной selfRegistration — 403, лимит по адресу Публичный минимум при включённой регистрации
POST /api/v1/feedback Любой действующий ключ/сессия 202, обращение авторам продукта; с serverLog — только администратор (ADR 0060) Свои учётные данные
GET /api/v1/feedback/attachments administrator, не managed key Серверный журнал и сводка установки, которые можно приложить к обращению Администратор
GET /api/v1/auth/options Без ключа 200, selfRegistration Публичный минимум
GET / POST / DELETE /api/v1/auth/tokens[/{id}] Только сессия, не PAT PAT: срок ≤ 365 дней, scope read/read-write, без administrator Свои учётные данные
GET / DELETE /api/v1/users/{id}/tokens[/{tokenId}] administrator, не PAT Список и отзыв PAT учётной записи identity.manage
GET /api/v1/security/audit administrator, не PAT Append-only журнал identity, курсор after, limit ≤ 100 identity.read
GET /api/v1/users administrator items, текущий предел 1000 пользователей identity.read
POST /api/v1/users administrator 201; name/password/administrator identity.manage, с ограничением назначения полномочий
PATCH /api/v1/users/{id} administrator 200; enabled и/или password; не изменение administrator identity.manage
GET /api/v1/access-groups administrator Группы с members/grants; до 100 групп identity.read
POST /api/v1/access-groups administrator 201; name identity.manage
PUT / DELETE /api/v1/access-groups/{id}/members/{userId} administrator 204; добавить/убрать membership identity.manage, membership не обходит delegation ceiling
PUT / DELETE /api/v1/access-groups/{id}/grants/{repository} administrator 204; access read/write либо снять grant policy.manage + разрешение делегировать конкретные actions/resources

CORS: OPTIONS для /api/v1/* и /health/ready проверяет origin/method/headers без Bearer. Это не разрешение на саму операцию; см. EXTERNAL_UI. /console/ — статический клиент, не API управления.

1a. Резервные копии — реализовано

Команды выполняет агент arkvory-backup agent; API ставит задания в очередь и читает состояние из БД, не принимает и не возвращает путей. Права проверяются до разбора входа. Байты — десятичные строки, время — ISO UTC. SDK: client.backup; CLI: arkvoryctl backup.

Метод и путь Право Результат / условие
GET /api/v1/backup/status backup.read vault {configured,id,available,encrypted,freeBytes,totalBytes} (encrypted — boolean или null: неизвестно, агент старой версии или нет vault.json; ADR 0070), agent {online,lastSeenAt,version}, plan, lastCompleted, nextRunAt, running, warnings
GET /api/v1/backup/plan backup.read {enabled,hour,minute,timezone,retention{daily,weekly,monthly},revision}
PUT /api/v1/backup/plan backup.manage Тело плана + expectedRevision; 200 план, 409 revision_mismatch, 400 validation с details (JSON Pointer)
POST /api/v1/backup/runs backup.manage Idempotency-Key обязателен; 202 {id,kind:'capture',state}; повтор ключа — то же задание; 507 queue_full при 100 открытых
POST /api/v1/backup/points/{id}/verify backup.manage Idempotency-Key; 202 {id,kind:'verify',state}, глубокая проверка; 404 для неизвестной точки; 409 idempotency_mismatch для ключа другой точки
POST /api/v1/backup/retention/apply backup.manage Idempotency-Key; 202 {id,kind:'retention',state}
GET /api/v1/backup/jobs?after&limit backup.read {items: Job[], next}, новые первыми, limit 1–100 (50); Job {id,kind,state,phase,startedAt,finishedAt,errorCode,pointId,progress}
GET /api/v1/backup/points?after&limit backup.read {items: Point[], next}, новейший T первым; Point {id,snapshotAt,completedAt,blobs,contentBytes,newBytes,tables,rows,pinned,verifiedAt,verifyDepth,…}
PUT /api/v1/backup/points/{id}/pin backup.manage {pinned: boolean} → Point; 404 для неизвестной или забытой точки
GET /api/v1/backup/retention/preview backup.read {keep: {id,reasons}[], delete: {id}[]}; reasons daily/weekly/monthly/pinned/newest; рекомендательный, apply решает заново по vault

state задания: queued|running|committing|completed|failed|interrupted; kind: capture|verify|retention. progress {bytesCopied,bytesTotal,blobsCopied,blobsTotal}: для копии — обработанные (скопированные или уже имевшиеся в vault) байты и объекты, для проверки — проверенные, для retention — удалённые blob и освобождённые байты. Коды предупреждений и уровни — CORE_RUNBOOK. GET также доступны как HEAD.

2. Загрузки, задания и байты — реализовано

Метод и путь Текущий доступ Контракт / повтор Целевое право
POST R/uploads write 201, descriptor; Idempotency-Key обязателен, конфликт другого descriptor upload.create
GET R/uploads/{id} write + own Состояние собственной сессии upload.read + own
DELETE R/uploads/{id} write + own 200, отменяет pending; опубликованный объект не удаляет upload.cancel + own
PUT R/uploads/{id}/content write + own 200, целый octet-stream с проверкой размера/SHA и публикацией. После потери ответа сначала status upload.write + upload.complete + own
GET R/uploads/{id}/parts write + own partBytes и принятые parts; часть от 8 MiB, до 1 GiB при >10 000 частей upload.read + own
PUT R/uploads/{id}/parts/{index} write + own 204; X-Content-SHA256, повтор той же части безопасен; другой hash — 409 upload.write + own
POST R/uploads/{id}/complete write + own 200; повтор завершённой сессии возвращает опубликованный результат upload.complete + own
POST R/uploads/{id}/complete-async write + own 202, durable job; публикация подтверждается отдельно upload.complete + own
GET /api/v1/jobs/{id} write в repo задания + own queued/running/completed/failed, attempts и errorCode job.read + own
GET R/artifacts read items/next; limit 1–100, по умолчанию 50, after artifact.list
GET R/artifacts/{id} read Только available; descriptor, не bytes artifact.read
GET / HEAD R/artifacts/{id}/content read GET: 200/206/304/416, ETag, Range/If-Range. HEAD не передаёт body и игнорирует Range content.read
GET / HEAD R/artifacts/{id}/tree?after=&limit= read Оглавление ZIP-артефакта (ADR 0083, N8): ready со страницами записей до 1000, pending, unavailable с reason content.read
GET / HEAD R/packages/content?group=…&name=…&version=… read Точная версия UPack; пустой group — корневая группа. Ответ как у artifacts/{id}/content content.read
GET / HEAD R/packages/content?name=…&range=…&stage=… read Версия по SemVer-диапазону и стадии, без них — старшая стабильная; правила content.read
GET / HEAD R/asset/content?path=… read Текущая ревизия файла по пути, исходные bytes; ответ как у artifacts/{id}/content content.read

packages/content (downloadPackageContent) и asset/content (downloadAssetContent) разрешают один неизменяемый артефакт на момент запроса и дальше используют тот же путь выдачи, что artifacts/{id}/content: ACL content.read без права перечислять пакеты/assets, admission, bandwidth, Range/ETag/If-Range. ETag относится к выбранному содержимому, поэтому If-Range после смены текущей ревизии или старшей версии не склеивает разные объекты. Аутентификация, как и у остальных операций, — Authorization: Bearer.

Upload owner привязан к principal. Долговечность сейчас — local filesystem + PostgreSQL; наличие маршрута resume не означает сохранность после потери диска/узла. Вся схема восстановления: TRANSFER_RECOVERY.

3. Каталог, metadata и ссылки — реализовано

Метод и путь Текущий доступ Контракт / граница Целевое право
GET R/artifacts/{id}/annotations read revision, labels, metadata, collections annotation.read
PUT R/artifacts/{id}/annotations read + write expectedRevision + value; CAS, 409 при конфликте annotation.write + artifact.read
POST R/artifacts/{id}/package read + write Читает и валидирует исходный UPack; регистрирует неизменяемую идентичность package.publish + artifact.read
GET R/packages read group/name, sort/direction/groupBy, after/limit; items/groups/next package.read
GET R/assets read prefix; items, текущий предел 1000, полноценного cursor нет asset.read
GET / HEAD R/assets/page read prefix/after/limit; items/next, до 100; literal prefix и UTF-8 порядок, контракт asset.read
GET R/asset?path=… read Текущий path/revision/artifactId asset.read
PUT R/asset read + write path/artifactId/expectedRevision; 0 для создания, CAS asset.write + artifact.read исходника
GET R/asset/history?path=…&before=… read До 50 ревизий и next asset.read
GET R/asset/revision?path=…&revision=… read Точная ревизия и artifactId asset.read
POST R/asset/restore read + write path/sourceRevision/expectedRevision; создаёт новую revision, не меняет старый blob asset.restore + asset.read + artifact.read
GET R/search read q/label/collection/metadata*/after; до 100 items (size, даты, labels, stages) и next artifact.list; metadata и collections не возвращаются — нужен annotation.read
GET R/audit?after=… write До 100 событий каталога; after — sequence, не аудит всех auth/download событий audit.read
GET R/changes?after=…&limit=… read Лента изменений репозитория для зеркал: публикация, удаление, аннотации, пакеты, пути (detail — путь), стадии (detail — стадия); порядок commit, без авторов; items/head/next, до 100 (ADR 0058) artifact.list
GET R/mirror read Состояние зеркального репозитория этой установки: фаза, caughtUp, ошибка, объём; 404 для обычного (ADR 0058) repository.read
GET /api/v1/events?after=…&limit=… любая сессия или ключ Лента событий установки, CloudEvents: до 500, types, repository; просмотр до 5000 строк, next за невидимыми; 410/409 для истёкшего курсора и новой эпохи (ADR 0080) artifact.list репозитория события; системные — глобальный администратор
GET /api/v1/events/types любая сессия или ключ Каталог типов событий со схемами data —
POST / DELETE R/artifacts/{id}/references read + write, reference owner 204; JSON body key, ссылка принадлежит principal reference.write + artifact.read
GET R/artifacts/{id}/stages read Текущие стадии продвижения, до 16 artifact.read
PUT / DELETE R/artifacts/{id}/stages/{s} read + write Идемпотентно добавляет/снимает стадию с журналом; body {comment} artifact.promote + artifact.read
POST R/artifacts/{id}/promote read (источник), write (цель) {target, mode: copy|move, stages, comment}; 201 копия, 200 существующая; контракт источник artifact.read + content.read, цель artifact.promote
GET R/artifacts/{id}/promotions, R/promotions read Журнал стадий и переносов по sequence, after/limit до 100 artifact.read / artifact.list
GET R/stages?stage=…&ids=… read Артефакты со стадией, cursor artifactId/stage; ids — до 100 artifact ID через запятую artifact.list
GET R/packages/resolve read name/group + version|range, stage, prerelease, order; версия, artifactId, SHA-256, стадии package.read
DELETE R/artifacts/{id} Только managed key Логическое удаление; body {expectedAnnotationRevision} обязателен, зависимости и CAS проверяются всегда; 200 не означает, что файл удалён физически (ARTIFACT_RETENTION) artifact.delete
GET R/artifacts/{id}/deletion Только managed key Инспекция опубликованного артефакта: блокирующие зависимости; без bytes artifact.delete
POST R/retention/preview Только managed key Страница кандидатов по criteria/limit/after, без изменений; на reader 405 artifact.delete
POST R/retention/apply Только managed key Повторно проверяет и обрабатывает только перечисленные IDs; результат по каждому объекту artifact.delete
GET / PUT R/storage/policy Только managed key Квоты и автоочистка; PUT с expectedRevision, CAS (STORAGE_POLICIES) storage.read / storage.manage
GET R/storage/usage Только managed key Опубликованные, незавершённые и ожидающие GC байты storage.read
GET R/storage/preview Только managed key До 100 кандидатов сохранённой политики, hasMore artifact.delete
POST R/storage/run Только managed key Одна порция включённой политики, body {expectedRevision}; на reader 405 storage.manage + artifact.delete
GET R/storage/events Только managed key События по возрастающему sequence, after, level, до 100 diagnostics.read
POST R/artifacts/{id}/links read (как content.read) 201 {token, url, expiresAt}; body {} или {ttlSeconds} (60–86400, по умолчанию 3600); токен dtl_… только в этом ответе; ссылка не выдаёт ссылок (ADR 0062) content.read
PUT R/raw/{assetPath} read + write Новая ревизия пути одним запросом (X-Checksum-Sha256, If-None-Match: *); 201 новая, 200 те же байты; 409 revision_mismatch; на reader 405 (ADR 0064) upload.*, asset.read + asset.write, artifact.read
GET / HEAD R/raw/{assetPath} read Текущая ревизия пути, Range, ETag, X-Arkvory-Artifact-Id content.read

Пустой group= выбирает корневую группу; отсутствие group — все группы. Cursor пакетов связан с параметрами запроса, страницы не образуют snapshot. SDK допускает package page и own permissions до 8 MiB; остальные JSON-ответы до 2 MiB. Эти различия сохраняются до отдельного совместимого изменения.

Отдельного CRUD для schemas, labels и collections пока нет: labels/collections — ограниченные поля annotations. Нет REST-управления репозиториями. Native удаление опубликованного содержимого есть, но только логическое и только для управляемого ключа с artifact.delete: DELETE R/artifacts/{id}, deletion и retention/* ниже; физическое освобождение места — storage/* (ARTIFACT_RETENTION, ONLINE_CLEANUP).

4. Сервисные API и дальнейшие расширения

Маршруты A/B ниже реализованы с уточнениями: создание аккаунтов и назначение делегирования требуют локального serviceAdministrator; управление существующими целями допускает отдельные admin actions в пределах ceiling. PATCH меняет только enabled; effective permissions не возвращает policy revision. GET /api/v1/service-accounts/{id}/audit требует bootstrap либо service-audit.read. Текущие контракты: ключи, делегирование и карта admin actions. В этапе C уже работают assets/page и список/карточки логических репозиториев; остальные строки C–E остаются проектом и не входят в рабочую OpenAPI.

Этап Метод / область Назначение и право
A GET /api/v1/capabilities Развёрнутые функции, gateway role, лимиты протокола; любой действующий credential. Не список чужих ресурсов.
A GET /api/v1/auth/permissions Собственные effective bindings, profile, credentialId и serviceAdministration; клиентский UX, не замена серверному authorize.
B GET / POST /api/v1/service-accounts Cursor-list: bootstrap или фильтр service-account.read; создание: только bootstrap.
B GET / PATCH /api/v1/service-accounts/{id} Карточка / enabled с expectedRevision: bootstrap либо service-account.read/manage. Policy меняется отдельным CAS-контрактом.
B GET / PUT /api/v1/service-accounts/{id}/policy Bootstrap либо policy.read/manage; expectedRevision, точные bindings, ceiling для изменения.
B GET / POST /api/v1/service-accounts/{id}/keys Metadata list / выдача pending key: bootstrap либо credential.read/manage. Secret только в первом ответе POST.
B GET /api/v1/api-keys/{id} Метаданные без hash/secret: bootstrap либо credential.read.
B POST /api/v1/api-keys/{id}/rotate Новый pending key, Idempotency-Key, прежние ограничения или сужение: bootstrap либо credential.manage + ceiling.
B POST /api/v1/api-keys/{id}/revoke Необратимый отзыв: bootstrap либо credential.manage + ceiling; повтор — 204.
B POST /api/v1/auth/activate-key Доказательство владения pending credential; 204, без выдачи дополнительных прав.
B GET /api/v1/api-keys/{id}/delegations Bootstrap либо владелец самого key; до 64 записей, включая tombstones.
B PUT / DELETE /api/v1/api-keys/{id}/delegations/{accountId} Только bootstrap, CAS expectedRevision; 200 grant/tombstone. PUT создания требует revision 0. Контракт.
C GET /api/v1/repositories и /{repository} Реализовано: собственные логические scopes, after/limit, карточка id/formats/permissions; managed repository.read, legacy собственные непустые grants. Настройки/создание не включены.
C Пагинация каталогов (assets/page и accounts/keys уже работают) Bounded pages, согласованный cursor, фильтрация ACL до LIMIT; старый ответ assets не менять молча.
C POST /api/v1/transfer-tickets Узкий краткоживущий допуск к одному immutable объекту; право выдачи отдельно от content access. Контракт после проверки gateway audience/revoke.
D GET R/changes (реализовано, ADR 0058); webhooks (реализовано файлом оператора, ADR 0069); GET / POST R/webhooks — не реализовано Cursor replay по ленте изменений; доставка webhook с подписью, повтором и защитой от SSRF. API подписок и event.read / webhook.manage остаются планом.
D Каталог schemas и типизированных metadata Версионированные схемы, ограниченная сложность; собственная policy, без исполнения пользовательского кода.
E Управление retention / операции удаления Реализованы explicit permission, preview, fixed-selection apply и защита ссылок/истории; scheduler и отдельный online GC реализованы: ONLINE_CLEANUP. Контракт.
E Статус replicas / gateways / очередей system.observe; управление квотами — отдельный операторский контракт, не параметр произвольного клиента.

Реализованы raw-файлы по пути в /api/v1 (ADR 0064) и протоколы рядом с ним: реестр образов OCI (ADR 0063), Git LFS с блокировками (ADR 0065) и npm-реестр для Unity Package Manager (ADR 0066). OAuth/OIDC federation, S3/NuGet adapters — потенциальные отдельные интеграции, не обещание совместимости. Они добавляются только при конкретном сценарии и используют те же authorizer/storage use cases.

5. Рецепты для клиентов

Клиент Рабочий маршрут сегодня Целевая минимизация
CI/CD create upload → parts → complete или async job → register package / set asset Publisher в одном repo, короткий срок ключа, отдельные identities dev/prod
Агент развёртывания packages/content или asset/content (либо resolve → artifact content) + Range/ETag Downloader либо только content по закреплённому объекту; approved/channel policy отдельно
Индексатор / каталог packages/search/annotations CatalogReader без content.read
Редактор metadata annotations GET/PUT с expectedRevision MetadataEditor без публикации и удаления
Внешняя браузерная консоль login/me + native SDK, CORS exact origin Пользовательские сессии; machine secret не встроен в frontend
Мониторинг authenticated health/ready Observer, минимум информации для health, подробности отдельно
Интеграция по событиям События GET /api/v1/events, GET R/changes (polling), webhook в файле оператора API управления подписками; события identity отдельно

6. Как поддерживать карту

При добавлении операции обновлять use case, runtime-схему, OpenAPI, SDK, право/ресурс в карте, негативные ACL-тесты и описание retry. HTTP method не определяет permission: GET jobs сегодня требует write, PUT annotations — read+write. Нельзя заменить эти проверки одним middleware «GET = read».

Экспортируемая OpenAPI описывает все операции, включая HEAD, liveness и сам endpoint спецификации. Все имеют operationId, описание авторизации, retry и роли шлюза. Сервер при onReady и CI сверяют фактические маршруты со схемой; исключения ограничены точными static GET/HEAD. При сборке создаётся packages/contracts/dist/openapi.json. Правила и границы проверок: API_CONTRACT_GUARD, ADR 0018.

Discovery: GET/HEAD /api/v1/repositories возвращает items/next (до 100), GET/HEAD /api/v1/repositories/{repository} — собственную карточку или 404. Это projection прав, не глобальный реестр storage и не право читать bytes. Точные правила и SDK.

Ревизионные вложения сборки: GET/HEAD/PUT /api/v1/repositories/{repository}/artifacts/{id}/attachments и GET/HEAD /attachments/history. Метаданные и произвольные метки используют существующий annotations API. Права, SDK и сценарии.

Логическое удаление и retention preview/apply реализованы в ARTIFACT_RETENTION: managed-only artifact.delete, CAS аннотаций, пины истории и receipts. Миграции 13/14. Реестр/настройки/квоты репозиториев, SDK distribution, identity delegation/SSO и глобальное управление очередями остаются отдельными этапами.

Настройки хранения: GET/PUT repositories/{repository}/storage/policy, GET storage/usage, GET storage/preview, POST storage/run, GET storage/events. Surface catalog, права storage.read/manage, artifact.delete и diagnostics.read по операции. Контракт.

Поиск GET search: q — literal substring имени или значения актуальной metadata без учёта регистра; metadataKey + metadataValue — точная пара с учётом регистра, задаются вместе. Значение может быть пустой строкой. Фильтры объединяются через AND, доступ и cursor/100 сохраняются. SQL параметризован; regex/wildcards не поддерживаются. См. CLI. Элемент результата: id, name, size (десятичная строка), createdAt, publishedAt (null, если время публикации не записано), labels (текущие: из annotation, иначе из descriptor загрузки) и stages (текущие стадии продвижения в байтовом порядке, до 16). Страница и стадии читаются одним ограниченным запросом без N+1. Metadata и collections в ответ не входят: для них нужен annotation.read.

Общий поиск GET /api/v1/search (ADR 0081, этап A1): те же элементы и поле repository. Ищет в репозиториях, где у принципала есть artifact.list (каждый проходит ту же проверку, что и R/search), — не больше первых 1000 по имени. Фильтры: q (до 240 символов, как в R/search), repositories (через запятую, до 100), labels (через запятую, до 8, нужны все), stage. Нечитаемый репозиторий в фильтре отбрасывается так же, как несуществующий, поэтому ответ не раскрывает существование. Порядок — (publishedAt desc, repository, id); для строк без времени публикации — время резервирования. Курсор непрозрачный (позиция в микросекундах, репозиторий, id), страница limit 1–100 (50 по умолчанию). Один запрос на страницу с собственным statement_timeout 5 с (тайм-аут — 503 unavailable); подстрока сканирует перечисленные репозитории, как и R/search (ADR 0075). Операция searchAllRepositories, доступ authenticated: фильтрует сам обработчик.