# US-INV-012: Recibir Notificaciones

## Metadata

| Campo | Valor |
|-------|-------|
| **ID** | US-INV-012 |
| **Épica** | OQI-004 - Cuentas de Inversión |
| **Módulo** | investment |
| **Prioridad** | P2 |
| **Story Points** | 3 |
| **Sprint** | Sprint 7 |
| **Estado** | Pendiente |
| **Asignado a** | Por asignar |

---

## Historia de Usuario

**Como** inversor,
**quiero** recibir notificaciones sobre eventos importantes de mi cuenta,
**para** estar informado en tiempo real sobre depósitos, retiros, distribuciones y actividad del agente.

## Descripción Detallada

El usuario debe poder configurar y recibir notificaciones por diferentes canales (email, push, in-app) sobre eventos clave: depósito completado, retiro procesado, distribución mensual, grandes ganancias/pérdidas, alertas de rendimiento, y más. Debe poder personalizar qué notificaciones recibir y por qué canal.

## Mockups/Wireframes

```
┌─────────────────────────────────────────────────────────────────┐
│                    CONFIGURACIÓN DE NOTIFICACIONES               │
├─────────────────────────────────────────────────────────────────┤
│                                                                  │
│  Elige cómo quieres recibir notificaciones:                     │
│                                                                  │
│  ┌──────────────────────────────────────────────────────────┐  │
│  │ Tipo de Notificación      │ Email │ Push │ In-App       │  │
│  ├──────────────────────────────────────────────────────────┤  │
│  │ 💰 Depósito completado     │  [x]  │ [x]  │  [x]         │  │
│  ├──────────────────────────────────────────────────────────┤  │
│  │ 💸 Retiro procesado        │  [x]  │ [x]  │  [x]         │  │
│  ├──────────────────────────────────────────────────────────┤  │
│  │ 📊 Distribución mensual    │  [x]  │ [x]  │  [x]         │  │
│  ├──────────────────────────────────────────────────────────┤  │
│  │ 🎉 Ganancia grande (>5%)   │  [x]  │ [x]  │  [x]         │  │
│  ├──────────────────────────────────────────────────────────┤  │
│  │ ⚠️ Pérdida importante (>3%)│  [x]  │ [x]  │  [x]         │  │
│  ├──────────────────────────────────────────────────────────┤  │
│  │ 📈 Nuevo récord de balance │  [x]  │ [ ]  │  [x]         │  │
│  ├──────────────────────────────────────────────────────────┤  │
│  │ 🤖 Agente abrió posición   │  [ ]  │ [ ]  │  [x]         │  │
│  ├──────────────────────────────────────────────────────────┤  │
│  │ 🤖 Agente cerró posición   │  [ ]  │ [ ]  │  [x]         │  │
│  ├──────────────────────────────────────────────────────────┤  │
│  │ 📉 Drawdown alcanzó límite │  [x]  │ [x]  │  [x]         │  │
│  ├──────────────────────────────────────────────────────────┤  │
│  │ 📬 Resumen semanal         │  [x]  │ [ ]  │  [ ]         │  │
│  ├──────────────────────────────────────────────────────────┤  │
│  │ 🔔 Actualizaciones sistema │  [x]  │ [ ]  │  [x]         │  │
│  └──────────────────────────────────────────────────────────┘  │
│                                                                  │
│  ┌──────────────────────────────────────────────────────────┐  │
│  │  Horario de notificaciones push                          │   │
│  │  [x] Respetar horario (solo 9am - 9pm)                   │   │
│  │  [ ] Recibir en cualquier horario                        │   │
│  └──────────────────────────────────────────────────────────┘  │
│                                                                  │
│  [Guardar Preferencias]                                          │
│                                                                  │
│  ─────────────────────────────────────────────────────────────  │
│                                                                  │
│  NOTIFICACIONES RECIENTES                                        │
│                                                                  │
│  ┌──────────────────────────────────────────────────────────┐  │
│  │ 🎉 Ganancia importante                        Hace 2h     │  │
│  │ Tu agente Atlas generó +$125 en un trade (+5.2%)         │  │
│  └──────────────────────────────────────────────────────────┘  │
│                                                                  │
│  ┌──────────────────────────────────────────────────────────┐  │
│  │ 💰 Depósito completado                        Ayer        │  │
│  │ Tu depósito de $1,000 fue procesado exitosamente         │  │
│  └──────────────────────────────────────────────────────────┘  │
│                                                                  │
│  ┌──────────────────────────────────────────────────────────┐  │
│  │ 📊 Distribución mensual                    Hace 5 días    │  │
│  │ Ganaste $48 este mes (+4.8%)                             │  │
│  └──────────────────────────────────────────────────────────┘  │
│                                                                  │
│  [Ver todas las notificaciones →]                               │
│                                                                  │
└─────────────────────────────────────────────────────────────────┘
```

