#688 feat(api): link savings goal to a specific vault — add vault_id to savings_goals#748
Open
Adeolu01 wants to merge 4 commits into
Open
#688 feat(api): link savings goal to a specific vault — add vault_id to savings_goals#748Adeolu01 wants to merge 4 commits into
Adeolu01 wants to merge 4 commits into
Conversation
…scope current_amount to the linked vault Add a nullable vault_id to savings_goals so a goal's current_amount reflects only the balance of its linked vault instead of summing every vault in the currency. Goals without a vault_id keep the legacy sum-all fallback, so existing goals are unaffected. - migration 040 adds nullable vault_id UUID REFERENCES vaults(id) ON DELETE SET NULL - CreateSavingsGoalInput accepts vault_id; the service validates the vault exists, belongs to the caller (403), and shares the goal currency (400) - enrichProgress reads the linked vault balance, falling back to sum-all for unlinked or soft-deleted vaults - service depends on a narrow VaultReader interface (GetVault only) Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
|
@Adeolu01 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! 🚀 |
main on this branch did not compile (pre-existing bad-merge artifacts that blocked go build, govulncheck and gosec). Repaired the minimum needed: - cmd/api: a duplicate notificationDispatcher := left the websocket channel orphaned and triggered "no new variables on left side of :="; merged the websocket and push channels into the single dispatcher used by savings goals and the recurring-deposit scheduler - ws.Hub: add PushToUser so it satisfies notifications.WebSocketHub (the websocket notification channel adapter) - savings schedule service: depend on the narrow VaultReader interface instead of the full vault.Repository (it only calls GetVault), unblocking the service test package fakes - savings schedule test fake: implement the goal repo's UpdateMilestones method Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
The recurring-deposit integration test lives in package postgres and imports service, while service (admin_rebalance_service.go) imported postgres for the ErrRebalanceInFlight sentinel — a cycle that broke 'go test' once the build compiled. Move the sentinel to the admin domain package (imported by both), re-export it from postgres as an alias for existing callers, and drop the service->postgres import. Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
…n test Pre-existing unused import that was masked by the earlier import cycle; it broke go test and govulncheck package loading once the cycle was resolved. Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
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
SavingsGoalService.enrichProgresscomputedcurrent_amountviaSumVaultBalance(userID, currency), summing every vault a user holds in that currency. For a user with multiple vaults, every goal in the same currency reported the combined balance of all vaults — an inflated, incorrect figure. This PR links a goal to a specific vault and scopescurrent_amountto that vault.closes #688
Changes
Schema —
migrations/040_add_savings_goal_vault_id.{up,down}.sqlvault_id UUID REFERENCES vaults(id) ON DELETE SET NULLplus a supporting index.NULLis allowed for backward compatibility: goals created before this migration keep working via the legacy fallback.Domain —
internal/domain/savingsgoal/model.goSavingsGoalgainsVaultID *uuid.UUID(json:"vault_id,omitempty").Service —
internal/service/savings_goal_service.goCreateSavingsGoalInputaccepts an optionalVaultID.enrichProgressnow reads the linked vault'sCurrentBalance. Goals with novault_id(and goals whose linked vault has since been soft-deleted) fall back to the original sum-all logic, so there is no regression for existing data.VaultReaderinterface (GetVaultonly) rather than the full vault repository — interface segregation keeps the dependency minimal and the unit tests light.Handler —
internal/handler/savings_goal_handler.govault_idfrom the create request (malformed UUID →400).403 FORBIDDEN; a currency mismatch surfaces as400 VALIDATION_ERROR.Wiring —
cmd/api/main.goinjects the existingvaultRepositoryinto the savings goal service.Validation behaviour
vault_idowned by caller, matching currencycurrent_amount= that vault's balancevault_idbelonging to another user403 FORBIDDEN400—vault currency (XLM) does not match goal currency (USDC)vault_idnot found400 VALIDATION_ERRORvault_id(legacy)Tests
403; malformedvault_id→400.TEST_DATABASE_DSN): two vaults / two goals isolation through the real Postgres path with a round-trip re-read; foreign-vault rejection.Acceptance criteria
vault_idcolumn tosavings_goalsvault_idlinks it correctlyvault_idbelonging to another user returns403current_amountreflects only the linked vault's balancevault_idfall back to sum-all-vaults (no regression)400