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:
57
sql/approval_status_unify.sql
Normal file
57
sql/approval_status_unify.sql
Normal 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.';
|
||||
@@ -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)
|
||||
|
||||
@@ -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)
|
||||
|
||||
@@ -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'));
|
||||
|
||||
8
sql/generation_requests_copy_v2.sql
Normal file
8
sql/generation_requests_copy_v2.sql
Normal 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'));
|
||||
Reference in New Issue
Block a user