diff --git a/app/api/projects/[projectId]/preview-url/route.ts b/app/api/projects/[projectId]/preview-url/route.ts index 9dd4017..accd86d 100644 --- a/app/api/projects/[projectId]/preview-url/route.ts +++ b/app/api/projects/[projectId]/preview-url/route.ts @@ -2,11 +2,16 @@ import { NextResponse } from 'next/server'; import { getServerSession } from 'next-auth'; import { authOptions } from '@/lib/auth/authOptions'; import { query } from '@/lib/db-postgres'; +import { listApplications, CoolifyApplication } from '@/lib/coolify'; + +const GITEA_BASE = process.env.GITEA_API_URL ?? 'https://git.vibnai.com'; export interface PreviewApp { name: string; url: string | null; - status: 'live' | 'deploying' | 'failed' | 'unknown'; + status: string; + coolifyUuid: string | null; + gitRepo: string | null; } export async function GET( @@ -20,6 +25,7 @@ export async function GET( return NextResponse.json({ error: 'Unauthorized' }, { status: 401 }); } + // 1. Load project — get the Gitea repo name const rows = await query<{ data: Record }>( `SELECT p.data FROM fs_projects p JOIN fs_users u ON u.id = p.user_id @@ -32,26 +38,58 @@ export async function GET( } const data = rows[0].data ?? {}; + const giteaRepo = data.giteaRepo as string | undefined; // e.g. "mark/scout-ai-engine" - // Gather apps with their deployment URLs - const storedApps = (data.apps as Array<{ name: string; fqdn?: string; coolifyServiceUuid?: string }>) ?? []; - const lastDeployment = (data as any).contextSnapshot?.lastDeployment ?? null; - - const apps: PreviewApp[] = storedApps.map(app => ({ - name: app.name, - url: app.fqdn ? (app.fqdn.startsWith('http') ? app.fqdn : `https://${app.fqdn}`) : null, - status: app.fqdn ? 'live' : 'unknown', - })); - - // If no stored apps but we have a last deployment URL, surface it - if (apps.length === 0 && lastDeployment?.url) { - apps.push({ - name: 'app', - url: lastDeployment.url.startsWith('http') ? lastDeployment.url : `https://${lastDeployment.url}`, - status: lastDeployment.status === 'finished' ? 'live' : lastDeployment.status === 'in_progress' ? 'deploying' : 'unknown', - }); + if (!giteaRepo) { + return NextResponse.json({ apps: [], message: 'No Gitea repo linked to this project' }); } - // Also expose the raw last deployment for the panel header - return NextResponse.json({ apps, lastDeployment }); + // 2. Build the possible Gitea remote URLs for this repo (with and without .git) + const repoBase = `${GITEA_BASE}/${giteaRepo}`; + const repoUrls = new Set([repoBase, `${repoBase}.git`]); + + // 3. Fetch all Coolify applications and match by git_repository + let coolifyApps: CoolifyApplication[] = []; + try { + coolifyApps = await listApplications(); + } catch (err) { + console.error('[preview-url] Coolify fetch failed:', err); + // Fall back to stored data + } + + const matched = coolifyApps.filter(app => + app.git_repository && repoUrls.has(app.git_repository.replace(/\/$/, '')) + ); + + if (matched.length > 0) { + const apps: PreviewApp[] = matched.map(app => ({ + name: app.name, + url: app.fqdn + ? (app.fqdn.startsWith('http') ? app.fqdn : `https://${app.fqdn}`) + : null, + status: app.status ?? 'unknown', + coolifyUuid: app.uuid, + gitRepo: app.git_repository ?? null, + })); + return NextResponse.json({ apps, source: 'coolify' }); + } + + // 4. Fallback: use whatever URL was stored by the Coolify webhook + const lastDeployment = (data as any).contextSnapshot?.lastDeployment ?? null; + if (lastDeployment?.url) { + const apps: PreviewApp[] = [{ + name: giteaRepo.split('/').pop() ?? 'app', + url: lastDeployment.url.startsWith('http') ? lastDeployment.url : `https://${lastDeployment.url}`, + status: lastDeployment.status === 'finished' ? 'running' : lastDeployment.status ?? 'unknown', + coolifyUuid: lastDeployment.applicationUuid ?? null, + gitRepo: giteaRepo, + }]; + return NextResponse.json({ apps, source: 'webhook' }); + } + + return NextResponse.json({ + apps: [], + message: `No Coolify app found for repo: ${giteaRepo}`, + giteaRepo, + }); } diff --git a/lib/coolify.ts b/lib/coolify.ts index 91158ff..3072f9b 100644 --- a/lib/coolify.ts +++ b/lib/coolify.ts @@ -188,6 +188,10 @@ export async function createMonorepoAppService(opts: { }); } +export async function listApplications(): Promise { + return coolifyFetch('/applications'); +} + export async function deployApplication(uuid: string): Promise<{ deployment_uuid: string }> { return coolifyFetch(`/applications/${uuid}/deploy`, { method: 'POST' }); }