76 lines
5.9 KiB
Markdown
76 lines
5.9 KiB
Markdown
# hub-api Specification
|
||
|
||
## Purpose
|
||
TBD - created by archiving change bridge-core. Update Purpose after archive.
|
||
|
||
## Requirements
|
||
|
||
### Requirement: Процесс и доступ
|
||
`jira-hub serve` SHALL запускать один процесс: HTTP на `0.0.0.0:<port>` (по умолчанию 8790), база и настройки в
|
||
`~/.local/share/jira-hub/` (переопределяется `JIRA_HUB_HOME`). Все маршруты SHALL требовать `Authorization: Bearer <token>`:
|
||
агентский токен открывает только `/agent/*`, клиентский — всё остальное. Ответы — JSON, ошибки — `{error, detail}` с
|
||
кодами 400/401/404/409/422.
|
||
|
||
#### Scenario: Чужой токен
|
||
- **WHEN** агентским токеном вызван `GET /issues`
|
||
- **THEN** 401
|
||
|
||
### Requirement: Маршруты агента
|
||
Хаб SHALL предоставлять агенту следующие маршруты (все под агентским токеном):
|
||
- `POST /agent/claim` `{agent_version, settings_version, last_jira_call_at}` — долгий запрос до 30 с; ответ `{command:
|
||
{id, type, params, pause_seconds}, settings_version}` или `{command: null, settings_version}`; обновляет `agent_status`.
|
||
- `GET /agent/settings` — настройки для агента (без токенов).
|
||
- `GET /agent/commands/{id}` — команда по id (для восстановления из журнала).
|
||
- `POST /agent/commands/{id}/result` `{status, result, error, jira_calls, rate_limited}` — идемпотентно: повторный
|
||
отчёт по команде в терминальном статусе отвечает 200 без изменений.
|
||
- `POST /agent/state` `{command_id, issues: [...], links: [...], neighbor_keys: [...], page, last_page}` — загрузка состояния
|
||
пачками; `neighbor_keys` — ключи вне базовой JQL, дочитанные по связям; хаб обновляет зеркало и `sync_run`.
|
||
- `GET /agent/known-keys` — ключи зеркала (для определения соседей).
|
||
|
||
#### Scenario: Выдача с подстановкой ключа
|
||
- **WHEN** следующая команда ссылается на `new:60`, а `ensure_issue` для `new:60` завершилась с `AURORA-1590`
|
||
- **THEN** `claim` отдаёт команду с `AURORA-1590` в параметрах
|
||
|
||
#### Scenario: Повторный отчёт
|
||
- **WHEN** агент дважды прислал `result` для команды 15
|
||
- **THEN** второй ответ 200, статус и результат не изменились
|
||
|
||
### Requirement: Маршруты интерфейсов
|
||
Хаб SHALL предоставлять интерфейсам (MCP, позже просмотрщик) следующие маршруты под клиентским токеном:
|
||
- `GET /issues` с фильтрами `sprint`, `assignee`, `work_kind`, `fact_status`, `status`, `label`, `epic`, `neighbor`,
|
||
`q` (подстрока темы), `limit`/`offset` — компактные карточки (ключ, тема, статус, приоритет, срок, исполнитель, спринт,
|
||
эпик, заметки кратко).
|
||
- `GET /issues/{key}` — задача целиком: поля, связи в обе стороны, заметки, последние 10 команд по ней.
|
||
- `PUT /issues/{key}/note` — заметки (частичное обновление, `updated_by` из тела).
|
||
- `POST /batches` `{title, author, commands: [...]}` → `{id, estimate_seconds}`; 422 при неизвестном типе, неверных
|
||
параметрах, временном ключе без `ensure_issue`.
|
||
- `GET /batches?limit=`, `GET /batches/{id}` (с командами), `POST /batches/{id}/cancel`.
|
||
- `POST /commands/{id}/retry` — новая команда с теми же параметрами в новом пакете «Повтор команды N».
|
||
- `POST /commands/{id}/cancel` — только для `queued`; для `claimed` — 409, если не передан `force: true`.
|
||
- `POST /refresh` `{keys | jql | full: true}` → пакет из одного `refresh`.
|
||
- `GET /agent`, `GET /sync-runs?limit=`, `GET /settings`, `PUT /settings` (частично; поднимает `settings_version`).
|
||
|
||
#### Scenario: Фильтр по спринту
|
||
- **WHEN** `GET /issues?sprint=Спринт 2`
|
||
- **THEN** только задачи с таким `sprint`, отсортированы по сроку, затем по ключу
|
||
|
||
#### Scenario: Отмена взятой команды
|
||
- **WHEN** `POST /commands/15/cancel` без `force`, команда `claimed`
|
||
- **THEN** 409 с `claimed_at`; с `force: true` — `cancelled`, следующий отчёт агента по ней принимается, но статус не меняется
|
||
|
||
### Requirement: Резервные копии
|
||
Перед выдачей первой команды пакета, содержащего записи в Jira, хаб SHALL скопировать файл базы в `backups/<дата-время>-<batch>.sqlite`
|
||
и хранить последние `backup_keep` копий.
|
||
|
||
#### Scenario: Ротация
|
||
- **WHEN** копий больше `backup_keep`
|
||
- **THEN** самые старые удаляются до `backup_keep`
|
||
|
||
### Requirement: Автообновление зеркала
|
||
Если `auto_refresh_minutes > 0`, агент на связи и очередь пуста дольше этого интервала, хаб SHALL поставить пакет
|
||
«Автообновление» из `refresh {jql: base_jql}`.
|
||
|
||
#### Scenario: Очередь занята
|
||
- **WHEN** интервал прошёл, но в очереди есть `queued` команды
|
||
- **THEN** автообновление не ставится до опустошения очереди
|