feat(integrations): add skills endpoint, enrich creative context with client info, and support meta in creatives
This commit is contained in:
@@ -108,12 +108,32 @@ export async function GET(
|
||||
topCreatives = fallbackRows || [];
|
||||
}
|
||||
|
||||
return NextResponse.json({
|
||||
client_id: tenantId,
|
||||
tenant_id: tenantId,
|
||||
// 5. Obtener datos del cliente (drive_folder_id, slug, nombre)
|
||||
const { data: tenant } = await adminClient
|
||||
.from('tenants')
|
||||
.select('id, name, slug, drive_folder_id, meta_ad_account_id')
|
||||
.eq('id', tenantId)
|
||||
.maybeSingle();
|
||||
|
||||
const contextData = {
|
||||
source_creative: creative,
|
||||
creative,
|
||||
metrics,
|
||||
rules: rules || null,
|
||||
top_creatives: topCreatives,
|
||||
top_historical_creatives: topCreatives,
|
||||
client: {
|
||||
id: tenantId,
|
||||
name: tenant?.name || null,
|
||||
slug: tenant?.slug || null,
|
||||
drive_folder_id: tenant?.drive_folder_id || null,
|
||||
},
|
||||
};
|
||||
|
||||
return NextResponse.json({
|
||||
data: contextData,
|
||||
client_id: tenantId,
|
||||
tenant_id: tenantId,
|
||||
...contextData,
|
||||
});
|
||||
}
|
||||
|
||||
@@ -66,6 +66,7 @@ export async function POST(req: NextRequest) {
|
||||
created_by: 'claude', // creadas por Claude
|
||||
parent_id: c.parent_id || defaultParentId,
|
||||
generation_request_id: c.generation_request_id || genRequestId || null,
|
||||
meta: c.meta || {},
|
||||
}));
|
||||
|
||||
const { data: inserted, error } = await adminClient
|
||||
|
||||
73
src/app/api/integrations/skills/route.ts
Normal file
73
src/app/api/integrations/skills/route.ts
Normal file
@@ -0,0 +1,73 @@
|
||||
import { NextRequest, NextResponse } from 'next/server';
|
||||
import { authenticateIntegrationRequest } from '@/lib/integrations-auth';
|
||||
import { createClient } from '@supabase/supabase-js';
|
||||
import fs from 'fs';
|
||||
import path from 'path';
|
||||
|
||||
export async function GET(req: NextRequest) {
|
||||
const auth = await authenticateIntegrationRequest(req, { requireTenant: true });
|
||||
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);
|
||||
|
||||
// 1. Obtener slug del cliente
|
||||
const { data: tenant, error: tErr } = await adminClient
|
||||
.from('tenants')
|
||||
.select('id, name, slug')
|
||||
.eq('id', tenantId)
|
||||
.maybeSingle();
|
||||
|
||||
if (tErr || !tenant) {
|
||||
return NextResponse.json({ error: 'Tenant not found' }, { status: 404 });
|
||||
}
|
||||
|
||||
const slug = (tenant.slug || 'bps').toLowerCase().trim();
|
||||
const formatParam = (req.nextUrl.searchParams.get('format') || 'estatico').toLowerCase().trim();
|
||||
|
||||
// 2. Resolver skill del cliente (skills/clients/<slug>.md)
|
||||
const skillsDir = path.join(process.cwd(), 'skills');
|
||||
const clientCandidates = [
|
||||
path.join(skillsDir, 'clients', `${slug}.md`),
|
||||
path.join(skillsDir, 'clients', slug === 'bps' ? 'blue-parrot-school.md' : `${slug}.md`),
|
||||
path.join(skillsDir, 'clients', 'blue-parrot-school.md'),
|
||||
];
|
||||
|
||||
let clientSkill = '';
|
||||
for (const p of clientCandidates) {
|
||||
if (fs.existsSync(p)) {
|
||||
clientSkill = fs.readFileSync(p, 'utf-8');
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
// 3. Resolver skill del formato (skills/formats/<format>-4-5.md o skills/formats/<format>.md, fallback a estatico)
|
||||
const formatCandidates = [
|
||||
path.join(skillsDir, 'formats', `${formatParam}-4-5.md`),
|
||||
path.join(skillsDir, 'formats', `${formatParam}.md`),
|
||||
path.join(skillsDir, 'formats', 'estatico-4-5.md'),
|
||||
path.join(skillsDir, 'formats', 'estatico.md'),
|
||||
];
|
||||
|
||||
let formatSkill = '';
|
||||
for (const p of formatCandidates) {
|
||||
if (fs.existsSync(p)) {
|
||||
formatSkill = fs.readFileSync(p, 'utf-8');
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
return NextResponse.json({
|
||||
data: {
|
||||
client_skill: clientSkill,
|
||||
format_skill: formatSkill,
|
||||
},
|
||||
// Compatibilidad en primer nivel
|
||||
client_skill: clientSkill,
|
||||
format_skill: formatSkill,
|
||||
});
|
||||
}
|
||||
Reference in New Issue
Block a user