Andrey Epifancev 6a2d8b7f5e spec(web-modules): веб под модули — состояние модулей, «Обзор», адреса модулей
Change web-modules по аудиту веба 24.10.2026 (#98).

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
2026-10-24 15:38:46 +04:00

113 lines
8.7 KiB
Markdown
Raw Blame History

This file contains ambiguous Unicode characters

This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.

## MODIFIED Requirements
### Requirement: Раздача веб-приложения
Хаб SHALL отдавать собранное веб-приложение (спека `web-app`) из каталога пакета `src/sdlc_hub/web/app/`, читая файлы
с диска на каждый запрос:
- `GET /app/assets/<путь>` — файл из `assets/` сборки; путь, который после разрешения выходит за `assets/`, не
существует или содержит нулевой байт, — 404; `Content-Type` по расширению (`.js` — `text/javascript; charset=utf-8`, `.css` —
`text/css; charset=utf-8`, `.svg` — `image/svg+xml`, `.png` — `image/png`, `.ico` — `image/x-icon`, `.woff2` —
`font/woff2`, `.map` — `application/json`, прочее — `application/octet-stream`);
`Cache-Control: public, max-age=31536000, immutable`;
- любой другой `GET /app` или `GET /app/…` — `index.html` сборки, `text/html; charset=utf-8`, `Cache-Control: no-cache`;
- если `index.html` сборки нет — на любой `GET /app…` 503 `text/html; charset=utf-8` с текстом, что приложение не
собрано и нужно выполнить `make web` в каталоге sdlc-hub;
- `GET /` и `GET /links` — 302 с `Location: /app/` (главная страница приложения — «Обзор»).
Сборка приложения не хранится в git; её создаёт `make web`.
#### Scenario: Файл сборки
- **WHEN** в сборке есть `assets/index-abc123.js`, запрошен `GET /app/assets/index-abc123.js`
- **THEN** 200, `Content-Type: text/javascript; charset=utf-8`, `Cache-Control` с `immutable`, тело — содержимое файла
#### Scenario: Путь приложения
- **WHEN** запрошен `GET /app/issues/AURORA-1620`
- **THEN** 200, тело — `index.html` сборки, `Cache-Control: no-cache`
#### Scenario: Выход за каталог сборки
- **WHEN** запрошен `GET /app/assets/../../api.py` (в том числе в виде `%2e%2e`)
- **THEN** 404, содержимое файлов вне `assets/` не отдаётся
#### Scenario: Приложение не собрано
- **WHEN** каталога сборки нет, запрошен `GET /app/board`
- **THEN** 503, тело — HTML с подсказкой `make web`
#### Scenario: Старый адрес доски
- **WHEN** запрошен `GET /links` или `GET /`
- **THEN** 302, `Location: /app/`
#### Scenario: Нулевой байт в пути
- **WHEN** запрошен `GET /app/assets/%00` или `GET /app/assets/a%00.js`
- **THEN** 404 `not_found`, а не 500
### Requirement: Маршруты проектов
Хаб SHALL предоставлять под клиентским токеном:
- `GET /projects` → список проектов по `created_at`, затем `label`; каждый — плоский объект из полей ядра (`label`,
`name`, `created_at`) и полей всех модулей (`modules`, «Поля проекта от модулей»). Модуль jira даёт `board_id`,
`board_type`, `issues_count` (задачи зеркала с меткой проекта), `jira_synced_at` (время завершения последнего полного
обновления зеркала, общее для всех проектов; `null`, если его не было), модуль wiki — `wiki_root`, `wiki_root_title`,
`wiki_pages`, `wiki_synced_at`, `wiki_sync_error`.
- `POST /projects` `{label, name, author?, <поля модулей>}` → 201 `{project, batch_id, batches}`: в одной транзакции
проект записывается, модули записывают свои поля и ставят свои пакеты; `batches` — список `{module, id}` всех
поставленных пакетов в порядке модулей; `batch_id` — пакет первого модуля, вернувшего пакет (у jira — «Новый проект <метка>» из одного `refresh` по базовой JQL, уже включающей новую метку). Автор пакетов —
`author` (по умолчанию `api`). Неизвестное поле, неверные поля ядра (см. `data-model`, «Проекты») или модуля — 422 с
указанием поля; метка, совпадающая с существующей без учёта регистра, — 409. При ошибке ни проекта, ни пакетов нет.
- `PATCH /projects/{label}` `{<изменяемые поля модулей>, author?}` → 200 `{project, batch_ids, batches}`: модули правят
свои поля и ставят пакеты в одной транзакции; `batches` — список `{module, id}`. Неизменяемое поле (метка, название, `board_id`) — 422 «<поле> после создания не
меняется»; неизвестное поле или неверное значение — 422 с указанием поля; проекта нет — 404.
#### Scenario: Новый проект
- **WHEN** `POST /projects {label: "STOCKS_DRRK", name: "Запасы ДРРК", board_id: 5120, author: "viewer"}`, есть проект `AWPCA`
- **THEN** 201; `GET /projects` отдаёт два проекта, у `STOCKS_DRRK` `board_type = null`, `wiki_root = null`; в очереди
пакет автора `viewer` с `refresh {jql: 'project = AURORA AND labels in ("AWPCA", "STOCKS_DRRK")'}`
#### Scenario: Проект без доски
- **WHEN** `POST /projects {label: "STOCKS_DRRK", name: "Запасы ДРРК"}`
- **THEN** 201, `board_id = null`
#### Scenario: Проект с корнем вики
- **WHEN** `POST /projects {label: "STOCKS_DRRK", name: "Запасы ДРРК", wiki_root: "DOC-001234"}`
- **THEN** 201; в очереди пакет `refresh` и пакет `wiki_sync {label: "STOCKS_DRRK", root: "DOC-001234"}`; `batch_id` —
пакет `refresh`; `batches` — `[{module: "jira", id: <refresh>}, {module: "wiki", id: <wiki_sync>}]`
#### Scenario: Повтор метки
- **WHEN** `POST /projects {label: "AWPCA", name: "…"}`, проект `AWPCA` есть
- **THEN** 409, пакет не поставлен
#### Scenario: Без названия
- **WHEN** `POST /projects {label: "STOCKS_DRRK", name: " "}`
- **THEN** 422 с указанием поля `name`
#### Scenario: Неизвестное поле
- **WHEN** `POST /projects {label: "X", name: "X", board: 5}`
- **THEN** 422 с указанием поля `board`, проекта нет
#### Scenario: Корень вики у существующего проекта
- **WHEN** `PATCH /projects/AWPCA {wiki_root: "DOC-000777"}`
- **THEN** 200, `batch_ids` — один пакет `wiki_sync`, `batches` — `[{module: "wiki", id: <он же>}]`; `GET /projects` отдаёт `AWPCA` с `wiki_root = DOC-000777`
#### Scenario: Доску не меняют
- **WHEN** `PATCH /projects/AWPCA {board_id: 1}`
- **THEN** 422 «board_id после создания не меняется», доска прежняя
#### Scenario: Свежесть Jira в проекте
- **WHEN** последний полный пакет `refresh` завершён в 11:07, `GET /projects`
- **THEN** у каждого проекта `jira_synced_at` — это время; до первого полного обновления — `null`
## ADDED Requirements
### Requirement: Модуль пакета
`GET /batches` и `GET /batches/{id}` SHALL отдавать у пакета поле `module` — имя модуля, которому принадлежит тип первой
команды пакета (по описаниям модулей в реестре); пакет без команд или с типом, которого не знает ни один модуль, —
`module = null`. Фильтр `GET /batches?module=<имя>` SHALL отдавать только пакеты модуля; неизвестный модуль — 404.
#### Scenario: Модуль у пакетов
- **WHEN** в очереди пакет «Автообновление» (`refresh`, автор `hub`) и пакет `wiki_sync` проекта `AWPCA`; `GET /batches`
- **THEN** у первого `module = "jira"`, у второго `module = "wiki"`
#### Scenario: Фильтр по модулю
- **WHEN** `GET /batches?module=wiki&project=AWPCA`
- **THEN** только пакеты модуля wiki проекта `AWPCA`
#### Scenario: Неизвестный модуль
- **WHEN** `GET /batches?module=nope`
- **THEN** 404