diff --git a/app/api/projects/route.ts b/app/api/projects/route.ts new file mode 100644 index 0000000..ac3f37f --- /dev/null +++ b/app/api/projects/route.ts @@ -0,0 +1,58 @@ +import { NextResponse } from 'next/server'; +import { getServerSession } from 'next-auth'; +import { authOptions } from '@/lib/auth/authOptions'; +import { query } from '@/lib/db-postgres'; + +export async function GET() { + try { + const session = await getServerSession(authOptions); + if (!session?.user?.email) { + return NextResponse.json({ error: 'Unauthorized' }, { status: 401 }); + } + + const email = session.user.email; + + // Fetch projects joined on user email + const projects = await query(` + SELECT p.id, p.data, p.workspace, p.slug + FROM fs_projects p + JOIN fs_users u ON u.id = p.user_id + WHERE u.data->>'email' = $1 + ORDER BY (p.data->>'updatedAt') DESC NULLS LAST + `, [email]); + + // Fetch session stats per project + const sessionStats = await query(` + SELECT + s.data->>'projectId' AS project_id, + COUNT(*)::int AS session_count, + COALESCE(SUM((s.data->>'cost')::float), 0) AS total_cost + FROM fs_sessions s + JOIN fs_users u ON u.id = s.user_id + WHERE u.data->>'email' = $1 + GROUP BY s.data->>'projectId' + `, [email]); + + const statsByProject = new Map(sessionStats.map((s: any) => [s.project_id, s])); + + const result = projects.map((p: any) => { + const stats = statsByProject.get(p.id) || { session_count: 0, total_cost: 0 }; + return { + id: p.id, + ...p.data, + stats: { + sessions: stats.session_count || 0, + costs: parseFloat(stats.total_cost) || 0, + }, + }; + }); + + return NextResponse.json({ projects: result }); + } catch (error) { + console.error('[GET /api/projects] Error:', error); + return NextResponse.json( + { error: 'Failed to fetch projects', details: error instanceof Error ? error.message : String(error) }, + { status: 500 } + ); + } +}