# Campañas de Email — API Documentation

## Índice

1. [Conceptos](#conceptos)
2. [Autenticación](#autenticación)
3. [Endpoints](#endpoints)
   - [Listar historial de campañas](#1-listar-historial-de-campañas)
   - [Crear campaña](#2-crear-campaña)
   - [Progreso de campaña](#3-progreso-de-campaña-polling)
4. [Estados de campaña](#estados-de-campaña)
5. [Tipos de destinatarios](#tipos-de-destinatarios)
6. [Consideraciones de envío](#consideraciones-de-envío)

---

## Conceptos

Una **campaña de email** es un mensaje masivo enviado a un segmento de usuarios del sistema. Al crearse, la campaña queda en estado `pending` y se encola para procesamiento asíncrono. El worker de cola se encarga de enviar los correos de forma progresiva y actualizar el estado de la campaña.

**Flujo de estados:**

```
pending → processing → sent
```

---

## Autenticación

Todos los endpoints requieren autenticación de administrador mediante JWT.

```
Authorization: Bearer <token_admin>
```

---

## Endpoints

### 1. Listar historial de campañas

Devuelve todas las campañas ordenadas por más reciente primero.

```
GET /api/admin/email-campaign
```

**Headers**

| Header          | Valor              |
|-----------------|--------------------|
| Authorization   | Bearer \<token\>   |
| Accept          | application/json   |

**Respuesta exitosa `200`**

```json
{
  "status": true,
  "data": {
    "campaigns": [
      {
        "id": 3,
        "title": "Promo Junio — 2 meses al precio de 1",
        "body": "Este mes tenemos una promo especial...",
        "recipients_type": "active",
        "recipients_label": "Usuarios activos",
        "status": "sent",
        "status_label": "Enviada",
        "sent_count": 142,
        "sent_at": "2026-05-13T12:00:00+00:00",
        "created_at": "2026-05-13T11:55:00+00:00"
      },
      {
        "id": 2,
        "title": "Notificación de mantenimiento",
        "body": "El sistema estará en mantenimiento el...",
        "recipients_type": "all",
        "recipients_label": "Todos los usuarios",
        "status": "sent",
        "status_label": "Enviada",
        "sent_count": 310,
        "sent_at": "2026-05-10T09:00:00+00:00",
        "created_at": "2026-05-10T08:50:00+00:00"
      }
    ]
  }
}
```

---

### 2. Crear campaña

Crea una nueva campaña con estado `pending`. El cronjob (cada 30 minutos) la detecta automáticamente y dispara el envío. La respuesta es inmediata.

```
POST /api/admin/email-campaign
```

**Headers**

| Header          | Valor              |
|-----------------|--------------------|
| Authorization   | Bearer \<token\>   |
| Content-Type    | application/json   |
| Accept          | application/json   |

**Body**

```json
{
  "title": "Promo Junio — 2 meses al precio de 1",
  "body": "Hola!\n\nEste mes tenemos una promo especial para vos...",
  "recipients_type": "active"
}
```

| Campo             | Tipo   | Requerido | Descripción                                               |
|-------------------|--------|-----------|-----------------------------------------------------------|
| `title`           | string | Sí        | Asunto / título del email (máx. 255 caracteres)           |
| `body`            | string | Sí        | Cuerpo del mensaje. Se respeta el salto de línea (`\n`).  |
| `recipients_type` | string | Sí        | Segmento destino: `active`, `inactive` o `all`            |

**Respuesta exitosa `200`**

```json
{
  "status": true,
  "data": {
    "campaign": {
      "id": 4,
      "title": "Promo Junio — 2 meses al precio de 1",
      "body": "Hola!\n\nEste mes tenemos una promo especial para vos...",
      "recipients_type": "active",
      "recipients_label": "Usuarios activos",
      "status": "pending",
      "status_label": "Sin enviar",
      "total_recipients": 0,
      "sent_count": 0,
      "sent_at": null,
      "created_at": "2026-05-13T14:00:00+00:00"
    }
  }
}
```

**Respuesta de error `400`**

```json
{
  "status": false,
  "message": "El campo title es requerido."
}
```

---

### 3. Progreso de campaña (polling)

Endpoint ultra liviano diseñado para ser consultado cada ~5 segundos mientras una campaña está en proceso. Solo lee 4 columnas de una fila.

```
GET /api/admin/email-campaign/{id}/progress
```

**Headers**

| Header          | Valor              |
|-----------------|--------------------|
| Authorization   | Bearer \<token\>   |
| Accept          | application/json   |

**Respuesta exitosa `200`**

```json
{
  "status": true,
  "data": {
    "id": 4,
    "campaign_status": "processing",
    "total_recipients": 142,
    "sent_count": 87,
    "percentage": 61.3
  }
}
```

| Campo               | Descripción                                                              |
|---------------------|--------------------------------------------------------------------------|
| `campaign_status`   | `pending` / `processing` / `sent`                                        |
| `total_recipients`  | Total de usuarios que recibirán el email (calculado al inicio del envío). |
| `sent_count`        | Emails enviados exitosamente hasta el momento.                           |
| `percentage`        | `(sent_count / total_recipients) * 100`, redondeado a 1 decimal.        |

> Cuando `campaign_status` es `sent` y `percentage` es `100`, el front puede dejar de hacer polling.

**Respuesta `404`**

```json
{
  "status": false,
  "message": "Campaña no encontrada."
}
```

---

## Estados de campaña

| Valor        | Label        | Descripción                                                           |
|--------------|--------------|-----------------------------------------------------------------------|
| `pending`    | Sin enviar   | Campaña creada, aún no fue tomada por el worker de cola.              |
| `processing` | En proceso   | El worker está enviando los emails activamente.                       |
| `sent`       | Enviada      | Todos los emails fueron procesados. `sent_count` indica cuántos OK.   |

> **Nota:** Si el worker falla inesperadamente durante el envío, la campaña vuelve a estado `pending` para poder reintentarse (ver sección de consideraciones).

---

## Tipos de destinatarios

| Valor      | Label               | Descripción                                                        |
|------------|---------------------|--------------------------------------------------------------------|
| `active`   | Usuarios activos    | Usuarios con suscripción activa (`status_id = 2`).                 |
| `inactive` | Usuarios inactivos  | Usuarios sin suscripción activa (`status_id ≠ 2`).                 |
| `all`      | Todos los usuarios  | Todos los usuarios con email registrado.                           |

---

## Consideraciones de envío

### Flujo completo
1. El front hace `POST` → la campaña se guarda con `status: pending`.
2. El cronjob `campaigns:send-pending` corre cada **30 minutos** y detecta las campañas `pending`.
3. Despacha `SendCampaignJob` a la cola → el worker lo toma y cambia el estado a `processing`.
4. Por cada email enviado se incrementa `sent_count` en la DB (en tiempo real).
5. Al finalizar, `status` pasa a `sent` y se registra `sent_at`.

### Cola de workers
El sistema usa `QUEUE_CONNECTION=database`. Es necesario tener corriendo un worker:

```bash
php artisan queue:work --timeout=3600
```

### Tolerancia a errores individuales
Si falla el envío a un email en particular (dirección inválida, timeout del proveedor, etc.) el error se registra en el log y el proceso continúa con el siguiente usuario. `sent_count` refleja únicamente los envíos exitosos.

### Paginación recomendada (frontend)
El endpoint `GET` devuelve todas las campañas. Si el historial crece, se recomienda implementar paginación por parte del frontend usando los parámetros estándar de la UI (ej: items per page).

---

*Documentación generada para integración del frontend — Ukraine Gym Backend v1*
