chore(openspec): archive fix-trash-counter-sync and sync main specs
This commit is contained in:
@@ -0,0 +1,2 @@
|
||||
schema: spec-driven
|
||||
created: 2026-10-12
|
||||
@@ -0,0 +1,61 @@
|
||||
# Design
|
||||
|
||||
## Context
|
||||
|
||||
См. `proposal.md` — Why. Существенное:
|
||||
|
||||
- `TrashStore` (`frontend/src/lib/stores/trash.svelte.ts`) держит `count` и умеет `load()`
|
||||
(запрос `GET /api/trash/count`) и `reset()`.
|
||||
- `AlbumRail.svelte` показывает `trash.count` и вызывает `trash.load()` только в `$effect`
|
||||
при смене `$page.url.pathname` и при аутентификации.
|
||||
- `trash/+page.svelte` вызывает `trash.load()` только в `emptyAll`; `restore`,
|
||||
`confirmRestore`, `remove` (окончательное удаление) обновляют лишь свой список.
|
||||
- Удаление фото разбросано: `deleteBatch` в сетке и панели, прямой `api(...DELETE)` в
|
||||
просмотре; удаление альбома — в `AlbumActionsDialogs` и `settings/+page.svelte`.
|
||||
- Серверный `TrashCount` считает мягко удалённые фото, доступные пользователю, и корректен.
|
||||
|
||||
## Goals / Non-Goals
|
||||
|
||||
**Goals:**
|
||||
- Счётчик корзины в рейле отражает актуальное состояние после любой операции, меняющей
|
||||
содержимое корзины, без перезагрузки.
|
||||
- Единообразный, предсказуемый способ обновления во всех точках.
|
||||
|
||||
**Non-Goals:**
|
||||
- Синхронизация счётчика между сессиями/устройствами (SSE-событий корзины нет).
|
||||
- Изменения backend и Android.
|
||||
- Оптимистичные локальные инкременты без сверки с сервером.
|
||||
|
||||
## Decisions
|
||||
|
||||
### 1. Обновлять счётчик из сервера (`trash.load()`), а не инкрементировать локально
|
||||
После каждой успешной мутации вызываем `trash.load()`. Это даёт точное значение для всех
|
||||
случаев, включая пакетное удаление и удаление альбома (где число фото заранее неизвестно
|
||||
точно), и повторяет уже принятый в `emptyAll` паттерн. Альтернатива с оптимистичным
|
||||
`+n`/`-1` требует знать точное число и расходится при частичных ошибках; альтернатива с
|
||||
общим сигналом (как `photo-updates`) добавляет лишний слой ради одного значения.
|
||||
|
||||
### 2. Вызывать обновление в каждой точке мутации, после успешного await
|
||||
Обновление идёт после успешного ответа (в `try`, не в `finally`), чтобы при ошибке
|
||||
счётчик не менялся. Точки: пакетное удаление (сетка), удаление из панели/просмотра,
|
||||
удаление в просмотре, восстановление и окончательное удаление в корзине, удаление
|
||||
альбома (диалог и настройки). Это устраняет исходный дефект и родственные рассинхроны
|
||||
той же природы.
|
||||
|
||||
### 3. Оставить асинхронность неблокирующей
|
||||
`trash.load()` уже глотает ошибки и не мешает основному действию; вызов не await-им
|
||||
блокирующе там, где это меняет UX (в остальных местах допустимо `await` для
|
||||
детерминизма тестов). Достаточно, чтобы счётчик обновился к моменту отрисовки.
|
||||
|
||||
## Risks / Trade-offs
|
||||
|
||||
- [Лишний `GET /api/trash/count` на каждую мутацию] → незначительная нагрузка, сопоставимо
|
||||
с текущим поведением при навигации и очистке корзины.
|
||||
- [Гонка при параллельных мутациях] → последний ответ сервера побеждает; значение
|
||||
остаётся корректным, т.к. берётся из источника истины.
|
||||
- [Разброс точек вызова — риск пропустить новую в будущем] → спека фиксирует инвариант;
|
||||
при добавлении новых операций с корзиной требование распространяется на них.
|
||||
|
||||
## Migration Plan
|
||||
|
||||
Не требуется: изменения только во фронтенде, без изменения API и данных.
|
||||
@@ -0,0 +1,42 @@
|
||||
# Proposal
|
||||
|
||||
## Why
|
||||
|
||||
Счётчик корзины в рейле альбомов (`trash.count`) перезагружается только при смене
|
||||
маршрута и после «Очистить корзину». Любая другая операция, меняющая содержимое корзины,
|
||||
не обновляет его: после удаления фото счётчик остаётся прежним, пока пользователь не
|
||||
перейдёт в другой раздел. Это и есть сообщённый дефект — «при удалении фото на корзине не
|
||||
меняется счётчик».
|
||||
|
||||
## What Changes
|
||||
|
||||
- Рейл SHALL обновлять число элементов корзины сразу после каждого действия, меняющего её
|
||||
содержимое, без перезагрузки страницы: помещение фото в корзину (одиночное и пакетное),
|
||||
восстановление, окончательное удаление, очистка корзины и удаление альбома (его фото
|
||||
уходят в корзину).
|
||||
- Изменения только во фронтенде: серверный `GET /api/trash/count` и семантика мягкого
|
||||
удаления корректны и не меняются.
|
||||
|
||||
## Capabilities
|
||||
|
||||
### New Capabilities
|
||||
|
||||
Нет.
|
||||
|
||||
### Modified Capabilities
|
||||
|
||||
- `ui-workspace`: добавляется требование синхронизации счётчика корзины в рейле с
|
||||
операциями, меняющими содержимое корзины, без перезагрузки страницы.
|
||||
|
||||
## Impact
|
||||
|
||||
- Frontend: `frontend/src/lib/stores/trash.svelte.ts` (способ обновления счётчика),
|
||||
`frontend/src/routes/(app)/albums/[id]/+page.svelte` (пакетное удаление),
|
||||
`frontend/src/lib/components/PhotoPanel.svelte` (удаление из панели/просмотра),
|
||||
`frontend/src/routes/(app)/albums/[id]/photos/[photoId]/+page.svelte` (удаление в
|
||||
просмотре), `frontend/src/routes/(app)/trash/+page.svelte` (восстановление и
|
||||
окончательное удаление), `frontend/src/lib/components/AlbumActionsDialogs.svelte` и
|
||||
`frontend/src/routes/(app)/albums/[id]/settings/+page.svelte` (удаление альбома).
|
||||
- Backend: не затрагивается.
|
||||
- Вне объёма: синхронизация счётчика между сессиями/устройствами через SSE (событий корзины
|
||||
сервер не публикует) и Android-клиент (корзины в нём нет).
|
||||
@@ -0,0 +1,24 @@
|
||||
# Spec Delta
|
||||
|
||||
## ADDED Requirements
|
||||
|
||||
### Requirement: Синхронизация счётчика корзины
|
||||
Рейл SHALL обновлять число элементов корзины сразу после любого действия, меняющего
|
||||
содержимое корзины, без перезагрузки страницы: помещения фото в корзину, восстановления,
|
||||
окончательного удаления и удаления альбома с фото.
|
||||
|
||||
#### Scenario: Помещение фото в корзину
|
||||
- **WHEN** пользователь удаляет одно или несколько фото
|
||||
- **THEN** фото покидают сетку, а число элементов корзины в рейле увеличивается на их количество
|
||||
|
||||
#### Scenario: Восстановление из корзины
|
||||
- **WHEN** пользователь восстанавливает фото из корзины
|
||||
- **THEN** фото покидает список корзины, а число элементов корзины в рейле уменьшается на единицу
|
||||
|
||||
#### Scenario: Окончательное удаление
|
||||
- **WHEN** пользователь окончательно удаляет фото из корзины
|
||||
- **THEN** число элементов корзины в рейле уменьшается на единицу
|
||||
|
||||
#### Scenario: Удаление альбома
|
||||
- **WHEN** пользователь удаляет альбом с фото
|
||||
- **THEN** его фото попадают в корзину, а число элементов корзины в рейле увеличивается на их количество
|
||||
@@ -0,0 +1,23 @@
|
||||
# Tasks
|
||||
|
||||
## 1. Счётчик после удаления фото
|
||||
|
||||
- [x] 1.1 Обновлять `trash.load()` после пакетного удаления в сетке (`routes/(app)/albums/[id]/+page.svelte`, `confirmMenuDelete`) — проверить вручную: удаление одного и нескольких фото увеличивает счётчик корзины в рейле без перехода между разделами
|
||||
- [x] 1.2 Обновлять `trash.load()` после удаления из панели (`lib/components/PhotoPanel.svelte`, `confirmDelete`) и в просмотре (`routes/(app)/albums/[id]/photos/[photoId]/+page.svelte`, `confirmDelete`) — проверить оба сценария вручную
|
||||
|
||||
## 2. Счётчик при удалении альбома
|
||||
|
||||
- [x] 2.1 Обновлять `trash.load()` после удаления альбома (`lib/components/AlbumActionsDialogs.svelte` после `albums.destroy` и `routes/(app)/albums/[id]/settings/+page.svelte` после DELETE) — проверить вручную: удаление альбома с фото увеличивает счётчик на число фото
|
||||
|
||||
## 3. Восстановление и окончательное удаление
|
||||
|
||||
- [x] 3.1 В `routes/(app)/trash/+page.svelte` обновлять `trash.load()` после `restore`, `confirmRestore` и `remove` — проверить вручную: восстановление и окончательное удаление уменьшают счётчик корзины
|
||||
|
||||
## 4. Проверка
|
||||
|
||||
- [x] 4.1 `cd frontend && npm run check` проходит без ошибок
|
||||
- [x] 4.2 Ручной чек-лист сквозного сценария: удаление фото (одно/несколько), удаление из просмотра, удаление альбома, восстановление, окончательное удаление, очистка корзины — счётчик в рейле всегда актуален без перезагрузки страницы
|
||||
|
||||
## Workflow follow-up
|
||||
|
||||
- Архивировать изменение после ревью и синхронизировать основную спеку `ui-workspace`.
|
||||
Reference in New Issue
Block a user