Files
specs/openspec/changes/archive/2026-08-28-portfolio-income-analytics/tasks.md
T

84 lines
19 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.
## 1. Базовые backend-механизмы операций и расчётов
- [x] 1.1 [backend] Расширить существующий сервис Account Ledger проверяющим доступ сборщиком полного диапазона, который переиспользует mapping страниц и LRU, проходит каждую cursor chain до terminal page и отклоняет отсутствующий либо повторяющийся continuation cursor; сохранить поведение публичного Ledger endpoint и добавить целевые regression tests.
- **Covers:** `brokerage-account-income-analytics` — `Realized income analytics is account-scoped and period-bound`; `brokerage-account-income-analytics` — `Realized analytics never presents an incomplete result as complete`
- **Verification:** Запустить целевые backend-наборы Jest для проверки ownership/cache в BrokerageOperationsService, успешного сбора нескольких страниц, распространения ошибки страницы, отсутствующего cursor и повторяющегося cursor.
- [x] 1.2 [backend] Расширить общие BigInt decimal utilities каноническим parsing/comparison десятичных строк и реализовать date-only планирование диапазонов в Europe/Moscow для периода по умолчанию и пользовательского периода, сравнения с предыдущим периодом/полным месяцем, доступности year-ago и day/week/month buckets; добавить risk-based unit tests.
- **Covers:** `brokerage-account-income-analytics` — `Realized income analytics is account-scoped and period-bound`; `brokerage-account-income-analytics` — `Period comparisons preserve calendar and currency meaning`; `brokerage-account-income-analytics` — `Analytics summary and trend remain readable per currency`
- **Verification:** Запустить целевые backend-тесты Jest для некорректных, обратных, будущих и превышающих 366 дней диапазонов, границ месяца по Москве, equal-duration и full-month comparisons, leap-day/pre-opened year comparison, порогов buckets и точной signed decimal arithmetic.
## 2. Backend-проекции дохода и публичный контракт
- [x] 2.1 [backend] Реализовать общую income aggregation core и защищённые проекции current-month summary/full analytics: выбирать только точные типы coupon/dividend, сохранять исходные валюты и знаки, формировать union для comparisons, empty buckets, точные группы инструментов и включённые primary entries.
- **Covers:** `brokerage-account-income-analytics` — `Realized income analytics is account-scoped and period-bound`; `brokerage-account-income-analytics` — `Realized income uses exact executed coupon and dividend payments`; `brokerage-account-income-analytics` — `Period comparisons preserve calendar and currency meaning`; `brokerage-account-income-analytics` — `Analytics summary and trend remain readable per currency`; `brokerage-account-income-analytics` — `Instrument breakdown is traceable to exact Ledger Entries`; `brokerage-account-income-analytics` — `Realized analytics never presents an incomplete result as complete`; `brokerage-account-income-analytics` — `Account overview has an independent current-month income summary`
- **Verification:** Запустить целевые backend-тесты сервиса для исключения неточных типов, отрицательных корректировок, мультивалютных итогов без grand total, нулевых результатов, differences сравнений, полноты buckets, стабильного instrument fallback/group ordering, сверки drill-down и поведения источника «полностью или ошибка».
- [x] 2.2 [backend] Добавить Nest DTO/controller contracts для `GET /api/v1/brokerage-accounts/:accountId/income-summary` и `GET /api/v1/brokerage-accounts/:accountId/income-analytics`, включая строгую валидацию date-only query, существующую семантику auth/account errors и Swagger schemas.
- **Covers:** `brokerage-account-income-analytics` — `Realized income analytics is account-scoped and period-bound`; `brokerage-account-income-analytics` — `Account overview has an independent current-month income summary`
- **Verification:** Запустить controller/DTO tests, проверяющие передачу аутентифицированного User, принятие периода по умолчанию и валидных дат, отклонение некорректных inputs, обработку недоступного счёта и сгенерированные response shapes.
- [x] 2.3 [backend] Добавить точный расчёт `incomeTotalsByCurrency` в существующий полный ответ Future Cash Events, учитывая только события coupon/dividend с известным projected Money и не меняя ordering событий, поведение списка и семантику ошибок.
- **Covers:** `brokerage-account-income-analytics` — `Forecast is separate from realized income`
- **Verification:** Запустить regression tests UpcomingEventsService для итогов coupon/dividend, неизвестных сумм, исключения maturity/offer, нескольких исходных валют, ошибки источника и неизменившихся ordering/content существующих событий.
- [x] 2.4 [backend] Добавить или расширить backend risk-based tests на границах service/HTTP contract для authorization, точного Money, полного cursor traversal и обратной совместимости additive public response.
- **Covers:** `brokerage-account-income-analytics` — `Realized income analytics is account-scoped and period-bound`; `brokerage-account-income-analytics` — `Realized income uses exact executed coupon and dividend payments`; `brokerage-account-income-analytics` — `Realized analytics never presents an incomplete result as complete`; `brokerage-account-income-analytics` — `Forecast is separate from realized income`
- **Verification:** Запустить затронутые backend-наборы Jest с `--runInBand` и проверить, что существующие regression cases Portfolio, Ledger и Events выполняются вместе с новыми критическими cases для money/security/public contract.
## 3. Синхронизация контракта OpenAPI
- [x] 3.1 [frontend] Скопировать сгенерированный backend-документ OpenAPI в committed frontend snapshot и регенерировать frontend schema types до добавления consumers; не редактировать transport DTO вручную.
- **Covers:** `N/A` — Это требуемый утверждённым Design мост совместимости для двух новых backend endpoints и additive Events field; он не вводит самостоятельного observable behavior.
- **Verification:** Запустить `npm run openapi:generate` в `frontend`, затем проверить, что generated `paths` содержат оба income endpoints и `incomeTotalsByCurrency` без несвязанного contract drift.
## 4. Frontend-данные, overview и состояние применённого периода
- [x] 4.1 [frontend] Добавить public API income entity и типизированные React Query hooks для summary/full analytics на основе generated `paths`, с 30-секундным stale time, без automatic retry и через существующий authenticated query client.
- **Covers:** `brokerage-account-income-analytics` — `Realized income analytics is account-scoped and period-bound`; `brokerage-account-income-analytics` — `Account overview has an independent current-month income summary`
- **Verification:** Запустить целевые hook tests для account-scoped path/query parameters, отключённых запросов без account, default summary request, cache identity применённого диапазона и настроенной query policy.
- [x] 4.2 [frontend] Интегрировать независимое состояние current-month income summary в ViewModel страницы Account и семантические section views для empty и loaded outcomes Portfolio, включая локальные loading/error/empty states и ссылку на полную аналитику.
- **Covers:** `brokerage-account-income-analytics` — `Account overview has an independent current-month income summary`
- **Verification:** Запустить tests ViewModel/view страницы Account, доказывающие отображение source-currency summary, фиксированный current-month behavior, локальную ошибку summary и сохранение видимости успешно загруженных Portfolio и соседних sections.
- [x] 4.3 [frontend] Реализовать ViewModel страницы дохода счёта с каноническими явными URL-параметрами `from`/`to`, draft state на react-hook-form/Zod, синхронизацией apply/reset и Back/Forward, состоянием полного realized query и независимой проекцией трёх ближайших forecast events из существующего Events query.
- **Covers:** `brokerage-account-income-analytics` — `Realized income analytics is account-scoped and period-bound`; `brokerage-account-income-analytics` — `User explicitly applies an analytics period represented in the URL`; `brokerage-account-income-analytics` — `Realized analytics never presents an incomplete result as complete`; `brokerage-account-income-analytics` — `Forecast is separate from realized income`
- **Verification:** Запустить целевые tests ViewModel для default URL canonicalization, изоляции draft, корректного apply, reset, восстановления navigation, ограничений для некорректного/будущего/слишком длинного периода, состояний loading/error/empty realized analytics и изоляции ошибки forecast.
## 5. Frontend-представление аналитики и навигация
- [x] 5.1 [frontend] Создать принадлежащие странице structural loading/error/empty/loaded views и source-currency sections для selected/previous/year summaries, включая требуемую формулировку налоговой границы и недоступное годовое сравнение без языка investment performance.
- **Covers:** `brokerage-account-income-analytics` — `Realized income uses exact executed coupon and dividend payments`; `brokerage-account-income-analytics` — `Period comparisons preserve calendar and currency meaning`; `brokerage-account-income-analytics` — `Realized analytics never presents an incomplete result as complete`
- **Verification:** Запустить tests рендеринга страницы для signed corrections, значений coupon/dividend/total по валютам, отсутствующего grand total, недоступного year comparison, явного успешного zero state и recoverable realized error.
- [x] 5.2 [frontend] Реализовать без новой зависимости управляемый валютой stacked trend с positive/negative baseline и его структурированный текстовый эквивалент с точными значениями, сохраняя все backend buckets, включая нулевые, для day/week/month granularities.
- **Covers:** `brokerage-account-income-analytics` — `Analytics summary and trend remain readable per currency`
- **Verification:** Запустить component tests, проверяющие переключение валюты, отдельные segments coupon/dividend, представление отрицательной корректировки, нулевые buckets, доступный с клавиатуры control и читаемые значения buckets независимо от графики/цвета.
- [x] 5.3 [frontend] Реализовать per-currency строки instrument breakdown в переданной backend сортировке и раскрываемые точные включённые Ledger Entries с переиспользованием существующего представления строки Ledger.
- **Covers:** `brokerage-account-income-analytics` — `Instrument breakdown is traceable to exact Ledger Entries`
- **Verification:** Запустить component tests, которые сверяют subtotal/total/count каждой строки с раскрытыми entries, сохраняют отрицательные корректировки и исключают несвязанные entries.
- [x] 5.4 [frontend] Добавить семантически отдельную forecast section на основе backend-поля `incomeTotalsByCurrency` и трёх ближайших подходящих Events, с локальными loading/error/empty states, предупреждением о неопределённости и ссылкой на полную страницу Events.
- **Covers:** `brokerage-account-income-analytics` — `Forecast is separate from realized income`
- **Verification:** Запустить component/page tests для source-currency forecast totals, неизвестного Money, исключения maturity/offer, фиксированного 30-дневного будущего периода, ограничения в три события, независимой ошибки forecast и неизменившегося realized content.
- [x] 5.5 [frontend] Зарегистрировать `/accounts/:accountId/income`, lazy export страницы и account breadcrumb trail, предоставить действия перехода только из overview выбранного Account и сохранить глобальную навигацию без изменений.
- **Covers:** `brokerage-account-income-analytics` — `User explicitly applies an analytics period represented in the URL`; `brokerage-account-income-analytics` — `Account overview has an independent current-month income summary`
- **Verification:** Запустить route/breadcrumb tests для прямого защищённого перехода, иерархии Accounts → account → income, ссылок overview и отсутствия нового элемента глобальной навигации.
## 6. As-built документация
- [x] 6.1 [docs] Документировать поставленный поток income analytics счёта, границу realized/forecast, endpoints, семантику source currency/date, поведение полного результата/ошибки и текущие ограничения; обновить применимые domain/system navigation без копирования planning artifacts.
- **Covers:** `N/A` — Durable as-built документация требуется утверждённой four-area Delivery Map, но не реализует дополнительного observable product requirement.
- **Verification:** Сверить затронутые Markdown links и terminology с поставленным runtime/OpenAPI behavior, затем запустить canonical gate репозитория docs.
## 7. Gates затронутых областей и cross-contract
- [x] 7.1 [backend] Запустить canonical gate backend под Node 22 после завершения всей backend-реализации и целевых risk tests.
- **Covers:** `N/A` — Это required governance completion gate затронутой backend-области; он проверяет реализацию, уже сопоставленную с утверждёнными Requirements.
- **Verification:** Запустить `npm run verify` в `backend` под Node 22.
- [x] 7.2 [frontend] Запустить canonical gate frontend под Node 22 после генерации OpenAPI, реализации route/UI и целевых tests.
- **Covers:** `N/A` — Это required governance completion gate затронутой frontend-области; он проверяет реализацию, уже сопоставленную с утверждёнными Requirements.
- **Verification:** Запустить `npm run verify` в `frontend` под Node 22.
- [x] 7.3 [docs] Запустить canonical gate docs под Node 22 после согласования as-built документации с поставленным поведением.
- **Covers:** `N/A` — Это required governance completion gate затронутой docs-области; он проверяет утверждённый documentation delivery outcome.
- **Verification:** Запустить `npm run verify` в `docs` под Node 22.
- [x] 7.4 [specs] Сверить отметки tasks только с evidence завершённой реализации и запустить strict canonical change validation без создания последующих artifacts или archive evidence.
- **Covers:** `N/A` — Это поддерживает canonical SDD authority и предоставляет gate затронутой specs-области; observable behavior реализуют backend/frontend tasks.
- **Verification:** Запустить `openspec validate portfolio-income-analytics --type change --strict --store wealth-ledger-specs` из `specs` и проверить, что у каждого завершённого checkbox есть соответствующее delivered evidence.
- [x] 7.5 [workspace] Проверить синхронизированный двусторонний runtime OpenAPI contract после публикации backend и генерации frontend snapshot/types.
- **Covers:** `N/A` — Cross-repository orchestration контракта требуется утверждённым Design, но не владеет backend- или frontend-поведением.
- **Verification:** Запустить `npm run test:openapi-contract` в `backend` под Node 22 против committed frontend OpenAPI snapshot.