Files
specs/openspec/changes/account-top-positions/analysis/docs-impact.md
T

144 lines
27 KiB
Markdown
Raw Blame History

This file contains ambiguous Unicode characters
This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.
# Documentation Impact
## Summary
Change `account-top-positions` (Issue [WealthLedger/main#48](https://git.personal.ksv741.ru/WealthLedger/main/issues/48)) добавляет на страницу одного счёта вкладку «Концентрация» с разрезами «Акции», «Облигации», «Секторы», «Эмитенты», а в позиции Portfolio — сектор и эмитента (бренд актива). Для docs это значит:
- В AS-IS появляются новые понятия и правила: вкладка, разрезы, «Прочее», сектор, эмитент (бренд актива во вкладке), правило 24 часов для сектора и бренда.
- Сектор и бренд — исключение из правила «справочные сведения только онлайн» ([ADR 019](../../../../../docs/adr/019-hourly-reads-and-online-instrument-reference.md)). Решение оформляется новым [ADR 022](../../../../../docs/adr/022-stored-instrument-classification.md); текст ADR 019 не переписывается, в его статус добавляется ссылка.
- Хранение решено в design (B1): отдельная глобальная таблица `TbankInstrumentClassification`, не связанная с подключением. Её состав и поведение при отказах отражаются в `containers.md` и `data-freshness.md`.
- Правки AS-IS — после реализации и её слияния в `develop`. До этого docs не описывает поведение, которого в системе нет.
Пути ниже — относительно корня workspace `WealthLedger/`; для docs-репозитория полный путь — `docs/<path>`.
## Documentation Changes
| Action | Target | Category | Итоговое AS-IS | Source | Verification |
| --- | --- | --- | --- | --- | --- |
| Изменить | `docs/domains/portfolio/overview.md`, разделы «Снимок и связанные области» и «Как читать экран» | Domain | На странице одного счёта рядом с «Позиции» есть вкладка «Концентрация». В ней четыре разреза: «Акции», «Облигации», «Секторы», «Эмитенты». По умолчанию открыт «Акции» и первая по ISO валюта. В каждом разрезе топ-5 элементов; при семи и более элементах остальные — в «Прочее», раскрытие не меняет топ-5. Суммы и доли — в одной валюте, конвертации нет. Вкладки нет в режиме «Все счета» и при загрузке, ошибке или пустом Portfolio. Вкладка не меняет вкладку по умолчанию. Деньги не входят в знаменатель долей (в отличие от «Структуры») | `specs/.../portfolio-concentration/spec.md` (Вкладка, Состояния, Переключение, Начальное состояние, Одна валюта); `proposal.md` What Changes; `design.md` D8–D10 | Сверка с мерджнутым frontend и итоговыми Specs; проверка ссылок |
| Добавить | `docs/domains/portfolio/concentration.md` (новый файл, если правила не умещаются в `overview.md`; решение при написании) | Domain / reference | Состав разрезов по типам позиций; топ-5 и «Прочее»; группы «Сектор не указан», «Эмитент не указан»; значение `government` с подписью «Государственный сектор»; правила долей и одной валюты | `specs/.../portfolio-concentration/spec.md` (Состав разрезов, Названия элементов); `proposal.md` | Линк из `overview.md` и `docs/README.md`; markdownlint |
| Изменить | `docs/domains/portfolio/data-reference.md`, таблица «Состав и денежные показатели»; раздел «Структура и доли» | Reference | Позиция получает `sector` (сектор T-Bank без перекодирования, пробелы обрезаны, пустое → `null`; только `STOCK`, `BOND`, `FUND`) и `issuer` (бренд актива T-Bank; `null` вне разрезов; фонды в разрез «Эмитенты» не входят). `logoName` не меняется. В «Структуре» отметить: знаменатель и валютные итоги включают деньги, вкладка «Концентрация» — нет | `specs/.../portfolio-view/spec.md` «Нормализованный состав Portfolio» (PVΔ:3); `data-mapping.md` M1, M2; `design.md` D7 | Сверка с кодом ответа и с OpenAPI, выпущенным backend; DTO не копируется |
| Изменить | `docs/domains/portfolio/flows/portfolio-loading.md`, разделы «Основной обмен» и «Ошибки и результат для пользователя» | Flow | Сектор и бренд получаются в том же часовом обходе, в шаге до публикации Snapshot: после GetPortfolio и GetPositions. Первая попытка по позиции — не раньше чем через 24 часа после последнего успешного получения; пока значение не получено, попытка повторяется при каждом обходе. Ошибка получения не мешает публикации Snapshot и не меняет `isStale` и `lastSuccessfulAt`, кроме отказа token: он даёт `400 INVALID_TBANK_TOKEN` без fallback. Сохранённое значение остаётся доступным. Обычный GET по-прежнему не обращается к T-Bank. Фраза «Metadata инструмента дополняет представление независимо» уточняется: сектор и эмитент входят в Snapshot | PVΔ:104, PVΔ:141, PVΔ:156; `failure-model.md`; `design.md` B2, D1–D5 | Сверка с таблицей исходов PVΔ:156 и с кодом после слияния |
| Изменить | `docs/integrations/tbank.md`, таблица «Данные и ответственность»; раздел «Публичные логотипы» | Integration | Новые данные из T-Bank: сектор инструментов акций, облигаций и фондов (вызовы `ShareBy`, `BondBy`, `EtfBy`); бренд актива (uid и название) через `GetAssetBy` по `asset_uid`. Эмитент не выводится из названия, тикера или ISIN. Логотип по-прежнему приходит из metadata инструмента (`logoName`) и не равен эмитенту. Вызовы проходят через общий лимитер (по умолчанию 5/с) и ограниченную очередь | `data-mapping.md` «Источники-кандидаты в T-Bank»; `design.md` B4, D6 | Сверка с кодом T-Bank-клиента после слияния; ссылки на CDN не меняются |
| Изменить | `docs/architecture/cross-cutting/data-freshness.md`, раздел «Клиентский и серверный снимки» (список данных SQLite) и абзац про часовой обход | Architecture (cross-cutting) | SQLite дополнительно хранит классификацию инструментов (сектор и бренд) в глобальной таблице `TbankInstrumentClassification`: она не принадлежит пользователю или подключению и не ограждается по connection revision. Каждое поле имеет свой возраст (`sectorFetchedAt`, `brandFetchedAt`). Классификация не входит в `meta.dependencies` и не меняет свежесть Snapshot. Прежнее утверждение «общие сведения об инструментах запрашиваются онлайн» получает оговорку про это исключение и ссылку на ADR 022 | `design.md` Data / Storage Changes, D1, D4; `design.md` Cross-cutting «Freshness»; PVΔ:104, PVΔ:3 | Сверка с миграцией Prisma после слияния; проверка ссылки на ADR 022 |
| Изменить | `docs/architecture/containers.md`, раздел «Хранимые данные и границы доступа» (абзац про portfolio и общие сведения) | Architecture (data) | Добавить: SQLite содержит таблицу `TbankInstrumentClassification` (провайдер, ключ инструмента, сектор с возрастом, uid актива и бренда с именем и возрастом). Данные публичные, без токена и позиций. Снимок Portfolio полей классификации отдельно не хранит: поля `sector` и `issuer` позиций заполняются из таблицы при публикации | `design.md` Data / Storage Changes; B2; PVΔ «Ограничения доступа» | Сверка с `schema.prisma` и миграцией после слияния |
| Изменить | `docs/glossary.md`, блок Portfolio (после «Currency Instrument Position», до «Instrument»): новые термины | Glossary | См. раздел «Glossary / Navigation Impact» | `proposal.md`; `specs/.../portfolio-concentration/spec.md`; решение владельца (3083) | Формат: `## Термин`, определение и «_Не использовать_»; ссылки на домен |
| Изменить | `docs/overview.md`, таблица «Основные задачи пользователя», строка «Понять текущий состав инвестиций» | Navigation | Добавить задачу «увидеть, где сконцентрированы деньги: бумаги, секторы, эмитенты» со ссылкой на портфель | `proposal.md` (Why) | markdownlint, relative-links |
| Изменить | `docs/README.md`, таблица «Предметные области», строка «Портфель» | Navigation | Строка «Позиции, остатки, суммы, структура и свежесть» дополняется концентрацией (и ссылкой на новый файл, если он появится) | Как выше | markdownlint, relative-links |
| Новый ADR | `docs/adr/022-stored-instrument-classification.md` и строка в `docs/adr/README.md` | ADR | Фиксирует исключение: сектор и бренд актива хранятся как последнее известное значение с отдельным возрастом, а не запрашиваются онлайн. Область: сектор для `STOCK`/`BOND`/`FUND`, бренд актива; 24-часовой отсчёт; сохранение при ошибке; глобальная таблица без привязки к подключению | `design.md` B1, D1–D2; PVΔ:104; ADR 019; решение владельца (3083) | Номер и отсутствие дубликата проверить на момент записи; ссылки проходят |
| Изменить (связь) | `docs/adr/019-hourly-reads-and-online-instrument-reference.md`, строка **Status** | ADR | Добавить: «дополнен [ADR 022](022-stored-instrument-classification.md) в части сектора и бренда актива позиции». Текст решения 019 не переписывается | `docs/CONTRIBUTING.md` («Подтверждённо заменённое решение связывается с новым, а не переписывается») | Ссылка открывается; markdownlint |
| Изменить (условно) | `docs/domains/portfolio/all-accounts.md`, раздел «Маршруты и навигация» | Navigation | Одна строка: вкладки «Концентрация» в общем режиме нет. Если владелец решит, что это не нужно описывать — не менять | `specs/.../portfolio-concentration/spec.md` («Режим «Все счета»») | Решение при написании |
### Что не меняется (и почему)
| Target | Причина |
| --- | --- |
| `docs/architecture/containers.md`, Mermaid-диаграмма Container и раздел «Контейнерная поставка» | Новых внешних систем и контейнеров нет; T-Bank Brands CDN используется только для изображений, как и раньше |
| `docs/architecture/context.md`, Mermaid-диаграмма и текст | Тот же набор внешних систем |
| `docs/architecture/http-api.md` | Контракт генерирует backend (OpenAPI). Новые необязательные поля не копируются в docs |
| `docs/domains/accounts/overview.md` | Перечня вкладок страницы счёта в docs нет; вкладка относится к портфелю |
| `docs/domains/instruments/stocks.md`, `docs/domains/instruments/bonds.md` | Сектор и бренд показываются только во вкладке счёта. Файлы **не читались целиком** — проверить поиском «сектор» перед PR |
| `docs/domains/portfolio/all-accounts.md` (кроме условной строки выше) | Общий режим без вкладки; новых маршрутов нет |
| `docs/CHANGELOG.md` | Генерируется release-it из коммитов; вручную не править |
| `docs/architecture/cross-cutting/ui-resilience.md` | Не читалось полностью. Проверить, описывает ли оно состояния страницы счёта |
## Diagram Promotion
Перенос диаграмм не требуется. По умолчанию перенос не делается (`schema.yaml`, `docs-impact`; `docs/CONTRIBUTING.md`).
- `analysis/ux-design.md`, Mermaid flowchart «Страница счёта → Концентрация» — UI-поток этого change, не системная архитектура. В docs не переносится.
- `visuals/*.svg` — материалы Visual Package; в docs не размещаются.
- Существующие диаграммы (Container, Context, sequence подключения T-Bank) не меняются.
- Sequence «часовой обход → классификация → Snapshot» в docs **не добавляется**: поток описан текстом в `portfolio-loading.md`. Если понадобится, её делает автор docs-PR по `design.md` B2.
## ADR Decision
**Практика ADR в docs есть:** журнал `docs/adr/`, индекс в `docs/adr/README.md`, последний номер — 021, следующий — **022**. Формат — по ADR 019: `# NNN. Название`, `**Status:**`, `## Decision`, `## Consequences`. Принятый ADR не переписывается; замена связывается ссылкой на новый (`docs/CONTRIBUTING.md`).
**Решение владельца (3083):** добавить ADR для хранения сектора и бренда как исключения из online-only справочных данных.
**ADR 022 — `docs/adr/022-stored-instrument-classification.md`, статус `Accepted`.** Содержание, подтверждённое источниками:
- Context: ADR 019 (справочные сведения онлайн; старые строки не источник актуальности); PVΔ:104 (исключение для сектора и бренда); design B1 (общий metadata-кэш не подходит: `Instrument` не содержит сектора, `brand` — `BrandData`, а не `Brand{uid,name}`).
- Decision: глобальная таблица `TbankInstrumentClassification` с последним известным значением сектора и бренда, возраст полей раздельно; обновление по правилу PVΔ:141 (не раньше 24 ч после последнего успешного получения); четыре исхода PVΔ:156; без привязки к пользователю и подключению.
- Consequences: первый долговременный справочник T-Bank в системе; число вызовов T-Bank растёт при первом обходе (разовый всплеск, ограничен D6); отказ token обрабатывается как в обходе Portfolio; пересмотр, если появится второй потребитель (design ADR Candidates).
- Альтернативы: design Solution Assessment, варианты B и C. В ADR описываются кратко, со ссылкой на design.
ADR 022 пишется в том же docs-PR, что и изменения AS-IS, или раньше — и тогда в статус ADR 019 добавляется ссылка в том же PR, что и ADR 022.
## Glossary / Navigation Impact
### Глоссарий (`docs/glossary.md`)
Новые термины — в блоке Portfolio (после «Currency Instrument Position», до «Instrument»). Формат: `## Термин`, краткое определение, строка `_Не использовать_`.
| Термин | Что писать |
| --- | --- |
| **Концентрация** | Вкладка страницы одного счёта с разрезами по бумагам, секторам и эмитентам текущего Portfolio. Ссылка на домен портфеля. Не «структура» |
| **Разрез** | Одна из четырёх группировок вкладки «Концентрация»: набор элементов, на которые делится оценка позиций |
| **Сектор** | Значение сектора T-Bank для позиций `STOCK`, `BOND`, `FUND`, без собственной классификации WealthLedger. Государственные облигации — значение `government` с подписью «Государственный сектор» |
| **Эмитент** | В разрезе «Эмитенты» вкладки «Концентрация» — бренд актива по данным T-Bank. Фонды в разрез не входят. **Оговорка (решение владельца 3083):** в этом разрезе слово означает бренд актива T-Bank, а не юридического эмитента ценной бумаги. Строка «_Не использовать_»: юридический эмитент, эмитент рейтинга (см. [рейтинг выпуска НКР](integrations/nkr.md)) |
| **«Прочее»** | Группа остальных элементов разреза при семи и более элементах. Это UI-подпись: описывается в доменной странице, в глоссарии — одна строка-ссылка |
Владелец оставил термин «Эмитенты». Конфликт с юридическим эмитентом в NKR, ADR 013, `context.md` и `bonds.md` сохраняется; оговорка в глоссарии — единственное место, где он снимается. Остальные страницы, использующие «эмитент» в значении рейтинга или выпуска, не меняются.
Не добавлять отдельными записями: «Сектор не указан», «Эмитент не указан», «Государственный сектор» — UI-подписи, описываются в доменной странице.
Связанная существующая запись: «Instrument Logo» (строка про `logoName`) — после change явно указать, что логотип не равен эмитенту.
### Навигация
- `docs/domains/portfolio/overview.md` — главная страница для концентрации; ссылки на `data-reference.md` и новый файл (если будет).
- `docs/overview.md`, `docs/README.md` — строки из таблицы изменений.
- `docs/architecture/README.md` — новых вопросов не добавляется.
- `docs/adr/README.md` — строка 022 в индексе.
## Порядок относительно реализации
Порядок из `docs/CONTRIBUTING.md` («Фазы работы»), `docs/AGENTS.md` и правила AS-IS. Design задаёт выкат: backup, миграция `CREATE TABLE`, backend, публикация OpenAPI, frontend (`design.md`, Migration / Rollout).
1. **Сейчас (G2 approved, G3 — design package):** AS-IS страницы не меняются. Создать пункты `[docs]` в `tasks.md` по таблице выше.
2. **Во время реализации:** черновики текста допустимы в issue-linked ветке docs от `develop`. ADR 022 — в статусе `Accepted` (решение принято владельцем 3083).
3. **Слияние в `develop` docs-PR** — после слияния backend и frontend и проверки на окружении: AS-IS-тексты не должны обещать поведение, которого в `develop` нет. ADR 022 можно слить раньше, если его текст не описывает поведение, а фиксирует решение.
4. **Перед завершением:** сверка «текст ↔ код ↔ Specs»; `docs-sync-audit` или ручная проверка; проверки из следующего раздела.
Заголовок PR — conventional commit (`docs/commitlint.config.cjs`; CI `commits.yml` запускает `commitlint --strict`). В описании PR — ссылка на Issue #48 и change-id.
## AS-IS правила
- Docs описывает только поведение, которое есть в `develop` и проверено. Спецификация change не копируется в docs как требование.
- Формулировки «будет», «планируется» в AS-IS-страницах не используются.
- Текущие утверждения, которые станут неверными после change (исправлять только после реализации):
- `docs/architecture/cross-cutting/data-freshness.md` — список данных SQLite и онлайн-правило для инструментов;
- `docs/domains/portfolio/flows/portfolio-loading.md` — «Metadata инструмента дополняет представление независимо»;
- `docs/adr/019-…` — онлайн-правило: исключение описывает ADR 022; текст 019 не переписывать;
- `docs/domains/portfolio/data-reference.md` — «Структура» и «Концентрация» не должны выглядеть одним показателем.
- Один факт — один источник: правила сектора и бренда живут в `portfolio-view` Specs; docs ссылается на них, а таблицы исходов из `failure-model.md` не копирует.
- Имена RPC T-Bank в docs упоминаются только как категории источников; точный контракт — код и `design.md`.
## Проверки
Из корня docs (`docs/`), по `docs/CONTRIBUTING.md` и `docs/AGENTS.md`:
```bash
nvm use --silent # если nvm не загружен, сначала загрузить $HOME/.nvm/nvm.sh (см. корневой AGENTS)
npm ci # если зависимости не установлены
npm run verify # = npm run lint && git diff --check
```
- `npm run lint`: markdownlint по `**/*.md` (кроме `node_modules` и `CHANGELOG.md`) с правилом относительных ссылок; отдельно `CHANGELOG.md`.
- Коммит: `npm run commitlint -- --strict`.
- Ручные проверки, которые lint не делает: якоря в ссылках; смысловая сверка с кодом и Specs; маршрут чтения в `README.md`; новый файл достижим из индекса.
- **Рендер Mermaid не проверяется** ни одним инструментом из `package.json`. Если меняется диаграмма, отмечать «не проверено рендером».
- Для ADR 022: номер, отсутствие дубликата в `docs/adr/README.md`, ссылка из ADR 019.
В этой задаче проверки не запускались: правок в docs нет.
## Открытые вопросы и расхождения
1. **Конфликт термина «эмитент»** сохраняется вне вкладки: NKR, ADR 013, `context.md`, `bonds.md` используют слово для юридического эмитента. Оговорка в глоссарии снимает конфликт только для вкладки; остальные страницы — решение владельца, если оно понадобится.
2. **Конфликт с ADR 019** снимается ADR 022 (решение 3083). Текст ADR 019 остаётся историческим.
3. **Не полностью прочитаны:** `docs/domains/instruments/stocks.md`, `bonds.md`, `docs/architecture/cross-cutting/ui-resilience.md`, `docs/integrations/README.md`. Проверить поиском перед PR.
4. **Основание решения 3083** в этом файле не цитируется дословно: текст комментария Issue не читался в этой задаче. Перед написанием ADR 022 сверить формулировку с комментарием.
5. **Вне scope:** `docs/code-quality-review.md` лежит в корне docs, хотя `docs/AGENTS.md` запрещает аудиты в docs. Не трогается.