Files
4ventures-client-portal/src/app/api/admin/create-client/route.ts
4Ventures eb00256bea feat: add Instagram, Facebook, TikTok and LinkedIn slots
Organic social channels per client in the agency hub, separate from
paid Meta Ads.

Co-authored-by: Cursor <cursoragent@cursor.com>
2026-09-22 18:58:29 +02:00

94 lines
3.4 KiB
TypeScript

import { NextRequest, NextResponse } from 'next/server';
import { createClient } from '@/lib/supabase/server';
export async function POST(req: NextRequest) {
try {
const supabase = await createClient();
const { data: { user } } = await supabase.auth.getUser();
if (!user) {
return NextResponse.json({ error: 'No autorizado. Inicia sesión.' }, { status: 401 });
}
const userRole = user.app_metadata?.role || user.user_metadata?.role || 'client';
if (userRole !== 'admin' && userRole !== 'team') {
return NextResponse.json({ error: 'Permisos insuficientes. Solo administradores pueden crear clientes.' }, { status: 403 });
}
const body = await req.json();
const { companyName, slug, email, password, role } = body;
if (!companyName || !slug || !email || !password) {
return NextResponse.json({ error: 'Todos los campos son obligatorios.' }, { status: 400 });
}
const sanitizedSlug = slug.toLowerCase().trim().replace(/[^a-z0-9-]/g, '-');
const targetRole = role === 'admin' || role === 'team' ? role : 'client';
const { data, error } = await supabase.rpc('provision_client', {
p_company_name: companyName.trim(),
p_slug: sanitizedSlug,
p_email: email.toLowerCase().trim(),
p_password: password,
p_role: targetRole,
});
if (error) {
console.error('Error in provision_client RPC:', error);
return NextResponse.json({ error: error.message || 'Error al provisionar cliente en base de datos.' }, { status: 500 });
}
// Seed integration slots (best-effort; ignore if table missing)
try {
const tenantId =
data?.tenant_id || data?.id || data?.client?.tenant_id || null;
const serviceKey = process.env.SUPABASE_SERVICE_ROLE_KEY?.trim();
const url = process.env.NEXT_PUBLIC_SUPABASE_URL || 'https://supabase.4ventures.es';
if (tenantId && serviceKey) {
const providers = [
['meta_ads', 'Meta Ads'],
['google_ads', 'Google Ads (MCC)'],
['ga4', 'Google Analytics 4'],
['search_console', 'Search Console'],
['tag_manager', 'Tag Manager'],
['clientify', 'Clientify'],
['klaviyo', 'Klaviyo'],
['mailchimp', 'Mailchimp'],
['google_drive', 'Google Drive'],
['wordpress', 'WordPress'],
['prestashop', 'PrestaShop'],
['shopify', 'Shopify'],
['instagram', 'Instagram'],
['facebook', 'Facebook Page'],
['tiktok', 'TikTok'],
['linkedin', 'LinkedIn'],
];
await fetch(`${url}/rest/v1/integrations`, {
method: 'POST',
headers: {
apikey: serviceKey,
Authorization: `Bearer ${serviceKey}`,
'Content-Type': 'application/json',
Prefer: 'resolution=ignore-duplicates',
},
body: JSON.stringify(
providers.map(([provider, label]) => ({
tenant_id: tenantId,
provider,
status: 'disconnected',
label,
}))
),
});
}
} catch (e) {
console.warn('seed integrations skipped', e);
}
return NextResponse.json({ success: true, client: data });
} catch (err: any) {
console.error('Server error creating client:', err);
return NextResponse.json({ error: err?.message || 'Error interno del servidor.' }, { status: 500 });
}
}