docs: reorganize system knowledge by domain
This commit is contained in:
@@ -0,0 +1,127 @@
|
||||
# Пассивный доход брокерского счёта
|
||||
|
||||
Пассивный доход отвечает на вопрос «сколько брокер сообщил исполненными
|
||||
купонами и дивидендами за выбранный период». Пользователь открывает
|
||||
`/accounts/:accountId/income` из обзора счёта или
|
||||
[общий доход](../portfolio/all-accounts.md) по доступным счетам.
|
||||
Экран показывает итоги по валютам, сравнение и отдельную карточку каждой
|
||||
включённой выплаты. Источником служат [исполненные операции](../operations/overview.md),
|
||||
а не изменение цены портфеля и не календарь будущих выплат.
|
||||
|
||||
Суммы сохраняют знак брокерского денежного движения. Налоговые операции
|
||||
не включаются; результат не называется суммой до или после налогов,
|
||||
инвестиционной эффективностью или налоговым расчётом.
|
||||
|
||||
## Период и данные
|
||||
|
||||
`GET /api/v1/brokerage-accounts/:accountId/income-summary` возвращает текущий месяц по сегодняшнюю дату для компактного блока обзора. Он не зависит от периода, который пользователь ранее выбрал на странице аналитики.
|
||||
|
||||
`GET /api/v1/brokerage-accounts/:accountId/income-analytics?from=YYYY-MM-DD&to=YYYY-MM-DD` возвращает полный результат. Даты задают включительный период в `Europe/Moscow`; без них применяется текущий месяц. Период не может быть будущим или обратным. Максимальная длительность периода не ограничена.
|
||||
|
||||
Оба запроса требуют Bearer token и используют обычные ответы о неподключённом T-Bank, отклонённом токене, недоступном счёте и временной недоступности источника.
|
||||
|
||||
## Выбор периода и состояния страницы
|
||||
|
||||
В блоке «Период» два календарных поля Mantine DateInput показывают даты в формате
|
||||
`ДД.ММ.ГГГГ`. Календарный выбор и ручной ввод изменяют только черновик. Кнопка
|
||||
«Применить» или отправка формы с клавиатуры проверяют видимый текст и передают допустимые
|
||||
даты в URL как `from=YYYY-MM-DD&to=YYYY-MM-DD`. До применения результат сохраняется; отдельной
|
||||
подписи периода под фильтрами нет. Открытие URL и навигация назад восстанавливают
|
||||
применённый период.
|
||||
|
||||
Пустая, несуществующая или будущая дата получает ошибку у своего поля;
|
||||
обратный диапазон — у поля «По». Некорректный текст не заменяется последней
|
||||
допустимой датой при потере фокуса, не меняет URL и не отправляет запрос.
|
||||
Календарь учитывает допустимую соседнюю дату и сегодняшний день в Europe/Moscow.
|
||||
«Сбросить» сразу применяет текущий московский месяц по сегодняшний день,
|
||||
восстанавливает оба поля и очищает ошибки, даже если изменён только черновик.
|
||||
|
||||
При первой загрузке или новом периоде без сохранённых данных показан
|
||||
каркас страницы. Пустой результат объясняет отсутствие исполненных купонов и
|
||||
дивидендов, сохраняя фильтры, налоговое пояснение и сравнения. Ошибка запроса
|
||||
или нарушение принадлежности выплат даёт локальное состояние с действием «Повторить».
|
||||
При фоновом обновлении того же периода сохранённый ответ и черновик
|
||||
остаются видимыми: загрузку обозначает индикатор, неуспешное обновление —
|
||||
предупреждение с повторной попыткой.
|
||||
|
||||
На узком экране поля и действия идут вертикально; все карточки выплат
|
||||
остаются в общем потоке страницы без раскрытия или внутренних областей прокрутки.
|
||||
|
||||
## Какие выплаты входят в результат
|
||||
|
||||
- Backend проверяет доступ к счёту, проходит все страницы исполненных операций и не возвращает частичный результат при ошибке страницы или повреждённой цепочке курсоров.
|
||||
- Только точные типы купона и дивиденда источника формируют результат. Суммы остаются точными десятичными строками в исходной валюте; отрицательные корректировки сохраняют знак. Налоги, комиссии, сделки, переводы, погашения и переводы дивидендов не входят в доход.
|
||||
- Итоги, сравнения, временные интервалы и разбиение по инструментам не смешивают валюты и не создают общий конвертированный итог. На странице показано только сравнение с годом ранее, когда календарная дата и история счёта позволяют. Предыдущий период остаётся в ответе API, но не отображается.
|
||||
- Временные интервалы по-прежнему приходят с backend: дни для 1–45 дней, недели для 46–180 и месяцы для более длинного периода, включая пустые интервалы. Страница дохода не строит из них график или текстовую динамику; ответ API не меняется.
|
||||
- Раздел «Выплаты» показывает единый список карточек выплат в исходном порядке `entries`: одна карточка на каждую выплату. Внешних групп по инструментам или валютам, итогов и количества выплат инструмента нет. Описание, дата, доступные идентификаторы инструмента и сумма со знаком видны в каждой карточке; валюты по-прежнему разделены в итогах и сравнениях. Дополнительный запрос за составом не нужен.
|
||||
|
||||
Сравнение с непосредственно предыдущим периодом сохраняется в API:
|
||||
для полного месяца это предыдущий полный месяц, иначе — непосредственно
|
||||
предшествующий интервал той же включительной длительности. Текущая страница
|
||||
его не показывает. Это расходится с
|
||||
[основным требованием сравнений](../../../specs/openspec/specs/brokerage-account-income-analytics/spec.md#requirement-period-comparisons-preserve-calendar-and-currency-meaning),
|
||||
которое описывает оба сравнения. Требуется отдельно согласовать этот разрыв;
|
||||
здесь сохранено различие между ответом API и фактическим экраном.
|
||||
|
||||
Раздел «Годом ранее» показывает цветные панели без общей белой подложки и
|
||||
внутренних отступов у внешнего блока. Точные периоды показаны в заголовках двух панелей с русским форматом диапазона
|
||||
и UTC для календарных дат.
|
||||
Отдельного заголовка с датами и валютного бейджа нет; валюта остаётся у каждой суммы.
|
||||
Панель «Разница» сохраняет серверную абсолютную разницу и дополняет итог, купоны
|
||||
и дивиденды процентом: абсолютная разница / сумма годом ранее × 100.
|
||||
Это округлённый показатель для отображения, а не пересчёт Money или инвестиционная
|
||||
доходность. Форматирование сохраняет знак и не более одного десятичного разряда.
|
||||
При нулевой или отрицательной базе либо непредставимом числовом отношении
|
||||
процентный бейдж не отображается; абсолютная разница остаётся видимой.
|
||||
|
||||
## Полнота и принадлежность выплат
|
||||
|
||||
Каждая запись `income-analytics.entries` содержит обязательный `instrumentKey`,
|
||||
равный `key` соответствующей строки `instruments`. Backend вычисляет этот ключ
|
||||
один раз при подготовке записей дохода и использует его же для группировки.
|
||||
Приоритет UID, FIGI, ticker/type и ID операции с разделением по валюте остаётся
|
||||
серверным правилом; клиент воспринимает ключ как непрозрачную строку.
|
||||
Это поле принадлежит ответу аналитики; общий журнал операций его не требует.
|
||||
|
||||
Frontend проверяет принадлежность выплат по полученному ключу до подготовки
|
||||
плоского списка выплат. Отсутствующий, пустой или
|
||||
нестроковый ключ, неоднозначные ключи инструментов, неизвестная группа, другая
|
||||
валюта или несовпадение числа выплат приводят к существующему локальному
|
||||
состоянию ошибки аналитики с повторной попыткой. Частичный список выплат не показывается как
|
||||
полный; формула идентификации в клиенте не восстанавливается. Полностью пустой
|
||||
ответ допустим. Состав и исходный серверный порядок записей и знак сумм
|
||||
сохраняются, frontend не пересчитывает денежные итоги. Повторяющиеся ID
|
||||
операций остаются отдельными строками; повторные вхождения учитываются раздельно, а изменение источника логотипа
|
||||
позволяет заново показать изображение после буквенной заглушки.
|
||||
|
||||
## Совместимость ответа
|
||||
|
||||
При обновлении с версии без `instrumentKey` сначала обновляется backend:
|
||||
дополнительное поле совместимо с прежним
|
||||
frontend. Затем синхронизируются OpenAPI snapshot/generated types и обновляется
|
||||
клиент. При переключении клиент перезагружается, чтобы не переносить
|
||||
старые результаты в памяти и незавершённые запросы. Новый frontend требует новый
|
||||
backend; отсутствие ключа принадлежности не скрывается подстановкой прежней формулы.
|
||||
|
||||
При регрессии сначала возвращается прежний frontend вместе с соответствующим
|
||||
snapshot/types и перезагружается клиент; затем при необходимости возвращается
|
||||
backend. Старый frontend может временно работать с новым ответом с добавленным полем.
|
||||
Календарные фильтры и отдельные карточки выплат используют тот же контракт и не требуют
|
||||
дополнительного обновления backend. Схема SQLite, учётные данные и сообщённые брокером
|
||||
операции не меняются: откат
|
||||
не удаляет данные, производные результаты запрашиваются заново.
|
||||
|
||||
## Будущие события и ограничения
|
||||
|
||||
На странице дохода нет блоков «Динамика» и «Ближайший прогноз». Она не запрашивает
|
||||
`/events` и не зависит от его доступности. Самостоятельная страница
|
||||
[«Будущие события»](upcoming-events.md) по-прежнему доступна из обзора
|
||||
выбранного счёта и сохраняет прежнее поведение. Будущие выплаты
|
||||
не включаются в итоги полученного дохода или сравнения.
|
||||
|
||||
Аналитика только читает данные, не хранит историю операций и не рассчитывает налоги, инвестиционную эффективность, доходность, валютную конвертацию или общий мультивалютный итог.
|
||||
|
||||
Основное проверяемое поведение — в [спецификации дохода](../../../specs/openspec/specs/brokerage-account-income-analytics/spec.md),
|
||||
точная форма ответа — в [HTTP API](../../architecture/http-api.md).
|
||||
Не следует использовать календарь будущих событий для восстановления
|
||||
состава уже полученного дохода.
|
||||
@@ -0,0 +1,109 @@
|
||||
# Будущие события
|
||||
|
||||
Будущие события помогают увидеть известные выплаты и даты по текущим
|
||||
позициям счёта. Обзор `/accounts/:accountId` показывает до пяти ближайших
|
||||
событий, полный список находится на `/accounts/:accountId/events`.
|
||||
[Общий режим](../portfolio/all-accounts.md) сохраняет отдельные строки
|
||||
событий каждого доступного счёта. Ошибка или пустой результат превью
|
||||
не заменяет основной портфель.
|
||||
|
||||
Прогноз отличается от [полученного дохода](overview.md): он основан
|
||||
на текущем количестве бумаг и опубликованных условиях, не подтверждает
|
||||
будущее зачисление и не входит в итоги исполненных выплат.
|
||||
|
||||
## Смысл события
|
||||
|
||||
| Событие | Источник и дата | Денежная оценка |
|
||||
| --- | --- | --- |
|
||||
| Купон | Календарь облигации из MOEX `bondization` | Известная выплата на бумагу × текущая позиция |
|
||||
| Дивиденд | T-Bank `GetDividends`, дата реестра `record_date` | `dividend_net` на бумагу × текущая позиция |
|
||||
| Полное погашение | MOEX `bondization` | Известные условия погашения × текущая позиция |
|
||||
| Оферта | MOEX `bondization` | Сумма не синтезируется, `projectedAmount: null` |
|
||||
|
||||
Для дивиденда `dateKind: registry` явно означает дату закрытия реестра,
|
||||
а не гарантированную дату поступления денег. Отменённые выплаты `Cancelled`
|
||||
не включаются. Будущие частичные погашения и амортизация не синтезируются
|
||||
без надёжного расписания. Неизвестные или неприменимые денежные условия
|
||||
остаются `null`, а не заменяются нулём.
|
||||
|
||||
Суммы рассчитаны по количеству на `calculatedAt`. Они не учитывают будущие
|
||||
сделки, право владения на дату реестра и персональный налоговый расчёт.
|
||||
Есть неразрешённое ограничение интерпретации:
|
||||
[основная спецификация](../../../specs/openspec/specs/brokerage-account-upcoming-events/spec.md#requirement-forecasts-preserve-event-meaning-and-uncertainty)
|
||||
и текущая подсказка экрана называют прогноз суммой «до налогов», но для
|
||||
дивиденда реализация только умножает `dividend_net` на количество.
|
||||
Налоговый смысл этого поля не подтверждён локальными материалами; на
|
||||
[странице акции](../instruments/stocks.md#дивиденды-и-финансовые-показатели)
|
||||
он также не трактуется как персональная сумма до или после налога.
|
||||
Расчёт подтверждён, налоговую формулировку требуется согласовать отдельно.
|
||||
|
||||
## Период и список
|
||||
|
||||
Без фильтра период начинается сегодня в UTC и заканчивается через 30 дней
|
||||
после начала, обе даты включены. Поля «С» и «По» позволяют изменить период:
|
||||
«Применить» сохраняет выбранные календарные даты в URL и запрашивает результат,
|
||||
«Сбросить» возвращает период по умолчанию. Обзор счёта сохраняет прогноз
|
||||
на текущую дату и следующие 30 дней.
|
||||
|
||||
События упорядочены по календарной дате. У каждой строки видны тип,
|
||||
инструмент, дата и доступная сумма в исходной валюте. Список не имеет
|
||||
пагинации и не конвертирует валюты. Пустой результат означает отсутствие
|
||||
известных поддерживаемых событий в выбранном окне, а не доказательство
|
||||
отсутствия всех будущих выплат. Инструмент без поддерживаемых данных
|
||||
не получает искусственную строку «нет данных».
|
||||
|
||||
API принимает необязательные `from` и `to` в формате `YYYY-MM-DD` для
|
||||
отдельного и общего счёта. Без `from` используется сегодня в UTC,
|
||||
без `to` — 30 дней после начала. Неверный формат или несуществующая дата
|
||||
дают `400`; обратный период — `400 INVALID_EVENTS_PERIOD`.
|
||||
Фильтрация на сервере предшествует сортировке и вычислению
|
||||
`incomeTotalsByCurrency`, включающего только купоны и дивиденды.
|
||||
Итоги остаются в ответе API; полный экран показывает список без общего итога.
|
||||
|
||||
Текущие controller, сервис и экран поддерживают выбор периода, тогда как
|
||||
[основная спецификация](../../../specs/openspec/specs/brokerage-account-upcoming-events/spec.md#requirement-account-page-presents-an-upcoming-events-list)
|
||||
описывает фиксированные 30 дней и экран без фильтров. Документация отражает
|
||||
реализованный выбор периода, не изменяя это несогласованное требование.
|
||||
|
||||
## Получение и отказы
|
||||
|
||||
```mermaid
|
||||
sequenceDiagram
|
||||
participant F as Frontend
|
||||
participant B as Backend
|
||||
participant T as T-Bank
|
||||
participant M as MOEX ISS
|
||||
F->>B: Счёт и выбранный период событий
|
||||
B->>B: Проверяет сессию и текущее подключение
|
||||
B->>T: Получает открытые счета и позиции доступного счёта
|
||||
par События акций
|
||||
B->>T: GetDividends за выбранный период
|
||||
T-->>B: Известные дивиденды
|
||||
and События облигаций
|
||||
B->>M: Календарь bondization
|
||||
M-->>B: Купоны, погашения и оферты
|
||||
end
|
||||
B->>B: Применяет период и текущее количество бумаг
|
||||
B-->>F: Полный список известных событий либо ошибка
|
||||
```
|
||||
|
||||
Запрос требует действующей сессии и подключения T-Bank. Получение
|
||||
необходимых финансовых данных брокера или календаря MOEX завершается ошибкой
|
||||
`503`, если источник недоступен: частичный список не выдаётся как полный.
|
||||
Доступные метаданные инструментов дополняют название и логотип; когда
|
||||
исходного тикера достаточно для календаря, ошибка дополнительного поиска
|
||||
метаданных не скрывает события.
|
||||
|
||||
При первом открытии показан каркас заголовка и строк, без интерактивных
|
||||
заглушек. Пустой ответ сохраняет возможность изменить период.
|
||||
При обычном фоновом обновлении уже полученные данные остаются на экране,
|
||||
ошибка получает предупреждение и повторную попытку. Без выбранного счёта
|
||||
запрос не выполняется. Смена сессии и подключения следует
|
||||
[общим правилам финансовых данных](../../architecture/cross-cutting/data-freshness.md).
|
||||
|
||||
Внешние границы объясняют интеграции [T-Bank](../../integrations/tbank.md)
|
||||
и [MOEX ISS](../../integrations/moex.md),
|
||||
точные транспортные поля — [HTTP API](../../architecture/http-api.md).
|
||||
Календарь конкретного выпуска и личные исполненные операции доступны
|
||||
на страницах [акций](../instruments/stocks.md) и
|
||||
[облигаций](../instruments/bonds.md), где их смысл также разделён.
|
||||
Reference in New Issue
Block a user