61 KiB
MODIFIED Requirements
Requirement: Список задач
Страница /app/issues SHALL показывать задачи текущего проекта из GET /issues?project=<текущий> таблицей: ключ
(открывает карточку задачи окном поверх списка) с пометкой «сосед» (относительно проекта), тема, статус Jira,
исполнитель, срок (planned_end, иначе duedate; просроченный срок незакрытой задачи выделен), спринт, эпик (имя
эпика, иначе ключ), вид работы, тип; статуса по факту в списке нет. Щелчок по строке (кроме ссылок и выделения текста)
SHALL открывать карточку задачи так же, как ключ. Шапка страницы SHALL показывать число показанных задач.
Фильтры SHALL соответствовать параметрам GET /issues (спринт, исполнитель, вид работы, статус Jira, метка, эпик,
только соседи, поиск по ключу или теме, скрыть закрытые), храниться в query-строке адреса вместе с project и
применяться сервером. На виду SHALL быть поиск, переключатель «Открытые | Все», переключатель «Только соседи» и
кнопка «Фильтры» с числом выбранных выпадающих списков; шесть выпадающих списков (спринт, исполнитель, вид работы,
статус Jira, метка, эпик) — в панели, которая раскрывается этой кнопкой; каждый выбранный список SHALL показываться
снимаемой плашкой «<подпись>: <значение>» и под строкой фильтров должно быть действие «Сбросить», снимающее все шесть
списков. Варианты выпадающих списков SHALL браться из снимка GET /board?project=<текущий>; значение фильтра из
адреса, которого нет среди вариантов, SHALL показываться в списке с пометкой «(нет на доске)». Положение «Открытые»
SHALL быть по умолчанию (в адресе ничего), «Все» — closed=1 в адресе; «Открытые» — запрос с hide_closed=1,
кроме случая, когда в фильтре «Статус Jira» выбран статус из closed_statuses. Параметр fact_status в адресе
игнорируется. Задачи SHALL загружаться порциями по 50 строк; «Показать ещё» SHALL быть доступна, пока последняя
порция полная. Запрос GET /issues MUST NOT уходить, пока не завершён запрос настроек хаба (closed_statuses): до этого страница показывает «Загрузка…», а не «По этим фильтрам задач нет»; настройки не загрузились — запрос уходит как без закрытых статусов. Поиск SHALL записываться в адрес после паузы ввода; если до записи открыта карточка задачи, поиск SHALL записываться в адрес списка сразу, до открытия окна, и окно поверх списка с этим поиском MUST NOT закрываться отложенной записью.
Scenario: Фильтр в адресе
- WHEN выбран спринт «AWPCA_Спринт 2» и исполнитель
- THEN адрес содержит
project=,sprint=иassignee=, таблица — результатGET /issuesс этими параметрами; открытие этого адреса в новой вкладке показывает ту же выборку, кнопка «Фильтры» показывает 2, видны плашки спринта и исполнителя
Scenario: Снять фильтр плашкой
- WHEN выбраны спринт и исполнитель, нажат ✕ на плашке спринта
- THEN в адресе нет
sprint=,assignee=остался, таблица перезапрошена
Scenario: Конец списка
- WHEN вторая порция вернула 17 задач
- THEN в таблице 67 задач, «Показать ещё» не показана
Scenario: Фильтр по закрытому спринту
- WHEN открыт адрес
/app/issues?project=AWPCA&sprint=AWPCA_Спринт 0, а в снимке доски такого спринта нет - THEN выпадающий список «Спринт» показывает «AWPCA_Спринт 0 (нет на доске)» выбранным, таблица — по этому фильтру
Scenario: Карточка поверх списка
- WHEN список отфильтрован по спринту, прокручен и догружен «Показать ещё», открыта карточка задачи и окно закрыто
- THEN адрес списка с тем же фильтром, в таблице те же строки, прокрутка та же
Scenario: Щелчок по строке
- WHEN в таблице щёлкнута ячейка темы строки AURORA-1620
- THEN адрес
/app/issues/AURORA-1620, карточка открыта окном поверх списка
Scenario: Закрытые скрыты по умолчанию
- WHEN открыт
/app/issues, в зеркале задачи в статусах «В работе», «Готово», «Снято» - THEN выбрано «Открытые», запрос
GET /issuesсhide_closed=1, в таблице только «В работе»; после выбора «Все» адрес содержитclosed=1, в таблице все три
Scenario: Выбран закрытый статус
- WHEN выбрано «Открытые» и в «Статус Jira» выбрано «Готово»
- THEN запрос
GET /issues?status=Готовобезhide_closed, в таблице задачи в статусе «Готово»
Scenario: Поиск перед открытием карточки
- WHEN в поиске списка введено «свод» и меньше чем через 300 мс щёлкнута строка AURORA-1620
- THEN окно карточки AURORA-1620 открыто и остаётся открытым; после его закрытия адрес списка содержит
q=свод
Scenario: Закрытый статус в адресе до настроек
- WHEN открыт
/app/jira/issues?project=AWPCA&status=Готово, ответ/settingsещё не пришёл - THEN запросов
GET /issuesнет, показано «Загрузка…»; после ответа/settings(где «Готово» вclosed_statuses) — один запросGET /issues?status=Готовобезhide_closed; сообщение «По этим фильтрам задач нет» не появлялось
Requirement: Карточка задачи
Адрес /app/issues/{key} SHALL открывать карточку задачи из GET /issues/{key} модальным окном поверх страницы, с
которой её открыли (список «Задачи» или доска); страница под окном SHALL оставаться смонтированной и сохранять фильтры,
загруженные строки, прокрутку и раскладку. Перезагрузка страницы с открытым окном SHALL сохранять страницу под окном. Открытый напрямую
адрес (новая вкладка, закладка) SHALL
показывать окно поверх списка задач без фильтров. Окно SHALL закрываться кнопкой ✕, клавишей Esc и щелчком по фону (нажатие и отпускание — на фоне; выделение текста,
отпущенное за краем окна, окно не закрывает) и
возвращать на страницу, с которой его открыли, даже после переходов по связям внутри окна; «назад» браузера после
закрытия MUST NOT открывать карточку снова. Переход по связанной задаче SHALL менять содержимое окна и адрес, «назад»
браузера — возвращать к прежней карточке. Пока окно открыто, фокус SHALL оставаться в окне, страница под ним не
прокручивается. Повторное закрытие, пока окно закрывается (двойной щелчок по ✕ или фону, Esc сразу после щелчка), MUST NOT уводить дальше назад по истории браузера.
Содержимое окна:
- шапка: ключ, статус Jira, «Открыть в Jira», ✕, тема; строка
«исполнитель · срок · спринт · эпик» без пустых частей, срок —
planned_end, иначеduedate, с пометкой «просрочено», если он раньше сегодняшней даты и статус Jira не входит вclosed_statuses; эпик — темой (epic_summary), иначе ключом; - «Связи» по группам в порядке: «Зависит от» (входящие связи логических типов
блокирует началоиблокирует завершениеизlink_types, с меткой «начало» / «завершение»), «Блокирует» (исходящие тех же типов, с теми же метками), «Связана с» (типсвязанныев обе стороны), «Прочие» (тип Jira внеlink_types: имя типа и направление «→» / «←»); в строке — ключ (открывает связанную задачу в окне), тема и статус Jira, а если задачи нет в зеркале — ключ ссылкой на задачу в Jira (новая вкладка, значок внешней ссылки) и «нет в зеркале»; окно хаба такая ссылка не открывает; пустые группы не показываются, без связей — «связей нет»; - «Описание» — текст, отрендеренный по требованию «Разметка Jira в карточке», с кнопкой «исходник» / «текст» в заголовке раздела; длиннее 8 строк — свёрнуто с кнопкой «развернуть» / «свернуть» в обоих режимах; без описания (пустое или из одних пробелов и переводов строк) раздела нет;
- «Вложения (N)» — новые сверху: значок по типу файла (картинка, таблица, PDF, прочее), имя, размер, «автор · дата» и кнопка скачивания (требование «Скачивание вложений в карточке»); без вложений раздела нет;
- «Комментарии (N)» — новые сверху, автор, время, кнопка «исходник» / «текст» у каждого комментария, текст,
отрендеренный по требованию «Разметка Jira в карточке», под текстом — вложения, на которые ссылается комментарий
(
attachment_ids): строка «плашек» с именем и размером, щелчок — скачивание; кнопка «Скрыть» / «Показать» сворачивает раздел, выбор SHALL запоминаться в браузере для всех карточек; без комментариев — «комментариев нет»; - «Служебные заметки» (требование «Служебные заметки»);
- «Прочие поля» — непустые из: тип, приоритет, автор, «Вид работы в Jira» (названия видов из
kind_labels, метки которых есть у задачи, через запятую), метки (кроме меток видов изkind_labels), плановое начало, обновлена в Jira, сосед по связям; - «Команды моста (N)» — 10 последних команд по задаче (id, пакет, тип, статус, время завершения, ошибка), раздел свёрнут при открытии; если команд не было — текст «команд по задаче не было». На ширине от 900 px «Связи», «Описание», «Вложения», «Комментарии» — в левой колонке, заметки, прочие поля и команды — в правой; уже — одна колонка: заметки, связи, описание, вложения, комментарии, прочие поля, команды. Если задачи нет в зеркале (404), окно SHALL сообщать об этом с кнопкой «Закрыть» (закрывает окно целиком, как ✕); если окно открыто переходом из другой карточки — ещё и с кнопкой «Назад», возвращающей к ней (так же у ошибки загрузки); хаб не отвечает — сообщение и «Повторить», ранее загруженные данные остаются.
Scenario: Связанная задача
- WHEN у AURORA-1620 исходящая связь
ASUPR_Блокер_Началана AURORA-1621 «Расчёт свода» в статусе «В работе» - THEN в карточке в группе «Блокирует» строка «начало · AURORA-1621 · Расчёт свода · В работе»; щелчок по ключу
меняет содержимое окна на AURORA-1621, адрес —
/app/issues/AURORA-1621; «назад» браузера возвращает AURORA-1620
Scenario: Входящий блокер
- WHEN у AURORA-1620 входящая связь
ASUPR_Блокер_Завершенияот AURORA-1500 - THEN строка с AURORA-1500 и меткой «завершение» — в группе «Зависит от»
Scenario: Задача без команд
- WHEN по AURORA-1620 не было команд
- THEN в разделе «Команды моста» — текст «команд по задаче не было», таблицы нет
Scenario: Закрытие после переходов
- WHEN со списка «Задачи» открыта AURORA-1620, в окне — переход по связи на AURORA-1621, нажата Esc
- THEN окно закрыто, адрес — адрес списка с прежними фильтрами; «назад» браузера не открывает карточку
Scenario: Прямой адрес
- WHEN в новой вкладке открыт
/app/issues/AURORA-1620, затем нажат ✕ - THEN под окном был список задач без фильтров; после закрытия адрес
/app/issues, «назад» не открывает карточку
Scenario: Скрытые комментарии
- WHEN в карточке нажато «Скрыть» у комментариев, затем страница перезагружена и открыта другая карточка
- THEN комментарии в ней скрыты, видна кнопка «Показать» и число комментариев
Scenario: Просрочка закрытой задачи
- WHEN у AURORA-1620 срок 2026-10-01, сегодня 2026-10-17, статус Jira «Готово»
- THEN в строке под темой «срок 01.10» без пометки «просрочено»; при статусе «В работе» — с пометкой
Scenario: Двойной щелчок по закрытию
- WHEN со списка «Задачи» открыта AURORA-1620, в окне — переход по связи на AURORA-1621, по ✕ щёлкнули дважды подряд
- THEN окно закрыто, адрес — адрес списка; запись истории перед списком не открыта
Scenario: Связанная задача не в зеркале
- WHEN у AURORA-1620 связь на AURORA-1999, которой нет в зеркале
- THEN в «Связях» строка «AURORA-1999 · нет в зеркале»; ключ — ссылка
<адрес Jira>/browse/AURORA-1999в новой вкладке, окно карточки остаётся на AURORA-1620
Scenario: Задача не в зеркале после перехода
- WHEN в окне AURORA-1620 щёлкнут ключ AURORA-1999 в тексте комментария, хаб ответил 404
- THEN окно сообщает «Задачи AURORA-1999 нет в зеркале хаба» с кнопками «Назад» и «Закрыть»; «Назад» возвращает окно к AURORA-1620, «Закрыть» закрывает окно и возвращает на страницу под ним
Scenario: Метки вида работы
- WHEN у задачи метки
AWPCAиkind-dev, вkind_labelsесть «разработка» →kind-dev - THEN в «Прочих полях» строки «Вид работы в Jira: разработка» и «Метки: AWPCA»
Scenario: Описание из пробелов
- WHEN описание задачи — три пробела и два перевода строки
- THEN раздела «Описание» нет
Requirement: Служебные заметки
Карточка задачи SHALL показывать служебные заметки в режиме чтения: «Вид работы», «Сделано»,
«Осталось», «Заметка владельца» (пустые — «—») и время и автор последнего изменения; кнопка «Править» SHALL открывать
форму: «вид работы» — выбор из значений kind_labels настроек (и текущего значения, если его там нет, и пустого),
«сделано», «осталось», «заметка владельца» —
многострочный текст; «Отмена» SHALL возвращать режим чтения, при несохранённых правках — после подтверждения.
Сохранение SHALL отправлять PUT /issues/{key}/note только с изменёнными полями и updated_by: "web"; очищенное поле
отправляется как null. После успеха SHALL показываться режим чтения с сохранённой заметкой; список задач под окном SHALL
показывать новый «вид работы» без «Перечитать», доска под окном SHALL перечитать снимок
(GET /board) без потери раскладки и прокрутки; при 422 — текст ошибки у формы без
потери введённого. Закрытие окна, переход по связи и уход в другой раздел с несохранёнными правками SHALL требовать
подтверждения; блок подтверждения — с доступным именем «Уйти без сохранения заметки?», при появлении фокус SHALL переходить на «Остаться». Статуса по факту в заметках нет. Заметки пишутся только в хаб, в Jira приложение ничего не отправляет.
Scenario: Только изменённые поля
- WHEN в заметке нажато «Править», изменено только «осталось» и нажато «Сохранить»
- THEN тело
PUT /issues/{key}/note—{rest_text: "…", updated_by: "web"}; карточка снова в режиме чтения с новым «Осталось»
Scenario: Уход с несохранёнными правками
- WHEN в форме заметки есть несохранённая правка и нажата Esc
- THEN приложение спрашивает подтверждение, фокус — на «Остаться»; при отказе окно открыто, форма с введённым текстом
Scenario: Заметка видна на доске
- WHEN карточка AURORA-9002 открыта с доски, вид работы изменён на «тестирование» и сохранён
- THEN доска под окном остаётся на месте и перезапрашивается (
GET /boardотдаётwork_kind«тестирование»); окно закрывается без потери раскладки и прокрутки доски
Requirement: Разметка Jira в карточке
Описание задачи и текст каждого комментария в карточке SHALL показываться отрендеренной вики-разметкой Jira (хаб хранит их как есть, в wiki) так, как их показывает Jira. Разбираются:
- блоки: заголовки
h1.–h6.в начале строки; списки — строки, начинающиеся (после необязательных пробелов) с маркеров*,#и пробела (уровень вложенности — числом маркеров,*— маркированный,#— нумерованный, смешанная вложенность*#— по последнему маркеру) или с одного-и пробела (маркированный, первый уровень);--,*-и прочие сочетания с-— не список; таблицы — строки, начинающиеся с|, ячейки||заголовок||и|ячейка|(|внутри[текст|адрес]ячейку не делит;[без парной]дальше в строке — обычный символ и на деление ячеек не влияет);{code}/{code:параметры}…{code}и{noformat}/{noformat:параметры}…{noformat}— моноширинный блок без разбора разметки внутри;{quote}/{quote:параметры}…{quote}и строкаbq.— цитата; открывающий тег блока — в начале строки, закрывающий — в любом месте той же или последующей строки, текст после закрывающего тега разбирается дальше как обычные строки; пробелы после открывающего тега в той же строке в блок не попадают; тег не в начале строки — текст как есть; строка----— горизонтальная черта; прочие строки — абзацы, разделённые пустыми строками, одиночный перенос внутри абзаца — перенос строки; - внутри строки:
*жирный*,_курсив_,-зачёркнутый-,+подчёркнутый+,^верхний^,~нижний~,{{моно}}({{…}}— без разбора внутри); маркер выделения действует, только если открывающий стоит в начале текста или после пробела либо знака препинания и за ним не пробел и не тот же символ (**x**— текст как есть), а закрывающий стоит после не-пробела и за ним не буква и не цифра (data_type,2026-10-15,счёт-фактура,a*b*c— обычный текст);\\— перенос строки;\перед символом разметки (в том числе#:\#— символ#) — сам символ; - ссылки:
[текст|адрес],[адрес]и голые адресаhttp://,https://— ссылка в новой вкладке, только для схемhttp,https,mailto, иначе текст как есть;[ключ задачи],[текст|ключ задачи]и ключ задачи в тексте видаПРОЕКТ-123, гдеПРОЕКТ—project_keyиз настроек хаба, — ссылка, открывающая карточку этой задачи в окне (UTF-8,SHA-256и ключи других проектов — текст);[~логин]и[~логин|текст]— «@логин»; - ссылки на вложения задачи —
!имя!,!имя|параметры!,[^имя],[текст|^имя]с тем же разбором имени, что у хаба (hub-api, «Ссылки на вложения в тексте»), имя есть среди вложений задачи: ссылка-кнопка со значком скрепки и текстом — именем файла (у[текст|^имя]— текстом), щелчок — скачивание; картинка в тексте не показывается; имени нет среди вложений — исходник как есть. Всё, что разборщик не распознал ({panel},{color},!картинка!и[^имя]без такого вложения у задачи, незакрытые маркеры и блоки и прочее), SHALL показываться как текст исходника без потерь. Разметка MUST NOT превращаться в HTML строкой (innerHTML,dangerouslySetInnerHTML): текст задачи не может добавить на страницу элементы, атрибуты или скрипты. Если рендер блока завершился ошибкой, блок SHALL показываться исходником.
Кнопка «исходник» у описания и у каждого комментария SHALL переключать этот блок на исходник — текст с сохранёнными переносами строк, как без разбора разметки, — и обратно кнопкой «текст»; остальные блоки не переключаются. При каждом открытии карточки (в том числе при переходе по связи) все блоки показываются отрендеренными, выбор не запоминается.
Scenario: Описание со структурой
- WHEN описание AURORA-1620 —
h3. Контекст, строкаШаги:, затем# Загрузить ОСВи# Открыть документ, затем пустая строка и*Итог:* ошибка в {{data_type}} - THEN в «Описании» заголовок «Контекст», абзац «Шаги:», нумерованный список из двух пунктов и абзац, где «Итог:» —
жирным, «data_type» — моноширинным; символов
h3.,#,*,{{не видно
Scenario: Переключение на исходник
- WHEN в карточке AURORA-1620 у описания нажато «исходник»
- THEN описание показано исходником с переносами строк (видны
h3. Контексти# Загрузить ОСВ), кнопка — «текст»; комментарии остаются отрендеренными; после «текст» описание снова отрендерено
Scenario: Исходник у одного комментария
- WHEN у второго комментария нажато «исходник», затем открыта связанная задача и возврат «назад»
- THEN сразу после нажатия исходником показан только второй комментарий; после возврата все комментарии отрендерены
Scenario: Ключ задачи в тексте
- WHEN комментарий —
П. 1 ведётся в AURORA-1445; AURORA-1645 снята как дубль. - THEN «AURORA-1445» и «AURORA-1645» — ссылки; щелчок по первой меняет содержимое окна на AURORA-1445
Scenario: Неизвестная разметка и опасный адрес
- WHEN описание —
{color:red}важно{color},!схема.png!и[нажми|javascript:alert(1)] - THEN все три показаны текстом исходника как есть, ссылки и картинки нет, скрипт не выполняется
Scenario: Списки с отступом и пустыми строками
- WHEN описание —
Шаги воспроизведения:,* Загрузить ОСВ., пустая строка,* Дождаться обработки. - THEN абзац «Шаги воспроизведения:» и маркированные пункты «Загрузить ОСВ.» и «Дождаться обработки.» без звёздочек
Scenario: Обычный текст не портится
- WHEN описание —
Поле data_type = null, дата 2026-10-15, оборот 18 803 903,65 - 9 351 102,89, a*b*c, UTF-8, **важно** - THEN текст показан как есть, без курсива, зачёркивания, жирного и ссылок
Scenario: Скриншот в тексте комментария
- WHEN комментарий — «см. !скрин 1.png|thumbnail!», у задачи есть вложение «скрин 1.png»
- THEN вместо
!скрин 1.png|thumbnail!— кнопка со скрепкой «скрин 1.png»; под комментарием плашка «скрин 1.png · 234,4 КБ»; щелчок по любой из них скачивает файл
Scenario: Экранированная решётка и цитата с параметрами
- WHEN описание —
\# не пункт, затем{quote:title=Итог},согласовано,{quote} - THEN абзац «# не пункт» (не нумерованный список) и цитата «согласовано»; тегов
{quoteне видно
Scenario: Таблица с непарной скобкой
- WHEN описание —
|[draft|итог|готово| - THEN таблица из одной строки с ячейками «[draft», «итог», «готово»
Scenario: Упоминание с подписью и код с пробелами
- WHEN комментарий —
[~ivanov|Иванов], затем строка{code},x = 1,{code} - THEN «@ivanov» и моноширинный блок из одной строки
x = 1без пустой строки перед ней
Requirement: Проект в приложении
«Обзор», доска, список задач, лента и вики SHALL показывать один проект — текущий. Текущий проект SHALL задаваться
параметром project в адресе страниц; без параметра — последний выбранный в этом браузере (localStorage), если он
есть в GET /projects, иначе первый из GET /projects; выбранный проект записывается в адрес без новой записи истории.
Проекта из адреса нет в GET /projects — страница SHALL показывать «проект <метка> не найден» и подсказку выбрать
проект в списке «Проект» боковой панели (на узком экране — в «Меню») вместо данных. Проектов нет — страницы SHALL
показывать приглашение создать проект («+ Новый проект…»). Список проектов не загрузился — сообщение с ошибкой и кнопкой «Повторить», перезапрашивающей GET /projects. Переходы между страницами SHALL сохранять текущий проект;
смена проекта на странице, которой нет у нового проекта, открывает «Обзор»; исключение — «Бэклог», «Спринт», «Kanban»:
адрес остаётся, страница показывает «У проекта нет …-доски» (требование «Спринты и бэклог»). Карточка задачи
(/app/jira/issues/{key}) от проекта не зависит.
Доска SHALL загружать GET /board?project=<текущий>. Раскладка, дорожки и фильтры доски в localStorage SHALL
храниться отдельно для каждого проекта; у проекта AWPCA — на прежних ключах (раскладка, сделанная до проектов,
сохраняется). Фильтр спринтов SHALL показываться, только если хотя бы у одной своей задачи снимка (neighbor = false), не
эпика, есть спринт; иначе — «колонки «Спринт» нет — показаны все задачи».
Форма «Новый проект» (пункт «+ Новый проект…» выпадающего списка) SHALL открываться окном поверх страницы: метка (с
подсказкой «метка задач в Jira и имя проекта в хабе») и название, затем поля каждого модуля в своей группе с
заголовком — названием модуля: «Jira» — номер доски Jira (необязательно; подсказка «scrum или kanban определится
сам»), «Вики» — корень вики (необязательно; подсказка «DOC-… или ссылка на страницу Eva»). Подсказка — текстом под
полем, не в placeholder. Пустое необязательное поле в запрос не попадает; числовое поле с нецелым значением — ошибка у
поля, запрос не уходит. «Создать» — POST /projects с автором viewer; ошибка хаба 409/422 — текст detail рядом с
кнопкой, окно остаётся открытым; успех — окно закрывается, текущим становится новый проект, каждый пакет из ответа
(batches) отслеживается своим модулем (требование «Состояние и обновление модулей»).
Scenario: Первый вход после выкатки
- WHEN открыт
/app/jira/linksбезproject, вlocalStorageвыбора нет, проектыAWPCAиSTOCKS_DRRK - THEN адрес —
/app/jira/links?project=AWPCA, доска —GET /board?project=AWPCAс прежней раскладкой карточек
Scenario: Переключение проекта
- WHEN на доске
AWPCAв выпадающем списке выбранSTOCKS_DRRK, затем открыт раздел «Задачи» - THEN доска —
GET /board?project=STOCKS_DRRKсо своей раскладкой; адрес «Задач» —/app/jira/issues?project=STOCKS_DRRK
Scenario: Неизвестный проект в адресе
- WHEN открыт
/app/jira/issues?project=NOPE - THEN «проект NOPE не найден» и подсказка выбрать проект в боковой панели; запроса
GET /issuesнет
Scenario: Создание проекта из формы
- WHEN в форме введены
STOCKS_DRRK, «Запасы ДРРК», доска и корень вики пусто; нажато «Создать» - THEN
POST /projects {label: "STOCKS_DRRK", name: "Запасы ДРРК", author: "viewer"}; текущий проект —STOCKS_DRRK; строка «Jira» блока состояния показывает «пакет #N выполняется»
Scenario: Проект с корнем вики из формы
- WHEN в форме введены
STOCKS_DRRK, «Запасы ДРРК», кореньDOC-001234; нажато «Создать» - THEN
POST /projects {label: "STOCKS_DRRK", name: "Запасы ДРРК", wiki_root: "DOC-001234", author: "viewer"}; строка «Jira» показывает пакет обновления, строка «Вики» — пакет синхронизации
Scenario: Метка занята
- WHEN в форме введена метка
awpca, хаб ответил 409 - THEN окно открыто, рядом с «Создать» — текст ошибки хаба
Scenario: Канбан-проект
- WHEN текущий проект —
STOCKS_DRRK, ни у одной своей задачи снимка нет спринта (у соседа изAWPCAспринт есть) - THEN вместо фильтра спринтов — «колонки «Спринт» нет — показаны все задачи»
Scenario: Нецелый номер доски
- WHEN в поле «Номер доски Jira» введено
51.5, нажато «Создать» - THEN у поля — «нужно целое число», запроса
POST /projectsнет
Scenario: Спринт только у эпика
- WHEN у эпика AURORA-9100 проекта спринт «AWPCA_Спринт 2», у остальных своих задач спринта нет
- THEN вместо фильтра спринтов — «колонки «Спринт» нет — показаны все задачи»
Scenario: Проекты не загрузились
- WHEN
GET /projectsответил 500, затем нажато «Повторить», хаб ответил списком проектов - THEN сначала «Проекты не загрузились: …» с кнопкой «Повторить»; после нажатия — страница текущего проекта
Requirement: Лента изменений
Страница /app/feed?project=<метка> SHALL показывать события журнала изменений своих задач текущего проекта за период
(GET /changes с project, since, until, kinds). Период SHALL выбираться переключателем «2 часа» / «Сегодня» /
«Вчера» / «7 дней» (по умолчанию «Сегодня»; границы — по местному времени браузера: «Сегодня» — с начала текущих суток
до сейчас, «Вчера» — с начала прошлых суток до начала текущих) и храниться в адресе (period=2h|today|yesterday|7d;
«Сегодня» в адрес не пишется). Виды событий SHALL выбираться флажками «Статусы», «Описание», «Сроки», «Комментарии»,
«Прочие поля» (по умолчанию все, кроме «Прочие поля») и храниться в адресе (kinds= через запятую; набор по умолчанию в
адрес не пишется; в адресе нет ни одного известного вида — набор по умолчанию); снятые все флажки — сообщение «выберите
хотя бы один вид», запроса нет.
События SHALL быть сгруппированы по задаче; задачи — по времени последнего события, новые сверху. У группы: ключ —
ссылка на карточку задачи (окно поверх ленты, требование «Карточка задачи»), тема и текущий статус; под ней события по
времени, новые сверху, каждое — время (ЧЧ:ММ, с датой ДД.ММ, если событие не в текущих сутках), автор и текст:
статус — «статус «было» → «стало»»; описание — «описание изменено»; срок, плановое начало и окончание — «срок ДД.ММ →
ДД.ММ» (дата по значению from_value/to_value, иначе строка журнала; пустое — «—»); комментарий — «комментарий:» и
первые 300 символов текста без вики-разметки Jira (так, как текст читается отрендеренным: без *, {code}, h3.; у [текст|адрес] — текст, [~логин] — «@логин») одной строкой с «…»; прочие поля — «<название поля>: «было» → «стало»» (значения до 80
символов с «…»), где название — подпись из словаря приложения (исполнитель, спринт, метки, приоритет, тема, эпик, связь,
вложение, резолюция), иначе имя поля Jira. Подзаголовок страницы — число событий и границы периода. Событий нет —
сообщение «за период изменений нет»; truncated — сообщение «показаны последние N событий — выберите период короче».
Ошибка хаба — сообщение с кнопкой «Повторить». Ленту SHALL перечитывать завершение «Обновить из Jira» (вместе со списками
задач) и возврат на вкладку браузера.
Scenario: Что закрылось за два часа
- WHEN открыта лента проекта AWPCA, выбран период «2 часа», сняты все флажки, кроме «Статусы»
- THEN адрес —
/app/feed?project=AWPCA&period=2h&kinds=status; запросGET /changes?project=AWPCA&since=<сейчас − 2 ч>&kinds=status; задачи сгруппированы, у каждой — события «ЧЧ:ММ автор: статус «В работе» → «Готово»»
Scenario: Карточка из ленты
- WHEN в ленте нажат ключ AURORA-9002
- THEN поверх ленты открыто окно карточки AURORA-9002; закрытие окна возвращает ленту с тем же периодом
Scenario: Пустой период
- WHEN за выбранный период событий нет
- THEN показано «за период изменений нет»
Scenario: Вчера
- WHEN выбран период «Вчера», сейчас 22.10 14:05 местного времени
- THEN запрос с
since= 21.10 00:00 иuntil= 22.10 00:00 местного времени
Scenario: Комментарий с разметкой
- WHEN в ленте событие комментария с текстом
h3. Итоги*Готово*, см. [протокол|https://x.ru/p] и [~ivanov] - THEN строка события — «комментарий: Итог Готово, см. протокол и @ivanov»
Requirement: Скачивание вложений в карточке
Кнопка скачивания вложения (в разделе «Вложения», плашка под комментарием, ссылка в тексте) SHALL работать одинаково:
POST /attachments/{id}/fetch {author: "web"};state = ready—GET /attachments/{id}/contentс клиентским токеном, браузер сохраняет файл под именемfilename(черезBlobи временную ссылкуdownload; адрес с токеном в строке браузера MUST NOT появляться);state = fetching— у всех кнопок этого вложения в карточке вместо «Скачать» — «Загружается…» (неактивна), опросGET /attachments/{id}раз в 2 с, пока окно открыто на этой задаче;ready— шаг 2 сам, без второго нажатия; закрыли окно или ушли на другую задачу — опрос прекращается, команда остаётся в очереди (файл ляжет в хаб);failed— под вложением в разделе «Вложения» текст ошибки и кнопка «Повторить» (новый запрос); 409agent_too_oldи прочие ошибки хаба — их текст там же; хаб не отвечает — «хаб не отвечает» там же; 401 на любом шаге — экран входа. После успешного повтора прежняя ошибкаfailedиз данных карточки MUST NOT показываться. Вложения в разделе SHALL идти в порядке ответа хаба (новые сверху); ссылка в тексте на имя, которое носят несколько вложений, SHALL вести к первому из них в этом порядке (какattachment_idsхаба). Вложение сstate = readyв разделе «Вложения» помечается «у хаба» и скачивается сразу. Размер неизвестен — «размер неизвестен» и обычная кнопка. Вложение больше 10 МБ — вместо кнопки ссылка «Открыть в Jira» (<адрес Jira>/secure/attachment/<id>/<имя в URL-кодировке>, новая вкладка) с подсказкой «больше 10 МБ — только в Jira»; плашка и ссылка в тексте ведут туда же.
Scenario: Скачать скриншот
- WHEN в карточке AURORA-1650 нажато «Скачать» у «скрин 1.png», файла у хаба нет, агент онлайн
- THEN кнопка — «Загружается…», через несколько секунд браузер сохраняет «скрин 1.png», кнопка снова «Скачать», у вложения отметка «у хаба»
Scenario: Окно закрыли во время скачивания
- WHEN нажато «Скачать», затем окно карточки закрыто
- THEN опросов
GET /attachments/{id}больше нет; при следующем открытии карточки, если файл уже у хаба, вложение с отметкой «у хаба»
Scenario: Большой файл
- WHEN у вложения «запись.mp4» размер 25 МБ
- THEN вместо «Скачать» — ссылка «Открыть в Jira» с подсказкой «больше 10 МБ — только в Jira»
Scenario: Агент старой версии
- WHEN нажато «Скачать», хаб ответил 409 «агент v13 не умеет скачивать вложения — нужен v14»
- THEN под вложением этот текст и «Повторить»
Scenario: Повтор после ошибки
- WHEN у вложения «скрин 1.png» в данных карточки
state = failed, нажато «Повторить», файл скачан - THEN браузер сохранил файл, текста ошибки под вложением нет — и до, и после перечитывания карточки
Scenario: Токен отозван во время скачивания
- WHEN нажато «Скачать», во время опроса
GET /attachments/{id}хаб ответил 401 - THEN приложение показывает экран входа
Requirement: Состояние и обновление модулей
Каждый веб-модуль SHALL описывать своё состояние данными, а рисовать их SHALL ядро. Описание модуля: название для
показа («Jira», «Вики»); агент (имя модуля в GET /agents) или его отсутствие; свежесть данных для текущего проекта —
время, охват («все проекты» или «проект») и ошибка последнего обновления; действие обновления (название, охват,
постановка пакета) или его отсутствие; правило, какие пакеты принадлежат модулю; данные, которые надо перечитать после
пакета модуля; есть ли у модуля данные для проекта (у вики без корня — нет).
Ядро SHALL:
- опрашивать
GET /agentsпри входе и раз в 60 с — один опрос на приложение; агент модуля: «на связи», «офлайн» или «обновите агента» (естьwarningилиupdate_hint, текст — в подсказке); - вести один трекер пакетов на приложение: на модуль — не больше одного отслеживаемого пакета; пакет подхватывается при
входе, раз в 60 с и после действия обновления, если он не завершён, принадлежит модулю (поле
moduleвGET /batches) и текущему проекту (для модулей с охватом «проект») — любого автора, в том числе автообновления хаба и MCP; опросGET /batches/{id}каждые 3 с до терминального статуса; 4xx (404 — «пакета нет в хабе») и 5 ошибок «хаб не отвечает» подряд — опрос остановлен с сообщением; по завершении — перечитать данные модуля и список проектов; при смене проекта отслеживаемый пакет модуля с охватом «проект» сбрасывается вместе с событием, и ответ опроса этого пакета, пришедший после смены, MUST NOT возвращать событие; - ответ 409 на постановку пакета — отслеживать уже идущий пакет модуля, без сообщения об ошибке;
- агент модуля офлайн при обновлении — пакет всё равно ставится, событие «агент офлайн — пакет выполнится, когда он выйдет на связь; пакет #N в очереди…».
Блок состояния в развёрнутой боковой панели — по строке на модуль, у которого есть данные для проекта: название модуля,
точка агента (цвет и текст «агент на связи» / «агент офлайн» / «обновите агента» — не только цвет), кнопка-значок
обновления с подписью действия в подсказке и aria-label («Обновить из Jira — все проекты», «Обновить вики — проект
AWPCA»); под ними — «данные на ДД.ММ ЧЧ:ММ» с охватом («все проекты» / «проект»), «обновления ещё не было» или ошибка
последнего обновления; под ними — одно текущее событие пакета модуля: в очереди / выполняется (с оставшимся временем,
если хаб его дал, и пометками «агент офлайн», «хаб не отвечает, повтор»), выполнен (исчезает через 10 с), не выполнен
с текстом ошибки, отменён, опрос остановлен с причиной. Кнопка обновления модуля недоступна (с признаком загрузки), пока
запрос постановки в пути или выполняется пакет действия обновления модуля (у jira — пакет с первой командой refresh, у
wiki — wiki_sync); прочие пакеты модуля показываются, но обновление не блокируют: нажатие ставит пакет обновления, и
трекер переключается на него. Свёрнутая панель — по значку модуля с точкой агента, подробности в
подсказке, нажатие — обновление. На узком экране — сводная точка в верхней строке (требование «Оболочка и адреса»),
событие пакета — строкой под верхней строкой.
Модуль jira: агент jira; свежесть — jira_synced_at из GET /projects, охват «все проекты»; действие «Обновить из
Jira» — POST /refresh {full: true, author: "viewer"}; после пакета перечитываются снимки досок, списки задач, лента и
открытая карточка; доска, показывающая снимок из файла, его не заменяет. Модуль wiki: агент wiki; свежесть —
wiki_synced_at, wiki_sync_error из GET /projects, охват «проект»; данные для проекта есть, только если есть
wiki_root; действие «Обновить вики» — POST /wiki/sync {project, author: "viewer"}; после пакета перечитываются дерево,
страницы и поиск. Блок состояния MUST NOT загружать снимок доски или GET /wiki/status.
Страница модуля с действием обновления SHALL дублировать его вторичной кнопкой в шапке страницы; основной (primary) кнопки обновления в приложении нет.
Scenario: Обновление со списка задач
- WHEN открыт
/app/jira/issues, нажато «Обновить из Jira» в строке «Jira», пакет выполнен - THEN в хабе один пакет
refreshавтораviewer; список задач перезапрошен; строка «Jira» показывала «пакет #N выполняется», затем «пакет #N выполнен»; строка «Вики» не изменилась
Scenario: Один прогон на модуль
- WHEN нажата «Обновить из Jira» и, пока пакет выполняется, выполнен переход между разделами и нажата «Обновить из Jira» в шапке доски
- THEN кнопки «Обновить из Jira» недоступны, в хабе один пакет, его опрашивает один опрос
Scenario: Опрос получил 404
- WHEN опрос пакета вики получил 404
- THEN опрос остановлен, строка «Вики» показывает «пакета нет в хабе», «Обновить вики» снова доступна
Scenario: Автообновление хаба
- WHEN хаб поставил пакет «Автообновление» (автор
hub, модульjira), приложение открыто на странице «Вики» - THEN не позже чем через 60 с строка «Jira» показывает «пакет #N выполняется», по завершении — новое «данные на …»
Scenario: Пакет другого проекта
- WHEN идёт пакет
wiki_syncпроектаSTOCKS_DRRK, текущий проект —AWPCA - THEN строка «Вики» его не показывает, «Обновить вики» доступна
Scenario: Пакет с другими командами
- WHEN незавершённый пакет модуля jira автора
viewerсостоит из командensure_fields - THEN строка «Jira» показывает «пакет #N выполняется», кнопка «Обновить из Jira» доступна; её нажатие ставит пакет
refresh, и строка показывает его
Scenario: Агент офлайн
- WHEN агент
wikiофлайн и нажато «Обновить вики» - THEN пакет поставлен; строка «Вики» — точка с текстом «агент офлайн» и событие «агент офлайн — пакет выполнится, когда он выйдет на связь; пакет #N в очереди…»
Scenario: Синхронизация уже идёт
- WHEN нажато «Обновить вики», хаб ответил 409
- THEN строка «Вики» показывает идущий пакет, сообщения об ошибке нет
Scenario: Проект без корня вики
- WHEN текущий проект
sfm_kedrбез корня вики - THEN в блоке состояния только строка «Jira»; на свёрнутой панели — один значок состояния
Scenario: Агенту нужно обновление
- WHEN
GET /agentsотдаёт агентаjiraсwarning - THEN строка «Jira» — точка с текстом «обновите агента», текст
warningв подсказке
Scenario: Смена проекта во время опроса
- WHEN строка «Вики» показывает пакет
wiki_syncпроектаAWPCA, текущий проект сменён наSTOCKS_DRRK, и в тот же момент пришёл ответ опроса этого пакета - THEN строка «Вики» без события пакета; опроса этого пакета больше нет