docs(specs): archive stock ticker change

This commit is contained in:
2026-08-27 00:44:12 +03:00
parent 15ce5b586d
commit 329f0a86a4
6 changed files with 326 additions and 4 deletions
@@ -0,0 +1,102 @@
## Context
Portfolio уже нормализуется backend-ом из финансовых данных и metadata
инструмента, после чего frontend получает только OpenAPI-контракт. Metadata
разрешается по instrument UID с fallback на FIGI и уже содержит тикер для
построения отображаемого имени, однако тикер не входит в нормализованную
Portfolio Position. Карточка позиции отображает ISIN независимо от типа
инструмента.
Изменение расширяет публичный ответ Portfolio nullable presentation metadata и
затрагивает обе стороны committed OpenAPI-контракта. Денежные значения,
расчёты, доступ к счёту, metadata lookup и cache policies остаются прежними.
## Goals / Non-Goals
**Goals:**
- Передавать доступный тикер через нормализованную Portfolio Position без
отдельного источника данных на клиенте.
- Отображать на карточке `STOCK` тикер либо ISIN как определённый fallback.
- Сохранить единый backend-owned API contract и generated frontend types.
**Non-Goals:**
- Не менять правила формирования отображаемого имени, порядок, секции или
финансовые данные Portfolio.
- Не менять представление облигаций и иных типов позиций.
- Не вводить новый upstream lookup, cache, endpoint, хранилище или клиентскую
интеграцию с T-Bank.
## Decisions
### Nullable ticker остаётся metadata Portfolio Position
Backend добавляет nullable `ticker` к нормализованной Position и заполняет его
из уже разрешённой metadata инструмента. Пустое значение и отсутствие metadata
нормализуются в `null`, как существующие presentation metadata. Это делает
данные доступными одинаково для всех типов Position, не меняет уже принятый
порядок разрешения metadata и не влияет на финансовый Snapshot.
Не использовать тикер непосредственно из исходной Portfolio Position: это
обошло бы единый UID/FIGI resolution path и могло бы расходиться с другими
metadata полями. Не запрашивать metadata на frontend: это нарушило бы
server-side boundary T-Bank и создало бы второй источник контрактных данных.
### OpenAPI — единственный межрепозиторный шов
DTO backend-а объявляет nullable `ticker`; опубликованный runtime OpenAPI
документ становится источником для committed frontend snapshot и generated
types. Frontend не создаёт ручной transport type и не меняет контракт локально.
Так additive field остаётся синхронным между runtime API и клиентом.
### Выбор идентификатора принадлежит presentation layer карточки
Существующая VM продолжает передавать structural Portfolio Position из
generated контракта. Карточка определяет подпись только из уже переданных
`type`, `ticker` и `isin`: для `STOCK` выбирает `ticker ?? isin`, для остальных
типов сохраняет `isin`. Это локальная presentation-логика одного значения,
поэтому не переносит в view fetching, группировку или финансовые вычисления.
## Delivery Map
| Area | Status | Architectural outcome or N/A reason |
| --- | --- | --- |
| frontend | `affected` | Получает синхронизированные generated types и отображает на карточке `STOCK` тикер с ISIN fallback, не меняя карточки иных типов. |
| backend | `affected` | Нормализует nullable ticker из существующей metadata и публикует его в Portfolio API/OpenAPI. |
| specs | `affected` | Delta `portfolio-view` закрепляет nullable ticker и type-specific presentation fallback. |
| docs | `affected` | После проверенной реализации feature documentation Portfolio описывает поле ticker и stock-only правило отображения. |
### Contract Gate Decision
| Gate | Status | Reason |
| --- | --- | --- |
| runtime-openapi | `required` | Backend публикует additive поле Portfolio API, а frontend потребляет его через committed OpenAPI snapshot и generated types. |
## Risks / Trade-offs
- Ticker остаётся best-effort metadata; nullable contract и ISIN fallback не
скрывают Position при его отсутствии.
- Additive публичное поле требует синхронной поставки runtime OpenAPI и
committed frontend snapshot; contract gate предотвращает их расхождение.
- Неэквивалентность тикера и отображаемого имени намеренна: имя сохраняет
существующий приоритет, тикер служит компактной подписью только акции.
## Migration Plan
1. Расширить backend-нормализацию и публичный contract nullable ticker без
изменения существующих полей или cache semantics.
2. Синхронизировать generated frontend contract с runtime OpenAPI и применить
type-specific presentation rule в карточке.
3. Обновить as-built Portfolio documentation после подтверждения delivered
поведения.
### Rollback Contract
| Field | Decision |
| --- | --- |
| Status | `required` |
| Trigger | Обнаружено, что новое поле или его отображение нарушает совместимость Portfolio API либо неправильно идентифицирует акции. |
| Actions | Сначала вернуть frontend-карточки акций к ISIN. Nullable `ticker` не удалять из backend публичного ответа во время rollback, чтобы не ломать уже синхронизированный клиентский contract; последующее удаление возможно только отдельным compatibility change. |
| Data safety | Тикер — производная metadata текущего in-memory Portfolio Snapshot; миграций, persistent data и денежных расчётов нет. |
| Verification | Подтвердить сохранение ISIN на stock-карточках и соответствие runtime OpenAPI committed frontend snapshot. |