16 KiB
16 KiB
ADDED Requirements
Requirement: Маршруты проектов
Хаб SHALL предоставлять под клиентским токеном:
GET /projects→ список{label, name, board_id, board_type, created_at, issues_count}поcreated_at, затемlabel;issues_count— задачи зеркала с меткой проекта.POST /projects{label, name, board_id?, author?}→ 201{project, batch_id}: в одной транзакции проект записывается и ставится пакет «Новый проект <метка>» из одногоrefreshпо базовой JQL, уже включающей новую метку; автор пакета —author(по умолчаниюapi). Неверные поля (см.data-model, «Проекты») — 422 с указанием поля; метка, совпадающая с существующей без учёта регистра, — 409. При ошибке ни проекта, ни пакета нет.
Scenario: Новый проект
- WHEN
POST /projects {label: "STOCKS_DRRK", name: "Запасы ДРРК", board_id: 5120, author: "viewer"}, есть проектAWPCA - THEN 201;
GET /projectsотдаёт два проекта, уSTOCKS_DRRKboard_type = null; в очереди пакет автораviewerсrefresh {jql: "project = AURORA AND labels in (AWPCA, STOCKS_DRRK)"}
Scenario: Проект без доски
- WHEN
POST /projects {label: "STOCKS_DRRK", name: "Запасы ДРРК"} - THEN 201,
board_id = null
Scenario: Повтор метки
- WHEN
POST /projects {label: "AWPCA", name: "…"}, проектAWPCAесть - THEN 409, пакет не поставлен
Scenario: Без названия
- WHEN
POST /projects {label: "STOCKS_DRRK", name: " "} - THEN 422 с указанием поля
name
MODIFIED Requirements
Requirement: Маршруты интерфейсов
Хаб SHALL предоставлять интерфейсам (MCP, веб-приложение) следующие маршруты под клиентским токеном:
GET /issuesс фильтрамиproject(разрез по проекту, см.data-model, «Проекты»: свои и соседи,neighborотносительно проекта; неизвестный проект — 404),sprint,assignee,work_kind,fact_status,status,label,epic,neighbor,q(подстрока темы),hide_closed(1/true— без задач, чейstatusвходит в настройкуclosed_statuses; задача без статуса не закрыта),limit/offset— строки зеркала (все поляissue) сfact_statusиwork_kindиз заметок; сокращение до карточки — дело интерфейса. Безproject— всё зеркало,neighbor— признак зеркала (вне базовой JQL).GET /issues/{key}— задача целиком: поля,epic_summary(тема эпика из зеркала илиnull), связи в обе стороны (links_out: [{target_key, link_type, summary, status}],links_in: [{source_key, link_type, summary, status}], гдеsummaryиstatus— связанной задачи из зеркала илиnull, если её там нет), заметки, последние 10 команд по ней,comments: [{comment_id, author, created, updated, body}]— все комментарии, новые сверху (поcreated, затемcomment_id, по убыванию).PUT /issues/{key}/note— заметки (частичное обновление,updated_byиз тела).POST /batches{title, author, project?, commands: [...]}→{id, estimate_seconds}; 422 при неизвестном типе, неверных параметрах (в том числе неверного типа значения), временном ключе безensure_issue, двух и болееensure_issueс одинаковойsummary(сравнение после обрезки пробелов по краям; в ответе перечислены повторяющиеся темы), по проверкам постановки изcommands(типbugбез настройки, файл вложения не загружен, доска дляensure_sprint), а также по проверкам пакета проекта (см.commands), если переданproject.POST /files{content}(content— base64 содержимого файла) →{file, size}, гдеfile— sha256 содержимого (64 hex-символа, нижний регистр); см. «Хранилище файлов вложений».GET /batches?limit=&project=(сproject— только пакеты этого проекта),GET /batches/{id}(с командами иproject),POST /batches/{id}/cancel— отменяетqueuedкоманды пакета; ответ — вид пакета с полемstill_claimed: список{id, type}команд пакета вclaimed(они будут выполнены агентом; остановить — отмена команды сforce).POST /commands/{id}/retry{author?, project?}— новая команда с теми же параметрами в новом пакете «Повтор команды N»; хаб снимает с параметров то, что дописывает сам (board_idуensure_sprint), и проверяет команду заново.projectпередан и у исходного пакета другой проект (или его нет) — 422 «команда #N не из проекта P»; не передан — новый пакет получает проект исходного и проходит его проверки.POST /commands/{id}/cancel— только дляqueued; дляclaimed— 409, если не переданforce: true.POST /refresh{keys | jql | full: true}→ пакет из одногоrefresh;full— по базовой JQL из проектов, без проектов — 422 «нет проектов».GET /agent,GET /sync-runs?limit=,GET /settings,PUT /settings(частично; поднимаетsettings_version; ответ — все настройки после записи, как уGET /settings, включаяsettings_version).
Scenario: Фильтр по спринту
- WHEN
GET /issues?sprint=Спринт 2 - THEN только задачи с таким
sprint, отсортированы по сроку, затем по ключу
Scenario: Список проекта
- WHEN свои задачи
STOCKS_DRRK— AURORA-1 и AURORA-4, сосед — AURORA-2;GET /issues?project=STOCKS_DRRK - THEN три задачи, у AURORA-2
neighbor = true; сneighbor=1— только AURORA-2; задач только с меткойAWPCAнет
Scenario: Неизвестный проект
- WHEN
GET /issues?project=NOPE - THEN 404
Scenario: Пакеты проекта
- WHEN пакет 10 поставлен с
project = STOCKS_DRRK, пакет 11 — без проекта;GET /batches?project=STOCKS_DRRK - THEN в ответе только пакет 10
Scenario: Повтор чужой команды
- WHEN команда 40 из пакета проекта
AWPCA;POST /commands/40/retry {project: "STOCKS_DRRK"} - THEN 422 «команда #40 не из проекта STOCKS_DRRK», пакет не создан
Scenario: Повтор ensure_sprint
- WHEN
ensure_sprint41 failed, в еёparamsboard_id = 4216;POST /commands/41/retry - THEN новый пакет создан,
board_idв новой команде вычислен хабом заново
Scenario: Полный прогон без проектов
- WHEN проектов нет,
POST /refresh {full: true} - THEN 422 «нет проектов», пакет не поставлен
Scenario: Отмена взятой команды
- WHEN
POST /commands/15/cancelбезforce, командаclaimed - THEN 409 с
claimed_at; сforce: true—cancelled, следующий отчёт агента по ней принимается, статус не меняется
Scenario: Поздний отчёт по отменённому созданию
- WHEN
ensure_issue {temp_key: new:7, …}отменена сforce: true, затем агент прислалdoneсresult.key = AURORA-1620 - THEN команда
cancelled, вresult—AURORA-1620; заметкаnew:7перенесена наAURORA-1620
Scenario: Дубль темы в пакете
- WHEN
POST /batchesс двумяensure_issue, у обеихsummary = "Шахматка: комментарии" - THEN 422 с темой «Шахматка: комментарии», пакет не создан
Scenario: Тема не строка
- WHEN
POST /batchesсensure_issue {temp_key: new:1, summary: 42, …} - THEN 422 с указанием параметра
summary, пакет не создан
Scenario: Отмена пакета с командой у агента
- WHEN в пакете 9 команда 30
claimed, команды 31 и 32queued;POST /batches/9/cancel - THEN 31 и 32
cancelled; в ответеstill_claimed = [{id: 30, type: …}]; 30 остаётсяclaimed
Scenario: Ответ на запись настроек
- WHEN
PUT /settings {relay_dir: "/Volumes/externalSSD/utm/rshb/jira-bridge"} - THEN 200; ответ содержит
relay_dirс записанным значением, новуюsettings_versionи остальные настройки; токенов в ответе нет
Scenario: Карточка с комментариями и связями
- WHEN у AURORA-9001 два комментария (14.10 и 15.10), исходящая связь на AURORA-9002 («API свода», «Новая») и на AURORA-1, которой нет в зеркале; эпик AURORA-9100 «Тестовый эпик»
- THEN
GET /issues/AURORA-9001отдаётcommentsс комментарием от 15.10 первым, у связи на AURORA-9002 —summary = "API свода",status = "Новая", у связи на AURORA-1 —summary = null,status = null;epic_summary = "Тестовый эпик"
Scenario: Без закрытых
- WHEN
closed_statuses = ["Готово", "Снято"], в зеркале задачи в статусах «В работе», «Готово», «Снято» и без статуса;GET /issues?hide_closed=1 - THEN в ответе задачи «В работе» и без статуса; без
hide_closed— все четыре
Requirement: Автообновление зеркала
Если auto_refresh_minutes > 0, агент на связи и есть хотя бы один проект, хаб SHALL поставить пакет «Автообновление»
из refresh {jql: <базовая JQL из проектов>}, когда в очереди нет команд в queued и claimed и последний sync_run
начат раньше, чем auto_refresh_minutes назад (или sync_run ещё нет).
Scenario: Очередь занята
- WHEN интервал прошёл, но в очереди есть
queuedкоманды - THEN автообновление не ставится до опустошения очереди
Scenario: Есть выданная команда без отчёта
- WHEN интервал прошёл,
queuedнет, одна команда вclaimed - THEN автообновление не ставится; команда довыдаётся при следующем
claim
Scenario: Недавнее обновление
- WHEN очередь пуста,
auto_refresh_minutes = 60, последнийsync_runначат 20 минут назад - THEN автообновление не ставится
Scenario: Два проекта
- WHEN интервал прошёл, очередь пуста, проекты
AWPCAиSTOCKS_DRRK - THEN поставлен один
refreshс JQLproject = AURORA AND labels in (AWPCA, STOCKS_DRRK)
Requirement: Снимок доски
Хаб SHALL предоставлять GET /board?project= под клиентским токеном — согласованный снимок зеркала для доски связей,
прочитанный в одной транзакции:
generated_at— момент снимка (UTC);last_sync— последний завершённый полный прогон (refreshпо текущей базовой JQL из проектов):{started_at, finished_at, issues_count}илиnull, если такого не было; общий для всех проектов;issues— сproject— свои задачи проекта и его соседи (см.data-model, «Проекты»),neighborотносительно проекта; безproject— все задачи зеркала, включая эпики и соседей,neighbor— признак зеркала. Поля:key,summary,issue_type,status,priority,assignee,sprint,duedate,planned_start,planned_end,epic_key,labels(список),neighbor(bool),fact_status,work_kind(из заметок,nullесли заметки нет); порядок — по ключу;links— сproject— связи, у которых хотя бы один конец — своя задача проекта; безproject— все связи зеркала:{source, target, link_type},link_type— имя типа в Jira, направление как вissue_link(sourceблокирует/ссылается наtarget). Неизвестный проект — 404. Перевод в модель доски (вид работы по меткам, имена эпиков, логические типы связей) — дело интерфейса; хаб отдаёт данные зеркала без преобразований.
Scenario: Снимок с задачами и связью
- WHEN в зеркале эпик AURORA-1351, задачи AURORA-1620 (метка
kind-dev, эпик AURORA-1351) и AURORA-1621, связьAURORA-1620 → AURORA-1621типаASUPR_Блокер_Начала, заметкаwork_kind = "разработка"у AURORA-1620 - THEN
GET /boardотдаёт три задачи по ключу, у AURORA-1620labels = ["kind-dev"],epic_key = "AURORA-1351",work_kind = "разработка"; вlinks—{source: "AURORA-1620", target: "AURORA-1621", link_type: "ASUPR_Блокер_Начала"}
Scenario: Снимок проекта
- WHEN AURORA-1 (метка
STOCKS_DRRK) связана с AURORA-2 (меткаAWPCA), AURORA-2 связана с AURORA-3 (меткаAWPCA);GET /board?project=STOCKS_DRRK - THEN
issues— AURORA-1 (neighbor = false) и AURORA-2 (neighbor = true);links— только AURORA-1 ↔ AURORA-2
Scenario: Последний полный прогон
- WHEN в журнале синхронизаций полный прогон, завершённый в 10:00, и после него обновление по ключам в 11:00
- THEN
last_sync.finished_at— 10:00
Scenario: Без токена
- WHEN
GET /boardбез токена или с агентским токеном - THEN 401