- Remove old combined requirement, add two focused requirements: 'Состояния и ошибки Portfolio на клиенте' and 'Представление карточек позиций на клиенте' - Archive extend-instrument-logo-to-bonds change
7.6 KiB
extend-instrument-logo-to-bonds — Design
Context
Данные уже готовы: logoName приходит в PortfolioPositionDto для позиций любого типа (passthrough из T-Bank metadata, без персистенции), фронтенд строит CDN-URL через instrumentLogoUrl и рендерит логотип компонентом PositionLogo (40px, фолбэк первой буквой через onError). Ограничение «только акции» существует в одном месте представления страницы счёта.
Осложнение: локальный проп stock на PositionSection/PositionCard управляет сразу тремя аспектами — одноколоночной раскладкой grid, рендером логотипа и форматом абсолютного дохода (знаковое значение против текстовой подписи). Паритет облигаций означает, что все три аспекта применяются к секции BOND целиком; менять их по отдельности не нужно.
Ограничения репозитория: FSD-границы и public API (dependency-cruiser, Knip), только typed client поверх generated OpenAPI, i18n через локали, gate npm ci && npm run verify под Node 22.
Goals / Non-Goals
Goals:
- Секции
BONDполучают полное представление плитокSTOCK: одна карточка в ряду, визуальный логотип с буква-фолбэком, знаковый доход без подписи. - Минимальный диф в слое представления страницы счёта; переиспользование существующих
instrumentLogoUrlиPositionLogoбез изменений. - Тесты, зеркалирующие существующие сценарии акций для облигаций.
Non-Goals:
- Логотипы для общей секции иных типов (фондов, валют и т.д.) — гейт остаётся allowlist по типам секций.
- Изменения backend, API-контракта, generated types и OpenAPI snapshot.
- Экстракция
PositionLogo/instrumentLogoUrlв entities ради переиспользования — потребителя по-прежнему один экран. - Логотипы на странице upcoming events; понятие «эмитент» в модели.
Decisions
D1. Разъединить смысл флага, сохранив один проп. Проп stock переименовывается в презентационный термин (например, wide), отражающий «широкая плитка во всю строку + логотип + знаковый доход». Секции STOCK и BOND передают его, общая секция иных типов — нет.
Alternative: два независимых пропа (onePerRow, withLogo). Отклонено: сегодня они всегда движутся вместе; разъединять, пока не появился тип, которому нужен только один аспект, — спекуляция.
D2. Логотип без изменений. PositionLogo и instrumentLogoUrl реиспользуются как есть, включая key={logoSrc ?? "no-logo"} для сброса failed-state между карточками и CDN-размер 160 для 40px аватара. Новых настроек размера/радиуса не вводится.
D3. Формат доходности следует за флагом. Знаковый формат без подписи применяется к STOCK и BOND, текстовая подпись остаётся только у секции иных типов — как прямое следствие D1, без отдельной ветки по типу.
D4. Тесты повторяют паттерны акций. В тестах страницы счёта добавляются случаи: облигация с logoName рендерит изображение с брендовым URL; облигация без logoName — буква-фолбэк без img; знаковый доход облигации без текстовой подписи; одноколоночная секция облигаций. Существующие тесты секции иных типов служат регрессионной сеткой неизменённого пути.
Delivery Map
| Area | Status | Architectural outcome or N/A reason |
|---|---|---|
| frontend | affected |
Представление страницы счёта: единый презентационный флаг для секций STOCK и BOND; логотип и знаковый доход на карточках облигаций; обновлённые unit/component тесты |
| backend | N/A |
logoName уже возвращается для всех типов позиций; контракт Portfolio и зависимости не меняются |
| specs | affected |
Утверждённые Delta Specs синхронизируются в главную спеку portfolio-view при archive после реализации |
| docs | affected |
As-built: docs/features/portfolio-view.md отражает паритет облигаций; глоссарий не меняется (термин Instrument Logo уже типо-агностичен) |
Contract Gate Decision
| Gate | Status | Reason |
|---|---|---|
| runtime-openapi | N/A |
API-контракт не меняется ни на одной стороне: backend вне scope, generated types не обновляются |
Risks / Trade-offs
- Редкие бренды у облигаций. Брендовые данные T-Bank для облигаций встречаются реже, чем у акций, поэтому буква-фолбэк будет видна чаще. Mitigation: фолбэк — штатное, уже протестированное поведение; спецификация явно допускает оба исхода.
- Связанность трёх аспектов представления. Общий флаг означает: нельзя включить логотип, не сделав плитку широкой. Осознанный trade-off ради минимального дифа; точка разъединения обозначена в D1.
- Визуальная регрессия других секций. Путь секции иных типов не меняется (ветка по умолчанию того же флага); риск ограничен одним файлом представления и покрыт существующими тестами.
Migration Plan
Поставка одним изменением frontend без флагов миграции: изменение чисто презентационное, состояние и данные не затрагиваются. Rollback — revert коммита frontend. Порядок: имплементация → npm ci && npm run verify → semantic verification против Proposal/Delta Specs/Design → as-built docs → workspace gate verify-workspace-change.sh → archive.