Files
2026-08-13 20:59:38 +03:00

9.7 KiB
Raw Permalink Blame History

Context

См. мотивацию в proposal.md и поведение в specs/brokerage-accounts/spec.md. Backend уже хранит один зашифрованный T-Bank token на User, проверяет его через UsersService/GetAccounts и применяет общую policy TLS, rate limit, deadline и retry. Этот RPC пока отбрасывает response body, а /accounts во frontend является placeholder-страницей. OpenAPI backend остаётся источником transport contract для frontend.

Goals / Non-Goals

Goals:

  • Использовать существующую T-Bank boundary и resilience policy для user-scoped read-path списка счетов.
  • Отделить публичную модель инвестиционного счёта от protobuf enum и банковских типов T-Bank.
  • Дать /accounts понятные loading, empty, error и loaded состояния в FSD-структуре, сохранив стиль codebase и визуальный язык references/fin-tracker без переноса его кода или неподдерживаемых данных.
  • Зафиксировать feature-документацию с пользовательским потоком, API и MVP-ограничениями после реализации.

Non-Goals:

  • Суммы, доходность, агрегация, графики, структура портфеля и любые вычисления по счетам.
  • Кэш backend, timestamp последнего обновления, ручная синхронизация или частичные результаты.
  • Закрытые, банковские и неизвестные типы счетов, операции и изменение T-Bank connection из списка.

Decisions

Read-path списка и public contract

Новый защищённый GET /api/v1/brokerage-accounts сначала читает TbankConnection User. При её отсутствии он немедленно возвращает 409 TBANK_NOT_CONNECTED; gRPC не вызывается. При connection сервис расшифровывает token только для вызова T-Bank и получает открытые счета через существующий общий client, поэтому к списку применяются те же TLS, limiter, deadline и retry, что и к проверке token.

Успех возвращает прямой JSON-массив, а не envelope: сейчас ответ не содержит метаданных, и обёртка не несёт семантики. Ошибка не возвращает данные. При gRPC UNAUTHENTICATED и PERMISSION_DENIED connection не удаляется, а клиент получает 400 INVALID_TBANK_TOKEN; другие ошибки остаются 503 TBANK_UNAVAILABLE.

Альтернативы: использовать /accounts для API смешало бы инвестиционные и банковские счета; статус 200 без connection сделал бы обязательную интеграцию неявным UI-флагом; сохранение или возврат старого списка потребовало бы cache invalidation и вводило бы пользователя в заблуждение об актуальности.

Нормализация Brokerage Account

Backend добавляет нормализованный DTO BrokerageAccount с id, name, type и openedOn. Трансляция включает только upstream-типы ACCOUNT_TYPE_TINKOFF, ACCOUNT_TYPE_TINKOFF_IIS, ACCOUNT_TYPE_INVEST_BOX и ACCOUNT_TYPE_INVEST_FUND, преобразуя их соответственно в BROKERAGE, INDIVIDUAL_INVESTMENT, INVEST_BOX и MONEY_MARKET_FUND. Остальные и неизвестные типы отфильтровываются, порядок upstream сохраняется.

name нормализуется через trim и при пустом результате заменяется fallback названием типа. Timestamp openedDate переводится в nullable YYYY-MM-DD; время намеренно не публикуется, потому что экран показывает календарную дату открытия, а не момент события.

Альтернативы: передача protobuf enum привязала бы frontend к T-Bank contract; показ неизвестных типов как инвестиционных расширил бы доменную границу без решения пользователя; отображение технического id вместо fallback-названия ухудшило бы интерфейс без пользы для MVP.

UI и React Query

Новый entity slice brokerage-account инкапсулирует typed API query, локальные transport aliases из generated paths и display helpers. AccountsPage использует entity через public barrel и выбирает одно из состояний: loading, known-error, generic error, empty либо loaded. Query имеет staleTime: 60_000 и отключённый automatic retry; отключённый focus refetch сохраняется глобальной настройкой. Свежий React Query cache исключает повторный GET в течение минуты; после его устаревания isFetching заменяет прежний список loading-state. Retry для временной и неизвестной ошибки вызывает refetch; кнопка настроек ведёт на /settings.

Успешная замена или удаление connection инвалидирует query списка. Карточки реализуются Mantine-компонентами и локальным CSS module: белая поверхность, тонкая slate-граница, умеренная мягкая тень, синий accent/kicker и заметный hover/focus. Сетка адаптивна: две колонки при доступной ширине и одна на узком экране. Карточка является доступной ссылкой на /accounts/:accountId, показывает имя, локализованный тип и при наличии дату открытия. Не добавляются hero, sparkline и финансовые метрики, поскольку текущий контракт их не предоставляет.

Альтернативы: размещение query прямо в page смешало бы transport и presentation; копирование разметки или mock-метрик FinTracker нарушило бы границы references и исказило бы реальные данные; фиксированная двухколоночная mobile-сетка ухудшила бы читаемость.

Документация и проверка

После реализации docs/features/brokerage-accounts.md описывает пользовательский поток, endpoint, коды ошибок, нормализованные типы и отсутствие кэша/времени актуальности; последовательность запроса фиксируется Mermaid-диаграммой. Постоянный ADR не требуется: backend boundary, OpenAPI и React Query policy уже закреплены ADR 003, 005 и 007, а новая фильтрация типов является ограниченной feature-деталью.

Risks / Trade-offs

  • [Токен может быть отозван после подключения] → Список возвращает INVALID_TBANK_TOKEN и ведёт в настройки, но не удаляет connection автоматически.
  • [Данные меняются у T-Bank между загрузками] → Frontend использует результат до 60 секунд, но backend не хранит кэш и не передаёт метку свежести.
  • [T-Bank добавит новый инвестиционный тип] → Неизвестный тип не показывается до явного расширения доменной модели.
  • [Визуальный референс содержит финансовые показатели, которых нет в API] → Сохраняются лишь стилистические признаки, не генерируются placeholder-значения.

Migration Plan

  1. Расширить T-Bank client получением response body и добавить user-scoped сервис, controller и OpenAPI DTO списка.
  2. Добавить backend unit/e2e проверки нормализации, отсутствующего connection, error mapping и auth.
  3. Перегенерировать frontend API client из работающего backend OpenAPI.
  4. Добавить entity, query, account cards и все состояния /accounts; инвалидировать query из T-Bank connection feature.
  5. Проверить backend и frontend quality gates, визуально проверить desktop/mobile и создать docs/features/brokerage-accounts.md.

Rollback до release удаляет endpoint и frontend-срез; схема базы данных не изменяется. Удалять TbankConnection или шифротекст при rollback не требуется.