2026-10-14 16:00:57 +04:00

8.5 KiB
Raw Blame History

MODIFIED Requirements

Requirement: Процесс и доступ

jira-hub serve SHALL запускать один процесс: HTTP на 0.0.0.0:<port> (по умолчанию 8790), база и настройки в ~/.local/share/jira-hub/ (переопределяется JIRA_HUB_HOME). Все маршруты API SHALL требовать Authorization: Bearer <token>: агентский токен открывает только /agent/*, клиентский — всё остальное. Исключение — страница доски связей (GET /, GET /links): это статический файл без данных, он отдаётся без токена. Ответы API — JSON, ошибки — {error, detail} с кодами 400 (неверное тело или Content-Length), 401, 404, 409, 413 (тело больше предела), 422, 500 (внутренняя ошибка); реле общей папки дополнительно отвечает 502. Методы, кроме GET, POST и PUT, отвечают 501 стандартной страницей http.server, не JSON.

Scenario: Чужой токен

  • WHEN агентским токеном вызван GET /issues
  • THEN 401

Scenario: Неподдерживаемый метод

  • WHEN DELETE /issues/AURORA-1
  • THEN 501, тело не JSON; база не меняется

Scenario: Страница без токена

  • WHEN GET / без заголовка Authorization
  • THEN 200, Content-Type: text/html; charset=utf-8, тело — страница доски связей; данных зеркала в ней нет

ADDED Requirements

Requirement: Снимок доски

Хаб SHALL предоставлять GET /board под клиентским токеном — согласованный снимок зеркала для доски связей, прочитанный в одной транзакции:

  • generated_at — момент снимка (UTC);
  • last_sync — последний завершённый полный прогон (refresh по базовой JQL): {started_at, finished_at, issues_count} или null, если такого не было;
  • issues — все задачи зеркала, включая эпики и соседей: key, summary, issue_type, status, priority, assignee, sprint, duedate, planned_start, planned_end, epic_key, labels (список), neighbor (bool), fact_status, work_kind (из заметок, null если заметки нет); порядок — по ключу;
  • links — все связи зеркала: {source, target, link_type}, link_type — имя типа в Jira, направление как в issue_link (source блокирует/ссылается на target). Перевод в модель доски (вид работы по меткам, имена эпиков, логические типы связей) — дело интерфейса; хаб отдаёт данные зеркала без преобразований.

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-1620 labels = ["kind-dev"], epic_key = "AURORA-1351", work_kind = "разработка"; в links — {source: "AURORA-1620", target: "AURORA-1621", link_type: "ASUPR_Блокер_Начала"}

Scenario: Последний полный прогон

  • WHEN в журнале синхронизаций полный прогон, завершённый в 10:00, и после него обновление по ключам в 11:00
  • THEN last_sync.finished_at — 10:00

Scenario: Без токена

  • WHEN GET /board без токена или с агентским токеном
  • THEN 401

Requirement: Страница доски связей

Хаб SHALL отдавать по GET / и GET /links страницу доски связей — один HTML-файл из пакета хаба (src/jira_hub/web/links.html, развитие просмотрщика «Спринт 2 линк»). Страница SHALL:

  • спрашивать клиентский токен хаба при первом открытии и после ответа 401, хранить его в localStorage браузера и передавать в заголовке Authorization своих запросов к API того же хоста;
  • при открытии загружать GET /board и строить доску из него: задачи-эпики — дорожки, остальные задачи (включая соседей) — карточки; вид работы — по меткам kind-*, иначе по типу задачи; срок карточки — planned_end, при его отсутствии duedate; связи — по известным странице типам Jira, неизвестные типы пропускаются;
  • показывать в шапке время последнего полного прогона (last_sync.finished_at);
  • по кнопке «Обновить из Jira» ставить POST /refresh {full: true, author: "viewer"}, показывать ход пакета по GET /batches/{id} до завершения и затем перечитывать GET /board; если агент офлайн (GET /agent), предупреждать, но пакет ставить; при ошибке пакета — показывать её текст;
  • по кнопке «Перечитать» загружать GET /board заново без обращения к Jira;
  • сохранять раскладку карточек, порядок и свёртку дорожек, фильтры в localStorage под ключами, не зависящими от источника данных; импорт JSON, выгруженного страницей, в режиме хаба SHALL сохранять эти настройки и сразу перечитывать данные хаба, а не показывать снимок из файла;
  • оставлять загрузку CSV из фильтра Jira как запасной путь (снимок с пометкой «из файла»; «Перечитать» возвращает данные хаба);
  • при недоступном хабе показывать понятное сообщение и предлагать загрузить файл; встроенной выгрузки данных страница не содержит.

Scenario: Первый вход

  • WHEN страница открыта впервые, токена в localStorage нет
  • THEN вместо доски — поле клиентского токена с подсказкой uv run jira-hub tokens; после ввода верного токена доска строится из GET /board, токен сохранён

Scenario: Неверный токен

  • WHEN сохранённый токен устарел и GET /board ответил 401
  • THEN страница снова показывает поле токена с пояснением, что токен не подошёл

Scenario: Обновление из Jira

  • WHEN нажата «Обновить из Jira», агент на связи
  • THEN в хабе пакет из одного refresh по базовой JQL с автором viewer; страница показывает «пакет #N выполняется», по завершении перечитывает доску и показывает новое время данных

Scenario: Перенос раскладки

  • WHEN в режиме хаба импортирован JSON, выгруженный старой страницей «Спринт 2 линк»
  • THEN раскладка, дорожки и фильтры из JSON применены к задачам хаба; задачи и связи — из хаба, не из JSON