3dct-client-mirror/snapshot-2026-08-15/home-weddingcaketopper/app/api/preview/generate/route.ts
Mannu 596cfcca34 snapshot(2026-08-15): client production system, pre-engagement baseline
Read-only mirror of the client's existing system as it stood before our
work began. Taken from matthijsexpand@149.210.159.152 (TransIP VPS,
Lelystad NL) with the client's written permission.

Contents:
- home-weddingcaketopper/  Next.js app, proxy.py, supabase schema
- var-www/                 static webroots for all three domains
- etc-nginx/               vhost configs (previously unversioned, server-only)

Excluded: node_modules (704M, regenerable), .next (17M, regenerable),
and env file contents (present on local disk, gitignored — see README).

Not our IP. Not covered by the proposal's assignment clause.
2026-08-15 08:57:40 +05:30

16 lines
1.5 KiB
TypeScript

import { NextResponse } from 'next/server';
import OpenAI from 'openai';
import { supabaseAdmin } from '@/lib/supabase';
export async function POST(req:Request){
try{ const {orderId}=await req.json(); const sb=supabaseAdmin();
const {data:order}=await sb.from('orders').select('*').eq('id',orderId).single(); if(!order) return NextResponse.json({error:'Order niet gevonden'},{status:404});
const prompt=`Maak een hoogwaardige 2D-preview voor een gepersonaliseerde wedding cake topper. Product: bruidspaar taarttopper. Stijl: ${order.style}. Geschikt als basis voor 3D-print, witte achtergrond, front-facing, vriendelijk, premium, geen tekst in beeld. Opmerkingen klant: ${order.notes||'geen'}`;
const openai=new OpenAI({apiKey:process.env.OPENAI_API_KEY!});
const img=await openai.images.generate({model:'gpt-image-2',prompt,size:'1024x1024'} as any);
const b64=(img as any).data?.[0]?.b64_json; if(!b64) throw new Error('Geen afbeelding ontvangen van OpenAI');
const buffer=Buffer.from(b64,'base64'); const bucket=process.env.SUPABASE_BUCKET || 'order-uploads'; const path=`${orderId}/preview.png`;
const up=await sb.storage.from(bucket).upload(path,buffer,{contentType:'image/png',upsert:true}); if(up.error) throw up.error;
const {data:pub}=sb.storage.from(bucket).getPublicUrl(path); await sb.from('orders').update({preview_url:pub.publicUrl,status:'preview_ready'}).eq('id',orderId);
return NextResponse.json({previewUrl:pub.publicUrl});
}catch(e:any){return NextResponse.json({error:e.message||'Preview fout'},{status:500})}
}