Files
fin-tracker/AGENTS.md
T
Dmitry 220f027652 docs: контракт для агентов, архитектура и план фаз
AGENTS.md — индекс, команды и обязательные ограничения (Decimal для денег, не
конвертировать валюту на записи, SDK T-Invest ровно в одном модуле, аналитика
читает только confirmed). docs/ai/ — архитектура, соглашения, эксплуатация и
полный план на шесть фаз с проверками для каждой.
2026-09-18 13:43:31 +03:00

82 lines
6.5 KiB
Markdown
Raw Blame History

This file contains ambiguous Unicode characters
This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.
# AGENTS.md
Контракт для AI-агентов в этом репозитории. Подробности — в [`docs/ai/`](docs/ai/README.md);
этот файл — индекс, команды и ограничения, не описание архитектуры.
## Проект одной фразой
Личная аналитика финансов и инвестиций: ZenMoney (повседневные деньги) + брокеры
(T-Invest API, отчёты Сбера и ВТБ) → PostgreSQL → FastAPI → Flutter-клиент. Заменяет
Snowball Income. Один пользователь, свой VPS.
## Команды
```bash
nix develop # backend toolchain (uv, python 3.12, postgres 17, just, openapi-generator)
nix develop .#app # + Flutter
just db-start # локальный Postgres в ./.pgdata на порту 54329
just migrate # alembic upgrade head
just api # FastAPI с reload, http://127.0.0.1:8000/api/v1/docs
just web # то же + Flutter web-сборка с того же origin (WEB_DIR=app/build/web)
just worker # планировщик синков
just check # ruff + pyright + pytest + проверка дрейфа OpenAPI
just openapi # экспорт openapi/openapi.json (коммитится)
just gen-client # Dart-клиент в app/packages/api_client (коммитится)
just revision "msg" # новая alembic-миграция из изменений моделей
```
Тесты поднимают собственный Postgres через `pg_ctl` (pytest-postgresql) — Docker не нужен.
## Карта задача → контекст
| Задача | Что читать |
|---|---|
| Любое изменение | [docs/ai/README.md](docs/ai/README.md), затем нужный раздел [architecture.md](docs/ai/architecture.md) |
| Новый источник данных (`backend/src/fintracker/sources/`) | architecture.md §Источники, `sources/base.py`, `worker/runner.py` |
| Модель данных / миграции (`models/`, `alembic/`) | architecture.md §Домен, [conventions.md](docs/ai/conventions.md) |
| Аналитика / метрики | architecture.md §Аналитика, [conventions.md](docs/ai/conventions.md) §Деньги |
| API / Flutter-клиент | architecture.md §API, `openapi/openapi.json` |
| Деплой | `docker-compose.yml`, `deploy/Caddyfile`, [ops.md](docs/ai/ops.md) |
## Обязательные ограничения
- **Деньги — `Decimal`**, в БД `NUMERIC(24,10)` + колонка валюты рядом. Никаких float в
хранении и в API (в JSON — строки). Float допустим только внутри расчёта коэффициентов.
- **Не конвертировать валюту на записи.** Конвертация — по курсу на дату операции, в
аналитике. Нет курса → NULL и запись в data quality, не подмена.
- **SDK T-Invest (`t_tech.invest`) импортируется только в `sources/tinvest/client.py`.**
Ставится с индекса T-Bank (`[tool.uv.index]` в `backend/pyproject.toml`) — не менять на PyPI.
- **Аналитика читает только `event.status = confirmed`.** Snapshot-таблицы — для сверки.
- **Сырые данные (`raw_*`) append-only и идемпотентны** по стабильному id источника.
- `openapi/openapi.json` и `app/packages/api_client` — генерируются, но коммитятся;
после изменения роутов запускай `just gen-client`.
- Секреты только в `.env``.gitignore`). Реальные отчёты брокеров — в
`backend/tests/fixtures/reports/raw/``.gitignore`); в git только обезличенные фикстуры.
- Коммиты — Conventional Commits на русском (`feat(ledger): …`), автор — только пользователь.
## Состояние
Фазы 0 и 1 завершены и проверены на живых данных (31 счёт, 5575 транзакций ZenMoney, курсы ЦБ,
все экраны работают). Правил классификации пока ноль — переводы и сбережения попадают в расходы.
Фаза 2 в работе. Готово и прогнано на живых данных:
- `sources/tinvest` — 7 счетов, 2756 операций → `event`, маппер на все 67 `OperationType`;
- `ledger/lots.py` + `rebuild.py` — FIFO, 804 лота, 672 закрытия, реализовано +1892 ₽;
короткие позиции поддержаны, `qty_remaining` хранится со знаком;
- `sources/moex` — 77 инструментов, 31 154 дневные цены, `price_daily` / `price_last`;
- `analytics/valuation` — дневная серия стоимости и холдинги по scope (`all`, `account:<id>`,
`portfolio:<id>`), сверка со снапшотами брокера; `analytics/returns` — XIRR и TWR по
периодам (`1m 3m 6m ytd 1y 3y all`) плюс XIRR на инструмент; `pricing/prices.py` — цена на
дату с протяжкой вперёд и порогом устаревания 10 дн.
Осталось: `analytics/allocation`, корпоративные действия, API и экраны позиций.
Известные расхождения derived vs брокерский снапшот по позициям (5 шт, не ошибки разбора):
редомициляция FIVE→X5, MGNT, HEAD, внебиржевая SIBN6P4. Без цен два инструмента — `SIBN6P4`
и `NDM_TBNK-PP-FIXPRCNT-08.25`, им нужен `price_manual`. По кэшу derived выше снапшота на
счетах 46, 48 и 52 (+6313, +56447, +146 ₽) — это неполнота леджера T-Invest, а не оценки:
счёт 51 сходится точно. История цен тонкая (большинство облигаций — только с апреля 2026,
TBRU@ — с 14.09.2026), поэтому TWR пропускает 32 дня и сообщает об этом в
`metric_data_quality`. План фаз — в `docs/ai/plan.md`.