feat(creatives): task 1 - migration, models and seed for creatives module
This commit is contained in:
185
src/lib/creatives-types.ts
Normal file
185
src/lib/creatives-types.ts
Normal file
@@ -0,0 +1,185 @@
|
||||
/**
|
||||
* Tipos y Modelos de datos para el módulo Creatividades (CREATIVOS_BRIEF.md)
|
||||
* Todas las entidades se estructuran con `tenant_id` (multi-tenant obligatorio).
|
||||
*/
|
||||
|
||||
export type CreativeFormat =
|
||||
| 'estatico'
|
||||
| 'carrusel'
|
||||
| 'video'
|
||||
| 'image'
|
||||
| 'carousel'
|
||||
| 'reel'
|
||||
| 'story'
|
||||
| 'rsa'
|
||||
| 'pmax'
|
||||
| 'pmax_landscape'
|
||||
| 'pmax_square'
|
||||
| 'pmax_portrait'
|
||||
| 'pmax_vertical'
|
||||
| 'pmax_logo'
|
||||
| 'youtube'
|
||||
| 'other';
|
||||
|
||||
export type CreativeStatus =
|
||||
| 'borrador'
|
||||
| 'pendiente_aprobacion'
|
||||
| 'aprobada'
|
||||
| 'rechazada'
|
||||
| 'publicada'
|
||||
| 'fatigada'
|
||||
| 'retirada'
|
||||
| 'draft'
|
||||
| 'in_review'
|
||||
| 'approved'
|
||||
| 'rejected';
|
||||
|
||||
export type CreativeVisibility = 'client' | 'agency';
|
||||
|
||||
export type CreativeCreatedBy = 'agency' | 'claude' | 'client';
|
||||
|
||||
export interface Creative {
|
||||
id: string;
|
||||
tenant_id: string;
|
||||
campaign_name: string | null;
|
||||
adset_id: string | null;
|
||||
meta_ad_id: string | null;
|
||||
format: CreativeFormat;
|
||||
angle: string | null;
|
||||
hook: string | null;
|
||||
primary_text: string | null;
|
||||
headline: string | null;
|
||||
cta: string | null;
|
||||
asset_url: string | null;
|
||||
thumbnail_url: string | null;
|
||||
status: CreativeStatus;
|
||||
visibility: CreativeVisibility;
|
||||
parent_id: string | null;
|
||||
generation_request_id: string | null;
|
||||
created_by: CreativeCreatedBy | string;
|
||||
created_at: string;
|
||||
updated_at: string;
|
||||
|
||||
// Campos relacionales opcionales al consultar con joins
|
||||
parent?: Creative | null;
|
||||
metrics_daily?: CreativeMetricsDaily[];
|
||||
}
|
||||
|
||||
export interface CreativeMetricsDaily {
|
||||
id: string;
|
||||
tenant_id: string;
|
||||
creative_id: string;
|
||||
meta_ad_id: string;
|
||||
date: string;
|
||||
impressions: number;
|
||||
reach: number;
|
||||
frequency: number;
|
||||
clicks: number;
|
||||
ctr: number;
|
||||
cpm: number;
|
||||
cpc: number;
|
||||
spend: number;
|
||||
results: number;
|
||||
cpa: number | null;
|
||||
raw?: Record<string, unknown> | null;
|
||||
created_at: string;
|
||||
}
|
||||
|
||||
export interface FatigueRules {
|
||||
id: string;
|
||||
tenant_id: string;
|
||||
lookback_days: number;
|
||||
min_impressions: number;
|
||||
max_frequency: number;
|
||||
ctr_drop_pct: number;
|
||||
cpa_rise_pct: number;
|
||||
signals_required: number;
|
||||
auto_request_relief: boolean;
|
||||
updated_at: string;
|
||||
}
|
||||
|
||||
export type GenerationRequestReason = 'fatiga' | 'calendario' | 'nueva_campana' | 'manual';
|
||||
export type GenerationRequestStatus = 'pendiente' | 'en_proceso' | 'completada' | 'fallida';
|
||||
|
||||
export interface GenerationRequestBrief {
|
||||
tenant_id: string;
|
||||
client_id?: string; // alias compatible si n8n lo envía
|
||||
client_slug: string;
|
||||
reason: GenerationRequestReason;
|
||||
source_creative_id?: string | null;
|
||||
format: 'estatico' | 'carrusel' | 'video';
|
||||
aspect_ratio?: string;
|
||||
variants_requested: number;
|
||||
avoid_angles?: string[];
|
||||
campaign_name?: string | null;
|
||||
adset_id?: string | null;
|
||||
language?: string;
|
||||
deadline?: string;
|
||||
}
|
||||
|
||||
export interface GenerationRequestResult {
|
||||
creatives: string[];
|
||||
notes?: string;
|
||||
skills_used?: string[];
|
||||
}
|
||||
|
||||
export interface GenerationRequest {
|
||||
id: string;
|
||||
tenant_id: string;
|
||||
reason: GenerationRequestReason;
|
||||
source_creative_id: string | null;
|
||||
brief: GenerationRequestBrief;
|
||||
status: GenerationRequestStatus;
|
||||
result: GenerationRequestResult | null;
|
||||
cost_estimate: Record<string, unknown> | null;
|
||||
error: string | null;
|
||||
requested_at: string;
|
||||
completed_at: string | null;
|
||||
}
|
||||
|
||||
export type ApprovalActorRole = 'client' | 'agency';
|
||||
export type ApprovalDecision = 'aprobada' | 'rechazada';
|
||||
export type ApprovalChannel = 'app' | 'slack';
|
||||
|
||||
export interface Approval {
|
||||
id: string;
|
||||
tenant_id: string;
|
||||
creative_id: string;
|
||||
user_id: string | null;
|
||||
actor_role: ApprovalActorRole;
|
||||
decision: ApprovalDecision;
|
||||
comment: string | null;
|
||||
channel: ApprovalChannel;
|
||||
created_at: string;
|
||||
}
|
||||
|
||||
export type CreativeEventType =
|
||||
| 'status_change'
|
||||
| 'metrics_ingested'
|
||||
| 'fatigue_detected'
|
||||
| 'generation_requested'
|
||||
| 'published'
|
||||
| 'error';
|
||||
|
||||
export interface CreativeEvent {
|
||||
id: string;
|
||||
tenant_id: string;
|
||||
creative_id: string | null;
|
||||
event_type: CreativeEventType | string;
|
||||
actor: string;
|
||||
from_status: CreativeStatus | null;
|
||||
to_status: CreativeStatus | null;
|
||||
payload: Record<string, unknown> | null;
|
||||
visibility: CreativeVisibility;
|
||||
created_at: string;
|
||||
}
|
||||
|
||||
export interface TenantWithCreativesMeta {
|
||||
id: string;
|
||||
name: string;
|
||||
slug: string;
|
||||
meta_ad_account_id?: string | null;
|
||||
slack_channel_id?: string | null;
|
||||
drive_folder_id?: string | null;
|
||||
creatives_enabled: boolean;
|
||||
}
|
||||
Reference in New Issue
Block a user