Архив OpenSpec: wiki-history (#140)
Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
This commit is contained in:
parent
a50ef9dcb1
commit
a4c23f3f0b
@ -264,20 +264,34 @@ HTTP API хаба клиентским токеном из настроек; с
|
||||
| `project_create` | `label`, `name`, `wiki_root` (необязательно) | `POST /projects` с автором `claude`; проект и фрагмент `.mcp.json` с записью `sdlc-wiki` |
|
||||
| `root_set` | `root` | `PATCH /projects/<текущий> {wiki_root}`; новый корень и id пакета синхронизации |
|
||||
| `tree` | `code` (необязательно), `depth` (по умолчанию 2) | дерево от корня или от `code`: отступ, код, название, размер |
|
||||
| `page` | `code` или `title`, `offset` (по умолчанию 0) | шапка (код, путь в дереве, адрес в Eva, дата синхронизации, вложения с `id`) и Markdown с `offset` до 20 000 символов, в конце — «продолжение: offset=<N>», если текст длиннее; `title` ищется точно, иначе — до 10 кандидатов с кодами |
|
||||
| `page` | `code` или `title`, `offset` (по умолчанию 0) | шапка (код, путь в дереве, адрес в Eva, дата синхронизации, строка «изменено: ДД.ММ ЧЧ:ММ <автор> (версий: N)» или «изменено: история не загружена», вложения с `id`) и Markdown с `offset` до 20 000 символов, в конце — «продолжение: offset=<N>», если текст длиннее; `title` ищется точно, иначе — до 10 кандидатов с кодами |
|
||||
| `search` | `query`, `limit` (по умолчанию 10) | страницы: код, название, путь, фрагмент |
|
||||
| `changes` | `hours`, `since`, `until`, `author` (все необязательные) | правки страниц проекта за период (`GET /wiki/changes`), см. ниже |
|
||||
| `diff` | `code`, `version` (необязательно), `offset` (по умолчанию 0) | шапка (код, название, путь, версия «N из M», автор, время, «+A / −R», предыдущая версия) и unified diff с `offset` до 20 000 символов, в конце — «продолжение: offset=<N>», если дифф длиннее; без `version` — последняя правка |
|
||||
| `attachment` | `id` | ставит скачивание, ждёт до 60 с; готово — путь к копии `downloads/wiki-<id>/<имя>`; иначе состояние и подсказка повторить |
|
||||
| `sync` | `wait` (по умолчанию `false`) | ставит синхронизацию (или сообщает о текущей) и id пакета; с `wait` — ждёт до 300 с и отдаёт итог |
|
||||
| `status` | — | корень, последняя синхронизация, ошибка, пакет в работе, агент `wiki`: онлайн/офлайн, версия, публикация, обновление, запускатель (как `agent_status` сервера jira) |
|
||||
| `sync` | `wait` (по умолчанию `false`) | без `wait` — «поставлено: пакет N» или «уже идёт: пакет N»; с `wait` — ждёт до 300 с: «ок: синхронизировано ДД.ММ ЧЧ:ММ», «ошибка: <текст>» или «не дождался за 300 с: пакет N»; данных копии в ответе нет |
|
||||
| `status` | — | корень, последняя синхронизация, загрузка истории (`history_at` или «история не загружена»), ошибка, пакет в работе, агент `wiki`: онлайн/офлайн, версия, публикация, обновление, запускатель (как `agent_status` сервера jira) |
|
||||
|
||||
Инструменты, кроме `projects` и `project_create`, SHALL требовать привязки к проекту. В привязанной сессии без корня
|
||||
(кроме `root_set`, `status`) ответ SHALL быть «у проекта <метка> нет корня вики: root_set DOC-…»; с корнем, но без
|
||||
синхронизаций — «вики проекта ещё не синхронизирована: sync». Набор инструментов и их описания у сервера `sdlc-jira`
|
||||
(модуль jira) SHALL остаться прежним.
|
||||
(модуль jira) SHALL остаться прежним. Инструменты `page`, `changes`, `diff` MUST NOT ставить команд: они читают только
|
||||
копию хаба.
|
||||
|
||||
`changes`: период — как у инструмента `changes` сервера jira («Лента изменений в MCP»): `hours` и `since` вместе —
|
||||
ответ «либо hours, либо since»; без обоих — с начала текущих суток по местному времени машины MCP-сервера; с `hours` —
|
||||
`since = сейчас − hours`; `since`/`until` без смещения — местное время машины MCP-сервера. `author` передаётся в хаб
|
||||
как есть. Вид ответа: первая строка — период по местному времени («правки вики с 28.10 00:00 по 28.10 14:05»), вторая
|
||||
— «синхронизировано: ДД.ММ ЧЧ:ММ»; затем правки, сгруппированные по странице; страницы — по времени последней правки,
|
||||
новые сверху; у страницы строка «DOC-… <название> — <путь>», под ней правки по времени, новые сверху, каждая — «ЧЧ:ММ
|
||||
<автор>: +A / −R (<версия>)», с датой «ДД.ММ» перед временем, если правка не в текущих сутках. Правок нет — «за период
|
||||
правок нет»; `history_at = null` — «история ещё не загружена: нужен eva-agent v2 и sync»; `truncated` — последняя
|
||||
строка «показаны последние N правок, сузьте период». Ошибка 422 хаба — её текст.
|
||||
|
||||
Значения из Eva, которые инструменты выводят внутри строки ответа (названия страниц и корня, путь, имя вложения,
|
||||
фрагмент поиска, кандидаты `page` по названию), SHALL выводиться одной строкой: переводы строк (`\r`, `\n`) и пробелы
|
||||
вокруг них заменяются одним пробелом. Тело страницы (Markdown после шапки `page`) выводится как есть.
|
||||
фрагмент поиска, кандидаты `page` по названию, имя автора правки), SHALL выводиться одной строкой: переводы строк
|
||||
(`\r`, `\n`) и пробелы вокруг них заменяются одним пробелом. Тело страницы (Markdown после шапки `page`) и дифф после
|
||||
шапки `diff` выводятся как есть.
|
||||
|
||||
#### Scenario: Поиск из сессии awp-ca
|
||||
- **WHEN** сервер запущен с `--project AWPCA`, копия синхронизирована, вызван `search {query: "статус согласован"}`
|
||||
@ -300,6 +314,24 @@ HTTP API хаба клиентским токеном из настроек; с
|
||||
- **WHEN** у DOC-3 название «Статусы\nпуть: поддельный», вызван `page {code: DOC-3}`
|
||||
- **THEN** первая строка ответа — «DOC-3 — Статусы путь: поддельный», строка «путь:» в шапке одна — настоящая
|
||||
|
||||
#### Scenario: Что сделали аналитики сегодня
|
||||
- **WHEN** сессия `AWPCA`, `changes {}` в 14:05; сегодня Соснов опубликовал две версии DOC-101252 в 11:02 и 12:40
|
||||
- **THEN** запрос `GET /wiki/changes?project=AWPCA&since=<сегодня 00:00 местного>`; в ответе строка DOC-101252 с
|
||||
названием и путём, под ней «12:40 Дмитрий Соснов: +40 / −12 (DOCH-…)» и «11:02 Дмитрий Соснов: …»; команд не
|
||||
поставлено
|
||||
|
||||
#### Scenario: Дифф правки
|
||||
- **WHEN** `diff {code: DOC-101252}`, у страницы 4 версии
|
||||
- **THEN** шапка «версия 4 из 4», автор, время, «+A / −R», предыдущая версия; затем unified diff
|
||||
|
||||
#### Scenario: Синхронизация с ожиданием
|
||||
- **WHEN** `sync {wait: true}`, пакет завершился `done` в 14:05
|
||||
- **THEN** ответ — одна строка «ок: синхронизировано 28.10 14:05»
|
||||
|
||||
#### Scenario: История ещё не загружена
|
||||
- **WHEN** у агента `wiki` версия 1, `changes {}`
|
||||
- **THEN** ответ содержит «история ещё не загружена: нужен eva-agent v2 и sync»
|
||||
|
||||
### Requirement: Спринты и бэклог в MCP
|
||||
MCP `sdlc-jira` SHALL давать инструменты чтения по `GET /agile` проекта сессии (сессия без проекта — тот же отказ, что у
|
||||
прочих инструментов с проектом):
|
||||
|
||||
@ -41,22 +41,24 @@ SHALL очищать токен и показывать экран входа.
|
||||
|
||||
### Requirement: Оболочка и адреса
|
||||
Приложение SHALL открываться под префиксом `/app/`. Главная страница — «Обзор» ядра (`/app/?project=<метка>`,
|
||||
требование «Обзор проекта»). Страницы модулей SHALL лежать под префиксом имени модуля: модуль jira — `/app/jira/links`
|
||||
(«Связи» — доска связей), `/app/jira/backlog` («Бэклог»), `/app/jira/sprint` («Спринт»), `/app/jira/kanban` («Kanban»;
|
||||
три последних — требование «Спринты и бэклог»), `/app/jira/issues` (список задач), `/app/jira/feed` (лента изменений, требование «Лента изменений») и
|
||||
`/app/jira/issues/{key}` (карточка задачи — окно поверх страницы, требование «Карточка задачи»); модуль wiki —
|
||||
`/app/wiki` (требование «Вики проекта»). Прежние адреса `/app/board` и `/app/jira/board` (на `/app/jira/links`),
|
||||
`/app/issues`, `/app/issues/{key}`, `/app/feed` SHALL перенаправлять на новые с сохранением строки запроса, без новой записи истории. Неизвестный путь — страница «не
|
||||
найдено» со ссылками на «Обзор» и разделы модулей.
|
||||
требование «Обзор проекта»); страница ядра «Лента» — `/app/feed` (требование «Лента изменений»). Страницы модулей SHALL
|
||||
лежать под префиксом имени модуля: модуль jira — `/app/jira/links` («Связи» — доска связей), `/app/jira/backlog`
|
||||
(«Бэклог»), `/app/jira/sprint` («Спринт»), `/app/jira/kanban` («Kanban»; три последних — требование «Спринты и
|
||||
бэклог»), `/app/jira/issues` (список задач) и `/app/jira/issues/{key}` (карточка задачи — окно поверх страницы,
|
||||
требование «Карточка задачи»); модуль wiki — `/app/wiki` (требование «Вики проекта») и
|
||||
`/app/wiki/pages/{code}/versions/{version}` (окно правки поверх страницы, требование «Правки вики в ленте»). Прежние адреса `/app/board` и `/app/jira/board` (на `/app/jira/links`),
|
||||
`/app/issues`, `/app/issues/{key}`, `/app/jira/feed` (на `/app/feed`) SHALL перенаправлять на новые с сохранением
|
||||
строки запроса, без новой записи истории. Неизвестный путь — страница «не найдено» со ссылками на «Обзор», «Ленту» и
|
||||
разделы модулей.
|
||||
|
||||
Боковая панель SHALL быть закреплена у левого края окна на всю его высоту и MUST NOT прокручиваться вместе со
|
||||
страницей; если её содержимое не помещается по высоте, прокручивается сама панель. Сверху вниз панель SHALL содержать:
|
||||
название «SDLC Hub» и кнопку «Свернуть панель»; выпадающий список проектов («<метка> — <название>», текущий отмечен, в
|
||||
конце «+ Новый проект…»; требование «Проект в приложении»); пункт «Обзор»; разделы модулей группами — заголовок группы
|
||||
— название модуля («Jira», «Вики»), под ним ссылки разделов модуля со значками (текущий отмечен
|
||||
конце «+ Новый проект…»; требование «Проект в приложении»); пункты «Обзор» и «Лента»; разделы модулей группами —
|
||||
заголовок группы — название модуля («Jira», «Вики»), под ним ссылки разделов модуля со значками (текущий отмечен
|
||||
`aria-current="page"`); внизу — блок состояния модулей (требование «Состояние и обновление модулей»), переключатель
|
||||
темы (требование «Тема») и меню с действием «Сменить токен». Свёрнутая панель SHALL быть узкой полосой с теми же
|
||||
действиями значками: «Развернуть панель», метка текущего проекта (полностью — в подсказке), «Обзор», разделы
|
||||
действиями значками: «Развернуть панель», метка текущего проекта (полностью — в подсказке), «Обзор», «Лента», разделы
|
||||
(группы разделены линией), по значку состояния на модуль, тема, меню; названия — в подсказках и `aria-label`. Свёртка
|
||||
SHALL храниться в `localStorage` под ключом `sdlc-hub-sidebar` (`collapsed`; без записи — развёрнута).
|
||||
|
||||
@ -68,8 +70,8 @@ SHALL храниться в `localStorage` под ключом `sdlc-hub-sidebar
|
||||
возвращается на «Меню». Горизонтальной прокрутки страницы на любой ширине нет.
|
||||
|
||||
Заголовок вкладки браузера SHALL быть «<название страницы> · <метка проекта> · SDLC Hub» (без проекта — без средней
|
||||
части); название страницы даёт оболочка («Обзор») или модуль. Неожиданная ошибка отрисовки страницы SHALL показываться
|
||||
сообщением с кнопкой «Перезагрузить», не пустым экраном.
|
||||
части); название страницы даёт оболочка («Обзор», «Лента») или модуль. Неожиданная ошибка отрисовки страницы SHALL
|
||||
показываться сообщением с кнопкой «Перезагрузить», не пустым экраном.
|
||||
|
||||
#### Scenario: Прежний адрес доски связей
|
||||
- **WHEN** открыт `/app/jira/board?project=AWPCA`
|
||||
@ -81,8 +83,12 @@ SHALL храниться в `localStorage` под ключом `sdlc-hub-sidebar
|
||||
- **THEN** адрес — `/app/jira/issues` с текущим проектом, показан список задач; «назад» возвращает на доску
|
||||
|
||||
#### Scenario: Раздел «Лента»
|
||||
- **WHEN** на доске в боковой панели выбран раздел «Лента»
|
||||
- **THEN** адрес — `/app/jira/feed` с текущим проектом, показана лента изменений за сегодня; раздел отмечен в панели
|
||||
- **WHEN** на доске в боковой панели выбран пункт «Лента»
|
||||
- **THEN** адрес — `/app/feed` с текущим проектом, показана лента изменений за сегодня; пункт отмечен в панели
|
||||
|
||||
#### Scenario: Прежний адрес ленты
|
||||
- **WHEN** открыт `/app/jira/feed?project=AWPCA&period=7d`
|
||||
- **THEN** адрес заменён на `/app/feed?project=AWPCA&period=7d`, показана общая лента
|
||||
|
||||
#### Scenario: Сменить токен
|
||||
- **WHEN** в меню боковой панели выбрано «Сменить токен»
|
||||
@ -636,48 +642,71 @@ Semibold 14/20, заголовок страницы Bold 20/28. Страницы
|
||||
- **THEN** приложение в тёмной теме, в `localStorage` `graph-theme` = `dark`
|
||||
|
||||
### Requirement: Лента изменений
|
||||
Страница `/app/feed?project=<метка>` SHALL показывать события журнала изменений своих задач текущего проекта за период
|
||||
(`GET /changes` с `project`, `since`, `until`, `kinds`). Период SHALL выбираться переключателем «2 часа» / «Сегодня» /
|
||||
«Вчера» / «7 дней» (по умолчанию «Сегодня»; границы — по местному времени браузера: «Сегодня» — с начала текущих суток
|
||||
до сейчас, «Вчера» — с начала прошлых суток до начала текущих) и храниться в адресе (`period=2h|today|yesterday|7d`;
|
||||
«Сегодня» в адрес не пишется). Виды событий SHALL выбираться флажками «Статусы», «Описание», «Сроки», «Комментарии»,
|
||||
«Прочие поля» (по умолчанию все, кроме «Прочие поля») и храниться в адресе (`kinds=` через запятую; набор по умолчанию в
|
||||
адрес не пишется; в адресе нет ни одного известного вида — набор по умолчанию); снятые все флажки — сообщение «выберите
|
||||
хотя бы один вид», запроса нет.
|
||||
Страница «Лента» (`/app/feed?project=<метка>`) SHALL быть страницей ядра и показывать события текущего проекта за
|
||||
период из источников модулей: «Jira» — журнал изменений своих задач (`GET /changes` с `project`, `since`, `until`,
|
||||
`kinds`), «Вики» — правки страниц (требование «Правки вики в ленте»). Источник показывается, если он доступен проекту
|
||||
(«Jira» — всегда, «Вики» — у проекта есть корень вики). Доступных источников больше одного — над лентой
|
||||
флажки источников «Jira», «Вики» (по умолчанию все доступные), выбор хранится в адресе (`sources=` через запятую; набор
|
||||
по умолчанию в адрес не пишется; в адресе нет ни одного известного источника — набор по умолчанию); сняты все флажки —
|
||||
сообщение «выберите хотя бы один источник», запросов нет. Доступный источник один — флажков нет.
|
||||
|
||||
События SHALL быть сгруппированы по задаче; задачи — по времени последнего события, новые сверху. У группы: ключ —
|
||||
ссылка на карточку задачи (окно поверх ленты, требование «Карточка задачи»), тема и текущий статус; под ней события по
|
||||
времени, новые сверху, каждое — время (`ЧЧ:ММ`, с датой `ДД.ММ`, если событие не в текущих сутках), автор и текст:
|
||||
статус — «статус «было» → «стало»»; описание — «описание изменено»; срок, плановое начало и окончание — «срок ДД.ММ →
|
||||
ДД.ММ» (дата по значению `from_value`/`to_value`, иначе строка журнала; пустое — «—»); комментарий — «комментарий:» и
|
||||
первые 300 символов текста без вики-разметки Jira (так, как текст читается отрендеренным: без `*`, `{code}`, `h3.`; у `[текст|адрес]` — текст, `[~логин]` — «@логин») одной строкой с «…»; прочие поля — «<название поля>: «было» → «стало»» (значения до 80
|
||||
символов с «…»), где название — подпись из словаря приложения (исполнитель, спринт, метки, приоритет, тема, эпик, связь,
|
||||
вложение, резолюция), иначе имя поля Jira. Подзаголовок страницы — число событий и границы периода. Событий нет —
|
||||
сообщение «за период изменений нет»; `truncated` — сообщение «показаны последние N событий — выберите период короче».
|
||||
Ошибка хаба — сообщение с кнопкой «Повторить». Ленту SHALL перечитывать завершение «Обновить из Jira» (вместе со списками
|
||||
задач) и возврат на вкладку браузера.
|
||||
Период SHALL выбираться переключателем «2 часа» / «Сегодня» / «Вчера» / «7 дней» (по умолчанию «Сегодня»; границы — по
|
||||
местному времени браузера: «Сегодня» — с начала текущих суток до сейчас, «Вчера» — с начала прошлых суток до начала
|
||||
текущих) и храниться в адресе (`period=2h|today|yesterday|7d`; «Сегодня» в адрес не пишется); период общий для всех
|
||||
источников. Виды событий Jira SHALL выбираться флажками «Статусы», «Описание», «Сроки», «Комментарии», «Прочие поля»
|
||||
(по умолчанию все, кроме «Прочие поля»), видными, пока выбран источник «Jira», и храниться в адресе (`kinds=` через
|
||||
запятую; набор по умолчанию в адрес не пишется; в адресе нет ни одного известного вида — набор по умолчанию); сняты все
|
||||
флажки видов — сообщение «выберите хотя бы один вид» на месте событий Jira, запроса `GET /changes` нет.
|
||||
|
||||
События SHALL быть сгруппированы: Jira — по задаче, Вики — по странице; группы обоих источников идут одним списком по
|
||||
времени последнего события, новые сверху. У группы Jira: ключ — ссылка на карточку задачи (окно поверх ленты,
|
||||
требование «Карточка задачи»), тема и текущий статус; под ней события по времени, новые сверху, каждое — время
|
||||
(`ЧЧ:ММ`, с датой `ДД.ММ`, если событие не в текущих сутках), автор и текст: статус — «статус «было» → «стало»»;
|
||||
описание — «описание изменено»; срок, плановое начало и окончание — «срок ДД.ММ → ДД.ММ» (дата по значению
|
||||
`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`;
|
||||
задачи сгруппированы, у каждой — события «ЧЧ:ММ автор: статус «В работе» → «Готово»»
|
||||
- **WHEN** открыта лента проекта AWPCA, выбран период «2 часа», снят источник «Вики», сняты все виды, кроме «Статусы»
|
||||
- **THEN** адрес — `/app/feed?project=AWPCA&period=2h&sources=jira&kinds=status`; запрос `GET
|
||||
/changes?project=AWPCA&since=<сейчас − 2 ч>&kinds=status`; запроса `GET /wiki/changes` нет; задачи сгруппированы, у
|
||||
каждой — события «ЧЧ:ММ автор: статус «В работе» → «Готово»»
|
||||
|
||||
#### Scenario: Карточка из ленты
|
||||
- **WHEN** в ленте нажат ключ AURORA-9002
|
||||
- **THEN** поверх ленты открыто окно карточки AURORA-9002; закрытие окна возвращает ленту с тем же периодом
|
||||
|
||||
#### Scenario: Пустой период
|
||||
- **WHEN** за выбранный период событий нет
|
||||
- **WHEN** за выбранный период событий нет ни в Jira, ни в Вики
|
||||
- **THEN** показано «за период изменений нет»
|
||||
|
||||
#### Scenario: Вчера
|
||||
- **WHEN** выбран период «Вчера», сейчас 22.10 14:05 местного времени
|
||||
- **THEN** запрос с `since` = 21.10 00:00 и `until` = 22.10 00:00 местного времени
|
||||
- **THEN** запросы источников с `since` = 21.10 00:00 и `until` = 22.10 00:00 местного времени
|
||||
|
||||
#### Scenario: Комментарий с разметкой
|
||||
- **WHEN** в ленте событие комментария с текстом `h3. Итог` и `*Готово*, см. [протокол|https://x.ru/p] и [~ivanov]`
|
||||
- **THEN** строка события — «комментарий: Итог Готово, см. протокол и @ivanov»
|
||||
|
||||
#### Scenario: Jira и Вики вперемешку
|
||||
- **WHEN** сегодня в 10:00 сменился статус AURORA-1, в 11:00 опубликована правка DOC-3, в 12:00 — комментарий к AURORA-2
|
||||
- **THEN** группы сверху вниз: AURORA-2, DOC-3, AURORA-1
|
||||
|
||||
#### Scenario: Проект без вики
|
||||
- **WHEN** у проекта `sfm_kedr` нет корня вики
|
||||
- **THEN** флажков источников нет, показаны события Jira; запроса `GET /wiki/changes` нет
|
||||
|
||||
#### Scenario: Ошибка одного источника
|
||||
- **WHEN** `GET /wiki/changes` ответил 500, `GET /changes` — событиями
|
||||
- **THEN** события Jira показаны; на месте правок вики — сообщение об ошибке с кнопкой «Повторить»
|
||||
|
||||
### Requirement: История в карточке задачи
|
||||
Карточка задачи SHALL показывать в основной колонке после комментариев блок «История (N)» — события `changes` из
|
||||
`GET /issues/{key}` (все виды, новые сверху) в том же виде, что в ленте, всегда с датой. Видны 10 последних событий,
|
||||
@ -886,8 +915,9 @@ Jira» — `POST /refresh {full: true, author: "viewer"}`; после пакет
|
||||
названием проекта и под ней карточку на каждый модуль, у которого есть данные для проекта: название модуля, агент (с
|
||||
версией из `GET /agents`), свежесть с охватом, текущее событие пакета, вторичная кнопка обновления и сводка, которую
|
||||
даёт модуль. Сводка jira: число своих задач проекта, из них открытых и просроченных (по снимку доски проекта), ссылки
|
||||
«Доска связей», «Задачи», «Лента». Сводка wiki: число страниц, поле поиска по вики (Enter открывает «Вики» с этим
|
||||
поиском), ссылка «Вики». Модуль без данных для проекта SHALL показывать карточку с объяснением и действием модуля (у
|
||||
«Доска связей», «Задачи», «Лента» (общая лента с источником Jira — `/app/feed?project=<метка>&sources=jira`). Сводка
|
||||
wiki: число страниц, поле поиска по вики (Enter открывает «Вики» с этим поиском), ссылки «Вики» и «Правки» (общая
|
||||
лента с источником Вики — `/app/feed?project=<метка>&sources=wiki`). Модуль без данных для проекта SHALL показывать карточку с объяснением и действием модуля (у
|
||||
вики — «Привязать корень вики» ведёт на страницу «Вики»). Под карточками — «Последние пакеты проекта»: до 10 из
|
||||
`GET /batches?project=<метка>`: номер, модуль, название, автор, статус, время создания.
|
||||
|
||||
@ -926,7 +956,7 @@ Jira» — `POST /refresh {full: true, author: "viewer"}`; после пакет
|
||||
### Requirement: Спринты и бэклог
|
||||
Модуль jira SHALL показывать для проекта с доской страницы по образцу Jira — только для просмотра: на них MUST NOT быть
|
||||
действий, меняющих Jira (перетаскивания, кнопок спринтов, смены статуса или ранга). Пункты меню группы «Jira» —
|
||||
«Связи», «Задачи», «Лента» и по типу доски текущего проекта (`board_type` из `GET /projects`): `scrum` — «Бэклог» и
|
||||
«Связи», «Задачи» и по типу доски текущего проекта (`board_type` из `GET /projects`): `scrum` — «Бэклог» и
|
||||
«Спринт»; `kanban` — «Kanban»; доски нет или тип неизвестен — новых пунктов нет, а прямой переход на их адрес
|
||||
показывает «У проекта нет scrum-доски» («…kanban-доски» для «Kanban») со ссылкой на «Связи». Данные — `GET
|
||||
/agile?project=<текущий>`; если доска есть, но её данных от агента нет (`board = null` или `board.fetched_at = null`) —
|
||||
@ -1002,7 +1032,7 @@ Jira» — `POST /refresh {full: true, author: "viewer"}`; после пакет
|
||||
|
||||
#### Scenario: Меню scrum-проекта
|
||||
- **WHEN** текущий проект `AWPCA`, `board_type = scrum`
|
||||
- **THEN** в группе «Jira» пункты «Связи», «Бэклог», «Спринт», «Задачи», «Лента»; пункта «Kanban» нет
|
||||
- **THEN** в группе «Jira» пункты «Связи», «Бэклог», «Спринт», «Задачи»; пункта «Kanban» нет
|
||||
|
||||
#### Scenario: Проект без доски
|
||||
- **WHEN** текущий проект `STOCKS_DRRK` без доски, открыт `/app/jira/backlog?project=STOCKS_DRRK`
|
||||
@ -1058,3 +1088,55 @@ Jira» — `POST /refresh {full: true, author: "viewer"}`; после пакет
|
||||
- **WHEN** окно 2560 × 1300 px, у доски 12 колонок, в одной из них 40 карточек
|
||||
- **THEN** все колонки одной высоты и помещаются в окно по высоте; полоса горизонтальной прокрутки доски видна в окне;
|
||||
прокрутка доски вправо до конца показывает «Без колонки» целиком; страница горизонтально не прокручивается
|
||||
|
||||
### Requirement: Правки вики в ленте
|
||||
Модуль wiki SHALL давать ленте источник «Вики»: правки страниц проекта за период (`GET /wiki/changes` с `project`,
|
||||
`since`, `until`). Правки сгруппированы по странице; у группы — название страницы ссылкой на неё в разделе «Вики»
|
||||
(`/app/wiki?project=<метка>&page=<код>`) и путь в дереве; под ней правки по времени, новые сверху, каждая — время
|
||||
(`ЧЧ:ММ`, с датой `ДД.ММ`, если правка не в текущих сутках), автор (имя) и «+A / −R». `history_at = null` — на месте
|
||||
правок вики сообщение «история вики ещё не загружена — нужен eva-agent v2».
|
||||
|
||||
Нажатие на правку SHALL открывать окно поверх ленты по адресу `/app/wiki/pages/{code}/versions/{version}?project=<метка>`
|
||||
(фоновая страница остаётся под ним, закрытие — кнопкой, Escape или «назад» — возвращает ленту с тем же периодом и
|
||||
источниками). Адрес окна, открытый напрямую (перезагрузка, ссылка), показывает окно поверх страницы «Вики» с этой
|
||||
страницей (`/app/wiki?project=<метка>&page=<код>`); закрытие оставляет её. Окно показывает: название и путь страницы, «правка N из M»,
|
||||
автора, время, «+A / −R» и дифф правки (`GET /wiki/pages/{code}/diff` с `version`): строки, добавленные и удалённые, —
|
||||
цветами состояния успеха и ошибки из токенов темы с подписью для экранных читалок, строки `@@` — второстепенным цветом,
|
||||
моноширинным шрифтом, без горизонтальной прокрутки страницы (длинная строка переносится или прокручивается внутри
|
||||
окна). Дифф длиннее одной части — кнопка «Показать дальше» догружает следующую (`offset = next_offset`). Кнопки
|
||||
«Предыдущая правка» и «Следующая правка» переключают версию той же страницы (по `GET /wiki/pages/{code}/versions`),
|
||||
заменяя адрес окна без новой записи истории, — «назад» по-прежнему закрывает окно; у первой и последней
|
||||
соответствующая кнопка недоступна. Ссылка «Открыть страницу» ведёт на страницу в разделе «Вики».
|
||||
Окно только показывает: в Eva и в хабе ничего не меняет.
|
||||
|
||||
Контракт веб-модуля SHALL получить необязательное поле источника ленты: ядро передаёт источнику проект, границы
|
||||
периода и признак «выбран», а источник отдаёт свои группы со временем последнего события, состояние (загрузка,
|
||||
ошибка, `truncated`, пустая история) и, при необходимости, свои настройки над лентой (виды событий Jira). Ядро MUST NOT
|
||||
знать видов событий Jira и полей правок вики (требование «Граница модулей в вебе»).
|
||||
|
||||
#### Scenario: Правка из ленты
|
||||
- **WHEN** в ленте AWPCA за сегодня группа DOC-101252 «17.2.2.1 ЭФ «Ознакомление перед подписанием»» с правкой «12:40
|
||||
Дмитрий Соснов +40 / −12»; нажата правка
|
||||
- **THEN** поверх ленты окно: «правка 4 из 4», Соснов, 12:40, «+40 / −12», дифф с подсвеченными строками; запрос
|
||||
`GET /wiki/pages/DOC-101252/diff?project=AWPCA&version=DOCH-…`
|
||||
|
||||
#### Scenario: Предыдущая правка
|
||||
- **WHEN** в окне правки 4 из 4 нажата «Предыдущая правка»
|
||||
- **THEN** показана правка 3 из 4 той же страницы; «Следующая правка» доступна; «назад» браузера закрывает окно и
|
||||
возвращает ленту
|
||||
|
||||
#### Scenario: Окно по ссылке
|
||||
- **WHEN** открыт `/app/wiki/pages/DOC-101252/versions/DOCH-3159076?project=AWPCA` в новой вкладке
|
||||
- **THEN** окно правки поверх страницы «Вики» с DOC-101252; закрытие окна — адрес `/app/wiki?project=AWPCA&page=DOC-101252`
|
||||
|
||||
#### Scenario: Длинный дифф
|
||||
- **WHEN** у правки `next_offset = 20000`
|
||||
- **THEN** под диффом кнопка «Показать дальше»; нажатие догружает часть с `offset=20000` ниже уже показанной
|
||||
|
||||
#### Scenario: История не загружена
|
||||
- **WHEN** у проекта `history_at = null`
|
||||
- **THEN** на месте правок вики — «история вики ещё не загружена — нужен eva-agent v2»
|
||||
|
||||
#### Scenario: Окно на узком экране
|
||||
- **WHEN** ширина окна 390 px, открыто окно правки с длинными строками Markdown
|
||||
- **THEN** горизонтальной прокрутки страницы нет; строки диффа переносятся или прокручиваются внутри окна
|
||||
|
||||
@ -206,3 +206,104 @@ SHALL проверить, что файл есть в `files/` и размер
|
||||
- **WHEN** у вложения 9 страницы DOC-3 имя «Схема расчёта суммы элиминации по тройке», адрес
|
||||
`…/vgo-matching-1.png?version=1`; у вложения 8 имя `attachment`, адрес `…/model.xlsx`
|
||||
- **THEN** в `GET /wiki/pages/DOC-3?project=AWPCA` у 9 `image = true`, у 8 `image = false`
|
||||
|
||||
### Requirement: История правок страниц
|
||||
Хаб SHALL хранить опубликованные версии страниц дерева проекта: код версии Eva (`DOCH-…`), код страницы, время правки
|
||||
(UTC), автора (`login`, `name`), Markdown версии и число строк, добавленных и удалённых против предыдущей версии той же
|
||||
страницы (порядок версий — по времени, затем по коду; у первой — против пустого текста). Время правки — время создания
|
||||
версии в Eva (`cmf_created_at`). Версии страниц, которых нет в дереве проекта, хаб MUST NOT хранить; неопубликованные
|
||||
версии (черновики) агент MUST NOT присылать.
|
||||
|
||||
При выдаче `wiki_sync` хаб SHALL дописывать в параметры команды `known_versions` — объект `{<код страницы>: [<код
|
||||
версии>…]}` по версиям, уже хранящимся у страниц текущей копии проекта (без копии — `{}`); в `command.params` в базе
|
||||
поле MUST NOT записываться. Агент `wiki` SHALL после страниц прислать опубликованные версии страниц дерева, которых нет
|
||||
в `known_versions` их страницы, пачками `POST /agent/wiki/versions {command_id, versions}`: версия — `{page_code, code,
|
||||
created_at, author: {login, name}, html, attachments, links}` (`created_at` — ISO-8601 со смещением; `login` и `name`
|
||||
— строки или `null`, если Eva автора не отдала; `attachments` и `links` — как у страниц, по `html` версии), в пачке не
|
||||
больше 50 версий, — и отчитаться `done` с `result.versions` —
|
||||
числом присланных версий. Пачка по команде не в `claimed` или не `wiki_sync` — 409; неверная форма версии — 422
|
||||
`bad_versions` с кодом версии и полем. Хаб SHALL переводить HTML версии в Markdown при приёме вне транзакции записи
|
||||
(ссылки на вложения — текстом `📎 <имя>` без ссылки, ссылки на страницы — `page:<код>`) и складывать в стадию команды.
|
||||
|
||||
По отчёту `done` с `result.versions` хаб SHALL в той же операции, что и копию (см. «Синхронизация вики»): добавить
|
||||
версии из стадии к страницам, чьи коды есть в `codes`, отбросив остальные; удалить версии страниц, которых нет в
|
||||
`codes`; посчитать «+/−» у новых версий и у версии, следующей за вставленной раньше неё; записать время применения
|
||||
истории `history_at`. Присланных версий меньше `result.versions` — команда `failed` «нет версий: пришло N из M», копия и
|
||||
история прежние. Отчёт `done` без `result.versions` (агент без истории) SHALL обновлять копию как прежде и не менять
|
||||
историю и `history_at`. Отчёт `failed` и отброшенный отчёт по сменённому корню историю не меняют. Сброс корня SHALL
|
||||
удалять историю проекта вместе с копией. Стадия версий очищается так же, как стадия страниц.
|
||||
|
||||
#### Scenario: Первая загрузка истории
|
||||
- **WHEN** у `AWPCA` дерево DOC-1, DOC-2; в хабе версий нет; выдан `wiki_sync`
|
||||
- **THEN** в параметрах выдачи `known_versions = {}`; агент прислал 3 версии DOC-1 и 2 версии DOC-2, отчёт `done
|
||||
{versions: 5}`; в хабе 5 версий, у первой версии каждой страницы «+N / −0», `history_at` заполнен
|
||||
|
||||
#### Scenario: Догрузка новых версий
|
||||
- **WHEN** у DOC-1 в хабе версии DOCH-10, DOCH-11; в Eva опубликована DOCH-12
|
||||
- **THEN** при выдаче `known_versions = {"DOC-1": ["DOCH-10", "DOCH-11"], …}`; агент прислал только DOCH-12; у неё
|
||||
«+/−» против DOCH-11
|
||||
|
||||
#### Scenario: Агент без истории
|
||||
- **WHEN** агент v1 отчитался `done {root_title, codes, eva_calls}` без `versions`
|
||||
- **THEN** копия обновлена, версии и `history_at` прежние
|
||||
|
||||
#### Scenario: Страница ушла из дерева
|
||||
- **WHEN** у DOC-3 в хабе 4 версии; новая синхронизация вернула `codes` без DOC-3
|
||||
- **THEN** версий DOC-3 в хабе нет
|
||||
|
||||
#### Scenario: Версия чужой страницы
|
||||
- **WHEN** в стадии версия с `page_code = DOC-99`, которой нет в `codes`
|
||||
- **THEN** версия не записана, команда `done`
|
||||
|
||||
#### Scenario: Потерянная пачка версий
|
||||
- **WHEN** отчёт `done {versions: 5}`, в стадии 3 версии
|
||||
- **THEN** команда `failed` «нет версий: пришло 3 из 5», копия и история прежние
|
||||
|
||||
### Requirement: Маршруты истории вики
|
||||
Хаб SHALL предоставлять под клиентским токеном (проект — `project=<метка>`, неизвестный — 404, без корня — 409
|
||||
`no_root`), читая только базу хаба:
|
||||
- `GET /wiki/changes?project=&since=&until=&author=&limit=` — правки страниц текущей копии проекта со временем в
|
||||
`[since, until]`. `since`, `until` — ISO-8601 со смещением или `Z` (без смещения — 422); без `until` — текущее время;
|
||||
без `since` — `until` минус 24 часа; `author` — подстрока имени или логина без учёта регистра; `limit` — по умолчанию
|
||||
500, 1–2000. Ответ — `{since, until, synced_at, history_at, truncated, changes: [{at, page_code, title, path,
|
||||
version, author: {login, name}, added, removed}]}` по `at` по убыванию, затем по `version` по убыванию; правок больше
|
||||
`limit` — первые `limit` и `truncated = true`. Неверное время, `since` позже `until`, `limit` вне 1..2000 — 422
|
||||
`bad_request` с именем параметра. `history_at = null` — история проекта ещё не загружалась.
|
||||
- `GET /wiki/pages/{code}/versions?project=` — `{code, title, versions: [{version, at, author: {login, name}, added,
|
||||
removed}]}`, новые первыми; страницы нет в копии — 404.
|
||||
- `GET /wiki/pages/{code}/diff?project=&version=&offset=` — правка `version` (без параметра — последняя) против
|
||||
предыдущей версии страницы: `{code, title, path, version, prev_version, at, author: {login, name}, added, removed,
|
||||
index, total, offset, next_offset, diff}`, где `diff` — unified diff Markdown (контекст 3 строки; у первой версии —
|
||||
против пустого, `prev_version = null`) с символа `offset` до 20 000 символов, `next_offset` — начало следующей части
|
||||
или `null`, `index` — номер версии от старой (с 1), `total` — число версий. Страницы нет в копии — 404; версии нет у
|
||||
страницы — 404 `no_version`; у страницы нет версий — 404 `no_versions`.
|
||||
|
||||
`GET /wiki/pages/{code}` SHALL дополнительно отдавать `modified_at`, `modified_by: {login, name}` (последняя версия;
|
||||
нет версий — `null`) и `versions` — число версий. `GET /wiki/status` SHALL дополнительно отдавать `history_at`.
|
||||
|
||||
#### Scenario: Что сделали за сегодня
|
||||
- **WHEN** у `AWPCA` 27.10 в 17:59 и 18:02 (MSK) Соснов опубликовал версии DOC-101252, 26.10 Молчанов — версию DOC-2;
|
||||
`GET /wiki/changes?project=AWPCA&since=2026-10-27T00:00:00+03:00`
|
||||
- **THEN** две правки DOC-101252, новая первой, у каждой автор `{login: "sosnov-dvi@rshbeco.ru", name: "Дмитрий
|
||||
Соснов"}`, `added`/`removed`, путь страницы в дереве; правки DOC-2 нет
|
||||
|
||||
#### Scenario: Фильтр по автору
|
||||
- **WHEN** `GET /wiki/changes?project=AWPCA&since=…&author=соснов`
|
||||
- **THEN** только правки Соснова
|
||||
|
||||
#### Scenario: Дифф последней правки
|
||||
- **WHEN** у DOC-101252 4 версии; `GET /wiki/pages/DOC-101252/diff?project=AWPCA`
|
||||
- **THEN** `index = 4`, `total = 4`, `prev_version` — третья версия, `diff` начинается с `--- ` и `+++ `
|
||||
|
||||
#### Scenario: Длинный дифф
|
||||
- **WHEN** дифф правки 45 000 символов, запрос без `offset`
|
||||
- **THEN** первые 20 000 символов, `next_offset = 20000`; запрос с `offset=40000` — остаток, `next_offset = null`
|
||||
|
||||
#### Scenario: История ещё не загружена
|
||||
- **WHEN** у `AWPCA` копия есть, агент v1, `GET /wiki/changes?project=AWPCA`
|
||||
- **THEN** 200, `history_at = null`, `changes = []`
|
||||
|
||||
#### Scenario: Последняя правка в странице
|
||||
- **WHEN** в хабе 4 версии DOC-101252, последняя — Соснов, `created_at = 2026-10-27T23:48:02+03:00`;
|
||||
`GET /wiki/pages/DOC-101252?project=AWPCA`
|
||||
- **THEN** `modified_at = "2026-10-27T20:48:02+00:00"`, `modified_by.name = "Дмитрий Соснов"`, `versions = 4`
|
||||
|
||||
Loading…
x
Reference in New Issue
Block a user