homelab/apps/finance/services/api/main/models_dream.go
Gonçalo Rodrigues 2ab3acdce2 feat(goals): Goal Planner — type-driven planner merged into /goals tab
* feat(property): Layer 3 — Dream House Simulator

Add /dream page with a four-phase simulation engine:

  Phase 1 — Save the down payment (uses current property equity)
  Phase 2 — Construction period (both loans running simultaneously)
  Phase 3 — Sell current house, apply proceeds to construction loan
  Phase 4 — Final state: just the construction loan remaining

Inputs: dream cost, down payment %, construction loan rate/term,
build duration, monthly savings, expected sale price. All pre-filled
from existing property/loan data when available.

Output: per-phase timeline cards, monthly cost bar chart, total
interest, final payoff date, and a key levers section.

Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>

* refactor(plan): rename Dream House to Goal Planner at /plan

- Route /dream → /plan
- Nav label "Dream House" → "Goal Planner"
- Template dream.html → plan.html
- All user-facing labels generalised (construction loan → new loan,
  build duration → acquisition/build period, current property →
  current asset, dream house cost → new goal cost, etc.)
- Empty state updated with generic copy and 🎯 icon

Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>

* feat(goals): merge Goal Planner into /goals as a second tab

- /goals now has two tabs: "Committed goals" and "Goal Planner"
- Goal creation only happens from the Planner tab (simulate first,
  then "Save as goal" → creates an uncommitted goal)
- Commitment, deadline adjustment, and deletion stay on the Goals tab
- Off-track goals show an "Adjust deadline →" button that pushes the
  deadline to the realistic date based on current savings rate
- /plan and /dream both redirect to /goals?tab=planner (301)
- "Goal Planner" nav link removed; plan.html kept for redirect compat
- GoalsData gains Tab, PlanProperties, PlanLoans, HasPlanResult,
  PlanResult, PlanForm fields

Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>

* feat(goals): type-driven planner — Save for a purchase vs Sell & upgrade

Goal Planner tab now opens with two goal type cards:

  🛒 Save for a purchase — name, target, monthly savings, optional
     deadline. Shows time-to-reach at current rate, monthly needed
     to hit the deadline, and a feasibility banner.

  🔄 Sell & upgrade — the full four-phase transition simulator
     (existing asset + loan → acquire new → sell old → payoff).

Each type has its own focused form and result section. Selecting a
type highlights the card and loads the matching form. Results include
a "Save as goal" action that drops an uncommitted goal into the
Goals tab.

Also adds runPurchaseSim() and PurchaseSimResult model.

Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>

---------

Co-authored-by: Gonçalo Rodrigues <guga@Goncalos-MacBook-Pro.local>
Co-authored-by: Claude Sonnet 4.6 <noreply@anthropic.com>
2026-06-16 22:02:41 +01:00

100 lines
2.7 KiB
Go

package main
import "time"
// DreamForm holds the raw user inputs echoed back to the template.
type DreamForm struct {
PropertyID string
LoanID string
DreamCostCents int64
DownPaymentPct float64
ConstructionRatePct float64
ConstructionTermYears int // what the user typed (years); converted to months internally
ConstructionTermMonths int // years * 12
BuildMonths int
MonthlySavingsCents int64
ExpectedSalePriceCents int64
}
// DreamSimResult is the computed output of one simulation run.
type DreamSimResult struct {
// Echoed inputs
Form DreamForm
// Current state (from selected property/loan)
CurrentProperty *PropertyView
CurrentLoan *LoanView
CurrentMonthlyCents int64
// Construction loan details
ConstructionLoanCents int64
ConstructionMonthly int64
// Phase 1 — save the down payment
DownPaymentCents int64
AlreadyHaveCents int64 // equity usable today
StillNeededCents int64
Phase1Months int
Phase1EndDate time.Time
// Phase 2 — construction (both loans running)
Phase2Months int
Phase2EndDate time.Time
Phase2MonthlyCents int64 // mortgage + construction EMI
ExistingBalanceAtSale int64 // mortgage balance at time of sale
ConstructionBalAtSale int64 // construction loan balance at time of sale
// Phase 3 — sell current house, pay down construction loan
SalePriceCents int64
MortgagePayoffCents int64
NetProceedsCents int64
RemainingBalanceCents int64 // construction loan after applying proceeds
// Phase 4 — just the construction loan
Phase4MonthlyCents int64
Phase4Months int
Phase4EndDate time.Time
// Totals
TotalMonths int
TotalYears int // TotalMonths / 12
TotalRemMonths int // TotalMonths % 12
FinalDate time.Time
TotalInterestCents int64
Warning string
}
// PurchaseSimResult is the computed output for a simple save-for-purchase goal.
type PurchaseSimResult struct {
Name string
TargetCents int64
MonthlySavingsCents int64
// At-current-savings projection
MonthsNeeded int
YearsNeeded int
RemMonths int
ReachDate time.Time
// Deadline projection (only set when a deadline was provided)
HasDeadline bool
DeadlineDate time.Time
DeadlineMonths int
MonthlyNeededForDeadline int64
Feasible bool // monthly savings >= monthly needed for deadline
}
// DreamData is passed to the dream.html template (kept for compat; redirect goes to /goals).
type DreamData struct {
UserID string
Email string
Title string
Route string
Properties []PropertyView
Loans []LoanView
HasResult bool
Result *DreamSimResult
Form DreamForm
}