Files
jellybit/openspec/changes/archive/2026-07-04-htmx-action-swap/proposal.md
T
avandClaude Opus 4.8 576fc4e6c0 OpenSpec: влить дельты htmx-action-swap в спеки, архив change
Sync новых требований в openspec/specs/: web-ui («Действия обновляют
интерфейс на месте») и review («Петлевые действия ревью обновляют экран на
месте»). Change перемещён в changes/archive/2026-07-04-htmx-action-swap.
Конвенция web-ui.md актуализирована: сняты маркеры «будем» по реализованному.

Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
2026-07-04 14:42:06 +03:00

74 lines
6.1 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.
## Why
Сейчас действия над загрузкой (откат, привязать заново, распознать заново,
уточнить, применить и т.д.) — это POST-формы с PRG-редиректом: после действия
браузер уходит на другую страницу и теряет контекст. Откат со страницы
загрузки `/download/{id}` и из карточки списка одинаково выкидывает на `/`, а
перераспознавание на `/review/{id}` перезагружает страницу с прыжком скролла
наверх. Пользователь хочет оставаться там, где действовал: действие со списка —
остаёшься в списке, со страницы загрузки/ревью — остаёшься на ней.
## What Changes
- Мутирующие UI-действия выполняются через **htmx-swap на месте** вместо
server-side PRG-редиректа: сервер отвечает обновлённым HTML-фрагментом той
области, которую затронуло действие, htmx подменяет её в DOM без навигации.
Паттерн уже применяется в `reviewBlockAction` (выбор источника) — расширяем
его на остальные действия.
- **Карточка в списке** (`/`): действия `undo`, `relink`, `retry`, `cancel`
подменяют карточку (`<article class="card">`) на месте — обновлённое
состояние, бейдж и набор кнопок. Фильтр/поиск/пагинация/прокрутка не
сбрасываются.
- **Страница загрузки** (`/download/{id}`): те же действия обновляют содержимое
страницы на месте (без перехода и без прыжка скролла), отражая новое
состояние.
- **Страница ревью** (`/review/{id}`): **петлевые** действия распознавания —
`rerecognize`, `refine` (и уже работающий выбор источника) — обновляют экран
на месте (без перезагрузки и прыжка скролла). Так как они асинхронны (переводят
загрузку в `recognizing`), своп отдаёт состояние `recognizing`, а экран сам
**допалливает** готовый план htmx-фрагментом (`GET /fragments/downloads/{id}/review`,
по образцу `progress`/`seeding`) и автоматически сменяется на план по
завершении — без ручного обновления. **Выходы** из ревью (`apply` → done,
`defer` → deferred, `cancel` → cancelled) уводят с экрана (загрузка покидает
ревью), поэтому остаются навигацией/редиректом. Отдельная кнопка
перераспознавания на `/download/{id}` НЕ добавляется — ревью считается частью
«страницы загрузки», действие остаётся в ревью-потоке.
- **Деградация без JS сохраняется**: формы остаются обычными POST; при
отсутствии htmx (нет заголовка `HX-Request`) сервер отвечает прежним
PRG-редиректом, поведение не ломается.
- **Ошибки действий** показываются на месте (в подменённом фрагменте), а не
только через `?err=` после редиректа.
Новых зависимостей нет: Alpine.js/SPA не вводятся, стек остаётся htmx-first
(см. решение `2026-06-30-web-ui-design-port`).
## Capabilities
### New Capabilities
<!-- Нет новых capability — меняется поведение существующих. -->
### Modified Capabilities
- `web-ui`: действия над карточкой/страницей загрузки выполняются htmx-swap'ом
фрагмента на месте (без навигации и сброса контекста списка), с graceful
degradation на PRG-редирект без htmx.
- `review`: петлевые действия ревью (`rerecognize`, `refine`) обновляют экран
на месте htmx-свопом, не перезагружая страницу и не сбрасывая прокрутку;
выходы из ревью (`apply`/`defer`/`cancel`) остаются навигацией.
## Impact
- **Код**: `internal/httpapi` — обработчики действий (`review.go`,
`httpapi.go`): вместо `redirect*` отвечать фрагментом (HTTP 200) при
`HX-Request`, сохранив редирект-ветку; извлечь `buildCardView`/
`buildDownloadView`; новый fragment-эндпоинт `handleFragReview` для
авто-поллинга recognizing (`live.go`).
- **Шаблоны** (`web/templates`): выделить переиспользуемые фрагменты —
карточка списка (в партиал), «главная область» страницы загрузки, тело
ревью; проставить `hx-post`/`hx-target`/`hx-swap` на формы действий, скрытое
поле `surface`, поллер на блок `recognizing`.
- **Зависимости**: без изменений (htmx уже вендорится).
- **Тесты**: обработчики действий — проверка ветвления `HX-Request`
фрагмент vs редирект.
- **Вне scope**: живой поллинг телеметрии (`live-status`) не трогаем;
клиентских фреймворков не добавляем.