feat(creatives): add configurable per-client creative style and skill builder in UI and API

This commit is contained in:
Marcos Fargas
2026-10-13 01:44:44 +02:00
parent 2a1629cda8
commit 142933a654
6 changed files with 2874 additions and 15 deletions

View File

@@ -1,6 +1,7 @@
import { NextRequest, NextResponse } from 'next/server';
import { authenticateIntegrationRequest } from '@/lib/integrations-auth';
import { createClient } from '@supabase/supabase-js';
import { compileClientSkillMarkdown, normalizeCreativeStyle } from '@/lib/creative-style';
import fs from 'fs';
import path from 'path';
@@ -17,10 +18,10 @@ export async function GET(req: NextRequest) {
const serviceRoleKey = process.env.SUPABASE_SERVICE_ROLE_KEY!;
const adminClient = createClient(supabaseUrl, serviceRoleKey);
// 1. Obtener slug del cliente
// 1. Obtener slug y creative_style del cliente desde BD
const { data: tenant, error: tErr } = await adminClient
.from('tenants')
.select('id, name, slug')
.select('id, name, slug, creative_style, settings')
.eq('id', tenantId)
.maybeSingle();
@@ -31,19 +32,32 @@ export async function GET(req: NextRequest) {
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'),
];
// 2. Resolver skill del cliente: primero desde BD (creative_style editable en la app), fallback a archivo en disco
const rawDbStyle =
tenant.creative_style && Object.keys(tenant.creative_style).length > 0
? tenant.creative_style
: (tenant.settings as any)?.creative_style;
let clientSkill = '';
for (const p of clientCandidates) {
if (fs.existsSync(p)) {
clientSkill = fs.readFileSync(p, 'utf-8');
break;
const skillsDir = path.join(process.cwd(), 'skills');
if (rawDbStyle && Object.keys(rawDbStyle).length > 0) {
const normalized = normalizeCreativeStyle(rawDbStyle, tenant.name || 'Cliente', slug);
clientSkill = compileClientSkillMarkdown(normalized, tenant.name || 'Cliente', slug);
} else {
const clientCandidates = [
path.join(skillsDir, 'clients', `${slug}.md`),
path.join(skillsDir, 'clients', slug === 'bps' ? 'blue-parrot-school.md' : `${slug}.md`),
];
for (const p of clientCandidates) {
if (fs.existsSync(p)) {
clientSkill = fs.readFileSync(p, 'utf-8');
break;
}
}
if (!clientSkill) {
const normalized = normalizeCreativeStyle(null, tenant.name || 'Cliente', slug);
clientSkill = compileClientSkillMarkdown(normalized, tenant.name || 'Cliente', slug);
}
}