Files
specs/openspec/changes/consolidate-tbank-connection-resolution/design.md
T

176 lines
11 KiB
Markdown
Raw 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.
# consolidate-tbank-connection-resolution — Design
## Context
Backend T-Bank flows сейчас повторяют один knowledge cluster: чтение сохранённой
T-Bank connection по User, расшифровку token, запрос открытых accounts,
отсечение неподдерживаемых account types, проверку accountId для account-scoped
flows и перевод `INVALID_TBANK_TOKEN` в публичную ошибку API. Полная
account-scoped последовательность есть в Portfolio, Account Ledger и Future Cash
Events; список Brokerage Accounts использует тот же persisted connection и
supported-account rules без проверки конкретного accountId; T-Bank connection
flow отдельно валидирует candidate token и использует то же crypto/error
knowledge.
Поставленное поведение менять нельзя. Для account-scoped read flows отсутствие
connection остаётся `409 TBANK_NOT_CONNECTED`, invalid token остаётся
`400 INVALID_TBANK_TOKEN`, недоступный или неподдерживаемый account остаётся
`404`, а upstream availability errors сохраняют текущие `503`/throw-through
semantics. Account Ledger уже документирует, что connection и account access
проверяются до выдачи cached page; этот порядок должен сохраниться.
Ограничения backend: NestJS module/provider model, Node 22, public HTTP API
`/api/v1`, generated OpenAPI как frontend contract authority, canonical gate
`npm ci && npm run verify`.
## Goals / Non-Goals
**Goals:**
- Сконцентрировать persisted T-Bank connection lookup, token decrypt,
supported-account policy, account access check и invalid-token translation в
одном backend module.
- Сохранить public API behavior, DTO shape, routes, status codes и Problem
Details codes.
- Сохранить service-specific responsibilities: Portfolio normalizes portfolio
data and snapshot fallback, Account Ledger maps operations and pagination,
Future Cash Events calculates projected events, Brokerage Accounts maps the
account list.
- Сделать новый module осмысленной test surface для shared access behavior,
сократив дублирование tests в feature services до orchestration и
feature-specific behavior.
**Non-Goals:**
- Новые T-Bank account types или изменение supported-account semantics.
- Frontend changes, OpenAPI snapshot changes, generated client updates или
runtime contract changes.
- Изменения Portfolio snapshot cache, Account Ledger page cache, Upcoming
Events dividend/instrument caches или metadata cache semantics.
- Durable storage, token versioning, account history или cache invalidation
after token replacement.
- Замена T-Bank gRPC client или добавление другой integration library.
## Decisions
**D1. Ввести один T-Bank access module с двумя public use cases.**
Module предоставляет list-oriented use case для supported Brokerage Accounts и
account-scoped use case для flows, которым нужен доступ к конкретному Brokerage
Account. Module владеет persisted connection lookup, token decrypt,
`getOpenAccounts`, supported-account filtering и inaccessible-account decision.
Feature services получают resolved token/account context или supported account
list и не повторяют access sequence.
*Alternative:* извлечь только маленький `supportedAccounts` constant и crypto
helper. Отклонено: access ordering и error translation остаются размазанными по
services, поэтому future account policy changes всё ещё могут разойтись.
**D2. Оборачивать account-scoped flow execution для централизованного
invalid-token translation.** Простой `resolveAccount(userId, accountId) ->
{ token, account }` не покрывает invalid-token errors, которые могут быть
выброшены более поздними T-Bank calls в том же service flow. Поэтому
account-scoped use case выполняет feature handler внутри translation boundary
access module. Missing connection, account lookup и handler failures используют
одно правило translation для `INVALID_TBANK_TOKEN`; unrelated exceptions
сохраняют существующее propagation.
*Alternative:* оставить `try/catch INVALID_TBANK_TOKEN` в каждом feature service
после shared resolver. Отклонено: это уменьшает duplication, но оставляет
behavior-critical string comparison в нескольких call sites.
**D3. Оставить T-Bank connection management вне account access, разделяя только
crypto/error primitives.** Сохранение или удаление T-Bank connection валидирует
candidate token и не разрешает persisted account. Этот flow не должен
принудительно проходить через account-scoped access use case. Shared module
может предоставить или переиспользовать crypto provider и invalid-token
translator, но connection management сохраняет текущую ответственность за token
validation, encryption и Portfolio snapshot invalidation.
**D4. Единая supported-account policy.** Supported upstream account types и их
normalized Investment Account Type/fallback display name живут в одной policy,
которой владеет T-Bank access module. Account list use case и account-scoped
validation оба опираются на эту policy, поэтому добавление или удаление
supported account type становится one-policy change.
**D5. Сохранить Account Ledger cache ordering.** Account Ledger должен
по-прежнему проверять current connection и account access до обращения к LRU
page cache. Implementation order: сначала access module, затем page cache,
затем upstream operations call при cache miss. Это сохраняет documented behavior
и 30-секундный token-replacement nuance, уже отражённый в as-built docs.
**D6. Tests переезжают к shared interface плюс тонкое service coverage.** Новые
tests покрывают observable branches access module: missing connection, invalid
token during account resolution, inaccessible/unsupported account, supported
account filtering и invalid token из wrapped account-scoped handler.
Существующие service tests корректируются так, чтобы проверять service-specific
behavior и факт использования shared access module без повторного тестирования
одной access matrix в каждом service.
## Delivery Map
| Area | Status | Architectural outcome or N/A reason |
| --- | --- | --- |
| frontend | `N/A` | Frontend behavior, generated client и OpenAPI snapshot не меняются. |
| backend | `affected` | T-Bank access module централизует connection lookup, token decrypt, supported-account policy, account access check и invalid-token translation; feature services сохраняют только feature-specific data retrieval, mapping и cache behavior. |
| specs | `affected` | Этот SDD change хранит Proposal, skipped Delta Specs, Design и Tasks для behavior-preserving refactor. |
| docs | `N/A` | As-built product behavior намеренно не меняется; docs обновляются только если implementation обнаружит ещё не задокументированный behavior nuance. |
### Contract Gate Decision
| Gate | Status | Reason |
| --- | --- | --- |
| runtime-openapi | `N/A` | Public API contract, DTO shape и generated frontend snapshot не меняются. |
### Solution Assessment
Формальная build-versus-buy assessment не triggered. Change не добавляет и не
заменяет auth, storage, external integration, observability, caching,
concurrency control или infrastructure. Он сохраняет существующий T-Bank gRPC
client и переносит project-owned access policy за более глубокий in-process
module.
## Risks / Trade-offs
- **Behavior drift during refactor.** Refactor затрагивает shared access
behavior нескольких endpoints. Mitigation: сохранить existing public status
codes/codes, добавить shared access tests для common matrix и оставить
feature-service tests для endpoint-specific behavior.
- **Over-wide callback interface.** Wrapping feature handlers централизует
invalid-token translation, но может создать впечатление, что access module
отвечает за feature logic. Mitigation: handler context ограничен resolved
token/account data; normalization, pagination, projections и caches остаются
в feature services.
- **Account Ledger cache ordering regression.** Перенос access code может
случайно начать отдавать cached pages до проверки current connection/account
access. Mitigation: Design требует access-before-cache ordering, а Tasks
должны включить focused regression test или semantic verification для этого
behavior.
- **T-Bank connection management partial duplication.** Connection settings flow
не может использовать account-scoped resolution, потому что валидирует
candidate token. Mitigation: разделить crypto/error primitives, но сохранить
connection management отдельно, не искажая account access interface.
## Migration Plan
Поставка выполняется одной backend-focused последовательностью без runtime
migration:
1. Добавить shared T-Bank access module и tests для common access matrix.
2. Перенести supported-account policy в shared module.
3. Refactor account-scoped flows так, чтобы они выполнялись через shared access
module, сохраняя feature-specific mapping, cache и fallback behavior каждого
flow.
4. Refactor Brokerage Accounts list на использование shared supported-account
policy/use case.
5. Оставить T-Bank connection management behavior неизменным, разделив только
безопасные crypto/error primitives, если это полезно.
6. Запустить backend canonical gate, semantic verification против этого Design
и Proposal, затем workspace change verification перед archive.
Rollback — обычный code revert: schema, data, contract или cache migration не
вводятся.
## Open Questions
<!-- none -->