Unify Ads/RRSS approval flow and add personalized Meta creative regen.

Agency validates first then client; Meta copy is 5+5+1 with on-image vs feed layers, emojis on feed, and partial v2 by image/hook/support/copy.

Co-authored-by: Cursor <cursoragent@cursor.com>
This commit is contained in:
4Ventures
2026-10-13 13:17:36 +02:00
parent 4bc9ed7820
commit 46492c3873
26 changed files with 2014 additions and 204 deletions

View File

@@ -0,0 +1,57 @@
-- Unifica estados de aprobación Ads (creatives) + RRSS (creative_pipeline).
-- Flujo: borrador → revision_agencia → pendiente_aprobacion → aprobada|rechazada → publicada
-- Idempotente.
-- ─── creative_pipeline (RRSS) ───────────────────────────────────────────────
alter table public.creative_pipeline drop constraint if exists creative_pipeline_status_check;
update public.creative_pipeline set status = 'borrador' where status in ('propuesta', 'en_diseno');
-- revision_interna se usaba como "el cliente decide" → pendiente_aprobacion
update public.creative_pipeline set status = 'pendiente_aprobacion' where status = 'revision_interna';
update public.creative_pipeline set status = 'aprobada' where status = 'aprobado';
update public.creative_pipeline set status = 'rechazada' where status = 'rechazado';
update public.creative_pipeline set status = 'publicada' where status = 'publicado';
alter table public.creative_pipeline
alter column status set default 'borrador';
alter table public.creative_pipeline
add constraint creative_pipeline_status_check
check (status in (
'borrador',
'revision_agencia',
'pendiente_aprobacion',
'aprobada',
'rechazada',
'publicada'
));
comment on column public.creative_pipeline.status is
'Flujo unificado: borrador → revision_agencia → pendiente_aprobacion → aprobada|rechazada → publicada';
-- ─── creatives (Ads) ────────────────────────────────────────────────────────
alter table public.creatives drop constraint if exists creatives_status_check;
-- Legacy EN → ES canónico
update public.creatives set status = 'borrador' where status = 'draft';
update public.creatives set status = 'pendiente_aprobacion' where status = 'in_review';
update public.creatives set status = 'aprobada' where status = 'approved';
update public.creatives set status = 'rechazada' where status = 'rejected';
alter table public.creatives
add constraint creatives_status_check
check (status in (
'borrador',
'revision_agencia',
'pendiente_aprobacion',
'aprobada',
'rechazada',
'publicada',
'fatigada',
'retirada'
));
comment on column public.creatives.status is
'Flujo unificado + extras Ads (fatigada, retirada). revision_agencia = validación interna antes de enviar al cliente.';

View File

@@ -1,9 +1,7 @@
-- Creative pipeline: producción interna de creatividades (Blue Parrot y resto
-- de clientes) separada de `creatives` (que es el repositorio de anuncios
-- Meta/Google ya aprobados). Aquí vive el flujo editorial completo:
-- Propuesta -> En diseño -> Revisión interna -> Aprobado / Rechazado -> Publicado
-- Visible también para el cliente en /dashboard/panel-cliente (RLS por tenant).
-- Idempotente.
-- Creative pipeline: producción RRSS separada de `creatives` (Ads Meta).
-- Flujo unificado (ver sql/approval_status_unify.sql):
-- borrador → revision_agencia → pendiente_aprobacion → aprobada|rechazada → publicada
-- Cliente solo ve desde pendiente_aprobacion. Idempotente.
create table if not exists public.creative_pipeline (
id uuid primary key default gen_random_uuid(),
@@ -19,10 +17,10 @@ create table if not exists public.creative_pipeline (
-- mes/calendario al que pertenece la pieza (agrupación en el board)
month text, -- 'YYYY-MM'
status text not null default 'propuesta'
status text not null default 'borrador'
check (status in (
'propuesta', 'en_diseno', 'revision_interna',
'aprobado', 'rechazado', 'publicado'
'borrador', 'revision_agencia', 'pendiente_aprobacion',
'aprobada', 'rechazada', 'publicada'
)),
-- portada (todas las piezas tienen una)

View File

@@ -1,6 +1,6 @@
-- Agency-only scheduling for editorial creativities.
-- aprobado + scheduled_at → cron publishes IG/FB; status becomes publicado.
-- Idempotent.
-- aprobada + scheduled_at → cron publishes IG/FB; status becomes publicada.
-- Idempotent. (Estados canónicos: sql/approval_status_unify.sql)
alter table public.creative_pipeline
add column if not exists scheduled_at timestamptz;
@@ -38,7 +38,7 @@ alter table public.creative_pipeline
create index if not exists creative_pipeline_due_publish_idx
on public.creative_pipeline (tenant_id, scheduled_at)
where status = 'aprobado' and publish_status in ('idle', 'queued', 'failed');
where status = 'aprobada' and publish_status in ('idle', 'queued', 'failed');
create index if not exists creative_pipeline_scheduled_at_idx
on public.creative_pipeline (tenant_id, scheduled_at)

View File

@@ -70,7 +70,7 @@ alter table public.creatives add constraint creatives_meta_ad_id_key unique (met
-- Enforce check constraints from brief
alter table public.creatives add constraint creatives_status_check
check (status in ('borrador','pendiente_aprobacion','aprobada','rechazada','publicada','fatigada','retirada','draft','in_review','approved','rejected'));
check (status in ('borrador','revision_agencia','pendiente_aprobacion','aprobada','rechazada','publicada','fatigada','retirada'));
alter table public.creatives add constraint creatives_format_check
check (format in ('estatico','carrusel','video','image','carousel','reel','story','rsa','pmax','pmax_landscape','pmax_square','pmax_portrait','pmax_vertical','pmax_logo','youtube','other'));

View File

@@ -0,0 +1,8 @@
-- Opcional: permite reason 'copy_v2' además de fatiga/calendario/nueva_campana/manual.
-- Idempotente. Si no se aplica, el código usa reason='manual' + brief.copy_v2.
alter table public.generation_requests drop constraint if exists generation_requests_reason_check;
alter table public.generation_requests
add constraint generation_requests_reason_check
check (reason in ('fatiga', 'calendario', 'nueva_campana', 'manual', 'copy_v2'));