spec: add quiet user feedback change and sync canonical specs
Part of the quiet-user-feedback change; frontend and docs land in their own repositories.
This commit is contained in:
@@ -25,6 +25,7 @@ types. CI каждого участника использует только е
|
|||||||
| Каталог компонентов | [UI catalog](openspec/specs/frontend-ui-catalog/spec.md) |
|
| Каталог компонентов | [UI catalog](openspec/specs/frontend-ui-catalog/spec.md) |
|
||||||
| Loading/skeleton | [Loading presentation](openspec/specs/frontend-loading-presentation/spec.md) |
|
| Loading/skeleton | [Loading presentation](openspec/specs/frontend-loading-presentation/spec.md) |
|
||||||
| UI error/recovery | [UI resilience](openspec/specs/frontend-ui-resilience/spec.md) |
|
| UI error/recovery | [UI resilience](openspec/specs/frontend-ui-resilience/spec.md) |
|
||||||
|
| Тихое чтение и редкие уведомления | [User feedback](openspec/specs/frontend-user-feedback/spec.md) |
|
||||||
| Query coherence/cache | [Query coherence](openspec/specs/frontend-query-coherence/spec.md), [data resilience](openspec/specs/frontend-data-resilience/spec.md) |
|
| Query coherence/cache | [Query coherence](openspec/specs/frontend-query-coherence/spec.md), [data resilience](openspec/specs/frontend-data-resilience/spec.md) |
|
||||||
| OpenAPI generation | [API contract generation](openspec/specs/api-contract-generation/spec.md) |
|
| OpenAPI generation | [API contract generation](openspec/specs/api-contract-generation/spec.md) |
|
||||||
| Logging/request context | [Structured logging](openspec/specs/backend-structured-logging/spec.md) |
|
| Logging/request context | [Structured logging](openspec/specs/backend-structured-logging/spec.md) |
|
||||||
|
|||||||
@@ -0,0 +1,2 @@
|
|||||||
|
schema: wealth-ledger-sdd
|
||||||
|
created: 2026-10-04
|
||||||
@@ -0,0 +1,424 @@
|
|||||||
|
## Context
|
||||||
|
|
||||||
|
Frontend уже разделяет получение данных, page VM и presentation. TanStack
|
||||||
|
Query хранит успешные результаты; инвестиционные ресурсы дополнительно
|
||||||
|
возвращают `data` и `meta` с полнотой, свежестью и состоянием источника.
|
||||||
|
`useResourceQuery` сохраняет общую query identity обычного чтения и наблюдения,
|
||||||
|
а `useScreenSync` наблюдает известную работу и предоставляет ручные действия.
|
||||||
|
На счетах и портфеле используются `InvestmentRefreshState` и
|
||||||
|
`SourceSyncStatus`; сходные элементы встроены в остальные finance views.
|
||||||
|
|
||||||
|
Сейчас query retries и focus refetch отключены, ошибка status GET прекращает
|
||||||
|
наблюдение, а `observe()` также запрещает retry. В банковских формах отдельно
|
||||||
|
существуют технические повторы загрузки справочников и перечитывание записи
|
||||||
|
после конфликта версий. Это разные случаи: удаление всех обработчиков с именем
|
||||||
|
`retry` или `onReload` без сохранения их ответственности недопустимо.
|
||||||
|
|
||||||
|
Предоставленный frontend OpenAPI уже содержит обычное чтение ресурсов,
|
||||||
|
`sync=observe`, status GET и принудительный screen refresh. Дополнительная
|
||||||
|
сверка реализации показала: обычное чтение запрашивает missing/stale источники,
|
||||||
|
свежие полные источники переиспользуются, существующая running work объединяется.
|
||||||
|
Принудительный refresh обходит freshness и охватывает зависимости экрана.
|
||||||
|
Поэтому он не подходит для автоматического восстановления обычного чтения.
|
||||||
|
|
||||||
|
Основные specs текущего store отстают от части реализованной синхронизации.
|
||||||
|
Есть пересечение с active change `persist-tbank-data`; его старые UI-требования
|
||||||
|
не используются как новая норма поверх согласованных quiet Delta Specs.
|
||||||
|
Это различие учитывается в порядке согласования требований ниже.
|
||||||
|
|
||||||
|
## Goals / Non-Goals
|
||||||
|
|
||||||
|
**Goals:**
|
||||||
|
|
||||||
|
- Сосредоточить transport recovery в существующем query layer, а восстановление
|
||||||
|
инвестиционной работы — у существующего владельца `useScreenSync`.
|
||||||
|
- Упростить presentation interface: view получает готовое содержимое,
|
||||||
|
недоступность или необходимое пользовательское действие, а не набор
|
||||||
|
технических статусов и callbacks повторной загрузки.
|
||||||
|
- Сохранить один финансовый кэш, действующую отмену запросов, границы доступа
|
||||||
|
и точные серверные финансовые результаты.
|
||||||
|
- Встроить редкие уведомления в существующие Mantine theme и i18n.
|
||||||
|
|
||||||
|
**Non-Goals:**
|
||||||
|
|
||||||
|
- Новый query client, offline-хранилище, event bus или универсальный scheduler.
|
||||||
|
- Автоматическое повторение мутаций, изменение auth refresh или правил
|
||||||
|
разрешения конфликтов пользовательских данных.
|
||||||
|
- Новые endpoints, удаление существующего refresh endpoint, изменение DTO,
|
||||||
|
серверных TTL, алгоритмов расчёта или схемы хранения.
|
||||||
|
- Переработка композиции финансовых страниц и диаграмм.
|
||||||
|
|
||||||
|
## Decisions
|
||||||
|
|
||||||
|
### 1. Два владельца восстановления вместо одного глобального retry
|
||||||
|
|
||||||
|
`shared/api` владеет классификацией transport errors, ограниченным retry и
|
||||||
|
deadline application GET. Существующие authenticated query hooks применяют
|
||||||
|
общую политику к чтению карт, справочников и статуса подключения. Auth bootstrap
|
||||||
|
и пользовательские mutations сохраняют текущую отдельную политику.
|
||||||
|
|
||||||
|
`useResourceQuery` использует тот же transport recovery, но жизненный цикл
|
||||||
|
инвестиционной работы остаётся в `features/tbank-connection`. `useScreenSync`
|
||||||
|
становится автоматической orchestration текущего экрана: его callers больше
|
||||||
|
не передают `refresh`/`retry` в UI. Page VM продолжает владеть смыслом готовности
|
||||||
|
конкретного результата, выбранными параметрами и доступными действиями.
|
||||||
|
|
||||||
|
Альтернативы: глобальный retry всех запросов и mutations нарушает границы
|
||||||
|
записи и доступа; независимые timers каждой страницы размножают политику.
|
||||||
|
Собственный универсальный recovery service дублирует Query lifecycle.
|
||||||
|
|
||||||
|
### 2. Конечная transport policy
|
||||||
|
|
||||||
|
Для application GET принимаются следующие параметры:
|
||||||
|
|
||||||
|
| Параметр | Решение |
|
||||||
|
| --- | --- |
|
||||||
|
| HTTP deadline | 15 секунд на попытку, включая чтение тела ответа |
|
||||||
|
| Автоматические повторы | Не более двух после исходного запроса |
|
||||||
|
| Паузы | 1 и 2 секунды; серия не перезапускается от render |
|
||||||
|
| Временные ошибки | Подтверждённая transport/network failure, timeout, HTTP 408, 500, 502, 503, 504, `TBANK_UNAVAILABLE` |
|
||||||
|
| Не повторять | Отмена, ошибки ввода, 401/403/404, известные access/domain failures, 409, неизвестный постоянный исход |
|
||||||
|
| Rate limiting | 429 не повторяется короткой серией без доступного корректного `Retry-After`; наличие серверной отсрочки исключает более ранний повтор |
|
||||||
|
| Новая серия | Новый актуальный запрос, возвращение сети или возвращение пользователя на экран |
|
||||||
|
|
||||||
|
Классификация использует существующие `ApiErrorCode` и структурированный
|
||||||
|
Problem Details status, с приоритетом отказа доступа над общим HTTP status.
|
||||||
|
Отсутствие известного code само по себе не означает временную ошибку.
|
||||||
|
Transport failure маркируется там, где выполняется GET: ошибка render,
|
||||||
|
`select` или преобразования данных не превращается в network failure.
|
||||||
|
Если `Retry-After` используется, его transport metadata сохраняется локально
|
||||||
|
в ошибке клиента, без нового поля публичного DTO.
|
||||||
|
|
||||||
|
Deadline применяется только к application GET, не к auth endpoints и не к
|
||||||
|
mutations. Сигнал Query объединяется с сигналом timeout; исходная отмена
|
||||||
|
сохраняет причину и не повторяется. Существующий единственный auth refresh
|
||||||
|
не дублируется query retry. Восстановление GET после исчерпанного auth refresh
|
||||||
|
не допускается до восстановления сессии.
|
||||||
|
|
||||||
|
Для обычных authenticated reads применяются штатные Query focus/reconnect
|
||||||
|
events и текущие entity `staleTime`. На инвестиционных ресурсах обработка этих
|
||||||
|
событий координируется `useScreenSync`: параллельный автоматический refetch
|
||||||
|
тех же ресурсов из второго владельца выключен. Lifecycle события берутся
|
||||||
|
из Query focus/online managers, без второго набора browser listeners.
|
||||||
|
|
||||||
|
Уход последнего consumer отменяет запрос и его retries через существующий
|
||||||
|
AbortSignal. Imperative чтение, начатое screen owner, также прекращается
|
||||||
|
при его cleanup, если у запроса не осталось других активных consumers.
|
||||||
|
|
||||||
|
### 3. Восстановление источника — обычным GET, наблюдение — только observe
|
||||||
|
|
||||||
|
Для инвестиционного ресурса разделяются три ситуации:
|
||||||
|
|
||||||
|
| Ситуация | Действие владельца |
|
||||||
|
| --- | --- |
|
||||||
|
| Не получен HTTP-ответ | Ограниченный transport retry того же режима чтения |
|
||||||
|
| Известна running work | Status GET и чтение проекции с `sync=observe` |
|
||||||
|
| Необходимые данные missing/stale, а work failed/cancelled либо отсутствует | Ограниченный повтор обычного GET ресурса без `sync=observe` |
|
||||||
|
|
||||||
|
Успешный HTTP `200` с `data: null` или `sync.state: failed` не считается
|
||||||
|
успешным восстановлением источника. Источники определяются из `meta` и
|
||||||
|
`meta.dependencies`; `unavailableReason` и предметные ограничения не считаются
|
||||||
|
временным сбоем. Неудачная прежняя принудительная сверка уже полного свежего
|
||||||
|
результата не запускается заново только ради удаления её внутреннего статуса.
|
||||||
|
|
||||||
|
После terminal source failure допускаются две повторные обычные загрузки
|
||||||
|
нуждающегося в данных ресурса: через 5 и 15 секунд после соответствующего
|
||||||
|
неуспеха. Бюджет относится к активации текущей выборки, а не к ID очередной
|
||||||
|
серверной попытки. Новый ID работы, успешное чтение failed metadata и повторный
|
||||||
|
render не обнуляют бюджет. После его исчерпания следующий запуск возможен
|
||||||
|
при новом lifecycle событии восстановления или выборе новой выборки.
|
||||||
|
|
||||||
|
Transport retry и source recovery не вкладываются бесконтрольно: следующая
|
||||||
|
source attempt начинается только после завершения предыдущего GET и его
|
||||||
|
transport retries. Для одной серии это не более трёх обычных загрузок ресурса,
|
||||||
|
каждая не более чем с тремя HTTP-попытками. Наблюдение running work не является
|
||||||
|
новой source attempt и никогда не вызывает принудительный POST refresh.
|
||||||
|
|
||||||
|
Status observation сохраняет существующий интервал 1 секунда при активном
|
||||||
|
экране и известной running work. Повторный tick не отменяет выполняющееся
|
||||||
|
чтение или его retry. После terminal status выполняется заключительное
|
||||||
|
observe-чтение; если другое чтение ещё идёт, заключительное выполняется после
|
||||||
|
него, а не теряется. После ухода, потери сессии или terminal status периодический
|
||||||
|
опрос соответствующей работы прекращается. В скрытой вкладке и offline
|
||||||
|
новые циклы приостанавливаются; возвращение возобновляет актуальную работу.
|
||||||
|
|
||||||
|
`404` status ID не означает автоматически потерю доступа ко всем счетам:
|
||||||
|
ресурс перечитывается по действующему адресу, где проверяется текущий доступ.
|
||||||
|
Подтверждённые access errors ресурса либо статуса подключения сохраняют
|
||||||
|
существующую invalidation личных данных. Коды отказа из metadata также не
|
||||||
|
должны маскироваться успешным HTTP-ответом.
|
||||||
|
|
||||||
|
Обычное чтение и observe остаются в одной generated query identity. Внутри
|
||||||
|
владельца режим запроса задаётся явно; observe не оставляет постоянный
|
||||||
|
observe-only queryFn для последующего обычного восстановления. При чтении
|
||||||
|
проверяется фактическое in-flight состояние Query, а не только снимок props.
|
||||||
|
Повторный event не создаёт второй запрос того же key. Переход на новую выборку
|
||||||
|
отменяет старые timers и не позволяет late response менять новую область.
|
||||||
|
|
||||||
|
### 4. UI readiness отдельно от query status
|
||||||
|
|
||||||
|
Page VM выбирает presentation в следующем порядке:
|
||||||
|
|
||||||
|
1. Подтверждённый access failure: скрытые личные данные и необходимое действие.
|
||||||
|
2. Доступный результат текущей выборки: loaded, partial или подтверждённый empty.
|
||||||
|
3. Отсутствие результата: первоначальный skeleton либо unavailable.
|
||||||
|
|
||||||
|
Loaded view не получает `isFetching`, время получения и callbacks технического
|
||||||
|
повтора. Технические metadata остаются у data owner для восстановления и
|
||||||
|
определения полноты. Не вводится второй кэш успешных финансовых payload.
|
||||||
|
|
||||||
|
Первичное ожидание области ограничивается 10 секундами. Ошибка завершившегося
|
||||||
|
получения или истечение этого срока переводит её в unavailable. Это UI budget,
|
||||||
|
а не отмена полезной source work: поздний успешный результат заменяет состояние
|
||||||
|
автоматически. Одна общая небольшая presentation-функция/hook в `shared/lib`
|
||||||
|
владеет временем ожидания и latch unavailable для identity области. Она
|
||||||
|
не выполняет запросы, не знает T-Bank и не копирует финансовые данные.
|
||||||
|
Page VM передаёт readiness и identity; смена выборки сбрасывает ожидание,
|
||||||
|
очередная попытка той же выборки не вызывает мигание skeleton.
|
||||||
|
|
||||||
|
Доступность проверяется явно, а не через truthiness суммы. `data: []` и полный
|
||||||
|
пустой Portfolio — успешные результаты; `data: null` не равен пустому результату.
|
||||||
|
Для неполных totals/comparisons выводится `—` с доступной подписью
|
||||||
|
«Итог пока недоступен»/«Сравнение пока недоступно». Для неполного списка
|
||||||
|
допустима подпись «Показана часть операций», без статуса синхронизации.
|
||||||
|
|
||||||
|
Ключи loaded containers не зависят от `isFetching`, revision или времени ответа.
|
||||||
|
Фильтры, локальные раскрытия, формы и focus сохраняют существующих владельцев.
|
||||||
|
В банковской пагинации прежняя страница не используется как placeholder новой:
|
||||||
|
текущий `placeholderData`, допускающий иной page, убирается для этого перехода.
|
||||||
|
Сохранение данных при refetch той же страницы обеспечивается самим Query.
|
||||||
|
|
||||||
|
`InvestmentRefreshState` и `SourceSyncStatus` удаляются вместе с их callers
|
||||||
|
и ненужными presentation props. Общие `StateView` и page skeleton переиспользуются;
|
||||||
|
нейтральная недоступность не требует нового компонента-обёртки. Ошибки форм,
|
||||||
|
валидация и сообщения, объясняющие финансовый смысл, не удаляются поиском строк.
|
||||||
|
|
||||||
|
### 5. Формы и конфликты сохраняют самостоятельное подтверждение
|
||||||
|
|
||||||
|
Запросы категорий, исходной покупки возврата и текущей версии записи получают
|
||||||
|
обычную политику чтения. Временный refetch не очищает ранее доступные варианты
|
||||||
|
и ввод. Когда необходимые данные отсутствуют, соответствующее сохранение
|
||||||
|
недоступно; отмена и выход из формы остаются доступны.
|
||||||
|
|
||||||
|
После `BANK_VERSION_CONFLICT` или аналогичного предметного конфликта существующая
|
||||||
|
invalidation автоматически получает актуальную запись. VM использует этот
|
||||||
|
результат вместо отдельной кнопки перечитывания. Пользователь по-прежнему
|
||||||
|
видит конфликт, сохраняет ввод и явно принимает новую версию перед повторным
|
||||||
|
сохранением или удалением. Фоновый ответ не принимает версию за него.
|
||||||
|
Пока новая версия неизвестна, повтор опасной записи заблокирован, но форма
|
||||||
|
не находится в бесконечном submit и допускает закрытие.
|
||||||
|
|
||||||
|
Создание и правка карт/операций, удаление, категории и изменение подключения
|
||||||
|
сохраняют `retry: false`, version и существующие intent IDs. Общая read policy
|
||||||
|
не означает автоматического повторения неуспешной записи.
|
||||||
|
|
||||||
|
### 6. Mantine Notifications с явным владельцем сообщения
|
||||||
|
|
||||||
|
Используется `@mantine/notifications` **9.6.1**, согласованный с установленными
|
||||||
|
`@mantine/core` и `@mantine/hooks` 9.6.1. Registry подтверждает эту версию и
|
||||||
|
peer requirements React/React DOM `^19.2.0`, совместимые с manifest проекта.
|
||||||
|
Стили пакета подключаются после Mantine core; один `Notifications` host
|
||||||
|
находится в application composition под MantineProvider.
|
||||||
|
|
||||||
|
Параметры: `limit=2`, `autoClose=4000`, desktop `bottom-right`, narrow viewport
|
||||||
|
`bottom-center`; видимая кнопка закрытия имеет русское доступное имя. Сообщение
|
||||||
|
не получает отдельный заголовок «Успех» и не переносит focus. Текст принадлежит
|
||||||
|
существующему i18n; имя пользователя, token и необработанный error в него не входят.
|
||||||
|
Очередь очищается при завершении или смене пользовательской сессии.
|
||||||
|
|
||||||
|
Уведомление вызывается из одного обработчика успешного действия в его VM,
|
||||||
|
не из `useEffect` по `isSuccess` и не из глобального query/mutation interceptor.
|
||||||
|
ID относится к выполнению действия, а не к названию операции вообще. Повторное
|
||||||
|
завершение того же выполнения подавляется у владельца и получает тот же ID;
|
||||||
|
следующее отдельное действие имеет новый ID. Не создаётся постоянный журнал
|
||||||
|
показанных сообщений.
|
||||||
|
|
||||||
|
Решение о необходимости подтверждения принадлежит VM, знающей оставшийся
|
||||||
|
экран. Критерий проверяется по фактически видимой выборке, а не по одному
|
||||||
|
наличию успешного HTTP-ответа:
|
||||||
|
|
||||||
|
| Действие и оставшийся контекст | Обратная связь |
|
||||||
|
| --- | --- |
|
||||||
|
| Созданная/изменённая карта или операция видна в обновлённом списке | Содержимое подтверждает результат, toast отсутствует |
|
||||||
|
| Успешная операция не видна из-за периода, страницы, фильтра или другого счёта | Одно «Операция сохранена» после закрытия формы |
|
||||||
|
| Удалённая запись исчезла из видимого списка | Toast отсутствует |
|
||||||
|
| Запись удалена, но оставшийся экран не отражает её исчезновение | Одно «Операция удалена» |
|
||||||
|
| Создание/удаление подключения меняет видимый статус | Toast отсутствует |
|
||||||
|
| Замена token при прежнем статусе «Подключён» | Одно «Подключение обновлено» |
|
||||||
|
| Категория появилась или изменена в открытом списке/поле | Toast отсутствует |
|
||||||
|
| Сохранение успешно, но связанное чтение не подтвердило результат на экране | Краткое подтверждение сохранения без сообщения о сбое чтения |
|
||||||
|
|
||||||
|
VM получает outcome связанного обновления от существующего владельца
|
||||||
|
invalidation; её решение о подтверждении выполняется один раз для action ID.
|
||||||
|
Успех записи отделён от успеха последующего GET: ошибка чтения не становится
|
||||||
|
ошибкой сохранения и не предлагает повторить уже выполненную запись.
|
||||||
|
Получение видимого подтверждения ограничено тем же 10-секундным UI budget;
|
||||||
|
после него при отсутствии подтверждения используется одно уведомление.
|
||||||
|
Отдельный глобальный наблюдатель mutation results для этого не вводится.
|
||||||
|
|
||||||
|
Альтернатива `react-toastify` добавляет вторую визуальную систему без нужной
|
||||||
|
дополнительной функции. Собственный toast из Mantine `Notification` потребовал
|
||||||
|
бы обслуживать очередь, timers и доступность; готовый пакет дешевле.
|
||||||
|
|
||||||
|
## UI/UX Applicability and Package
|
||||||
|
|
||||||
|
**Applicability and scope:** `new/changed` — меняются feedback и состояния
|
||||||
|
существующих экранов, а не их финансовая композиция.
|
||||||
|
|
||||||
|
**Package revision:** `quiet-user-feedback-ui-v1`.
|
||||||
|
|
||||||
|
Пакет полностью inline. Отдельные PNG/SVG не нужны: новая геометрия страниц,
|
||||||
|
иллюстрации и визуализация финансовых данных не вводятся. Следующие описания
|
||||||
|
и схемы входят в единое Design approval.
|
||||||
|
|
||||||
|
**Screens, states and interactions:**
|
||||||
|
|
||||||
|
| Область | Loaded / background failure | Нет результата | Действия |
|
||||||
|
| --- | --- | --- | --- |
|
||||||
|
| Счета, портфель, режим всех счетов | Заголовок сразу переходит в карточки и содержимое; строки синхронизации отсутствуют | Page-owned skeleton → нейтральная недоступность | Открыть счёт, перейти в раздел, настроить отсутствующее подключение |
|
||||||
|
| Операции, доход, события | Фильтры и доступный результат сохраняются; даты событий остаются | Недоступность только текущей выборки или расчёта | Применить/сбросить фильтры, сменить страницу, навигация |
|
||||||
|
| Поиск и детали инструментов | Поиск, график и доступные секции без технических controls | Незагруженная секция сохраняет свой заголовок и локальное состояние | Поиск, выбор инструмента и диапазона |
|
||||||
|
| Карты, сводки и история | Данные и пользовательские controls сохраняются | Локальная недоступность без ложного нулевого остатка | Добавить/изменить, фильтры, страницы |
|
||||||
|
| Настройки подключения | Статус и введённый token сохраняются при временном сбое чтения | Нет формы до первого подтверждённого статуса | Подключить/заменить/отключить после получения статуса |
|
||||||
|
| Формы и подтверждения удаления | Локальное ожидание явного действия; ошибки у владельца | Недоступность нужного справочника или актуальной версии | Сохранить/отменить; явное принятие новой версии при конфликте |
|
||||||
|
|
||||||
|
Схема loaded портфеля:
|
||||||
|
|
||||||
|
```text
|
||||||
|
Счета / Основной счёт
|
||||||
|
Основной счёт
|
||||||
|
|
||||||
|
[ ₽ 125 000,50 ] [ $ 320,00 ]
|
||||||
|
Структура портфеля
|
||||||
|
Позиции / Деньги / Последние операции / Доход
|
||||||
|
```
|
||||||
|
|
||||||
|
Между заголовком и содержимым нет зарезервированного места под удалённые
|
||||||
|
кнопки, даты и баннеры. Temporary refetch failure имеет тот же вид, что loaded.
|
||||||
|
|
||||||
|
Схема локальной недоступности:
|
||||||
|
|
||||||
|
```text
|
||||||
|
Получено купонами и дивидендами
|
||||||
|
Пока недоступно
|
||||||
|
|
||||||
|
Открыть пассивный доход →
|
||||||
|
```
|
||||||
|
|
||||||
|
Ссылка присутствует только там, где у блока уже есть предметная навигация.
|
||||||
|
Нет дополнительного «Попробуйте позже», countdown или обещания завершения.
|
||||||
|
Для основной страницы сохраняются shell и существующие пути навигации.
|
||||||
|
Нейтральное состояние — читаемый текст, не warning/error Alert. Символ `—`
|
||||||
|
для отсутствующей суммы всегда имеет доступное объяснение.
|
||||||
|
|
||||||
|
Схема редкого подтверждения:
|
||||||
|
|
||||||
|
```text
|
||||||
|
Операция сохранена ×
|
||||||
|
```
|
||||||
|
|
||||||
|
Нотификация объявляется ненавязчиво, не закрывает modal, не переводит фокус
|
||||||
|
и не является единственным носителем ошибки или необходимого действия.
|
||||||
|
При отображении над формой учитывается её focus trap; закрытие уведомления
|
||||||
|
не отбирает доступ к кнопкам формы. Повторные фоновые попытки не создают
|
||||||
|
live-announcements. Skeleton busy остаётся только у реально ожидающей области.
|
||||||
|
|
||||||
|
**Responsive behavior:** существующие layout и semantic tokens сохраняются.
|
||||||
|
При ширине 320–767 px нейтральные состояния занимают ширину области; toast
|
||||||
|
располагается снизу по центру с отступами и учётом safe area, без горизонтального
|
||||||
|
скролла. От 768 px — справа снизу. Сообщения переносятся, кнопка закрытия
|
||||||
|
остаётся доступной. Контейнер уведомлений не блокирует pointer events вне
|
||||||
|
самих сообщений и не перекрывает единственный путь к основным controls.
|
||||||
|
Появление учитывает reduced motion.
|
||||||
|
|
||||||
|
**Reused source and differences:** формального reuse чужого SDD UI package нет.
|
||||||
|
Применяются текущие Mantine theme, `StateView` и page-owned skeleton; их
|
||||||
|
ответственность сохраняется. Отдельная новая theme или макет неизменяемых
|
||||||
|
финансовых секций не создаются.
|
||||||
|
|
||||||
|
## Delivery Map
|
||||||
|
|
||||||
|
| Area | Status | Architectural outcome or N/A reason |
|
||||||
|
| --- | --- | --- |
|
||||||
|
| frontend | `affected` | Query recovery, автоматическое наблюдение ресурсов, упрощённые VM/views, сохранение form conflict flow, Mantine Notifications, согласованные UI/data conventions и каталог состояний |
|
||||||
|
| backend | `N/A` | Существующие обычные GET, observe и server-side work deduplication достаточны; DTO, force endpoint, TTL, хранение и серверные повторы не меняются |
|
||||||
|
| specs | `affected` | Согласованные Delta Specs заменяют старые UI/retry obligations; новое правило feedback входит в canonical specs и индекс; пересечение с persist lifecycle разрешается без переписывания чужого active change |
|
||||||
|
| docs | `affected` | As-built объяснение тихой загрузки, восстановления и уведомлений заменяет описание ручного refresh в UI resilience, data freshness и затронутых предметных страницах; принятое сквозное решение фиксируется в журнале ADR |
|
||||||
|
|
||||||
|
## Solution Assessment
|
||||||
|
|
||||||
|
Обязательный trigger — изменение общей политики caching/recovery и
|
||||||
|
координации concurrent reads; дополнительно выбирается общий механизм уведомлений.
|
||||||
|
|
||||||
|
| Вариант | Fit и зрелость | Security и ограничения | Operating / migration cost | Решение |
|
||||||
|
| --- | --- | --- | --- | --- |
|
||||||
|
| Существующий TanStack Query + текущие resource/screen owners | Уже владеет cache, retry, cancellation, focus/online events; domain metadata остаётся отдельной | Сохраняет session cancellation; требует отличать read failure от failed work и запретить retries mutations | Без новой runtime-инфраструктуры; изменения сосредоточены в существующих owners | Выбран |
|
||||||
|
| Новый scheduler или state-machine runtime | Потребовал бы повторить текущий query lifecycle | Добавляет второе состояние и риск late-response/cache рассогласования | Новая dependency и миграция всех consumers без текущей необходимости | Отклонён |
|
||||||
|
| Периодический force refresh | Не соответствует ограниченному recovery текущих missing/stale данных | Повторяет внешнюю работу и игнорирует freshness | Лишние RPC и нагрузка; усложняет rate limiting | Отклонён |
|
||||||
|
| Mantine Notifications 9.6.1 | Зрелый companion текущей UI-системы; очередь, lifecycle, responsive position | Только доверенные локализованные тексты, без HTML/error payload | Один согласованный пакет; нет нового сервиса или отдельной темы | Выбран |
|
||||||
|
| React-Toastify | Зрелый самостоятельный механизм, но дополнительная функция не нужна | Потребует отдельно согласовывать styling и accessibility | Вторая UI-интеграция и её поддержка | Отклонён |
|
||||||
|
| Собственная очередь над Mantine Notification | Встроенный primitive есть, готовой очереди в core нет | Собственные timers, focus/live-region и cleanup повышают риск | Собственный код дороже готового companion | Отклонён |
|
||||||
|
|
||||||
|
Выбор опирается на текущие исходники и публичную документацию
|
||||||
|
[Query retries](https://tanstack.com/query/latest/docs/framework/react/guides/query-retries),
|
||||||
|
[Query cancellation](https://tanstack.com/query/latest/docs/framework/react/guides/query-cancellation),
|
||||||
|
[focus refetch](https://tanstack.com/query/latest/docs/framework/react/guides/window-focus-refetching)
|
||||||
|
и [Mantine Notifications](https://mantine.dev/x/notifications/).
|
||||||
|
Документация объясняет возможности библиотек; domain recovery и UI-пакет
|
||||||
|
полностью определены здесь и не зависят от доступа к этим ссылкам.
|
||||||
|
|
||||||
|
## Risks / Trade-offs
|
||||||
|
|
||||||
|
- **Тишина не означает актуальность в реальном времени.** TTL сам не создаёт
|
||||||
|
расписание; после исчерпания recovery budget новая серия ждёт lifecycle
|
||||||
|
event. Это ограничивает нагрузку ценой возможного ожидания следующего
|
||||||
|
возвращения на экран при долгой недоступности источника.
|
||||||
|
- **Короткий UI budget и долгая история.** Через 10 секунд может появиться
|
||||||
|
«Пока недоступно», хотя работа продолжается. Готовый результат заменяет
|
||||||
|
это состояние; уже доступные области не ждут чужой истории.
|
||||||
|
- **Умножение повторов.** Transport, status polling и source recovery имеют
|
||||||
|
разных владельцев и конечные бюджеты. Новые source IDs и failed metadata
|
||||||
|
не запускают неограниченную серию.
|
||||||
|
- **Access loss важнее cached content.** Ошибки доступа проверяются до loaded
|
||||||
|
presentation. Status ID not found не смешивается с account not found.
|
||||||
|
- **Конфликт версии не является ошибкой чтения.** Автоматическое получение
|
||||||
|
новой версии не подтверждает её принятие и не повторяет запись.
|
||||||
|
- **Уведомления могут дублировать содержимое.** Решение остаётся у action VM,
|
||||||
|
где известна видимая выборка; глобальный toast на каждый success исключён.
|
||||||
|
- **Исходные ветки не равны новой canonical норме.** Существующие local
|
||||||
|
изменения переноса PortfolioStructure сохраняются; design не требует их
|
||||||
|
отката. Удалённая актуальность specs ранее не была подтверждена из-за DNS;
|
||||||
|
фактическая база поставки требует сверки перед её объединением.
|
||||||
|
|
||||||
|
## Migration Plan
|
||||||
|
|
||||||
|
1. Сохранить текущую canonical базу quiet change и порядок требований:
|
||||||
|
утверждённое quiet-поведение заменяет старые обязательства показывать
|
||||||
|
статусы и ручной retry. Технические возможности уже предоставленного API
|
||||||
|
используются без автоматического переноса всех artifacts `persist-tbank-data`.
|
||||||
|
Его последующий sync/archive не должен восстанавливать отменённые UI-правила:
|
||||||
|
пересекающийся change требует отдельного rebase и approval до своего archive.
|
||||||
|
Если он попадает в canonical specs раньше quiet, quiet deltas адаптируются
|
||||||
|
к новой базе с сохранением согласованного поведения и повторным approval
|
||||||
|
затронутых artifacts. Чужие active artifacts сейчас не переписываются.
|
||||||
|
2. Ввести recovery у существующих владельцев чтения и отделить presentation
|
||||||
|
readiness от transport status. Сохранить текущие auth/access/invalidation
|
||||||
|
semantics и различие обычного чтения и observe.
|
||||||
|
3. Перевести экраны и формы на тихую presentation, убрать ручные технические
|
||||||
|
controls и сохранить предметные conflict actions. Подключить единый host
|
||||||
|
уведомлений и явные action outcomes. Эти части выпускаются одним frontend
|
||||||
|
изменением: удаление recovery-кнопок не поставляется отдельно от замены.
|
||||||
|
4. Согласовать новые conventions и presentation states, затем обновить
|
||||||
|
as-built docs и canonical specs по принятому lifecycle. Серверный rollout
|
||||||
|
и миграция данных для этого решения не требуются.
|
||||||
|
|
||||||
|
### Rollback Contract
|
||||||
|
|
||||||
|
| Field | Decision |
|
||||||
|
| --- | --- |
|
||||||
|
| Status | `required` |
|
||||||
|
| Reason | Recovery касается сохранения личных снимков, access invalidation и взаимодействия с финансовыми mutations |
|
||||||
|
| Trigger | Новая политика показывает данные прежней границы, создаёт неконтролируемые запросы, повторяет запись или ломает восстановление без ручных controls |
|
||||||
|
| Actions | Вернуть предыдущую frontend-поставку целиком: старые query policies вместе с прежними UI recovery controls; не откатывать только автоматическое восстановление под уже тихим UI |
|
||||||
|
| Data safety | Не менять БД, серверные данные, connection revision, intent IDs и versions; не повторять пользовательские mutations для компенсации; при подозрении на неправильный показ завершить локальную сессию и очистить её кэш |
|
||||||
|
| Verification | После отката данные разделены по сессии и подключению, временный сбой имеет прежний доступный recovery path, чтение ограничено прежней политикой, сохранение и удаление требуют явного действия |
|
||||||
@@ -0,0 +1,102 @@
|
|||||||
|
## Why
|
||||||
|
|
||||||
|
Пользователь WealthLedger хочет видеть свои финансы, а не обслуживать получение
|
||||||
|
данных. Сейчас сообщения «Источник не удалось обновить», «Сохранённые данные
|
||||||
|
не изменены», время последней загрузки и действия «Обновить»/«Повторить»
|
||||||
|
перекладывают на него контроль технической работы приложения. Эти элементы
|
||||||
|
повторяются на разных экранах и отвлекают от содержимого.
|
||||||
|
|
||||||
|
Простого удаления надписей недостаточно: восстановление после временного сбоя
|
||||||
|
не должно зависеть от исчезнувшей кнопки. Нужен единый принцип:
|
||||||
|
тихое чтение и обновление, самостоятельное восстановление и понятный результат
|
||||||
|
явных действий пользователя.
|
||||||
|
|
||||||
|
## What Changes
|
||||||
|
|
||||||
|
- На экранах просмотра приложение сохраняет доступные данные при фоновом
|
||||||
|
обновлении и временном сбое, не показывает технические предупреждения,
|
||||||
|
индикаторы фоновой работы, отметки времени получения и элементы ручного
|
||||||
|
обновления или повторной загрузки. Это относится к счетам, портфелю, операциям,
|
||||||
|
доходам, событиям, инструментам, поиску, картам и чтению состояния подключения.
|
||||||
|
Те же сообщения не переносятся во всплывающие уведомления или подсказки.
|
||||||
|
- После временных сбоев приложение самостоятельно возвращается к нормальной
|
||||||
|
работе, не требуя от пользователя повторять загрузку или перезагружать страницу.
|
||||||
|
- Первичное ожидание сохраняет понятную структуру будущего содержимого. При
|
||||||
|
затянувшейся недоступности вместо бесконечной загрузки показывается спокойное
|
||||||
|
локальное состояние «Пока недоступно» без технического повтора. После
|
||||||
|
восстановления содержимое появляется автоматически. Сбой одного блока не
|
||||||
|
скрывает остальные доступные блоки.
|
||||||
|
- Отсутствие данных, подтверждённая пустота и неполный финансовый результат
|
||||||
|
остаются различимыми. Неизвестные суммы не становятся нулями, незавершённый
|
||||||
|
расчёт не выдаётся за окончательный, а незагруженный список — за отсутствие
|
||||||
|
операций. Неполнота передаётся состоянием конкретного результата без отчёта
|
||||||
|
о процессе синхронизации. Даты операций, выплат и выбранных периодов сохраняются.
|
||||||
|
- Редкие краткие уведомления подтверждают завершённые действия пользователя,
|
||||||
|
когда результат иначе легко пропустить. Очевидные изменения экрана не
|
||||||
|
сопровождаются дублирующим уведомлением. Фоновая загрузка не порождает
|
||||||
|
уведомлений об успехе или ошибке, а повтор одного события — каскад сообщений.
|
||||||
|
- Ошибки ввода и неуспешное сохранение остаются у соответствующего поля или
|
||||||
|
формы с сохранением ввода. Действия, необходимые от пользователя, например
|
||||||
|
вход или восстановление подключения, остаются понятными и доступными.
|
||||||
|
Исчезающее уведомление не является единственным сообщением о таком препятствии.
|
||||||
|
- Обновление данных не сбрасывает выбранные счёт, инструмент, период, фильтры
|
||||||
|
и не прерывает работу пользователя. Личные данные остаются доступны только
|
||||||
|
тому, кто имеет право их просматривать.
|
||||||
|
|
||||||
|
Ожидаемый результат: пользователь видит устойчивое финансовое содержимое,
|
||||||
|
не управляет загрузкой и получает обратную связь только там, где она помогает
|
||||||
|
понять результат его действия или необходимый следующий шаг.
|
||||||
|
|
||||||
|
Non-goals:
|
||||||
|
|
||||||
|
- Скрывать неуспешные изменения данных или выдавать их за сохранённые.
|
||||||
|
- Менять финансовые расчёты, валютный смысл, даты событий и правила доступа.
|
||||||
|
- Добавлять центр уведомлений, историю сообщений или уведомления вне приложения.
|
||||||
|
- Обещать актуальность данных в реальном времени.
|
||||||
|
|
||||||
|
## Capabilities
|
||||||
|
|
||||||
|
### New Capabilities
|
||||||
|
|
||||||
|
- `specs/frontend-user-feedback/spec.md`: единая политика редких уведомлений
|
||||||
|
о действиях пользователя, локальных ошибок и отсутствия технического шума
|
||||||
|
на всех экранах приложения, включая карты и инструменты.
|
||||||
|
|
||||||
|
### Modified Capabilities
|
||||||
|
|
||||||
|
- `specs/frontend-data-resilience/spec.md`: тихое сохранение доступного
|
||||||
|
результата и самостоятельное восстановление вместо предупреждений
|
||||||
|
и ручного повтора; защита границ личных данных сохраняется.
|
||||||
|
- `specs/frontend-loading-presentation/spec.md`: отсутствие индикации фонового
|
||||||
|
обновления при доступных данных и переход от первичного ожидания к устойчивому
|
||||||
|
локальному состоянию недоступности; явные действия сохраняют обратную связь.
|
||||||
|
- `specs/frontend-ui-resilience/spec.md`: ожидаемые состояния не требуют
|
||||||
|
предупреждения об устаревании и ручного повтора; навигация после
|
||||||
|
аварийной ошибки и действия восстановления доступа остаются доступными.
|
||||||
|
- `specs/brokerage-accounts/spec.md`: тихое отображение сохранённого списка,
|
||||||
|
автоматическое восстановление временных ошибок и отсутствие ручной загрузки.
|
||||||
|
- `specs/portfolio-view/spec.md`: показ портфеля без времени получения,
|
||||||
|
предупреждений об обновлении и кнопок повтора, с автоматическим восстановлением
|
||||||
|
и сохранением корректного смысла доступных финансовых значений.
|
||||||
|
- `specs/brokerage-account-ledger/spec.md`: локальное тихое восстановление
|
||||||
|
последних операций и журнала без технических действий пользователя.
|
||||||
|
- `specs/brokerage-account-upcoming-events/spec.md`: сохранение доступных событий
|
||||||
|
при временной ошибке и локальное автоматическое восстановление вместо ручного
|
||||||
|
повтора и технической ошибки блока.
|
||||||
|
- `specs/brokerage-account-income-analytics/spec.md`: локальная недоступность
|
||||||
|
незавершённого расчёта и автоматическое восстановление дохода и его сводки
|
||||||
|
без выдачи неполного результата за окончательный.
|
||||||
|
- `specs/tbank-connection/spec.md`: автоматическое восстановление чтения статуса
|
||||||
|
без кнопки повтора; ошибки создания, замены и удаления подключения сохраняют
|
||||||
|
явную обратную связь и введённые данные.
|
||||||
|
|
||||||
|
## Impact
|
||||||
|
|
||||||
|
Изменение охватывает просмотр счетов, портфеля, операций, доходов, будущих
|
||||||
|
событий, инструментов и карт, поиск и настройки подключения.
|
||||||
|
|
||||||
|
Пользователю больше не нужно следить за обновлением данных и устранять
|
||||||
|
временные сбои загрузки вручную. Интерфейс становится спокойнее, а сообщения
|
||||||
|
помогают понять результат собственного действия или необходимый следующий шаг.
|
||||||
|
Финансовый смысл данных, понятность ошибок сохранения и защита личной
|
||||||
|
информации сохраняются.
|
||||||
@@ -0,0 +1,82 @@
|
|||||||
|
## MODIFIED Requirements
|
||||||
|
|
||||||
|
### Requirement: Realized analytics never presents an incomplete result as complete
|
||||||
|
|
||||||
|
Система MUST формировать итог выбранного периода, его trend buckets,
|
||||||
|
instrument breakdown и drill-down только после успешного получения всех
|
||||||
|
необходимых cursor pages исполненных операций этого периода. Каждое comparison
|
||||||
|
MUST дополнительно требовать полного результата соответствующего периода
|
||||||
|
сравнения. Ошибка любой необходимой страницы MUST NOT возвращать частичные
|
||||||
|
totals, comparisons, buckets или
|
||||||
|
breakdown как полный результат. При временной недоступности клиент MUST
|
||||||
|
сохранять предыдущий полный результат той же выборки либо показывать
|
||||||
|
нейтральную недоступность соответствующего расчёта без технических сообщений
|
||||||
|
и ручного повтора. Восстановление SHALL выполняться автоматически по
|
||||||
|
`frontend-data-resilience`.
|
||||||
|
|
||||||
|
Доступные независимые части MUST оставаться видимыми; неполное сравнение MUST
|
||||||
|
обозначаться как недоступное без нулевой базы и окончательной разницы. Успешный
|
||||||
|
полный период без подходящих выплат MUST возвращать нулевой результат и
|
||||||
|
отображаться с объяснением пустого состояния. Неизвестный результат MUST NOT
|
||||||
|
подменяться таким нулевым результатом.
|
||||||
|
|
||||||
|
#### Scenario: Все страницы операций успешно получены
|
||||||
|
- **WHEN** для расчёта требуется несколько cursor pages и каждая страница успешно получена
|
||||||
|
- **THEN** система формирует результат по всем подходящим Ledger Entries со всех страниц
|
||||||
|
|
||||||
|
#### Scenario: Одна из страниц операций недоступна
|
||||||
|
- **WHEN** получение любой необходимой cursor page завершается временной ошибкой
|
||||||
|
- **THEN** страница сохраняет предыдущий полный результат той же выборки либо показывает нейтральную недоступность расчёта без ручного повтора и не выдаёт частичный результат за полный
|
||||||
|
|
||||||
|
#### Scenario: В периоде нет купонов и дивидендов
|
||||||
|
- **WHEN** все необходимые операции успешно получены, но среди них нет подходящих coupon или dividend Ledger Entries
|
||||||
|
- **THEN** страница показывает нулевой результат и объясняет, что за выбранный период купоны и дивиденды не найдены
|
||||||
|
|
||||||
|
#### Scenario: Основной период готов, сравнение пока нет
|
||||||
|
- **WHEN** выбранный период полностью рассчитан, а необходимый период сравнения ещё не получен
|
||||||
|
- **THEN** основной доход остаётся доступным, сравнение обозначается как недоступное без нулевой базы, частичной разницы и сообщения о синхронизации
|
||||||
|
|
||||||
|
### Requirement: Account overview has an independent current-month income summary
|
||||||
|
|
||||||
|
Обзор выбранного Brokerage Account MUST показывать компактный source-currency
|
||||||
|
summary «Получено купонами и дивидендами» за период от первого дня текущего
|
||||||
|
месяца по Europe/Moscow до сегодняшнего дня включительно и действие перехода
|
||||||
|
на страницу «Пассивный доход». Summary MUST всегда использовать этот current-month
|
||||||
|
период и MUST NOT наследовать последний пользовательский период страницы аналитики.
|
||||||
|
Пустой или неуспешный расчёт MUST оставаться локальным состоянием блока и
|
||||||
|
MUST NOT заменять успешно отображённый Portfolio или другие блоки обзора.
|
||||||
|
Временная ошибка обновления MUST сохранять доступную сводку той же выборки без
|
||||||
|
предупреждения и ручного повтора. При отсутствии результата SHALL показываться
|
||||||
|
нейтральная недоступность после первичного ожидания с автоматическим восстановлением.
|
||||||
|
|
||||||
|
#### Scenario: Обзор показывает доход текущего месяца
|
||||||
|
- **WHEN** обзор Brokerage Account загружен и current-month analytics успешно рассчитана
|
||||||
|
- **THEN** он показывает отдельные source-currency итоги с начала текущего месяца по сегодняшний день и переход к полной аналитике
|
||||||
|
|
||||||
|
#### Scenario: Пользовательский период не влияет на обзор
|
||||||
|
- **WHEN** User ранее применил на странице аналитики период, отличный от текущего месяца
|
||||||
|
- **THEN** summary обзора по-прежнему рассчитывается от первого дня текущего месяца по сегодняшний день
|
||||||
|
|
||||||
|
#### Scenario: Current-month summary недоступен
|
||||||
|
- **WHEN** Portfolio обзора успешно загружен, но расчёт current-month summary завершается временной ошибкой
|
||||||
|
- **THEN** Portfolio и остальные блоки остаются доступными, а summary сохраняет предыдущий результат той же выборки либо показывает нейтральную недоступность без ручного повтора
|
||||||
|
|
||||||
|
## ADDED Requirements
|
||||||
|
|
||||||
|
### Requirement: Доход обновляется без технических сообщений
|
||||||
|
|
||||||
|
Страница дохода MUST сохранять применённый период, черновик фильтров и
|
||||||
|
доступный результат при фоновом обновлении. Временная ошибка SHALL
|
||||||
|
восстанавливаться автоматически без кнопок обновления и повтора, времени
|
||||||
|
получения данных и уведомлений об их загрузке. Изменение периода MUST NOT
|
||||||
|
подписывать прежний результат новыми датами. Ошибки пользовательского периода
|
||||||
|
MUST оставаться у полей и MUST NOT запускать автоматический повтор ошибочного
|
||||||
|
ввода. Подтверждённая потеря доступа MUST скрывать личные результаты.
|
||||||
|
|
||||||
|
#### Scenario: Доход обновляется при редактировании периода
|
||||||
|
- **WHEN** пользователь редактирует черновик дат, а фоновое обновление применённого периода завершилось
|
||||||
|
- **THEN** черновик и фокус сохраняются, результат относится к прежнему применённому периоду и техническое уведомление не появляется
|
||||||
|
|
||||||
|
#### Scenario: Новый период пока недоступен
|
||||||
|
- **WHEN** пользователь применил другой допустимый период, но его расчёт ещё не получен
|
||||||
|
- **THEN** страница показывает ожидание или недоступность нового результата, не выдаёт прежние суммы за доход нового периода и восстанавливается автоматически
|
||||||
@@ -0,0 +1,46 @@
|
|||||||
|
## MODIFIED Requirements
|
||||||
|
|
||||||
|
### Requirement: Account overview includes recent ledger events
|
||||||
|
|
||||||
|
Обзор счёта MUST показывать пять последних исполненных записей журнала этого
|
||||||
|
счёта и действие перехода к его полному журналу. Каждая запись MUST иметь ту же
|
||||||
|
визуальную идентичность инструмента и семантику денежного движения, что и запись
|
||||||
|
полного журнала. Неуспешный или пустой запрос MUST оставаться локальным состоянием
|
||||||
|
блока и MUST NOT заменять успешно отображённый Portfolio. При временном сбое
|
||||||
|
обновления блок MUST сохранять доступные записи без технического предупреждения
|
||||||
|
или ручного повтора. При отсутствии результата он SHALL показывать первичное
|
||||||
|
ожидание либо нейтральную недоступность, автоматически восстанавливая чтение.
|
||||||
|
Неподтверждённая пустота MUST NOT представляться отсутствием операций.
|
||||||
|
|
||||||
|
#### Scenario: Отображение последних событий
|
||||||
|
- **WHEN** загружается обзор счёта и его журнал содержит исполненные операции
|
||||||
|
- **THEN** обзор показывает не более пяти последних записей и ссылку на полный журнал
|
||||||
|
|
||||||
|
#### Scenario: Последние записи недоступны
|
||||||
|
- **WHEN** обзор счёта успешно загружается, но запрос последних записей завершается временной ошибкой
|
||||||
|
- **THEN** Portfolio остаётся доступным, а блок сохраняет прежние записи либо показывает нейтральную недоступность без технического повтора и восстанавливается автоматически
|
||||||
|
|
||||||
|
#### Scenario: Последняя запись не содержит visual metadata инструмента
|
||||||
|
- **WHEN** одна из последних записей не имеет доступной presentation metadata инструмента
|
||||||
|
- **THEN** обзор показывает для неё понятный текстовый fallback и сохраняет дату, тип, инструмент и денежное изменение записи доступными для чтения
|
||||||
|
|
||||||
|
## ADDED Requirements
|
||||||
|
|
||||||
|
### Requirement: Журнал восстанавливает чтение без ручного обновления
|
||||||
|
|
||||||
|
Страница журнала SHALL сохранять записи текущей выборки при временном сбое
|
||||||
|
обновления и восстанавливать чтение автоматически по `frontend-data-resilience`.
|
||||||
|
Период, категории и выбранная страница MUST сохраняться; результат другой
|
||||||
|
выборки MUST NOT подменять текущую. Страница MUST NOT показывать время получения,
|
||||||
|
технические статусы или действия ручного повтора. Даты операций, фильтры,
|
||||||
|
действия их применения и переходы по страницам MUST оставаться доступными.
|
||||||
|
При отсутствии результата SHALL применяться первичное ожидание и нейтральная
|
||||||
|
недоступность, а не сообщение об отсутствии операций до подтверждения полноты.
|
||||||
|
|
||||||
|
#### Scenario: Обновление журнала временно не удалось
|
||||||
|
- **WHEN** для применённого периода и страницы уже есть записи, а обновление завершается временной ошибкой
|
||||||
|
- **THEN** записи и параметры просмотра сохраняются без предупреждения и кнопки повтора до автоматического восстановления
|
||||||
|
|
||||||
|
#### Scenario: Следующая страница ещё не получена
|
||||||
|
- **WHEN** пользователь перешёл к следующей странице, но её загрузка временно не удалась
|
||||||
|
- **THEN** область новой страницы показывает ожидание или нейтральную недоступность, не выдаёт прежние записи за новую страницу и восстанавливает чтение автоматически
|
||||||
@@ -0,0 +1,49 @@
|
|||||||
|
## MODIFIED Requirements
|
||||||
|
|
||||||
|
### Requirement: Account page presents an upcoming events list
|
||||||
|
|
||||||
|
Страница Brokerage Account MUST предоставлять действие перехода на отдельную
|
||||||
|
страницу «Будущие события». Эта страница MUST показывать все полученные события
|
||||||
|
компактным списком без фильтров, пагинации и суммарного итога, с датой, типом,
|
||||||
|
инструментом и прогнозной суммой в исходной валюте, если она известна. Страница
|
||||||
|
MUST объяснять, что прогноз основан на позиции счёта, указан до налогов и может
|
||||||
|
быть неполным из-за доступности данных источника. Это предметное ограничение
|
||||||
|
прогноза MUST NOT превращаться в отчёт о технической синхронизации.
|
||||||
|
|
||||||
|
При временном сбое обновления страница MUST сохранять ранее доступный результат
|
||||||
|
той же выборки без технических сообщений, времени получения и ручного повтора.
|
||||||
|
При отсутствии результата SHALL показываться первичное ожидание либо нейтральная
|
||||||
|
недоступность с автоматическим восстановлением по `frontend-data-resilience`.
|
||||||
|
Подтверждённая потеря доступа MUST скрывать личные данные независимо от наличия
|
||||||
|
сохранённого результата.
|
||||||
|
|
||||||
|
#### Scenario: Просмотр ближайших событий
|
||||||
|
- **WHEN** User открывает «Будущие события» из обзора Brokerage Account
|
||||||
|
- **THEN** он видит отсортированный список событий ближайших 30 дней, где offer обозначен без суммы
|
||||||
|
|
||||||
|
#### Scenario: Пустое состояние страницы
|
||||||
|
- **WHEN** запрос будущих событий успешно возвращает полный пустой список
|
||||||
|
- **THEN** страница сообщает, что на ближайшие 30 дней событий не найдено, и объясняет предметные ограничения покрытия источника
|
||||||
|
|
||||||
|
#### Scenario: Ошибка страницы
|
||||||
|
- **WHEN** запрос будущих событий завершается временной ошибкой
|
||||||
|
- **THEN** страница сохраняет доступный результат той же выборки либо показывает нейтральную недоступность без ручного повтора, восстанавливая чтение автоматически и не выдавая частичные данные за полный прогноз
|
||||||
|
|
||||||
|
### Requirement: Account overview includes upcoming events
|
||||||
|
|
||||||
|
Обзор Brokerage Account MUST показывать не более пяти ближайших Future Cash
|
||||||
|
Event и действие перехода на полную страницу «Будущие события». Неуспешный
|
||||||
|
или пустой запрос этого блока MUST оставаться локальным состоянием блока и
|
||||||
|
не заменять успешно отображённый Portfolio. При временном сбое обновления
|
||||||
|
блок MUST сохранять доступные события без технического предупреждения; при
|
||||||
|
отсутствии результата SHALL показываться нейтральная недоступность после
|
||||||
|
первичного ожидания. Восстановление MUST выполняться автоматически без ручного
|
||||||
|
повтора и без подмены неизвестного результата подтверждённой пустотой.
|
||||||
|
|
||||||
|
#### Scenario: Отображение ближайших событий
|
||||||
|
- **WHEN** обзор счёта успешно загружен и календарь содержит будущие события
|
||||||
|
- **THEN** обзор показывает первые пять событий в порядке даты и действие перехода к полной странице
|
||||||
|
|
||||||
|
#### Scenario: Ближайшие события недоступны
|
||||||
|
- **WHEN** обзор счёта успешно загружен, но запрос будущих событий завершается временной ошибкой
|
||||||
|
- **THEN** Portfolio остаётся доступным, а блок сохраняет прежние события либо показывает нейтральную недоступность без технической ошибки и ручного повтора
|
||||||
@@ -0,0 +1,101 @@
|
|||||||
|
## MODIFIED Requirements
|
||||||
|
|
||||||
|
### Requirement: Экран списка брокерских счетов
|
||||||
|
|
||||||
|
Клиент SHALL загружать список при открытии защищённого маршрута `/accounts`
|
||||||
|
без ручного обновления. Клиент MUST использовать успешный frontend-кэш списка
|
||||||
|
в течение 60 секунд. После истечения этого срока открытие или возвращение
|
||||||
|
на экран SHALL инициировать получение актуального списка; имеющийся Client
|
||||||
|
Cached Snapshot MUST оставаться видимым во время обновления и после временной
|
||||||
|
ошибки без технических статусов, времени получения и действий повтора.
|
||||||
|
Автоматическое восстановление SHALL соответствовать `frontend-data-resilience`.
|
||||||
|
|
||||||
|
При успешном непустом ответе клиент MUST отобразить адаптивный одноколоночный
|
||||||
|
список широких интерактивных карточек счетов с локализованными типом и, если
|
||||||
|
доступна, датой открытия без времени; каждая карточка MUST ясно показывать тип,
|
||||||
|
имя, финансовую сводку, вторичные метаданные и заметное действие открытия счёта,
|
||||||
|
вести на `/accounts/:accountId` по всей области и сохранять доступное
|
||||||
|
клавиатурное состояние. После успешной замены или удаления T-Bank connection
|
||||||
|
клиент MUST инвалидировать список счетов.
|
||||||
|
|
||||||
|
Для доступной `portfolioSummary` карточка MUST показывать не более двух
|
||||||
|
Money-итогов в исходных валютах и обозначать наличие остальных валют, если
|
||||||
|
они есть; она MUST NOT показывать или подразумевать FX-конвертацию,
|
||||||
|
межвалютный агрегированный итог либо Cash Balance как отдельный второй итог.
|
||||||
|
При `portfolioSummary: null` карточка MUST показывать локальное нейтральное
|
||||||
|
состояние недоступности сводки, сохраняя метаданные счёта и возможность открыть
|
||||||
|
его. При доступной пустой сводке карточка MUST не выдавать отсутствие итогов
|
||||||
|
за временную ошибку.
|
||||||
|
|
||||||
|
#### Scenario: Пользователь открывает счёт из списка
|
||||||
|
- **WHEN** клиент успешно загрузил непустой список и User выбирает карточку счёта
|
||||||
|
- **THEN** клиент переходит на `/accounts/:accountId` с `id` выбранного счёта
|
||||||
|
|
||||||
|
#### Scenario: Список пуст
|
||||||
|
- **WHEN** клиент получает успешный полный пустой массив
|
||||||
|
- **THEN** клиент показывает штатное сообщение об отсутствии инвестиционных счетов T-Bank
|
||||||
|
|
||||||
|
#### Scenario: Список берётся из свежего frontend-кэша
|
||||||
|
- **WHEN** User повторно открывает список в течение 60 секунд после успешной загрузки
|
||||||
|
- **THEN** клиент показывает сохранённые счета без нового API-запроса
|
||||||
|
|
||||||
|
#### Scenario: Устаревший список загружается повторно
|
||||||
|
- **WHEN** User открывает список после истечения 60 секунд frontend-кэша и уже существует последний успешный список
|
||||||
|
- **THEN** клиент оставляет этот список видимым во время нового запроса без индикации фонового обновления
|
||||||
|
|
||||||
|
#### Scenario: Ошибка фонового обновления не скрывает snapshot
|
||||||
|
- **WHEN** обновление устаревшего списка завершается временной ошибкой при наличии последнего успешного Client Cached Snapshot
|
||||||
|
- **THEN** клиент сохраняет snapshot видимым без предупреждения и ручного повтора и восстанавливает получение данных автоматически
|
||||||
|
|
||||||
|
#### Scenario: Карточка ограничивает валютные итоги
|
||||||
|
- **WHEN** доступная сводка счёта содержит итоги в трёх или более валютах
|
||||||
|
- **THEN** карточка показывает не более двух исходных валютных итогов и обозначает наличие остальных без общего сконвертированного значения
|
||||||
|
|
||||||
|
#### Scenario: Недоступность сводки локальна карточке
|
||||||
|
- **WHEN** клиент получает список, в котором `portfolioSummary` одного счёта равна `null`
|
||||||
|
- **THEN** он показывает нейтральную недоступность только этой сводки, не скрывает остальные карточки и сохраняет переход на детали счёта
|
||||||
|
|
||||||
|
#### Scenario: Пустая сводка не является ошибкой
|
||||||
|
- **WHEN** клиент получает доступную `portfolioSummary` с пустым `totalsByCurrency`
|
||||||
|
- **THEN** он показывает нейтральное состояние отсутствия финансовых итогов, а не состояние временной ошибки
|
||||||
|
|
||||||
|
### Requirement: Клиентские состояния ошибки списка счетов
|
||||||
|
|
||||||
|
Клиент SHALL автоматически восстанавливать временно неуспешное чтение списка
|
||||||
|
по правилам `frontend-data-resilience` без кнопок обновления и повтора. При
|
||||||
|
`TBANK_NOT_CONNECTED` клиент MUST показать необходимость подключения и действие
|
||||||
|
открытия настроек T-Bank. При `INVALID_TBANK_TOKEN` клиент MUST показать
|
||||||
|
необходимость восстановить подключение и то же действие. Эти подтверждённые
|
||||||
|
состояния MUST скрывать личный список и MUST NOT запускать автоматические повторы.
|
||||||
|
|
||||||
|
При временной недоступности, включая `TBANK_UNAVAILABLE`, клиент MUST сохранять
|
||||||
|
успешный результат текущей границы доступа без предупреждений. Если результата
|
||||||
|
нет, после первичного ожидания клиент SHALL показать спокойную локальную
|
||||||
|
недоступность без технических подробностей. Неизвестная ошибка MUST получать
|
||||||
|
безопасное локальное представление; отсутствие известного кода MUST NOT
|
||||||
|
разрешать бесконечные повторы или обход доступа. Временный сбой MUST NOT
|
||||||
|
предлагать перенастройку действующего подключения как способ повторить загрузку.
|
||||||
|
|
||||||
|
#### Scenario: Подключение требуется
|
||||||
|
- **WHEN** клиент получает `TBANK_NOT_CONNECTED`
|
||||||
|
- **THEN** клиент не показывает список и предлагает открыть настройки T-Bank
|
||||||
|
|
||||||
|
#### Scenario: Известная ошибка не повторяется автоматически
|
||||||
|
- **WHEN** запрос списка завершается подтверждённой ошибкой подключения или доступа, требующей действия пользователя
|
||||||
|
- **THEN** клиент не выполняет автоматических повторов и предлагает соответствующее действие вместо технической повторной загрузки
|
||||||
|
|
||||||
|
#### Scenario: Token требует внимания
|
||||||
|
- **WHEN** клиент получает `INVALID_TBANK_TOKEN`
|
||||||
|
- **THEN** клиент скрывает личный список и предлагает восстановить подключение в настройках T-Bank
|
||||||
|
|
||||||
|
#### Scenario: Временная ошибка T-Bank
|
||||||
|
- **WHEN** клиент получает `TBANK_UNAVAILABLE` без доступного результата списка
|
||||||
|
- **THEN** клиент автоматически восстанавливает получение и после первичного ожидания показывает нейтральную недоступность без повторной загрузки и предложения перенастроить подключение
|
||||||
|
|
||||||
|
#### Scenario: Неизвестная ошибка загрузки
|
||||||
|
- **WHEN** клиент получает ошибку без известного кода списка счетов и без доступного результата
|
||||||
|
- **THEN** клиент показывает безопасное нейтральное состояние без технического сообщения или кнопки повтора, применяя только допустимое ограниченное восстановление
|
||||||
|
|
||||||
|
#### Scenario: Известная ошибка при сохранённом snapshot
|
||||||
|
- **WHEN** фоновое обновление списка с последним успешным Client Cached Snapshot получает `TBANK_UNAVAILABLE`
|
||||||
|
- **THEN** клиент сохраняет snapshot видимым без предупреждения, времени получения и ручных действий восстановления
|
||||||
@@ -0,0 +1,127 @@
|
|||||||
|
## MODIFIED Requirements
|
||||||
|
|
||||||
|
### Requirement: Client Cached Snapshot остаётся доступным при обновлении Accounts и Portfolio
|
||||||
|
|
||||||
|
Frontend MUST сохранять последний успешный результат списка Brokerage Accounts,
|
||||||
|
Portfolio и других экранов чтения при фоновом обновлении и временной ошибке
|
||||||
|
для того же пользователя, подключения и набора данных. Подтверждённый пустой
|
||||||
|
результат MUST также считаться успешным. Смена счёта, инструмента, поискового
|
||||||
|
запроса, страницы или применённого периода MUST NOT представлять данные прежней
|
||||||
|
выборки как результат новой.
|
||||||
|
|
||||||
|
Доступный результат MUST оставаться видимым без предупреждений о свежести,
|
||||||
|
времени получения, индикаторов фонового обновления и действий ручного повтора.
|
||||||
|
Frontend MUST NOT подменять внутренние признаки свежести и полноты, успешное
|
||||||
|
время источника или ошибку обновления только ради отсутствия их отображения.
|
||||||
|
Client Cached Snapshot MUST оставаться отличным от server-side fallback;
|
||||||
|
ошибка чтения MUST NOT изменять `Portfolio.isStale`.
|
||||||
|
|
||||||
|
Обновление MUST сохранять выбранные фильтры, период, открытые разделы, ввод,
|
||||||
|
фокус и положение просмотра, пока соответствующее содержимое существует.
|
||||||
|
При logout, смене подключения или подтверждённом отказе доступа личные данные
|
||||||
|
прежней границы MUST перестать отображаться; поздний результат прежней загрузки
|
||||||
|
MUST NOT возвращать их на экран.
|
||||||
|
|
||||||
|
#### Scenario: Список Brokerage Accounts обновляется в фоне
|
||||||
|
- **WHEN** экран Accounts уже показывает Client Cached Snapshot и начинается фоновое обновление того же списка
|
||||||
|
- **THEN** frontend оставляет список видимым без индикации обновления, времени получения и технических действий
|
||||||
|
|
||||||
|
#### Scenario: Обновление Portfolio завершается ошибкой после успешного ответа
|
||||||
|
- **WHEN** экран Brokerage Account уже показывает Client Cached Snapshot Portfolio, а последующее обновление этого же Portfolio завершается временной ошибкой
|
||||||
|
- **THEN** frontend сохраняет Portfolio видимым без предупреждения и ручного повтора, а восстановление выполняется автоматически
|
||||||
|
|
||||||
|
#### Scenario: Server-side fallback и client cached snapshot различаются
|
||||||
|
- **WHEN** backend возвращает Portfolio с `isStale` либо фоновое обновление Client Cached Snapshot завершается временной ошибкой
|
||||||
|
- **THEN** frontend сохраняет доступные данные без технических сообщений и не подменяет один внутренний вид состояния другим
|
||||||
|
|
||||||
|
#### Scenario: Подтверждённая пустота переживает фоновую ошибку
|
||||||
|
- **WHEN** текущая выборка ранее успешно вернула полный пустой результат, а её обновление временно не удалось
|
||||||
|
- **THEN** подтверждённое пустое состояние сохраняется без предупреждения и не заменяется первичной загрузкой
|
||||||
|
|
||||||
|
#### Scenario: Изменились параметры выборки
|
||||||
|
- **WHEN** пользователь применил другой период или открыл другой счёт, а данных новой выборки ещё нет
|
||||||
|
- **THEN** экран показывает ожидание или недоступность новой выборки и не подписывает прежние суммы новым периодом или счётом
|
||||||
|
|
||||||
|
#### Scenario: Обновление не сбрасывает работу пользователя
|
||||||
|
- **WHEN** пользователь раскрыл раздел, выбрал фильтры или вводит данные, а фоновое чтение завершилось
|
||||||
|
- **THEN** обновление не сбрасывает эти действия, не переносит фокус и не возвращает пользователя в начало сохранившегося содержимого
|
||||||
|
|
||||||
|
#### Scenario: Изменился доступ к личным данным
|
||||||
|
- **WHEN** пользователь вышел, успешно сменил подключение либо получил подтверждённый отказ доступа к текущим данным
|
||||||
|
- **THEN** прежние личные данные скрываются, а позднее завершение старой загрузки не восстанавливает их
|
||||||
|
|
||||||
|
## ADDED Requirements
|
||||||
|
|
||||||
|
### Requirement: Временные сбои чтения восстанавливаются автоматически
|
||||||
|
|
||||||
|
Frontend SHALL автоматически повторять временно неуспешное чтение и восстанавливать
|
||||||
|
получение необходимых текущему экрану данных без ручного обновления. Повторы
|
||||||
|
одной попытки MUST иметь конечный предел и паузы, исключающие непрерывную
|
||||||
|
череду запросов. При исчерпании предела доступные данные SHALL сохраняться,
|
||||||
|
а при их отсутствии SHALL показываться локальная недоступность. Возвращение сети,
|
||||||
|
возвращение пользователя к открытому экрану и повторное открытие экрана MUST
|
||||||
|
возобновлять получение отсутствующих или требующих обновления данных без
|
||||||
|
перезагрузки страницы. Свежий полный результат MUST NOT требовать обращения
|
||||||
|
к источнику только из-за такого события.
|
||||||
|
|
||||||
|
Восстановление MUST учитывать сбой чтения результата и сбой самого получения
|
||||||
|
данных из источника, даже если чтение состояния завершилось успешно. Наблюдение
|
||||||
|
уже выполняющейся работы MUST NOT запускать её повторно. Уход с экрана MUST
|
||||||
|
прекращать новые попытки его восстановления; это не требует отменять уже начатую
|
||||||
|
работу источника. Автоматическое восстановление MUST NOT повторять запросы,
|
||||||
|
требующие исправления ввода, входа или восстановления доступа, и MUST NOT
|
||||||
|
переносить старые параметры в новую пользовательскую выборку.
|
||||||
|
|
||||||
|
#### Scenario: Кратковременный сбой чтения
|
||||||
|
- **WHEN** чтение текущей выборки временно не удалось, а следующая разрешённая автоматическая попытка успешна
|
||||||
|
- **THEN** экран самостоятельно показывает результат без ручного действия и без сообщения о сбое или восстановлении
|
||||||
|
|
||||||
|
#### Scenario: Источник завершил работу ошибкой
|
||||||
|
- **WHEN** чтение сохранённых данных успешно, но получение необходимых новых данных из источника временно не удалось
|
||||||
|
- **THEN** приложение применяет ограниченное автоматическое восстановление к неуспешной работе, а не считает успешное чтение доказательством её успеха
|
||||||
|
|
||||||
|
#### Scenario: Повторы исчерпаны
|
||||||
|
- **WHEN** временная недоступность сохраняется после конечного предела автоматических попыток
|
||||||
|
- **THEN** приложение прекращает серию повторов, сохраняет доступный результат либо локальную недоступность без бесконечной загрузки и ожидает следующего события восстановления
|
||||||
|
|
||||||
|
#### Scenario: Сеть или пользователь вернулись
|
||||||
|
- **WHEN** после временного сбоя восстановилась сеть либо пользователь вернулся к экрану с отсутствующим или требующим обновления результатом
|
||||||
|
- **THEN** получение данных возобновляется автоматически для текущей выборки и при успехе заменяет состояние недоступности содержимым
|
||||||
|
|
||||||
|
#### Scenario: Несколько событий восстановления совпали
|
||||||
|
- **WHEN** сеть восстановилась одновременно с возвращением пользователя на экран
|
||||||
|
- **THEN** приложение не запускает дублирующую работу получения одного набора данных
|
||||||
|
|
||||||
|
#### Scenario: Работа источника ещё выполняется
|
||||||
|
- **WHEN** приложение восстанавливает чтение состояния уже выполняющейся работы
|
||||||
|
- **THEN** оно продолжает получение её результата без повторного запуска той же работы
|
||||||
|
|
||||||
|
#### Scenario: Пользователь покинул экран
|
||||||
|
- **WHEN** пользователь ушёл со страницы с ожидающим восстановлением
|
||||||
|
- **THEN** новые попытки для покинутого экрана прекращаются, а уже начатая работа не изменяет содержимое другой выборки
|
||||||
|
|
||||||
|
#### Scenario: Ошибка требует действия пользователя
|
||||||
|
- **WHEN** подтверждены недействительное подключение, отсутствие доступа или некорректный ввод
|
||||||
|
- **THEN** автоматическая серия повторов прекращается и появляется соответствующее действие или локальная ошибка без технической кнопки повторной загрузки
|
||||||
|
|
||||||
|
### Requirement: Неполный результат не выдаётся за окончательный
|
||||||
|
|
||||||
|
Frontend MUST различать неизвестный результат, доступную часть данных и
|
||||||
|
подтверждённую пустоту. Неполные суммы и сравнения MUST NOT показываться как
|
||||||
|
окончательные или заменяться нулями. Доступные записи MAY оставаться видимыми,
|
||||||
|
но их список MUST NOT представляться полным при неподтверждённой полноте.
|
||||||
|
Состояние SHALL относиться к содержимому конкретной области, например
|
||||||
|
недоступному итогу, без отчёта о прогрессе синхронизации. Готовая область MUST
|
||||||
|
NOT ждать догрузки истории, которая не влияет на её результат.
|
||||||
|
|
||||||
|
#### Scenario: Итог ещё не определён
|
||||||
|
- **WHEN** часть данных, необходимых для суммы или сравнения, отсутствует
|
||||||
|
- **THEN** соответствующее значение обозначается как недоступное без вымышленного нуля или окончательного частичного итога
|
||||||
|
|
||||||
|
#### Scenario: Пустота ещё не подтверждена
|
||||||
|
- **WHEN** записи не получены и полнота выбранного периода неизвестна
|
||||||
|
- **THEN** экран не сообщает об отсутствии операций или выплат за этот период
|
||||||
|
|
||||||
|
#### Scenario: Период готов раньше остальной истории
|
||||||
|
- **WHEN** данные показанного периода полны, а не влияющая на него история ещё загружается
|
||||||
|
- **THEN** пользователь видит готовый результат без сообщения о догрузке остальной истории
|
||||||
@@ -0,0 +1,52 @@
|
|||||||
|
## MODIFIED Requirements
|
||||||
|
|
||||||
|
### Requirement: Контекстная индикация действий и фонового обновления
|
||||||
|
|
||||||
|
Frontend MUST сохранять уже доступное содержимое или элемент управления
|
||||||
|
основным контекстом, когда выполняется пользовательское действие либо фоновое
|
||||||
|
обновление Client Cached Snapshot. Явное действие пользователя SHALL иметь
|
||||||
|
компактную индикацию ожидания рядом с соответствующим элементом управления.
|
||||||
|
Фоновое обновление при доступном результате MUST проходить без индикаторов,
|
||||||
|
технических сообщений и объявлений о ходе работы. В обоих случаях frontend
|
||||||
|
MUST NOT заменять уже доступный контекст skeleton placeholders.
|
||||||
|
|
||||||
|
#### Scenario: Выполняется пользовательское действие
|
||||||
|
- **WHEN** User запустил действие и его результат ещё ожидается
|
||||||
|
- **THEN** frontend сохраняет соответствующий элемент управления или окружающий контекст видимым, показывает компактную индикацию процесса и не заменяет интерфейс skeleton placeholders
|
||||||
|
|
||||||
|
#### Scenario: Обновляется уже показанный snapshot
|
||||||
|
- **WHEN** frontend обновляет данные при наличии видимого Client Cached Snapshot
|
||||||
|
- **THEN** frontend оставляет snapshot видимым без индикации фонового обновления и без замены snapshot skeleton placeholders
|
||||||
|
|
||||||
|
## ADDED Requirements
|
||||||
|
|
||||||
|
### Requirement: Первичное ожидание не становится бесконечной загрузкой
|
||||||
|
|
||||||
|
При отсутствии результата frontend SHALL сначала показывать структурное
|
||||||
|
ожидание соответствующей области. После неуспешного завершения получения
|
||||||
|
либо истечения ограниченного времени первичного ожидания область MUST переходить
|
||||||
|
в спокойное локализованное состояние недоступности без технических подробностей
|
||||||
|
и ручного повтора. Это состояние MUST NOT утверждать, что результат пустой,
|
||||||
|
или требовать перезагрузки страницы. Продолжающееся автоматическое восстановление
|
||||||
|
MUST NOT заставлять область постоянно переключаться между недоступностью и
|
||||||
|
skeleton. После успешного получения содержимое SHALL появляться автоматически.
|
||||||
|
|
||||||
|
Отсутствие результата одной области MUST NOT скрывать остальные доступные
|
||||||
|
области. Первичная загрузка MUST сохранять доступное обозначение занятости,
|
||||||
|
а состояние недоступности MUST NOT продолжать объявляться бесконечно занятым.
|
||||||
|
|
||||||
|
#### Scenario: Первый результат успешно получен
|
||||||
|
- **WHEN** экран ожидает первый результат и получает его в пределах первоначального ожидания
|
||||||
|
- **THEN** структурные placeholders сменяются содержимым либо подтверждённым пустым состоянием
|
||||||
|
|
||||||
|
#### Scenario: Первое получение данных не удалось
|
||||||
|
- **WHEN** у области нет результата и первоначальная загрузка завершилась ошибкой или превысила ограниченное время ожидания
|
||||||
|
- **THEN** область показывает нейтральную недоступность без кнопки повтора, вымышленных данных и бесконечного индикатора занятости
|
||||||
|
|
||||||
|
#### Scenario: Восстановление продолжается после недоступности
|
||||||
|
- **WHEN** область уже показывает недоступность и выполняется очередная разрешённая попытка восстановления
|
||||||
|
- **THEN** область сохраняет устойчивое состояние без мигания skeleton и автоматически показывает содержимое после успеха
|
||||||
|
|
||||||
|
#### Scenario: Один блок недоступен
|
||||||
|
- **WHEN** основной результат загружен, а дополнительный блок не получил данных
|
||||||
|
- **THEN** состояние недоступности ограничено этим блоком и не заменяет доступное содержимое страницы
|
||||||
@@ -0,0 +1,20 @@
|
|||||||
|
## MODIFIED Requirements
|
||||||
|
|
||||||
|
### Requirement: Ожидаемые finance states не становятся route failures
|
||||||
|
|
||||||
|
Frontend SHALL сохранять локальное отображение известных состояний Brokerage
|
||||||
|
Account, Portfolio и T-Bank connection. Эти состояния MUST NOT заменяться
|
||||||
|
глобальным fallback. Временная ошибка фонового чтения MUST сохранять доступный
|
||||||
|
результат без предупреждения об устаревании, технической ошибки и ручного
|
||||||
|
повтора. При отсутствии результата SHALL показываться локальная недоступность
|
||||||
|
с автоматическим восстановлением. Подтверждённая необходимость входа,
|
||||||
|
восстановления подключения или выбора доступного счёта MUST сохранять понятное
|
||||||
|
объяснение и соответствующее действие, не маскируясь сохранёнными личными данными.
|
||||||
|
|
||||||
|
#### Scenario: Portfolio Snapshot устарел
|
||||||
|
- **WHEN** frontend получает устаревший Portfolio Snapshot в действующей границе доступа
|
||||||
|
- **THEN** frontend отображает Portfolio без предупреждения об устаревании и без глобального fallback
|
||||||
|
|
||||||
|
#### Scenario: Ошибка T-Bank connection
|
||||||
|
- **WHEN** запрос T-Bank connection завершается известной ошибкой
|
||||||
|
- **THEN** frontend сохраняет локальное состояние: временный сбой чтения восстанавливается автоматически, а подтверждённая необходимость действия пользователя сопровождается этим действием вместо глобального fallback
|
||||||
@@ -0,0 +1,112 @@
|
|||||||
|
## Purpose
|
||||||
|
|
||||||
|
Определяет спокойную и понятную обратную связь во всех разделах WealthLedger:
|
||||||
|
пользователь видит финансовые данные и результат своих действий, а не состояние
|
||||||
|
внутреннего процесса получения данных.
|
||||||
|
|
||||||
|
## ADDED Requirements
|
||||||
|
|
||||||
|
### Requirement: Чтение данных не требует внимания к техническим состояниям
|
||||||
|
|
||||||
|
На экранах счетов, портфеля, операций, доходов, событий, инструментов, поиска,
|
||||||
|
карт и настроек подключения приложение MUST NOT показывать время получения
|
||||||
|
данных, признаки их технического устаревания, ход фонового обновления и сообщения
|
||||||
|
об успехе либо временной ошибке такого обновления. Приложение MUST NOT предоставлять
|
||||||
|
кнопки или иные действия ручного обновления и повторной загрузки, включая их
|
||||||
|
иконные варианты. Эти сведения MUST NOT переноситься в уведомления, подсказки
|
||||||
|
или объявления вспомогательных технологий. Даты операций, выплат, открытия
|
||||||
|
счёта и выбранных периодов MUST сохранять свой предметный смысл.
|
||||||
|
|
||||||
|
Запрет технических действий MUST NOT удалять применение фильтров, переходы между
|
||||||
|
страницами, поиск, отправку формы, вход, подключение банка или безопасную навигацию.
|
||||||
|
После неуспешного сохранения пользователь SHALL иметь возможность вновь отправить
|
||||||
|
сохранённый ввод обычным действием формы.
|
||||||
|
|
||||||
|
#### Scenario: Фоновая загрузка завершилась ошибкой
|
||||||
|
- **WHEN** на любом из перечисленных экранов уже есть доступный результат и его фоновое обновление временно не удалось
|
||||||
|
- **THEN** результат остаётся видимым без предупреждения, времени получения, индикатора, уведомления и действия ручного повтора
|
||||||
|
|
||||||
|
#### Scenario: Фоновая загрузка завершилась успешно
|
||||||
|
- **WHEN** приложение получает обновлённые данные без явного действия сохранения со стороны пользователя
|
||||||
|
- **THEN** содержимое обновляется без сообщения об успешной загрузке и без переноса фокуса
|
||||||
|
|
||||||
|
#### Scenario: Просмотр списка карт и операций карты
|
||||||
|
- **WHEN** временная ошибка возникает при обновлении уже показанных карт, сводки или операций выбранной карты
|
||||||
|
- **THEN** соответствующий результат остаётся доступным без технического предупреждения и ручного повтора, а действия работы с картой сохраняются
|
||||||
|
|
||||||
|
#### Scenario: Поиск или новый диапазон инструмента пока недоступен
|
||||||
|
- **WHEN** пользователь изменил поисковый запрос либо диапазон графика, а соответствующий результат ещё не получен
|
||||||
|
- **THEN** экран показывает ожидание или локальную недоступность нового результата без кнопки повтора и не выдаёт результат прежнего запроса или диапазона за новый
|
||||||
|
|
||||||
|
#### Scenario: Предметные даты остаются видимыми
|
||||||
|
- **WHEN** экран показывает дату операции, выплаты или выбранный период
|
||||||
|
- **THEN** эти даты остаются доступны независимо от отсутствия времени технического получения данных
|
||||||
|
|
||||||
|
### Requirement: Краткое уведомление подтверждает неочевидный результат действия
|
||||||
|
|
||||||
|
Приложение SHALL показывать краткое локализованное уведомление об успешном
|
||||||
|
явном действии пользователя, если после завершения на экране отсутствует
|
||||||
|
однозначное подтверждение результата. Если результат уже очевиден по состоянию
|
||||||
|
формы или содержимого, приложение MUST NOT дублировать его уведомлением.
|
||||||
|
Уведомление MUST описывать выполненное действие, а не внутренний процесс.
|
||||||
|
Ожидание действия MUST NOT представляться его успешным завершением.
|
||||||
|
|
||||||
|
#### Scenario: Результат действия иначе легко пропустить
|
||||||
|
- **WHEN** действие успешно завершилось, его форма закрылась, а оставшийся экран не подтверждает результат однозначно
|
||||||
|
- **THEN** пользователь получает одно краткое уведомление о выполненном действии
|
||||||
|
|
||||||
|
#### Scenario: Результат уже очевиден
|
||||||
|
- **WHEN** успешное сохранение оставляет на экране явное подтверждение результата
|
||||||
|
- **THEN** приложение не добавляет дублирующее уведомление
|
||||||
|
|
||||||
|
#### Scenario: Приём действия ещё не означает успех
|
||||||
|
- **WHEN** приложение только начало выполнение действия и окончательный результат неизвестен
|
||||||
|
- **THEN** оно не показывает уведомление об успешном завершении
|
||||||
|
|
||||||
|
### Requirement: Уведомления не мешают работе и не дублируются
|
||||||
|
|
||||||
|
Уведомления MUST быть доступны как текст, не полагаться только на цвет и не
|
||||||
|
перехватывать клавиатурный фокус. Подтверждение успеха SHALL автоматически
|
||||||
|
закрываться и позволять доступное ручное закрытие. Повторная обработка одного
|
||||||
|
результата MUST NOT создавать повторное уведомление. Приложение MUST ограничивать
|
||||||
|
число одновременно видимых уведомлений и MUST NOT создавать каскад сообщений
|
||||||
|
из-за фонового восстановления данных.
|
||||||
|
|
||||||
|
#### Scenario: Один результат обработан повторно
|
||||||
|
- **WHEN** приложение повторно обрабатывает результат того же пользовательского действия
|
||||||
|
- **THEN** пользователь не получает второе уведомление об этом результате
|
||||||
|
|
||||||
|
#### Scenario: Работа с клавиатурой продолжается
|
||||||
|
- **WHEN** уведомление появляется во время ввода или навигации с клавиатуры
|
||||||
|
- **THEN** текущий фокус сохраняется, текст уведомления доступен вспомогательным технологиям, а действие закрытия имеет понятное доступное имя
|
||||||
|
|
||||||
|
#### Scenario: Несколько действий завершились рядом по времени
|
||||||
|
- **WHEN** несколько различных действий успешно завершаются за короткое время
|
||||||
|
- **THEN** уведомления соблюдают конечный предел одновременного показа и не блокируют доступ к содержимому и действиям страницы
|
||||||
|
|
||||||
|
### Requirement: Ошибки действий и препятствия доступа остаются понятными
|
||||||
|
|
||||||
|
Ошибка ввода MUST показываться у соответствующего поля. При неуспешном
|
||||||
|
сохранении приложение MUST сохранять ввод и показывать понятную локальную ошибку
|
||||||
|
в контексте действия, не объявляя его успешным. Если продолжение требует входа,
|
||||||
|
подключения банка или другого действия пользователя, объяснение и применимое
|
||||||
|
действие MUST оставаться доступны в соответствующей области. Исчезающее
|
||||||
|
уведомление MUST NOT быть единственным способом сообщить такое препятствие.
|
||||||
|
Приложение MUST NOT самостоятельно повторять изменение пользовательских данных
|
||||||
|
только потому, что включено автоматическое восстановление чтения.
|
||||||
|
|
||||||
|
#### Scenario: Операция не сохранилась
|
||||||
|
- **WHEN** пользователь отправил форму операции, а сохранение завершилось ошибкой
|
||||||
|
- **THEN** введённые значения остаются в форме вместе с локальной ошибкой, обычное действие сохранения снова доступно и подтверждение успеха отсутствует
|
||||||
|
|
||||||
|
#### Scenario: Поле содержит недопустимое значение
|
||||||
|
- **WHEN** пользователь пытается отправить форму с недопустимым значением
|
||||||
|
- **THEN** ошибка относится к этому полю и не заменяется общим всплывающим уведомлением
|
||||||
|
|
||||||
|
#### Scenario: Требуется восстановить доступ
|
||||||
|
- **WHEN** приложение подтвердило необходимость входа или восстановления подключения
|
||||||
|
- **THEN** соответствующая область предлагает необходимое действие и сохраняет объяснение до устранения препятствия или ухода пользователя
|
||||||
|
|
||||||
|
#### Scenario: Ответ на изменение данных не получен
|
||||||
|
- **WHEN** соединение прервалось после отправки пользовательского изменения и результат неизвестен
|
||||||
|
- **THEN** приложение не объявляет успех и не повторяет изменение автоматически как обычную загрузку данных
|
||||||
@@ -0,0 +1,73 @@
|
|||||||
|
## MODIFIED Requirements
|
||||||
|
|
||||||
|
### Requirement: Состояния и ошибки Portfolio на клиенте
|
||||||
|
|
||||||
|
Клиент SHALL загружать Portfolio при открытии защищённого маршрута
|
||||||
|
`/accounts/:accountId` и использовать успешный ответ в течение 30 секунд.
|
||||||
|
Временные сбои и возвращение к экрану с требующими обновления данными SHALL
|
||||||
|
обрабатываться автоматическим восстановлением по `frontend-data-resilience`.
|
||||||
|
Клиент MUST NOT предоставлять ручное обновление или повторную загрузку.
|
||||||
|
|
||||||
|
При первичной загрузке без успешного результата того же Brokerage Account
|
||||||
|
клиент MUST показывать структурный skeleton ожидаемого содержимого, включая
|
||||||
|
сводку, без вымышленных сумм. Область MUST иметь доступное обозначение занятости;
|
||||||
|
skeleton MUST NOT быть интерактивным или получать фокус. Неуспешное или
|
||||||
|
затянувшееся первичное получение SHALL переходить в локальную недоступность
|
||||||
|
по `frontend-loading-presentation`, а не в бесконечную загрузку.
|
||||||
|
|
||||||
|
Истечение срока свежести MUST NOT скрывать доступный Client Cached Snapshot.
|
||||||
|
При обновлении и временной ошибке клиент MUST сохранять данные того же
|
||||||
|
Portfolio, включая валютные итоги, без индикации фоновой работы, предупреждений,
|
||||||
|
времени получения и уведомлений. Исходное `lastSuccessfulAt` и `isStale` MUST
|
||||||
|
сохранять внутренний смысл: скрытие этих сведений MUST NOT делать сохранённый
|
||||||
|
снимок новым успешным результатом или подтверждением текущего доступа.
|
||||||
|
Server-side stale и ошибка клиентского чтения MUST NOT подменять друг друга.
|
||||||
|
|
||||||
|
Клиент MUST показывать штатное empty-состояние только при подтверждённом полном
|
||||||
|
результате с пустыми `positions` и `cashBalances`, без вымышленных нулевых карточек.
|
||||||
|
Неполный итог MUST NOT выдаваться за окончательный; доступные независимые данные
|
||||||
|
MUST сохраняться на экране. При подтверждённом `404` клиент MUST скрыть личный
|
||||||
|
Portfolio и предложить возврат к списку счетов. При `TBANK_NOT_CONNECTED` или
|
||||||
|
`INVALID_TBANK_TOKEN` он MUST скрыть личные данные и предложить восстановление
|
||||||
|
подключения. Эти состояния MUST NOT маскироваться сохранённым снимком или
|
||||||
|
вызывать техническую повторную загрузку.
|
||||||
|
|
||||||
|
#### Scenario: Показ устаревшего Portfolio
|
||||||
|
- **WHEN** клиент получает успешный ответ с `isStale: true` в действующей границе доступа
|
||||||
|
- **THEN** клиент показывает позиции, остатки и доступные валютные итоги без времени последнего снимка, предупреждения и ручного обновления
|
||||||
|
|
||||||
|
#### Scenario: Недоступный счёт на клиенте
|
||||||
|
- **WHEN** клиент получает подтверждённый `404` текущего Portfolio
|
||||||
|
- **THEN** клиент не показывает личный Portfolio, включая ранее сохранённый, и предлагает вернуться к списку Brokerage Account без действия повтора
|
||||||
|
|
||||||
|
#### Scenario: Первичная загрузка Portfolio
|
||||||
|
- **WHEN** клиент ожидает Portfolio этого Brokerage Account без ранее полученного успешного ответа
|
||||||
|
- **THEN** он показывает структурный skeleton, включая место сводки, с доступным обозначением загрузки, без вымышленных или нулевых сумм и без фокусируемых placeholders
|
||||||
|
|
||||||
|
#### Scenario: Обновление после истечения срока свежести
|
||||||
|
- **WHEN** срок свежести показанного Portfolio истёк и началось фоновое обновление данных того же Brokerage Account
|
||||||
|
- **THEN** клиент сохраняет прежние валютные итоги без индикации обновления и не заменяет доступный состав и сводку skeleton-состоянием
|
||||||
|
|
||||||
|
#### Scenario: Ошибка обновления после успешного ответа
|
||||||
|
- **WHEN** клиент уже показывает Client Cached Snapshot Portfolio, а обновление этих же данных завершается временной ошибкой
|
||||||
|
- **THEN** клиент сохраняет данные и суммы без предупреждения и действия повтора; ошибка не делает снимок свежим и не изменяет `isStale`
|
||||||
|
|
||||||
|
#### Scenario: Ошибка клиентского обновления при server-side stale
|
||||||
|
- **WHEN** клиент показывает Portfolio с `isStale: true`, а фоновое обновление этого же Portfolio завершается временной ошибкой
|
||||||
|
- **THEN** прежние суммы остаются видимыми без технических предупреждений и ручных действий, сохраняя различие внутренних состояний
|
||||||
|
|
||||||
|
#### Scenario: Повторное обновление успешно
|
||||||
|
- **WHEN** после временной ошибки автоматическое восстановление получает успешный Portfolio Snapshot
|
||||||
|
- **THEN** до ответа прежние суммы остаются видимыми, затем клиент показывает новый результат без уведомления об обновлении и без переноса пользовательского фокуса
|
||||||
|
|
||||||
|
#### Scenario: Штатный пустой Portfolio на клиенте
|
||||||
|
- **WHEN** успешно полученный полный Portfolio содержит пустые `positions` и `cashBalances`
|
||||||
|
- **THEN** клиент показывает существующее empty-состояние без валютных карточек с вымышленными нулевыми итогами
|
||||||
|
|
||||||
|
#### Scenario: Первичный Portfolio пока недоступен
|
||||||
|
- **WHEN** данных Portfolio нет, а первичное получение не удалось или превысило ограниченное время ожидания
|
||||||
|
- **THEN** клиент показывает нейтральную недоступность без кнопки повтора и автоматически заменяет её содержимым после успешного восстановления
|
||||||
|
|
||||||
|
#### Scenario: Требуется восстановить подключение
|
||||||
|
- **WHEN** клиент получает `TBANK_NOT_CONNECTED` или `INVALID_TBANK_TOKEN` при наличии сохранённого личного Portfolio
|
||||||
|
- **THEN** личные данные скрываются, а клиент предлагает необходимое действие подключения без технической повторной загрузки
|
||||||
@@ -0,0 +1,45 @@
|
|||||||
|
## MODIFIED Requirements
|
||||||
|
|
||||||
|
### Requirement: Управление подключением в настройках
|
||||||
|
|
||||||
|
Клиент SHALL показывать в настройках статус T-Bank connection, текст о
|
||||||
|
необходимости read-only T-Bank Invest token, поле token и действие подключения
|
||||||
|
либо замены. Для существующего подключения клиент MUST показывать действие
|
||||||
|
удаления с modal-подтверждением. Во время создания, замены или удаления все
|
||||||
|
действия секции подключения и действия modal MUST быть отключены. После
|
||||||
|
успешного создания или замены клиент MUST очистить поле token и обновить статус;
|
||||||
|
при ошибке token MUST остаться в поле.
|
||||||
|
|
||||||
|
Временный сбой чтения статуса SHALL восстанавливаться автоматически без кнопки
|
||||||
|
повтора и технического предупреждения. Пока первый статус неизвестен, клиент
|
||||||
|
MUST NOT показывать форму как подтверждённое отсутствие подключения: после
|
||||||
|
первичного ожидания SHALL отображаться нейтральная недоступность секции. Если
|
||||||
|
статус уже известен для текущей сессии, временный сбой его фонового чтения MUST
|
||||||
|
NOT скрывать доступную секцию или очищать ввод. Подтверждённое изменение
|
||||||
|
сессии или доступа MUST NOT маскироваться старым статусом.
|
||||||
|
|
||||||
|
Ошибки создания, замены и удаления MUST оставаться локальными, сохранять ввод
|
||||||
|
и возвращать применимые действия формы. Эти действия MUST NOT повторяться
|
||||||
|
автоматически как чтение статуса. Подтверждения успеха SHALL следовать
|
||||||
|
`frontend-user-feedback`: очевидное изменение статуса не требует дублирующего
|
||||||
|
уведомления, неочевидный результат получает одно краткое подтверждение.
|
||||||
|
|
||||||
|
#### Scenario: Пользователь подтверждает удаление
|
||||||
|
- **WHEN** User подтверждает удаление в modal
|
||||||
|
- **THEN** клиент блокирует действия секции до результата и после успешного ответа показывает состояние без подключения
|
||||||
|
|
||||||
|
#### Scenario: Ошибка загрузки статуса
|
||||||
|
- **WHEN** клиент временно не может получить статус подключения
|
||||||
|
- **THEN** он автоматически восстанавливает чтение, сохраняет известный статус текущей сессии либо показывает нейтральную недоступность после первичного ожидания без формы и кнопки повтора
|
||||||
|
|
||||||
|
#### Scenario: Ошибка проверки token в клиенте
|
||||||
|
- **WHEN** создание или замена получает `INVALID_TBANK_TOKEN` либо `TBANK_UNAVAILABLE`
|
||||||
|
- **THEN** клиент показывает соответственно локализованное сообщение о token и правах либо о временной недоступности T-Bank в контексте формы, возвращает интерактивность и сохраняет введённый token
|
||||||
|
|
||||||
|
#### Scenario: Фоновое чтение не сбрасывает ввод
|
||||||
|
- **WHEN** пользователь редактирует token в доступной секции, а фоновое чтение статуса временно не удалось
|
||||||
|
- **THEN** ввод и доступная секция сохраняются без технического предупреждения или уведомления
|
||||||
|
|
||||||
|
#### Scenario: Удаление не удалось
|
||||||
|
- **WHEN** пользователь подтвердил удаление подключения, а действие завершилось ошибкой
|
||||||
|
- **THEN** клиент не показывает успех, сохраняет известный статус и локальную ошибку, возвращает применимые действия и не повторяет удаление автоматически
|
||||||
@@ -0,0 +1,159 @@
|
|||||||
|
# Implementation tasks
|
||||||
|
|
||||||
|
Основание: согласованные Delta Specs и [Design](design.md), включая inline
|
||||||
|
UI/UX package `quiet-user-feedback-ui-v1` и Solution Assessment.
|
||||||
|
|
||||||
|
Задачи выполняются по порядку групп и пунктов. Каждая задача имеет одного
|
||||||
|
владельца репозитория; технические проверки выполняет implementer. Проверки
|
||||||
|
сети используют synthetic fixtures и существующий MSW, а не реальный T-Bank.
|
||||||
|
Перед Node-командами в каждом репозитории выполняется `nvm use --silent`.
|
||||||
|
Указанные ниже проверки — план, а не свидетельство выполненной реализации.
|
||||||
|
|
||||||
|
Перед изменениями сохраняются чужие staged/unstaged/new files, в частности
|
||||||
|
перенос PortfolioStructure. База требований сверяется по Migration Plan Design:
|
||||||
|
изменение порядка интеграции `persist-tbank-data` требует согласования
|
||||||
|
затронутых artifacts, а не молчаливого перезаписывания active change.
|
||||||
|
Recovery и удаление ручных controls поставляются вместе. Backend и workspace
|
||||||
|
не получают implementation tasks: они не входят в affected Delivery Map.
|
||||||
|
|
||||||
|
## 1. Принятые решения и зависимости
|
||||||
|
|
||||||
|
- [x] 1.1 [frontend] Применить Solution Assessment: оставить TanStack Query и существующих resource/screen owners, добавить exact `@mantine/notifications@9.6.1` с согласованным lockfile без второго query runtime или toast framework.
|
||||||
|
- **Covers:** `N/A` — dependency preparation не вводит отдельного пользовательского поведения; реализует выбранные средства из Design §1 и §6 до custom recovery work.
|
||||||
|
- **Verification:** `npm ci`; `npm ls @mantine/core @mantine/hooks @mantine/notifications react react-dom`; сверить exact versions, peer compatibility и отсутствие посторонних dependency changes.
|
||||||
|
|
||||||
|
## 2. Ограниченное восстановление чтения
|
||||||
|
|
||||||
|
- [x] 2.1 [frontend] В существующем `shared/api` реализовать классификацию временных GET failures, 15-секундный deadline с отменой чтения тела и до двух повторов с паузами 1/2 секунды; исключить auth endpoints, mutations, access/domain errors и отмену.
|
||||||
|
- **Covers:** `frontend-data-resilience` — `Временные сбои чтения восстанавливаются автоматически`; `frontend-user-feedback` — `Ошибки действий и препятствия доступа остаются понятными`.
|
||||||
|
- **Verification:** MSW-проверки через public client/query interface: recovery после network/timeout/503, конечное число запросов, прерванное чтение тела, отсутствие retries для 401/403/404/409 и malformed result, поведение 429 и серверной отсрочки по Design; `npm run test:run -- src/shared/api`.
|
||||||
|
|
||||||
|
- [x] 2.2 [frontend] Подключить read policy к authenticated query hooks и `useResourceQuery`, сохранив одну generated cache identity, независимые ordinary/observe режимы и существующие session/access fences; убрать локальные запреты retry только там, где они заменяются принятой политикой.
|
||||||
|
- **Covers:** `frontend-data-resilience` — `Client Cached Snapshot остаётся доступным при обновлении Accounts и Portfolio`; `frontend-data-resilience` — `Временные сбои чтения восстанавливаются автоматически`.
|
||||||
|
- **Verification:** Расширить resource lifecycle MSW-сценарии: cached snapshot при ошибке, `data: null` при HTTP success, ordinary GET после observe, unmount/cancel и late response после logout/connection replacement; `npm run test:run -- src/shared/api src/features/tbank-connection/model/connection-boundary`.
|
||||||
|
|
||||||
|
- [x] 2.3 [frontend] Перевести `useScreenSync` на ограниченное восстановление failed/cancelled missing/stale источников обычным GET: две дополнительные source attempts с паузами 5/15 секунд, бюджет на текущую выборку и отсутствие автоматического force POST.
|
||||||
|
- **Covers:** `frontend-data-resilience` — `Временные сбои чтения восстанавливаются автоматически`; `frontend-data-resilience` — `Неполный результат не выдаётся за окончательный`.
|
||||||
|
- **Verification:** MSW + управляемое время: failed source при HTTP 200, новая work ID без сброса бюджета, исчерпание серии, fresh complete после неудачного force, permanent unavailableReason; проверить число ordinary GET и отсутствие POST `/api/v1/tbank-sync`; `npm run test:run -- src/features/tbank-connection/model`.
|
||||||
|
|
||||||
|
- [x] 2.4 [frontend] Согласовать status observation и заключительное observe-чтение с in-flight запросами, сохранив интервал 1 секунда только для running work; различить status ID not found и подтверждённый отказ доступа к ресурсу.
|
||||||
|
- **Covers:** `frontend-data-resilience` — `Временные сбои чтения восстанавливаются автоматически`; `frontend-data-resilience` — `Client Cached Snapshot остаётся доступным при обновлении Accounts и Portfolio`.
|
||||||
|
- **Verification:** MSW-сценарии: медленное observe не отменяется каждым tick, terminal status не теряет заключительное чтение, HTTP/status failure не запускает force sync, `404` work ID перечитывает ресурс, access loss очищает личный snapshot; `npm run test:run -- src/features/tbank-connection/model/screen-sync.test.tsx src/shared/api/resource-query.test.tsx`.
|
||||||
|
|
||||||
|
- [x] 2.5 [frontend] Подключить единый lifecycle recovery на focus/reconnect и смену выборки: обычные reads используют штатную Query policy, инвестиционные — screen owner; отменять неактуальные timers и не дублировать восстановление при совпадении событий.
|
||||||
|
- **Covers:** `frontend-data-resilience` — `Временные сбои чтения восстанавливаются автоматически`; `frontend-data-resilience` — `Client Cached Snapshot остаётся доступным при обновлении Accounts и Portfolio`.
|
||||||
|
- **Verification:** Через Query focus/online managers и MSW проверить fresh/stale/missing results, offline/hidden pause, одновременный reconnect/focus, повторное открытие, переход на другой счёт/период и уход последнего consumer; `npm run test:run -- src/shared/api src/features/tbank-connection/model`.
|
||||||
|
|
||||||
|
## 3. Состояния ожидания и доступного результата
|
||||||
|
|
||||||
|
- [x] 3.1 [frontend] Реализовать общую presentation-only модель ограниченного первичного ожидания в `shared/lib`: 10-секундный budget, устойчивый unavailable latch для identity области и автоматический переход к результату; применить её к существующим loading/state presentation без второго кэша.
|
||||||
|
- **Covers:** `frontend-loading-presentation` — `Первичное ожидание не становится бесконечной загрузкой`; `frontend-loading-presentation` — `Контекстная индикация действий и фонового обновления`.
|
||||||
|
- **Verification:** Минимальная runnable проверка собственного state transition: skeleton → timeout/error unavailable → loaded, отсутствие мигания при retry, сброс только при новой выборке, cleanup и доступное busy-состояние; `npm run test:run -- src/shared/lib` и `npm run typecheck`.
|
||||||
|
|
||||||
|
- [x] 3.2 [frontend] В общих investment section models разделить readiness, полноту и access failure: успешные пустые данные не теряются, missing/partial не становятся нулевым итогом, а технические metadata остаются у владельца данных.
|
||||||
|
- **Covers:** `frontend-data-resilience` — `Неполный результат не выдаётся за окончательный`; `frontend-ui-resilience` — `Ожидаемые finance states не становятся route failures`.
|
||||||
|
- **Verification:** Проверки через потребляющие views: `null` против полного `[]`, partial rows против полного empty, недоступный total/comparison, independent ready section и access failure при cached content; `npm run test:run -- src/features/instrument-details src/pages/account-income`.
|
||||||
|
|
||||||
|
## 4. Инвестиционные экраны без технических controls
|
||||||
|
|
||||||
|
- [x] 4.1 [frontend] Перевести Accounts и AccountPage, включая «Все счета», на новые состояния: убрать даты получения, refresh/retry и технические предупреждения, сохранить валютные итоги, доступные snapshots, контекст и предметную навигацию.
|
||||||
|
- **Covers:** `brokerage-accounts` — `Экран списка брокерских счетов`; `brokerage-accounts` — `Клиентские состояния ошибки списка счетов`; `portfolio-view` — `Состояния и ошибки Portfolio на клиенте`; `frontend-data-resilience` — `Client Cached Snapshot остаётся доступным при обновлении Accounts и Portfolio`; `frontend-ui-resilience` — `Ожидаемые finance states не становятся route failures`.
|
||||||
|
- **Verification:** RTL/MSW: initial/loaded/empty/partial/unavailable, quiet refetch failure, сохранение раскрытий и focus, отсутствие вымышленных нулей, `404` и invalid token скрывают снимок; `npm run test:run -- src/pages/accounts src/pages/account src/app/routes/AppRoutes/AllAccounts.test.tsx`.
|
||||||
|
|
||||||
|
- [x] 4.2 [frontend] Перевести полный журнал и recent operations на локальное тихое восстановление; сохранить применённые фильтры, cursor navigation, даты и смысл строк, не подменять новую страницу прежней.
|
||||||
|
- **Covers:** `brokerage-account-ledger` — `Account overview includes recent ledger events`; `brokerage-account-ledger` — `Журнал восстанавливает чтение без ручного обновления`.
|
||||||
|
- **Verification:** RTL/MSW: background failure с прежними записями, missing новой страницы, отсутствие false empty и retry, локальный сбой preview не скрывает Portfolio; `npm run test:run -- src/pages/account-operations src/pages/account`.
|
||||||
|
|
||||||
|
- [x] 4.3 [frontend] Перевести страницу будущих событий и preview на сохранение доступного результата и нейтральную локальную недоступность; убрать технические статусы, сохранив даты и ограничения финансового прогноза.
|
||||||
|
- **Covers:** `brokerage-account-upcoming-events` — `Account page presents an upcoming events list`; `brokerage-account-upcoming-events` — `Account overview includes upcoming events`.
|
||||||
|
- **Verification:** RTL/MSW: cached events при временной ошибке, неизвестный результат против полного empty, offer без суммы, потеря доступа и независимость preview; `npm run test:run -- src/pages/account-events src/entities/brokerage-event src/pages/account`.
|
||||||
|
|
||||||
|
- [x] 4.4 [frontend] Перевести доход и current-month summary на тихое обновление; оставить независимые готовые результаты, недоступные comparisons без нулевой базы и неизменный пользовательский черновик периода.
|
||||||
|
- **Covers:** `brokerage-account-income-analytics` — `Realized analytics never presents an incomplete result as complete`; `brokerage-account-income-analytics` — `Account overview has an independent current-month income summary`; `brokerage-account-income-analytics` — `Доход обновляется без технических сообщений`; `frontend-data-resilience` — `Неполный результат не выдаётся за окончательный`.
|
||||||
|
- **Verification:** RTL/MSW: полный старый результат при временном сбое, missing/partial текущего периода, готовый доход с недоступным сравнением, смена периода без переименования прежних сумм, сохранение черновика; `npm run test:run -- src/pages/account-income src/pages/account`.
|
||||||
|
|
||||||
|
- [x] 4.5 [frontend] Убрать refresh/retry из поиска акций и облигаций, связав VM с автоматическим recovery и ожиданием текущего debounced query; сохранить фильтры и отсутствие подмены результата прежним запросом.
|
||||||
|
- **Covers:** `frontend-user-feedback` — `Чтение данных не требует внимания к техническим состояниям`; `frontend-loading-presentation` — `Первичное ожидание не становится бесконечной загрузкой`.
|
||||||
|
- **Verification:** RTL/MSW: смена query во время запроса, delayed/failed поиск с последующим восстановлением, отсутствие false no-results и технических controls; `npm run test:run -- src/features/instrument-search src/pages/stocks src/pages/bonds`.
|
||||||
|
|
||||||
|
- [x] 4.6 [frontend] Перевести детали акции/облигации и их секции на readiness текущей выборки: график, личные позиции, история, сведения и выплаты сохраняют доступное содержимое без технических дат и действий.
|
||||||
|
- **Covers:** `frontend-user-feedback` — `Чтение данных не требует внимания к техническим состояниям`; `frontend-data-resilience` — `Неполный результат не выдаётся за окончательный`; `frontend-ui-resilience` — `Ожидаемые finance states не становятся route failures`.
|
||||||
|
- **Verification:** RTL/MSW: independent sections, новый диапазон свечей и instrument ID не показывают прежний результат как новый, partial history не является полной; `npm run test:run -- src/features/instrument-details src/pages/stock src/pages/bond`.
|
||||||
|
|
||||||
|
## 5. Карты, формы и настройки подключения
|
||||||
|
|
||||||
|
- [x] 5.1 [frontend] Перевести CardsPage, CardPage и BankSummary на тихое чтение, ограниченное ожидание и сохранение текущей выборки; удалить placeholder прежней страницы при переходе к другой странице банковских операций.
|
||||||
|
- **Covers:** `frontend-user-feedback` — `Чтение данных не требует внимания к техническим состояниям`; `frontend-data-resilience` — `Client Cached Snapshot остаётся доступным при обновлении Accounts и Portfolio`; `frontend-loading-presentation` — `Первичное ожидание не становится бесконечной загрузкой`.
|
||||||
|
- **Verification:** RTL/MSW: карты/summary/history при refetch failure, `page` и период меняются без подмены данных, полный empty отличается от missing, формы не размонтируются из-за фоновой ошибки; `npm run test:run -- src/pages/cards src/pages/card/ui/CardPage src/entities/bank-card/api`.
|
||||||
|
|
||||||
|
- [x] 5.2 [frontend] Сохранить ввод и предметные действия BankCardForm и CategoryManager, заменив техническое перечитывание автоматической загрузкой; актуальную версию после конфликта принимать только явно, не повторяя запись.
|
||||||
|
- **Covers:** `frontend-user-feedback` — `Ошибки действий и препятствия доступа остаются понятными`; `frontend-loading-presentation` — `Контекстная индикация действий и фонового обновления`.
|
||||||
|
- **Verification:** RTL/MSW: field errors, сохранённый ввод при network failure, version conflict → автоматическое чтение → явное принятие версии, доступная отмена при unavailable, отсутствие второго mutation request; `npm run test:run -- src/entities/bank-card/ui`.
|
||||||
|
|
||||||
|
- [x] 5.3 [frontend] Перевести чтение категорий, исходной покупки и версий OperationForm/DeleteOperation на автоматическое восстановление; сохранить intent ID, refund constraints, явное подтверждение версии и недопущение повторной финансовой записи.
|
||||||
|
- **Covers:** `frontend-user-feedback` — `Ошибки действий и препятствия доступа остаются понятными`; `frontend-loading-presentation` — `Контекстная индикация действий и фонового обновления`.
|
||||||
|
- **Verification:** RTL/MSW: сбой зависимого GET без потери ввода, отсутствие ложного empty для расходов, конфликт удаления/правки, network loss после submit без auto-resubmit, сохранность version/intent при ручной повторной отправке; `npm run test:run -- src/pages/card/ui/OperationForm src/pages/card/ui/DeleteOperation src/entities/bank-card/api/banking.test.tsx`.
|
||||||
|
|
||||||
|
- [x] 5.4 [frontend] Перевести чтение T-Bank connection status на тихое восстановление: не показывать форму до первого известного статуса, сохранять уже открытую секцию и token при временном GET failure, оставить явные локальные ошибки mutations.
|
||||||
|
- **Covers:** `tbank-connection` — `Управление подключением в настройках`; `frontend-user-feedback` — `Ошибки действий и препятствия доступа остаются понятными`; `frontend-ui-resilience` — `Ожидаемые finance states не становятся route failures`.
|
||||||
|
- **Verification:** RTL/MSW: initial unavailable → loaded, сохранность ввода при фоновом сбое, single mutation на submit/delete, ошибки token и удаления, новая cache boundary только после успешной mutation; `npm run test:run -- src/features/tbank-connection`.
|
||||||
|
|
||||||
|
## 6. Редкие подтверждения действий
|
||||||
|
|
||||||
|
- [x] 6.1 [frontend] Подключить один Mantine Notifications host с общей темой, styles и i18n: limit 2, autoClose 4000 ms, desktop/mobile positions, доступное закрытие, reduced motion и очистка очереди при смене/завершении сессии.
|
||||||
|
- **Covers:** `frontend-user-feedback` — `Уведомления не мешают работе и не дублируются`.
|
||||||
|
- **Verification:** Проверить application-owned cleanup при logout/смене сессии через RTL; выполнить `npm run typecheck`; конфигурацию third-party limit/timer не дублировать unit-тестами библиотеки, доступность и размещение проверить в задаче 7.3.
|
||||||
|
|
||||||
|
- [x] 6.2 [frontend] В action VMs карт, операций и категорий отделить успех записи от последующего чтения и реализовать однократное подтверждение по таблице Design: видимый результат без toast, неочевидный — краткое сообщение с action ID и ограниченным ожиданием подтверждения.
|
||||||
|
- **Covers:** `frontend-user-feedback` — `Краткое уведомление подтверждает неочевидный результат действия`; `frontend-user-feedback` — `Уведомления не мешают работе и не дублируются`; `frontend-user-feedback` — `Ошибки действий и препятствия доступа остаются понятными`.
|
||||||
|
- **Verification:** RTL/MSW: сохранённая запись внутри/вне видимой выборки, удаление видимой/невидимой записи, успешная запись с неуспешным GET, 10-секундный предел подтверждения, повторный callback того же action ID и отдельное следующее действие; `npm run test:run -- src/entities/bank-card/ui src/pages/card src/pages/cards`.
|
||||||
|
|
||||||
|
- [x] 6.3 [frontend] В VM подключения добавить одно подтверждение успешной замены token при неизменном видимом статусе; создание/удаление с очевидным изменением статуса и все фоновые чтения оставить без toast.
|
||||||
|
- **Covers:** `tbank-connection` — `Управление подключением в настройках`; `frontend-user-feedback` — `Краткое уведомление подтверждает неочевидный результат действия`; `frontend-user-feedback` — `Чтение данных не требует внимания к техническим состояниям`.
|
||||||
|
- **Verification:** RTL/MSW: create/delete без дублирующего подтверждения, replace с единственным toast, failure без success, background recovery без notifications, сообщение без token; `npm run test:run -- src/features/tbank-connection/ui`.
|
||||||
|
|
||||||
|
## 7. Завершение frontend и UI-проверки
|
||||||
|
|
||||||
|
- [x] 7.1 [frontend] После миграции consumers удалить InvestmentRefreshState, SourceSyncStatus, неиспользуемые props/exports/строки и их устаревшие stories; проверить оставшиеся технические actions во всём scope без удаления предметных form/access controls.
|
||||||
|
- **Covers:** `frontend-user-feedback` — `Чтение данных не требует внимания к техническим состояниям`; `frontend-loading-presentation` — `Контекстная индикация действий и фонового обновления`.
|
||||||
|
- **Verification:** Проверить callers и i18n keys, отсутствие видимых/иконных/tooltip/live-region замен удалённых статусов; `npm run knip`; `npm run deps`; `npm run test:run -- src/test/storybook.test.tsx`; убедиться, что внутренние metadata и серверный контракт не удалены.
|
||||||
|
|
||||||
|
- [x] 7.2 [frontend] Обновить UI/data/testing conventions и значимые presentation stories под UI package v1: тихий loaded, нейтральный unavailable, partial без ложного итога и редкое подтверждение; сохранить изоляцию Storybook от application API/auth/query.
|
||||||
|
- **Covers:** `N/A` — conventions и каталог закрепляют уже утверждённую архитектуру и UI-пакет, не вводя отдельного поведения; необходимы для согласованной frontend delivery из Design.
|
||||||
|
- **Verification:** Сверить локальные инструкции с новыми retry/focus policies, примеры и ссылки; `npm run deps:storybook`; `npm run build:catalog`; проверить достижимость stories и отсутствие устаревшего обещания ручного retry.
|
||||||
|
|
||||||
|
- [x] 7.3 [frontend] Выполнить implementation-owned browser review состояний и interactions UI package v1 на 320, 768 и 1440 px: страницы чтения, partial/unavailable, формы, notification host и восстановление контекста.
|
||||||
|
- **Covers:** `frontend-user-feedback` — `Уведомления не мешают работе и не дублируются`; `frontend-user-feedback` — `Чтение данных не требует внимания к техническим состояниям`; `frontend-loading-presentation` — `Первичное ожидание не становится бесконечной загрузкой`; `frontend-data-resilience` — `Client Cached Snapshot остаётся доступным при обновлении Accounts и Portfolio`.
|
||||||
|
- **Verification:** В браузере проверить Tab/focus, modal trap и доступное закрытие, busy/live announcements, reduced motion, длинный текст, safe area, отсутствие перекрытых controls/горизонтального скролла, сохранение scroll и раскрытий; presentation states воспроизвести synthetic stories, runtime lifecycle — приложением и RTL/MSW, без browser MSW worker.
|
||||||
|
|
||||||
|
- [x] 7.4 [frontend] Завершить Boy Scout review затронутого diff и выполнить полный canonical frontend gate после всех production, test, dependency и convention изменений.
|
||||||
|
- **Covers:** `N/A` — финальная проверка frontend delivery по Design, без нового observable behavior; targeted tests не заменяют canonical gate.
|
||||||
|
- **Verification:** `npm ci` и `npm run verify`; отдельно сверить сохранность чужого PortfolioStructure diff, отсутствие generated/OpenAPI drift, дублированных query owners и global toast interception; записать фактические результаты и ограничения.
|
||||||
|
|
||||||
|
## 8. As-built документация
|
||||||
|
|
||||||
|
- [x] 8.1 [docs] После frontend delivery оформить принятое решение о тихом чтении и редких уведомлениях в существующем журнале ADR, с причинами, альтернативами, последствиями и связью с предыдущим решением о background sync.
|
||||||
|
- **Covers:** `N/A` — ADR фиксирует rationale уже утверждённого Design и выполненной delivery, а не создаёт новую behavioral spec; docs отмечен affected в Delivery Map.
|
||||||
|
- **Verification:** Проверить номер по актуальному `adr/README.md`, самостоятельность текста, связь с ADR 017 и сохранность его исторического содержания; новый ADR описывает реализованный механизм и не обещает непоставленное поведение.
|
||||||
|
|
||||||
|
- [x] 8.2 [docs] Обновить объяснения UI resilience, data freshness и visual states, убрав описание обязательных предупреждений/ручного обновления и объяснив ограниченное автоматическое восстановление, первичную недоступность и сохранение ошибок действий.
|
||||||
|
- **Covers:** `N/A` — as-built тематические страницы объясняют согласованные требования и технические решения; это documentation outcome Design, без самостоятельного нового поведения.
|
||||||
|
- **Verification:** Сверить `architecture/cross-cutting/ui-resilience.md`, `architecture/cross-cutting/data-freshness.md` и `design/overview.md` с реализованным flow, исключить противоречия между freshness, completeness и UI; проверить локальные ссылки и предметные даты.
|
||||||
|
|
||||||
|
- [x] 8.3 [docs] Согласовать затронутые предметные описания счетов, портфеля, операций, дохода, событий, инструментов и карт с тихим UI; обновить только фрагменты, описывающие изменённые состояния и recovery.
|
||||||
|
- **Covers:** `N/A` — предметная документация устраняет устаревшие инструкции пользователю после frontend delivery; область и поведение уже заданы Design и Delta Specs.
|
||||||
|
- **Verification:** Пройти маршруты README к затронутым domains; сверить упоминания refresh/retry, времени получения и ошибок с приложением, сохранив полезные финансовые пояснения, ограничения прогнозов и входящие ссылки.
|
||||||
|
|
||||||
|
- [x] 8.4 [docs] Выполнить semantic/link review обновлённой документации и canonical docs gate с учётом новых файлов.
|
||||||
|
- **Covers:** `N/A` — проверка документационной delivery из Design; не является новой пользовательской capability.
|
||||||
|
- **Verification:** `npm ci` при отсутствии установленных dependencies, затем `npm run verify`; проверить ADR index, новые локальные anchors и пользовательские маршруты чтения; если затронуты диаграммы, отдельно проверить их рендер доступным средством.
|
||||||
|
|
||||||
|
## 9. Canonical specifications и итоговые gates
|
||||||
|
|
||||||
|
- [x] 9.1 [specs] После подтверждения реализации перенести согласованные quiet Delta Requirements в canonical specs через OpenSpec sync workflow и добавить `frontend-user-feedback` в AI_INDEX; учесть порядок пересечения с persist по Design, сохраняя несвязанные требования.
|
||||||
|
- **Covers:** `N/A` — canonical publication не вводит поведения сверх утверждённых Delta Specs; реализует обязательный specs outcome Delivery Map и сохраняет единственный источник требований.
|
||||||
|
- **Verification:** Сравнить перенесённые Requirement blocks со всеми десятью delta paths, проверить отсутствие восстановления старых UI/retry obligations и потери несвязанных scenarios; проверить новый target в AI_INDEX; при изменившейся базе вернуть затронутые artifacts на согласование до переноса.
|
||||||
|
|
||||||
|
- [x] 9.2 [specs] Выполнить canonical specs gate, native schema/change/spec validation и итоговую сверку трассировки с реально выполненными задачами.
|
||||||
|
- **Covers:** `N/A` — проверка полноты и согласованности specs delivery, обязательная по Design и местным правилам; нового observable behavior нет.
|
||||||
|
- **Verification:** `npm run verify`; `openspec schema validate wealth-ledger-sdd --verbose`; `openspec validate quiet-user-feedback --type change --strict --store wealth-ledger-specs`; `openspec validate --specs --strict --store wealth-ledger-specs`; проверить новые файлы и их diff отдельно, а checklist отмечать только по наблюдённым результатам.
|
||||||
@@ -118,7 +118,23 @@
|
|||||||
|
|
||||||
### Requirement: Realized analytics never presents an incomplete result as complete
|
### Requirement: Realized analytics never presents an incomplete result as complete
|
||||||
|
|
||||||
Система MUST формировать выбранный результат, его comparisons, trend buckets, instrument breakdown и drill-down только после успешного получения всех необходимых cursor pages исполненных операций. Ошибка любой необходимой страницы MUST завершать расчёт восстанавливаемой ошибкой и MUST NOT возвращать частичные totals, comparisons, buckets или breakdown как полный результат. Успешный период без подходящих выплат MUST возвращать нулевой результат и отображаться с явным объяснением пустого состояния.
|
Система MUST формировать итог выбранного периода, его trend buckets,
|
||||||
|
instrument breakdown и drill-down только после успешного получения всех
|
||||||
|
необходимых cursor pages исполненных операций этого периода. Каждое comparison
|
||||||
|
MUST дополнительно требовать полного результата соответствующего периода
|
||||||
|
сравнения. Ошибка любой необходимой страницы MUST NOT возвращать частичные
|
||||||
|
totals, comparisons, buckets или
|
||||||
|
breakdown как полный результат. При временной недоступности клиент MUST
|
||||||
|
сохранять предыдущий полный результат той же выборки либо показывать
|
||||||
|
нейтральную недоступность соответствующего расчёта без технических сообщений
|
||||||
|
и ручного повтора. Восстановление SHALL выполняться автоматически по
|
||||||
|
`frontend-data-resilience`.
|
||||||
|
|
||||||
|
Доступные независимые части MUST оставаться видимыми; неполное сравнение MUST
|
||||||
|
обозначаться как недоступное без нулевой базы и окончательной разницы. Успешный
|
||||||
|
полный период без подходящих выплат MUST возвращать нулевой результат и
|
||||||
|
отображаться с объяснением пустого состояния. Неизвестный результат MUST NOT
|
||||||
|
подменяться таким нулевым результатом.
|
||||||
|
|
||||||
#### Scenario: Все страницы операций успешно получены
|
#### Scenario: Все страницы операций успешно получены
|
||||||
|
|
||||||
@@ -127,17 +143,31 @@
|
|||||||
|
|
||||||
#### Scenario: Одна из страниц операций недоступна
|
#### Scenario: Одна из страниц операций недоступна
|
||||||
|
|
||||||
- **WHEN** получение любой необходимой cursor page завершается ошибкой
|
- **WHEN** получение любой необходимой cursor page завершается временной ошибкой
|
||||||
- **THEN** страница показывает восстанавливаемую ошибку и не показывает частичный результат как полный
|
- **THEN** страница сохраняет предыдущий полный результат той же выборки либо показывает нейтральную недоступность расчёта без ручного повтора и не выдаёт частичный результат за полный
|
||||||
|
|
||||||
#### Scenario: В периоде нет купонов и дивидендов
|
#### Scenario: В периоде нет купонов и дивидендов
|
||||||
|
|
||||||
- **WHEN** все необходимые операции успешно получены, но среди них нет подходящих coupon или dividend Ledger Entries
|
- **WHEN** все необходимые операции успешно получены, но среди них нет подходящих coupon или dividend Ledger Entries
|
||||||
- **THEN** страница показывает нулевой результат и объясняет, что за выбранный период купоны и дивиденды не найдены
|
- **THEN** страница показывает нулевой результат и объясняет, что за выбранный период купоны и дивиденды не найдены
|
||||||
|
|
||||||
|
#### Scenario: Основной период готов, сравнение пока нет
|
||||||
|
|
||||||
|
- **WHEN** выбранный период полностью рассчитан, а необходимый период сравнения ещё не получен
|
||||||
|
- **THEN** основной доход остаётся доступным, сравнение обозначается как недоступное без нулевой базы, частичной разницы и сообщения о синхронизации
|
||||||
|
|
||||||
### Requirement: Account overview has an independent current-month income summary
|
### Requirement: Account overview has an independent current-month income summary
|
||||||
|
|
||||||
Обзор выбранного Brokerage Account MUST показывать компактный source-currency summary «Получено купонами и дивидендами» за период от первого дня текущего месяца по Europe/Moscow до сегодняшнего дня включительно и действие перехода на страницу «Пассивный доход». Summary MUST всегда использовать этот current-month период и MUST NOT наследовать последний пользовательский период страницы аналитики. Пустой или неуспешный расчёт summary MUST оставаться локальным состоянием блока и MUST NOT заменять успешно отображённый Portfolio или другие блоки обзора.
|
Обзор выбранного Brokerage Account MUST показывать компактный source-currency
|
||||||
|
summary «Получено купонами и дивидендами» за период от первого дня текущего
|
||||||
|
месяца по Europe/Moscow до сегодняшнего дня включительно и действие перехода
|
||||||
|
на страницу «Пассивный доход». Summary MUST всегда использовать этот current-month
|
||||||
|
период и MUST NOT наследовать последний пользовательский период страницы аналитики.
|
||||||
|
Пустой или неуспешный расчёт MUST оставаться локальным состоянием блока и
|
||||||
|
MUST NOT заменять успешно отображённый Portfolio или другие блоки обзора.
|
||||||
|
Временная ошибка обновления MUST сохранять доступную сводку той же выборки без
|
||||||
|
предупреждения и ручного повтора. При отсутствии результата SHALL показываться
|
||||||
|
нейтральная недоступность после первичного ожидания с автоматическим восстановлением.
|
||||||
|
|
||||||
#### Scenario: Обзор показывает доход текущего месяца
|
#### Scenario: Обзор показывает доход текущего месяца
|
||||||
|
|
||||||
@@ -151,8 +181,28 @@
|
|||||||
|
|
||||||
#### Scenario: Current-month summary недоступен
|
#### Scenario: Current-month summary недоступен
|
||||||
|
|
||||||
- **WHEN** Portfolio обзора успешно загружен, но расчёт current-month summary завершается ошибкой
|
- **WHEN** Portfolio обзора успешно загружен, но расчёт current-month summary завершается временной ошибкой
|
||||||
- **THEN** Portfolio и остальные успешно загруженные блоки остаются доступными, а summary показывает собственное состояние восстановления
|
- **THEN** Portfolio и остальные блоки остаются доступными, а summary сохраняет предыдущий результат той же выборки либо показывает нейтральную недоступность без ручного повтора
|
||||||
|
|
||||||
|
### Requirement: Доход обновляется без технических сообщений
|
||||||
|
|
||||||
|
Страница дохода MUST сохранять применённый период, черновик фильтров и
|
||||||
|
доступный результат при фоновом обновлении. Временная ошибка SHALL
|
||||||
|
восстанавливаться автоматически без кнопок обновления и повтора, времени
|
||||||
|
получения данных и уведомлений об их загрузке. Изменение периода MUST NOT
|
||||||
|
подписывать прежний результат новыми датами. Ошибки пользовательского периода
|
||||||
|
MUST оставаться у полей и MUST NOT запускать автоматический повтор ошибочного
|
||||||
|
ввода. Подтверждённая потеря доступа MUST скрывать личные результаты.
|
||||||
|
|
||||||
|
#### Scenario: Доход обновляется при редактировании периода
|
||||||
|
|
||||||
|
- **WHEN** пользователь редактирует черновик дат, а фоновое обновление применённого периода завершилось
|
||||||
|
- **THEN** черновик и фокус сохраняются, результат относится к прежнему применённому периоду и техническое уведомление не появляется
|
||||||
|
|
||||||
|
#### Scenario: Новый период пока недоступен
|
||||||
|
|
||||||
|
- **WHEN** пользователь применил другой допустимый период, но его расчёт ещё не получен
|
||||||
|
- **THEN** страница показывает ожидание или недоступность нового результата, не выдаёт прежние суммы за доход нового периода и восстанавливается автоматически
|
||||||
|
|
||||||
### Requirement: Income payments remain traceable to exact Ledger Entries
|
### Requirement: Income payments remain traceable to exact Ledger Entries
|
||||||
|
|
||||||
|
|||||||
@@ -48,20 +48,48 @@
|
|||||||
- **THEN** запись журнала передаёт её вместе с доступными идентификаторами инструмента, не меняя остальные сведения операции
|
- **THEN** запись журнала передаёт её вместе с доступными идентификаторами инструмента, не меняя остальные сведения операции
|
||||||
|
|
||||||
### Requirement: Account overview includes recent ledger events
|
### Requirement: Account overview includes recent ledger events
|
||||||
Обзор счёта MUST показывать пять последних исполненных записей журнала этого счёта и действие перехода к его полному журналу. Каждая показанная запись MUST иметь ту же визуальную идентичность инструмента и семантику денежного движения, что и запись полного журнала. Неуспешный или пустой запрос последних записей MUST оставаться локальным состоянием блока последних событий и MUST NOT заменять успешно отображённый обзор Portfolio.
|
|
||||||
|
Обзор счёта MUST показывать пять последних исполненных записей журнала этого
|
||||||
|
счёта и действие перехода к его полному журналу. Каждая запись MUST иметь ту же
|
||||||
|
визуальную идентичность инструмента и семантику денежного движения, что и запись
|
||||||
|
полного журнала. Неуспешный или пустой запрос MUST оставаться локальным состоянием
|
||||||
|
блока и MUST NOT заменять успешно отображённый Portfolio. При временном сбое
|
||||||
|
обновления блок MUST сохранять доступные записи без технического предупреждения
|
||||||
|
или ручного повтора. При отсутствии результата он SHALL показывать первичное
|
||||||
|
ожидание либо нейтральную недоступность, автоматически восстанавливая чтение.
|
||||||
|
Неподтверждённая пустота MUST NOT представляться отсутствием операций.
|
||||||
|
|
||||||
#### Scenario: Отображение последних событий
|
#### Scenario: Отображение последних событий
|
||||||
- **WHEN** загружается обзор счёта и его журнал содержит исполненные операции
|
- **WHEN** загружается обзор счёта и его журнал содержит исполненные операции
|
||||||
- **THEN** обзор показывает не более пяти последних записей и ссылку на полный журнал
|
- **THEN** обзор показывает не более пяти последних записей и ссылку на полный журнал
|
||||||
|
|
||||||
#### Scenario: Последние записи недоступны
|
#### Scenario: Последние записи недоступны
|
||||||
- **WHEN** обзор счёта успешно загружается, но запрос последних записей завершается ошибкой
|
- **WHEN** обзор счёта успешно загружается, но запрос последних записей завершается временной ошибкой
|
||||||
- **THEN** обзор Portfolio остаётся доступным, а блок последних событий отображает собственное состояние восстановления
|
- **THEN** Portfolio остаётся доступным, а блок сохраняет прежние записи либо показывает нейтральную недоступность без технического повтора и восстанавливается автоматически
|
||||||
|
|
||||||
#### Scenario: Последняя запись не содержит visual metadata инструмента
|
#### Scenario: Последняя запись не содержит visual metadata инструмента
|
||||||
- **WHEN** одна из последних записей не имеет доступной presentation metadata инструмента
|
- **WHEN** одна из последних записей не имеет доступной presentation metadata инструмента
|
||||||
- **THEN** обзор показывает для неё понятный текстовый fallback и сохраняет дату, тип, инструмент и денежное изменение записи доступными для чтения
|
- **THEN** обзор показывает для неё понятный текстовый fallback и сохраняет дату, тип, инструмент и денежное изменение записи доступными для чтения
|
||||||
|
|
||||||
|
### Requirement: Журнал восстанавливает чтение без ручного обновления
|
||||||
|
|
||||||
|
Страница журнала SHALL сохранять записи текущей выборки при временном сбое
|
||||||
|
обновления и восстанавливать чтение автоматически по `frontend-data-resilience`.
|
||||||
|
Период, категории и выбранная страница MUST сохраняться; результат другой
|
||||||
|
выборки MUST NOT подменять текущую. Страница MUST NOT показывать время получения,
|
||||||
|
технические статусы или действия ручного повтора. Даты операций, фильтры,
|
||||||
|
действия их применения и переходы по страницам MUST оставаться доступными.
|
||||||
|
При отсутствии результата SHALL применяться первичное ожидание и нейтральная
|
||||||
|
недоступность, а не сообщение об отсутствии операций до подтверждения полноты.
|
||||||
|
|
||||||
|
#### Scenario: Обновление журнала временно не удалось
|
||||||
|
- **WHEN** для применённого периода и страницы уже есть записи, а обновление завершается временной ошибкой
|
||||||
|
- **THEN** записи и параметры просмотра сохраняются без предупреждения и кнопки повтора до автоматического восстановления
|
||||||
|
|
||||||
|
#### Scenario: Следующая страница ещё не получена
|
||||||
|
- **WHEN** пользователь перешёл к следующей странице, но её загрузка временно не удалась
|
||||||
|
- **THEN** область новой страницы показывает ожидание или нейтральную недоступность, не выдаёт прежние записи за новую страницу и восстанавливает чтение автоматически
|
||||||
|
|
||||||
### Requirement: Full ledger presents compact rows
|
### Requirement: Full ledger presents compact rows
|
||||||
|
|
||||||
Страница полного журнала MUST показывать для каждой записи дату, тип операции, инструмент и денежное изменение в исходной валюте в компактной структурированной строке. При доступной presentation metadata инструмента строка MUST показывать его визуальную идентичность; при её отсутствии MUST использовать понятный текстовый fallback. Для каждой записи денежное изменение в исходной валюте MUST сопровождаться подписью конкретного типа события и знаком: для купонной операции — «Купон», для дивидендной — «Дивиденд», для остальных записей — подпись их категории («Сделка», «Налог», «Комиссия», «Перевод», «Прочее»). Строка MUST NOT повторять подпись типа события во вторичной метадате записи. Знак «+» / «−» и семантический цвет MUST оставаться носителями направления и MUST NOT заменяться только текстом. Страница MUST обозначать записи без движения денег нейтрально и MUST NOT показывать цену или количество.
|
Страница полного журнала MUST показывать для каждой записи дату, тип операции, инструмент и денежное изменение в исходной валюте в компактной структурированной строке. При доступной presentation metadata инструмента строка MUST показывать его визуальную идентичность; при её отсутствии MUST использовать понятный текстовый fallback. Для каждой записи денежное изменение в исходной валюте MUST сопровождаться подписью конкретного типа события и знаком: для купонной операции — «Купон», для дивидендной — «Дивиденд», для остальных записей — подпись их категории («Сделка», «Налог», «Комиссия», «Перевод», «Прочее»). Строка MUST NOT повторять подпись типа события во вторичной метадате записи. Знак «+» / «−» и семантический цвет MUST оставаться носителями направления и MUST NOT заменяться только текстом. Страница MUST обозначать записи без движения денег нейтрально и MUST NOT показывать цену или количество.
|
||||||
|
|||||||
@@ -64,27 +64,49 @@ Instrument в Future Cash Event MUST иметь тот же доменный с
|
|||||||
- **THEN** система трактует ответ как отсутствие данных по инструменту и не завершает запрос ошибкой
|
- **THEN** система трактует ответ как отсутствие данных по инструменту и не завершает запрос ошибкой
|
||||||
|
|
||||||
### Requirement: Account page presents an upcoming events list
|
### Requirement: Account page presents an upcoming events list
|
||||||
Страница Brokerage Account MUST предоставлять действие перехода на отдельную страницу «Будущие события». Эта страница MUST показывать все полученные события компактным списком без фильтров, пагинации и суммарного итога, с датой, типом, инструментом и прогнозной суммой в исходной валюте, если она известна. Страница MUST объяснять, что прогноз основан на текущей позиции, указан до налогов и может быть неполным из-за доступности данных источника.
|
|
||||||
|
Страница Brokerage Account MUST предоставлять действие перехода на отдельную
|
||||||
|
страницу «Будущие события». Эта страница MUST показывать все полученные события
|
||||||
|
компактным списком без фильтров, пагинации и суммарного итога, с датой, типом,
|
||||||
|
инструментом и прогнозной суммой в исходной валюте, если она известна. Страница
|
||||||
|
MUST объяснять, что прогноз основан на позиции счёта, указан до налогов и может
|
||||||
|
быть неполным из-за доступности данных источника. Это предметное ограничение
|
||||||
|
прогноза MUST NOT превращаться в отчёт о технической синхронизации.
|
||||||
|
|
||||||
|
При временном сбое обновления страница MUST сохранять ранее доступный результат
|
||||||
|
той же выборки без технических сообщений, времени получения и ручного повтора.
|
||||||
|
При отсутствии результата SHALL показываться первичное ожидание либо нейтральная
|
||||||
|
недоступность с автоматическим восстановлением по `frontend-data-resilience`.
|
||||||
|
Подтверждённая потеря доступа MUST скрывать личные данные независимо от наличия
|
||||||
|
сохранённого результата.
|
||||||
|
|
||||||
#### Scenario: Просмотр ближайших событий
|
#### Scenario: Просмотр ближайших событий
|
||||||
- **WHEN** User открывает «Будущие события» из обзора Brokerage Account
|
- **WHEN** User открывает «Будущие события» из обзора Brokerage Account
|
||||||
- **THEN** он видит отсортированный список событий ближайших 30 дней, где offer обозначен без суммы
|
- **THEN** он видит отсортированный список событий ближайших 30 дней, где offer обозначен без суммы
|
||||||
|
|
||||||
#### Scenario: Пустое состояние страницы
|
#### Scenario: Пустое состояние страницы
|
||||||
- **WHEN** запрос будущих событий успешно возвращает пустой список
|
- **WHEN** запрос будущих событий успешно возвращает полный пустой список
|
||||||
- **THEN** страница сообщает, что на ближайшие 30 дней событий не найдено, и объясняет ограничения покрытия источника
|
- **THEN** страница сообщает, что на ближайшие 30 дней событий не найдено, и объясняет предметные ограничения покрытия источника
|
||||||
|
|
||||||
#### Scenario: Ошибка страницы
|
#### Scenario: Ошибка страницы
|
||||||
- **WHEN** запрос будущих событий завершается ошибкой
|
- **WHEN** запрос будущих событий завершается временной ошибкой
|
||||||
- **THEN** страница не показывает частичный или устаревший список и предоставляет действие повторить запрос
|
- **THEN** страница сохраняет доступный результат той же выборки либо показывает нейтральную недоступность без ручного повтора, восстанавливая чтение автоматически и не выдавая частичные данные за полный прогноз
|
||||||
|
|
||||||
### Requirement: Account overview includes upcoming events
|
### Requirement: Account overview includes upcoming events
|
||||||
Обзор Brokerage Account MUST показывать не более пяти ближайших Future Cash Event и действие перехода на полную страницу «Будущие события». Неуспешный или пустой запрос этого блока MUST оставаться локальным состоянием блока и не заменять успешно отображённый Portfolio.
|
|
||||||
|
Обзор Brokerage Account MUST показывать не более пяти ближайших Future Cash
|
||||||
|
Event и действие перехода на полную страницу «Будущие события». Неуспешный
|
||||||
|
или пустой запрос этого блока MUST оставаться локальным состоянием блока и
|
||||||
|
не заменять успешно отображённый Portfolio. При временном сбое обновления
|
||||||
|
блок MUST сохранять доступные события без технического предупреждения; при
|
||||||
|
отсутствии результата SHALL показываться нейтральная недоступность после
|
||||||
|
первичного ожидания. Восстановление MUST выполняться автоматически без ручного
|
||||||
|
повтора и без подмены неизвестного результата подтверждённой пустотой.
|
||||||
|
|
||||||
#### Scenario: Отображение ближайших событий
|
#### Scenario: Отображение ближайших событий
|
||||||
- **WHEN** обзор счёта успешно загружен и календарь содержит будущие события
|
- **WHEN** обзор счёта успешно загружен и календарь содержит будущие события
|
||||||
- **THEN** обзор показывает первые пять событий в порядке даты и действие перехода к полной странице
|
- **THEN** обзор показывает первые пять событий в порядке даты и действие перехода к полной странице
|
||||||
|
|
||||||
#### Scenario: Ближайшие события недоступны
|
#### Scenario: Ближайшие события недоступны
|
||||||
- **WHEN** обзор счёта успешно загружен, но запрос будущих событий завершается ошибкой
|
- **WHEN** обзор счёта успешно загружен, но запрос будущих событий завершается временной ошибкой
|
||||||
- **THEN** Portfolio остаётся доступным, а блок будущих событий отображает собственную ошибку
|
- **THEN** Portfolio остаётся доступным, а блок сохраняет прежние события либо показывает нейтральную недоступность без технической ошибки и ручного повтора
|
||||||
|
|||||||
@@ -57,16 +57,38 @@
|
|||||||
- **THEN** система отвечает `503` Problem Details с code `TBANK_UNAVAILABLE` без счетов
|
- **THEN** система отвечает `503` Problem Details с code `TBANK_UNAVAILABLE` без счетов
|
||||||
|
|
||||||
### Requirement: Экран списка брокерских счетов
|
### Requirement: Экран списка брокерских счетов
|
||||||
Клиент SHALL загружать список при открытии защищённого маршрута `/accounts` без ручного обновления и без автоматического refetch при возврате фокуса. Клиент MUST использовать успешный frontend-кэш списка в течение 60 секунд. После истечения этого срока клиент MUST запрашивать актуальный список; при уже имеющемся успешном списке он MUST сохранять последний успешный Client Cached Snapshot видимым во время фонового обновления и после его ошибки, ясно отделяя это состояние от свежего результата. При успешном непустом ответе клиент MUST отобразить адаптивный одноколоночный список широких интерактивных карточек счетов с локализованными типом и, если доступна, датой открытия без времени; каждая карточка MUST ясно показывать тип, имя, финансовую сводку, вторичные метаданные и заметное действие открытия счёта, вести на `/accounts/:accountId` по всей области и сохранять доступное клавиатурное состояние. После успешной замены или удаления T-Bank connection клиент MUST инвалидировать список счетов.
|
|
||||||
|
|
||||||
Для доступной `portfolioSummary` карточка MUST показывать не более двух Money-итогов в исходных валютах и обозначать наличие остальных валют, если они есть; она MUST NOT показывать или подразумевать FX-конвертацию, межвалютный агрегированный итог либо Cash Balance как отдельный второй итог. При `portfolioSummary: null` карточка MUST показывать локальное безопасное состояние временной недоступности сводки, сохраняя метаданные счёта и возможность открыть его. При доступной пустой сводке карточка MUST не выдавать отсутствие итогов за временную ошибку.
|
Клиент SHALL загружать список при открытии защищённого маршрута `/accounts`
|
||||||
|
без ручного обновления. Клиент MUST использовать успешный frontend-кэш списка
|
||||||
|
в течение 60 секунд. После истечения этого срока открытие или возвращение
|
||||||
|
на экран SHALL инициировать получение актуального списка; имеющийся Client
|
||||||
|
Cached Snapshot MUST оставаться видимым во время обновления и после временной
|
||||||
|
ошибки без технических статусов, времени получения и действий повтора.
|
||||||
|
Автоматическое восстановление SHALL соответствовать `frontend-data-resilience`.
|
||||||
|
|
||||||
|
При успешном непустом ответе клиент MUST отобразить адаптивный одноколоночный
|
||||||
|
список широких интерактивных карточек счетов с локализованными типом и, если
|
||||||
|
доступна, датой открытия без времени; каждая карточка MUST ясно показывать тип,
|
||||||
|
имя, финансовую сводку, вторичные метаданные и заметное действие открытия счёта,
|
||||||
|
вести на `/accounts/:accountId` по всей области и сохранять доступное
|
||||||
|
клавиатурное состояние. После успешной замены или удаления T-Bank connection
|
||||||
|
клиент MUST инвалидировать список счетов.
|
||||||
|
|
||||||
|
Для доступной `portfolioSummary` карточка MUST показывать не более двух
|
||||||
|
Money-итогов в исходных валютах и обозначать наличие остальных валют, если
|
||||||
|
они есть; она MUST NOT показывать или подразумевать FX-конвертацию,
|
||||||
|
межвалютный агрегированный итог либо Cash Balance как отдельный второй итог.
|
||||||
|
При `portfolioSummary: null` карточка MUST показывать локальное нейтральное
|
||||||
|
состояние недоступности сводки, сохраняя метаданные счёта и возможность открыть
|
||||||
|
его. При доступной пустой сводке карточка MUST не выдавать отсутствие итогов
|
||||||
|
за временную ошибку.
|
||||||
|
|
||||||
#### Scenario: Пользователь открывает счёт из списка
|
#### Scenario: Пользователь открывает счёт из списка
|
||||||
- **WHEN** клиент успешно загрузил непустой список и User выбирает карточку счёта
|
- **WHEN** клиент успешно загрузил непустой список и User выбирает карточку счёта
|
||||||
- **THEN** клиент переходит на `/accounts/:accountId` с `id` выбранного счёта
|
- **THEN** клиент переходит на `/accounts/:accountId` с `id` выбранного счёта
|
||||||
|
|
||||||
#### Scenario: Список пуст
|
#### Scenario: Список пуст
|
||||||
- **WHEN** клиент получает успешный пустой массив
|
- **WHEN** клиент получает успешный полный пустой массив
|
||||||
- **THEN** клиент показывает штатное сообщение об отсутствии инвестиционных счетов T-Bank
|
- **THEN** клиент показывает штатное сообщение об отсутствии инвестиционных счетов T-Bank
|
||||||
|
|
||||||
#### Scenario: Список берётся из свежего frontend-кэша
|
#### Scenario: Список берётся из свежего frontend-кэша
|
||||||
@@ -75,11 +97,11 @@
|
|||||||
|
|
||||||
#### Scenario: Устаревший список загружается повторно
|
#### Scenario: Устаревший список загружается повторно
|
||||||
- **WHEN** User открывает список после истечения 60 секунд frontend-кэша и уже существует последний успешный список
|
- **WHEN** User открывает список после истечения 60 секунд frontend-кэша и уже существует последний успешный список
|
||||||
- **THEN** клиент оставляет этот список видимым во время нового запроса и ясно обозначает фоновое обновление
|
- **THEN** клиент оставляет этот список видимым во время нового запроса без индикации фонового обновления
|
||||||
|
|
||||||
#### Scenario: Ошибка фонового обновления не скрывает snapshot
|
#### Scenario: Ошибка фонового обновления не скрывает snapshot
|
||||||
- **WHEN** обновление устаревшего списка завершается ошибкой при наличии последнего успешного Client Cached Snapshot
|
- **WHEN** обновление устаревшего списка завершается временной ошибкой при наличии последнего успешного Client Cached Snapshot
|
||||||
- **THEN** клиент сохраняет snapshot видимым, безопасно сообщает о неуспешном обновлении и предоставляет применимое действие повторной загрузки
|
- **THEN** клиент сохраняет snapshot видимым без предупреждения и ручного повтора и восстанавливает получение данных автоматически
|
||||||
|
|
||||||
#### Scenario: Карточка ограничивает валютные итоги
|
#### Scenario: Карточка ограничивает валютные итоги
|
||||||
- **WHEN** доступная сводка счёта содержит итоги в трёх или более валютах
|
- **WHEN** доступная сводка счёта содержит итоги в трёх или более валютах
|
||||||
@@ -87,35 +109,49 @@
|
|||||||
|
|
||||||
#### Scenario: Недоступность сводки локальна карточке
|
#### Scenario: Недоступность сводки локальна карточке
|
||||||
- **WHEN** клиент получает список, в котором `portfolioSummary` одного счёта равна `null`
|
- **WHEN** клиент получает список, в котором `portfolioSummary` одного счёта равна `null`
|
||||||
- **THEN** он показывает временную недоступность только на этой карточке, не скрывает остальные карточки и сохраняет переход на детали недоступной сводки счёта
|
- **THEN** он показывает нейтральную недоступность только этой сводки, не скрывает остальные карточки и сохраняет переход на детали счёта
|
||||||
|
|
||||||
#### Scenario: Пустая сводка не является ошибкой
|
#### Scenario: Пустая сводка не является ошибкой
|
||||||
- **WHEN** клиент получает доступную `portfolioSummary` с пустым `totalsByCurrency`
|
- **WHEN** клиент получает доступную `portfolioSummary` с пустым `totalsByCurrency`
|
||||||
- **THEN** он показывает нейтральное состояние отсутствия финансовых итогов, а не состояние временной недоступности
|
- **THEN** он показывает нейтральное состояние отсутствия финансовых итогов, а не состояние временной ошибки
|
||||||
|
|
||||||
### Requirement: Клиентские состояния ошибки списка счетов
|
### Requirement: Клиентские состояния ошибки списка счетов
|
||||||
Клиент MUST NOT автоматически повторять неуспешный запрос списка. При `TBANK_NOT_CONNECTED` клиент SHALL показать объяснение отсутствия подключения и действие «Открыть настройки T-Bank». При `INVALID_TBANK_TOKEN` клиент SHALL показать объяснение недействительного token и то же действие. При `TBANK_UNAVAILABLE` клиент SHALL показать безопасное объяснение временной недоступности, действие повторной загрузки и действие открытия настроек T-Bank. При иной ошибке клиент MUST показать общий безопасный error-state только с действием повторной загрузки. Если последний успешный Client Cached Snapshot отсутствует, эти состояния MUST NOT показывать список; если snapshot существует во время фонового обновления, клиент MUST сохранить его видимым и показать соответствующее безопасное предупреждение и только применимые действия.
|
|
||||||
|
Клиент SHALL автоматически восстанавливать временно неуспешное чтение списка
|
||||||
|
по правилам `frontend-data-resilience` без кнопок обновления и повтора. При
|
||||||
|
`TBANK_NOT_CONNECTED` клиент MUST показать необходимость подключения и действие
|
||||||
|
открытия настроек T-Bank. При `INVALID_TBANK_TOKEN` клиент MUST показать
|
||||||
|
необходимость восстановить подключение и то же действие. Эти подтверждённые
|
||||||
|
состояния MUST скрывать личный список и MUST NOT запускать автоматические повторы.
|
||||||
|
|
||||||
|
При временной недоступности, включая `TBANK_UNAVAILABLE`, клиент MUST сохранять
|
||||||
|
успешный результат текущей границы доступа без предупреждений. Если результата
|
||||||
|
нет, после первичного ожидания клиент SHALL показать спокойную локальную
|
||||||
|
недоступность без технических подробностей. Неизвестная ошибка MUST получать
|
||||||
|
безопасное локальное представление; отсутствие известного кода MUST NOT
|
||||||
|
разрешать бесконечные повторы или обход доступа. Временный сбой MUST NOT
|
||||||
|
предлагать перенастройку действующего подключения как способ повторить загрузку.
|
||||||
|
|
||||||
#### Scenario: Подключение требуется
|
#### Scenario: Подключение требуется
|
||||||
- **WHEN** клиент получает `TBANK_NOT_CONNECTED`
|
- **WHEN** клиент получает `TBANK_NOT_CONNECTED`
|
||||||
- **THEN** клиент не показывает список и предлагает открыть настройки T-Bank
|
- **THEN** клиент не показывает список и предлагает открыть настройки T-Bank
|
||||||
|
|
||||||
#### Scenario: Известная ошибка не повторяется автоматически
|
#### Scenario: Известная ошибка не повторяется автоматически
|
||||||
- **WHEN** запрос списка завершается известной ошибкой
|
- **WHEN** запрос списка завершается подтверждённой ошибкой подключения или доступа, требующей действия пользователя
|
||||||
- **THEN** клиент не выполняет дополнительные запросы, пока User не выберет действие повторной загрузки
|
- **THEN** клиент не выполняет автоматических повторов и предлагает соответствующее действие вместо технической повторной загрузки
|
||||||
|
|
||||||
#### Scenario: Token требует внимания
|
#### Scenario: Token требует внимания
|
||||||
- **WHEN** клиент получает `INVALID_TBANK_TOKEN`
|
- **WHEN** клиент получает `INVALID_TBANK_TOKEN`
|
||||||
- **THEN** клиент не показывает список и предлагает открыть настройки T-Bank
|
- **THEN** клиент скрывает личный список и предлагает восстановить подключение в настройках T-Bank
|
||||||
|
|
||||||
#### Scenario: Временная ошибка T-Bank
|
#### Scenario: Временная ошибка T-Bank
|
||||||
- **WHEN** клиент получает `TBANK_UNAVAILABLE`
|
- **WHEN** клиент получает `TBANK_UNAVAILABLE` без доступного результата списка
|
||||||
- **THEN** клиент не показывает список и предлагает повторить загрузку либо открыть настройки T-Bank
|
- **THEN** клиент автоматически восстанавливает получение и после первичного ожидания показывает нейтральную недоступность без повторной загрузки и предложения перенастроить подключение
|
||||||
|
|
||||||
#### Scenario: Неизвестная ошибка загрузки
|
#### Scenario: Неизвестная ошибка загрузки
|
||||||
- **WHEN** клиент получает ошибку без известного кода списка счетов
|
- **WHEN** клиент получает ошибку без известного кода списка счетов и без доступного результата
|
||||||
- **THEN** клиент не показывает список и предлагает только повторить загрузку
|
- **THEN** клиент показывает безопасное нейтральное состояние без технического сообщения или кнопки повтора, применяя только допустимое ограниченное восстановление
|
||||||
|
|
||||||
#### Scenario: Известная ошибка при сохранённом snapshot
|
#### Scenario: Известная ошибка при сохранённом snapshot
|
||||||
- **WHEN** фоновое обновление списка с последним успешным Client Cached Snapshot получает `TBANK_UNAVAILABLE`
|
- **WHEN** фоновое обновление списка с последним успешным Client Cached Snapshot получает `TBANK_UNAVAILABLE`
|
||||||
- **THEN** клиент сохраняет snapshot видимым, сообщает о временной недоступности и предлагает повторить загрузку либо открыть настройки T-Bank
|
- **THEN** клиент сохраняет snapshot видимым без предупреждения, времени получения и ручных действий восстановления
|
||||||
|
|||||||
@@ -9,28 +9,125 @@
|
|||||||
## Requirements
|
## Requirements
|
||||||
|
|
||||||
### Requirement: Client Cached Snapshot остаётся доступным при обновлении Accounts и Portfolio
|
### Requirement: Client Cached Snapshot остаётся доступным при обновлении Accounts и Portfolio
|
||||||
Frontend MUST сохранять Client Cached Snapshot списка Brokerage Accounts или
|
|
||||||
Portfolio на экране, если для этого же набора данных уже был успешно получен
|
Frontend MUST сохранять последний успешный результат списка Brokerage Accounts,
|
||||||
ответ. Начальная загрузка без такого ответа может показывать блокирующее
|
Portfolio и других экранов чтения при фоновом обновлении и временной ошибке
|
||||||
состояние загрузки. Client Cached Snapshot MUST оставаться видимым во время
|
для того же пользователя, подключения и набора данных. Подтверждённый пустой
|
||||||
фонового обновления и после его ошибки; он не является server-side fallback и MUST NOT
|
результат MUST также считаться успешным. Смена счёта, инструмента, поискового
|
||||||
изменять или интерпретировать поле `Portfolio.isStale`.
|
запроса, страницы или применённого периода MUST NOT представлять данные прежней
|
||||||
|
выборки как результат новой.
|
||||||
|
|
||||||
|
Доступный результат MUST оставаться видимым без предупреждений о свежести,
|
||||||
|
времени получения, индикаторов фонового обновления и действий ручного повтора.
|
||||||
|
Frontend MUST NOT подменять внутренние признаки свежести и полноты, успешное
|
||||||
|
время источника или ошибку обновления только ради отсутствия их отображения.
|
||||||
|
Client Cached Snapshot MUST оставаться отличным от server-side fallback;
|
||||||
|
ошибка чтения MUST NOT изменять `Portfolio.isStale`.
|
||||||
|
|
||||||
|
Обновление MUST сохранять выбранные фильтры, период, открытые разделы, ввод,
|
||||||
|
фокус и положение просмотра, пока соответствующее содержимое существует.
|
||||||
|
При logout, смене подключения или подтверждённом отказе доступа личные данные
|
||||||
|
прежней границы MUST перестать отображаться; поздний результат прежней загрузки
|
||||||
|
MUST NOT возвращать их на экран.
|
||||||
|
|
||||||
#### Scenario: Список Brokerage Accounts обновляется в фоне
|
#### Scenario: Список Brokerage Accounts обновляется в фоне
|
||||||
- **WHEN** экран Accounts уже показывает Client Cached Snapshot и начинается
|
- **WHEN** экран Accounts уже показывает Client Cached Snapshot и начинается фоновое обновление того же списка
|
||||||
фоновое обновление того же списка
|
- **THEN** frontend оставляет список видимым без индикации обновления, времени получения и технических действий
|
||||||
- **THEN** frontend оставляет список видимым и показывает только
|
|
||||||
неблокирующий индикатор обновления
|
|
||||||
|
|
||||||
#### Scenario: Обновление Portfolio завершается ошибкой после успешного ответа
|
#### Scenario: Обновление Portfolio завершается ошибкой после успешного ответа
|
||||||
- **WHEN** экран Brokerage Account уже показывает Client Cached Snapshot
|
- **WHEN** экран Brokerage Account уже показывает Client Cached Snapshot Portfolio, а последующее обновление этого же Portfolio завершается временной ошибкой
|
||||||
Portfolio, а последующее обновление этого же Portfolio завершается ошибкой
|
- **THEN** frontend сохраняет Portfolio видимым без предупреждения и ручного повтора, а восстановление выполняется автоматически
|
||||||
- **THEN** frontend сохраняет Portfolio видимым, показывает локализованное
|
|
||||||
неблокирующее предупреждение о показе последних полученных данных и
|
|
||||||
предоставляет повторную попытку обновления
|
|
||||||
|
|
||||||
#### Scenario: Server-side fallback и client cached snapshot различаются
|
#### Scenario: Server-side fallback и client cached snapshot различаются
|
||||||
- **WHEN** backend возвращает Portfolio с `isStale` либо фоновое обновление
|
- **WHEN** backend возвращает Portfolio с `isStale` либо фоновое обновление Client Cached Snapshot завершается временной ошибкой
|
||||||
Client Cached Snapshot завершается ошибкой
|
- **THEN** frontend сохраняет доступные данные без технических сообщений и не подменяет один внутренний вид состояния другим
|
||||||
- **THEN** frontend отображает соответствующее server-side либо client-side
|
|
||||||
предупреждение независимо, не представляя один вид состояния другим
|
#### Scenario: Подтверждённая пустота переживает фоновую ошибку
|
||||||
|
- **WHEN** текущая выборка ранее успешно вернула полный пустой результат, а её обновление временно не удалось
|
||||||
|
- **THEN** подтверждённое пустое состояние сохраняется без предупреждения и не заменяется первичной загрузкой
|
||||||
|
|
||||||
|
#### Scenario: Изменились параметры выборки
|
||||||
|
- **WHEN** пользователь применил другой период или открыл другой счёт, а данных новой выборки ещё нет
|
||||||
|
- **THEN** экран показывает ожидание или недоступность новой выборки и не подписывает прежние суммы новым периодом или счётом
|
||||||
|
|
||||||
|
#### Scenario: Обновление не сбрасывает работу пользователя
|
||||||
|
- **WHEN** пользователь раскрыл раздел, выбрал фильтры или вводит данные, а фоновое чтение завершилось
|
||||||
|
- **THEN** обновление не сбрасывает эти действия, не переносит фокус и не возвращает пользователя в начало сохранившегося содержимого
|
||||||
|
|
||||||
|
#### Scenario: Изменился доступ к личным данным
|
||||||
|
- **WHEN** пользователь вышел, успешно сменил подключение либо получил подтверждённый отказ доступа к текущим данным
|
||||||
|
- **THEN** прежние личные данные скрываются, а позднее завершение старой загрузки не восстанавливает их
|
||||||
|
|
||||||
|
### Requirement: Временные сбои чтения восстанавливаются автоматически
|
||||||
|
|
||||||
|
Frontend SHALL автоматически повторять временно неуспешное чтение и восстанавливать
|
||||||
|
получение необходимых текущему экрану данных без ручного обновления. Повторы
|
||||||
|
одной попытки MUST иметь конечный предел и паузы, исключающие непрерывную
|
||||||
|
череду запросов. При исчерпании предела доступные данные SHALL сохраняться,
|
||||||
|
а при их отсутствии SHALL показываться локальная недоступность. Возвращение сети,
|
||||||
|
возвращение пользователя к открытому экрану и повторное открытие экрана MUST
|
||||||
|
возобновлять получение отсутствующих или требующих обновления данных без
|
||||||
|
перезагрузки страницы. Свежий полный результат MUST NOT требовать обращения
|
||||||
|
к источнику только из-за такого события.
|
||||||
|
|
||||||
|
Восстановление MUST учитывать сбой чтения результата и сбой самого получения
|
||||||
|
данных из источника, даже если чтение состояния завершилось успешно. Наблюдение
|
||||||
|
уже выполняющейся работы MUST NOT запускать её повторно. Уход с экрана MUST
|
||||||
|
прекращать новые попытки его восстановления; это не требует отменять уже начатую
|
||||||
|
работу источника. Автоматическое восстановление MUST NOT повторять запросы,
|
||||||
|
требующие исправления ввода, входа или восстановления доступа, и MUST NOT
|
||||||
|
переносить старые параметры в новую пользовательскую выборку.
|
||||||
|
|
||||||
|
#### Scenario: Кратковременный сбой чтения
|
||||||
|
- **WHEN** чтение текущей выборки временно не удалось, а следующая разрешённая автоматическая попытка успешна
|
||||||
|
- **THEN** экран самостоятельно показывает результат без ручного действия и без сообщения о сбое или восстановлении
|
||||||
|
|
||||||
|
#### Scenario: Источник завершил работу ошибкой
|
||||||
|
- **WHEN** чтение сохранённых данных успешно, но получение необходимых новых данных из источника временно не удалось
|
||||||
|
- **THEN** приложение применяет ограниченное автоматическое восстановление к неуспешной работе, а не считает успешное чтение доказательством её успеха
|
||||||
|
|
||||||
|
#### Scenario: Повторы исчерпаны
|
||||||
|
- **WHEN** временная недоступность сохраняется после конечного предела автоматических попыток
|
||||||
|
- **THEN** приложение прекращает серию повторов, сохраняет доступный результат либо локальную недоступность без бесконечной загрузки и ожидает следующего события восстановления
|
||||||
|
|
||||||
|
#### Scenario: Сеть или пользователь вернулись
|
||||||
|
- **WHEN** после временного сбоя восстановилась сеть либо пользователь вернулся к экрану с отсутствующим или требующим обновления результатом
|
||||||
|
- **THEN** получение данных возобновляется автоматически для текущей выборки и при успехе заменяет состояние недоступности содержимым
|
||||||
|
|
||||||
|
#### Scenario: Несколько событий восстановления совпали
|
||||||
|
- **WHEN** сеть восстановилась одновременно с возвращением пользователя на экран
|
||||||
|
- **THEN** приложение не запускает дублирующую работу получения одного набора данных
|
||||||
|
|
||||||
|
#### Scenario: Работа источника ещё выполняется
|
||||||
|
- **WHEN** приложение восстанавливает чтение состояния уже выполняющейся работы
|
||||||
|
- **THEN** оно продолжает получение её результата без повторного запуска той же работы
|
||||||
|
|
||||||
|
#### Scenario: Пользователь покинул экран
|
||||||
|
- **WHEN** пользователь ушёл со страницы с ожидающим восстановлением
|
||||||
|
- **THEN** новые попытки для покинутого экрана прекращаются, а уже начатая работа не изменяет содержимое другой выборки
|
||||||
|
|
||||||
|
#### Scenario: Ошибка требует действия пользователя
|
||||||
|
- **WHEN** подтверждены недействительное подключение, отсутствие доступа или некорректный ввод
|
||||||
|
- **THEN** автоматическая серия повторов прекращается и появляется соответствующее действие или локальная ошибка без технической кнопки повторной загрузки
|
||||||
|
|
||||||
|
### Requirement: Неполный результат не выдаётся за окончательный
|
||||||
|
|
||||||
|
Frontend MUST различать неизвестный результат, доступную часть данных и
|
||||||
|
подтверждённую пустоту. Неполные суммы и сравнения MUST NOT показываться как
|
||||||
|
окончательные или заменяться нулями. Доступные записи MAY оставаться видимыми,
|
||||||
|
но их список MUST NOT представляться полным при неподтверждённой полноте.
|
||||||
|
Состояние SHALL относиться к содержимому конкретной области, например
|
||||||
|
недоступному итогу, без отчёта о прогрессе синхронизации. Готовая область MUST
|
||||||
|
NOT ждать догрузки истории, которая не влияет на её результат.
|
||||||
|
|
||||||
|
#### Scenario: Итог ещё не определён
|
||||||
|
- **WHEN** часть данных, необходимых для суммы или сравнения, отсутствует
|
||||||
|
- **THEN** соответствующее значение обозначается как недоступное без вымышленного нуля или окончательного частичного итога
|
||||||
|
|
||||||
|
#### Scenario: Пустота ещё не подтверждена
|
||||||
|
- **WHEN** записи не получены и полнота выбранного периода неизвестна
|
||||||
|
- **THEN** экран не сообщает об отсутствии операций или выплат за этот период
|
||||||
|
|
||||||
|
#### Scenario: Период готов раньше остальной истории
|
||||||
|
- **WHEN** данные показанного периода полны, а не влияющая на него история ещё загружается
|
||||||
|
- **THEN** пользователь видит готовый результат без сообщения о догрузке остальной истории
|
||||||
|
|||||||
@@ -59,9 +59,11 @@ MUST NOT быть основным loading-состоянием.
|
|||||||
|
|
||||||
Frontend MUST сохранять уже доступное содержимое или элемент управления
|
Frontend MUST сохранять уже доступное содержимое или элемент управления
|
||||||
основным контекстом, когда выполняется пользовательское действие либо фоновое
|
основным контекстом, когда выполняется пользовательское действие либо фоновое
|
||||||
обновление Client Cached Snapshot. В этих состояниях frontend SHALL показывать
|
обновление Client Cached Snapshot. Явное действие пользователя SHALL иметь
|
||||||
компактный progress indicator рядом с соответствующим контекстом и MUST NOT
|
компактную индикацию ожидания рядом с соответствующим элементом управления.
|
||||||
заменять этот контекст skeleton placeholders.
|
Фоновое обновление при доступном результате MUST проходить без индикаторов,
|
||||||
|
технических сообщений и объявлений о ходе работы. В обоих случаях frontend
|
||||||
|
MUST NOT заменять уже доступный контекст skeleton placeholders.
|
||||||
|
|
||||||
#### Scenario: Выполняется пользовательское действие
|
#### Scenario: Выполняется пользовательское действие
|
||||||
|
|
||||||
@@ -71,4 +73,39 @@ Frontend MUST сохранять уже доступное содержимое
|
|||||||
#### Scenario: Обновляется уже показанный snapshot
|
#### Scenario: Обновляется уже показанный snapshot
|
||||||
|
|
||||||
- **WHEN** frontend обновляет данные при наличии видимого Client Cached Snapshot
|
- **WHEN** frontend обновляет данные при наличии видимого Client Cached Snapshot
|
||||||
- **THEN** frontend оставляет snapshot видимым, показывает компактную индикацию фонового обновления и не заменяет snapshot skeleton placeholders
|
- **THEN** frontend оставляет snapshot видимым без индикации фонового обновления и без замены snapshot skeleton placeholders
|
||||||
|
|
||||||
|
### Requirement: Первичное ожидание не становится бесконечной загрузкой
|
||||||
|
|
||||||
|
При отсутствии результата frontend SHALL сначала показывать структурное
|
||||||
|
ожидание соответствующей области. После неуспешного завершения получения
|
||||||
|
либо истечения ограниченного времени первичного ожидания область MUST переходить
|
||||||
|
в спокойное локализованное состояние недоступности без технических подробностей
|
||||||
|
и ручного повтора. Это состояние MUST NOT утверждать, что результат пустой,
|
||||||
|
или требовать перезагрузки страницы. Продолжающееся автоматическое восстановление
|
||||||
|
MUST NOT заставлять область постоянно переключаться между недоступностью и
|
||||||
|
skeleton. После успешного получения содержимое SHALL появляться автоматически.
|
||||||
|
|
||||||
|
Отсутствие результата одной области MUST NOT скрывать остальные доступные
|
||||||
|
области. Первичная загрузка MUST сохранять доступное обозначение занятости,
|
||||||
|
а состояние недоступности MUST NOT продолжать объявляться бесконечно занятым.
|
||||||
|
|
||||||
|
#### Scenario: Первый результат успешно получен
|
||||||
|
|
||||||
|
- **WHEN** экран ожидает первый результат и получает его в пределах первоначального ожидания
|
||||||
|
- **THEN** структурные placeholders сменяются содержимым либо подтверждённым пустым состоянием
|
||||||
|
|
||||||
|
#### Scenario: Первое получение данных не удалось
|
||||||
|
|
||||||
|
- **WHEN** у области нет результата и первоначальная загрузка завершилась ошибкой или превысила ограниченное время ожидания
|
||||||
|
- **THEN** область показывает нейтральную недоступность без кнопки повтора, вымышленных данных и бесконечного индикатора занятости
|
||||||
|
|
||||||
|
#### Scenario: Восстановление продолжается после недоступности
|
||||||
|
|
||||||
|
- **WHEN** область уже показывает недоступность и выполняется очередная разрешённая попытка восстановления
|
||||||
|
- **THEN** область сохраняет устойчивое состояние без мигания skeleton и автоматически показывает содержимое после успеха
|
||||||
|
|
||||||
|
#### Scenario: Один блок недоступен
|
||||||
|
|
||||||
|
- **WHEN** основной результат загружен, а дополнительный блок не получил данных
|
||||||
|
- **THEN** состояние недоступности ограничено этим блоком и не заменяет доступное содержимое страницы
|
||||||
|
|||||||
@@ -25,12 +25,20 @@ Frontend SHALL сбрасывать состояние route error после п
|
|||||||
- **THEN** frontend сбрасывает предыдущую runtime-ошибку и отображает целевой route
|
- **THEN** frontend сбрасывает предыдущую runtime-ошибку и отображает целевой route
|
||||||
|
|
||||||
### Requirement: Ожидаемые finance states не становятся route failures
|
### Requirement: Ожидаемые finance states не становятся route failures
|
||||||
Frontend SHALL сохранять локальное отображение и recovery actions известных состояний Brokerage Account, Portfolio и T-Bank connection. Эти состояния MUST NOT заменяться глобальным fallback.
|
|
||||||
|
Frontend SHALL сохранять локальное отображение известных состояний Brokerage
|
||||||
|
Account, Portfolio и T-Bank connection. Эти состояния MUST NOT заменяться
|
||||||
|
глобальным fallback. Временная ошибка фонового чтения MUST сохранять доступный
|
||||||
|
результат без предупреждения об устаревании, технической ошибки и ручного
|
||||||
|
повтора. При отсутствии результата SHALL показываться локальная недоступность
|
||||||
|
с автоматическим восстановлением. Подтверждённая необходимость входа,
|
||||||
|
восстановления подключения или выбора доступного счёта MUST сохранять понятное
|
||||||
|
объяснение и соответствующее действие, не маскируясь сохранёнными личными данными.
|
||||||
|
|
||||||
#### Scenario: Portfolio Snapshot устарел
|
#### Scenario: Portfolio Snapshot устарел
|
||||||
- **WHEN** frontend получает устаревший Portfolio Snapshot
|
- **WHEN** frontend получает устаревший Portfolio Snapshot в действующей границе доступа
|
||||||
- **THEN** frontend отображает данные Portfolio и существующее предупреждение об устаревании вместо глобального fallback
|
- **THEN** frontend отображает Portfolio без предупреждения об устаревании и без глобального fallback
|
||||||
|
|
||||||
#### Scenario: Ошибка T-Bank connection
|
#### Scenario: Ошибка T-Bank connection
|
||||||
- **WHEN** запрос T-Bank connection завершается известной ошибкой
|
- **WHEN** запрос T-Bank connection завершается известной ошибкой
|
||||||
- **THEN** frontend показывает существующее локальное состояние ошибки и доступное для него recovery action вместо глобального fallback
|
- **THEN** frontend сохраняет локальное состояние: временный сбой чтения восстанавливается автоматически, а подтверждённая необходимость действия пользователя сопровождается этим действием вместо глобального fallback
|
||||||
|
|||||||
@@ -0,0 +1,114 @@
|
|||||||
|
# frontend-user-feedback Specification
|
||||||
|
|
||||||
|
## Purpose
|
||||||
|
|
||||||
|
Определяет спокойную и понятную обратную связь во всех разделах WealthLedger:
|
||||||
|
пользователь видит финансовые данные и результат своих действий, а не состояние
|
||||||
|
внутреннего процесса получения данных.
|
||||||
|
|
||||||
|
## Requirements
|
||||||
|
|
||||||
|
### Requirement: Чтение данных не требует внимания к техническим состояниям
|
||||||
|
|
||||||
|
На экранах счетов, портфеля, операций, доходов, событий, инструментов, поиска,
|
||||||
|
карт и настроек подключения приложение MUST NOT показывать время получения
|
||||||
|
данных, признаки их технического устаревания, ход фонового обновления и сообщения
|
||||||
|
об успехе либо временной ошибке такого обновления. Приложение MUST NOT предоставлять
|
||||||
|
кнопки или иные действия ручного обновления и повторной загрузки, включая их
|
||||||
|
иконные варианты. Эти сведения MUST NOT переноситься в уведомления, подсказки
|
||||||
|
или объявления вспомогательных технологий. Даты операций, выплат, открытия
|
||||||
|
счёта и выбранных периодов MUST сохранять свой предметный смысл.
|
||||||
|
|
||||||
|
Запрет технических действий MUST NOT удалять применение фильтров, переходы между
|
||||||
|
страницами, поиск, отправку формы, вход, подключение банка или безопасную навигацию.
|
||||||
|
После неуспешного сохранения пользователь SHALL иметь возможность вновь отправить
|
||||||
|
сохранённый ввод обычным действием формы.
|
||||||
|
|
||||||
|
#### Scenario: Фоновая загрузка завершилась ошибкой
|
||||||
|
- **WHEN** на любом из перечисленных экранов уже есть доступный результат и его фоновое обновление временно не удалось
|
||||||
|
- **THEN** результат остаётся видимым без предупреждения, времени получения, индикатора, уведомления и действия ручного повтора
|
||||||
|
|
||||||
|
#### Scenario: Фоновая загрузка завершилась успешно
|
||||||
|
- **WHEN** приложение получает обновлённые данные без явного действия сохранения со стороны пользователя
|
||||||
|
- **THEN** содержимое обновляется без сообщения об успешной загрузке и без переноса фокуса
|
||||||
|
|
||||||
|
#### Scenario: Просмотр списка карт и операций карты
|
||||||
|
- **WHEN** временная ошибка возникает при обновлении уже показанных карт, сводки или операций выбранной карты
|
||||||
|
- **THEN** соответствующий результат остаётся доступным без технического предупреждения и ручного повтора, а действия работы с картой сохраняются
|
||||||
|
|
||||||
|
#### Scenario: Поиск или новый диапазон инструмента пока недоступен
|
||||||
|
- **WHEN** пользователь изменил поисковый запрос либо диапазон графика, а соответствующий результат ещё не получен
|
||||||
|
- **THEN** экран показывает ожидание или локальную недоступность нового результата без кнопки повтора и не выдаёт результат прежнего запроса или диапазона за новый
|
||||||
|
|
||||||
|
#### Scenario: Предметные даты остаются видимыми
|
||||||
|
- **WHEN** экран показывает дату операции, выплаты или выбранный период
|
||||||
|
- **THEN** эти даты остаются доступны независимо от отсутствия времени технического получения данных
|
||||||
|
|
||||||
|
### Requirement: Краткое уведомление подтверждает неочевидный результат действия
|
||||||
|
|
||||||
|
Приложение SHALL показывать краткое локализованное уведомление об успешном
|
||||||
|
явном действии пользователя, если после завершения на экране отсутствует
|
||||||
|
однозначное подтверждение результата. Если результат уже очевиден по состоянию
|
||||||
|
формы или содержимого, приложение MUST NOT дублировать его уведомлением.
|
||||||
|
Уведомление MUST описывать выполненное действие, а не внутренний процесс.
|
||||||
|
Ожидание действия MUST NOT представляться его успешным завершением.
|
||||||
|
|
||||||
|
#### Scenario: Результат действия иначе легко пропустить
|
||||||
|
- **WHEN** действие успешно завершилось, его форма закрылась, а оставшийся экран не подтверждает результат однозначно
|
||||||
|
- **THEN** пользователь получает одно краткое уведомление о выполненном действии
|
||||||
|
|
||||||
|
#### Scenario: Результат уже очевиден
|
||||||
|
- **WHEN** успешное сохранение оставляет на экране явное подтверждение результата
|
||||||
|
- **THEN** приложение не добавляет дублирующее уведомление
|
||||||
|
|
||||||
|
#### Scenario: Приём действия ещё не означает успех
|
||||||
|
- **WHEN** приложение только начало выполнение действия и окончательный результат неизвестен
|
||||||
|
- **THEN** оно не показывает уведомление об успешном завершении
|
||||||
|
|
||||||
|
### Requirement: Уведомления не мешают работе и не дублируются
|
||||||
|
|
||||||
|
Уведомления MUST быть доступны как текст, не полагаться только на цвет и не
|
||||||
|
перехватывать клавиатурный фокус. Подтверждение успеха SHALL автоматически
|
||||||
|
закрываться и позволять доступное ручное закрытие. Повторная обработка одного
|
||||||
|
результата MUST NOT создавать повторное уведомление. Приложение MUST ограничивать
|
||||||
|
число одновременно видимых уведомлений и MUST NOT создавать каскад сообщений
|
||||||
|
из-за фонового восстановления данных.
|
||||||
|
|
||||||
|
#### Scenario: Один результат обработан повторно
|
||||||
|
- **WHEN** приложение повторно обрабатывает результат того же пользовательского действия
|
||||||
|
- **THEN** пользователь не получает второе уведомление об этом результате
|
||||||
|
|
||||||
|
#### Scenario: Работа с клавиатурой продолжается
|
||||||
|
- **WHEN** уведомление появляется во время ввода или навигации с клавиатуры
|
||||||
|
- **THEN** текущий фокус сохраняется, текст уведомления доступен вспомогательным технологиям, а действие закрытия имеет понятное доступное имя
|
||||||
|
|
||||||
|
#### Scenario: Несколько действий завершились рядом по времени
|
||||||
|
- **WHEN** несколько различных действий успешно завершаются за короткое время
|
||||||
|
- **THEN** уведомления соблюдают конечный предел одновременного показа и не блокируют доступ к содержимому и действиям страницы
|
||||||
|
|
||||||
|
### Requirement: Ошибки действий и препятствия доступа остаются понятными
|
||||||
|
|
||||||
|
Ошибка ввода MUST показываться у соответствующего поля. При неуспешном
|
||||||
|
сохранении приложение MUST сохранять ввод и показывать понятную локальную ошибку
|
||||||
|
в контексте действия, не объявляя его успешным. Если продолжение требует входа,
|
||||||
|
подключения банка или другого действия пользователя, объяснение и применимое
|
||||||
|
действие MUST оставаться доступны в соответствующей области. Исчезающее
|
||||||
|
уведомление MUST NOT быть единственным способом сообщить такое препятствие.
|
||||||
|
Приложение MUST NOT самостоятельно повторять изменение пользовательских данных
|
||||||
|
только потому, что включено автоматическое восстановление чтения.
|
||||||
|
|
||||||
|
#### Scenario: Операция не сохранилась
|
||||||
|
- **WHEN** пользователь отправил форму операции, а сохранение завершилось ошибкой
|
||||||
|
- **THEN** введённые значения остаются в форме вместе с локальной ошибкой, обычное действие сохранения снова доступно и подтверждение успеха отсутствует
|
||||||
|
|
||||||
|
#### Scenario: Поле содержит недопустимое значение
|
||||||
|
- **WHEN** пользователь пытается отправить форму с недопустимым значением
|
||||||
|
- **THEN** ошибка относится к этому полю и не заменяется общим всплывающим уведомлением
|
||||||
|
|
||||||
|
#### Scenario: Требуется восстановить доступ
|
||||||
|
- **WHEN** приложение подтвердило необходимость входа или восстановления подключения
|
||||||
|
- **THEN** соответствующая область предлагает необходимое действие и сохраняет объяснение до устранения препятствия или ухода пользователя
|
||||||
|
|
||||||
|
#### Scenario: Ответ на изменение данных не получен
|
||||||
|
- **WHEN** соединение прервалось после отправки пользовательского изменения и результат неизвестен
|
||||||
|
- **THEN** приложение не объявляет успех и не повторяет изменение автоматически как обычную загрузку данных
|
||||||
@@ -117,105 +117,84 @@ Portfolio Snapshot является результатом наблюдения
|
|||||||
### Requirement: Состояния и ошибки Portfolio на клиенте
|
### Requirement: Состояния и ошибки Portfolio на клиенте
|
||||||
|
|
||||||
Клиент SHALL загружать Portfolio при открытии защищённого маршрута
|
Клиент SHALL загружать Portfolio при открытии защищённого маршрута
|
||||||
`/accounts/:accountId`. Он MUST использовать успешный ответ в течение
|
`/accounts/:accountId` и использовать успешный ответ в течение 30 секунд.
|
||||||
30 секунд, без automatic retry, polling или refetch при возврате фокуса.
|
Временные сбои и возвращение к экрану с требующими обновления данными SHALL
|
||||||
При загрузке без ранее полученного успешного ответа для этого же Brokerage
|
обрабатываться автоматическим восстановлением по `frontend-data-resilience`.
|
||||||
Account клиент MUST показывать структурное skeleton-состояние ожидаемого
|
Клиент MUST NOT предоставлять ручное обновление или повторную загрузку.
|
||||||
содержимого, включая сводку, без вымышленных сумм. Область загрузки MUST
|
|
||||||
иметь доступное обозначение занятости; skeleton MUST NOT быть интерактивным
|
|
||||||
или получать клавиатурный фокус.
|
|
||||||
|
|
||||||
Истечение срока свежести MUST NOT само по себе скрывать уже доступный
|
При первичной загрузке без успешного результата того же Brokerage Account
|
||||||
Client Cached Snapshot. Во время фонового обновления и после его ошибки
|
клиент MUST показывать структурный skeleton ожидаемого содержимого, включая
|
||||||
клиент MUST сохранять ранее полученные данные того же Portfolio, включая
|
сводку, без вымышленных сумм. Область MUST иметь доступное обозначение занятости;
|
||||||
валютные итоги и исходное `lastSuccessfulAt`. При обновлении клиент MUST
|
skeleton MUST NOT быть интерактивным или получать фокус. Неуспешное или
|
||||||
показывать компактную неблокирующую индикацию без замены данных skeleton.
|
затянувшееся первичное получение SHALL переходить в локальную недоступность
|
||||||
При ошибке обновления он MUST показывать локализованное неблокирующее
|
по `frontend-loading-presentation`, а не в бесконечную загрузку.
|
||||||
предупреждение о последних полученных данных и предоставлять действие
|
|
||||||
повторной попытки. Сохранённые данные MUST NOT считаться новым успешным
|
|
||||||
снимком или подтверждением текущей доступности Brokerage Account.
|
|
||||||
|
|
||||||
Клиент MUST показать штатное empty-состояние только при пустых `positions`
|
Истечение срока свежести MUST NOT скрывать доступный Client Cached Snapshot.
|
||||||
и `cashBalances`, без нулевых валютных карточек. Для показываемого состава
|
При обновлении и временной ошибке клиент MUST сохранять данные того же
|
||||||
Portfolio клиент MUST сохранять время успешного получения снимка
|
Portfolio, включая валютные итоги, без индикации фоновой работы, предупреждений,
|
||||||
`lastSuccessfulAt`, форматируемое в UTC. При `isStale: true` клиент MUST
|
времени получения и уведомлений. Исходное `lastSuccessfulAt` и `isStale` MUST
|
||||||
показывать Snapshot, его исходное время и нейтральное предупреждение
|
сохранять внутренний смысл: скрытие этих сведений MUST NOT делать сохранённый
|
||||||
о временной недоступности T-Bank. Это предупреждение само по себе MUST NOT
|
снимок новым успешным результатом или подтверждением текущего доступа.
|
||||||
добавлять действие ручного обновления. Server-side stale и ошибка фонового
|
Server-side stale и ошибка клиентского чтения MUST NOT подменять друг друга.
|
||||||
обновления Client Cached Snapshot MUST оставаться раздельными состояниями:
|
|
||||||
ошибка клиента MUST NOT менять или подменять `isStale`, а оба предупреждения
|
|
||||||
и действие повтора клиентского обновления MUST оставаться доступными при
|
|
||||||
одновременном наличии этих состояний.
|
|
||||||
|
|
||||||
При отсутствии ранее успешно полученного Client Cached Snapshot этого же
|
Клиент MUST показывать штатное empty-состояние только при подтверждённом полном
|
||||||
Portfolio и ответе `404` клиент MUST показать состояние недоступного счёта
|
результате с пустыми `positions` и `cashBalances`, без вымышленных нулевых карточек.
|
||||||
с действием возврата к списку счетов без действия повтора. При отсутствии
|
Неполный итог MUST NOT выдаваться за окончательный; доступные независимые данные
|
||||||
Snapshot и `TBANK_NOT_CONNECTED`, `INVALID_TBANK_TOKEN`, `TBANK_UNAVAILABLE`
|
MUST сохраняться на экране. При подтверждённом `404` клиент MUST скрыть личный
|
||||||
или иной ошибке клиент MUST показать безопасное error-состояние с доступными
|
Portfolio и предложить возврат к списку счетов. При `TBANK_NOT_CONNECTED` или
|
||||||
для ошибки действиями; действие повтора разрешено только для временной
|
`INVALID_TBANK_TOKEN` он MUST скрыть личные данные и предложить восстановление
|
||||||
и неизвестной ошибки.
|
подключения. Эти состояния MUST NOT маскироваться сохранённым снимком или
|
||||||
|
вызывать техническую повторную загрузку.
|
||||||
|
|
||||||
#### Scenario: Показ устаревшего Portfolio
|
#### Scenario: Показ устаревшего Portfolio
|
||||||
|
|
||||||
- **WHEN** клиент получает успешный ответ с `isStale: true`
|
- **WHEN** клиент получает успешный ответ с `isStale: true` в действующей границе доступа
|
||||||
- **THEN** клиент показывает позиции, остатки, валютные итоги, время
|
- **THEN** клиент показывает позиции, остатки и доступные валютные итоги без времени последнего снимка, предупреждения и ручного обновления
|
||||||
последнего успешного снимка и нейтральное предупреждение; само это
|
|
||||||
предупреждение не добавляет действие ручного обновления
|
|
||||||
|
|
||||||
#### Scenario: Недоступный счёт на клиенте
|
#### Scenario: Недоступный счёт на клиенте
|
||||||
|
|
||||||
- **WHEN** для текущего Portfolio отсутствует ранее успешно полученный
|
- **WHEN** клиент получает подтверждённый `404` текущего Portfolio
|
||||||
Client Cached Snapshot и клиент получает `404`
|
- **THEN** клиент не показывает личный Portfolio, включая ранее сохранённый, и предлагает вернуться к списку Brokerage Account без действия повтора
|
||||||
- **THEN** клиент не показывает Portfolio и предлагает вернуться к списку
|
|
||||||
Brokerage Account без действия повтора
|
|
||||||
|
|
||||||
#### Scenario: Первичная загрузка Portfolio
|
#### Scenario: Первичная загрузка Portfolio
|
||||||
|
|
||||||
- **WHEN** клиент ожидает Portfolio этого Brokerage Account без ранее
|
- **WHEN** клиент ожидает Portfolio этого Brokerage Account без ранее полученного успешного ответа
|
||||||
полученного успешного ответа
|
- **THEN** он показывает структурный skeleton, включая место сводки, с доступным обозначением загрузки, без вымышленных или нулевых сумм и без фокусируемых placeholders
|
||||||
- **THEN** он показывает структурный skeleton, включая место сводки,
|
|
||||||
с доступным обозначением загрузки, без вымышленных или нулевых сумм
|
|
||||||
и без фокусируемых placeholders
|
|
||||||
|
|
||||||
#### Scenario: Обновление после истечения срока свежести
|
#### Scenario: Обновление после истечения срока свежести
|
||||||
|
|
||||||
- **WHEN** срок свежести показанного Portfolio истёк и началось фоновое
|
- **WHEN** срок свежести показанного Portfolio истёк и началось фоновое обновление данных того же Brokerage Account
|
||||||
обновление данных того же Brokerage Account
|
- **THEN** клиент сохраняет прежние валютные итоги без индикации обновления и не заменяет доступный состав и сводку skeleton-состоянием
|
||||||
- **THEN** клиент сохраняет прежние валютные итоги и время их успешного
|
|
||||||
получения, показывает неблокирующую индикацию обновления и не заменяет
|
|
||||||
доступный состав и сводку skeleton-состоянием
|
|
||||||
|
|
||||||
#### Scenario: Ошибка обновления после успешного ответа
|
#### Scenario: Ошибка обновления после успешного ответа
|
||||||
|
|
||||||
- **WHEN** клиент уже показывает Client Cached Snapshot Portfolio,
|
- **WHEN** клиент уже показывает Client Cached Snapshot Portfolio, а обновление этих же данных завершается временной ошибкой
|
||||||
а обновление этих же данных завершается ошибкой
|
- **THEN** клиент сохраняет данные и суммы без предупреждения и действия повтора; ошибка не делает снимок свежим и не изменяет `isStale`
|
||||||
- **THEN** клиент сохраняет данные, суммы и время прежнего снимка,
|
|
||||||
показывает неблокирующее предупреждение и действие повтора;
|
|
||||||
ошибка не делает сохранённый снимок свежим и не изменяет `isStale`
|
|
||||||
|
|
||||||
#### Scenario: Ошибка клиентского обновления при server-side stale
|
#### Scenario: Ошибка клиентского обновления при server-side stale
|
||||||
|
|
||||||
- **WHEN** клиент показывает Portfolio с `isStale: true`, а фоновое
|
- **WHEN** клиент показывает Portfolio с `isStale: true`, а фоновое обновление этого же Portfolio завершается временной ошибкой
|
||||||
обновление этого же Portfolio завершается ошибкой
|
- **THEN** прежние суммы остаются видимыми без технических предупреждений и ручных действий, сохраняя различие внутренних состояний
|
||||||
- **THEN** прежние суммы и время остаются видимыми одновременно
|
|
||||||
с нейтральным server-side предупреждением, отдельным предупреждением
|
|
||||||
об ошибке клиентского обновления и его действием повтора
|
|
||||||
|
|
||||||
#### Scenario: Повторное обновление успешно
|
#### Scenario: Повторное обновление успешно
|
||||||
|
|
||||||
- **WHEN** после ошибки фонового обновления User запускает повторную
|
- **WHEN** после временной ошибки автоматическое восстановление получает успешный Portfolio Snapshot
|
||||||
попытку и получает успешный Portfolio Snapshot
|
- **THEN** до ответа прежние суммы остаются видимыми, затем клиент показывает новый результат без уведомления об обновлении и без переноса пользовательского фокуса
|
||||||
- **THEN** до ответа прежние суммы и время остаются видимыми, затем
|
|
||||||
клиент показывает значения и `lastSuccessfulAt` успешного ответа,
|
|
||||||
убирает предупреждение об ошибке клиентского обновления и показывает
|
|
||||||
server-side предупреждение только в соответствии с новым `isStale`
|
|
||||||
|
|
||||||
#### Scenario: Штатный пустой Portfolio на клиенте
|
#### Scenario: Штатный пустой Portfolio на клиенте
|
||||||
|
|
||||||
- **WHEN** успешно полученный Portfolio содержит пустые `positions`
|
- **WHEN** успешно полученный полный Portfolio содержит пустые `positions` и `cashBalances`
|
||||||
и `cashBalances`
|
- **THEN** клиент показывает существующее empty-состояние без валютных карточек с вымышленными нулевыми итогами
|
||||||
- **THEN** клиент показывает существующее empty-состояние без валютных
|
|
||||||
карточек с вымышленными нулевыми итогами
|
#### Scenario: Первичный Portfolio пока недоступен
|
||||||
|
|
||||||
|
- **WHEN** данных Portfolio нет, а первичное получение не удалось или превысило ограниченное время ожидания
|
||||||
|
- **THEN** клиент показывает нейтральную недоступность без кнопки повтора и автоматически заменяет её содержимым после успешного восстановления
|
||||||
|
|
||||||
|
#### Scenario: Требуется восстановить подключение
|
||||||
|
|
||||||
|
- **WHEN** клиент получает `TBANK_NOT_CONNECTED` или `INVALID_TBANK_TOKEN` при наличии сохранённого личного Portfolio
|
||||||
|
- **THEN** личные данные скрываются, а клиент предлагает необходимое действие подключения без технической повторной загрузки
|
||||||
|
|
||||||
### Requirement: Представление карточек позиций на клиенте
|
### Requirement: Представление карточек позиций на клиенте
|
||||||
Клиент MUST отображать `STOCK` и `BOND` отдельными секциями. Внутри каждой секции MUST сохраняться upstream-порядок позиций. Позиции иных типов MUST оставаться доступными в отдельной общей секции.
|
Клиент MUST отображать `STOCK` и `BOND` отдельными секциями. Внутри каждой секции MUST сохраняться upstream-порядок позиций. Позиции иных типов MUST оставаться доступными в отдельной общей секции.
|
||||||
|
|||||||
@@ -66,16 +66,45 @@
|
|||||||
- **THEN** система сохраняет подключение и отвечает текущим статусом
|
- **THEN** система сохраняет подключение и отвечает текущим статусом
|
||||||
|
|
||||||
### Requirement: Управление подключением в настройках
|
### Requirement: Управление подключением в настройках
|
||||||
Клиент SHALL показывать в настройках статус T-Bank connection, текст о необходимости read-only T-Bank Invest token, поле token и действие подключения либо замены. Для существующего подключения клиент MUST показывать действие удаления с modal-подтверждением. Во время создания, замены или удаления все действия секции подключения и действия modal MUST быть отключены. После успешного создания или замены клиент MUST очистить поле token и обновить статус; при ошибке token MUST остаться в поле.
|
|
||||||
|
Клиент SHALL показывать в настройках статус T-Bank connection, текст о
|
||||||
|
необходимости read-only T-Bank Invest token, поле token и действие подключения
|
||||||
|
либо замены. Для существующего подключения клиент MUST показывать действие
|
||||||
|
удаления с modal-подтверждением. Во время создания, замены или удаления все
|
||||||
|
действия секции подключения и действия modal MUST быть отключены. После
|
||||||
|
успешного создания или замены клиент MUST очистить поле token и обновить статус;
|
||||||
|
при ошибке token MUST остаться в поле.
|
||||||
|
|
||||||
|
Временный сбой чтения статуса SHALL восстанавливаться автоматически без кнопки
|
||||||
|
повтора и технического предупреждения. Пока первый статус неизвестен, клиент
|
||||||
|
MUST NOT показывать форму как подтверждённое отсутствие подключения: после
|
||||||
|
первичного ожидания SHALL отображаться нейтральная недоступность секции. Если
|
||||||
|
статус уже известен для текущей сессии, временный сбой его фонового чтения MUST
|
||||||
|
NOT скрывать доступную секцию или очищать ввод. Подтверждённое изменение
|
||||||
|
сессии или доступа MUST NOT маскироваться старым статусом.
|
||||||
|
|
||||||
|
Ошибки создания, замены и удаления MUST оставаться локальными, сохранять ввод
|
||||||
|
и возвращать применимые действия формы. Эти действия MUST NOT повторяться
|
||||||
|
автоматически как чтение статуса. Подтверждения успеха SHALL следовать
|
||||||
|
`frontend-user-feedback`: очевидное изменение статуса не требует дублирующего
|
||||||
|
уведомления, неочевидный результат получает одно краткое подтверждение.
|
||||||
|
|
||||||
#### Scenario: Пользователь подтверждает удаление
|
#### Scenario: Пользователь подтверждает удаление
|
||||||
- **WHEN** User подтверждает удаление в modal
|
- **WHEN** User подтверждает удаление в modal
|
||||||
- **THEN** клиент блокирует действия секции до результата и после успешного ответа показывает состояние без подключения
|
- **THEN** клиент блокирует действия секции до результата и после успешного ответа показывает состояние без подключения
|
||||||
|
|
||||||
#### Scenario: Ошибка загрузки статуса
|
#### Scenario: Ошибка загрузки статуса
|
||||||
- **WHEN** клиент не может получить статус подключения
|
- **WHEN** клиент временно не может получить статус подключения
|
||||||
- **THEN** клиент показывает отдельное error-состояние с возможностью повторить запрос и не показывает форму подключения
|
- **THEN** он автоматически восстанавливает чтение, сохраняет известный статус текущей сессии либо показывает нейтральную недоступность после первичного ожидания без формы и кнопки повтора
|
||||||
|
|
||||||
#### Scenario: Ошибка проверки token в клиенте
|
#### Scenario: Ошибка проверки token в клиенте
|
||||||
- **WHEN** создание или замена получает `INVALID_TBANK_TOKEN` либо `TBANK_UNAVAILABLE`
|
- **WHEN** создание или замена получает `INVALID_TBANK_TOKEN` либо `TBANK_UNAVAILABLE`
|
||||||
- **THEN** клиент показывает соответственно локализованное сообщение о token и правах либо о временной недоступности T-Bank, возвращает интерактивность и сохраняет введённый token
|
- **THEN** клиент показывает соответственно локализованное сообщение о token и правах либо о временной недоступности T-Bank в контексте формы, возвращает интерактивность и сохраняет введённый token
|
||||||
|
|
||||||
|
#### Scenario: Фоновое чтение не сбрасывает ввод
|
||||||
|
- **WHEN** пользователь редактирует token в доступной секции, а фоновое чтение статуса временно не удалось
|
||||||
|
- **THEN** ввод и доступная секция сохраняются без технического предупреждения или уведомления
|
||||||
|
|
||||||
|
#### Scenario: Удаление не удалось
|
||||||
|
- **WHEN** пользователь подтвердил удаление подключения, а действие завершилось ошибкой
|
||||||
|
- **THEN** клиент не показывает успех, сохраняет известный статус и локальную ошибку, возвращает применимые действия и не повторяет удаление автоматически
|
||||||
|
|||||||
Reference in New Issue
Block a user