6.2 KiB
MODIFIED Requirements
Requirement: Схема базы хаба
База хаба SHALL быть одним файлом SQLite (WAL) с таблицами issue, issue_link, issue_comment, issue_note, batch,
command, sync_run, agent_status, setting. Схема SHALL создаваться и мигрироваться самим хабом при старте по номеру
версии в setting.schema_version (текущая — 3). Миграция существующей базы SHALL выполняться в одной транзакции с
блокировкой записи; в той же транзакции, после повторной проверки версии, хаб SHALL скопировать файл базы в
backups/<дата-время>-schema-v<старая>.sqlite рядом с базой — одна копия на миграцию, сколько бы соединений ни
открывалось одновременно. Каталог данных хаба и backups/ SHALL иметь права 0700 (в базе токены): хаб выставляет их
при создании и при каждом старте; если выставить не удалось — предупреждение в лог, работа продолжается. Денежных и
дробных полей нет; даты — ISO-8601 строки в UTC, кроме duedate и плановых дат (даты без времени) и времени
комментариев (строки Jira как есть).
Scenario: Первый запуск
- WHEN хаб стартует с несуществующим файлом базы
- THEN файл создаётся, таблицы и индексы на месте,
setting.schema_version= текущая; каталог данных с правами0700
Scenario: Миграция базы v1
- WHEN хаб стартует с базой
schema_version = 1, в которой есть задачи, заметки и команда вclaimed - THEN в
backups/копия базы v1; добавленаcommand.deliveries(уclaimed— 1, у остальных — 0); добавлена пустаяissue_comment; данные на месте;schema_version = 3
Scenario: Миграция базы v2
- WHEN хаб стартует с базой
schema_version = 2, в которой есть задачи, связи и заметки - THEN в
backups/копия базы v2; добавлена пустаяissue_comment; данные на месте;schema_version = 3
Scenario: Два соединения к базе v1
- WHEN к базе
schema_version = 1одновременно открываются два соединения - THEN миграция выполнена один раз, в
backups/одна копияschema-v1
Scenario: Открытый каталог данных
- WHEN хаб стартует, каталог данных существует с правами
0755 - THEN права каталога и
backups/—0700
Requirement: Зеркало задачи
Таблица issue SHALL хранить задачу Jira как есть: key (PK), id, issue_type, summary, description (wiki),
status, priority, assignee, reporter, duedate, planned_start, planned_end, epic_key, labels (JSON-список),
sprint, jira_updated, fetched_at, neighbor (0/1 — вне базовой JQL, дочитана по связи), created. Таблица issue_link
SHALL хранить связи (source_key, target_key, link_type) с направлением по семантике Jira: source блокирует/ссылается
на target (у source в GET это outwardIssue). Таблица issue_comment SHALL хранить комментарии задачи как есть:
key, comment_id (PK вместе с key), author, created, updated, body (wiki). Обновлять issue, issue_link и
issue_comment SHALL только загрузка состояния от агента; HTTP API интерфейсов и MCP MUST NOT писать в них. Присланные
комментарии задачи SHALL заменять все её прежние комментарии; задача, присланная без поля comments, свои комментарии
SHALL сохранять. Полный прогон (refresh по базовой JQL), завершившийся done, SHALL помечать neighbor = 1 задачи, не
обновлённые им, — только если прогон загрузил хотя бы одну задачу.
Scenario: Загрузка состояния заменяет связи
- WHEN агент прислал состояние задачи X с двумя связями
- THEN все строки
issue_linkсsource_key = Xзаменены на присланные; строки сtarget_key = X, не присланные со стороны X, не трогаются до загрузки их источника
Scenario: Соседняя задача
- WHEN в
issuelinksзадачи из базовой JQL есть ключ Y вне JQL - THEN Y сохраняется с
neighbor = 1; при следующем полномrefresh, если Y вошла в JQL,neighbor = 0
Scenario: Пустой полный прогон
- WHEN полный
refreshзавершилсяdone, загрузив 0 задач - THEN признак
neighborзадач зеркала не меняется
Scenario: Комментарий удалён в Jira
- WHEN у X в зеркале комментарии 101 и 102, агент прислал X с
comments = [{id: "102", …}] - THEN у X в
issue_commentтолько 102
Scenario: Состояние от агента до v10
- WHEN у X в зеркале три комментария, агент v9 прислал X без поля
comments - THEN поля X обновлены, три комментария на месте