---

## Criterios de Aceptación

**Escenario 1: Configurar preferencias de notificaciones**
```gherkin
DADO que el usuario está en configuración de notificaciones
CUANDO marca "Email" para "Depósito completado"
Y desmarca "Push" para "Agente abrió posición"
Y hace click en "Guardar Preferencias"
ENTONCES se guardan las preferencias
Y se muestra confirmación "Preferencias guardadas"
Y las notificaciones futuras respetan la configuración
```

**Escenario 2: Recibir notificación de depósito**
```gherkin
DADO que el usuario tiene notificaciones de depósito activadas (email + push)
CUANDO se completa un depósito de $1,000
ENTONCES se envía email con asunto "Depósito completado - $1,000"
Y se envía notificación push
Y se crea notificación in-app
Y el contador de notificaciones se incrementa
```

**Escenario 3: Notificación de ganancia grande**
```gherkin
DADO que el agente cierra trade con ganancia de $125 (+5.2%)
Y supera el umbral de 5%
CUANDO se procesa el trade
ENTONCES se envía notificación "Ganancia importante"
Y incluye monto y porcentaje
Y link para ver detalle del trade
```

**Escenario 4: Ver notificaciones in-app**
```gherkin
DADO que el usuario tiene 5 notificaciones sin leer
CUANDO hace click en el icono de notificaciones
ENTONCES se abre panel lateral con lista
Y muestra las 5 notificaciones ordenadas por fecha
Y las más recientes están resaltadas
Y al hacer click en una, se marca como leída
```

**Escenario 5: Respetar horario de push**
```gherkin
DADO que el usuario tiene "Respetar horario" activado
Y son las 11pm (fuera de horario)
CUANDO ocurre un evento que genera notificación push
ENTONCES NO se envía push en ese momento
Y se envía al día siguiente a las 9am
Y las notificaciones in-app siguen funcionando normalmente
```

**Escenario 6: Resumen semanal por email**
```gherkin
DADO que es lunes a las 9am
Y el usuario tiene "Resumen semanal" activado
CUANDO se ejecuta el cron job de resúmenes
ENTONCES se envía email con resumen de la semana pasada
Y incluye: balance inicial/final, trades, rendimiento, top ganancias
```

**Escenario 7: Desactivar todas las notificaciones**
```gherkin
DADO que el usuario quiere pausar todas las notificaciones
CUANDO desmarca todos los checkboxes
Y guarda
ENTONCES NO se envían notificaciones de ningún tipo
Y se muestra advertencia "No recibirás notificaciones"
```

## Criterios Adicionales

- [ ] Badge de contador en icono de notificaciones
- [ ] Marcar todas como leídas con un click
- [ ] Eliminar notificaciones antiguas (>30 días)
- [ ] Notificaciones agrupadas ("3 trades cerrados hoy")
- [ ] Deep links desde notificaciones a secciones específicas

---

## Tareas Técnicas

**Database:**
- [ ] DB-INV-001: Tabla notifications.preferences (por usuario)
- [ ] DB-INV-002: Tabla notifications.notifications
- [ ] DB-INV-003: Índices en (user_id, read, created_at)

