# Пассивный доход брокерского счёта Пассивный доход отвечает на вопрос «сколько брокер сообщил исполненными купонами и дивидендами за выбранный период». Пользователь открывает `/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 проверяет доступ локально и читает сохранённые операции. Фоновая загрузка должна завершить все страницы; ошибка страницы или повреждённая цепочка курсоров не подтверждают полноту. - Только точные типы купона и дивиденда источника формируют результат. Суммы остаются точными десятичными строками в исходной валюте; отрицательные корректировки сохраняют знак. Налоги, комиссии, сделки, переводы, погашения и переводы дивидендов не входят в доход. - Итоги, сравнения, временные интервалы и разбиение по инструментам не смешивают валюты и не создают общий конвертированный итог. Страница показывает сравнения с предыдущим периодом и годом ранее, когда календарная дата и история счёта позволяют. Неполное сравнение имеет отдельное сообщение, без нулевой базы. - Временные интервалы по-прежнему приходят с backend: дни для 1–45 дней, недели для 46–180 и месяцы для более длинного периода, включая пустые интервалы. Страница дохода не строит из них график или текстовую динамику; ответ API не меняется. - Раздел «Выплаты» показывает единый список карточек выплат в исходном порядке `entries`: одна карточка на каждую выплату. Внешних групп по инструментам или валютам, итогов и количества выплат инструмента нет. Описание, дата, доступные идентификаторы инструмента и сумма со знаком видны в каждой карточке; валюты по-прежнему разделены в итогах и сравнениях. Дополнительный запрос за составом не нужен. Сравнение с непосредственно предыдущим периодом использует предыдущий полный месяц для полного выбранного месяца, иначе — непосредственно предшествующий интервал той же включительной длительности. Оно не подменяет сравнение годом ранее. Незагруженное сравнение и ошибка его источника отличаются от недоступности годового сравнения по календарю или дате открытия счёта. Каждый раздел сравнения показывает цветные панели без общей белой подложки и внутренних отступов у внешнего блока. Точные периоды показаны в заголовках двух панелей с русским форматом диапазона и UTC для календарных дат. Отдельного заголовка с датами и валютного бейджа нет; валюта остаётся у каждой суммы. Панель «Разница» сохраняет серверную абсолютную разницу и дополняет итог, купоны и дивиденды процентом: абсолютная разница / сумма годом ранее × 100. Это округлённый показатель для отображения, а не пересчёт Money или инвестиционная доходность. Форматирование сохраняет знак и не более одного десятичного разряда. При нулевой или отрицательной базе либо непредставимом числовом отношении процентный бейдж не отображается; абсолютная разница остаётся видимой. ## Полнота и принадлежность выплат Доходы читают сохранённые операции и coverage в согласованной транзакции. Selected, previous и yearAgo имеют независимую готовность. Неполный selected не получает окончательных итогов; неполное сравнение не создаёт нулевую базу. Подтверждённый пустой период отличается от ещё не загруженного. При смене периода прежний snapshot не показывается под новым названием. Ручная сверка полного периода сохраняет весь прежний результат до успешной атомарной публикации всех необходимых интервалов и счетов. История счёта может ещё догружаться после готовности выбранного месяца. Каждая запись `income-analytics.entries` содержит обязательный `instrumentKey`, равный `key` соответствующей строки `instruments`. Backend вычисляет этот ключ один раз при подготовке записей дохода и использует его же для группировки. Приоритет UID, FIGI, ticker/type и ID операции с разделением по валюте остаётся серверным правилом; клиент воспринимает ключ как непрозрачную строку. Это поле принадлежит ответу аналитики; общий журнал операций его не требует. Backend обеспечивает принадлежность выплат, валюту и receipt count при построении entries и instrument groups из одного набора данных. Frontend доверяет типизированному contract, не восстанавливает формулу идентификации и не выполняет второй consistency validator. Полностью пустой ответ допустим. Состав и исходный серверный порядок записей и знак сумм сохраняются, frontend не пересчитывает денежные итоги. Стабильный ID в пределах подключения и счёта определяет одну операцию: повторная сверка обновляет её без двойного учёта. Одинаковые ID разных счетов остаются разными выплатами. Изменение источника логотипа позволяет заново показать изображение после буквенной заглушки. ## Будущие события и ограничения На странице дохода нет блоков «Динамика» и «Ближайший прогноз». Она не запрашивает `/events` и не зависит от его доступности. Самостоятельная страница [«Будущие события»](upcoming-events.md) по-прежнему доступна из обзора выбранного счёта и сохраняет прежнее поведение. Будущие выплаты не включаются в итоги полученного дохода или сравнения. Аналитика читает сохранённую историю операций и не рассчитывает налоги, инвестиционную эффективность, доходность, валютную конвертацию или общий мультивалютный итог. Основное проверяемое поведение — в [спецификации дохода](https://git.personal.ksv741.ru/WealthLedger/specs/src/commit/9e227a563dda67620f0ad78228aa8a4c18bf35a0/openspec/specs/brokerage-account-income-analytics/spec.md), точная форма ответа — в [HTTP API](../../architecture/http-api.md). Не следует использовать календарь будущих событий для восстановления состава уже полученного дохода.