[2026-06-25] taiga-vault: family/how-to/htpc-emulators-setup.md family/how-to/htpc-gaming-plans.md family/how-to/kraken-access.md family/how-to/openmediavault-rpi5.md family/how-to/time-machine.md family/how-to/wireguard-vpn.md personal/documents/todo-list.md personal/plans/extract-stable-prompt-blocks.md personal/plans/hermes-whale-system-prompt.md personal/plans/thread-scoped-memory.md

This commit is contained in:
Taiga
2026-06-25 05:23:46 +00:00
parent ac0d753ec0
commit 16987d69f3
26 changed files with 2656 additions and 457 deletions
@@ -0,0 +1,355 @@
# Импорт банковских выписок за последний год
**Создано:** 2026-06-23
**Цель:** Получить все транзакции за последний год (середина 2025 — июнь 2026) в Budget App, автоматизируя импорт банковских выписок как можно полнее.
## Проблема
В `Budget.xlsx` данные заканчиваются в **середине 2025** (май-июнь 2025, в зависимости от счёта). Последние ~12 месяцев транзакций не внесены в Excel. Вручную вспомнить каждую трату за год — нереалистично.
## Существующий инструмент: budget-bank-statement-converter
**Путь:** `~/Developer/budget-bank-statement-converter/`
**Язык:** Swift (macOS command-line tool)
**Формат вывода:** CSV с колонками `[дата, сумма, дебет, кредит, категория, комментарий, курс]` — совпадает с форматом Excel.
### Поддерживаемые банки
| Банк | Формат входа | Конфиг | Статус |
|------|-------------|--------|--------|
| Demir | CSV (из PDF → Adobe Extract → CSV) | `demir-config.json` | ✅ Работает |
| Сбер | CSV (выгрузка из СберБизнес) | `sber-config.json` | ✅ Работает |
| Тинькофф | CSV (выгрузка из Тинькофф) | `tinkoff-config.json` | ✅ Работает |
| ВТБ | CSV (из PDF → Adobe Extract → CSV) | `vtb-config.json` | ✅ Работает |
| Альфа | — | — | ❌ `fatalError("Alfa not implemented")` |
### Как работает
1. **PDF → CSV**: использует Adobe PDF Extract API (`pdfservices-api-credentials.json`) — загружает PDF, получает ZIP с CSV-таблицами.
2. **CSV → формат App**: разбирает CSV, маппит категории через regex-конфиг, нормализует double-entry (дебет/кредит/конверсии).
3. Если нужно — автоматически конкатенирует `fileoutpart0001.csv`… файлы.
4. Использует OpenAI GPT-3.5-turbo для AI-категоризации (закомментировано, `aiMaxTokens = 80`).
### Что нужно для использования
- Xcode (для сборки Swift-проекта)
- `OPENAI_API_KEY` в env (не обязательно, выключено)
- `pdfservices-api-credentials.json` для Adobe Extract
- JSON config для каждого банка: `Сбер config`, `Tinkoff config`, `Demir config`, `VTB config`
## План импорта
### Шаг 1: Получить выписки из банков
**Что нужно выгрузить за июнь 2025 — июнь 2026:**
| Счёт | Банк | Как получить выписку |
|------|------|---------------------|
| Нал RUB | Наличные | Ручной ввод (см. ниже про наличные) |
| Нал KGS | Наличные | Ручной ввод |
| Нал USD | Наличные | Ручной ввод |
| Нал KZT | Наличные | Ручной ввод |
| Demir ИП | Demir | CSV (интернет-банк/моб. приложение) |
| Demir ИП USD | Demir | CSV (интернет-банк/моб. приложение) |
| Demir KGS | Demir | CSV (интернет-банк/моб. приложение) |
| Demir USD | Demir | CSV (интернет-банк/моб. приложение) |
| Тинькофф Black | Тинькофф | CSV (выгрузка из Тинькофф) |
| Тинькофф Кредитка | Тинькофф | CSV (выгрузка из Тинькофф) |
| Сбер | Сбер | CSV (СберБизнес / PDF) |
| Сбер Кредитка | Сбер | CSV (СберБизнес / PDF) |
| Альфа | Альфа | CSV — но конвертер Альфу не поддерживает |
| Альфа Кредитка | Альфа | — |
| ВТБ | ВТБ | PDF → Adobe Extract → CSV |
| ВТБ Кредитка | ВТБ | PDF → Adobe Extract → CSV |
### Шаг 2: Конвертировать выписки в CSV формата App
Запуск для каждого банка:
```bash
./budget-bank-statement-converter --bank <bank> --account <account> <input.csv>
```
Выход: `_processed.csv` с колонками `дата, сумма, дебет, кредит, категория, комментарий, курс`.
### Шаг 3: Написать Python импортёр CSV → Budget App DB
Существующий `xlsx_import.py` читает из Excel. Нужен новый: `csv_bank_import.py`, который:
- Читает CSV в формате App (колонки из `csvHeaders` в `Common.swift`)
- Привязывает `дебет`/`кредит` к существующим счетам в БД (по имени)
- Маппит категории из CSV на существующие категории в БД (по имени подкатегории)
- Игнорирует дубликаты (hash по `date + amount + source + dest + comment`)
- Поддерживает несколько CSV-файлов за раз (много выписок)
- Выводит отчёт: сколько добавлено, сколько пропущено (дубликаты), какие категории не найдены
### Шаг 4: Импортировать в Budget App
```bash
cd ~/Developer/budget-app
uv run python src/budget/importers/csv_bank_import.py <output1.csv> <output2.csv> ...
```
### Шаг 5: Дописать недостающее в Swift-конвертере
- **AlfaToCSV**: реализовать парсер для Альфа-банка (CSV выгрузка из моб. банка/СберБизнес)
- **AI-категоризация**: раскомментировать и обновить (GPT-3.5 → DeepSeek/local LLM?)
## Наличные расходы — проблема и решение
### Проблема
Наличные траты не трекались последний год. У нас есть конечный остаток налички на руках сейчас, но нет истории по категориям.
### Подходы
#### A. Снять остаток наличных сейчас → счёт в БД (простой)
- Посчитать физическую наличку сейчас → записать как `initial_balance` для `Нал RUB`, `Нал KGS`, `Нал USD`, `Нал KZT`.
- Все траты наличными за год никогда не будут зафиксированы.
- **Минус:** дыра в данных большого объёма (вероятно значительная часть расходов).
#### B. Экстраполяция по историческим трендам (средний)
- Взять помесячные тренды наличных трат по категориям за 2023–первую половину 2025.
- Экстраполировать на июнь 2025 — июнь 2026 с учётом сезонности.
- Создать транзакции-плейсхолдеры с пометкой `import_id = 'cash_estimate'`.
- **Минус:** неточность, может не отражать реальные изменения.
#### C. Ретроспектива через месяц-два + экстраполяция (предпочтительный)
- **Сейчас:** начать трекать наличные расходы (вручную или через мобильный интерфейс Budget App).
- **Через 1–2 месяца:** по собранным данным наличных трат вычислить реальные помесячные паттерны.
- Экстраполировать на пропущенный год с этими паттернами.
- **Плюс:** база для экстраполяции будет основана на реальных данных, а не на исторических.
#### D. None of the above — принять дыру
- Сделать только безналичный импорт. Наличные начинаем трекать с сегодня.
- В аналитике отмечать периоды как "без наличных".
- **Плюс:** не надо ничего выдумывать.
### Рекомендация: C+D combined
1. Трекать наличку вручную через UI Budget App начиная с сегодня.
2. Через 2 месяца посчитать реальные тренды и решить, стоит ли экстраполировать на прошлый год.
3. Если нет — просто принять дыру и жить с хорошей аналитикой начиная с 2026-06.
## Что уже реализовано в Budget App для импорта
-`xlsx_import.py` — полный импорт из Budget.xlsx (34k строк)
- ✅ Все счета, категории, курсы, транзакции — в БД
- ✅ Идемпотентный UPSERT для счетов и курсов
- ✅ Транзакции добавляются обычным insert (без import_hash после фикса)
## Реализованный скрипт: bank_scraper
**Путь:** `~/Developer/budget-app/scripts/bank_scraper/`
Структура:
```
scripts/bank_scraper/
├── __init__.py
├── .gitignore # config.yaml + data/imports/ не коммитятся
├── config.example.yaml # шаблон для копирования в config.yaml
├── base_driver.py # base class BankDriver + load_config()
├── orchestrator.py # entry point (н.п.)
└── drivers/
└── demir.py # Demir IB драйвер (н.п.)
```
**Статус:** ✅ base + Demir driver написаны, Playwright установлен. **НО — Demir требует QR-логин через мобильное приложение**, не логин/пароль на сайте.
## Реальность Demir IB
Сайт `93.171.215.109``apps.demirbank.kg/ib/`) — **Flutter web SPA** с QR-аутентификацией. Нет формы логина с паролем — нужно сканировать QR мобильным приложением Demir.
**Варианты решения:**
### A. Продолжить с Playwright + session persistence
- Один раз залогиниться руками (QR → моб. приложение)
- Сохранить session cookies/storage в persistent context
- Дальше переиспользовать сессию для выгрузок (пока не протухнет)
- **Плюс:** минимум кода
- **Минус:** сессия рано или поздно протухнет, нужен ручной ре-логин
### B. Appium / ADB — эмуляция мобильного приложения
- Демонстратор Android/iOS эмулятора с мобильным приложением Demir
- Appium для UI automation внутри приложения
- **Плюс:** полный контроль
- **Минус:** сложно, накладно
### C. Заменить Demir на первый банк с логином/паролем
- Тинькофф имеет API для разработчиков (OAuth)
- Сбер — есть API SberBusinessAPI (хотя для юрлиц)
- Можно начать с Тинькофф: Tinkoff API → выписка без браузера
- **Плюс:** самый простой tech-wise
- **Минус:** Demir пока под вопросом
### D. Парсить CSV выписки, которые уже есть в mobile/email
- Возможно Demir присылает выписки на email
- Или можно скачать через мобильное приложение → экспорт → AirDrop/email себе
- Это полу-ручной подход (но быстрее чем QR scraping)
## Решение
**Рекомендация: A + D**
1. Самый ценный банк — **Тинькофф** (есть API) — начинаем с него
2. Demir — разово выгрузить через мобильное приложение (Export CSV/email)
3. Если сессия Demir долго живёт — Playwright persistent context отработает
### Новый порядок разработки
1. ✅ Demir driver (написан, но упирается в QR)
2. **Tinkoff API driver** — следующий приоритет (без браузера, REST API)
3. **Сбер / ВТБ / Альфа** — Playwright или Tinkoff-style API
4. **Parse Demir CSV** — Python-версия DemirToCSV для уже скачанных файлов
## Файл вывода Swift-конвертера
```
csvHeaders = ["дата", "сумма", "дебет", "кредит", "категория", "комментарий", "курс"]
```
- `дата``dd.MM.yyyy HH:mm` (формат EUR)
- `сумма` — строка с суммой (±знак)
- `дебет` — имя счёта-источника (пусто = доход извне)
- `кредит` — имя счёта-получателя (пусто = расход вовне)
- `категория` — имя подкатегории
- `комментарий` — очищенный текст
- `курс` — кросс-курс при внутреннем переводе между валютами
## Автоматизация выгрузки выписок из банков
### 1. Browser automation libraries (CV-driven)
| Библиотека | Язык | Браузеры | CV | 2FA/SMS |
|-----------|------|----------|----|---------|
| **Playwright** (MS) | Python, JS, Java, .NET ⭐ | Chromium, Firefox, WebKit | Есть (locator screenshots) | `page.wait_for_selector` на поле ввода кода |
| **Puppeteer** (Google) | JS (Python через pyppeteer) | Chromium | Есть | — |
| **Selenium** | Python, Java, JS и др. | Все major | Через сторонние утилиты | — |
**Рекомендация: Playwright Python** — де-факто стандарт в 2025, cross-browser, async, видит элементы даже в SPA, встроенные ожидания. Подходит и для РФ-банков (Сбер, Тинькофф, Альфа-клик — все на SPA).
### 2. Готовые решения на GitHub
**AploBankParsers** ([github.com/Zaurrex1/AploBankParsers](https://github.com/Zaurrex1/AploBankParsers)):
- Парсер выписок **СберБизнес** (production-ready) — читает xlsx/сsv из уже выгруженного файла
- Заглушки для Альфа, ВТБ, Тинькофф
- Это парсер **уже скачанных файлов**, не скрапер
**bank_scrapers** ([github.com/eebette/bank_scrapers](https://github.com/eebette/bank_scrapers)):
- Playwright-based для scraping bank websites
- Generic, не специфичен под РФ-банки
**Sber API** — официальный REST API Сбера:
- `developers.sber.ru/docs/ru/sber-api/specifications/statement/transactions`
- Получение выписки по счёту за 5 лет
- **Требует** корпоративного доступа (SberBusinessAPI / ДБО), не подойдёт для личного СберБанк
**Готового решения "под ключ" для РФ-банков** (Playwright → bank login → 2FA → CSV выписка) **нет** в открытом доступе. Каждый банк — свой уникальный UI и flow. Придётся писать самим.
### 3. Архитектура скрипта
```
┌─────────────────────────────────┐
│ Telegram Bot (Hermes/кит) │ ← запрашивает SMS-код
├─────────────────────────────────┤
│ Orchestrator (Python) │ ← запускает по крону / кнопке
│ ┌─────────────────────────┐ │
│ │ Playwright browser │ │ ← drives bank login page
│ │ - headless=false │ │ (visible для отладки)
│ │ - persistent context │ │ (сессия не слетает)
│ └─────────────────────────┘ │
│ ┌─────────────────────────┐ │
│ │ Bank drivers: │ │
│ │ - tinkoff.py │ │
│ │ - sber.py │ │
│ │ - alfa.py │ │
│ │ - demir.py │ │
│ │ - vtb.py │ │
│ └─────────────────────────┘ │
│ ┌─────────────────────────┐ │
│ │ Output: CSV в формате │ │
│ │ budget-bank-statement- │ │
│ │ converter │ │
│ └─────────────────────────┘ │
└─────────────────────────────────┘
```
### 4. Flow для каждого банка
```
1. Запустить headless Playwright (или visible=False для отладки)
2. Открыть страницу логина банка
3. Ввести credentials (из конфига, НЕ скрипта)
4. Если запрошен SMS-код:
→ отправить в Telegram: "Код из смс для {bank}:"
→ ждать ответа (polling/async)
→ ввести полученный код
5. Дождаться загрузки дашборда
6. Перейти на страницу выписок/истории
7. Указать период: 2025-06-01 — 2026-06-23
8. Скачать CSV/Excel
9. Сохранить в ~/Developer/budget-app/data/imports/{bank}/{date}.csv
10. Конвертировать через budget-bank-statement-converter (или Python-версию)
11. Импортировать в БД
12. Закрыть браузер
```
### 5. Обработка SMS-кодов (Telegram)
Скрипт не должен хранить сессию банка, каждый запуск — новая авторизация.
**Варианты:**
1. **Telegram Bot (inline keyboard)**: скрипт ждёт сообщение, когда нужен код — присылает кнопку "Отправить код для {bank}", пользователь вводит → скрипт вставляет
2. **Hermes-агент**: крон-джоб спрашивает в Telegram нужный код, ждёт ответа через webhook
3. **Простой stdin**: скрипт пишет "Введите код для Тинькофф:" и ждёт ввод (если запуск из терминала)
**Рекомендация: вариант 1** — TG bot минимальная зависимость, полный контроль.
Для реализации: существующий Hermes/Zulip может служить relay. Или простой скрипт на Python + python-telegram-bot с `await incoming_message`.
### 6. Чувствительность данных — ограничения
Скрипт будет:
- Знать **логины/пароли** банков (хранятся в локальном конфиге, НЕ в коде)
- Открывать **браузер на машине Алекса** (никаких VPN/прокси)
- Передавать только SMS-коды через TG — пароли не передаются
- Работать **локально**, без LLM/агентов в browser automation
Код пишем так, чтобы ни одна строка credentials не была в скрипте:
```python
# config.yaml (chmod 600)
banks:
tinkoff:
login: "7999..."
password: "..."
phone: "7999..."
sber:
login: "..."
password: "..."
```
### 7. Альтернатива: API банков (без browser)
| Банк | REST API для личных счетов | Комментарий |
|------|---------------------------|-------------|
| Тинькофф | Есть (Tinkoff API для разработчиков) | Требует регистрации приложения, OAuth |
| Сбер | Sber API для юрлиц, нет для личных | Не подходит |
| Альфа | Альфа-Бизнес API (юрлица) | Не подходит |
| Demir | Нет публичного API | — |
| ВТБ | Нет публичного API | — |
Тинькофф — единственный из списка, у кого есть адекватный API для физлиц (Tinkoff API / Tinkoff Invest API). Можно получить выписку через API, без browser. Остальные — только SPA scraping.
**Код:** 10 swift-файлов, ~2 400 строк.
**Что хорошо:**
- Хорошая архитектура: каждый банк = отдельный struct с чётким интерфейсом
- Конфиги вынесены из кода (JSON)
- Regex-маппинг категорий гибкий
- Умеет объединять multi-part CSV и извлекать из PDF через Adobe API
- Формат вывода совпадает со структурой Excel/Budget App
**Чего не хватает:**
- Парсер Альфа-банка (только заглушка)
- AI-категоризация закомментирована (GPT-3.5, устарела)
- Нет интеграции с Budget App (только → CSV, не → БД)
- Нет обработки для Demir ИП USD / Demir USD / Demir KGS отдельно (DemirToCSV один конфиг на все)
- PDF-парсер привязан к Adobe PDF Extract API (платный сервис, credentials нужны)
- Нет обработки для Сбер Кредитка как отдельного счёта (SberToCSV один конфиг)
- Нет автоматического определения новых форматов CSV от банков
@@ -0,0 +1,70 @@
# Остатки счетов из Excel (Budget.xlsx)
Файл: `~/Downloads/Budget.xlsx`
Лист: `транзакции`
Балансы **совпадают** с API после фиксов (2026-06-23).
| Счёт | Баланс | Валюта | Последняя операция |
|---|---|---|---|
| Нал RUB | 815 555.70 | RUB | 2025-05-16 (R6029, 60 000 deb) |
| Нал KGS | 1 794.00 | KGS | 2025-06-17 (R6042, deb) |
| Нал KZT | -22 820.00 | KZT | 2024-12-15 (R5505, deb) |
| Нал USD | 1.00 | USD | 2025-02-04 (R5976, deb) |
| Нал AED | 0.00 | AED | 2023-11-16 (R2335, deb) |
| Нал EUR | — | EUR | нет операций |
| Нал UZS | 18 000.35 | UZS | 2024-03-31 (R3337, deb) |
| Demir ИП | 192 308.54 | KGS | 2025-01-31 (R5943, deb) |
| Demir ИП USD | 284 842.96 | USD | 2026-05-29 (R6053, cred) |
| Demir KGS | 96 013.12 | KGS | 2025-01-31 (R5947, deb) |
| Demir USD | 3 394.29 | USD | 2025-01-31 (R5950, cred) |
| Тинькофф Black | 521 263.65 | RUB | 2025-01-31 (R5959, deb) |
| Тинькофф Кредитка | 7 170.17 | RUB | 2025-01-28 (R5901, deb) |
| Сбер | 266 905.98 | RUB | 2025-01-28 (R5898, deb) |
| Сбер Кредитка | 3 059.00 | RUB | 2025-01-31 (R5946, deb) |
| Альфа | 78 030.00 | RUB | 2025-01-28 (R5925, cred) |
| Альфа Кредитка | 0.50 | RUB | 2025-01-28 (R5924, deb) |
| ВТБ | 265 178.95 | RUB | 2025-01-27 (R5887, deb) |
| ВТБ Кредитка | 297 189.00 | RUB | 2025-01-31 (R5952, deb) |
| Райффайзен | — | RUB | нет операций |
## Формула API
`balance = incoming_transfer + incoming_income - outgoing + initial_balance`
Где:
- `incoming_transfer``SUM(cross_rate * amount)` где source IS NOT NULL (cross_rate конвертирует валюту source в валюту dest)
- `incoming_income``SUM(amount)` где source IS NULL (amount уже в валюте счёта, cross_rate — только для отчёта)
- `outgoing``SUM(amount)` (всегда в валюте счёта-источника)
## Фиксы (2026-06-23)
### 1. incoming для income и transfer — разный расчёт
Было: `incoming = SUM(COALESCE(cross_rate, 1.0) * amount)` — cross_rate применялся ко всем включая income (где amount уже в валюте счёта). Для KGS-счетов с income-пополнениями (например "Конвертация USD по курсу 87") incoming умножался на 87, давая баланс ×87.
Стало: incoming разделён на две части:
- `incoming_transfer (source IS NOT NULL)`: cross_rate применяется (конвертирует валюту source→dest)
- `incoming_income (source IS NULL)`: просто amount (cross_rate — только для отчётной валюты)
### 2. import_hash и on_conflict_do_nothing — удалены
Было: дедупликация по `import_hash = SHA256(date|amount|source|dest|comment)`. В Excel есть 141 дублирующаяся строка с одинаковыми этими полями (реальные повторные списания). `on_conflict_do_nothing` молча пропускал их, но `tx_count` врал что импортировал.
Стало: обычный `session.add(tx)`. Колонка `import_hash` и уникальный индекс дропнуты из таблицы. Функция `_make_import_hash` удалена.
### 3. Accounts — идемпотентность
Было: каждый запуск импорта создавал 20 новых аккаунтов (session.add). После нескольких запусков — 40+ аккаунтов с разными UUID, транзакции привязаны к разным наборам.
Стало: UPSERT — ищет существующий account по `name + user_id`, переиспользует.
### 4. UserSettings — UPSERT
Было: `session.add(UserSettings(...))` — падало с UniqueViolation при повторном запуске.
Стало: `pg_insert(...).on_conflict_do_update(...)`.
### 5. Нюанс Excel col I/L
Для некоторых строк Excel не кеширует вычисленные значения col I (остаток деб) — показывает None. Это не баг, а особенность data_only=True — если Excel не пересчитал формулы перед сохранением, кеш пуст. В таких случаях последний корректный баланс берётся из предыдущей строки минус amount.
@@ -0,0 +1,264 @@
---
aliases:
- Freedom Strategy
- Budget app FIRE
- Budget app strategy
related:
- '[[personal/projects/budget-app/index]]'
- '[[personal/projects/budget-app/fire-investment-strategies-2026]]'
tags:
- personal
- budget-app
- finance
- FIRE
- freedom
- roadmap
title: Финансовая стратегия + FIRE-адаптация для Budget App
updated: '2026-06-23T00:00:00.000Z'
---
# Финансовая стратегия + FIRE-адаптация для Budget App
**Обновлено:** 2026-06-23
**Основание:** анализ данных budget-app + личные вводные Alex
---
## 1. Текущая позиция (June 2026)
### 1.1 Балансы счетов
| Счёт | Валюта | Баланс | Статус |
|------|--------|--------|--------|
| Нал USD | USD | $925,511 | **Накопления** |
| Demir ИП USD | USD | $284,843 | **Накопления** |
| Demir USD | USD | $3,394 | Остаток |
| Нал KGS | KGS | 1,794 | Остаток (текущие) |
| Demir ИП | KGS | -359,861 | На расход |
| Demir KGS | KGS | -3,542,775 | Ушёл в минус |
| RUB счета (Альфа, Сбер, ВТБ, Тинькофф, Нал) | RUB | ~-29.5M | Кредитки + овердрафты |
| Нал RUB | RUB | -12,709,478 | Долг |
| Альфа | RUB | -18,187,976 | Долг |
**Итого накопления:** ~$1,210,000 USD ≈ **112.5M KGS** (по курсу 93)
**Реально свободные:** ~$100k (нал USD), остальное — предпринимательские счета + оборотка
### 1.2 Расходы (из БД, 2024 — июнь 2025, 17 мес)
| Показатель | Значение |
|------------|----------|
| Средние расходы/мес | ~1,075,000 KGS |
| Средний доход/мес | ~851,000 KGS |
| Норма сбережений (по БД) | -26% (данные неполные — часть трат не проведена) |
Категоризация в БД сломана: все расходы свалены в "📉 Расходы" (11.4M), остальное — депозиты, кэшбэк, аренда (~378k). Данные после июня 2025 не вносились, последняя транзакция май 2026 — видимо разовый импорт.
### 1.3 Внешние активы и доходы
| Статья | Цифра |
|--------|-------|
| **Накопления (ликвид)** | ~$100k (Нал USD) |
| **Аренда 2 квартир** | 60-80k KGS/мес |
| **Образование старшей** | $8-10k/год = 65-77k KGS/мес |
| **Младшая (дистант)** | Запуск в этом году — точные цифры появятся |
| **Частный дом** | Текущее содержание |
| **Indie dev** | Проекта пока нет |
---
## 2. Стратегия (Freedom, не FIRE)
Классический FIRE (накопить 25x и сидеть без дела) **тебе не подходит** по нескольким причинам:
1. **Валютный риск** — живёшь в KGS, доход в RUB/USD. KGS волатильна. FIRE-расчёт в KGS ненадёжен
2. **Образование детей** — крупный обязательный платёж на ~10 лет вперёд. Это не "сократить", это фиксированная статья
3. **Ты не хочешь "не работать"** — инди-дев показывает что хочешь заниматься проектами, а не сидеть на пляже
4. **Две квартиры** — актив, который уже почти покрывает образование старшей
### 2.1 Твоя цель: "Freedom Gap"
Не FIRE number, а **Freedom Gap** — разница между расходами и пассивным/полупассивным доходом, которую нужно закрыть капиталом.
```
Freedom Gap = (расходы/мес) − (аренда + дивиденды + проектный доход)
```
| Сценарий | Расходы/мес | Аренда | Проект | Gap/мес | Капитал для 4% |
|----------|------------|--------|--------|---------|----------------|
| **Сейчас** | ~900k KGS | 70k | 0 | **830k KGS** | **249M KGS** ($2.7M) |
| **Аренда → образование** | 900k | 70k→на образование | 0 | 830k | 249M KGS ($2.7M) |
| **+Проект $2k/мес** | 900k | 70k | 186k | **644k KGS** | **193M KGS** ($2.1M) |
| **+Проект $5k/мес** | 900k | 70k | 465k | **365k KGS** | **110M KGS** ($1.2M) |
### 2.2 Реалистичные вехи
| Веха | Условие | Цифра |
|------|---------|-------|
| **🟢 1ая: аренда = образование** | Аренда 80k покрывает старшую ~77k | ✅ **УЖЕ почти** |
| **🟢 2ая: проект = жизнь** | Проект $3k/мес покрывает ~280k KGS | Нужен работающий проект |
| **🟡 3ая: капитал + аренда = всё** | Накопить 110M KGS ($1.2M) при проекте $5k | 10-15 лет |
| **🔴 4ая: полная свобода** | Накопить 249M KGS ($2.7M) | Долгий горизонт |
---
## 3. Инвестиционная стратегия для Alex
### 3.1 Принципы
1. **Core-Satellite** — 70% широкий рынок (VT / VWRA), 30% дивиденды + защита
2. **Мультивалютность** — портфель в USD (защита от девальвации KGS)
3. **Дивиденды как income stream** — снижают sequence-of-returns risk, частично покрывают расходы
4. **Буфер 12 мес** — в USD, не трогать
5. **Ребаланс раз в год** — не дёргаться
### 3.2 Рекомендуемая аллокация
| Класс | % | Инструмент | Назначение |
|-------|---|-----------|------------|
| **Global Equity ETF** | 60% | VWRA (VT) — IRSH / LSE | Рост капитала, мультивалютная диверсификация |
| **Dividend ETF** | 15% | VIG, SCHD, или HDV | Стабильный дивидендный поток |
| **Bonds (TIPS)** | 10% | TIP (iShares TIPS) | Защита от инфляции |
| **Cash USD** | 10% | HYSA / money market | Буфер, ~12 мес расходов |
| **Real Estate (REIT)** | 5% | VNQ / O | Доход от недвижимости без управления |
**Почему не BND:** для тебя облигации в USD не дают премии, а TIPS защищают от инфляции которая в KGS выше номинальной.
### 3.3 Ребаланс
- **Раз в год** в декабре
- **Автоматический триггер:** любая позиция отклонилась >5% от цели
- **Новые деньги:** направляются в самый отстающий класс (автоматический buy-low)
---
## 4. Что внедрить в budget-app (Phase 6 — Roadmap)
### 4.1 Приоритеты (по ценности)
| # | Фича | Зачем | Оценка сложности | Статус |
|---|------|-------|-----------------|--------|
| **P0** | **Savings Rate Dashboard** | Увидеть реальную норму сбережений. Сейчас -26% — надо понять куда уходят деньги | Medium | ❌ Не начато |
| **P0** | **Multi-Currency Net Worth** | Общий капитал в USD: наличка + счета + квартиры + пассивы | Low | ❌ Не начато |
| **P1** | **Investment Snapshots** | Раз в месяц вбить "сколько на Нал USD / IBKR / крипте" — увидеть динамику | Low | ❌ Не начато |
| **P1** | **Freedom Gap Dashboard** | Доход (аренда+дивиденды+проект) - расходы = gap | Medium | ❌ Не начато |
| **P1** | **Passive Income Tracker** | Сколько приносят аренда, дивиденды, депозиты в месяц | Low | ❌ Не начато |
| **P2** | **Projection Engine** | "Если докладываю X/мес и проекты дают Y/мес — через N лет свобода" | Medium+ | ❌ Не начато |
| **P2** | **What-if Simulator** | "Что если аренда упадёт / курс изменится / проект взлетит" | Medium+ | ❌ Не начато |
| **P3** | **Monte Carlo FI Calculator** | Классический 4% vs 3.5% vs variable, probability of success | High | ❌ Не начато |
| **P3** | **Withdrawal Strategy Planner** | Бакетная / guardrails / dividend | High | ❌ Не начато |
### 4.2 Схема расширения БД
```sql
-- Инвестиционные снапшоты (ручной ввод раз в месяц)
CREATE TABLE investment_snapshot (
id UUID PRIMARY KEY DEFAULT gen_random_uuid(),
user_id UUID NOT NULL REFERENCES "user"(id),
account_id UUID REFERENCES account(id), -- NULL для внешних брокеров
name VARCHAR(128) NOT NULL, -- "Нал USD", "Interactive Brokers", "Крипта"
portfolio_value NUMERIC(16,2) NOT NULL,
currency_code VARCHAR(5) NOT NULL REFERENCES currency(code),
snapshot_date DATE NOT NULL,
asset_class VARCHAR(32), -- cash, bonds, stocks, real_estate, crypto, business
notes TEXT,
UNIQUE(user_id, name, snapshot_date)
);
-- Цели свободы
CREATE TABLE freedom_goal (
id UUID PRIMARY KEY DEFAULT gen_random_uuid(),
user_id UUID NOT NULL REFERENCES "user"(id),
name VARCHAR(128) NOT NULL, -- "Свобода", "Образование детей", "Ремонт дома"
target_amount NUMERIC(16,2) NOT NULL,
target_currency_code VARCHAR(5) NOT NULL REFERENCES currency(code),
current_amount NUMERIC(16,2) DEFAULT 0, -- ручной или вычисляемый
category VARCHAR(32), -- freedom, education, major_purchase
monthly_contribution NUMERIC(16,2), -- план пополнения
target_date DATE,
expected_return_rate NUMERIC(5,4), -- 0.07 = 7%
is_active BOOLEAN DEFAULT true
);
```
### 4.3 UI макет (какие страницы добавить)
```
/dashboard
├── Savings Rate (график за 12 мес + норма)
├── Net Worth (USD, KGS — два числа)
├── Freedom Gap (прогресс-бар: 0% → 100%)
└── Cash Reserve (мес жизни / норма 12)
/freedom
├── Goals (список целей с прогресс-барами)
├── Investment Snapshots (таблица + график)
├── Projection (график: сегодня → свобода)
└── What-if (слайдеры: аренда, проект, курс)
/finances
├── Passive Income (аренда, дивиденды, депозиты за месяц)
└── Allocations (pie chart портфеля)
```
### 4.4 API эндпоинты (новые)
```
GET /api/freedom/goals — список целей свободы
POST /api/freedom/goals — создать цель
PUT /api/freedom/goals/:id — обновить
GET /api/freedom/goals/:id/projection — проекция к цели
GET /api/investments/snapshots — список снапшотов (с пагинацией)
POST /api/investments/snapshots — добавить снапшот
GET /api/investments/snapshots/latest — последний по каждому инструменту
GET /api/dashboard/net-worth — общий капитал (USD + KGS)
GET /api/dashboard/freedom-gap — gap месяца
GET /api/dashboard/passive-income — аренда + дивиденды за период
```
---
## 5. Первый шаг (что сделать прямо сейчас)
### Step 0: Заполнить данные в budget-app
Без актуальных расходов любой расчёт — гадание. Нужно:
1. Импортировать выписки за июнь 2025 — июнь 2026 (Альфа, Сбер, Demir)
2. Разнести по категориям (хотя бы крупные статьи: дети, дом, стройка, еда)
3. Вбить балансы квартир и других активов как investment_snapshot
### Step 1: Net Worth Dashboard
Показать общий капитал в USD без лишних действий.
Уже можно сделать — данные по счетам есть в БД, квартиры добавляются как manual entry.
### Step 2: Investment Snapshots
Форма: дата, инструмент, сумма, валюта → график роста капитала с проекцией.
Без автоматизации — раз в месяц ввести руками.
### Step 3: Freedom Goal
После того как есть:
- реальные расходы (не -26%)
- актуальный капитал с квартирами
- доход от проекта (хоть какой-то)
→ построить Freedom Gap Dashboard с what-if сценариями.
---
## 6. Что не надо делать (анти-приоритеты)
| Не надо | Почему |
|---------|--------|
| Monte Carlo Simulation | Сложно, данных мало, толку для твоего случая 0 |
| Withdrawal Strategy Planner | Ты не на пенсии, не нужен |
| Roth Conversion Ladder | Не применимо (не US resident) |
| FIRE Number Calculator в классике | Тебе нужен Freedom Gap, не 25x |
| Авто-импорт курсов валют | Не влияет на решение — достаточно раз в месяц |
| Сложные прогнозы в KGS | Курс KGS непредсказуем, считай в USD |
---
## 7. Связанные заметки
- [[personal/projects/budget-app/index|Budget App — главный документ]]
- [[personal/projects/budget-app/fire-investment-strategies-2026|Исходное исследование FIRE + инвестстратегий]]
- [[personal/documents/budget-app-features|Список всех идей фич]]
@@ -0,0 +1,246 @@
---
title: FIRE и инвестиционные стратегии для Budget App
tags:
- personal
- budget-app
- finance
- FIRE
- investments
related: '[[personal/projects/budget-app/index]]'
updated: '2026-06-23T00:00:00.000Z'
---
# FIRE и инвестиционные стратегии для Budget App
**Создано:** 2026-06-23
**Источник:** исследование whale (FIRE guides, Goldman Sachs, PIMCO, Bogleheads, 2026)
---
## 1. FIRE-типы и целевые показатели
### 1.1 Виды FIRE
| Тип | Годовые расходы | Целевой портфель | Суть |
|-----|----------------|-------------------|------|
| **Lean FIRE** | < $40,000 | < $1,000,000 | Минимализм, быстрый выход |
| **Chubby FIRE** | $40k$100k | $1M$2.5M | Комфорт без излишеств |
| **Fat FIRE** | $100k+ | $2.5M$6M+ | Высокий уровень жизни |
| **Barista FIRE** | Переменные | 50–80% от полного | Частичная занятость покрывает часть |
| **Coast FIRE** | Любые | Достаточно чтобы дорасти | Перестать пополнять, дать сложному % работать |
### 1.2 FIRE Number
**Формула:** `FIRE Number = Annual Expenses × 25` (4% rule)
На 2026 год рекомендуется **33.5%** вместо 4%:
- Ранний выход = 40–60 лет на пенсии (Trinity Study считала 30 лет)
- Повышенные оценки рынка (Shiller CAPE выше исторической нормы)
- Низкая доходность облигаций
| Норма сбережений | Годовые расходы | FIRE (4%) | FIRE (3.5%) |
|------------------|----------------|-----------|-------------|
| $30,000 | $30,000 | $750,000 | $857,000 |
| $40,000 | $40,000 | $1,000,000 | $1,143,000 |
| $50,000 | $50,000 | $1,250,000 | $1,429,000 |
| $75,000 | $75,000 | $1,875,000 | $2,143,000 |
| $100,000 | $100,000 | $2,500,000 | $2,857,000 |
### 1.3 Скорость до FIRE от нормы сбережений
| Норма сбережений | Лет до FIRE |
|-----------------|-------------|
| 10% | 51 лет |
| 20% | 37 лет |
| 30% | 28 лет |
| 40% | 22 года |
| 50% | 17 лет |
| 60% | 12.5 лет |
| 70% | 8.5 лет |
| 80% | 5.5 лет |
*Assumes 5% real returns, starting from zero*
---
## 2. Стратегии вывода (Withdrawal Strategies)
### 2.1 4% Rule (Trinity Study)
- 95% success rate для 30 лет с 60/40 портфелем
- **Для FIRE (40+ лет):** риск sequence-of-returns выше → используй 3.5%
### 2.2 Flexible Spending (Variable Withdrawal)
- В плохие годы режешь дискреционные траты на 10–20%
- В хорошие — тратишь больше
- **Guardrails:** увеличиваешь withdrawal когда портфель выше цели, уменьшаешь когда ниже
### 2.3 Bucket Strategy
- **Bucket 1 (12 года):** кэш/деньги — текущие расходы
- **Bucket 2 (37 лет):** облигации
- **Bucket 3 (8+ лет):** акции
- Ребалансируешь только когда акции переросли
### 2.4 Dividend Investing
- Покрываешь расходы дивидендами (не продавая акции)
- Ниже общая доходность, но выше стабильность
### 2.5 Roth Conversion Ladder
- Конвертируешь traditional IRA → Roth IRA ежегодно (1 год расходов)
- Через 5 лет конвертированные средства доступны без штрафа
- Нужен 5-летний bridge из taxable счетов
---
## 3. Инвестиционные стратегии на 2026
### 3.1 Strategic Asset Allocation (классика)
- Фиксированные цели, ребаланс раз в квартал/год
- **Типичный model:** 60% equities / 30% fixed income / 10% alternatives
- **Историческая доходность 60/40:** ~6.5% annualized (20142024)
- **Плюс:** убирает эмоции, дисциплина правил
- **Минус:** не адаптируется к среде
### 3.2 Three-Fund Portfolio (Bogleheads)
- US Total Stock Market (VTI/VTSAX)
- International Total Stock Market (VXUS/VTIAX)
- US Total Bond Market (BND/VBTLX)
- **Allocation:** 60/20/20 (или агрессивнее для молодых)
- **Expense ratios:** 0.030.05%
- **Разница в комиссиях:** 0.03% vs 1.0% на $500k за 20 лет = ~$100k+
### 3.3 Tactical Asset Allocation (2026 context)
- Отклонения 5–20% от стратегической аллокации на основе макро
- **Overweight:** энергия (commodities supercycle), floating-rate securities, инфраструктура
- **Underweight:** long-duration bonds, перегретые US tech
- **Добавить:** emerging market debt, inflation-protected assets
- **Alpha:** ~2.1% annually above static (multi-asset, 2024 study)
### 3.4 Enhanced Passive (Goldman Sachs 2026)
- **Alpha Enhanced:** tracking error 50200 bps, чуть выше комиссии
- **Зачем 2026:** снижение ожидаемой рыночной доходности, концентрация индексов, неопределённость
- **Systematic factor tilts** — небольшие ставки на value, momentum, quality
### 3.5 Insured / Dynamic Allocation
- **Insured:** автоматический переход в консерватив при drawdown > X%
- **Dynamic:** 7.8% annualized vs static с меньшими просадками (2024)
- **Рекомендация 2026:** infrastructure, private credit, low-duration fixed income
### 3.6 Goldman Sachs 2026: активные ETF + alternatives
- **Active ETFs:** AUM растёт 46% CAGR с 2020
- **Derivative-income ETFs:** $47B inflows (Q1Q3 2025)
- **Private assets:** Millennials держат ~20%, Boomers ~6% — поколенческий сдвиг
- **Tail-risk hedging:** нужен более широкий набор инструментов (не только bonds/USD)
---
## 4. Тактики для нашего контекста (Alex, мультивалютный, KGS-based)
### 4.1 Особенности
- **Базовая валюта:** KGS (высокая волатильность, зависимость от переводов РФ)
- **Счета:** RUB, USD, EUR, KGS, KZT, UZS, AED, CNY
- **Доход:** в основном RUB/USD
- **Расходы:** KGS (жизнь), USD (крупные/накопления), RUB (регулярные)
### 4.2 Что адаптировать в budget-app
#### Phase 6 — что строить (приоритеты):
1. **FIRE Number Calculator**
- Поле: годовые расходы (берутся из фактических транзакций за 12 мес)
- Поле: текущий инвестированный капитал
- Поле: expected return (47%)
- Вывод: FIRE number (25x / 28.6x / 33x), years to FIRE
- Вывод: сколько нужно докладывать в месяц для выхода через N лет
2. **Savings Rate Dashboard**
- `Норма сбережений = (Доходы - Расходы) / Доходы`
- График: savings rate по месяцам
- График: накопленный капитал vs FIRE trajectory (projection line)
3. **FireGoal модель**
- `fire_goal` таблица: user_id, target_amount, target_currency_id, expected_return_rate, monthly_contribution, target_date
- Progress bar: сколько % от цели накоплено
- What-if: "что если увеличу savings rate на 5%?"
4. **Multi-currency FIRE number**
- Пересчёт цели в base currency (KGS) и в USD
- Проблема: валютный риск при пенсии в KGS — нужно показывать и USD-эквивалент
5. **Investment Tracking**
- `investment` / `portfolio` таблицы: date, account_id, value, currency_id
- Ввод: ручные snapshots (когда обновляешь брокерский счёт)
- График: капитал по месяцам + проекция 7% CAGR
- Автоматический импорт: нет (ручной ввод раз в месяц)
6. **Withdrawal Simulator (+FI Calc)**
- Monte Carlo simulation (по историческим данным)
- Поля: начальный капитал, годовые расходы, asset allocation, withdrawal rate
- Результат: probability of success (не остаться без денег)
- Модель 4% vs 3.5% vs variable
7. **"Буфер" / Cash Reserve Dashboard**
- Сколько месяцев расходов в кэше (по счетам типа cash/debit)
- Целевой буфер: 6–12 месяцев расходов
- Trigger: < 3 мес → alert
### 4.3 Архитектурные решения для budget-app
```
investment_account (таблица):
id, user_id, account_id FK → account,
portfolio_value, currency_id, snapshot_date,
asset_class {cash, bonds, stocks, real_estate, crypto, other},
notes
fire_goal (уже есть в схеме):
id, user_id, target_amount, target_currency_id,
expected_return_rate (decimal, 0.07 = 7%),
monthly_contribution (decimal),
target_date NULL,
current_portfolio_value (вычисляется из investment_account snapshot)
fire_projection:
computed view: по месяцам от текущей даты
columns: month, contribution, return, portfolio_value, is_fire (bool если >= target)
```
### 4.4 Какие FIRE-варианты реалистичны для Alex
| FIRE-тип | Расходы/мес | Год | FIRE Number (4%) | Годовая норма сбережений | Лет* |
|----------|-------------|-----|------------------|-------------------------|------|
| Lean FIRE | Минимальные | ??? | ??? | ??? | ??? |
| Chubby FIRE | Текущие | ??? | ??? | ??? | ??? |
| Barista FIRE | С part-time | ??? | ??? | ??? | ??? |
*\* — нужно подставить фактические цифры из budget-app*
**Рекомендуемая стратегия для Alex:**
- Core: Three-Fund Portfolio (VT + BNDW) — глобальная диверсификация, не привязана к KGS
- Satellite: TIPS / real assets (инфляция в KGS выше чем в USD)
- Дивидендная составляющая: покрывает часть расходов (снижает sequence-of-returns risk)
- Буфер: 12+ месяцев расходов в USD (не KGS — защита от девальвации)
- Ребаланс: раз в год, или при drift > 5%
---
## 5. Ключевые метрики на дашборд
| Метрика | Откуда берётся | Формула |
|---------|---------------|---------|
| **Норма сбережений** | Транзакции за 12 мес | (Доходы - Расходы) / Доходы |
| **FIRE Number** | Средние расходы × 25 | (AvgExpenses × 12) × 25 |
| **FIRE Progress** | Инвестиционный капитал | PortfolioValue / FIRE_Number × 100% |
| **Years to FIRE** | Калькулятор | (ln(FIRE/R) - ln(FIRE/(R - P×12))) / ln(1+r) — сложно |
| **Safe Withdrawal Amount** | Портфель × 4% | PortfolioValue × 0.04 |
| **Runway (мес)** | Кэш / расходы в месяц | CashBalance / MonthlyExpenses |
| **Dollar-Cost Avg Equity** | Инвестиции / куплено единиц | — |
---
## 6. Связанные ресурсы
- [[personal/projects/budget-app/index|Budget App — главный документ]]
- [[personal/documents/budget-app-features|Исходный список фич]]
- [WealthVieu FIRE Guide 2026](https://wealthvieu.com/retirement/fire/)
- [Goldman Sachs — Portfolio Construction 2026](https://am.gs.com/en-us/advisors/insights/article/investment-outlook/portfolio-construction-2026)
- [Bogleheads Safe Withdrawal Rates](https://www.bogleheads.org/wiki/Safe_withdrawal_rates)
- [PIMCO — Investment Ideas for 2026](https://www.pimco.com/us/en/insights/charting-the-year-ahead-investment-ideas-for-2026)
+189 -10
View File
@@ -81,7 +81,7 @@
- Категоризация — ручная.
- Невозможно нормально работать с мобильного.
- Анализ ограничен сводными в Excel: нет нормальных графиков по подкатегориям, кросс-фильтрации, прогнозов.
- Нет ничего про FIRE: проекций пенсии, моделирования инвестиций, целевых процентов нормы сбережений.
- Нет ничего про Freedom Gap / инвестиции: нет трекинга портфеля, нормы сбережений, проекции "когда аренда + проекты покроют расходы".
- История курсов хранится в строках листа `курсы` — это не нормализованная таблица.
- Нет API: нельзя интегрировать с банковскими экспортами, нельзя автоматически тянуть в дашборд.
@@ -95,7 +95,7 @@
2. Считает аналитику и сводки **на лету** через SQL, а не через `VLOOKUP`.
3. Импортирует банковские выписки (Альфа, Сбер, Demir, …) автоматически + AI-резолвер для неоднозначных случаев.
4. Даёт мобильный UI для быстрого ввода трат на ходу.
5. Моделирует **FIRE-сценарии** (отдельная фаза после готового бюджетирования).
5. **Freedom Gap** — разница между расходами и пассивным/полупассивным доходом (аренда, дивиденды, проекты). График прогресса к нулевому gap. What-if сценарии: "если проект даёт X, аренда Y — через N лет свобода".
6. Прогнозирует траты на N месяцев вперёд по сезонной модели (категории `🧱 Стройка`, `🏖️ Отдых` цикличны).
### Доменная модель (первая итерация)
@@ -144,13 +144,34 @@ Base currency не хардкодится — выбирается в `Settings`
1. **Phase 0 — Discovery & schema**. Полностью разобрать Excel, утвердить доменную модель. *(в процессе — этот док)*
2. **Phase 1 — Skeleton + import**. Создать `~/Developer/budget-app/` (git init), FastAPI + Vue в Docker Compose в `~/docker/budget-app/` с подключением к существующему Postgres-кластеру на хосте (новая БД `budget_app`). Миграция xlsx → БД. Read-only viewer транзакций + остатков + годовые отчёты. Внешний доступ через `budget.qentra.top` с auth (FastAPI Users + JWT).
3. **Phase 2 — Курсы и настройки**. Cron-джоб для НБ КР с back-fill. Базовая валюта в настройках. Все пересчёты привязаны к ней.
4. **Phase 3 — Ручной ввод**. Форма добавления транзакции, CRUD категорий/счетов, ручная правка курсов.
5. **Phase 4 — Импорт банков + AI-резолвер**. Автофетч/парсеры (Альфа, Сбер, Demir). LLM-резолвер. TG-бот для ручных подтверждений.
6. **Phase 5 — Аналитика**. Дашборды: расход по категориям, динамика, бёрндаун по бюджету. Прогнозы.
7. **Phase 6 — Mobile / PWA**. Быстрый ввод с телефона.
8. **Phase 7 — MCP HTTP**. Экспонировать MCP-эндпоинт для Hermes.
9. **Phase 8 — Инвестпортфели + FIRE**. Тикеры/цены/дивы. Калькулятор FIRE. *(отдельное планирование когда бюджетирование готово.)*
3. **Phase 2 — Полноценный Viewer + CRUD**. Довести до уровня Excel по функциональности:
- Валюта у счетов (символ)
- Категории с иерархией (группа → подкатегория)
- Свёртка по годам/месяцам (drill-down как в Excel)
- Dynamic scrolling (infinite scroll вместо кнопок пагинации)
- CRUD транзакций: добавление, редактирование, удаление
- CRUD категорий
- CRUD счетов
- Ручная правка курсов
- Дашборды: расход по категориям, динамика, бёрндаун по бюджету
- Прогнозы (сезонная модель по категориям)
- Multi-currency: отображение балансов в валюте счёта + в base currency
- Сводная таблица по годам (как лист `сводная` в Excel)
- Налоговый учёт (как лист `налоги 22-24` в Excel)
4. **Phase 3 — Импорт банков + AI-резолвер**. Автофетч/парсеры (Альфа, Сбер, Demir). LLM-резолвер. TG-бот для ручных подтверждений.
5. **Phase 4 — Mobile / PWA**. Быстрый ввод с телефона.
6. **Phase 5 — MCP HTTP**. Экспонировать MCP-эндпоинт для Hermes.
7. **Phase 6 — Freedom / Инвестиции**. Замена классического FIRE на Freedom Gap — разница между расходами и пассивным доходом.
- P0: Savings Rate Dashboard (норма сбережений из транзакций)
- P0: Multi-Currency Net Worth (общий капитал USD/KGS)
- P1: Investment Snapshots (ручной ввод раз в месяц, таблица + график)
- P1: Freedom Gap Dashboard (доход-расход-аренда-проект = gap)
- P1: Passive Income Tracker (аренда + дивиденды + депозиты)
- P2: Freedom Goal with Projection Engine (what-if сценарии)
- P3: What-if Simulator (слайдеры: курс, аренда, проект, норма сбережений)
- Новые таблицы: `investment_snapshot`, `freedom_goal`
- Новые страницы: `/freedom`, `/finances`
- *Не делать:* Monte Carlo, Withdrawal Strategy Planner, Roth Conversion Ladder — не применимы
### Multi-tenant readiness (для будущего public SaaS)
@@ -340,6 +361,12 @@ CLOUDFLARE_TUNNEL_TOKEN=...
- `echarts` (скаффолд под Phase 5, не используем активно)
- dev: `vite`, `typescript`, `eslint`, `prettier`
### Правила работы
1. **Тесты — обязательны** для каждого нового API-роута или изменения. Если код не покрыт тестом — он не готов.
2. **Обновление доку** — после каждой завершённой задачи обновлять таблицу прогресса и Acceptance criteria в этом доке.
3. **Комит** — после каждой логически завершённой задачи (не раз в 10 шагов).
### Acceptance criteria Phase 1
- [ ] `https://budget.qentra.top` открывается, login работает.
@@ -364,4 +391,156 @@ CLOUDFLARE_TUNNEL_TOKEN=...
---
**Создано:** 2026-06-21
**Статус:** Phase 0 закрыт, Phase 1 спланирован
**Статус:** Phase 1 — в работе
## Phase 1 progress
| Шаг | Статус | Кем |
| -------------------------------------- | ------ | ---- |
| Init репо | ✅ | Орёл |
| Backend skeleton | ✅ | Орёл |
| Postgres bootstrap — роль + БД | ✅ | Кит |
| Alembic initial migration | ✅ | Кит |
| FastAPI Users + auth routes | ✅ | Кит |
| Bootstrap первого юзера | ✅ | Кит |
| XLSX импортёр (6 045 транзакций) | ✅ | Кит |
| Read-only API (12 тестов) | ✅ | Кит |
| Frontend skeleton + read-only страницы | ✅ | Кит |
| Docker Compose (2 сервиса, работает) | ✅ | Кит |
| Cloudflare Tunnel budget.qentra.top | ✅ | Alex |
| Сверка данных | ✅ | Кит |
| | | |
## Disaster recovery: CASCADE data loss
**Сценарий:** Удалён пользователь (A-click → user delete). Из-за `ON DELETE CASCADE` на `transaction_user_id_fkey` все транзакции этого пользователя удалены мгновенно (6 045 строк). Балансы обнулены.
### Recovery шаги (на будущее)
```bash
# 1. Пересоздать пользователя с тем же email (admin123)
curl -XPOST .../api/auth/register -H... -d'{"email":"alex@qentra.top","password":"admin123"}'
# 2. Переимпортировать транзакции из xlsx
cd ~/Developer/budget-app
uv run python src/budget/importers/__init__.py
# 3. Проверить балансы — все 18 счетов должны совпасть с excel-balances.md
# 4. Пересобрать и передеплоить backend (дата формат) + frontend (любые изменения)
docker-compose build backend && docker-compose up -d backend
cd frontend && npm run build && cd .. && docker-compose build --no-cache frontend && docker-compose up -d frontend
```
### Формат даты на фронте (актуальный)
API возвращает `t.date.isoformat()` → `2026-05-29T17:00:00`.
Фронт режет: `{{ t.date.slice(0, 10) }} {{ t.date.slice(11, 16) }}` → `2026-05-29 17:00`.
Если время = `00:00` — в Excel не было времени для этой транзакции. Это корректно.
### Символы валют вместо колонки
Колонка "Валюта" убрана из таблиц Transactions, Accounts, TaxRecords.
Вместо неё символ валюты показывается непосредственно перед суммой (Transactions, TaxRecords) или в ячейке (Accounts).
Маппинг на фронте (постоянный, не из БД):
| Код | Символ | Валюта |
|-----|--------|--------|
| USD | $ | Доллар |
| EUR | € | Евро |
| RUB | ₽ | Рубль |
| KGS | С̲ | Сом (с с нижней чертой) |
| KZT | ₸ | Тенге (уже есть в Unicode) |
Файлы: `frontend/src/pages/Transactions.vue`, `Accounts.vue`, `TaxRecords.vue` — каждая содержит `CURRENCY_SYMBOLS` маппинг и функцию `getCurrencySymbol`/`currencySymbol`.
### Пароль
- `admin123` — совпадает с `ADMIN_PASSWORD` в `.env`
## Phase 2 progress
| Шаг | Статус | Кем |
| ---------------------------------------------------------------------------- | ------ | -------- |
| Валюта у счетов (символ) | ✅ | Кит |
| Категории с иерархией (API + фронт) | ✅ | Кит |
| Фронт: формы CRUD (транзакции, категории, счета) | ✅ | Кит |
| Свёртка по годам/месяцам (drill-down) | ✅ | Кит |
| Dynamic scrolling (infinite scroll) | ✅ | Кит |
| CRUD транзакций (API + тесты) | ✅ | Кит |
| CRUD категорий (API + тесты) | ✅ | Кит |
| CRUD счетов (API + тесты) | ✅ | Кит |
| Ручная правка курсов + API | ✅ | Кит |
| Дашборды (расход по категориям, динамика, сводная) | ✅ | Кит |
| Multi-currency отображение (баланс в валюте счёта + base currency) | ✅ | Кит |
| Сводная по годам | ✅ | Кит |
| Налоговый учёт | ✅ | Кит |
| DateTime в транзакциях (date → DateTime, datetime-local на фронте, миграция) | ✅ | Кит |
| Символ валюты вместо колонки (Transactions, Accounts, TaxRecords) | ✅ | Кит |
### Phase 2 — что сделано (подробно)
**API (новые эндпоинты):**
- `GET /api/reports/monthly?year=` — помесячная разбивка доходов/расходов
- `GET /api/reports/summary` — сводная по годам
- `GET /api/reports/category-breakdown?year=&month=` — расходы по группам категорий (данные для дашборда)
- `GET/POST/PUT/DELETE /api/exchange-rates` — CRUD курсов валют
- `GET /api/exchange-rates/summary` — группировка по типу налога
- `GET/POST/PUT/DELETE /api/tax-records` — CRUD налоговых записей
- Accounts API теперь возвращает `balance_in_base` и `base_currency` (мультивалютность)
**БД:**
- Новая таблица `tax_record` (alembic migration)
**Фронтенд (новые страницы):**
- `/dashboard` — дашборд с помесячной динамикой (CSS-chart), расходами по категориям, сводной по годам
- `/exchange-rates` — таблица курсов с фильтрами, CRUD через модалку
- `/tax-records` — таблица налогов с фильтрами и сводкой по типам
**Фронтенд (доработки):**
- `/transactions` — infinite scroll вместо пагинации (scroll-based)
- `/accounts` — отображение баланса в валюте счёта + в базовой валюте
- Навигация обновлена — добавлены ссылки на Дашборд, Курсы, Налоги
## Тесты
Запуск всех тестов одной командой (из `backend/`):
```bash
cd backend && uv run pytest
```
Verbose: `cd backend && uv run pytest -v`
### Фикстуры
Общий `conftest.py` в `tests/` предоставляет:
- `engine` — Postgres test DB (`budget_app_test`) с `create_all`/`drop_all` на каждый тест + seed валют
- `client` — ASGI клиент с зарегистрированным тестовым юзером
- `auth_headers` — JWT Bearer token
Все тесты используют **Postgres** (не sqlite). Настройка через `settings.test_database_url`.
### Покрытие
**37 тестов + 1 skipped**:
| Файл | Тестов | Что проверяет |
|------|--------|---------------|
| `test_health.py` | 1 | Health endpoint |
| `test_models.py` | 3 | Импорт моделей, метаданные, create_all в sqlite |
| `test_auth.py` | 2 | Auth flow (register→login→me), unauthorized |
| `test_api.py` | 6 | Транзакции (list, filter, search), accounts, reports, unauthorized |
| `test_crud.py` | 6 | CRUD транзакций |
| `test_categories.py` | 8 | CRUD групп и категорий |
| `test_accounts.py` | 6 | CRUD счетов, удаление с транзакциями |
| `test_account_balances.py` | 6 | **Баланс: доход+расход, переводы, cross_rate, initial_balance** |
### Вычисление баланса
`balance = initial_balance + incoming - outgoing`
- `incoming` = SUM(amount) if cross_rate IS NULL, SUM(amount * cross_rate) если перевод между валютами (для dest_account)
- `outgoing` = SUM(amount) — всегда в валюте источника