**Backend:**
- [ ] BE-INV-001: Endpoint GET /notifications/preferences
- [ ] BE-INV-002: Endpoint PUT /notifications/preferences
- [ ] BE-INV-003: Implementar NotificationService.send()
- [ ] BE-INV-004: Email notifications (Nodemailer/SendGrid)
- [ ] BE-INV-005: Push notifications (Firebase Cloud Messaging)
- [ ] BE-INV-006: Endpoint GET /notifications (lista)
- [ ] BE-INV-007: Endpoint PATCH /notifications/:id/read
- [ ] BE-INV-008: Endpoint PATCH /notifications/mark-all-read
- [ ] BE-INV-009: Cron job para resumen semanal
- [ ] BE-INV-010: Event emitter para disparar notificaciones
- [ ] BE-INV-011: Cleanup job para notificaciones antiguas

**Frontend:**
- [ ] FE-INV-001: Crear página NotificationsSettingsPage.tsx
- [ ] FE-INV-002: Crear componente NotificationPreferences.tsx
- [ ] FE-INV-003: Crear componente NotificationBell.tsx (header)
- [ ] FE-INV-004: Crear componente NotificationsList.tsx
- [ ] FE-INV-005: Crear componente NotificationItem.tsx
- [ ] FE-INV-006: Integrar Firebase SDK para push
- [ ] FE-INV-007: Solicitar permisos de notificaciones
- [ ] FE-INV-008: Implementar notificationsStore
- [ ] FE-INV-009: WebSocket para notificaciones en tiempo real

**Tests:**
- [ ] TEST-INV-001: Test guardado de preferencias
- [ ] TEST-INV-002: Test envío de emails
- [ ] TEST-INV-003: Test envío de push
- [ ] TEST-INV-004: Test horario de notificaciones
- [ ] TEST-INV-005: Test resumen semanal
- [ ] TEST-INV-006: Test E2E flujo completo

---

## Dependencias

**Depende de:**
- [ ] Firebase Cloud Messaging configurado
- [ ] Email service configurado (SendGrid/SES)

**Bloquea:**
- Ninguna

---

## Notas Técnicas

**Endpoints involucrados:**
| Método | Endpoint | Descripción |
|--------|----------|-------------|
| GET | /notifications/preferences | Obtener preferencias |
| PUT | /notifications/preferences | Guardar preferencias |
| GET | /notifications | Lista de notificaciones |
| PATCH | /notifications/:id/read | Marcar como leída |
| PATCH | /notifications/mark-all-read | Marcar todas |

**Entidades/Tablas:**

**notifications.preferences:**
```sql
CREATE TABLE notifications.preferences (
  user_id UUID PRIMARY KEY REFERENCES auth.users(id),
  deposit_completed_email BOOLEAN DEFAULT true,
  deposit_completed_push BOOLEAN DEFAULT true,
  deposit_completed_inapp BOOLEAN DEFAULT true,
  withdrawal_processed_email BOOLEAN DEFAULT true,
  withdrawal_processed_push BOOLEAN DEFAULT true,
  withdrawal_processed_inapp BOOLEAN DEFAULT true,
  monthly_distribution_email BOOLEAN DEFAULT true,
  monthly_distribution_push BOOLEAN DEFAULT true,
  monthly_distribution_inapp BOOLEAN DEFAULT true,
  large_profit_email BOOLEAN DEFAULT true,
  large_profit_push BOOLEAN DEFAULT true,
  large_profit_inapp BOOLEAN DEFAULT true,
  -- ... más tipos
  respect_quiet_hours BOOLEAN DEFAULT true,
  quiet_hours_start TIME DEFAULT '21:00',
  quiet_hours_end TIME DEFAULT '09:00',
  weekly_summary_email BOOLEAN DEFAULT true,
  updated_at TIMESTAMP DEFAULT NOW()
);
```

