docs(specs): archive api contract resilience remediation

This commit is contained in:
2026-08-24 00:51:06 +03:00
parent 6e20cdffaf
commit 800450d075
8 changed files with 386 additions and 0 deletions
@@ -0,0 +1,36 @@
# frontend-data-resilience Specification
## Purpose
Определяет, когда frontend сохраняет последний успешный ответ на экране и как
сообщает пользователю о неудачном фоновом обновлении без искажения доменных
состояний Portfolio.
## Requirements
### Requirement: Client Cached Snapshot остаётся доступным при обновлении Accounts и Portfolio
Frontend MUST сохранять Client Cached Snapshot списка Brokerage Accounts или
Portfolio на экране, если для этого же набора данных уже был успешно получен
ответ. Начальная загрузка без такого ответа может показывать блокирующее
состояние загрузки. Client Cached Snapshot MUST оставаться видимым во время
фонового обновления и после его ошибки; он не является server-side fallback и MUST NOT
изменять или интерпретировать поле `Portfolio.isStale`.
#### 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 отображает соответствующее server-side либо client-side
предупреждение независимо, не представляя один вид состояния другим
@@ -123,3 +123,40 @@
#### Scenario: Выход из настроек
- **WHEN** пользователь нажимает logout на `/settings`
- **THEN** клиент очищает локальную сессию и cache и направляет пользователя на `/login` независимо от результата сетевого запроса
### Requirement: Единый HTTP contract успешных auth endpoints
Успешные `POST /api/v1/auth/register`, `POST /api/v1/auth/login` и
`POST /api/v1/auth/refresh` MUST отвечать HTTP `200`; опубликованный
OpenAPI-документ, зафиксированный frontend snapshot и сгенерированные
transport types MUST описывать этот же status. Каждая операция сохраняет свои
существующие payload, refresh-cookie и session semantics. Logout MUST
продолжать отвечать `204`.
#### Scenario: Успешная регистрация возвращает контрактный status
- **WHEN** пользователь отправляет новую валидную регистрацию
- **THEN** система устанавливает refresh-cookie, возвращает профиль и access
token с HTTP `200`
#### Scenario: Успешный login или refresh возвращает контрактный status
- **WHEN** пользователь успешно входит либо восстанавливает Session
- **THEN** система устанавливает или заменяет refresh-cookie, возвращает
профиль и access token с HTTP `200`
### Requirement: Клиент контролируемо завершает неуспешный refresh
Frontend MUST обрабатывать HTTP и транспортную ошибку общего refresh flow без
необработанного отклонения Promise. При неуспешном cold-start refresh frontend
MUST завершить инициализацию как неавторизованный, не сохраняя access token
или профиль. При неуспешном refresh после защищённого запроса frontend MUST
очистить in-memory session и query cache перед existing navigation to login.
#### Scenario: Cold-start refresh завершается транспортной ошибкой
- **WHEN** приложение запускается без access token и refresh запрос не может
получить транспортный response
- **THEN** frontend завершается в готовом неавторизованном состоянии без
необработанного отклонения Promise и показывает обычный public/login flow
#### Scenario: Повторный refresh после protected 401 завершается транспортной ошибкой
- **WHEN** защищённый API отвечает `401`, а единственный serialised refresh
завершается транспортной ошибкой
- **THEN** frontend очищает in-memory session и query cache и направляет User
в существующий login flow без необработанного отклонения Promise