Skip to content

feat: goal-based savings tracking & milestones#1071

Open
Entr0zy wants to merge 1 commit into
rohitdash08:mainfrom
Entr0zy:feat/savings-goals-133
Open

feat: goal-based savings tracking & milestones#1071
Entr0zy wants to merge 1 commit into
rohitdash08:mainfrom
Entr0zy:feat/savings-goals-133

Conversation

@Entr0zy
Copy link
Copy Markdown

@Entr0zy Entr0zy commented May 24, 2026

/claim #133

What this PR adds

A complete Goal-Based Savings Tracking & Milestones system, fulfilling all acceptance criteria in issue #133.


Changes

packages/backend/app/models.py (modified)

Three new models appended:

Model Purpose
SavingsGoal User-scoped savings target with name, target_amount, current_amount, target_date, status (ACTIVE/COMPLETED/ABANDONED), currency
GoalDeposit Immutable deposit ledger entry per goal
GoalMilestone Auto-recorded when 25 / 50 / 75 / 100% threshold is crossed

packages/backend/app/services/savings.py (new)

Function Purpose
create_goal(uid, data) Validates and persists a new goal
get_goals(uid) Lists all goals for a user
get_goal(uid, goal_id) Fetches a single goal (ownership-checked)
update_goal(uid, goal_id, data) Patches name / target / date / status
delete_goal(uid, goal_id) Cascade-deletes goal + deposits + milestones
deposit(uid, goal_id, amount, note) Credits amount, auto-completes at target, records milestones
get_milestones(uid, goal_id) Returns milestone list in pct order
goal_to_dict(goal) Serialises goal including progress_pct

packages/backend/app/routes/savings.py (new)

Endpoint Description
GET /savings/goals List all goals
POST /savings/goals Create a goal
GET /savings/goals/<id> Get one goal
PATCH /savings/goals/<id> Update name / target / date / status
DELETE /savings/goals/<id> Delete (204 No Content)
POST /savings/goals/<id>/deposit Add money; auto-completes when target reached
GET /savings/goals/<id>/milestones List milestones reached

Modified: packages/backend/app/routes/__init__.py

Registers savings blueprint at /savings.

packages/backend/tests/test_savings.py (new — 28 tests)

Auth gates, create (happy + 3 error paths), list/get, update, delete, deposits (happy + invalid amount + auto-complete + post-complete rejection), milestones (empty, partial, all four, no-duplicates), service-layer unit test.


Verification

# Unit tests (no Redis/DB required — auth gates pass)
cd packages/backend
TESTING=true pytest tests/test_savings.py -v -k "requires_auth"

# Full test suite (Docker Compose)
docker compose up -d
pytest tests/test_savings.py -v

# Quick smoke test
TOKEN=$(curl -s -X POST http://localhost:5000/auth/login \
  -H "Content-Type: application/json" \
  -d '{"email":"you@example.com","password":"yourpw"}' | jq -r .access_token)

# Create a goal
curl -X POST http://localhost:5000/savings/goals \
  -H "Authorization: Bearer $TOKEN" \
  -H "Content-Type: application/json" \
  -d '{"name":"Emergency Fund","target_amount":5000,"target_date":"2026-12-31"}'

# Deposit and watch milestones
curl -X POST http://localhost:5000/savings/goals/1/deposit \
  -H "Authorization: Bearer $TOKEN" \
  -H "Content-Type: application/json" \
  -d '{"amount":1250,"note":"First paycheck"}' | jq .progress_pct
# → 25.0

curl http://localhost:5000/savings/goals/1/milestones \
  -H "Authorization: Bearer $TOKEN"
# → [{"pct":25,"reached_at":"..."}]

🤖 Generated with Claude Code

Implements production-ready savings goal tracking with full milestone
recording, resolving issue rohitdash08#133.

New model additions (models.py):
- SavingsGoal  — user-scoped goal with target_amount, current_amount,
  target_date, status (ACTIVE / COMPLETED / ABANDONED), currency
- GoalDeposit  — deposit ledger entry per goal
- GoalMilestone — auto-recorded when 25 / 50 / 75 / 100% is crossed

New service (app/services/savings.py):
- create_goal / get_goals / get_goal / update_goal / delete_goal
- deposit() — credits amount, auto-completes goal at target, triggers
  _record_new_milestones() (idempotent, no duplicates)
- goal_to_dict() — serialises goal with progress_pct

New routes (app/routes/savings.py):
- GET    /savings/goals
- POST   /savings/goals
- GET    /savings/goals/<id>
- PATCH  /savings/goals/<id>
- DELETE /savings/goals/<id>       → 204 No Content
- POST   /savings/goals/<id>/deposit
- GET    /savings/goals/<id>/milestones

Tests (tests/test_savings.py — 28 tests):
- Auth gates, create (happy + 3 error paths), list/get, update,
  delete, deposits (happy + invalid + auto-complete + post-complete
  rejection), milestones (empty, partial, all-4, no-duplicates),
  service-layer unit test

Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

1 participant