## MODIFIED Requirements ### Requirement: Процесс и доступ `jira-hub serve` SHALL запускать один процесс: HTTP на `0.0.0.0:` (по умолчанию 8790), база и настройки в `~/.local/share/jira-hub/` (переопределяется `JIRA_HUB_HOME`). Все маршруты API SHALL требовать `Authorization: Bearer `: агентский токен открывает только `/agent/*`, клиентский — всё остальное. Исключение — раздача веб-приложения (`GET /app`, `GET /app/…`) и перенаправления `GET /`, `GET /links`: это статические файлы без данных, они отдаются без токена. Ответы API — JSON, ошибки — `{error, detail}` с кодами 400 (неверное тело или `Content-Length`), 401, 404, 409, 413 (тело больше предела), 422, 500 (внутренняя ошибка); реле общей папки дополнительно отвечает 502. Методы, кроме GET, POST и PUT, отвечают 501 стандартной страницей `http.server`, не JSON. #### Scenario: Чужой токен - **WHEN** агентским токеном вызван `GET /issues` - **THEN** 401 #### Scenario: Неподдерживаемый метод - **WHEN** `DELETE /issues/AURORA-1` - **THEN** 501, тело не JSON; база не меняется #### Scenario: Страница без токена - **WHEN** `GET /app/board` без заголовка `Authorization`, сборка приложения есть - **THEN** 200, `Content-Type: text/html; charset=utf-8`, тело — `index.html` сборки; данных зеркала в нём нет ## ADDED Requirements ### Requirement: Раздача веб-приложения Хаб SHALL отдавать собранное веб-приложение (спека `web-app`) из каталога пакета `src/jira_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` в каталоге jira-hub; - `GET /` и `GET /links` — 302 с `Location: /app/board`. Сборка приложения не хранится в 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/board` ## REMOVED Requirements ### Requirement: Страница доски связей **Reason**: страница `links.html` заменена страницей «Доска» веб-приложения (спека `web-app`, требование «Доска связей»); поведение перенесено без изменений, кроме закрытых недочётов jira-hub#20 и действия «Открыть карточку». **Migration**: `GET /` и `GET /links` перенаправляют на `/app/board`; токен (`jira-hub-token`) и раскладки (`graph-<имя>…`) в `localStorage` читаются приложением под теми же ключами.