**notifications.notifications:**
```sql
CREATE TABLE notifications.notifications (
  id UUID PRIMARY KEY DEFAULT gen_random_uuid(),
  user_id UUID NOT NULL REFERENCES auth.users(id),
  account_id UUID REFERENCES investment.accounts(id),
  type VARCHAR(50) NOT NULL,
  title VARCHAR(200) NOT NULL,
  message TEXT NOT NULL,
  data JSONB,
  read BOOLEAN DEFAULT false,
  created_at TIMESTAMP DEFAULT NOW()
);
```

**Tipos de Notificación:**
```typescript
enum NotificationType {
  DEPOSIT_COMPLETED = 'deposit_completed',
  WITHDRAWAL_PROCESSED = 'withdrawal_processed',
  MONTHLY_DISTRIBUTION = 'monthly_distribution',
  LARGE_PROFIT = 'large_profit',
  SIGNIFICANT_LOSS = 'significant_loss',
  NEW_BALANCE_RECORD = 'new_balance_record',
  POSITION_OPENED = 'position_opened',
  POSITION_CLOSED = 'position_closed',
  DRAWDOWN_LIMIT = 'drawdown_limit',
  WEEKLY_SUMMARY = 'weekly_summary',
  SYSTEM_UPDATE = 'system_update'
}
```

**Response GET /notifications:**
```typescript
{
  notifications: [
    {
      id: "uuid",
      type: "large_profit",
      title: "Ganancia importante",
      message: "Tu agente Atlas generó +$125 en un trade (+5.2%)",
      data: {
        accountId: "uuid",
        tradeId: "uuid",
        amount: 125,
        percentage: 5.2
      },
      read: false,
      createdAt: "2025-12-05T08:30:00Z"
    }
  ],
  unreadCount: 3,
  pagination: {
    page: 1,
    total: 45
  }
}
```

**Lógica de Envío:**
```typescript
class NotificationService {
  async send(userId: string, type: NotificationType, data: any) {
    const prefs = await this.getPreferences(userId);

    // In-app (siempre)
    if (prefs[`${type}_inapp`]) {
      await this.createInAppNotification(userId, type, data);
    }

    // Email
    if (prefs[`${type}_email`]) {
      await this.sendEmail(userId, type, data);
    }

    // Push
    if (prefs[`${type}_push`]) {
      if (this.isWithinQuietHours(prefs) && prefs.respect_quiet_hours) {
        await this.schedulePushForLater(userId, type, data);
      } else {
        await this.sendPush(userId, type, data);
      }
    }
  }
}
```

**Email Templates:**
- Usar HTML templates con branding
- Incluir botones de acción (CTA)
- Link de unsubscribe al final

**Push Notifications:**
- Firebase Cloud Messaging (FCM)
- Solicitar permisos en frontend
- Guardar FCM token en DB
- Deeplinks a secciones específicas

**Umbrales para Alertas:**
- Ganancia grande: >5% en un trade
- Pérdida importante: >3% en un trade
- Drawdown límite: Alcanza 80% del max drawdown del producto

---

## Definition of Ready (DoR)

- [x] Historia claramente escrita
- [x] Criterios de aceptación definidos
- [x] Story points estimados
- [x] Dependencias identificadas
- [ ] Firebase configurado
- [ ] Email service configurado
- [ ] Diseño/mockup disponible
- [x] API spec disponible

## Definition of Done (DoD)

- [ ] Código implementado según criterios
- [ ] Tests unitarios escritos y pasando
- [ ] Tests de integración pasando
- [ ] Email templates creados
- [ ] Push notifications funcionando
- [ ] In-app notifications funcionando
- [ ] Preferencias guardándose correctamente
- [ ] Horario de quiet hours respetado
- [ ] Code review aprobado
- [ ] Documentación actualizada
- [ ] QA aprobado
- [ ] Desplegado en ambiente de pruebas

---

## Historial de Cambios

| Fecha | Cambio | Autor |
|-------|--------|-------|
| 2025-12-05 | Creación | Requirements-Analyst |

---

**Creada por:** Requirements-Analyst
**Fecha:** 2025-12-05
**Última actualización:** 2025-12-05
