feat: budgets / envelopes (#7) #17

Open
agent-int wants to merge 1 commit from feat/issue-7-budgets into main
Collaborator

Budgets / envelopes

Fourth item of the P1 double-entry tier (#7): budgets (hledger --budget / Ledger virtual
postings). Assign a target amount to a category over a period (date range), then compare it to the
actual summed activity in that category over the period.

Surfaces (server-depth, mirroring the payees/attachments features)

  • Migration 0011: budgets table (category_id FK ON DELETE CASCADE, period_start,
    period_end, amount) + index + changelog trigger (entity_kind = 'budget').
  • Store: Commands.budgetAdd/budgetList/budgetRemove/budgetStatus + LedgerStore SQL +
    categoryActivity(categoryId, from, to).
  • gRPC: AddBudget / RemoveBudget (writes) + ListBudgets / GetBudgetStatus (reads)
    (+ proto Budget / BudgetStatus messages).
  • Client: addBudget/listBudgets/removeBudget/budgetStatus + BudgetInfo/BudgetStatusInfo.
  • MCP: direct add_budget / remove_budget (destructiveHint) / list_budgets /
    get_budget_status tools (no money moves → no propose/commit).
  • Tests: store (BudgetTests), gRPC (BudgetRPCTests), MCP. make test green.

Sign convention (documented in code)

categoryActivity returns the raw signed sum of the categorized splits' amounts over the period
— positive = debit-side (spending) activity, negative = credit-side (income) activity — matching the
ledger's normal signs (Report/Statements.swift: expense accounts are debit-normal, income
credit-normal). Money is folded exactly in Swift (not lossy SQL SUM), like currentBalance.
Period bounds are inclusive (t.date BETWEEN period_start AND period_end).

⚠️ Migration version — cross-branch coordination

Numbered version 11 (main is at 8; 9 = attachments/#15, 10 = effective-date/#16 on their
still-open branches). The migrator applies per-recorded-version, so the gap is safe. When merging the
migration-adding PRs, order the Schema.migrations array by version and set the migration-count
assertion in CommonsStoreTests to the final count.

Scope

One P1 item (does not close #7). Remaining item: pending/cleared two-phase. Report/UI integration of
budgets is a follow-up (#4).

## Budgets / envelopes Fourth item of the **P1 double-entry tier** (#7): budgets (hledger `--budget` / Ledger virtual postings). Assign a target `amount` to a category over a period (date range), then compare it to the **actual** summed activity in that category over the period. ### Surfaces (server-depth, mirroring the payees/attachments features) - **Migration 0011**: `budgets` table (`category_id` FK `ON DELETE CASCADE`, `period_start`, `period_end`, `amount`) + index + changelog trigger (`entity_kind = 'budget'`). - **Store**: `Commands.budgetAdd/budgetList/budgetRemove/budgetStatus` + `LedgerStore` SQL + `categoryActivity(categoryId, from, to)`. - **gRPC**: `AddBudget` / `RemoveBudget` (writes) + `ListBudgets` / `GetBudgetStatus` (reads) (+ proto `Budget` / `BudgetStatus` messages). - **Client**: `addBudget/listBudgets/removeBudget/budgetStatus` + `BudgetInfo`/`BudgetStatusInfo`. - **MCP**: direct `add_budget` / `remove_budget` (destructiveHint) / `list_budgets` / `get_budget_status` tools (no money moves → no propose/commit). - **Tests**: store (`BudgetTests`), gRPC (`BudgetRPCTests`), MCP. `make test` green. ### Sign convention (documented in code) `categoryActivity` returns the **raw signed sum** of the categorized splits' amounts over the period — positive = debit-side (spending) activity, negative = credit-side (income) activity — matching the ledger's normal signs (`Report/Statements.swift`: expense accounts are debit-normal, income credit-normal). Money is folded exactly in Swift (not lossy SQL `SUM`), like `currentBalance`. Period bounds are inclusive (`t.date BETWEEN period_start AND period_end`). ### ⚠️ Migration version — cross-branch coordination Numbered **version 11** (main is at 8; **9** = attachments/#15, **10** = effective-date/#16 on their still-open branches). The migrator applies per-recorded-version, so the gap is safe. When merging the migration-adding PRs, order the `Schema.migrations` array by version and set the migration-count assertion in `CommonsStoreTests` to the final count. ### Scope One P1 item (does not close #7). Remaining item: pending/cleared two-phase. Report/UI integration of budgets is a follow-up (#4).
feat: budgets / envelopes (#7)
Some checks failed
ci / macos (pull_request) Successful in 4m3s
ci / linux (pull_request) Has been cancelled
ci / proto (pull_request) Has been cancelled
ci / purity (pull_request) Has been cancelled
7bd4227a75
Add budgets (hledger --budget / Ledger virtual postings): assign a target
amount to a category over a period (date range), then compare it to the actual
summed activity in that category over the period.

- migration 0011 (budgets table; category_id FK ON DELETE CASCADE)
- Domain: Budget + BudgetStatus
- Store: Commands.budgetAdd/List/Remove/budgetStatus + LedgerStore SQL +
  categoryActivity(categoryId, from, to)
- gRPC: AddBudget / RemoveBudget (writes) + ListBudgets / GetBudgetStatus (reads)
- Client: addBudget/listBudgets/removeBudget/budgetStatus + view models
- MCP: direct add_budget / remove_budget / list_budgets / get_budget_status
- Tests at the store, gRPC, and MCP layers

categoryActivity returns the raw signed sum of categorized splits over the
inclusive period (positive = debit-side/spending, negative = credit-side/income,
matching the ledger's normal signs); Money is folded exactly in Swift, not via
lossy SQL SUM.

Migration numbered version 11 (main is at 8; v9=attachments #15, v10=
effective-date #16 on their still-open branches); the migrator applies
per-recorded-version so the gap is safe. Fourth item of the P1 tier (#7);
remaining: pending/cleared two-phase.
Some checks failed
ci / macos (pull_request) Successful in 4m3s
ci / linux (pull_request) Has been cancelled
ci / proto (pull_request) Has been cancelled
ci / purity (pull_request) Has been cancelled
This pull request can be merged automatically.
You are not authorized to merge this pull request.
View command line instructions

Checkout

From your project repository, check out a new branch and test the changes.
git fetch -u origin "feat/issue-7-budgets:feat/issue-7-budgets"
git switch "feat/issue-7-budgets"

Merge

Merge the changes and update on Forgejo.

Warning: The "Autodetect manual merge" setting is not enabled for this repository, you will have to mark this pull request as manually merged afterwards.

git switch "main"
git merge --no-ff "feat/issue-7-budgets"
git switch "feat/issue-7-budgets"
git rebase "main"
git switch "main"
git merge --ff-only "feat/issue-7-budgets"
git switch "feat/issue-7-budgets"
git rebase "main"
git switch "main"
git merge --no-ff "feat/issue-7-budgets"
git switch "main"
git merge --squash "feat/issue-7-budgets"
git switch "main"
git merge --ff-only "feat/issue-7-budgets"
git switch "main"
git merge "feat/issue-7-budgets"
git push origin "main"
Sign in to join this conversation.
No reviewers
No labels
No milestone
No project
No assignees
1 participant
Notifications
Due date
The due date is invalid or out of range. Please use the format "yyyy-mm-dd".

No due date set.

Dependencies

No dependencies set

Reference
nic/commons!17
No description provided.