130 lines
17 KiB
Markdown
130 lines
17 KiB
Markdown
# Brokerage Account Ledger Specification
|
||
|
||
## Purpose
|
||
|
||
Позволяет пользователю просматривать исполненные операции одного брокерского счёта, чтобы понимать фактические денежные и инструментальные движения.
|
||
|
||
## Requirements
|
||
|
||
### Requirement: User can retrieve an account ledger
|
||
Система MUST предоставлять аутентифицированный журнал только для чтения одного Brokerage Account, принадлежащего текущему User. Журнал MUST содержать только исполненные операции T-Bank и при отсутствии периода по умолчанию охватывать интервал от начала текущего календарного года до момента запроса.
|
||
|
||
#### Scenario: Получение журнала с периодом по умолчанию
|
||
- **WHEN** аутентифицированный User запрашивает журнал принадлежащего ему Brokerage Account без периода
|
||
- **THEN** система возвращает его исполненные операции от начала текущего календарного года до момента запроса
|
||
|
||
#### Scenario: Отклонение недоступного счёта
|
||
- **WHEN** аутентифицированный User запрашивает журнал счёта, который не является открытым поддерживаемым счётом, доступным через его T-Bank connection
|
||
- **THEN** система возвращает существующий ответ о недоступности счёта и не раскрывает операции
|
||
|
||
### Requirement: User can browse a filtered ledger
|
||
Система MUST позволять User ограничивать журнал включительным периодом дат и любым подмножеством категорий trade, income, tax, fee, transfer, other. Система MUST разбивать упорядоченный результат на страницы с непрозрачным cursor и возвращать признак доступности следующей страницы.
|
||
|
||
#### Scenario: Фильтрация доходных операций за период
|
||
- **WHEN** User запрашивает период дат и категорию income
|
||
- **THEN** результат содержит только исполненные доходные операции с датой в пределах этого периода
|
||
|
||
#### Scenario: Продолжение истории
|
||
- **WHEN** User запрашивает cursor следующей страницы, возвращённый предыдущим ответом журнала
|
||
- **THEN** система возвращает следующую страницу без повторения записей предыдущей страницы
|
||
|
||
### Requirement: Ledger entries preserve broker operation meaning
|
||
Система MUST представлять одну upstream-операцию одной записью журнала и MUST передавать её timestamp, тип операции, категорию, описание, доступные идентификаторы инструмента, доступную presentation metadata инструмента, денежную выплату, количество, цену, НКД и комиссию. Денежные поля MUST сохранять исходную валюту и точное десятичное значение.
|
||
|
||
#### Scenario: Отображение купонной выплаты
|
||
- **WHEN** T-Bank возвращает исполненную купонную операцию с выплатой и данными инструмента
|
||
- **THEN** запись журнала определяет её как income и передаёт исходную сумму выплаты, валюту и данные инструмента
|
||
|
||
#### Scenario: Отображение комиссии сделки без синтетической записи
|
||
- **WHEN** T-Bank возвращает исполненную сделку, содержащую выплату и комиссию
|
||
- **THEN** журнал содержит одну запись сделки с комиссией в качестве её детали
|
||
|
||
#### Scenario: Отображение движения бумаг без денег
|
||
- **WHEN** T-Bank возвращает исполненную операцию, изменяющую состав инструментов, но без денежной выплаты
|
||
- **THEN** запись журнала передаёт доступное количество и не содержит искусственной денежной выплаты с нулевым значением
|
||
|
||
#### Scenario: Доступна визуальная идентичность инструмента
|
||
- **WHEN** для инструмента исполненной операции доступна presentation metadata бренда
|
||
- **THEN** запись журнала передаёт её вместе с доступными идентификаторами инструмента, не меняя остальные сведения операции
|
||
|
||
### Requirement: Account overview includes recent ledger events
|
||
Обзор счёта MUST показывать пять последних исполненных записей журнала этого счёта и действие перехода к его полному журналу. Каждая показанная запись MUST иметь ту же визуальную идентичность инструмента и семантику денежного движения, что и запись полного журнала. Неуспешный или пустой запрос последних записей MUST оставаться локальным состоянием блока последних событий и MUST NOT заменять успешно отображённый обзор Portfolio.
|
||
|
||
#### Scenario: Отображение последних событий
|
||
- **WHEN** загружается обзор счёта и его журнал содержит исполненные операции
|
||
- **THEN** обзор показывает не более пяти последних записей и ссылку на полный журнал
|
||
|
||
#### Scenario: Последние записи недоступны
|
||
- **WHEN** обзор счёта успешно загружается, но запрос последних записей завершается ошибкой
|
||
- **THEN** обзор Portfolio остаётся доступным, а блок последних событий отображает собственное состояние восстановления
|
||
|
||
#### Scenario: Последняя запись не содержит visual metadata инструмента
|
||
- **WHEN** одна из последних записей не имеет доступной presentation metadata инструмента
|
||
- **THEN** обзор показывает для неё понятный текстовый fallback и сохраняет дату, тип, инструмент и денежное изменение записи доступными для чтения
|
||
|
||
### Requirement: Full ledger presents compact rows
|
||
|
||
Страница полного журнала MUST показывать для каждой записи дату, тип операции, инструмент и денежное изменение в исходной валюте в компактной структурированной строке. При доступной presentation metadata инструмента строка MUST показывать его визуальную идентичность; при её отсутствии MUST использовать понятный текстовый fallback. Для каждой записи денежное изменение в исходной валюте MUST сопровождаться подписью конкретного типа события и знаком: для купонной операции — «Купон», для дивидендной — «Дивиденд», для остальных записей — подпись их категории («Сделка», «Налог», «Комиссия», «Перевод», «Прочее»). Строка MUST NOT повторять подпись типа события во вторичной метадате записи. Знак «+» / «−» и семантический цвет MUST оставаться носителями направления и MUST NOT заменяться только текстом. Страница MUST обозначать записи без движения денег нейтрально и MUST NOT показывать цену или количество.
|
||
|
||
#### Scenario: Отображение записи только с инструментом
|
||
- **WHEN** полный журнал отображает запись без денежной выплаты
|
||
- **THEN** страница определяет её как запись без движения денег
|
||
|
||
#### Scenario: Отображение поступления
|
||
- **WHEN** полный журнал отображает запись с положительной денежной выплатой
|
||
- **THEN** строка явно показывает поступление знаком и подписью конкретного типа события («Купон», «Дивиденд» или категории) и его денежное изменение в исходной валюте, не полагаясь только на цвет
|
||
|
||
#### Scenario: Отображение списания
|
||
- **WHEN** полный журнал отображает запись с отрицательной денежной выплатой
|
||
- **THEN** строка явно показывает списание знаком и подписью конкретного типа события («Купон», «Дивиденд» или категории) и его денежное изменение в исходной валюте, не полагаясь только на цвет
|
||
|
||
#### Scenario: Отображение купона
|
||
- **WHEN** полный журнал отображает запись с upstream-типом купона
|
||
- **THEN** строка показывает подпись «Купон»
|
||
|
||
#### Scenario: Отображение дивиденда
|
||
- **WHEN** полный журнал отображает запись с upstream-типом дивиденда
|
||
- **THEN** строка показывает подпись «Дивиденд»
|
||
|
||
#### Scenario: Подпись типа не дублируется
|
||
- **WHEN** полный журнал отображает запись с типом события и вторичной метадатой
|
||
- **THEN** подпись типа события присутствует в строке один раз и не повторяется во вторичной метадате записи
|
||
|
||
#### Scenario: Отсутствует visual metadata инструмента
|
||
- **WHEN** полный журнал отображает запись без доступной presentation metadata инструмента
|
||
- **THEN** строка показывает понятный текстовый fallback без подмены или сокрытия доступных данных инструмента
|
||
|
||
### Requirement: Кэш страниц журнала ограничивает локальные ресурсы
|
||
Система SHALL кэшировать не более 100 недавно использованных страниц Account Ledger в каждом backend process не более чем на 30 секунд. Cache key MUST включать User, Brokerage Account, нормализованные период и categories, opaque cursor и limit; порядок или дублирование categories MUST NOT создавать отдельную cache identity, а отсутствующий конец периода MUST использовать текущий 30-секундный bucket. Просроченная страница MUST NOT возвращаться, а при переполнении cache MUST удалять наименее недавно использованную страницу.
|
||
|
||
#### Scenario: Равнозначные фильтры используют одну cache identity
|
||
- **WHEN** User в одном 30-секундном bucket повторяет запрос страницы журнала с теми же периодом, cursor и limit, но с categories в другом порядке или с дубликатами
|
||
- **THEN** система использует ту же cache identity и не запрашивает upstream повторно для свежей страницы
|
||
|
||
#### Scenario: Большое число уникальных запросов не увеличивает cache без границы
|
||
- **WHEN** backend обслуживает больше 100 уникальных запросов страниц журнала
|
||
- **THEN** cache содержит не более 100 страниц и освобождает наименее недавно использованные страницы
|
||
|
||
#### Scenario: Просроченная страница не возвращается
|
||
- **WHEN** cached страница журнала старше 30 секунд
|
||
- **THEN** система не возвращает её как свежий результат и получает актуальную страницу из upstream
|
||
|
||
### Requirement: User can explicitly apply ledger filters
|
||
Система MUST позволять User формировать черновик периода и категорий на странице полного журнала и применять его явным действием. Пока черновик изменён, но не применён, видимый список записей и его курсорная пагинация MUST оставаться основанными на последнем применённом состоянии. Явное применение MUST коммитить черновик в применимое состояние и сбрасывать курсорную пагинацию на первую страницу. Сброс фильтров MUST очищать черновик, немедленно применять пустой фильтр (период по умолчанию и все категории) и сбрасывать пагинацию.
|
||
|
||
#### Scenario: Черновик изменён, но не применён
|
||
- **WHEN** User изменил период или категории в контролах фильтров, но не нажал «Применить»
|
||
- **THEN** видимый список записей остаётся основанным на последнем применённом фильтре, а новый запрос к серверу не выполняется
|
||
|
||
#### Scenario: Применение черновика
|
||
- **WHEN** User нажал «Применить» на фильтре журнала с изменённым черновиком
|
||
- **THEN** черновик коммитится в применимое состояние, курсорная пагинация сбрасывается на первую страницу и выполняется новый запрос с применённым периодом и категориями
|
||
|
||
#### Scenario: Сброс фильтров
|
||
- **WHEN** User нажал «Сбросить» на фильтре журнала
|
||
- **THEN** черновик очищается, немедленно применяется пустой фильтр (период по умолчанию и все категории) и курсорная пагинация сбрасывается на первую страницу
|
||
|
||
#### Scenario: Пагинация по применённому фильтру
|
||
- **WHEN** User переходит к следующей или предыдущей странице журнала при изменённом, но не применённом черновике
|
||
- **THEN** пагинация выполняется по последнему применённому фильтру, а черновик в контролах сохраняется
|