Files
specs/openspec/changes/stock-screener/system-analysis/analysis.md
T
ksv741 951f1a9a20
Specs security / security (push) Successful in 7s
Specs verify / verify (push) Successful in 9s
Conventional commits / commits (pull_request) Successful in 12s
Specs security / security (pull_request) Successful in 7s
Specs verify / verify (pull_request) Successful in 9s
spec: add stock screener
2026-10-11 11:18:21 +03:00

15 KiB
Raw Blame History

System Analysis

Requirement Coverage

Требование delta spec Межсистемная граница и поток
Скринер ищет среди доступных к покупке акций Запуск поиска, полный список Shares, обязательные признаки и время получения: поиск, контракт.
Условия скринера применяются совместно Необязательные параметры в запросе, отбор по всему полученному списку до разделения на страницы; неизвестное не совпадает.
Результат представляет отдельные выпуски После отбора группировка по нормализованному ISIN, иначе по UID; карточка выбранного представителя с точным UID.
Страницы относятся к одному результату поиска Создание нового результата при каждом запуске, чтение последующих страниц того же результата по непрозрачному идентификатору; не более 30 выпусков на страницу.
Отсутствие совпадений отличается от недоступности поиска Успешный пустой набор имеет 200 и items: []; ошибка каталога или потеря результата возвращает ошибку, не пустую страницу.

Systems and Responsibilities

  • Пользователь задаёт условия и запускает поиск в приложении.
  • Frontend хранит черновик условий отдельно от применённого поиска, показывает карточки, время получения и управляет навигацией по страницам. Он не отбирает только первые найденные строки и не склеивает результаты разных поисков.
  • Backend проверяет локальную сессию и действующее подключение T-Bank, получает полный список акций, применяет обязательные признаки и выбранные условия, выбирает один подходящий инструмент на выпуск, фиксирует результат и выдаёт страницы. Инструмент и личный портфель — разные данные.
  • T-Invest поставляет список акций с характеристиками и признаками доступности. Это источник сведений для нового поиска, но не подтверждение доступа конкретного счёта к сделке.

Interaction Flows

stock-screener.mmd описывает новый поиск без текста, переход к следующей странице того же результата, повторный поиск, неподтверждённую доступность инструмента, отказ внешнего источника и отсутствие сохранённого результата. Чтение карточки выбранной акции после перехода по ссылке относится к существующему маршруту инструмента.

Contracts

  • Frontend → Backend, HTTP JSON, новая пара операций POST /api/v1/stocks/screener/search и GET /api/v1/stocks/screener/search/{searchId}. Целевой контракт версии /api/v1: stock-screener.openapi.yaml. Каждый POST — новый поиск даже при совпадающих параметрах; повтор того же POST не идемпотентен в смысле получения данных. GET следующей страницы не повторяет обращение к каталогу. Ответ содержит items, asOf, searchId, page, hasNext. searchId непрозрачен и принадлежит аутентифицированному пользователю и текущему подключению; page — номер страницы с единицы. Контракт не задаёт срок хранения результата и не позволяет подменить применённые условия в запросе страницы.
  • Backend → T-Invest, существующий gRPC over TLS: InstrumentsService.Shares(InstrumentsRequest) с instrument_status = INSTRUMENT_STATUS_ALL возвращает список Share. Базовый список не должен заранее исключать выпуск, у которого оба необходимых признака подтверждены. Отбор по сектору, типу, валюте, площадке, стране риска и лоту выполняется после получения всего списка: этих параметров нет в InstrumentsRequest. Ожидаются buy_available_flag, api_trade_available_flag, uid, isin, ticker, name, sector, share_type, currency, real_exchange, country_of_risk, lot. FindInstrument с обязательной поисковой строкой не является источником полного скринера.
  • Контракт старого GET /api/v1/stocks?query=... не меняется в этой версии. Его обязательный текст, ограничение и текущая форма ответа продолжают работать для существующих потребителей; новое представление не выводится из его первых 30 результатов.

Data and State Semantics

Источник истины для нового поиска — полученный целиком ответ Shares, а не накопленные инструменты портфеля или прежние текстовые запросы. Backend фиксирует полный набор совпавших выпусков и время успешного получения каталога до выдачи первой страницы. Пустая выдача подтверждается только успешным получением списка. Результат поиска отделён от долговременного самостоятельного справочника инструментов; правила существующего online-instrument-information остаются в силе.

