docs: explain persisted T-Bank reads and synchronization
Conventional commits / commits (pull_request) Successful in 14s
Docs security / security (pull_request) Successful in 8s
Docs verify / verify (pull_request) Successful in 13s
Docs security / security (push) Successful in 8s
Docs verify / verify (push) Successful in 12s

Document local data ownership, coverage and freshness, refresh behavior, failure
recovery and additive migration rollback. Record ADR 017.
This commit was merged in pull request #22.
This commit is contained in:
2026-09-26 21:22:50 +03:00
parent 55610ea2b4
commit 07de062ebb
19 changed files with 459 additions and 432 deletions
+23 -14
View File
@@ -49,21 +49,19 @@
## Какие выплаты входят в результат
- Backend проверяет доступ к счёту, проходит все страницы исполненных операций и не возвращает частичный результат при ошибке страницы или повреждённой цепочке курсоров.
- Backend проверяет доступ локально и читает сохранённые операции. Фоновая загрузка должна завершить все страницы; ошибка страницы или повреждённая цепочка курсоров не подтверждают полноту.
- Только точные типы купона и дивиденда источника формируют результат. Суммы остаются точными десятичными строками в исходной валюте; отрицательные корректировки сохраняют знак. Налоги, комиссии, сделки, переводы, погашения и переводы дивидендов не входят в доход.
- Итоги, сравнения, временные интервалы и разбиение по инструментам не смешивают валюты и не создают общий конвертированный итог. На странице показано только сравнение с годом ранее, когда календарная дата и история счёта позволяют. Предыдущий период остаётся в ответе API, но не отображается.
- Итоги, сравнения, временные интервалы и разбиение по инструментам не смешивают валюты и не создают общий конвертированный итог. Страница показывает сравнения с предыдущим периодом и годом ранее, когда календарная дата и история счёта позволяют. Неполное сравнение имеет отдельное сообщение, без нулевой базы.
- Временные интервалы по-прежнему приходят с backend: дни для 1–45 дней, недели для 46–180 и месяцы для более длинного периода, включая пустые интервалы. Страница дохода не строит из них график или текстовую динамику; ответ API не меняется.
- Раздел «Выплаты» показывает единый список карточек выплат в исходном порядке `entries`: одна карточка на каждую выплату. Внешних групп по инструментам или валютам, итогов и количества выплат инструмента нет. Описание, дата, доступные идентификаторы инструмента и сумма со знаком видны в каждой карточке; валюты по-прежнему разделены в итогах и сравнениях. Дополнительный запрос за составом не нужен.
Сравнение с непосредственно предыдущим периодом сохраняется в API:
для полного месяца это предыдущий полный месяц, иначе — непосредственно
предшествующий интервал той же включительной длительности. Текущая страница
его не показывает. Это расходится с
[основным требованием сравнений](https://git.personal.ksv741.ru/WealthLedger/specs/src/commit/9e227a563dda67620f0ad78228aa8a4c18bf35a0/openspec/specs/brokerage-account-income-analytics/spec.md#requirement-period-comparisons-preserve-calendar-and-currency-meaning),
которое описывает оба сравнения. Требуется отдельно согласовать этот разрыв;
здесь сохранено различие между ответом API и фактическим экраном.
Сравнение с непосредственно предыдущим периодом использует предыдущий полный
месяц для полного выбранного месяца, иначе — непосредственно предшествующий
интервал той же включительной длительности. Оно не подменяет сравнение годом
ранее. Незагруженное сравнение и ошибка его источника отличаются от
недоступности годового сравнения по календарю или дате открытия счёта.
Раздел «Годом ранее» показывает цветные панели без общей белой подложки и
Каждый раздел сравнения показывает цветные панели без общей белой подложки и
внутренних отступов у внешнего блока. Точные периоды показаны в заголовках двух панелей с русским форматом диапазона
и UTC для календарных дат.
Отдельного заголовка с датами и валютного бейджа нет; валюта остаётся у каждой суммы.
@@ -76,6 +74,16 @@
## Полнота и принадлежность выплат
Доходы читают сохранённые операции и coverage в согласованной транзакции.
Selected, previous и yearAgo имеют независимую готовность. Неполный selected
не получает окончательных итогов; неполное сравнение не создаёт нулевую базу.
Подтверждённый пустой период отличается от ещё не загруженного. При смене
периода прежний snapshot не показывается под новым названием.
Ручная сверка полного периода сохраняет весь прежний результат до успешной
атомарной публикации всех необходимых интервалов и счетов. История счёта
может ещё догружаться после готовности выбранного месяца.
Каждая запись `income-analytics.entries` содержит обязательный `instrumentKey`,
равный `key` соответствующей строки `instruments`. Backend вычисляет этот ключ
один раз при подготовке записей дохода и использует его же для группировки.
@@ -90,9 +98,10 @@ Frontend проверяет принадлежность выплат по по
состоянию ошибки аналитики с повторной попыткой. Частичный список выплат не показывается как
полный; формула идентификации в клиенте не восстанавливается. Полностью пустой
ответ допустим. Состав и исходный серверный порядок записей и знак сумм
сохраняются, frontend не пересчитывает денежные итоги. Повторяющиеся ID
операций остаются отдельными строками; повторные вхождения учитываются раздельно, а изменение источника логотипа
позволяет заново показать изображение после буквенной заглушки.
сохраняются, frontend не пересчитывает денежные итоги. Стабильный ID в пределах подключения и счёта определяет одну операцию:
повторная сверка обновляет её без двойного учёта. Одинаковые ID разных счетов
остаются разными выплатами. Изменение источника логотипа позволяет заново
показать изображение после буквенной заглушки.
## Будущие события и ограничения
@@ -102,7 +111,7 @@ Frontend проверяет принадлежность выплат по по
выбранного счёта и сохраняет прежнее поведение. Будущие выплаты
не включаются в итоги полученного дохода или сравнения.
Аналитика только читает данные, не хранит историю операций и не рассчитывает налоги, инвестиционную эффективность, доходность, валютную конвертацию или общий мультивалютный итог.
Аналитика читает сохранённую историю операций и не рассчитывает налоги, инвестиционную эффективность, доходность, валютную конвертацию или общий мультивалютный итог.
Основное проверяемое поведение — в [спецификации дохода](https://git.personal.ksv741.ru/WealthLedger/specs/src/commit/9e227a563dda67620f0ad78228aa8a4c18bf35a0/openspec/specs/brokerage-account-income-analytics/spec.md),
точная форма ответа — в [HTTP API](../../architecture/http-api.md).
+14 -30
View File
@@ -60,39 +60,23 @@ API принимает необязательные `from` и `to` в форма
`incomeTotalsByCurrency`, включающего только купоны и дивиденды.
Итоги остаются в ответе API; полный экран показывает список без общего итога.
Текущие controller, сервис и экран поддерживают выбор периода, тогда как
[основная спецификация](https://git.personal.ksv741.ru/WealthLedger/specs/src/commit/9e227a563dda67620f0ad78228aa8a4c18bf35a0/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: Полный список известных событий либо ошибка
```
Запрос требует сессии, подключения и локально подтверждённого membership.
Прогноз строится из личного сохранённого portfolio и общих календарей: T-Bank для
дивидендов, MOEX для bond events. Отдельного синхронного получения portfolio
нет. Личные оценки сохраняются отдельно от общих календарей.
Запрос требует действующей сессии и подключения T-Bank. Получение
необходимых финансовых данных брокера или календаря MOEX завершается ошибкой
`503`, если источник недоступен: частичный список не выдаётся как полный.
Доступные метаданные инструментов дополняют название и логотип; когда
исходного тикера достаточно для календаря, ошибка дополнительного поиска
метаданных не скрывает события.
Последний полный forecast привязан к scope, периоду и membership.
Если новый portfolio требует ещё недоступного календаря, прежний полный
прогноз и его source times остаются, в том числе после рестарта. Новый
полный результат заменяет его атомарно. Без fallback показывается
missing/partial, а не подтверждённое отсутствие выплат. Другой период или
изменившийся membership не получают старый прогноз под новым названием.
Source failure сообщается в metadata и не изменяет успешное время.
Успешный ответ MOEX без запрошенного блока означает отсутствие поддерживаемых
событий этого источника; это отличается от transport failure и повреждённого
формата ответа.
При первом открытии показан каркас заголовка и строк, без интерактивных
заглушек. Пустой ответ сохраняет возможность изменить период.