Данные пользователя обновляются backend автоматически раз в час и без отдельной команды синхронизации с frontend. При открытии кабинета backend быстро возвращает последние сохранённые данные из SQLite; при отсутствии данных либо старше 1 часа дополнительно запускает обновление. Данные должны быть пригодны для будущего графика динамики стоимости портфеля.
Текущее решение
Для одного пользователя, одного backend-процесса и SQLite достаточно cron-задачи в backend с интервалом 1 час.
При запросе кабинета backend обслуживает сохранённое состояние и не ждёт T-Bank. Обновление выполняется фоном, если данные старше 1 часа.
Frontend не выступает источником синхронизирующих запросов и не управляет расписанием.
Накопление истории стоимости отдельно от текущего состояния: текущий снимок портфеля можно перезаписывать для быстрого чтения, а исторические точки добавлять со временем.
Для истории достаточно агрегатов по счету и стоимости; полный JSON портфеля в каждую точку не сохранять без подтверждённой потребности. Для одного пользователя и часового шага SQLite остаётся подходящей базой; при добавлении полной истории позиций оценивать объём перед увеличением шага данных.
Все частичные либо неуспешные обновления не должны заменять последнее успешное состояние.
Что подтвердить до реализации
Является ли открытие клиента дополнительным триггером к обновлению только при отсутствии данных либо возрасте более 1 часа.
Охват cron-задачи: все подключённые счета, портфель, доступные счета, актуальные операции и события по бумагам из портфеля. Полная рыночная история и ранее полностью загруженные интервалы исторических операций остаются вне автоматического обхода.
Политика хранения истории: интервал записи, измерение стоимости брокера либо собственный расчёт, пункты графика по времени либо торговым сессиям.
Обновление ADR 017: сейчас он фиксирует запуск синхронизации только запросами экранов и ручным действием. Также уточнить, остаются ли per-source TTL вспомогательными правилами обычных запросов, а cron — отдельным ограничением полного обновления данных.
Архитектурные ограничения
Сохранить существующих владельцев source sync, дедупликацию, reservations, атомарную публикацию и попытки изменения revision/connection.
Не создавать параллельную загрузку и запись тех же данных.
Не накапливать повторно загруженные полные интервалы операций и свечи.
Модель deployment пока один backend process с SQLite; scheduler не должен считаться безопасным для нескольких экземпляров без отдельного решения по координации.
Для оценки фактического размера и прироста SQLite необходимо провести замер на реальном количестве счетов, операций и инструментов. Числовые внешние лимиты T-Bank дополнительно подтвердить действующей первичной документацией до настройки частоты вызовов.
Ожидаемый результат
Backend каждые 60 минут обновляет согласованный набор текущих данных пользователя, добавляет исторические точки стоимости, быстро отдаёт сохранённое состояние и корректно отражает последнее успешное обновление и частичные сбои.
## Цель
Данные пользователя обновляются backend автоматически раз в час и без отдельной команды синхронизации с frontend. При открытии кабинета backend быстро возвращает последние сохранённые данные из SQLite; при отсутствии данных либо старше 1 часа дополнительно запускает обновление. Данные должны быть пригодны для будущего графика динамики стоимости портфеля.
## Текущее решение
- Для одного пользователя, одного backend-процесса и SQLite достаточно cron-задачи в backend с интервалом **1 час**.
- При запросе кабинета backend обслуживает сохранённое состояние и не ждёт T-Bank. Обновление выполняется фоном, если данные старше 1 часа.
- Frontend не выступает источником синхронизирующих запросов и не управляет расписанием.
- Накопление истории стоимости отдельно от текущего состояния: текущий снимок портфеля можно перезаписывать для быстрого чтения, а исторические точки добавлять со временем.
- Для истории достаточно агрегатов по счету и стоимости; полный JSON портфеля в каждую точку не сохранять без подтверждённой потребности. Для одного пользователя и часового шага SQLite остаётся подходящей базой; при добавлении полной истории позиций оценивать объём перед увеличением шага данных.
- Все частичные либо неуспешные обновления не должны заменять последнее успешное состояние.
## Что подтвердить до реализации
1. Является ли открытие клиента дополнительным триггером к обновлению только при отсутствии данных либо возрасте более 1 часа.
2. Охват cron-задачи: все подключённые счета, портфель, доступные счета, актуальные операции и события по бумагам из портфеля. Полная рыночная история и ранее полностью загруженные интервалы исторических операций остаются вне автоматического обхода.
3. Политика хранения истории: интервал записи, измерение стоимости брокера либо собственный расчёт, пункты графика по времени либо торговым сессиям.
4. Обновление ADR 017: сейчас он фиксирует запуск синхронизации только запросами экранов и ручным действием. Также уточнить, остаются ли per-source TTL вспомогательными правилами обычных запросов, а cron — отдельным ограничением полного обновления данных.
## Архитектурные ограничения
- Сохранить существующих владельцев source sync, дедупликацию, reservations, атомарную публикацию и попытки изменения revision/connection.
- Не создавать параллельную загрузку и запись тех же данных.
- Не накапливать повторно загруженные полные интервалы операций и свечи.
- Модель deployment пока один backend process с SQLite; scheduler не должен считаться безопасным для нескольких экземпляров без отдельного решения по координации.
- Для оценки фактического размера и прироста SQLite необходимо провести замер на реальном количестве счетов, операций и инструментов. Числовые внешние лимиты T-Bank дополнительно подтвердить действующей первичной документацией до настройки частоты вызовов.
## Ожидаемый результат
Backend каждые 60 минут обновляет согласованный набор текущих данных пользователя, добавляет исторические точки стоимости, быстро отдаёт сохранённое состояние и корректно отражает последнее успешное обновление и частичные сбои.
Синхронизация личных данных управляется backend, без запуска с frontend или при открытии экранов. Первый обход — после нового подключения; далее через 60 минут от начала предыдущей попытки для этого подключения. При рестарте учитывать сохранённое время последней попытки, не воспроизводить пропущенные тики и не запускать параллельные обходы; сбой повторять на следующем тике. Если попытки ещё не было и данные отсутствуют или старше часа — запускать при старте. Обход > часа пропускает перекрытый тик.
Обход: подтверждённый список доступных счетов, портфель каждого счёта, изменяемый хвост операций, события по бумагам портфеля; без полной рыночной истории и повторной сверки полностью загруженных исторических интервалов. Успех фиксируется по счёту/источнику: сбой не заменяет предыдущие успешные данные, а результат всего обхода может быть частичным. Хранить последний статус попытки, время и проблемные счета/разделы; показывать на кабинете. При временном сбое показывать последние успешные данные; при подтверждённом отказе токена скрывать личные данные до восстановления доступа.
Убрать с инвестиционных экранов кнопки и команды ручной синхронизации с T-Bank и автоматическое обновление личных данных по коротким per-source TTL. Первичная загрузка ещё не загруженного исторического периода операций сохраняется; полностью загруженные старые периоды не перечитываются. Повтор чтения после сетевой ошибки и действия с ручными банковскими картами остаются. На всех открытых инвестиционных экранах перечитывать данные с backend каждые 30 минут, без запуска синхронизации T-Bank. Свежесть портфеля отражает час с последнего успешного обновления; ошибки показываются отдельно.
Точка истории стоимости записывается после любого успешного получения полной оценки портфеля, включая первую загрузку, на реальное время, по пользователю, счёту и валюте, без конвертации и ретроспективного заполнения. Пустой счёт без известной валюты не даёт денежной точки. Если хотя бы одна позиция без цены, пропускать все точки обновления этого счёта (но сохранять новый текущий состав). Хранить точки без установленного срока; график и его API пока не нужны.
История продолжает линию того же accountId после замены токена; при отключении/успешном исчезновении счёта из membership проставлять deletedAt и скрывать историю. После успешного подтверждения доступа к этому accountId снова снять отметку; при ошибке получения membership не менять видимость. Текущие данные/attempts сохраняют существующую revision-изоляцию и правила доступа.
Справочные данные инструментов (название, тикер, ISIN, описание, показатели компании) и поиск не хранить отдельно: запрашивать онлайн при чтении, в том числе при 30-минутном перечитывании открытой страницы. При сбое показывать ошибку справочного блока; подписи из сохранённого снимка портфеля допустимы как fallback. События (дивиденды/купоны и др.) сохранять и обновлять; во время их расчёта разрешён онлайн-запрос необходимых сведений без сохранения отдельного справочника. Котировки/свечи сохраняются; при открытии страницы обновлять не чаще часа.
ADR 017 и объяснение свежести нужно согласовать с новым поведением при реализации. Ограничение: один backend process + SQLite, без предположения о безопасности нескольких экземпляров.
Согласовано в обсуждении (Q1–Q53):
- Синхронизация личных данных управляется backend, без запуска с frontend или при открытии экранов. Первый обход — после нового подключения; далее через 60 минут от **начала** предыдущей попытки для этого подключения. При рестарте учитывать сохранённое время последней попытки, не воспроизводить пропущенные тики и не запускать параллельные обходы; сбой повторять на следующем тике. Если попытки ещё не было и данные отсутствуют или старше часа — запускать при старте. Обход > часа пропускает перекрытый тик.
- Обход: подтверждённый список доступных счетов, портфель каждого счёта, изменяемый хвост операций, события по бумагам портфеля; без полной рыночной истории и повторной сверки полностью загруженных исторических интервалов. Успех фиксируется по счёту/источнику: сбой не заменяет предыдущие успешные данные, а результат всего обхода может быть частичным. Хранить последний статус попытки, время и проблемные счета/разделы; показывать на кабинете. При временном сбое показывать последние успешные данные; при подтверждённом отказе токена скрывать личные данные до восстановления доступа.
- Убрать с инвестиционных экранов кнопки и команды ручной синхронизации с T-Bank и автоматическое обновление личных данных по коротким per-source TTL. Первичная загрузка ещё не загруженного исторического периода операций сохраняется; полностью загруженные старые периоды не перечитываются. Повтор чтения после сетевой ошибки и действия с ручными банковскими картами остаются. На всех открытых инвестиционных экранах перечитывать данные с backend каждые 30 минут, без запуска синхронизации T-Bank. Свежесть портфеля отражает час с последнего успешного обновления; ошибки показываются отдельно.
- Точка истории стоимости записывается после любого успешного получения полной оценки портфеля, включая первую загрузку, на реальное время, по пользователю, счёту и валюте, без конвертации и ретроспективного заполнения. Пустой счёт без известной валюты не даёт денежной точки. Если хотя бы одна позиция без цены, пропускать **все** точки обновления этого счёта (но сохранять новый текущий состав). Хранить точки без установленного срока; график и его API пока не нужны.
- История продолжает линию того же accountId после замены токена; при отключении/успешном исчезновении счёта из membership проставлять deletedAt и скрывать историю. После успешного подтверждения доступа к этому accountId снова снять отметку; при ошибке получения membership не менять видимость. Текущие данные/attempts сохраняют существующую revision-изоляцию и правила доступа.
- Справочные данные инструментов (название, тикер, ISIN, описание, показатели компании) и поиск не хранить отдельно: запрашивать онлайн при чтении, в том числе при 30-минутном перечитывании открытой страницы. При сбое показывать ошибку справочного блока; подписи из сохранённого снимка портфеля допустимы как fallback. События (дивиденды/купоны и др.) сохранять и обновлять; во время их расчёта разрешён онлайн-запрос необходимых сведений без сохранения отдельного справочника. Котировки/свечи сохраняются; при открытии страницы обновлять не чаще часа.
ADR 017 и объяснение свежести нужно согласовать с новым поведением при реализации. Ограничение: один backend process + SQLite, без предположения о безопасности нескольких экземпляров.
Проверка реализации перед правками: TbankConnectionService.put удаляет прежнее подключение вместе с приватными строками, TbankAccessRepository.publishMembership удаляет исчезнувшие счета каскадно, PortfolioRepository.publish атомарно сохраняет текущий снимок по (userId, revision, accountId); историю стоимости нужно хранить отдельно от каскадных связей и проверять доступ при чтении. tbank-source.policy.ts и владельцы отдельных ресурсов реализуют TTL, TbankSyncService управляет screen-intent, screen-sync.ts вызывает POST и восстанавливает неудачные GET. Справочные сведения хранятся в TbankInstrument, TbankCatalogDiscovery, TbankInstrumentLookup и TbankInstrumentSource, причём detail служит зависимостью событий и рыночных данных. Это означает, что отказ от их хранения — отдельная совместимая миграция с проверкой всех потребителей, не простая смена TTL. Первая безопасная граница: атомарная история в publish + учёт доступа/удаления; затем durable hourly orchestration и status; после — переход читающих маршрутов/frontend и онлайн-справочник. Каждую границу проверять на реальной SQLite для CAS/migration и контрактом API при изменении wire shape.
Проверка реализации перед правками: `TbankConnectionService.put` удаляет прежнее подключение вместе с приватными строками, `TbankAccessRepository.publishMembership` удаляет исчезнувшие счета каскадно, `PortfolioRepository.publish` атомарно сохраняет текущий снимок по `(userId, revision, accountId)`; историю стоимости нужно хранить отдельно от каскадных связей и проверять доступ при чтении. `tbank-source.policy.ts` и владельцы отдельных ресурсов реализуют TTL, `TbankSyncService` управляет screen-intent, `screen-sync.ts` вызывает POST и восстанавливает неудачные GET. Справочные сведения хранятся в `TbankInstrument`, `TbankCatalogDiscovery`, `TbankInstrumentLookup` и `TbankInstrumentSource`, причём detail служит зависимостью событий и рыночных данных. Это означает, что отказ от их хранения — отдельная совместимая миграция с проверкой всех потребителей, не простая смена TTL. Первая безопасная граница: атомарная история в publish + учёт доступа/удаления; затем durable hourly orchestration и status; после — переход читающих маршрутов/frontend и онлайн-справочник. Каждую границу проверять на реальной SQLite для CAS/migration и контрактом API при изменении wire shape.
Проверяемый порядок внедрения (без параллельной второй синхронизации):
История и доступ, backend/SQLite. Добавить отдельные таблицы истории стоимости/видимости счетов, не каскадящиеся при смене revision; сохранять оценки вместе с публикацией полного снимка в одной транзакции после проверки attemptId/revision. Исключать точки при любой позиции без оценки; пустой безвалютный счёт не даёт точек. Миграция additive, существующую БД не очищать. При успешном новом membership помечать/восстанавливать видимость, при замене токена оставлять историю только видимой для подтверждённых счетов, при DELETE скрывать, при ошибке не менять. Тест на реальной SQLite: повторная публикация/старый attempt/замена токена/исчезновение и восстановление счёта, ошибка membership.
Расписание, backend. В owner tbank-sync сделать одну durable hourly attempt per user+connection с persisted startedAt/status/issues, запуск при первом подключении и после старта по age попытки. Existing source owners выполняют работу с теми же reservations, вне длинных DB-транзакций; источник/счёт могут успешно публиковаться независимо. Перекрытый тик пропускать, рестарт не ускоряет retry и не оставляет вечный running. Статус только последней попытки, публичный read-only endpoint/DTO для кабинета; тесты на сбой одного источника, рестарт, race revision и длительную попытку + contract parity.
Развести причины загрузки, backend. Обычные reads инвестиционных экранов не резервируют refresh личных данных; продолжить первичную загрузку отсутствующей истории и range свечей. Свежесть личного portfolio/membership/tail отражает час, а ошибку показывает отдельно. Текущие котировки/незавершённые свечи обновлять при запросе не чаще часа. События портфеля участвуют в обходе. Проверить по всем экранным owner-методам, что GET не запускает повторную личную синхронизацию и старые полные интервалы не перечитываются.
Онлайн-справочник, backend. Изменить instrument/search owner так, чтобы detail/company/metadata/lookup/catalog получались на каждый запрос онлайн без отдельной долговременной копии; сохранённые котировки, свечи и календари/события не терять. Развязать их зависимость от detail row, не нарушив идентичность UID/FIGI, null/ambiguous lookup и нормализацию; сохранённые подписи snapshot остаются fallback. Только после перехода всех readers — совместимая миграция старых справочных строк, без каскадного удаления свечей. Тесты недоступного провайдера, отсутствующей цены, дублей и доступа.
Frontend + контракт. Получить опубликованный OpenAPI от backend локальным контрактным способом; убрать лишь инвестиционные sync POST/кнопки/recovery-trigger, сохранить transport retry. Data GET/статус перечитывать раз в 30 мин на открытых инвестиционных экранах, статус частичного обхода показывать в кабинете с проблемными счетами/разделами; онлайн detail показывать с локальной ошибкой. Не изменять auth refresh и банковские карты. Проверить контракт, граничные состояния, перезапрос без POST, полные frontend gates.
Документация и контроль. ADR 017 сохранить как историю выбора и явно пометить изменённые решения новым ADR (часовой scheduler/отказ от ручной сверки/онлайн-справочник); обновить тематические страницы только после проверки кода. Измерить рост реальной SQLite и уточнить внешние rate limits по первичной документации до окончательной частоты RPC. На всех границах проверить git diff --check, тесты owner, migration/durability, backend/frontend verify и безопасность доступа; frontend получает только публичный API artifact.
Границы 1–4 — отдельные backend изменения, 5 — consumer; до завершения перехода контракт старых экранов нельзя удалять без согласованного совместимого релиза.
Проверяемый порядок внедрения (без параллельной второй синхронизации):
1. **История и доступ, backend/SQLite.** Добавить отдельные таблицы истории стоимости/видимости счетов, не каскадящиеся при смене `revision`; сохранять оценки вместе с публикацией полного снимка в одной транзакции после проверки `attemptId`/`revision`. Исключать точки при любой позиции без оценки; пустой безвалютный счёт не даёт точек. Миграция additive, существующую БД не очищать. При успешном новом membership помечать/восстанавливать видимость, при замене токена оставлять историю только видимой для подтверждённых счетов, при DELETE скрывать, при ошибке не менять. Тест на реальной SQLite: повторная публикация/старый attempt/замена токена/исчезновение и восстановление счёта, ошибка membership.
2. **Расписание, backend.** В owner `tbank-sync` сделать одну durable hourly attempt per user+connection с persisted startedAt/status/issues, запуск при первом подключении и после старта по age попытки. Existing source owners выполняют работу с теми же reservations, вне длинных DB-транзакций; источник/счёт могут успешно публиковаться независимо. Перекрытый тик пропускать, рестарт не ускоряет retry и не оставляет вечный `running`. Статус только последней попытки, публичный read-only endpoint/DTO для кабинета; тесты на сбой одного источника, рестарт, race revision и длительную попытку + contract parity.
3. **Развести причины загрузки, backend.** Обычные reads инвестиционных экранов не резервируют refresh личных данных; продолжить первичную загрузку отсутствующей истории и range свечей. Свежесть личного portfolio/membership/tail отражает час, а ошибку показывает отдельно. Текущие котировки/незавершённые свечи обновлять при запросе не чаще часа. События портфеля участвуют в обходе. Проверить по всем экранным owner-методам, что GET не запускает повторную личную синхронизацию и старые полные интервалы не перечитываются.
4. **Онлайн-справочник, backend.** Изменить instrument/search owner так, чтобы detail/company/metadata/lookup/catalog получались на каждый запрос онлайн без отдельной долговременной копии; сохранённые котировки, свечи и календари/события не терять. Развязать их зависимость от detail row, не нарушив идентичность UID/FIGI, null/ambiguous lookup и нормализацию; сохранённые подписи snapshot остаются fallback. Только после перехода всех readers — совместимая миграция старых справочных строк, без каскадного удаления свечей. Тесты недоступного провайдера, отсутствующей цены, дублей и доступа.
5. **Frontend + контракт.** Получить опубликованный OpenAPI от backend локальным контрактным способом; убрать лишь инвестиционные sync POST/кнопки/recovery-trigger, сохранить transport retry. Data GET/статус перечитывать раз в 30 мин на открытых инвестиционных экранах, статус частичного обхода показывать в кабинете с проблемными счетами/разделами; онлайн detail показывать с локальной ошибкой. Не изменять auth refresh и банковские карты. Проверить контракт, граничные состояния, перезапрос без POST, полные frontend gates.
6. **Документация и контроль.** ADR 017 сохранить как историю выбора и явно пометить изменённые решения новым ADR (часовой scheduler/отказ от ручной сверки/онлайн-справочник); обновить тематические страницы только после проверки кода. Измерить рост реальной SQLite и уточнить внешние rate limits по первичной документации до окончательной частоты RPC. На всех границах проверить `git diff --check`, тесты owner, migration/durability, backend/frontend verify и безопасность доступа; frontend получает только публичный API artifact.
Границы 1–4 — отдельные backend изменения, 5 — consumer; до завершения перехода контракт старых экранов нельзя удалять без согласованного совместимого релиза.
Blocking a user prevents them from interacting with repositories, such as opening or commenting on pull requests or issues. Learn more about blocking a user.
Цель
Данные пользователя обновляются backend автоматически раз в час и без отдельной команды синхронизации с frontend. При открытии кабинета backend быстро возвращает последние сохранённые данные из SQLite; при отсутствии данных либо старше 1 часа дополнительно запускает обновление. Данные должны быть пригодны для будущего графика динамики стоимости портфеля.
Текущее решение
Что подтвердить до реализации
Архитектурные ограничения
Ожидаемый результат
Backend каждые 60 минут обновляет согласованный набор текущих данных пользователя, добавляет исторические точки стоимости, быстро отдаёт сохранённое состояние и корректно отражает последнее успешное обновление и частичные сбои.
Согласовано в обсуждении (Q1–Q53):
ADR 017 и объяснение свежести нужно согласовать с новым поведением при реализации. Ограничение: один backend process + SQLite, без предположения о безопасности нескольких экземпляров.
Проверка реализации перед правками:
TbankConnectionService.putудаляет прежнее подключение вместе с приватными строками,TbankAccessRepository.publishMembershipудаляет исчезнувшие счета каскадно,PortfolioRepository.publishатомарно сохраняет текущий снимок по(userId, revision, accountId); историю стоимости нужно хранить отдельно от каскадных связей и проверять доступ при чтении.tbank-source.policy.tsи владельцы отдельных ресурсов реализуют TTL,TbankSyncServiceуправляет screen-intent,screen-sync.tsвызывает POST и восстанавливает неудачные GET. Справочные сведения хранятся вTbankInstrument,TbankCatalogDiscovery,TbankInstrumentLookupиTbankInstrumentSource, причём detail служит зависимостью событий и рыночных данных. Это означает, что отказ от их хранения — отдельная совместимая миграция с проверкой всех потребителей, не простая смена TTL. Первая безопасная граница: атомарная история в publish + учёт доступа/удаления; затем durable hourly orchestration и status; после — переход читающих маршрутов/frontend и онлайн-справочник. Каждую границу проверять на реальной SQLite для CAS/migration и контрактом API при изменении wire shape.Проверяемый порядок внедрения (без параллельной второй синхронизации):
revision; сохранять оценки вместе с публикацией полного снимка в одной транзакции после проверкиattemptId/revision. Исключать точки при любой позиции без оценки; пустой безвалютный счёт не даёт точек. Миграция additive, существующую БД не очищать. При успешном новом membership помечать/восстанавливать видимость, при замене токена оставлять историю только видимой для подтверждённых счетов, при DELETE скрывать, при ошибке не менять. Тест на реальной SQLite: повторная публикация/старый attempt/замена токена/исчезновение и восстановление счёта, ошибка membership.tbank-syncсделать одну durable hourly attempt per user+connection с persisted startedAt/status/issues, запуск при первом подключении и после старта по age попытки. Existing source owners выполняют работу с теми же reservations, вне длинных DB-транзакций; источник/счёт могут успешно публиковаться независимо. Перекрытый тик пропускать, рестарт не ускоряет retry и не оставляет вечныйrunning. Статус только последней попытки, публичный read-only endpoint/DTO для кабинета; тесты на сбой одного источника, рестарт, race revision и длительную попытку + contract parity.git diff --check, тесты owner, migration/durability, backend/frontend verify и безопасность доступа; frontend получает только публичный API artifact.Границы 1–4 — отдельные backend изменения, 5 — consumer; до завершения перехода контракт старых экранов нельзя удалять без согласованного совместимого релиза.