# 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