Modelo Campaign
Overview
services/api/src/models/Campaign.js define el modelo de persistencia de una campaña en MongoDB con Mongoose. El esquema guarda el nombre, el anuncio relacionado, el autor, el estado, el objetivo, el presupuesto, las métricas y notas libres. También enlaza la campaña con Listing, User y PaymentOrder mediante referencias explícitas en el esquema
[!NOTE] El esquema usa
timestamps: true, así que Mongoose agregacreatedAtyupdatedAtautomáticamente
How it works
flowchart TB
Campaign[Campaign]
CampaignSchema[CampaignSchema]
BudgetSchema[BudgetSchema]
MetricsSchema[MetricsSchema]
Listing[Listing]
User[User]
PaymentOrder[PaymentOrder]
Campaign --> CampaignSchema
CampaignSchema --> BudgetSchema
CampaignSchema --> MetricsSchema
CampaignSchema --> Listing
CampaignSchema --> User
CampaignSchema --> PaymentOrder
Campaign se registra con mongoose.model("Campaign", CampaignSchema). CampaignSchema combina campos simples, referencias y dos subesquemas embebidos. BudgetSchema guarda presupuesto, y MetricsSchema guarda métricas agregadas. El archivo no define métodos propios; todo el comportamiento proviene de Mongoose y de la configuración del esquema
Key components
Este archivo contiene cuatro piezas principales. Cada una participa en la estructura persistida de la campaña.
{
"title": "BudgetSchema",
"content": "Subesquema embebido que almacena el presupuesto total, el gasto acumulado y la moneda.",
"type": "class",
"filePath": "services/api/src/models/Campaign.js",
"badges": [
"public"
]
}
{
"title": "MetricsSchema",
"content": "Subesquema embebido que guarda impresiones, clics y leads de la campa\u00f1a.",
"type": "class",
"filePath": "services/api/src/models/Campaign.js",
"badges": [
"public"
]
}
{
"title": "CampaignSchema",
"content": "Esquema principal de la campa\u00f1a. Define campos, referencias, valores por defecto y restricciones.",
"type": "class",
"filePath": "services/api/src/models/Campaign.js",
"badges": [
"public"
]
}
{
"title": "Campaign",
"content": "Modelo de Mongoose exportado por defecto. Representa la colecci\u00f3n de campa\u00f1as en la base de datos.",
"type": "class",
"filePath": "services/api/src/models/Campaign.js",
"badges": [
"public"
]
}
Data & fields
La estructura combina campos obligatorios, opciones con valores por defecto y subdocumentos embebidos. Las referencias conectan la campaña con otras entidades del backend
[
{
"name": "name",
"type": "string",
"required": true,
"description": "Nombre visible de la campaña. Usa trim y no admite vacío."
},
{
"name": "listingId",
"type": "ObjectId ref Listing",
"required": true,
"description": "Referencia obligatoria al anuncio asociado."
},
{
"name": "createdBy",
"type": "ObjectId ref User",
"required": true,
"description": "Referencia obligatoria al usuario que creó la campaña."
},
{
"name": "status",
"type": "string",
"description": "Estado de la campaña. Valores permitidos: draft, active, paused, completed, cancelled. Valor por defecto: draft."
},
{
"name": "objective",
"type": "string",
"description": "Objetivo de la campaña. Valores permitidos: leads, visibility, calls, messages. Valor por defecto: leads."
},
{
"name": "startDate",
"type": "Date",
"description": "Fecha de inicio. Valor por defecto: null."
},
{
"name": "endDate",
"type": "Date",
"description": "Fecha de fin. Valor por defecto: null."
},
{
"name": "budget",
"type": "object",
"description": "Subdocumento embebido con datos del presupuesto. Usa BudgetSchema y se inicializa con un objeto vacío.",
"children": [
{
"name": "total",
"type": "number",
"description": "Presupuesto total. Valor por defecto: 0. No admite negativos."
},
{
"name": "spent",
"type": "number",
"description": "Monto gastado. Valor por defecto: 0. No admite negativos."
},
{
"name": "currency",
"type": "string",
"description": "Moneda del presupuesto. Valor por defecto: MXN. Aplica trim."
}
]
},
{
"name": "metrics",
"type": "object",
"description": "Subdocumento embebido con métricas acumuladas. Usa MetricsSchema y se inicializa con un objeto vacío.",
"children": [
{
"name": "impressions",
"type": "number",
"description": "Impresiones acumuladas. Valor por defecto: 0. No admite negativos."
},
{
"name": "clicks",
"type": "number",
"description": "Clics acumulados. Valor por defecto: 0. No admite negativos."
},
{
"name": "leads",
"type": "number",
"description": "Leads acumulados. Valor por defecto: 0. No admite negativos."
}
]
},
{
"name": "paymentOrderId",
"type": "ObjectId ref PaymentOrder",
"description": "Referencia opcional a la orden de pago relacionada. Valor por defecto: null."
},
{
"name": "notes",
"type": "string",
"description": "Notas libres de la campaña. Valor por defecto: cadena vacía. Aplica trim."
}
]
Campos automáticos
El esquema activa timestamps: true. Eso agrega estos campos administrados por Mongoose:
createdAt— fecha de creación automática del documento.updatedAt— fecha de última actualización automática del documento.
Behaviors
El archivo no define funciones personalizadas. Su comportamiento depende de las opciones del esquema y de Mongoose
new Schema(...)— construye la estructura de datos de la campaña.BudgetSchema— define el subdocumento de presupuesto sin_idinterno.MetricsSchema— define el subdocumento de métricas sin_idinterno.enumenstatus— limita el estado a cinco valores válidos.enumenobjective— limita el objetivo a cuatro valores válidos.min: 0— bloquea valores negativos en presupuesto y métricas.default— inicializa valores comodraft,leads,MXN,0ynull.trim: true— recortaname,currencyynotesantes de guardar.ref— declara relaciones conListing,UseryPaymentOrder.mongoose.model("Campaign", CampaignSchema)— registra el modelo para uso en el backend.
Workflows
El modelo participa en el flujo de creación y consulta de campañas. El contexto del repositorio lo conecta con el módulo de campañas y con la interfaz de backoffice
sequenceDiagram
participant UI as CampaignsPage
participant ROUTE as campaigns routes
participant VALID as validateCampaignPayload
participant MODEL as Campaign
participant DB as MongoDB
UI->>ROUTE: POST api campaigns
ROUTE->>VALID: validateCampaignPayload payload
VALID-->>ROUTE: valid or errors
ROUTE->>MODEL: create payload
MODEL->>DB: save campaign document
DB-->>MODEL: stored document
MODEL-->>ROUTE: new campaign
ROUTE-->>UI: 201 response with data
apps/backoffice-web/src/pages/CampaignsPage.jsx envía datos de campaña. services/api/src/modules/campaigns/campaigns.routes.js valida la carga y crea el documento con este modelo. El contexto también indica que campaigns.routes.js expone lista, creación, actualización, cambio de estado y eliminación fileciteturn0file4turn0file5
Gotchas & edge cases
[!WARNING]
statussolo aceptadraft,active,paused,completedycancelled. Cualquier otro valor falla en la validación del esquema fileciteturn0file2turn0file10
[!WARNING]
objectivesolo aceptaleads,visibility,callsymessages. Un valor fuera de esa lista no pasa la validación fileciteturn0file2turn0file10
[!CAUTION]
budget.total,budget.spent,metrics.impressions,metrics.clicksymetrics.leadsno admiten negativos. El esquema bloquea esos valores conmin: 0
[!NOTE]
startDateyendDateaceptannullpor defecto. También aceptan fechas válidas cuando se envían
[!IMPORTANT]
budgetymetricsson subdocumentos embebidos sin_idpropio. Esa configuración está definida explícitamente en sus esquemas internos
Related
services/api/src/modules/campaigns/campaigns.routes.js usa Campaign para operar sobre campañas. El contexto disponible muestra que también filtra por createdBy y protege la propiedad del registro fileciteturn0file4turn0file5
services/api/src/modules/campaigns/campaigns.validators.js valida campos como status, objective y budget según el contexto mostrado
apps/backoffice-web/src/pages/CampaignsPage.jsx consume este modelo desde la interfaz de backoffice para crear y consultar campañas
PaymentOrder aparece como referencia opcional mediante paymentOrderId. Eso conecta la campaña con el flujo de pago del backend