feat(api): auto-complete savings goals when current_amount reaches target_amount#755
Open
Salmatcre8 wants to merge 1 commit into
Open
feat(api): auto-complete savings goals when current_amount reaches target_amount#755Salmatcre8 wants to merge 1 commit into
Salmatcre8 wants to merge 1 commit into
Conversation
Goals had no status field and never transitioned to completed at 100%, so the frontend couldn't tell an in-progress goal from a fully-funded one and there was no trigger point for completion notifications (Suncrest-Labs#684). - Migration 040 adds status (active|completed|archived, default active, CHECK-constrained) and completed_at columns + a status index. - Domain: GoalStatus type + ParseStatus; Status and CompletedAt fields on SavingsGoal; ErrGoalCompleted. - enrichProgress auto-transitions an active goal to completed once progress_pct >= 100, stamping completed_at and persisting the change. - GET /api/v1/users/savings-goals?status=active|completed|archived filters (default returns all); filtering is applied post-enrichment so freshly completed goals are included. - PATCH on a completed goal returns 409 (ErrGoalCompleted); a completed goal may only be archived. - Repository reads/writes the new columns; Create defaults status=active. Tests (handler-level, real service + in-memory repo): goal at 99% stays active, goal at 100% auto-completes with completed_at set, ?status=completed filter, and PATCH on a completed goal returns 409. Closes Suncrest-Labs#684
|
@Salmatcre8 Great news! 🎉 Based on an automated assessment of this PR, the linked Wave issue(s) no longer count against your application limits. You can now already apply to more issues while waiting for a review of this PR. Keep up the great work! 🚀 |
0xDeon
requested changes
Jun 27, 2026
0xDeon
left a comment
Contributor
There was a problem hiding this comment.
Merge conflict with main. Rebase onto main and resolve conflicts before this can be merged.
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment
Add this suggestion to a batch that can be applied as a single commit.This suggestion is invalid because no changes were made to the code.Suggestions cannot be applied while the pull request is closed.Suggestions cannot be applied while viewing a subset of changes.Only one suggestion per line can be applied in a batch.Add this suggestion to a batch that can be applied as a single commit.Applying suggestions on deleted lines is not supported.You must change the existing code in this line in order to create a valid suggestion.Outdated suggestions cannot be applied.This suggestion has been applied or marked resolved.Suggestions cannot be applied from pending reviews.Suggestions cannot be applied on multi-line comments.Suggestions cannot be applied while the pull request is queued to merge.Suggestion cannot be applied right now. Please check back later.
Summary
Goals had no status field and never transitioned to completed at 100%, so the frontend couldn't distinguish an in-progress goal from a fully-funded one, and there was no trigger point for completion notifications / celebration UI.
Closes #684
What's included
status(active|completed|archived, defaultactive, CHECK-constrained) andcompleted_atcolumns, plus astatusindex.GoalStatustype +ParseStatus;StatusandCompletedAtonSavingsGoal;ErrGoalCompleted.enrichProgresstransitions an active goal tocompletedonceprogress_pct >= 100, stampscompleted_at, and persists the change.GET /api/v1/users/savings-goals?status=active|completed|archived(default returns all). Filtering is applied post-enrichment so a goal that just hit 100% shows up under?status=completedimmediately.PATCHon a completed goal returns 409 (ErrGoalCompleted); a completed goal may only be archived.Createdefaultsstatus=active.Acceptance criteria
status(default active) +completed_atprogress_pct >= 100completed_atset on completion?status=completedreturns only completed goalsPATCHon a completed goal → 409Tests
Real
SavingsGoalService+ in-memory repo, driven through the handler: 99% stays active, 100% auto-completes withcompleted_at,?status=completedfilter, andPATCHcompleted → 409.Notes / judgment calls
handlerpackage (real service + in-memory repo, end-to-end via HTTP) becauseinternal/service's existing*_test.gofiles (savings_goal_service_test.go,savings_schedule_service_test.go) do not compile onmain— leftovers from #689 feat(api): fire push notifications when savings goal crosses #710 / the savings-schedule merge (stale mocks missingUpdateMilestones/CreateVault, uuid-keyed balances, missing constructor args). I deliberately kept this PR from touching those files to avoid conflicts with whatever fixes them; the behaviour is fully covered through the handler instead.cmd/api/main.godoes not build onmain(wsHubmissingPushToUser) — untouched here; myinternal/...packages build and vet cleanly.status: archived); manualstatus: completedvia PATCH is rejected (completion is automatic).