* feat(assistant): add get_budget function for budget tracking
Exposes the existing Budget / BudgetCategory pacing data to the AI
assistant as a `get_budget` function. Supports a target month and an
optional `prior_months` window for trend comparison, with the response
shape matching the budget UI (totals, income, per-category status,
suggested daily spend on the current month).
Honors custom month_start_day by matching `Budget.param_to_date`
semantics for explicit slug input, so `month` round-trips with the
response's `month` field.
Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
* test(assistant): use fixture reference for Food & Drink lookup
Replace fragile string match on `bc.category.name == "Food & Drink"`
with the `categories(:food_and_drink)` fixture so the test setup
isn't sensitive to category-name translations.
Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
* fix(assistant): enforce strict month format in get_budget
`Date.strptime` is lenient about trailing characters, so inputs like
`"2026-05-01"` or `"may-2026foo"` were parsing successfully and being
silently truncated to May 2026. Pre-validate the raw string with anchored
regex patterns for the documented YYYY-MM and MMM-YYYY shapes so
malformed tool arguments raise Assistant::Error instead.
Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
* fix(budgets): suggested_daily_spending handles custom-month periods
The helper compared `budget.start_date.month/year` against
`Date.current.month/year` and returned nil whenever the current period
straddled two calendar months — common for families with
`month_start_day != 1` (e.g., May 15–Jun 14 viewed on Jun 1). Replace
the calendar-month check with `budget.current?` and compute remaining
days from `budget.end_date` so the helper works for both standard and
custom periods. This also restores the daily pacing row in the budget
UI for custom-month families.
Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
* fix(assistant): make get_budget read-only for prior months
`prior_months: N` was calling `Budget.find_or_bootstrap` for every
month, which created empty `Budget` rows (and synced `BudgetCategory`
children) as a side effect of an AI query. Only the explicit target
month now bootstraps; prior months use `Budget.find_by` and are
dropped from the response if they don't exist. The response now
includes `months_unavailable: N` so the LLM can phrase a sensible
answer when fewer months come back than requested.
Extract `Budget.period_for(date, family:)` to share the date-bracket
math between `find_or_bootstrap`, `budget_date_valid?`, and the new
read-only path in `get_budget`.
Adds two tests covering the no-bootstrap behavior for prior months
and the `prior_months` clamp at `MAX_PRIOR_MONTHS`. Updates the
existing N+1 sorted-months test to seed prior budgets explicitly.
Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
---------
Co-authored-by: wolstad <wesleyolstad@protonmail.com>
Co-authored-by: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
* Optimize UI in budget
* update locales
* Optimize UI
* optimize suggested_daily_spending
* try over_budget and on_track
* update locale
* optimize
* add budgets_helper.rb
* fix
* hide no buget and no expense sub-catogory
* Optimize
* Optimize button on phone
* Fix Pipelock CI noise
* using section to render both overbudget and onTrack
* hide last ruler
* fix
* update test
---------
Co-authored-by: Juan José Mata <juanjo.mata@gmail.com>
The `subcategories` method queries `WHERE parent_id = category.id`, but
for the synthetic uncategorized budget category, `category.id` is nil.
This caused `WHERE parent_id IS NULL` to match ALL top-level categories,
making them appear as subcategories of uncategorized. This inflated
actual_spending and produced a large negative available_to_spend.
Add a nil guard on category.id to return an empty relation for synthetic
categories.
Fixes#819
Co-authored-by: Claude Opus 4.6 <noreply@anthropic.com>
* First reporting version
* Fixes for all tabs
* Transactions table
* Budget section re-design
* FIX exports
Fix transactions table aggregation
* Add support for google sheets
Remove pdf and xlsx for now
* Multiple fixes
- Trends & Insights now follows top filter
- Transactions Breakdown removed filters, implemented sort by amount.
- The entire section follows top filters.
- Export to CSV adds per month breakdown
* Linter and tests
* Fix amounts
- Correctly handle amounts across the views and controller.
- Pass proper values to do calculation on, and not loose precision
* Update Gemfile.lock
* Add support for api-key on reports
Also fix custom date filter
* Review fixes
* Move budget status calculations out of the view.
* fix ensures that quarterly reports end at the quarter boundary
* Fix bugdet days remaining
Fix raw css style
* Fix test
* Implement google sheets properly with hotwire
* Improve UX on period comparison
* FIX csv export for non API key auth
* Fix category dark mode styles
* Fix sidebar account tab states
* Fix dashboard balance sheet group styles
* Fix budget dark mode styles
* Fix chart gradient split
* Fix prose styles in dark mode
* Add back chat nav id for tests
Since the very first 0.1.0-alpha.1 release, we've been moving quickly to add new features to the Maybe app. In doing so, some parts of the codebase have become outdated, unnecessary, or overly-complex as a natural result of this feature prioritization.
Now that "core" Maybe is complete, we're moving into a second phase of development where we'll be working hard to improve the accuracy of existing features and build additional features on top of "core". This PR is a quick overhaul of the existing codebase aimed to:
- Establish the brand new and simplified dashboard view (pictured above)
- Establish and move towards the conventions introduced in Cursor rules and project design overview #1788
- Consolidate layouts and improve the performance of layout queries
- Organize the core models of the Maybe domain (i.e. Account::Entry, Account::Transaction, etc.) and break out specific traits of each model into dedicated concerns for better readability
- Remove stale / dead code from codebase
- Remove overly complex code paths in favor of simpler ones