import { NextRequest, NextResponse } from 'next/server'; import { auth } from '@clerk/nextjs/server'; import { db, projects, users } from '@mcpengine/db'; import { eq, desc, and, count } from 'drizzle-orm'; // ── GET /api/projects — list user's projects with pagination ──────────────── export async function GET(req: NextRequest) { try { const { userId: clerkId } = await auth(); if (!clerkId) { return NextResponse.json({ error: 'Unauthorized' }, { status: 401 }); } const user = await db.query.users.findFirst({ where: eq(users.clerkId, clerkId), }); if (!user) { return NextResponse.json({ error: 'User not found' }, { status: 404 }); } const url = new URL(req.url); const page = Math.max(1, parseInt(url.searchParams.get('page') || '1', 10)); const limit = Math.min(50, Math.max(1, parseInt(url.searchParams.get('limit') || '20', 10))); const offset = (page - 1) * limit; const [rows, totalResult] = await Promise.all([ db.query.projects.findMany({ where: eq(projects.userId, user.id), orderBy: [desc(projects.updatedAt)], limit, offset, with: { tools: { columns: { id: true, name: true, enabled: true } }, apps: { columns: { id: true, name: true, pattern: true } }, }, }), db.select({ count: count() }).from(projects).where(eq(projects.userId, user.id)), ]); const total = totalResult[0]?.count ?? 0; return NextResponse.json({ data: rows, meta: { page, limit, total, totalPages: Math.ceil(total / limit), }, }); } catch (error) { console.error('[GET /api/projects]', error); return NextResponse.json( { error: 'Internal server error' }, { status: 500 }, ); } } // ── POST /api/projects — create a new project ────────────────────────────── export async function POST(req: NextRequest) { try { const { userId: clerkId } = await auth(); if (!clerkId) { return NextResponse.json({ error: 'Unauthorized' }, { status: 401 }); } const user = await db.query.users.findFirst({ where: eq(users.clerkId, clerkId), }); if (!user) { return NextResponse.json({ error: 'User not found' }, { status: 404 }); } const body = await req.json(); const { name, slug, description, specUrl, templateId } = body; if (!name || !slug) { return NextResponse.json( { error: 'name and slug are required' }, { status: 400 }, ); } // Check for duplicate slug under same user const existing = await db.query.projects.findFirst({ where: and(eq(projects.userId, user.id), eq(projects.slug, slug)), }); if (existing) { return NextResponse.json( { error: 'A project with this slug already exists' }, { status: 409 }, ); } const [project] = (await db .insert(projects) .values({ userId: user.id, teamId: user.teamId, name, slug, description: description || null, specUrl: specUrl || null, templateId: templateId || null, status: 'draft', }) .returning()) as any[]; return NextResponse.json({ data: project }, { status: 201 }); } catch (error) { console.error('[POST /api/projects]', error); return NextResponse.json( { error: 'Internal server error' }, { status: 500 }, ); } }