fix: handle multi-component investment recommendations (CD ladders)

When adding a multi-stage investment strategy (e.g. CD ladder) from AI
recommendations to a board planning scenario, all component investments
are now created as separate rows instead of collapsing into a single
investment. The AI prompt now instructs inclusion of a components array,
the backend loops through components to create individual scenario
investments, and the frontend passes and displays component details.

Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
This commit is contained in:
2026-03-16 15:59:56 -04:00
parent a98a7192bb
commit 7ba5c414b1
3 changed files with 79 additions and 1 deletions

View File

@@ -85,6 +85,15 @@ interface MarketRatesResponse {
high_yield_savings: MarketRate[];
}
interface RecommendationComponent {
label: string;
amount: number;
term_months: number;
rate: number;
bank_name?: string;
investment_type?: string;
}
interface Recommendation {
type: string;
priority: 'high' | 'medium' | 'low';
@@ -97,6 +106,7 @@ interface Recommendation {
suggested_rate?: number;
bank_name?: string;
rationale: string;
components?: RecommendationComponent[];
}
interface AIResponse {
@@ -392,6 +402,7 @@ export function InvestmentPlanningPage() {
termMonths: rec.suggested_term ? parseInt(rec.suggested_term) || null : null,
bankName: rec.bank_name,
rationale: rec.rationale,
components: rec.components || undefined,
});
return scenarioId;
},
@@ -421,6 +432,7 @@ export function InvestmentPlanningPage() {
termMonths: rec.suggested_term ? parseInt(rec.suggested_term) || null : null,
bankName: rec.bank_name,
rationale: rec.rationale,
components: rec.components || undefined,
});
return scenario.id;
},
@@ -865,6 +877,16 @@ export function InvestmentPlanningPage() {
{selectedRec.suggested_amount != null && (
<Text size="sm">Amount: {fmt(selectedRec.suggested_amount)}</Text>
)}
{selectedRec.components && selectedRec.components.length > 0 && (
<Stack gap={2} mt={6}>
<Text size="xs" c="dimmed" fw={600}>{selectedRec.components.length} investments will be created:</Text>
{selectedRec.components.map((c, i) => (
<Text key={i} size="xs" c="dimmed">
{c.label}: {fmt(c.amount)} @ {c.rate}% ({c.term_months} mo)
</Text>
))}
</Stack>
)}
</Alert>
)}