Require 9:16 and 1.91:1 adaptations alongside every static 4:5 ad creative.

Generation briefs and Canva webhooks now declare all three Meta placements so WF3/WF5 deliver feed, Stories, and landscape from one Freepik base.

Co-authored-by: Cursor <cursoragent@cursor.com>
This commit is contained in:
4Ventures
2026-10-13 17:03:40 +02:00
parent c8608f36f5
commit 1cf8e7c1bd
12 changed files with 243 additions and 35 deletions

View File

@@ -127,16 +127,31 @@ export async function PATCH(
(existingMeta as any).raw_image_url ||
(!creative.asset_final && creative.asset_url ? creative.asset_url : undefined);
const placementMeta: Record<string, string> = {};
if (typeof body.stories_asset_url === 'string' && body.stories_asset_url) {
placementMeta.stories_asset_url = body.stories_asset_url;
}
if (typeof body.landscape_asset_url === 'string' && body.landscape_asset_url) {
placementMeta.landscape_asset_url = body.landscape_asset_url;
}
if (body.meta !== undefined && typeof body.meta === 'object' && body.meta !== null) {
updates.meta = {
...existingMeta,
...(preservedRawUrl ? { raw_image_url: preservedRawUrl } : {}),
...body.meta,
...placementMeta,
};
} else if (preservedRawUrl && body.asset_final) {
updates.meta = {
...existingMeta,
raw_image_url: preservedRawUrl,
...placementMeta,
};
} else if (Object.keys(placementMeta).length > 0) {
updates.meta = {
...existingMeta,
...placementMeta,
};
}

View File

@@ -1,6 +1,7 @@
import { NextRequest, NextResponse } from 'next/server';
import { authenticateIntegrationRequest } from '@/lib/integrations-auth';
import { dispatchN8nWebhookAsync } from '@/lib/creatives-webhooks';
import { staticAdWebhookAspectFields } from '@/lib/creatives-aspect-ratios';
import { normalizeMetaAdCopyInput } from '@/lib/meta-ad-copy';
import { createClient } from '@supabase/supabase-js';
@@ -66,6 +67,11 @@ export async function POST(req: NextRequest) {
if (c.composition_notes) {
meta.composition_notes = c.composition_notes;
}
if (c.composition_notes_by_aspect) {
meta.composition_notes_by_aspect = c.composition_notes_by_aspect;
}
if (c.stories_asset_url) meta.stories_asset_url = c.stories_asset_url;
if (c.landscape_asset_url) meta.landscape_asset_url = c.landscape_asset_url;
if (c.asset_url && !c.asset_final && !meta.raw_image_url) {
meta.raw_image_url = c.asset_url;
}
@@ -154,6 +160,7 @@ export async function POST(req: NextRequest) {
meta: c.meta || {},
client: clientInfo,
},
...staticAdWebhookAspectFields(c.format),
});
}
}

View File

@@ -1,6 +1,7 @@
import { NextRequest, NextResponse } from 'next/server';
import { authenticateIntegrationRequest } from '@/lib/integrations-auth';
import { dispatchN8nWebhookAsync } from '@/lib/creatives-webhooks';
import { staticAdBriefAspectFields } from '@/lib/creatives-aspect-ratios';
import { createClient } from '@supabase/supabase-js';
export async function POST(req: NextRequest) {
@@ -109,14 +110,18 @@ export async function POST(req: NextRequest) {
const deadline = new Date();
deadline.setDate(deadline.getDate() + 1); // 24 horas después
const format =
creative.format === 'video' || creative.format === 'carrusel'
? creative.format
: 'estatico';
const brief = {
client_id: tenantId,
tenant_id: tenantId,
client_slug: clientSlug,
reason: 'fatiga',
source_creative_id: creativeId,
format: creative.format === 'video' || creative.format === 'carrusel' ? creative.format : 'estatico',
aspect_ratio: '4:5',
format,
...staticAdBriefAspectFields(format),
variants_requested: 2,
avoid_angles: avoidAngles,
campaign_name: campaignName,