Архив OpenSpec: sidebar (#69)

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
This commit is contained in:
Andrey Epifancev 2026-10-22 10:01:08 +04:00
parent 73ec28267e
commit 3f75eb5909
5 changed files with 53 additions and 22 deletions

View File

@ -38,21 +38,41 @@ SHALL очищать токен и показывать экран входа.
### Requirement: Оболочка и адреса
Приложение SHALL открываться под префиксом `/app/` и иметь страницы `/app/board` (доска связей), `/app/issues` (список
задач) и `/app/issues/{key}` (карточка задачи — окно поверх страницы, требование «Карточка задачи»); `/app` и `/app/` SHALL вести на `/app/board`, неизвестный путь —
на страницу «не найдено» со ссылками на разделы. Верхняя панель SHALL содержать название, выпадающий список проектов
(«<метка> — <название>», текущий отмечен, в конце «+ Новый проект…»; требование «Проект в приложении»), разделы
«Доска связей» и «Задачи» сегментным переключателем (текущий отмечен `aria-current="page"`), блок данных Jira с
действием «Обновить из Jira» (требование «Обновление из Jira»), переключатель темы (требование «Тема») и меню с
действием «Сменить токен». На узких экранах панель SHALL переноситься на две строки без горизонтальной прокрутки.
на страницу «не найдено» со ссылками на разделы. Боковая панель SHALL быть закреплена у левого края окна на всю его
высоту и MUST NOT прокручиваться вместе со страницей; страница занимает остальную ширину. Сверху вниз панель SHALL
содержать: название «Хаб Jira» и кнопку «Свернуть панель»; выпадающий список проектов («<метка> — <название>», текущий
отмечен, в конце «+ Новый проект…»; требование «Проект в приложении»); разделы «Доска связей» и «Задачи» — вертикальным
списком ссылок со значками (текущий отмечен `aria-current="page"`); внизу — блок данных Jira с действием «Обновить из
Jira» (требование «Обновление из Jira»), переключатель темы (требование «Тема») и меню с действием «Сменить токен».
Свёрнутая панель SHALL быть узкой полосой с теми же действиями значками: «Развернуть панель», метка текущего проекта,
разделы, «Обновить из Jira» с точкой состояния агента, тема, меню; названия — в подсказках и `aria-label`. Свёртка
SHALL храниться в `localStorage` под ключом `jira-hub-sidebar` (`collapsed`; без записи — развёрнута). На экранах уже
640 px панели в потоке нет: сверху SHALL быть закреплена строка с кнопкой «Меню», названием и кнопкой «Обновить из
Jira»; «Меню» открывает развёрнутую панель поверх страницы, панель закрывается выбором раздела, клавишей Escape или
щелчком мимо неё. Горизонтальной прокрутки страницы на любой ширине нет.
Неожиданная ошибка отрисовки страницы SHALL показываться сообщением с кнопкой «Перезагрузить», не пустым экраном.
#### Scenario: Переход между разделами
- **WHEN** на доске выбран раздел «Задачи»
- **WHEN** на доске в боковой панели выбран раздел «Задачи»
- **THEN** адрес — `/app/issues` с текущим проектом, показан список задач; «назад» возвращает на доску
#### Scenario: Сменить токен
- **WHEN** в меню верхней панели выбрано «Сменить токен»
- **WHEN** в меню боковой панели выбрано «Сменить токен»
- **THEN** токен очищен, показан экран входа
#### Scenario: Панель на месте при прокрутке
- **WHEN** доска прокручена до самого низа
- **THEN** боковая панель видна целиком на прежнем месте: разделы и «Обновить из Jira» доступны без прокрутки вверх
#### Scenario: Свёрнутая панель
- **WHEN** нажата «Свернуть панель», страница перезагружена
- **THEN** панель свёрнута в полосу значков, доска шире; значок «Задачи» открывает список задач; «Развернуть панель»
возвращает полную панель
#### Scenario: Узкий экран
- **WHEN** ширина окна 390 px, нажата «Меню», в панели выбран раздел «Задачи»
- **THEN** панель открылась поверх страницы, после выбора закрыта, показан список задач; горизонтальной прокрутки нет
### Requirement: Ошибки хаба
Приложение SHALL различать ошибки запросов к хабу: 401 — экран входа; хаб не отвечает (сеть, 5xx) — сообщение
«хаб не отвечает» с возможностью повторить, ранее загруженные данные остаются на экране; прочие 4xx — текст `detail`
@ -93,7 +113,7 @@ SHALL очищать токен и показывать экран входа.
передачи», «Скрыть без связей») и группы «Режим» («Критический путь», «По датам»), каждый с `aria-pressed` и прежней
подсказкой. Под панелью — легенда, которая сворачивается кнопкой «Легенда»; свёрнутая показывает число скрытых видов
работ и типов связей; состояние свёртки хранится в `localStorage` под ключом `jira-hub-legend`. «Обновить из Jira»,
тема и «Сменить токен» — в верхней панели приложения, на доске их нет.
тема и «Сменить токен» — в боковой панели приложения, на доске их нет.
У карточки задачи (не у заглушки) SHALL быть значок «Открыть карточку»,
открывающий `/app/issues/{key}` окном поверх доски; ключ карточки по-прежнему открывает задачу в Jira. Пока окно открыто
@ -107,6 +127,11 @@ SHALL очищать токен и показывать экран входа.
При возврате на `/app/board` с другой страницы приложения в той же вкладке доска SHALL восстанавливать прежнюю
прокрутку; после перезагрузки страницы доска открывается сверху.
Дорожки SHALL разделяться линией; фон развёрнутых дорожек один, без чередования, чтобы подсветка колонок «по датам»
(прошедшие даты, сегодня) была видна на всех дорожках; свёрнутая дорожка выделяется фоном. У карточки задачи, статус
Jira которой не входит в `closed_statuses`, с плановой датой окончания раньше сегодняшней дата «до …» SHALL быть цветом
ошибки, с подсказкой и текстом для экранного чтения «просрочено»; это только вид, модель и раскладка от него не зависят.
#### Scenario: Раскладка переживает переход
- **WHEN** раскладка карточек сохранена страницей `links.html`, открыта `/app/board` с теми же данными
- **THEN** карточки стоят на тех же местах, дорожки в том же порядке и свёртке, фильтры те же
@ -137,6 +162,12 @@ SHALL очищать токен и показывать экран входа.
- **WHEN** в легенде скрыт вид работы «тестирование», легенда свёрнута, страница перезагружена
- **THEN** легенда свёрнута, рядом с кнопкой «Легенда» — «скрыто: 1»; карточек вида «тестирование» на доске нет
#### Scenario: Просрочка на доске
- **WHEN** сегодня 22.10, у AURORA-1620 статус «В работе» и срок 20.10, у AURORA-1621 «Готово» и срок 20.10, включено
«По датам»
- **THEN** дата AURORA-1620 — цветом ошибки с пометкой «просрочено», у AURORA-1621 — обычная; подсветка колонки 20.10
видна на всех дорожках, дорожки одного фона
### Requirement: Источник данных доски
Доска SHALL хранить явный источник данных — хаб или файл. Пока показан снимок из файла (CSV или JSON-снимок), ответы
хаба SHALL его не заменять; «Перечитать» SHALL возвращать источник «хаб» и загружать `GET /board` заново без обращения к
@ -144,7 +175,7 @@ Jira. Импорт JSON в режиме хаба SHALL применять рас
показывать источник данных (пометка «из файла» с именем файла; данные хаба пометки не имеют) и одно текущее событие
доски (загрузка; хаб не отвечает — прежние данные, а при снимке из файла — «на доске снимок из файла»; ошибка разбора
файла — «файл не разобран: <причина>»; раскладка и фильтры из JSON применены; ошибка); новое событие заменяет
предыдущее целиком. События пакета обновления из Jira показывает верхняя панель приложения (требование «Обновление из
предыдущее целиком. События пакета обновления из Jira показывает боковая панель приложения (требование «Обновление из
Jira»), не шапка доски.
#### Scenario: Поздний ответ хаба не затирает файл
@ -161,23 +192,23 @@ Jira»), не шапка доски.
#### Scenario: Нет второго полного прогона
- **WHEN** нажата «Обновить из Jira» и, пока пакет выполняется, доска перерисована (фильтр, «Перечитать»)
- **THEN** кнопка «Обновить из Jira» в верхней панели остаётся недоступной, в хабе один пакет, его опрашивает один опрос
- **THEN** кнопка «Обновить из Jira» в боковой панели остаётся недоступной, в хабе один пакет, его опрашивает один опрос
#### Scenario: Пакет пропал
- **WHEN** опрос пакета получил 404, на доске данные хаба
- **THEN** доска показывает прежние данные без своего события об ошибке; сообщение о пропавшем пакете — в верхней панели
- **THEN** доска показывает прежние данные без своего события об ошибке; сообщение о пропавшем пакете — в боковой панели
#### Scenario: Пакет после «Перечитать»
- **WHEN** пакет `viewer` поставлен с другой вкладки и не завершён, на доске нажато «Перечитать»
- **THEN** верхняя панель показывает «пакет #N выполняется», по завершении доска перечитывает данные
- **THEN** боковая панель показывает «пакет #N выполняется», по завершении доска перечитывает данные
#### Scenario: «Перечитать» во время пакета
- **WHEN** пакет `viewer` выполняется и на доске нажато «Перечитать»
- **THEN** верхняя панель по-прежнему показывает «пакет #N выполняется», шапка доски — без события пакета
- **THEN** боковая панель по-прежнему показывает «пакет #N выполняется», шапка доски — без события пакета
#### Scenario: Чужой пакет не подхватывается
- **WHEN** незавершённый пакет автора `viewer` состоит из команд `ensure_fields`, открыта доска
- **THEN** доска и верхняя панель его не опрашивают, кнопка «Обновить из Jira» доступна
- **THEN** доска и боковая панель его не опрашивают, кнопка «Обновить из Jira» доступна
### Requirement: Список задач
Страница `/app/issues` SHALL показывать задачи текущего проекта из `GET /issues?project=<текущий>` таблицей: ключ
@ -426,7 +457,7 @@ SHALL сообщать об этом с кнопкой «Закрыть»; ха
Форма «Новый проект» (пункт «+ Новый проект…» выпадающего списка) SHALL открываться окном поверх страницы: метка,
название, номер доски Jira (необязательно; подсказка «scrum или kanban определится сам»). «Создать» — `POST /projects`
с автором `viewer`; ошибка хаба 409/422 — текст `detail` рядом с кнопкой, окно остаётся открытым; успех — окно
закрывается, текущим становится новый проект, верхняя панель показывает ход пакета обновления из ответа (`batch_id`).
закрывается, текущим становится новый проект, боковая панель показывает ход пакета обновления из ответа (`batch_id`).
#### Scenario: Первый вход после выкатки
- **WHEN** открыт `/app/board` без `project`, в `localStorage` выбора нет, проекты `AWPCA` и `STOCKS_DRRK`
@ -443,7 +474,7 @@ SHALL сообщать об этом с кнопкой «Закрыть»; ха
#### Scenario: Создание проекта из формы
- **WHEN** в форме введены `STOCKS_DRRK`, «Запасы ДРРК», доска пусто; нажато «Создать»
- **THEN** `POST /projects {label: "STOCKS_DRRK", name: "Запасы ДРРК", author: "viewer"}`; текущий проект — `STOCKS_DRRK`;
верхняя панель показывает «пакет #N выполняется»
боковая панель показывает «пакет #N выполняется»
#### Scenario: Метка занята
- **WHEN** в форме введена метка `awpca`, хаб ответил 409
@ -477,7 +508,7 @@ Semibold 14/20, заголовок страницы Bold 20/28. Страницы
страницах, в окнах и меню
### Requirement: Обновление из Jira
Действие «Обновить из Jira» SHALL быть в верхней панели приложения и доступно с любой страницы. Оно SHALL проверять
Действие «Обновить из Jira» SHALL быть в боковой панели приложения и доступно с любой страницы. Оно SHALL проверять
агента (`GET /agent`; офлайн — предупреждение, пакет всё равно ставится), ставить `POST /refresh {full: true, author:
"viewer"}` и опрашивать `GET /batches/{id}` каждые 3 с одним опросом до терминального статуса пакета. Кнопка SHALL быть
недоступна (с признаком загрузки), пока запрос `/refresh` в пути или пакет выполняется. Незавершённый пакет автора
@ -488,7 +519,7 @@ Semibold 14/20, заголовок страницы Bold 20/28. Страницы
снимки досок, списки задач, открытую карточку и список проектов; доска, показывающая снимок из файла, его не заменяет.
Пакет, поставленный формой «Новый проект», SHALL опрашиваться так же сразу после создания.
Верхняя панель SHALL показывать блок данных Jira: состояние агента («агент на связи» / «агент офлайн», по `GET /agent`
Боковая панель SHALL показывать блок данных Jira: состояние агента («агент на связи» / «агент офлайн», по `GET /agent`
при входе и раз в 60 с), время последнего полного обновления («данные на ДД.ММ ЧЧ:ММ» по `last_sync` снимка доски
текущего проекта, «полного обновления не было», если его нет) и одно текущее событие пакета: в очереди / выполняется (с
оставшимся временем, с пометкой «агент офлайн» и «хаб не отвечает, повтор»), выполнен, не выполнен с текстом ошибки,
@ -497,7 +528,7 @@ Semibold 14/20, заголовок страницы Bold 20/28. Страницы
#### Scenario: Обновление со списка задач
- **WHEN** открыт `/app/issues`, нажато «Обновить из Jira», пакет выполнен
- **THEN** в хабе один пакет `refresh` автора `viewer`; список задач перезапрошен; верхняя панель показывала «пакет #N
- **THEN** в хабе один пакет `refresh` автора `viewer`; список задач перезапрошен; боковая панель показывала «пакет #N
выполняется», затем «пакет #N выполнен»
#### Scenario: Один прогон на всё приложение
@ -506,11 +537,11 @@ Semibold 14/20, заголовок страницы Bold 20/28. Страницы
#### Scenario: Опрос получил 404
- **WHEN** опрос пакета получил 404
- **THEN** опрос остановлен, верхняя панель показывает «пакета нет в хабе», кнопка «Обновить из Jira» снова доступна
- **THEN** опрос остановлен, боковая панель показывает «пакета нет в хабе», кнопка «Обновить из Jira» снова доступна
#### Scenario: Пакет с другой вкладки
- **WHEN** пакет `viewer` с командой `refresh` поставлен с другой вкладки и не завершён, приложение открыто
- **THEN** верхняя панель показывает «пакет #N выполняется» и по завершении данные перечитываются
- **THEN** боковая панель показывает «пакет #N выполняется» и по завершении данные перечитываются
#### Scenario: Пакет с другими командами
- **WHEN** незавершённый пакет автора `viewer` состоит из команд `ensure_fields`
@ -521,7 +552,7 @@ Semibold 14/20, заголовок страницы Bold 20/28. Страницы
- **THEN** пакет поставлен, событие — «агент офлайн — пакет выполнится, когда он выйдет на связь; пакет #N в очереди…»
### Requirement: Тема
Переключатель темы SHALL быть в верхней панели приложения: два положения — светлая и тёмная. Выбор SHALL храниться в
Переключатель темы SHALL быть в боковой панели приложения: два положения — светлая и тёмная. Выбор SHALL храниться в
`localStorage` под ключом `graph-theme` (`light` / `dark`), как у прежней доски; без сохранённого выбора или со
значением `""` тема SHALL следовать настройке системы, и переключатель показывает её. Тема применяется до первой
отрисовки, без мигания.