diff --git a/app/[workspace]/project/[projectId]/design/page.tsx b/app/[workspace]/project/[projectId]/design/page.tsx index d2e4184..69b43e3 100644 --- a/app/[workspace]/project/[projectId]/design/page.tsx +++ b/app/[workspace]/project/[projectId]/design/page.tsx @@ -291,12 +291,35 @@ function SurfaceSection({ ); } +// --------------------------------------------------------------------------- +// Surface ID fuzzy-match helper — maps AI-generated labels to our surface IDs +// --------------------------------------------------------------------------- + +function matchSurfaceId(label: string): string | null { + const l = label.toLowerCase(); + if (l.includes("web app") || l.includes("webapp") || l.includes("saas") || l.includes("dashboard") || l.includes("pwa")) return "web-app"; + if (l.includes("marketing") || l.includes("landing") || l.includes("site") || l.includes("homepage")) return "marketing"; + if (l.includes("admin") || l.includes("internal") || l.includes("back office") || l.includes("backoffice")) return "admin"; + if (l.includes("mobile") || l.includes("ios") || l.includes("android") || l.includes("native")) return "mobile"; + if (l.includes("email") || l.includes("notification")) return "email"; + if (l.includes("doc") || l.includes("content") || l.includes("blog") || l.includes("knowledge")) return "docs"; + return null; +} + // --------------------------------------------------------------------------- // Phase 1 — Surface picker // --------------------------------------------------------------------------- -function SurfacePicker({ onConfirm, saving }: { onConfirm: (ids: string[]) => void; saving: boolean }) { - const [selected, setSelected] = useState>(new Set()); +function SurfacePicker({ + onConfirm, + saving, + aiSuggested, +}: { + onConfirm: (ids: string[]) => void; + saving: boolean; + aiSuggested: string[]; +}) { + const [selected, setSelected] = useState>(new Set(aiSuggested)); const toggle = (id: string) => { setSelected(prev => { @@ -307,17 +330,31 @@ function SurfacePicker({ onConfirm, saving }: { onConfirm: (ids: string[]) => vo }; return ( -
+

Design surfaces

-

- Which surfaces does your product need? Select all that apply. +

0 ? 10 : 24 }}> + Which surfaces does your product need?

+ {aiSuggested.length > 0 && ( +
+ + + Based on your PRD, the AI pre-selected the surfaces your product needs. Adjust if needed. + +
+ )} +
{ALL_SURFACES.map(surface => { const isSelected = selected.has(surface.id); + const isAiPick = aiSuggested.includes(surface.id); return ( ); })} @@ -392,9 +436,11 @@ export default function DesignPage({ params }: { params: Promise<{ workspace: st const [savingLock, setSavingLock] = useState(null); const [savingSurfaces, setSavingSurfaces] = useState(false); const [loading, setLoading] = useState(true); + const [aiSuggestedSurfaces, setAiSuggestedSurfaces] = useState([]); useEffect(() => { - fetch(`/api/projects/${projectId}/design-surfaces`) + // Load saved design surfaces + const designP = fetch(`/api/projects/${projectId}/design-surfaces`) .then(r => r.json()) .then(d => { const loaded = (d.surfaces ?? []) as string[]; @@ -402,7 +448,24 @@ export default function DesignPage({ params }: { params: Promise<{ workspace: st setSurfaceThemes(d.surfaceThemes ?? {}); setSelectedThemes(d.surfaceThemes ?? {}); if (loaded.length > 0) setActiveSurfaceId(loaded[0]); + return loaded; + }); + + // Load architecture to get AI-suggested surfaces + const archP = fetch(`/api/projects/${projectId}/architecture`) + .then(r => r.json()) + .then(d => { + const arch = d.architecture; + if (arch?.designSurfaces && Array.isArray(arch.designSurfaces)) { + const matched = (arch.designSurfaces as string[]) + .map(matchSurfaceId) + .filter((id): id is string => id !== null); + setAiSuggestedSurfaces([...new Set(matched)]); + } }) + .catch(() => {}); + + Promise.all([designP, archP]) .catch(() => toast.error("Failed to load design data")) .finally(() => setLoading(false)); }, [projectId]); @@ -462,7 +525,7 @@ export default function DesignPage({ params }: { params: Promise<{ workspace: st } if (surfaces.length === 0) { - return ; + return ; } const activeSurfaces = ALL_SURFACES.filter(s => surfaces.includes(s.id)); diff --git a/app/api/projects/[projectId]/architecture/route.ts b/app/api/projects/[projectId]/architecture/route.ts index 56c84b2..0db21cd 100644 --- a/app/api/projects/[projectId]/architecture/route.ts +++ b/app/api/projects/[projectId]/architecture/route.ts @@ -137,16 +137,10 @@ ${phaseContext} ${prd}`; try { - const res = await fetch(`${AGENT_RUNNER_URL}/atlas/chat`, { + const res = await fetch(`${AGENT_RUNNER_URL}/generate`, { method: "POST", headers: { "Content-Type": "application/json" }, - body: JSON.stringify({ - message: prompt, - session_id: `arch_${projectId}_${Date.now()}`, - history: [], - is_init: false, - tools: [], // no tools needed — just structured generation - }), + body: JSON.stringify({ prompt }), signal: AbortSignal.timeout(120_000), });