import { NextResponse } from 'next/server'; import { getServerSession } from 'next-auth'; import { authOptions } from '@/lib/auth/authOptions'; import { query } from '@/lib/db-postgres'; export const maxDuration = 120; const GEMINI_API_KEY = process.env.GOOGLE_API_KEY || ''; const GEMINI_MODEL = process.env.GEMINI_MODEL || 'gemini-2.0-flash-exp'; const GEMINI_BASE_URL = 'https://generativelanguage.googleapis.com/v1beta/models'; async function callGemini(prompt: string): Promise { const res = await fetch(`${GEMINI_BASE_URL}/${GEMINI_MODEL}:generateContent?key=${GEMINI_API_KEY}`, { method: 'POST', headers: { 'Content-Type': 'application/json' }, body: JSON.stringify({ contents: [{ parts: [{ text: prompt }] }], generationConfig: { temperature: 0.3, maxOutputTokens: 8000 }, }), }); const data = await res.json(); return data?.candidates?.[0]?.content?.parts?.[0]?.text ?? ''; } export async function POST( req: Request, { params }: { params: Promise<{ projectId: string }> } ) { try { const { projectId } = await params; const session = await getServerSession(authOptions); if (!session?.user?.email) { return NextResponse.json({ error: 'Unauthorized' }, { status: 401 }); } const body = await req.json() as { analysisResult?: Record; sourceData?: { repoUrl?: string; liveUrl?: string; hosting?: string }; }; // Verify ownership const rows = await query<{ data: Record }>( `SELECT p.data FROM fs_projects p JOIN fs_users u ON u.id = p.user_id WHERE p.id = $1::text AND u.data->>'email' = $2::text LIMIT 1`, [projectId, session.user.email] ); if (rows.length === 0) { return NextResponse.json({ error: 'Project not found' }, { status: 404 }); } const current = rows[0].data ?? {}; const projectName = (current.productName as string) || (current.name as string) || 'the product'; const { analysisResult, sourceData } = body; const prompt = `You are a senior DevOps and platform migration architect. Generate a comprehensive, phased migration plan in Markdown for migrating an existing product into a new infrastructure (VIBN — a self-hosted PaaS). Product: ${projectName} Repo: ${sourceData?.repoUrl || 'Not provided'} Live URL: ${sourceData?.liveUrl || 'Not provided'} Current hosting: ${sourceData?.hosting || 'Unknown'} Architecture audit summary: ${analysisResult?.summary || 'No audit data provided.'} Detected components: ${JSON.stringify(analysisResult?.rows || [], null, 2).slice(0, 3000)} Generate a complete migration plan with exactly these 4 phases: # ${projectName} — Migration Plan ## Overview Brief 2-3 sentence description of the migration approach and guiding principle (non-destructive duplication). ## Phase 1: Mirror Set up parallel infrastructure on VIBN without touching production. - [ ] Clone repository to VIBN Gitea - [ ] Configure Coolify application - [ ] Set up identical database schema - [ ] Configure environment variables - [ ] Verify build passes ## Phase 2: Validate Run both systems in parallel and compare outputs. - [ ] Route 5% of traffic to new infrastructure (or test internally) - [ ] Compare API responses between old and new - [ ] Run full end-to-end test suite - [ ] Validate data sync between databases - [ ] Sign off on performance benchmarks ## Phase 3: Cutover Redirect production traffic to the new infrastructure. - [ ] Update DNS records to point to VIBN load balancer - [ ] Monitor error rates and latency for 24h - [ ] Validate all integrations (auth, payments, third-party APIs) - [ ] Keep old infrastructure on standby for 7 days ## Phase 4: Decommission Remove old infrastructure after successful validation period. - [ ] Confirm all data has been migrated - [ ] Archive old repository access - [ ] Terminate old hosting resources - [ ] Update all internal documentation ## Risk Register | Risk | Likelihood | Impact | Mitigation | |------|-----------|--------|------------| | Database migration failure | Medium | High | Full backup before any migration step | | DNS propagation delay | Low | Medium | Use low TTL before cutover | | Third-party integration breakage | Medium | High | Test all webhooks and OAuth in Phase 2 | ## Rollback Plan At any phase, revert by: pointing DNS back to original infrastructure. Data written during parallel run must be synced back manually. Old infrastructure MUST remain live until Phase 4 completes. --- Write a thorough, specific plan. Use real details from the audit where available. Every checklist item should be actionable. Return only the Markdown document.`; const migrationPlan = await callGemini(prompt); // Save to project const updated = { ...current, migrationPlan, creationStage: 'plan', updatedAt: new Date().toISOString(), }; await query( `UPDATE fs_projects SET data = $2::jsonb WHERE id = $1::text`, [projectId, JSON.stringify(updated)] ); return NextResponse.json({ migrationPlan }); } catch (err) { console.error('[generate-migration-plan]', err); return NextResponse.json({ error: 'Internal error' }, { status: 500 }); } }