После исчерпания автоматических повторов чтения на investment views появляются неблокирующее предупреждение «Не удалось обновить данные» и кнопка «Повторить», которая повторяет только GET затронутого запроса. Пока идут автоповторы, экраны остаются тихими.
Linked Issue
Closes WealthLedger/frontend#55 (AC 2, 3, 5; AC 1 и 4 закрыты в #133). Основание: specs WealthLedger/specs#79 (PR #80, develop 0469756). Audit 2026-10-11: FE-001, FE-002.
Решения владельца
Формулировка по specs: предупреждение и «Повторить» только после исчерпания автоповторов; тот же GET, не sync; успех снимает предупреждение без сообщения.
Экраны: Account, Accounts, Income, Operations, Events, секции деталей Stock/Bond. Поиск, график, карты и настройки подключения не тронуты.
Текст: «Не удалось обновить данные» + «Повторить», один на все экраны; время и статус источника не дублируются (их показывает SourceSyncStatus).
Changes
shared/api/read-failure.ts: isReadFailureExhausted (query в error, не потеря доступа и не UNAUTHORIZED) и readRetry([...queries]) (какие запросы упали, onRetry = refetch только упавших, retrying). Своего счётчика повторов нет: fetchAppRead делает 3 попытки внутри одного queryFn, TanStack retry: false, так что query в состоянии error = автоповторы исчерпаны. Во время ручного повтора isError остаётся true, предупреждение не мигает.
shared/ui/ReadRetry: ReadRetry (Alert, role="status", aria-live="polite") и ReadRetryButton (для StateView без данных); строки investment.readFailed, investment.retry.
Экраны: VM каждого экрана отдаёт readRetry, view встраивает его (Account: loaded/empty/error; Accounts: loaded/error; Income: loaded/error; Operations и Events: loaded/error рядом с существующим «Сбросить»; section() в instrument-details несёт retry своей секции, поэтому секции восстанавливаются независимо).
Потеря доступа (INVALID_TBANK_TOKEN, NOT_FOUND, TBANK_NOT_CONNECTED) и UNAUTHORIZED retry не получают, прежние действия сохранены.
Не тронуты: фильтры Events (frontend#63), InvestmentRefreshState/useScreenSync (нигде не подключены, удаление не в scope), Portfolio.isStale.
Verification
Новые route-тесты (RTL/MSW, реальные 1 с + 2 с автоповторов): кэш остаётся, видны предупреждение и «Повторить», в запросах 3 автоповтора + 1 на кнопку, предупреждение снимается; первичный сбой восстанавливается на месте; независимая секция Stock/Bond; Events, Operations, Income; NOT_FOUND и UNAUTHORIZED без кнопки; потеря связи в Accounts — только настройки. Юнит: классификатор, readRetry, ReadRetry, section().
Устаревшие «тихие» проверки отсутствия «Повторить» заменены положительными (Account, Income, Operations, Events, Stock, Bond).
Не проверено: реальный backend и браузер, ручная доступность (клавиатура, скринридер); story для ReadRetry не добавлялась; превью событий/операций/дохода на странице Account не показывают отдельный retry (экран опирается на запрос портфеля).
Breaking Changes (если есть)
Нет. API-контракт не менялся; меняется утверждённое UX-поведение (по решению владельца, specs#79).
## Summary
После исчерпания автоматических повторов чтения на investment views появляются неблокирующее предупреждение «Не удалось обновить данные» и кнопка «Повторить», которая повторяет только GET затронутого запроса. Пока идут автоповторы, экраны остаются тихими.
## Linked Issue
Closes WealthLedger/frontend#55 (AC 2, 3, 5; AC 1 и 4 закрыты в #133). Основание: specs WealthLedger/specs#79 (PR #80, develop `0469756`). Audit 2026-10-11: FE-001, FE-002.
## Решения владельца
- Формулировка по specs: предупреждение и «Повторить» только после исчерпания автоповторов; тот же GET, не sync; успех снимает предупреждение без сообщения.
- Экраны: Account, Accounts, Income, Operations, Events, секции деталей Stock/Bond. Поиск, график, карты и настройки подключения не тронуты.
- Текст: «Не удалось обновить данные» + «Повторить», один на все экраны; время и статус источника не дублируются (их показывает `SourceSyncStatus`).
## Changes
- `shared/api/read-failure.ts`: `isReadFailureExhausted` (query в `error`, не потеря доступа и не `UNAUTHORIZED`) и `readRetry([...queries])` (какие запросы упали, `onRetry` = `refetch` только упавших, `retrying`). Своего счётчика повторов нет: `fetchAppRead` делает 3 попытки внутри одного `queryFn`, TanStack `retry: false`, так что query в состоянии `error` = автоповторы исчерпаны. Во время ручного повтора `isError` остаётся true, предупреждение не мигает.
- `shared/ui/ReadRetry`: `ReadRetry` (Alert, `role="status"`, `aria-live="polite"`) и `ReadRetryButton` (для `StateView` без данных); строки `investment.readFailed`, `investment.retry`.
- Экраны: VM каждого экрана отдаёт `readRetry`, view встраивает его (Account: loaded/empty/error; Accounts: loaded/error; Income: loaded/error; Operations и Events: loaded/error рядом с существующим «Сбросить»; `section()` в `instrument-details` несёт retry своей секции, поэтому секции восстанавливаются независимо).
- Потеря доступа (`INVALID_TBANK_TOKEN`, `NOT_FOUND`, `TBANK_NOT_CONNECTED`) и `UNAUTHORIZED` retry не получают, прежние действия сохранены.
- Не тронуты: фильтры Events (frontend#63), `InvestmentRefreshState`/`useScreenSync` (нигде не подключены, удаление не в scope), `Portfolio.isStale`.
## Verification
- Новые route-тесты (RTL/MSW, реальные 1 с + 2 с автоповторов): кэш остаётся, видны предупреждение и «Повторить», в запросах 3 автоповтора + 1 на кнопку, предупреждение снимается; первичный сбой восстанавливается на месте; независимая секция Stock/Bond; Events, Operations, Income; NOT_FOUND и UNAUTHORIZED без кнопки; потеря связи в Accounts — только настройки. Юнит: классификатор, `readRetry`, `ReadRetry`, `section()`.
- Устаревшие «тихие» проверки отсутствия «Повторить» заменены положительными (Account, Income, Operations, Events, Stock, Bond).
- `npm run verify`: `openapi:check`, `tsc -b`, eslint `--max-warnings=0`, test:lint, vitest coverage (77 файлов / 580 тестов), knip, depcruise ×2, build, storybook build — exit 0.
- Не проверено: реальный backend и браузер, ручная доступность (клавиатура, скринридер); story для `ReadRetry` не добавлялась; превью событий/операций/дохода на странице Account не показывают отдельный retry (экран опирается на запрос портфеля).
## Breaking Changes (если есть)
Нет. API-контракт не менялся; меняется утверждённое UX-поведение (по решению владельца, specs#79).
Blocking a user prevents them from interacting with repositories, such as opening or commenting on pull requests or issues. Learn more about blocking a user.
Summary
После исчерпания автоматических повторов чтения на investment views появляются неблокирующее предупреждение «Не удалось обновить данные» и кнопка «Повторить», которая повторяет только GET затронутого запроса. Пока идут автоповторы, экраны остаются тихими.
Linked Issue
Closes WealthLedger/frontend#55 (AC 2, 3, 5; AC 1 и 4 закрыты в #133). Основание: specs WealthLedger/specs#79 (PR #80, develop
0469756). Audit 2026-10-11: FE-001, FE-002.Решения владельца
SourceSyncStatus).Changes
shared/api/read-failure.ts:isReadFailureExhausted(query вerror, не потеря доступа и неUNAUTHORIZED) иreadRetry([...queries])(какие запросы упали,onRetry=refetchтолько упавших,retrying). Своего счётчика повторов нет:fetchAppReadделает 3 попытки внутри одногоqueryFn, TanStackretry: false, так что query в состоянииerror= автоповторы исчерпаны. Во время ручного повтораisErrorостаётся true, предупреждение не мигает.shared/ui/ReadRetry:ReadRetry(Alert,role="status",aria-live="polite") иReadRetryButton(дляStateViewбез данных); строкиinvestment.readFailed,investment.retry.readRetry, view встраивает его (Account: loaded/empty/error; Accounts: loaded/error; Income: loaded/error; Operations и Events: loaded/error рядом с существующим «Сбросить»;section()вinstrument-detailsнесёт retry своей секции, поэтому секции восстанавливаются независимо).INVALID_TBANK_TOKEN,NOT_FOUND,TBANK_NOT_CONNECTED) иUNAUTHORIZEDretry не получают, прежние действия сохранены.InvestmentRefreshState/useScreenSync(нигде не подключены, удаление не в scope),Portfolio.isStale.Verification
readRetry,ReadRetry,section().npm run verify:openapi:check,tsc -b, eslint--max-warnings=0, test:lint, vitest coverage (77 файлов / 580 тестов), knip, depcruise ×2, build, storybook build — exit 0.ReadRetryне добавлялась; превью событий/операций/дохода на странице Account не показывают отдельный retry (экран опирается на запрос портфеля).Breaking Changes (если есть)
Нет. API-контракт не менялся; меняется утверждённое UX-поведение (по решению владельца, specs#79).