From 0c948f5074fb7e1d228b3cc1d7f7535000279678 Mon Sep 17 00:00:00 2001 From: Fusion Date: Wed, 15 Apr 2026 09:49:45 -0700 Subject: [PATCH] feat(FN-1671): add AI milestone suggestion feature - Add milestone suggestion generation backend contract with scoring algorithm - Add milestone suggestion hook actions (generate, accept, dismiss) in useRoadmaps - Add RoadmapsView UI with suggestion panel, cards, and accept/dismiss buttons - Document AI milestone suggestion feature in dashboard guide - Add roadmap-suggestions unit tests covering generation and UX flows --- docs/dashboard-guide.md | 22 + packages/dashboard/app/api.ts | 27 + .../dashboard/app/components/RoadmapsView.tsx | 133 ++++ packages/dashboard/app/hooks/useRoadmaps.ts | 220 ++++++- packages/dashboard/app/styles.css | 224 +++++++ .../dashboard/src/roadmap-suggestions.test.ts | 619 ++++++++++++++++++ packages/dashboard/src/roadmap-suggestions.ts | 521 +++++++++++++++ packages/dashboard/src/routes.ts | 64 ++ 8 files changed, 1829 insertions(+), 1 deletion(-) create mode 100644 packages/dashboard/src/roadmap-suggestions.test.ts create mode 100644 packages/dashboard/src/roadmap-suggestions.ts diff --git a/docs/dashboard-guide.md b/docs/dashboard-guide.md index 67078794d..7b27a30e9 100644 --- a/docs/dashboard-guide.md +++ b/docs/dashboard-guide.md @@ -224,6 +224,28 @@ Milestones and features can be reordered using native drag-and-drop: - Use the header buttons to edit or delete the selected roadmap - Delete requires confirmation and removes all associated milestones and features +### AI Milestone Suggestions + +Roadmaps View includes one-click AI-powered milestone generation to help you quickly create milestone ideas from a goal prompt. + +**How to use:** + +1. Select a roadmap from the sidebar +2. In the "Generate Milestone Ideas" section, describe your roadmap goal in the text area +3. Click **Generate Milestones** to create AI suggestions +4. Review the suggested milestones: + - Click the **check icon** on any suggestion to accept it as a milestone + - Click **Accept All** to add all suggestions as milestones (in order) + - Click the **X** button to clear all suggestions + +**Key features:** + +- Suggestions are generated using AI and include both titles and descriptions +- Accepted milestones appear immediately in your roadmap +- Milestones are created in the order displayed in the suggestion list +- Suggestions are ephemeral (in-memory only) and don't persist to the database +- The generate button is disabled when no roadmap is selected or prompt is empty + ### Empty States - **No roadmaps**: "No roadmaps yet. Click + to create one." diff --git a/packages/dashboard/app/api.ts b/packages/dashboard/app/api.ts index 454431a10..79e667534 100644 --- a/packages/dashboard/app/api.ts +++ b/packages/dashboard/app/api.ts @@ -4566,6 +4566,33 @@ export function moveRoadmapFeature( }); } +/** Response from milestone suggestion generation */ +export interface MilestoneSuggestionsResponse { + suggestions: Array<{ + title: string; + description?: string; + }>; +} + +/** Generate milestone suggestions from a goal prompt */ +export function generateMilestoneSuggestions( + roadmapId: string, + goalPrompt: string, + count?: number, + projectId?: string +): Promise { + return api( + withProjectId(`/roadmaps/${encodeURIComponent(roadmapId)}/suggestions/milestones`, projectId), + { + method: "POST", + body: JSON.stringify({ + goalPrompt: goalPrompt.trim(), + ...(count !== undefined ? { count } : {}), + }), + } + ); +} + // ── AI Sessions (Background Tasks) ───────────────────────────────────────── export interface AiSessionSummary { diff --git a/packages/dashboard/app/components/RoadmapsView.tsx b/packages/dashboard/app/components/RoadmapsView.tsx index 5b8ad6e42..5b4259530 100644 --- a/packages/dashboard/app/components/RoadmapsView.tsx +++ b/packages/dashboard/app/components/RoadmapsView.tsx @@ -783,8 +783,17 @@ export function RoadmapsView({ projectId, addToast }: RoadmapsViewProps) { reorderMilestones, reorderFeatures, moveFeature, + milestoneSuggestions, + isGeneratingSuggestions, + generateMilestoneSuggestions, + acceptMilestoneSuggestion, + acceptAllMilestoneSuggestions, + clearMilestoneSuggestions, } = useRoadmaps({ projectId }); + // Goal prompt state for milestone suggestion generation + const [goalPrompt, setGoalPrompt] = useState(""); + // Inline edit states const [roadmapEdit, setRoadmapEdit] = useState({ roadmapId: null, @@ -1232,6 +1241,55 @@ export function RoadmapsView({ projectId, addToast }: RoadmapsViewProps) { [deleteFeature, addToast] ); + // Milestone suggestion handlers + const handleGenerateSuggestions = useCallback( + async () => { + if (!goalPrompt.trim()) return; + try { + await generateMilestoneSuggestions(goalPrompt, 5, { + onError: (err) => addToast(err.message, "error"), + }); + } catch { + // Error handled in callback + } + }, + [goalPrompt, generateMilestoneSuggestions, addToast] + ); + + const handleAcceptSuggestion = useCallback( + async (index: number) => { + try { + await acceptMilestoneSuggestion(index, { + onError: (err) => addToast(err.message, "error"), + }); + addToast("Milestone added", "success"); + } catch { + // Error handled in callback + } + }, + [acceptMilestoneSuggestion, addToast] + ); + + const handleAcceptAllSuggestions = useCallback( + async () => { + try { + await acceptAllMilestoneSuggestions({ + onError: (err) => addToast(err.message, "error"), + }); + addToast(`${milestoneSuggestions.length} milestones added`, "success"); + setGoalPrompt(""); + } catch { + // Error handled in callback + } + }, + [acceptAllMilestoneSuggestions, milestoneSuggestions.length, addToast] + ); + + const handleClearSuggestions = useCallback(() => { + clearMilestoneSuggestions(); + setGoalPrompt(""); + }, [clearMilestoneSuggestions]); + const handleCreateFeature = useCallback( async (milestoneId: string, input: RoadmapFeatureCreateInput) => { try { @@ -1396,6 +1454,81 @@ export function RoadmapsView({ projectId, addToast }: RoadmapsViewProps) { )} + {/* Milestone Suggestions Section */} +
+
+

Generate Milestone Ideas

+
+
+