Files
codex-bot 0469756d3b
Specs security / security (push) Successful in 7s
Specs verify / verify (push) Successful in 10s
spec: allow warning and retry after exhausted read retries (WealthLedger/specs#79) (#80)
2026-11-03 07:45:09 +03:00

169 lines
19 KiB
Markdown

# frontend-data-resilience Specification
## Purpose
Определяет, когда frontend сохраняет последний успешный ответ на экране и как
сообщает пользователю о неудачном фоновом обновлении без искажения доменных
состояний Portfolio.
## 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`.
Состояние источника из `meta` — время последнего успешного результата, признак
устаревания, исход последней часовой попытки и неполнота — MUST представляться
текстом либо доступно именованным элементом, а не только цветом, и MUST
различать отсутствие попытки, выполнение, полный успех, частичный успех и
неуспех. Это состояние принадлежит источнику данных, а не собственному чтению
клиента, и MUST NOT требовать от пользователя действия.
Обновление MUST сохранять выбранные фильтры, период, открытые разделы, ввод,
фокус и положение просмотра, пока соответствующее содержимое существует.
При logout, смене подключения или подтверждённом отказе доступа личные данные
прежней границы MUST перестать отображаться; поздний результат прежней загрузки
MUST NOT возвращать их на экран.
#### Scenario: Список Brokerage Accounts обновляется в фоне
- **WHEN** экран Accounts уже показывает Client Cached Snapshot и начинается фоновое обновление того же списка
- **THEN** frontend оставляет список видимым без индикации собственного чтения и технических действий
#### Scenario: Resource сохраняется после неуспешной часовой попытки
- **WHEN** response содержит полный `data` и `meta`, обозначающий неуспех последней часовой попытки
- **THEN** frontend сохраняет `data` и его исходное время видимыми и отдельно обозначает неуспех попытки, не предлагая запуск повторного получения данных из источника
#### 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** прежние личные данные скрываются, а позднее завершение старой загрузки не восстанавливает их
### Requirement: Временные сбои чтения восстанавливаются автоматически
Frontend SHALL автоматически повторять временно неуспешное чтение и восстанавливать
получение необходимых текущему экрану данных без ручного обновления. Повторы
одной попытки MUST иметь конечный предел и паузы, исключающие непрерывную
череду запросов. При исчерпании предела доступные данные SHALL сохраняться,
а при их отсутствии SHALL показываться локальная недоступность. На экранах
Account, Accounts, Income, Operations, Events и секций деталей инструмента при исчерпании предела
frontend SHALL дополнительно показывать неблокирующее локализованное предупреждение
о неудачном обновлении и действие «Повторить» рядом с затронутым результатом либо
локальной недоступностью. Действие MUST повторять только чтение (GET) затронутого
запроса, не запускать получение данных из источника и не менять выбранные
фильтры, период, открытые разделы и ввод; успешное чтение MUST снимать
предупреждение и MUST NOT сообщать об успехе. Предупреждение MUST NOT дублировать
состояние источника из `meta` и MUST NOT изменять `Portfolio.isStale`. На остальных
экранах чтения, включая поиск, диапазон графика, карты и настройки подключения,
предупреждение и действие повтора MUST NOT показываться. Возвращение сети,
возвращение пользователя к открытому экрану и повторное открытие экрана MUST
возобновлять получение отсутствующих или требующих обновления данных без
перезагрузки страницы. Свежий полный результат MUST NOT требовать обращения
к источнику только из-за такого события.
Восстановление MUST учитывать сбой чтения результата и сбой самого получения
данных из источника, даже если чтение состояния завершилось успешно. Наблюдение
уже выполняющейся работы MUST NOT запускать её повторно. Уход с экрана MUST
прекращать новые попытки его восстановления; это не требует отменять уже начатую
работу источника. Автоматическое восстановление MUST NOT повторять запросы,
требующие исправления ввода, входа или восстановления доступа, и MUST NOT
переносить старые параметры в новую пользовательскую выборку.
#### Scenario: Кратковременный сбой чтения
- **WHEN** чтение текущей выборки временно не удалось, а следующая разрешённая автоматическая попытка успешна
- **THEN** экран самостоятельно показывает результат без ручного действия и без сообщения о сбое или восстановлении
#### Scenario: Источник завершил работу ошибкой
- **WHEN** чтение сохранённых данных успешно, но получение необходимых новых данных из источника временно не удалось
- **THEN** приложение применяет ограниченное автоматическое восстановление к неуспешной работе, а не считает успешное чтение доказательством её успеха
#### Scenario: Повторы исчерпаны
- **WHEN** временная недоступность сохраняется после конечного предела автоматических попыток
- **THEN** приложение прекращает серию повторов, сохраняет доступный результат либо локальную недоступность без бесконечной загрузки и ожидает следующего события восстановления
#### Scenario: Повторы исчерпаны при сохранённом результате
- **WHEN** на экране Account, Accounts, Income, Operations, Events либо в секции деталей инструмента автоматические повторы исчерпаны, а ранее полученный результат остаётся доступным
- **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** пользователь видит готовый результат без сообщения о догрузке остальной истории