Files
4ventures-client-portal/src/app/api/integrations/creatives/route.ts

142 lines
4.0 KiB
TypeScript

import { NextRequest, NextResponse } from 'next/server';
import { authenticateIntegrationRequest } from '@/lib/integrations-auth';
import { createClient } from '@supabase/supabase-js';
export async function POST(req: NextRequest) {
let body: any;
try {
body = await req.json();
} catch {
return NextResponse.json({ error: 'Invalid JSON body' }, { status: 400 });
}
const auth = await authenticateIntegrationRequest(req, { requireTenant: true, parsedBody: body });
if (!auth.ok) {
return auth.errorResponse!;
}
const tenantId = auth.tenantId!;
const supabaseUrl = process.env.NEXT_PUBLIC_SUPABASE_URL!;
const serviceRoleKey = process.env.SUPABASE_SERVICE_ROLE_KEY!;
const adminClient = createClient(supabaseUrl, serviceRoleKey);
// Acepta array o un único objeto
const items = Array.isArray(body)
? body
: Array.isArray(body.creatives)
? body.creatives
: [body];
if (!items.length) {
return NextResponse.json({ error: 'No creatives provided' }, { status: 400 });
}
// Si viene generation_request_id, averiguar parent_id (source_creative_id del request)
let defaultParentId: string | null = null;
const genRequestId = body.generation_request_id || items[0]?.generation_request_id;
if (genRequestId) {
const { data: genReq } = await adminClient
.from('generation_requests')
.select('source_creative_id')
.eq('id', genRequestId)
.eq('tenant_id', tenantId)
.maybeSingle();
if (genReq) {
defaultParentId = genReq.source_creative_id;
}
}
const toInsert = items.map((c: any) => {
const meta = { ...(c.meta || {}) };
if (c.composition_notes) {
meta.composition_notes = c.composition_notes;
}
return {
tenant_id: tenantId,
campaign_name: c.campaign_name || null,
adset_id: c.adset_id || null,
meta_ad_id: c.meta_ad_id || null,
format: c.format || 'estatico',
angle: c.angle || null,
hook: c.hook || null,
primary_text: c.primary_text || null,
headline: c.headline || null,
cta: c.cta || null,
asset_url: c.asset_url || null,
thumbnail_url: c.thumbnail_url || null,
status: 'borrador', // nacen siempre en borrador
visibility: 'agency', // nacen siempre en agency
created_by: 'claude', // creadas por Claude
parent_id: c.parent_id || defaultParentId,
generation_request_id: c.generation_request_id || genRequestId || null,
meta,
};
});
const { data: inserted, error } = await adminClient
.from('creatives')
.insert(toInsert)
.select('*');
if (error) {
return NextResponse.json({ error: error.message }, { status: 500 });
}
// Registrar cada creación en creative_events con actor 'claude'
for (const c of inserted || []) {
await adminClient.from('creative_events').insert({
tenant_id: tenantId,
creative_id: c.id,
event_type: 'creative_generated',
actor: 'claude',
to_status: 'borrador',
payload: {
angle: c.angle,
format: c.format,
generation_request_id: c.generation_request_id,
parent_id: c.parent_id,
},
visibility: 'agency',
});
}
return NextResponse.json({
ok: true,
count: inserted?.length || 0,
creatives: inserted,
});
}
export async function GET(req: NextRequest) {
const auth = await authenticateIntegrationRequest(req, { requireTenant: true });
if (!auth.ok) {
return auth.errorResponse!;
}
const tenantId = auth.tenantId!;
const status = req.nextUrl.searchParams.get('status');
const supabaseUrl = process.env.NEXT_PUBLIC_SUPABASE_URL!;
const serviceRoleKey = process.env.SUPABASE_SERVICE_ROLE_KEY!;
const adminClient = createClient(supabaseUrl, serviceRoleKey);
let query = adminClient
.from('creatives')
.select('*')
.eq('tenant_id', tenantId);
if (status) {
query = query.eq('status', status);
}
const { data: creatives, error } = await query;
if (error) {
return NextResponse.json({ error: error.message }, { status: 500 });
}
return NextResponse.json(creatives || []);
}