Skip to content

feat: category overspend early warning system (#117)#469

Open
qiridigital wants to merge 1 commit intorohitdash08:mainfrom
qiridigital:feat/category-overspend-warning
Open

feat: category overspend early warning system (#117)#469
qiridigital wants to merge 1 commit intorohitdash08:mainfrom
qiridigital:feat/category-overspend-warning

Conversation

@qiridigital
Copy link

Category Overspend Early Warning System

closes #117 | /claim #117

Summary

Implements a production-ready category budget management system that alerts users before they exceed their spending limits, with configurable warning thresholds and real-time progress tracking.

Backend Changes

New model: CategoryBudget

  • Per-category monthly spending limit with optional month field (null = applies every month)
  • Configurable warning_threshold_pct (default 80%) — fire warning when spending hits this %

New endpoints (/budgets):

Method Path Description
GET /budgets List all budget limits for the current user
POST /budgets Set a budget limit for a category
PATCH /budgets/:id Update limit or threshold
DELETE /budgets/:id Remove budget limit
GET /budgets/overspend Overspend report for a given month

Overspend endpoint (GET /budgets/overspend):

  • ?month=YYYY-MM — defaults to current month
  • ?only_warnings=true — filter out OK categories
  • Warning levels: OK < 75% ≤ MEDIUM < 90% ≤ HIGH < 100% ≤ CRITICAL
  • Response sorted: CRITICAL → HIGH → MEDIUM → OK
  • Summary counts per level for dashboard badges
  • Income transactions excluded from spend calculation

Frontend Changes

  • BudgetOverspend.tsx — Full dashboard with:
    • Summary pills (over budget / almost over / warning / on track)
    • Per-category warning cards with colour-coded progress bars
    • Toggle "Warnings Only" filter
    • Budget management table with remove controls
    • Create budget form with category selector
  • api/budgets.ts — TypeScript API client with complete type definitions
  • Route /overspend added to App.tsx + nav link in Navbar.tsx

Database

CREATE TABLE category_budgets (
  id, user_id FK, category_id FK,
  month VARCHAR(7),            -- NULL = every month
  budget_limit NUMERIC(12,2),
  warning_threshold_pct INT DEFAULT 80,
  created_at
);

Tests

15 pytest tests covering:

  • List/create budgets, update, delete
  • Validation (negative limits, invalid category, missing fields)
  • Overspend OK/MEDIUM/HIGH/CRITICAL levels
  • ?only_warnings filter
  • Income not counted toward spending
  • Auth protection

- Add CategoryBudget model with per-category monthly spending limits
- Configurable warning_threshold_pct (default 80%)
- Budget CRUD: GET/POST /budgets, PATCH/DELETE /budgets/:id
- GET /budgets/overspend: computes % spent vs limit per category
  - Warning levels: OK / MEDIUM (>=75%) / HIGH (>=90%) / CRITICAL (>=100%)
  - ?only_warnings=true filter to surface actionable alerts only
  - Sorted: CRITICAL first, then HIGH, MEDIUM, OK
  - Summary object with counts per level
- Update schema.sql with category_budgets table and index
- React BudgetOverspend page: summary pills, warning cards with
  progress bars, colour-coded by severity, budget management table
- TypeScript API client with full types
- 15 pytest tests covering CRUD, warning levels, income exclusion, auth

/claim rohitdash08#117
Copilot AI review requested due to automatic review settings March 16, 2026 21:15
Copy link

Copilot AI left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Pull request overview

Adds a category budget system with an overspend “early warning” report, plus a new frontend dashboard page to view/manage budgets and warnings.

Changes:

  • Introduces CategoryBudget model/table and /budgets CRUD + /budgets/overspend reporting endpoint.
  • Adds backend pytest coverage for budget CRUD and overspend warning behavior.
  • Adds an /overspend route + UI page and a budgets API client.

Reviewed changes

Copilot reviewed 9 out of 9 changed files in this pull request and generated 14 comments.

Show a summary per file
File Description
packages/backend/tests/test_budgets.py New pytest coverage for budgets + overspend report
packages/backend/app/routes/budgets.py New budgets CRUD + overspend reporting endpoints
packages/backend/app/routes/init.py Registers the new budgets blueprint
packages/backend/app/models.py Adds CategoryBudget ORM model
packages/backend/app/db/schema.sql Adds category_budgets table + index
app/src/pages/BudgetOverspend.tsx New overspend dashboard page + budget management UI
app/src/components/layout/Navbar.tsx Adds navigation link to /overspend
app/src/api/budgets.ts Adds frontend budgets API client + types
app/src/App.tsx Adds protected route for the overspend page

💡 Add Copilot custom instructions for smarter, more guided reviews. Learn how to get started.


def _spent_this_month(user_id: int, category_id: int, month: str) -> float:
"""Sum of EXPENSE-type transactions for (user, category, month)."""
year, mo = map(int, month.split("-"))
Comment on lines +168 to +169
month = (request.args.get("month") or _current_month()).strip()
only_warnings = request.args.get("only_warnings", "false").lower() == "true"
Comment on lines +181 to +184
results = []
for b in budgets:
cat = Category.query.get(b.category_id)
spent = _spent_this_month(uid, b.category_id, month)
Comment on lines +89 to +92
budget_limit = float(data.get("budget_limit", 0))
if budget_limit <= 0:
return jsonify(error="budget_limit must be positive"), 400

Comment on lines +135 to +137
if "month" in data:
budget.month = data["month"] or None

"category_id": category_id,
"amount": amount,
"expense_type": expense_type,
"spent_at": date.today().isoformat(),
budget_limit NUMERIC(12,2) NOT NULL,
warning_threshold_pct INT NOT NULL DEFAULT 80,
created_at TIMESTAMP NOT NULL DEFAULT NOW()
);
Comment on lines +78 to +82
Spent: <strong style={{ color: "#fff" }}>₹{w.spent.toLocaleString()}</strong>
</span>
<span>
{w.pct_used.toFixed(1)}% of ₹{w.budget_limit.toLocaleString()}
</span>
Comment on lines +138 to +140
const { default: api } = await import("../api/index");
const r = await api.get("/categories");
setCategories(r.data || []);
Comment on lines +29 to +33
Expense.user_id == user_id,
Expense.category_id == category_id,
Expense.expense_type != "INCOME",
func.strftime("%Y", Expense.spent_at) == str(year),
func.strftime("%m", Expense.spent_at) == f"{mo:02d}",
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Projects

None yet

Development

Successfully merging this pull request may close these issues.

Category overspend early warning system

2 participants