# tbank-connection Specification ## Purpose Позволяет авторизованному пользователю безопасно подключить T-Bank Invest для будущего получения только собственных инвестиционных данных через backend. ## Requirements ### Requirement: Статус подключения T-Bank Система SHALL предоставлять авторизованному User `GET /api/v1/tbank-connection`, возвращающий состояние его единственного подключения в форме `{ connected, connectedAt }`. При отсутствии подключения ответ MUST быть `{ connected: false, connectedAt: null }`; при наличии подключения `connectedAt` MUST быть timestamp в RFC 3339 UTC. Получение статуса MUST NOT обращаться к T-Bank. #### Scenario: Подключение отсутствует - **WHEN** авторизованный User запрашивает статус без сохранённого подключения - **THEN** система отвечает `200` с `{ connected: false, connectedAt: null }` #### Scenario: Подключение существует - **WHEN** авторизованный User запрашивает статус после успешного подключения - **THEN** система отвечает `200` с `{ connected: true, connectedAt: }` без token ### Requirement: Создание и замена подключения T-Bank Система SHALL позволять авторизованному User создать или заменить единственное подключение через `PUT /api/v1/tbank-connection` с token. Система MUST удалить внешние пробелы token, отклонить пустое значение как ошибку валидации и проверить token запросом T-Bank открытых счетов до сохранения. Пустой список счетов MUST считаться успешной проверкой. Успех MUST вернуть `200` с текущим статусом подключения; успешная замена MUST установить новый `connectedAt`. После успешного подключения MUST начинаться первый часовой обход без команды frontend. История стоимости прежних счетов MUST сохраняться, но MUST быть доступна только для счетов, доступ к которым подтверждён новым подключением. #### Scenario: Успешное создание подключения без счетов - **WHEN** User отправляет непустой token и T-Bank успешно возвращает пустой список открытых счетов - **THEN** система сохраняет подключение, отвечает `200` с `{ connected: true, connectedAt: }` и не создаёт фиктивные счета #### Scenario: Успешная замена подключения - **WHEN** User с подключением отправляет другой token и T-Bank успешно его проверяет - **THEN** система заменяет token, обновляет `connectedAt`, отвечает текущим статусом без token и начинает первый часовой обход нового подключения #### Scenario: Невалидный token не заменяет существующее подключение - **WHEN** T-Bank отклоняет token как неаутентифицированный или не имеющий прав - **THEN** система отвечает `400` Problem Details с code `INVALID_TBANK_TOKEN` и сохраняет прежнее подключение без изменений #### Scenario: T-Bank временно недоступен при проверке token - **WHEN** проверка token не завершается из-за временной или иной upstream-ошибки - **THEN** система отвечает `503` Problem Details с code `TBANK_UNAVAILABLE` и не создаёт либо не изменяет подключение ### Requirement: Удаление подключения T-Bank Система SHALL позволять авторизованному User удалить своё подключение через `DELETE /api/v1/tbank-connection`. Удаление MUST быть идемпотентным и отвечать `204`; после успешного удаления backend MUST прекратить использовать удалённый token и сделать относящиеся к User текущие личные данные недоступными. История стоимости счёта MUST сохраняться, но MUST NOT раскрываться до подтверждения нового доступа к тому же счёту. #### Scenario: Удаление существующего подключения - **WHEN** User удаляет существующее подключение - **THEN** система удаляет token, скрывает текущие личные данные и историю стоимости и отвечает `204` #### Scenario: Повторное удаление подключения - **WHEN** User удаляет уже отсутствующее подключение - **THEN** система отвечает `204`, не раскрывая сохранённую историю ### Requirement: Конфиденциальность token T-Bank Система MUST хранить не более одного token T-Bank для каждого User только в зашифрованном виде. Token MUST расшифровываться только для серверного вызова T-Bank и MUST NOT передаваться в frontend, HTTP-ответах, OpenAPI examples, сообщениях ошибок или application logs. #### Scenario: API не раскрывает token - **WHEN** User создаёт, заменяет, удаляет или получает статус подключения - **THEN** ни один HTTP-ответ не содержит token или его фрагмент ### Requirement: Устойчивость проверки T-Bank Система SHALL выполнять проверку token только через защищённое TLS-подключение к T-Bank. Все вызовы T-Bank MUST проходить через общий для экземпляра backend лимит, задаваемый конфигурацией и равный 5 запросам в секунду по умолчанию, с FIFO-очередью не более 50 ожидающих вызовов. Для временных ошибок система MUST выполнить не более одного повторного вызова; если проверка не завершается успешно, token MUST NOT сохраняться. #### Scenario: Лимит ожидания upstream-вызовов исчерпан - **WHEN** 50 вызовов T-Bank уже ожидают общий лимитер - **THEN** следующий запрос не обращается к T-Bank и получает `503` Problem Details с code `TBANK_UNAVAILABLE` #### Scenario: Временная ошибка успешно повторяется - **WHEN** первая проверка token завершается временной ошибкой, а единственный повтор завершается успешно - **THEN** система сохраняет подключение и отвечает текущим статусом ### Requirement: Управление подключением в настройках Клиент SHALL показывать в настройках статус T-Bank connection, текст о необходимости read-only T-Bank Invest token, поле token и действие подключения либо замены. Для существующего подключения клиент MUST показывать действие удаления с modal-подтверждением. Во время создания, замены или удаления все действия секции подключения и действия modal MUST быть отключены. После успешного создания или замены клиент MUST очистить поле token и обновить статус; при ошибке token MUST остаться в поле. Временный сбой чтения статуса SHALL восстанавливаться автоматически без кнопки повтора и технического предупреждения. Пока первый статус неизвестен, клиент MUST NOT показывать форму как подтверждённое отсутствие подключения: после первичного ожидания SHALL отображаться нейтральная недоступность секции. Если статус уже известен для текущей сессии, временный сбой его фонового чтения MUST NOT скрывать доступную секцию или очищать ввод. Подтверждённое изменение сессии или доступа MUST NOT маскироваться старым статусом. Ошибки создания, замены и удаления MUST оставаться локальными, сохранять ввод и возвращать применимые действия формы. Эти действия MUST NOT повторяться автоматически как чтение статуса. Подтверждения успеха SHALL следовать `frontend-user-feedback`: очевидное изменение статуса не требует дублирующего уведомления, неочевидный результат получает одно краткое подтверждение. #### Scenario: Пользователь подтверждает удаление - **WHEN** User подтверждает удаление в modal - **THEN** клиент блокирует действия секции до результата и после успешного ответа показывает состояние без подключения #### Scenario: Ошибка загрузки статуса - **WHEN** клиент временно не может получить статус подключения - **THEN** он автоматически восстанавливает чтение, сохраняет известный статус текущей сессии либо показывает нейтральную недоступность после первичного ожидания без формы и кнопки повтора #### Scenario: Ошибка проверки token в клиенте - **WHEN** создание или замена получает `INVALID_TBANK_TOKEN` либо `TBANK_UNAVAILABLE` - **THEN** клиент показывает соответственно локализованное сообщение о token и правах либо о временной недоступности T-Bank в контексте формы, возвращает интерактивность и сохраняет введённый token #### Scenario: Фоновое чтение не сбрасывает ввод - **WHEN** пользователь редактирует token в доступной секции, а фоновое чтение статуса временно не удалось - **THEN** ввод и доступная секция сохраняются без технического предупреждения или уведомления #### Scenario: Удаление не удалось - **WHEN** пользователь подтвердил удаление подключения, а действие завершилось ошибкой - **THEN** клиент не показывает успех, сохраняет известный статус и локальную ошибку, возвращает применимые действия и не повторяет удаление автоматически