spec: simplify runtime requirements #20

Merged
ksv741 merged 2 commits from codex/simplify-complexity-ci into develop 2026-10-03 21:32:47 +03:00
3 changed files with 35 additions and 9 deletions
Showing only changes of commit d861de5ead - Show all commits
@@ -156,7 +156,7 @@
### Requirement: Income payments remain traceable to exact Ledger Entries
В разделе «Выплаты» страница MUST показывать единый список карточек точных исполненных Ledger Entries применённого периода в исходном серверном порядке entries. Каждая выплата MUST иметь собственную сразу видимую карточку с описанием, датой, доступной identity Instrument и signed Money в исходной валюте. Страница MUST NOT добавлять внешние группировочные карточки или заголовки по Instrument либо валюте, subtotals инструмента или количество выплат инструмента. Список MUST сохранять отрицательные корректировки и повторяющиеся operation IDs как отдельные записи и MUST NOT включать записи вне аналитического итога. Отказ от группировочного UI MUST NOT отменять проверки принадлежности entries к instrumentKey, валюты и receipt count ответа или приводить к пересчёту денежных итогов на клиенте.
В разделе «Выплаты» страница MUST показывать единый список карточек точных исполненных Ledger Entries применённого периода в исходном серверном порядке entries. Каждая выплата MUST иметь собственную сразу видимую карточку с описанием, датой, доступной identity Instrument и signed Money в исходной валюте. Страница MUST NOT добавлять внешние группировочные карточки или заголовки по Instrument либо валюте, subtotals инструмента или количество выплат инструмента. Список MUST сохранять отрицательные корректировки и повторяющиеся operation IDs как отдельные записи и MUST NOT включать записи вне аналитического итога. Backend MUST обеспечивать согласованность entries, instrumentKey, валюты и receipt count при формировании ответа из одного набора записей. Frontend SHALL доверять типизированному contract без второго runtime consistency validator и MUST NOT пересчитывать денежные итоги.
#### Scenario: Каждая выплата показана отдельной карточкой
+22 -6
View File
@@ -94,20 +94,29 @@ Portfolio Snapshot является результатом наблюдения
- **THEN** система передаёт её как строку `"-0.5"`
### Requirement: Свежесть и fallback полного Portfolio Snapshot
Система MUST кэшировать полный успешный Portfolio Snapshot отдельно для каждой пары User и Brokerage Account в памяти на 30 секунд. После истечения свежего кэша система MUST получить новый полный снимок; при временной upstream-недоступности она SHALL вернуть последний успешный полный снимок, если ему не более пяти минут, с `isStale: true`. Metadata инструмента MUST NOT влиять на успешность или свежесть Portfolio Snapshot, но MUST быть получено до формирования нового Snapshot, чтобы при доступном upstream-ответе вернуть отображаемое имя инструмента.
Система MUST хранить последний полный успешный Portfolio Snapshot в SQLite
с принадлежностью User, экземпляру подключения и Brokerage Account. Обычный
GET MUST читать сохранённые данные без ожидания T-Bank; missing/stale источники
обновляются в фоне по пользовательскому запросу. Portfolio source свеж 60 секунд.
Ошибка обновления MUST сохранять прежний полный Snapshot и его время без
пятиминутного лимита fallback. Metadata MUST NOT определять успешность или
свежесть финансового Snapshot; при её отсутствии используется доступный fallback.
Система MUST очищать все Portfolio Snapshot User после успешной замены или удаления его T-Bank connection. Успешные metadata инструмента и подтверждённое отсутствие инструмента MUST кэшироваться глобально по FIGI на 24 часа; ошибка metadata lookup MUST NOT кэшироваться.
Система MUST делать прежние личные datasets недоступными после успешной замены
или удаления подключения. Поздняя работа прежнего подключения MUST NOT
публиковаться в новом. Общие metadata и подтверждённое отсутствие инструмента
сохраняются по UID/FIGI на 24 часа; ошибка lookup не подтверждает отсутствие.
#### Scenario: Свежий Snapshot
- **WHEN** User повторно запрашивает тот же Portfolio в течение 30 секунд после успешного получения
- **WHEN** User повторно запрашивает тот же Portfolio в течение 60 секунд после успешного получения
- **THEN** система возвращает свежий Snapshot без нового обращения к T-Bank
#### Scenario: Медленный lookup инструмента
- **WHEN** metadata инструмента ещё отсутствует и его lookup не завершился
- **THEN** система ожидает lookup в пределах gRPC deadline и возвращает name при успешном ответе upstream
- **THEN** система не задерживает локальный ответ ради lookup и показывает доступную identity; сохранённая успешная metadata используется последующим чтением
#### Scenario: Fallback после временной upstream-ошибки
- **WHEN** обновление устаревшего Snapshot неуспешно из-за временной недоступности T-Bank, а последний полный успешный Snapshot получен не более пяти минут назад
- **WHEN** обновление устаревшего Snapshot неуспешно из-за временной недоступности T-Bank, а в текущей границе подключения есть полный успешный Snapshot
- **THEN** система отвечает `200` этим Snapshot с `isStale: true` и исходным `lastSuccessfulAt`
#### Scenario: Недействительный token не маскируется fallback-данными
@@ -118,7 +127,14 @@ Portfolio Snapshot является результатом наблюдения
Клиент SHALL загружать Portfolio при открытии защищённого маршрута
`/accounts/:accountId`. Он MUST использовать успешный ответ в течение
30 секунд, без automatic retry, polling или refetch при возврате фокуса.
30 секунд, без automatic retry или refetch при возврате фокуса.
Polling допускается только для известной работы открытого экрана;
data GET наблюдения использует `sync=observe` и MUST NOT запускать новый импорт.
Status сообщает state/errorCode без hash notifications и численных progress counters.
После ухода или завершения работы polling MUST прекращаться.
Предзагрузка всей истории свечей бумаг портфеля MUST NOT выполняться.
Новый диапазон свечей загружается при его открытии; initial loading допустим.
При загрузке без ранее полученного успешного ответа для этого же Brokerage
Account клиент MUST показывать структурное skeleton-состояние ожидаемого
содержимого, включая сводку, без вымышленных сумм. Область загрузки MUST
+12 -2
View File
@@ -53,11 +53,21 @@
#### Scenario: Истёкшая сессия
- **WHEN** клиент отправляет refresh-cookie Session, не обновлявшейся более 7 дней
- **THEN** система удаляет refresh-cookie и отвечает `401` Problem Details с code `UNAUTHORIZED`
- **THEN** система отвечает `401` Problem Details с code `UNAUTHORIZED`, не изменяя cookie неуспешным refresh
#### Scenario: Повторное использование refresh token
- **WHEN** клиент отправляет refresh token, заменённый предыдущим успешным refresh
- **THEN** система удаляет refresh-cookie и отвечает `401` Problem Details с code `UNAUTHORIZED`, не отзывая связанную Session только из-за этого запроса
- **THEN** система отвечает `401` Problem Details с code `UNAUTHORIZED`, не изменяет cookie и не отзывает связанную Session только из-за этого запроса
### Requirement: Межвкладочная координация не требуется
Frontend MUST сохранять изоляцию данных текущей identity внутри вкладки.
Он MUST NOT требовать cross-tab synchronization для auth flow. После смены
auth-состояния в другой вкладке допускаются reload или повторная авторизация.
Неуспешный refresh MUST NOT удалять cookie успешного конкурентного запроса.
#### Scenario: Конкурентный refresh проигрывает в другой вкладке
- **WHEN** вкладка получает `401` после ротации общей cookie другой вкладкой
- **THEN** она может перейти на login; cookie победителя остаётся доступной для последующего восстановления
### Requirement: Завершение сессии
Система SHALL позволять завершить текущую Session через logout. Logout MUST отозвать Session, если refresh-cookie соответствует активной Session, и MUST удалить refresh-cookie. Logout MUST быть идемпотентным и не раскрывать существование Session.