docs(sdd): add tbank access refactor change

This commit is contained in:
2026-08-25 12:06:41 +03:00
parent 678a671d23
commit 79faa29ac0
6 changed files with 312 additions and 5 deletions
@@ -0,0 +1,175 @@
# 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 -->