Bicycle/.claude/memory/бюджет_текущий_план.md
2026-08-10 23:24:41 +03:00

10 KiB
Raw Blame History

name description metadata
budget-current-plan Актуальный бизнес-процесс фичи «Бюджет» — версия после полного сброса проекта (см. ниже "Второй урок"); не путать со старым бюджет_проект_план.md (2006 год, источник идей, не требований)
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/контроллеры/репозитории — свериться с этим файлом и убедиться, что каждый пункт был реально произнесён в текущем контексте разговора, а не просто существует здесь с прошлого раза. Новые уточнения — дописывать сюда сразу.