Признаки buy_available_flag = true и api_trade_available_flag = true обязательны вместе. Неизвестное либо неподтверждённое значение любого из них исключает инструмент. Эти признаки относятся к снимку каталога, а не к биржевой сессии, счёту пользователя или исполнению заявки.

Применённые условия сравниваются с данными конкретного инструмента: текст — с названием или тикером, выбранные категории — с соответствующими значениями, maxLot — с известным положительным размером лота не больше границы. Отсутствие выбранного свойства исключает инструмент; отсутствие незаданного свойства не мешает совпадению. Страна риска — код страны основного бизнеса, а не юрисдикция регистрации. «Площадка» означает real_exchange, а не секцию/режим class_code и не дилерский instrument_exchange.

После отбора инструменты с одинаковым нормализованным ISIN представляют один выпуск; пустой ISIN заменяется точным UID, а не общим пустым ключом. При нескольких подходящих инструментах одного выпуска выбор представителя должен быть детерминированным; он определяет ссылку и все сведения карточки, данные режимов не смешиваются. Затем выпуски упорядочиваются по тикеру и UID выбранного инструмента и делятся на страницы по 30. asOf и порядок неизменны для всех страниц одного searchId. Повторное нажатие «Найти» не использует старый результат как новый, даже если условия совпадают.

Error and Recovery Semantics

  • Неверные границы или формат условий / страницы: 400 с публичной ошибкой в стандартном профиле. Отсутствующая сессия: 401. Отсутствующее/недействительное подключение T-Bank: соответствующая ошибка доступа подключения; секрет и upstream-исключение не раскрываются.
  • Источник каталога недоступен, возвращает неполный или неинтерпретируемый список: ошибка запроса, не items: []. При новом поиске предыдущий успешно показанный результат не становится доказательством нового поиска. Пользователь может повторить запуск.
  • Идентификатор результата больше не доступен или не принадлежит текущему пользователю/подключению: ошибка вместо пустой страницы или пересчёта по новому каталогу. Frontend предлагает выполнить новый поиск. Потеря результата в рамках действующего поиска — техническая деградация; время и данные прошлого результата не выдаются за новый.
  • Нет утверждений о «прямо сейчас можно купить»: статус торгов и права конкретного счёта не проверяются. Недоступная цена/логотип не меняет состав подходящих выпусков.

Observability Semantics

Существенны попытка нового поиска, успешное получение каталога (asOf, число исходных инструментов, подходящих выпусков), технический отказ источника, чтение страницы недоступного результата и отказ доступа к чужому результату. Секрет подключения, пользовательский токен и полный текст запроса не нужны для диагностики. Успешный пустой результат отличим от отказа источника.

Security and NFR at System Boundaries

Обе HTTP-операции требуют локальной аутентификации; доступ к T-Invest выполняется только на backend с токеном текущего подключения. Идентификатор результата не является правом доступа и не переносит данные между пользователями или поколениями подключения. Полный каталог нужен до пагинации, чтобы 30 карточек не превратились в ограничение области поиска. Значение asOf относится к получению каталога, не к актуальности возможности купить позже. Количественная задержка/SLA для получения списка пока не установлена; не следует обещать мгновенную выдачу при сбое внешнего сервиса.

Compatibility / Migration

Новый маршрут добавляется без изменения действующего текстового поиска и адресов отдельных акций. Frontend переходит на новый контракт для скринера; старый маршрут остаётся доступен его текущим потребителям. После реализации backend-generated OpenAPI должен быть семантически совместим с целевым контрактом в архивируемом change. Документ в этом change не становится вторым постоянным источником исполняемой схемы.

Durable Documentation Candidates

  • Новое назначение раздела акций, набор фильтров и смысл «доступна к покупке по данным каталога» в описании домена акций.
  • Граница между online-каталогом, страницей акции и личным портфелем; снимок результата, время получения и стабильные страницы.
  • Семантика новых HTTP-операций на уровне описания API без дублирования machine-readable OpenAPI. Окончательный выбор принадлежит docs-impact.

Open Questions

Нет блокирующих вопросов по согласованным границам поведения. Выбор механизма хранения результата и допустимой внутренней длительности его доступности принадлежит Engineering Design; потеря результата остаётся ошибкой, а не молчаливой заменой поиска.