110 lines
10 KiB
Markdown
110 lines
10 KiB
Markdown
---
|
||
name: budget-current-plan
|
||
description: Актуальный бизнес-процесс фичи «Бюджет» — версия после полного сброса проекта (см. ниже "Второй урок"); не путать со старым бюджет_проект_план.md (2006 год, источник идей, не требований)
|
||
metadata:
|
||
type: project
|
||
---
|
||
|
||
Старый файл `бюджет_проект_план.md` — заметки 2006 года, источник идей, не требований. Этот файл —
|
||
то, что реально подтверждено в разговоре. **Актуальна только эта версия** — предыдущая версия этого
|
||
же файла (обсуждение копилок/целей ДО того, как весь проект снесли и начали заново) частично устарела,
|
||
см. "Второй урок" ниже про то, почему.
|
||
|
||
## Продукт
|
||
|
||
Личный (не мульти-пользовательский) трекер бюджета — один человек ведёт свой бюджет. `users` всё же
|
||
нужна (не совсем однопользовательский в смысле схемы БД) — счета/категории/транзакции ссылаются на
|
||
`user_id`, без этого пришлось бы возвращаться к вопросу при первом же втором пользователе.
|
||
|
||
## Users
|
||
|
||
`id`, `login`, `password`, `name`, `email`, `date_add`, `last_login`. Пока достаточно.
|
||
|
||
## Accounts (счета)
|
||
|
||
Три типа `type_acc`:
|
||
- **`cash`** — кошелёк (наличные).
|
||
- **`bank`** — счёт в банке; карта просто привязана к нему, сама по себе денег не хранит (это
|
||
сознательное упрощение — раньше в модели были отдельные "дебетовая карта"/"кредитная карта"/
|
||
"е-money" и т.п., это НЕ подтверждено заново после сброса, убрано).
|
||
- **`savings`** — копилка: тот же счёт, но с процентом на остаток (история ставок — отдельная таблица,
|
||
привязанная к `account_id`). Опционально может иметь цель (см. `goals` ниже) — если записи в `goals`
|
||
нет, это просто копилка "без цели", копишь под процент без конкретной суммы/даты.
|
||
|
||
Поля: `id`, `user_id`, `type_acc`, `title`, `summa` (баланс), `is_delete` (архивация вместо удаления),
|
||
`order`.
|
||
|
||
## Categories (статьи) — с подкатегориями
|
||
|
||
`id`, `user_id`, `parent_id` (null — категория верхнего уровня; иначе — id родителя), `title`, `type`
|
||
(`income`/`expense`), `order`.
|
||
|
||
Пример: «Продукты» — родительская категория, «Алкоголь» — подкатегория внутри неё. Транзакция
|
||
привязывается к конкретной (под)категории. В отчёте можно смотреть по родителю целиком (сумма всех
|
||
подкатегорий) или провалиться в конкретную подкатегорию отдельно.
|
||
|
||
## Transactions
|
||
|
||
`id`, `user_id`, `categorie_id`, `account_f_id` (откуда), `account_in_id` (куда), `date`, `summa`,
|
||
`type` (`income`/`expense`/`transfer`). Для дохода — только `account_in_id`, для расхода — только
|
||
`account_f_id`, для перевода — оба.
|
||
|
||
**Обычный transfer между обычными счетами — без категории** (пример: переложил 3000 ₽ с карты в
|
||
кошелёк — деньги не потрачены и не заработаны, просто переехали, категория тут не имеет смысла).
|
||
|
||
**⚠️ ОТКРЫТЫЙ ВОПРОС — transfer на savings-счёт (пополнение копилки/цели) МОЖЕТ иметь категорию**,
|
||
и пользователь хочет, чтобы такой transfer засчитывался как "потрачено" по этой категории в
|
||
план/факт бюджета — то есть отложил 10 000 ₽ в копилку «Отпуск» в январе → сразу считается
|
||
"потрачено 10 000 на Отпуск" в январском бюджете, ещё до самой поездки.
|
||
|
||
Нерешённая проблема с этим: когда деньги реально тратятся (сама поездка — гостиница, билеты), если те
|
||
траты ТОЖЕ пометить категорией «Отпуск» — сумма задвоится (одни и те же деньги посчитаны и при
|
||
откладывании, и при реальной трате). Пользователь сказал «я подумаю» — **решение пока не принято**,
|
||
не проектировать/не кодировать эту часть, пока не будет ответа. Варианты, которые обсуждались (но не
|
||
выбраны): (а) реальные траты в момент поездки НЕ помечать той же категорией, раз уже засчитано при
|
||
откладывании; (б) какой-то другой механизм анти-задвоения.
|
||
|
||
## Budgets (план/факт)
|
||
|
||
`id`, `categorie_id`, `plan_summ`, `year`, `month`, `type`. План — вручную на месяц по категории; факт
|
||
— не хранится, считается на лету как сумма `transactions` по этой категории за месяц (с учётом
|
||
открытого вопроса выше — возможно, включая помеченные transfer на копилки).
|
||
|
||
## Account_rates (история ставок)
|
||
|
||
`id`, `account_id`, `rate_percent`, `valid_from`, `valid_to` (null = текущая). Общая механика для
|
||
`savings`, с расчётом на будущее переиспользование для кредита (там % работает в другую сторону —
|
||
не начисление, а долг — но структура «ставка + период» та же). Кредит сейчас вне скоупа.
|
||
|
||
## Goals (цель для копилки)
|
||
|
||
`id`, `account_id`, `target_summa`, `deadline`. Необязательная надстройка над `savings`-счётом.
|
||
Прогноз «сколько класть в месяц» считается на лету по ТЕКУЩЕЙ ставке (не хранится), в предположении,
|
||
что она не изменится до дедлайна; пересчитывается при просмотре/смене ставки.
|
||
|
||
**Проценты, начисленные на копилку** — `income`-транзакция на счёт-копилку с одной системной
|
||
категорией «Проценты по вкладам/целям» (одна на все копилки, не по одной на каждую) — заводится
|
||
пользователю автоматически при первом использовании.
|
||
|
||
## Приоритет фич
|
||
|
||
1. **Цели (план/факт) + анализ бюджета** — сейчас.
|
||
2. **Инвестиции** (вклады/акции/облигации) — следующий слой, схему делать с запасом.
|
||
3. **Кредиты** — отложены, но `account_rates` намеренно универсальна для переиспользования позже.
|
||
|
||
## Второй урок (почему эта версия файла переписана)
|
||
|
||
После того как весь код/схема домена бюджета были снесены "с нуля" по прямому требованию пользователя,
|
||
я в следующем же заходе молча притащил старые выводы из ПРЕДЫДУЩЕЙ версии этого файла (users, accounts,
|
||
categories, transactions, budgets) как будто они уже согласованы — хотя после сброса заново обсуждались
|
||
только копилки/цели. Пользователь: «про пользователя мы ничего не обсуждали, про бюджет мы ничего не
|
||
обсуждали... ОТКУДА БЛЯДЬ???». **Урок: "сохранено в памяти" ≠ "можно молча переиспользовать после
|
||
полного сброса"** — если проект/фичу explicitly снесли и просили начать заново, каждое решение
|
||
переподтверждается в текущем разговоре заново, даже если оно дословно совпадёт с тем, что уже было
|
||
записано. Ссылаться на память можно только явно и открыто ("вот что записано, актуально ли?"), не
|
||
молча вставлять в предложение как решённое.
|
||
|
||
**How to apply**: перед тем как писать `schema.sql`/контроллеры/репозитории — свериться с этим файлом
|
||
**и убедиться, что каждый пункт был реально произнесён в текущем контексте разговора**, а не просто
|
||
существует здесь с прошлого раза. Новые уточнения — дописывать сюда сразу.
|