feat(investments): warn and offer retry after exhausted read retries (WealthLedger/frontend#55) #136

Merged
codex-bot merged 7 commits from fix/55-read-failure-retry into develop 2026-11-03 09:49:08 +03:00
Owner

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).

## 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).
codex-bot added 7 commits 2026-11-03 08:46:56 +03:00
codex-bot merged commit 8ce1e8e444 into develop 2026-11-03 09:49:08 +03:00
codex-bot deleted branch fix/55-read-failure-retry 2026-11-03 09:49:09 +03:00
Sign in to join this conversation.
No Reviewers
1 Participants
Notifications
Due Date
No due date set.
Dependencies

No dependencies set.

Reference: WealthLedger/frontend#136