Все статьи

Как работает бюджет в Unitcore

Бюджет — первый продукт Unitcore, и правило у него то же, что у остальных: всё живёт внутри пространства и видно всем, кто в нём есть. В личном это ваши траты, в семейном — общие, где не нужно пересылать друг другу скриншоты, чтобы понять, куда ушёл месяц.

Ниже — от простого к сложному: из чего собрана запись о деньгах, что показывает дашборд, что умеет ассистент и как это устроено внутри.

Из чего собрана запись

Транзакция — это один поход в магазин, а не одна сумма. Внутри неё позиции, и категория стоит у каждой позиции отдельно.

Супермаркет4 сентября · EUR
Продукты на неделюЕда38,10
Стиральный порошокДом6,20
ПакетБез категории3,00
Итого47,30

Один чек — три строки и три разные категории. Если бы категория стояла на всей транзакции, «Еда» и «Дом» пришлось бы записывать двумя походами в один и тот же магазин.

Категории заводятся в пространстве и бывают двух видов: расход и доход. Больше у категории ничего нет — ни лимита, ни цвета, ни вложенности.

Суммы всегда положительные

В базе нет ни одного отрицательного числа: сумма — это всегда «сколько», а знак берётся из категории. Зарплата с категорией-доходом приходит плюсом, продукты с категорией-расходом — минусом, и считает это сама база, а не приложение.

Деньги без категории считаются расходом. Это не забытая ветка, а решение: чаще всего строка без категории — это трата, которую не успели разложить, и она должна портить итог месяца, а не тихо исчезать из него.

Отсюда же следует, что удаление категории не удаляет деньги: позиции остаются на месте и просто теряют ярлык. Пересобрать категории можно в любой момент, история от этого не пострадает.

Что показывает дашборд

Карточка на каждую валюту. Валюты никогда не складываются — курсов в проекте нет вообще, и общая цифра «потрачено» была бы выдуманной.

Расходы за сентябрь
1 240,00EUR
−12% к прошлому месяцу
Еда430,00
Дом260,00
Без категории95,00
Расходы за сентябрь
18 400RUB
+4% к прошлому месяцу
Связь6 400
Прочее3 900

Каждая карточка отвечает на одни и те же четыре вопроса про свою валюту: сколько в этом месяце, как это по сравнению с прошлым, как выглядели последние полгода и на что именно ушло. Категорий в списке пять, остальное сворачивается в «Прочее».

Ниже — последние операции из всех ваших пространств сразу. По умолчанию дашборд показывает всё вместе; фильтр сверху сужает его до одного пространства.

Как записать трату руками

Форма открывается прямо с карточки: название, дата, валюта и строки — по одной на покупку. Категорию можно создать не выходя из формы, вместе с выбором «расход или доход». Открыв существующую транзакцию, её же можно исправить или удалить.

Удаление транзакции необратимо. Корзины, как у задач, здесь нет: транзакция уходит вместе со всеми своими позициями и не возвращается. Это единственное действие в бюджете, которое нельзя отменить.

То же самое — ассистенту

Одиннадцать инструментов
Три на чтение, восемь на запись. Ассистент работает в том пространстве, в котором находитесь вы.
вечером
«Запиши: супермаркет, продукты 38,10 и порошок 6,20» → одна транзакция, две позиции.
в конце месяца
«Сколько ушло на еду в июле?» → суммы по категориям за период.
когда ошиблись
«Поменяй сумму на 41,30» → правится позиция, транзакция остаётся той же.
в семейном
«Что мы тратили на дом с весны?» → транзакции с их позициями.

Два решения, которые стоит назвать вслух:

  • Право на запись выдаётся каждому подключению отдельно. Незнакомый клиент, который добрался до вашего аккаунта, может только читать — писать он не сможет, пока вы сами не разрешите это в настройках подключений.
  • Транзакция без позиций не остаётся. Если позиции не записались, ассистент удаляет созданную транзакцию сам: пустая запись в бюджете хуже, чем её отсутствие.

Как это устроено внутри

Отдельная схема в базе и никакого промежуточного слоя приложения: и веб, и ассистент ходят в одну и ту же базу под вашим собственным пользователем, а решает, что вам видно, сама база.

Клиенты

Читают готовое представление, пишут прямо в таблицы.

дашбордформа транзакции
Ассистент

Те же запросы, тот же пользователь — просто вызванные словами.

summarylist_transactionscreate_transaction…ещё 8
Права

Одна проверка на все таблицы, список колонок, которые вообще нельзя записать, и отдельный рубеж для подключённых ассистентов.

RLS: участник пространства?гранты по колонкамразрешение клиенту на запись
Данные

Три таблицы и триггеры, которые держат правила: позиции наследуют дату и валюту от своей транзакции, сумма всегда больше нуля.

categoriestransactionstransaction_items
Чтение

Представление подставляет имя категории и знак суммы — чтобы клиент не считал это сам и не считал по-своему.

transaction_items_signed
Граница доступа одна и лежит в базе, а не в трёх клиентах
Ассистент физически не может увидеть больше вашего
Знак и категория считаются в одном месте — цифры сходятся везде
Новый клиент подключается без нового бэкенда
Подробности для тех, кому интересен SQL
  • Позиция ссылается на транзакцию и категорию парой (id, space_id). Поэтому категория из чужого пространства структурно невозможна, без единой проверки в коде.
  • Синхронизация только сверху вниз: дата и валюта живут на транзакции, а позиции их наследуют. Изменили дату у чека — уехали все его строки; обратно это не работает, и колонки на запись позиции просто не выданы.
  • amount numeric(14,4). Три знака после точки нужны фактически — у динара и риала минорная единица тысячная; четвёртый оставлен под остатки от деления счёта между участниками и под конвертацию, чтобы сумма строк сходилась с итогом чека.
  • Валюта — это домен с проверкой ^[A-Z]{3}$, а не список: продукт не решает за вас, в чём вы считаете.
  • «Кто записал» проставляется из вашей сессии и клиенту на запись не выдано.
  • Дашборд читает полгода постранично: PostgREST отдаёт не больше 1000 строк за запрос независимо от лимита в коде.

Чего пока нет

Нет курсов валют и конвертации, регулярных платежей, счетов и остатков на них, лимитов по категориям, импорта банковских выписок и деления чека между участниками. Последнее спроектировано — под него в схеме уже оставлен запас точности.

Второй продукт поверх тех же пространств — задачи, и устроен он по тем же правилам: Как работают задачи в Unitcore. А если бюджет ещё не подключён к ассистенту, это пара минут: Подключите Unitcore к Claude.