spec: unify income payment cards and drop period comparisons (WealthLedger/main#33)
124 lines
11 KiB
Markdown
124 lines
11 KiB
Markdown
# System Analysis
|
||
|
||
## Requirement Coverage
|
||
|
||
| Нормативная область | Поток и контракт |
|
||
| --- | --- |
|
||
| `brokerage-account-income-analytics`: удаление `Period comparisons preserve calendar and currency meaning`, выбранный период, полнота, читаемые итоги, отсутствие прогноза | [income-period.mmd](sequences/income-period.mmd), [target schema](contracts/income-analytics-response.schema.json) |
|
||
| `brokerage-account-income-analytics`: точные карточки выплат | [payment-sources.mmd](sequences/payment-sources.mmd), существующая форма entries |
|
||
| `brokerage-account-ledger`: журнал, недавние операции и история инструмента | [payment-sources.mmd](sequences/payment-sources.mmd), существующий ответ операций |
|
||
| `brokerage-account-upcoming-events`: полный список и превью | [payment-sources.mmd](sequences/payment-sources.mmd), существующий ответ событий |
|
||
| `instrument-income-schedules`: будущее, прошлое, неопределённая дата/сумма | [payment-sources.mmd](sequences/payment-sources.mmd), существующие ответы календарей |
|
||
|
||
## Systems and Responsibilities
|
||
|
||
- Пользователь выбирает применённый период и отличает исполненные выплаты от
|
||
возможных поступлений и условий выпуска.
|
||
- Frontend хранит применённые даты в URL, показывает только финансовые значения
|
||
их собственного источника и использует один предметный компонент для
|
||
купонов/дивидендов всех трёх режимов. Он не выводит исполнение из календаря.
|
||
- Backend проверяет доступ, период и покрытие операций; формирует точные
|
||
source-currency итоги и записи выбранного периода. Для income-analytics не
|
||
запрашивает предыдущий или годовой период ради сравнения.
|
||
- Сохранённые операции T-Bank остаются источником фактических выплат; прогноз
|
||
основан на позиции, календарь бумаги — на опубликованных условиях T-Bank/MOEX.
|
||
Они не становятся взаимозаменяемыми при объединении представления.
|
||
|
||
## Interaction Flows
|
||
|
||
- [Доход выбранного периода](sequences/income-period.mmd): доступ, полнота,
|
||
успешный/пустой результат и неполное покрытие без запросов сравнения.
|
||
- [Три источника карточки выплаты](sequences/payment-sources.mmd): подтверждённая
|
||
операция, будущий прогноз и событие календаря; остальные типы сохраняют
|
||
существующее представление.
|
||
|
||
## Contracts
|
||
|
||
| Производитель → потребитель | Транспорт / операция | Целевой контракт |
|
||
| --- | --- | --- |
|
||
| Backend → frontend | `GET /api/v1/brokerage-accounts/{accountId}/income-analytics`, `GET /api/v1/brokerage-accounts/all/income-analytics`, `application/json` 200 | [JSON Schema ограничений ответа](contracts/income-analytics-response.schema.json) поверх текущего backend-generated OpenAPI: убрать `data.previous`, `data.yearComparison`, comparison roles в `meta.dependencies`; оставить выбранный период и все прочие поля и ошибки в исходном смысле. |
|
||
| Backend → frontend | Income summary, операции, события, календари акций/облигаций | Без изменений wire-формы; типизированные исходные данные адаптируются к общему представлению купона/дивиденда на границе UI. |
|
||
|
||
Целевой schema-файл описывает *изменение* ответа и не подменяет полную схему
|
||
неизменённых полей; при согласовании используется вместе с предоставленным
|
||
OpenAPI snapshot. `meta.dependencies` содержит только зависимость выбранного
|
||
периода с ролью `selected`; это не новая причина загрузки другого периода.
|
||
Существующие auth, invalid-period и resource errors не меняются. Отсутствуют
|
||
новые операции/версии и callback-протоколы. Порядок entries и повторяющиеся ID
|
||
сохраняются; повторный HTTP read не должен создавать второе зачисление.
|
||
|
||
## Data and State Semantics
|
||
|
||
- `data: null` с незавершённым покрытием выбранного периода не становится
|
||
нулевым доходом. Успешный полный период без qualifying entries — доступный
|
||
нулевой результат. Свежесть и попытка обновления относятся к выбранному
|
||
результату, не к удалённым comparison-периодам.
|
||
- Купоны/дивиденды фактического дохода — точные исполненные операции с
|
||
исходным знаком, валютой и timestamp; календарное событие с прошедшей датой
|
||
не доказывает их наличие.
|
||
- Forecast projected amount может быть `null`; для dividend `dateKind=registry`
|
||
означает дату реестра, не зачисления. График хранит per-share/per-bond Money,
|
||
опциональную оценку по позиции, известные даты и время источника отдельно от
|
||
`payment` исполненной операции. Неизвестное не становится нулём.
|
||
- Общий предметный компонент получает явный режим происхождения данных;
|
||
адаптация не пересчитывает backend totals и не меняет source identity.
|
||
|
||
## Error and Recovery Semantics
|
||
|
||
- Некорректный черновик остаётся на клиенте с ошибкой поля; серверный invalid
|
||
period и отказ доступа сохраняют действующие ответы без fallback на другой
|
||
период или чужой счёт.
|
||
- Ошибка получения страницы исполненных операций не завершает покрытие
|
||
выбранного периода и не публикует частичный итог как полный. Последний
|
||
подтверждённый результат и его исходное время остаются независимыми от
|
||
неуспеха последней попытки.
|
||
- Ошибка прогноза не скрывает уже загруженный доход; отсутствие оценки,
|
||
логотипа либо даты в календаре не создаёт ложного исполнения или нуля.
|
||
- Поздний ответ прежнего подключения не должен восстановить личные данные
|
||
нового/недоступного подключения; граница доступа сохраняется.
|
||
|
||
## Observability Semantics
|
||
|
||
- Существующие status результата, `meta` полноты/попытки и request correlation
|
||
позволяют отличить полный выбранный период, pending и failure.
|
||
- Событие синхронизации выбранного периода не включает comparison-only
|
||
dependencies; получение прошлого/годового интервала для иных самостоятельных
|
||
запросов не считается сравнением дохода.
|
||
- Новых аналитических событий или чувствительных атрибутов не требуется.
|
||
|
||
## Security and NFR at System Boundaries
|
||
|
||
- Bearer-сессия, текущее подключение и доступ к выбранному счёту проверяются
|
||
до выдачи личных операций; `all` ограничен доступными счетами.
|
||
- Даты остаются включительными календарными датами Europe/Moscow, без
|
||
максимальной длительности; валюты не конвертируются. Не вводится новый SLA.
|
||
|
||
## Compatibility / Migration
|
||
|
||
Удаление `previous` и `yearComparison` из ответа намеренно breaking для
|
||
потребителя старой формы. Backend публикует обновлённый исполняемый OpenAPI;
|
||
frontend получает его как явный artifact и обновляет локальные типы прежде,
|
||
чем интеграция начнёт опираться на новую форму. Строгая semantic compatibility
|
||
между новым OpenAPI и target schema проверяется до поставки. При поставке
|
||
backend и frontend согласуются как пара, без обещания одновременной
|
||
совместимости со старым потребителем. Существующие поля buckets/instruments,
|
||
запросы сводки/журнала/прогноза и их доступность не меняются.
|
||
|
||
## Durable Documentation Candidates
|
||
|
||
- `docs/domains/income/overview.md`: отсутствие сравнений и загрузки чужих
|
||
периодов, только полнота выбранного периода.
|
||
- `docs/domains/portfolio/all-accounts.md`,
|
||
`docs/adr/017-local-tbank-reads-and-background-sync.md`: проверить
|
||
упоминания приоритета и смысла удалённых comparisons; ADR хранить как
|
||
историческое решение, не переписывать как AS-IS.
|
||
- `docs/domains/income/upcoming-events.md`, `docs/domains/instruments/stocks.md`,
|
||
`docs/domains/instruments/bonds.md`, `docs/domains/operations/overview.md`:
|
||
общая карточка при сохранении границы между исполнением, прогнозом и графиком.
|
||
|
||
## Open Questions
|
||
|
||
Нет блокирующих вопросов в утверждённом scope. Детали визуальной композиции
|
||
общего компонента остаются за Engineering Design при сохранении нормативных
|
||
различий денежного и календарного смысла.
|