89 lines
11 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.

## Context
`main` 9f4bb75. Устройство, на которое опираются правки:
- **Настройки** — `src/jira_hub/settings.py`: `DEFAULTS` (ключ → значение по умолчанию), `ensure_defaults` при открытии
базы добавляет недостающие ключи (`INSERT OR IGNORE`), `validate` проверяет тип по значению по умолчанию,
`AGENT_KEYS` — что уходит агенту. `GET /settings` отдаёт всё, кроме токенов.
- **Список на сервере** — `api.ISSUE_FILTERS` → `mirror.list_issues(conn, filters, limit, offset)`: `_FILTERS`
(точное совпадение по колонке) плюс отдельные ветки для `label`, `neighbor`, `q`.
- **Список в приложении** — `web/src/issues/IssuesPage.tsx`: фильтры из query-строки по `ISSUE_FILTER_NAMES`
(`web/src/api/queries.ts`), все уходят в `GET /issues` как есть; `SELECTS` — выпадающие списки, варианты —
`filterOptions` (`web/src/issues/options.ts`), «только соседи» — флажок `neighbor=1`. Порции по 50 (`useIssues`).
- **Доска** — `web/src/board/`: модель из `GET /board` / CSV / JSON → видимая выборка (`analysis/visible.ts`, `VisNode`
с `dim` — сосед, класс карточки `out`) → `BoardCanvas` → `Card.tsx` (класс `card`, `out`, `crit`, `focus`) и
`Edges.tsx` (`<path>` на каждую связь). Настройки — `useSettings()` в `BoardPage.tsx`, словари — `dicts.ts`.
Golden-тесты сравнивают модель, выборку, критический путь и проблемы с `links.html@3931a88`.
- **Карточка** — `web/src/issues/IssueCard.tsx`: шапка с бейджем статуса по факту (`factClass` по `status_labels`),
«просрочено» — `isOverdue(due, fact, statusLabels, today)` (`card.ts`, R-2 #37). `Notes.tsx` — строки заметки,
`NoteForm.tsx` — форма, поле `fact_status` с подсказками из `status_labels`; сохраняются только изменённые поля.
- **Живые данные** (17.10.2026): закрытые статусы AURORA — «Готово» и «Снято»; `transitions_map` и `status_labels`
в настройках ключуются статусами по факту — это касается будущего полного удаления, не этой задачи.
## Goals / Non-Goals
**Goals:** в списке по умолчанию только незакрытые задачи, закрытые — одним флажком; на доске закрытые не отвлекают, но
связи через них видны; «статуса по факту» в веб-приложении нет.
**Non-Goals:** см. proposal.md.
## Decisions
1. **Набор закрытых статусов — настройка хаба `closed_statuses`**, список строк, по умолчанию `["Готово", "Снято"]`.
Приложение по правилу «Справочники из настроек хаба» своих копий словарей не держит, а сервер нужен для фильтра
списка. В `DEFAULTS`, поэтому на живом хабе ключ появится при первом открытии базы после выкатки (`ensure_defaults`);
тип проверяет `validate` (список). В `AGENT_KEYS` не входит. Сравнение — точное совпадение строки статуса.
2. **Фильтр списка — на сервере:** `GET /issues?hide_closed=1` добавляет условие `i.status IS NULL OR i.status NOT IN
(…closed_statuses)` (задача без статуса — не закрыта). Клиентский фильтр поверх порций по 50 ломал бы «Показать
ещё» (порция могла бы прийти пустой). Значение `1` / `true` — включено, иное или отсутствие — выключено (как
`neighbor`). Пустой `closed_statuses` — фильтр ничего не скрывает.
3. **Адрес списка:** по умолчанию закрытые скрыты, в адресе ничего нет; снятый флажок «скрыть закрытые» — `closed=1`.
Приложение отправляет `hide_closed=1`, пока `closed` не `1`. `closed` — параметр приложения, в `GET /issues` не
уходит. Флажок — рядом с «только соседи».
4. **Явный выбор статуса сильнее флажка:** если в фильтре «Статус Jira» выбран статус из `closed_statuses`,
`hide_closed` не отправляется — иначе выборка всегда пуста. Флажок при этом остаётся как есть.
5. **Доска:** признак закрытости вычисляется при отрисовке, а не в модели — модель, выборка, критический путь и
проблемы остаются как у `links.html` (golden-тесты не трогаются). Карточка получает класс `closed`
(`opacity: .4`), под указателем и с фокусом внутри — полная яркость (`.card.closed:hover`, `.card.closed:focus-within`;
признак `VisNode.focus` нигде не включается, выделения карточек на доске нет). Стрелка, у которой хотя бы один конец —
закрытая задача, — класс/атрибут с той же прозрачностью. Сосед (`out`) и закрытая — признаки независимые, вместе
— оба стиля. Набор закрытых — из `useSettings()`; карточки из CSV и JSON приглушаются по тому же правилу (статус у
них есть).
6. **Нет `closed_statuses` в настройках** (хаб старее приложения) — ничего не считается закрытым: список без фильтра,
доска без приглушения, ошибки «нет словаря» нет. Хаб и приложение выкатываются вместе, это окно короткое.
7. **«Просрочено» в карточке** — по статусу Jira: срок раньше сегодня и статус не из `closed_statuses` (было — по
классу статуса по факту, R-2 #37). Без статуса по факту прежнее правило не на чем считать.
8. **«Статус по факту» из приложения:** убрать из `ISSUE_FILTER_NAMES` и `SELECTS`, колонку таблицы, вариант из
`filterOptions`, бейдж в шапке карточки (`factClass`, стили `.badge.fact*`), строку в `Notes.tsx`, поле и подсказки
в `NoteForm.tsx`. Тип `NoteFields` / `NOTE_FIELDS` приложения — без `fact_status`; так форма не может отправить его
и в `PUT` значение не трогается. Тип ответа API (`IssueRow.fact_status`, `Note.fact_status`) — поле остаётся
необязательным, приложение его не читает. Старый адрес с `fact_status=` — параметр игнорируется (нет в
`ISSUE_FILTER_NAMES`).
## Risks / Trade-offs
- Новый статус Jira закрытого смысла (например, «Отклонено») не будет скрыт, пока его не добавят в `closed_statuses`
— осознанно: владелец назвал ровно два статуса.
- Пока хаб не перезапущен после выкатки, сборка приложения новее хаба: `hide_closed` хаб старой версии игнорирует, и
список покажет закрытые — безвредно.
## Decisions made without discussion
- 2026-10-17 — **набор закрытых статусов в настройке хаба `closed_statuses`**, а не константой в коде. Обоснование:
правило «Справочники из настроек хаба», фильтр нужен и серверу, и приложению. Цена ошибки: лишний ключ настроек;
убрать — правка `DEFAULTS` и двух мест чтения.
- 2026-10-17 — **фильтр `hide_closed` на сервере**, а не в браузере. Обоснование: порции по 50. Цена ошибки: один
параметр API; поведение MCP не меняется.
- 2026-10-17 — **адрес: `closed=1` — показать закрытые; по умолчанию параметра нет.** Обоснование: умолчание владельца
«скрыты», адрес без лишних параметров. Цена ошибки: переименование параметра.
- 2026-10-17 — **выбранный в «Статус Jira» закрытый статус отменяет скрытие.** Обоснование: иначе выборка всегда пуста.
Цена ошибки: поведение одного сочетания фильтров.
- 2026-10-17 — **приглушение: `opacity .4`, полная яркость под указателем и с фокусом клавиатуры внутри; стрелки — если закрыт хотя бы один
конец.** Обоснование: владелец подтвердил «связи тоже бледнеют»; степень прозрачности — на глаз, отличается от
соседа (`.7`, пунктир). Цена ошибки: правка CSS.
- 2026-10-17 — **без `closed_statuses` — ничего не закрыто, без сообщения об ошибке.** Обоснование: это не словарь
подписей, без него страница работает как раньше. Цена ошибки: нет.
- 2026-10-17 — **«просрочено» — по статусу Jira из `closed_statuses`.** Обоснование: статус по факту из приложения
убран. Цена ошибки: пометка «просрочено» у задачи, закрытой по факту, но не в Jira, — теперь видна (это и есть
статус Jira).