/** * GET /api/workspaces/[slug]/databases/[uuid] — database details (incl. URLs) * PATCH /api/workspaces/[slug]/databases/[uuid] — update fields * DELETE /api/workspaces/[slug]/databases/[uuid]?confirm= * Volumes KEPT by default (data). Pass &delete_volumes=true to drop. */ import { NextResponse } from 'next/server'; import { requireWorkspacePrincipal } from '@/lib/auth/workspace-auth'; import { getDatabaseInProject, updateDatabase, deleteDatabase, projectUuidOf, TenantError, } from '@/lib/coolify'; export async function GET( request: Request, { params }: { params: Promise<{ slug: string; uuid: string }> } ) { const { slug, uuid } = await params; const principal = await requireWorkspacePrincipal(request, { targetSlug: slug }); if (principal instanceof NextResponse) return principal; const ws = principal.workspace; if (!ws.coolify_project_uuid) { return NextResponse.json({ error: 'Workspace has no Coolify project yet' }, { status: 503 }); } try { const db = await getDatabaseInProject(uuid, ws.coolify_project_uuid); return NextResponse.json({ uuid: db.uuid, name: db.name, type: db.type ?? null, status: db.status, isPublic: db.is_public ?? false, publicPort: db.public_port ?? null, internalUrl: db.internal_db_url ?? null, externalUrl: db.external_db_url ?? null, projectUuid: projectUuidOf(db), }); } catch (err) { if (err instanceof TenantError) return NextResponse.json({ error: err.message }, { status: 403 }); return NextResponse.json({ error: 'Database not found' }, { status: 404 }); } } export async function PATCH( request: Request, { params }: { params: Promise<{ slug: string; uuid: string }> } ) { const { slug, uuid } = await params; const principal = await requireWorkspacePrincipal(request, { targetSlug: slug }); if (principal instanceof NextResponse) return principal; const ws = principal.workspace; if (!ws.coolify_project_uuid) { return NextResponse.json({ error: 'Workspace has no Coolify project yet' }, { status: 503 }); } try { await getDatabaseInProject(uuid, ws.coolify_project_uuid); } catch (err) { if (err instanceof TenantError) return NextResponse.json({ error: err.message }, { status: 403 }); return NextResponse.json({ error: 'Database not found' }, { status: 404 }); } let body: Record = {}; try { body = await request.json(); } catch { return NextResponse.json({ error: 'Invalid JSON body' }, { status: 400 }); } const allowed = new Set([ 'name', 'description', 'is_public', 'public_port', 'image', 'limits_memory', 'limits_cpus', ]); const patch: Record = {}; for (const [k, v] of Object.entries(body)) { if (allowed.has(k) && v !== undefined) patch[k] = v; } if (Object.keys(patch).length === 0) { return NextResponse.json({ error: 'No updatable fields in body' }, { status: 400 }); } try { await updateDatabase(uuid, patch); return NextResponse.json({ ok: true, uuid }); } catch (err) { return NextResponse.json( { error: 'Coolify update failed', details: err instanceof Error ? err.message : String(err) }, { status: 502 } ); } } export async function DELETE( request: Request, { params }: { params: Promise<{ slug: string; uuid: string }> } ) { const { slug, uuid } = await params; const principal = await requireWorkspacePrincipal(request, { targetSlug: slug }); if (principal instanceof NextResponse) return principal; const ws = principal.workspace; if (!ws.coolify_project_uuid) { return NextResponse.json({ error: 'Workspace has no Coolify project yet' }, { status: 503 }); } let db; try { db = await getDatabaseInProject(uuid, ws.coolify_project_uuid); } catch (err) { if (err instanceof TenantError) return NextResponse.json({ error: err.message }, { status: 403 }); return NextResponse.json({ error: 'Database not found' }, { status: 404 }); } const url = new URL(request.url); const confirm = url.searchParams.get('confirm'); if (confirm !== db.name) { return NextResponse.json( { error: 'Confirmation required', hint: `Pass ?confirm=${db.name}` }, { status: 409 } ); } // Default: preserve volumes (it's a database — user data lives there). const deleteVolumes = url.searchParams.get('delete_volumes') === 'true'; const deleteConfigurations = url.searchParams.get('delete_configurations') !== 'false'; const deleteConnectedNetworks = url.searchParams.get('delete_connected_networks') !== 'false'; const dockerCleanup = url.searchParams.get('docker_cleanup') !== 'false'; try { await deleteDatabase(uuid, { deleteConfigurations, deleteVolumes, deleteConnectedNetworks, dockerCleanup, }); return NextResponse.json({ ok: true, deleted: { uuid, name: db.name, volumesKept: !deleteVolumes }, }); } catch (err) { return NextResponse.json( { error: 'Coolify delete failed', details: err instanceof Error ? err.message : String(err) }, { status: 502 } ); } }