Адрес бэкенда хранится в shared_preferences и читается до runApp; switchApiBaseUrl сбрасывает токены и кэш старого сервера. Выход стирает refresh-токен и sqlite-кэш ответов. Экран настроек переделан под разделы.
SectionHeader — заголовок блока с короткой акцентной полоской вместо
разделителя. TileCarousel — горизонтальная прокрутка StatTile вместо
Wrap, не требует общей высоты у детей. Оба без экрана-потребителя пока
не влияют на вид приложения.
ColorScheme в AppTheme.light()/.dark() строится из одного seed вместо
двух параллельных наборов чисел для тёмной и светлой темы — акцент
сведён к ChartColors.slot1Blue, чтобы фирменный цвет интерфейса и
основной цвет графиков совпадали. cardTheme/navigationRailTheme/
navigationBarTheme заданы централизованно и каскадом меняют вид
существующих карточек и навигации на всех экранах.
CacheInterceptor кэширует каждый успешный GET по путь+параметры в drift
(sqlite нативно, wasm+OPFS в браузере) и подменяет им сетевую ошибку;
провайдер отдаёт Cached<T>, экран показывает баннер «данные на …».
Контракт для остальных экранов — docs/ai/offline-cache.md.
flake.nix: libsecret/pkg-config для линуксовой сборки, jq/curl для
just app-web-assets (сборка sqlite3.wasm + drift_worker.js).
DateTime.tryParse("2026-09-18") в Dart возвращает локальное время, не UTC —
на MSK (UTC+3) это трёхчасовой сдвиг относительно того, что сервер имел
в виду датой без времени. asDate() перетэговывает те же значения полей как
UTC вместо доверия tryParse; настоящий таймстемп с "Z"/смещением проходит
насквозь без изменений.
Импорт (/imports, /instruments/pending) и фаза 4 (/goals, /income,
/rebalance, /tax, аналитика-хаб с benchmarks_card) — по
docs/ai/import-contract.md и docs/ai/phase4-contract.md. file_picker для
загрузки отчёта.
Riverpod + go_router с auth-guard, NavigationRail на широком экране и bottom bar
на узком. Токены в flutter_secure_storage, на web access живёт в памяти.
Интерцептор подставляет токен и делает ровно один refresh на 401.
Деньги приходят строками и форматируются через Decimal: парсить их в double
значило бы терять копейки ровно там, где бэкенд их бережёт.