121 lines
8.6 KiB
Markdown
121 lines
8.6 KiB
Markdown
## Контекст
|
||
|
||
Мотивация изложена в `proposal.md`, а поведенческий contract — в delta specs.
|
||
Backend документирует `200` через OpenAPI decorators, но Nest использует
|
||
стандартный `201` для трёх auth `POST` handlers, поскольку их runtime status
|
||
не задан явно. Runtime OpenAPI verifier сравнивает два документа, поэтому не
|
||
может обнаружить это расхождение HTTP responses.
|
||
|
||
Во frontend Accounts и Account view models выбирают блокирующий loading/error
|
||
state до проверки cached query data. У auth provider два пути refresh:
|
||
cold start напрямую вызывает API без `catch`, а общий refresh может отклонить
|
||
Promise при повторе защищённого запроса.
|
||
|
||
## Цели и исключения
|
||
|
||
**Цели:**
|
||
|
||
- Согласовать фактические auth success responses, OpenAPI, snapshot и
|
||
generated types на `200` с детерминированным regression gate без Prisma или
|
||
базы данных.
|
||
- Отображать существующие данные Accounts и Portfolio во время refetch и после
|
||
его ошибки с доступным локализованным warning и retry action.
|
||
- Дать cold start и повтору защищённого запроса единый non-throwing результат
|
||
refresh, сохранив текущие serialization и защиту routes.
|
||
- Фиксировать active remediation и обновлять feature/development документацию
|
||
только фактически поставленным поведением.
|
||
|
||
**Исключения:**
|
||
|
||
- Исправлять Prisma migration/e2e infrastructure или создавать workspace-wide
|
||
verifier, отложенный как WL-P2-05 и WL-P2-13.
|
||
- Менять refresh-cookie attributes, token lifetime, session rotation,
|
||
unauthorised-error codes, auth routes, cache TTL, refetch triggers или
|
||
backend Portfolio fallback policy.
|
||
- Распространять Client Cached Snapshot на постраничные operations/events,
|
||
чьи cursor и filters могут определять иной result set.
|
||
|
||
## Решения
|
||
|
||
### Явно установить `200` для трёх auth handlers успешного ответа
|
||
|
||
Handlers register, login и refresh получают явный HTTP `200`, сохраняя
|
||
существующие `ApiOkResponse` и payload/cookie code. Frontend artifacts остаются
|
||
сгенерированными из backend document: запускается штатный sync workflow, а
|
||
artifact коммитится только если этот workflow создаёт изменение; ручное
|
||
редактирование generated schema запрещено.
|
||
|
||
Небольшой независимый от БД backend test проверяет status metadata каждого
|
||
handler. Он защищает decorator, управляющий реальным Nest output, пока
|
||
Prisma-backed e2e gate остаётся deferred. Существующие e2e assertions меняются
|
||
с `201` на `200`, но не являются terminal evidence до восстановления Prisma
|
||
bootstrap.
|
||
|
||
Отклонённые альтернативы: неявный `201` потребовал бы большего перехода
|
||
snapshot/types и противоречил бы согласованному единообразному contract;
|
||
опора только на runtime OpenAPI comparison повторила бы исходную blind spot.
|
||
|
||
### Определять представление refetch по наличию данных, а не `isFetching` или `isError`
|
||
|
||
Accounts и Account view models сначала определяют наличие Client Cached
|
||
Snapshot. Без данных они сохраняют текущие loading, error и empty views. При
|
||
наличии данных они возвращают loaded/empty presentation с опциональной
|
||
информацией об обновлении и его ошибке. Page components сначала отображают
|
||
данные, добавляют неблокирующий progress indicator во время fetch и передают
|
||
локализованное warning/retry action в loaded presentation после ошибки.
|
||
|
||
Account view сохраняет backend warning `Portfolio.isStale` отдельно от client
|
||
warning об ошибке refresh. Оба могут отображаться, когда независимо истинны.
|
||
Новая терминология документируется в `CONTEXT.md`; это не новое API field и
|
||
не интерпретация server freshness.
|
||
|
||
Отклонённые альтернативы: полный error/loading view после refetch скрывает уже
|
||
полезные финансовые данные; применение правила к operations/events могло бы
|
||
показать прошлую cursor/filter page как запрошенный результат.
|
||
|
||
### Сделать общий refresh возвращающим `false` при любом неуспешном исходе
|
||
|
||
Auth provider централизует успешное применение session и локальную очистку
|
||
session. Single-flight refresh function перехватывает transport rejection API,
|
||
а также no-data/HTTP failures, очищает token, profile и React Query cache и
|
||
возвращает `false`; она всегда освобождает in-flight Promise. Cold start
|
||
использует эту общую function и устанавливает `ready` в `finally`.
|
||
`authenticatedFetch` сохраняет existing one-retry behavior: при `false` он
|
||
возвращает исходный `401` после очистки, позволяя protected-route state
|
||
перенаправить на login.
|
||
|
||
Отклонённые альтернативы: перехват только mount effect оставляет 401 retry
|
||
path способным отклонить Promise; добавление третьего startup error state
|
||
меняет согласованный anonymous/login recovery flow.
|
||
|
||
## Риски и компромиссы
|
||
|
||
- [Metadata test не является HTTP e2e test] → WL-P2-05 остаётся deferred,
|
||
существующие e2e expectations обновляются, а реальное HTTP coverage станет
|
||
обязательным после выполнения Prisma trigger.
|
||
- [Ошибка refresh утрачивает in-memory session] → после cold start браузер не
|
||
имеет действительного access token; очистка state предотвращает неоднозначный
|
||
protected UI и следует существующему 401 recovery behavior.
|
||
- [Client warning и backend stale warning могут сосуществовать] → каждому
|
||
назначается отдельное localized message и проверяется их независимый render.
|
||
- [Generated sync может затронуть frontend artifacts] → он запускается явно
|
||
только после backend contract change, а итоговый diff проверяется до принятия.
|
||
|
||
## План изменений
|
||
|
||
1. Сначала добавить regression tests, затем сделать backend status явным и
|
||
обновить существующие e2e assertions, не заявляя, что deferred e2e gate
|
||
прошёл.
|
||
2. Обновить OpenAPI artifacts через штатную sync command, проверить
|
||
согласованность runtime document и generated client и оставить только
|
||
намеренный итоговый diff.
|
||
3. Добавить observable frontend tests для состояний refetch cached data и
|
||
ошибок refresh, затем отрефакторить view models, pages, localized copy и
|
||
auth provider до их прохождения.
|
||
4. Обновить feature docs и remediation registry, выполнить применимые
|
||
non-mutating gates и OpenSpec verification до archive.
|
||
|
||
Rollback затрагивает только код: отмена затронутых commits восстанавливает
|
||
предыдущий status/UX; data migration, dependency change и очистка persisted
|
||
state не нужны.
|