Files

11 KiB
Raw Permalink Blame History

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