Skip to content

feat(goals): multiple concurrent goals with priority-weighted allocation (#358) - #733

Open
huangji6693-max wants to merge 1 commit into
Neurowealth:mainfrom
huangji6693-max:feat/multiple-concurrent-goals-allocation-358
Open

huangji6693-max wants to merge 1 commit into
Neurowealth:mainfrom
huangji6693-max:feat/multiple-concurrent-goals-allocation-358

Conversation

@huangji6693-max

Copy link
Copy Markdown
Contributor

Closes #358

Summary

Implements multiple concurrent SavingsGoal support with priority-weighted and sequential allocation across shared portfolio capital:

  1. Schema & Migration (prisma/schema.prisma):

    • Added User.goalFundingMode (SEQUENTIAL | WEIGHTED, default SEQUENTIAL).
    • Added SavingsGoal.priority (Int @default(100)), allocationWeight (Decimal @default(1) @db.Decimal(10, 4)), and fundingMode (String @default("SEQUENTIAL")).
    • Added GoalAllocation append-only attribution ledger (goalId, amount, sourceType, sourceRef, createdAt) with forward migration and rollback.sql.
  2. Pure Allocation Engine (src/goals/allocation.ts):

    • sortGoalsByPriority: deterministic ordering (priority ASC, targetDate ASC, createdAt ASC, id ASC).
    • attributeContribution: supports SEQUENTIAL waterfall and WEIGHTED proportional water-filling cascade up to each active goal's remaining headroom, returning any unallocated remainder.
    • attributeYield: attributes snapshot yield proportional to each active goal's attributed balance (currentAmount), capped by remaining headroom.
    • attributeWithdrawal: reduces attributed capital in reverse funding order (or position-scoped goals first when positionId is specified), clamping attributed balances to >= 0.
    • reconcileUserGoalAllocations: computes per-goal currentAmount, portfolioShare, and portfolio-level unallocated capital.
    • selectBindingGoal: selects the under-funded active goal with the highest requiredApy for GoalTrackingStrategy and enforces the stricter (Math.max) riskCeiling across all active goals while preserving exact single-goal backward compatibility.
  3. Service, Agent & API Integration:

    • src/goals/service.ts & src/controllers/goal-controller.ts & src/routes/goals.ts (/api/v1/portfolio/goals and /api/v1/goals):
      • GET /: returns all goals sorted by priority with portfolioShare, bindingGoalId, effectiveRiskCeiling, totalPortfolioAmount, totalAttributedAmount, and unallocatedAmount.
      • PATCH /:id: updates priority, allocationWeight, fundingMode, targetAmount, targetDate, riskCeiling, name.
      • POST /reorder: atomic bulk priority update.
      • POST /reassign: atomic ledger-backed balance transfer (MANUAL_REASSIGN -amount / +amount) between two same-user goals without touching on-chain positions.
    • src/agent/router.ts: loadActiveGoals / loadActiveGoal resolves the binding goal and strictest risk ceiling across all active goals.
    • Documentation (docs/GOALS_MULTI.md, ASSUMPTIONS.md, docs/openapi.yaml, docs/API_KEYS.md).

Verification

  • npx prisma generate
  • npm run docs:scopes
  • node scripts/check-openapi-drift.js
  • bash scripts/check-migration-rollback.sh
  • npm run typecheck
  • npx jest tests/unit/goals/allocation.test.ts tests/unit/goals/externalHoldings.test.ts tests/integration/goals-multi.integration.test.ts tests/integration/agent/goal-strategy-selection.integration.test.ts tests/unit/middleware/rateLimitTierMatrix.test.ts tests/unit/auth/scopeCatalog.test.ts --runInBand

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.

Multiple Concurrent Goals with Priority-Weighted Allocation

2 participants