Files

121 lines
8.6 KiB
Markdown
Raw Permalink Blame History

This file contains ambiguous Unicode characters
This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.
## Контекст
Мотивация изложена в `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 не нужны.