412 lines
18 KiB
Markdown
412 lines
18 KiB
Markdown
# 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
|