353 lines
14 KiB
Markdown
353 lines
14 KiB
Markdown
# US-INV-008: Recibir Distribución de Utilidades
|
|
|
|
## Metadata
|
|
|
|
| Campo | Valor |
|
|
|-------|-------|
|
|
| **ID** | US-INV-008 |
|
|
| **Épica** | OQI-004 - Cuentas de Inversión |
|
|
| **Módulo** | investment |
|
|
| **Prioridad** | P1 |
|
|
| **Story Points** | 5 |
|
|
| **Sprint** | Sprint 6 |
|
|
| **Estado** | Pendiente |
|
|
| **Asignado a** | Por asignar |
|
|
|
|
---
|
|
|
|
## Historia de Usuario
|
|
|
|
**Como** inversor,
|
|
**quiero** recibir distribuciones automáticas de utilidades mensuales,
|
|
**para** obtener retornos periódicos de mi inversión sin tener que hacer nada manualmente.
|
|
|
|
## Descripción Detallada
|
|
|
|
El sistema debe ejecutar un proceso automático mensual (primer día de cada mes) que calcula las utilidades generadas por cada cuenta de inversión en el mes anterior, y distribuye las ganancias (o registra las pérdidas) actualizando el balance. Los usuarios deben recibir notificación de la distribución y poder ver el histórico.
|
|
|
|
## Mockups/Wireframes
|
|
|
|
```
|
|
┌─────────────────────────────────────────────────────────────────┐
|
|
│ DISTRIBUCIÓN DE UTILIDADES │
|
|
├─────────────────────────────────────────────────────────────────┤
|
|
│ │
|
|
│ 📬 Nueva Distribución Mensual - Noviembre 2025 │
|
|
│ │
|
|
│ ┌──────────────────────────────────────────────────────────┐ │
|
|
│ │ 🎉 ¡Felicidades! │ │
|
|
│ │ │ │
|
|
│ │ Tu agente Atlas generó utilidades en Noviembre 2025 │ │
|
|
│ │ │ │
|
|
│ │ Balance inicial (01 Nov): $1,000.00 │ │
|
|
│ │ Balance final (30 Nov): $1,048.00 │ │
|
|
│ │ ───────────────────────────── │ │
|
|
│ │ Utilidad del mes: +$48.00 (+4.8%) │ │
|
|
│ │ │ │
|
|
│ │ Nuevo balance: $1,048.00 │ │
|
|
│ └──────────────────────────────────────────────────────────┘ │
|
|
│ │
|
|
│ ┌──────────────────────────────────────────────────────────┐ │
|
|
│ │ 📊 Desglose del Mes │ │
|
|
│ │ │ │
|
|
│ │ Total trades: 28 │ │
|
|
│ │ Trades ganadores: 22 (78.6%) │ │
|
|
│ │ Trades perdedores: 6 (21.4%) │ │
|
|
│ │ │ │
|
|
│ │ Ganancia total trades: +$125.30 │ │
|
|
│ │ Pérdida total trades: -$45.20 │ │
|
|
│ │ Comisiones exchange: -$32.10 │ │
|
|
│ │ ───────────────────────────── │ │
|
|
│ │ Utilidad neta: +$48.00 │ │
|
|
│ └──────────────────────────────────────────────────────────┘ │
|
|
│ │
|
|
│ ┌──────────────────────────────────────────────────────────┐ │
|
|
│ │ 📈 Historial de Distribuciones │ │
|
|
│ │ │ │
|
|
│ │ Nov 2025: +$48.00 (+4.8%) 🟢 │ │
|
|
│ │ Oct 2025: +$32.00 (+3.2%) 🟢 │ │
|
|
│ │ Sep 2025: +$51.00 (+5.1%) 🟢 │ │
|
|
│ │ Ago 2025: +$29.00 (+2.9%) 🟢 │ │
|
|
│ │ Jul 2025: -$12.00 (-1.2%) 🔴 │ │
|
|
│ │ Jun 2025: +$63.00 (+6.3%) 🟢 │ │
|
|
│ │ │ │
|
|
│ │ [Ver historial completo →] │ │
|
|
│ └──────────────────────────────────────────────────────────┘ │
|
|
│ │
|
|
└─────────────────────────────────────────────────────────────────┘
|
|
```
|
|
|
|
---
|
|
|
|
## Criterios de Aceptación
|
|
|
|
**Escenario 1: Distribución mensual automática exitosa**
|
|
```gherkin
|
|
DADO que es el día 1 del mes a las 00:00 UTC
|
|
Y existen cuentas de inversión activas
|
|
CUANDO el cron job executeMonthlyDistribution() se ejecuta
|
|
ENTONCES para cada cuenta activa:
|
|
Y se calcula utilidad del mes anterior
|
|
Y se crea transacción tipo "distribution"
|
|
Y se actualiza balance de la cuenta
|
|
Y se envía email con resumen de distribución
|
|
Y se envía notificación push
|
|
Y se registra log de ejecución exitosa
|
|
```
|
|
|
|
**Escenario 2: Distribución con utilidad positiva**
|
|
```gherkin
|
|
DADO que la cuenta tuvo balance inicial $1,000
|
|
Y balance final $1,048
|
|
CUANDO se ejecuta distribución
|
|
ENTONCES se calcula utilidad = $48 (+4.8%)
|
|
Y se crea transacción con amount = 48, type = "distribution"
|
|
Y el nuevo balance es $1,048
|
|
Y se envía email "¡Ganaste $48 este mes!"
|
|
```
|
|
|
|
**Escenario 3: Distribución con pérdida**
|
|
```gherkin
|
|
DADO que la cuenta tuvo balance inicial $1,000
|
|
Y balance final $988
|
|
CUANDO se ejecuta distribución
|
|
ENTONCES se calcula pérdida = -$12 (-1.2%)
|
|
Y se crea transacción con amount = -12, type = "distribution"
|
|
Y el nuevo balance es $988
|
|
Y se envía email "Reporte mensual: -$12 este mes"
|
|
```
|
|
|
|
**Escenario 4: Cuenta sin actividad en el mes**
|
|
```gherkin
|
|
DADO que la cuenta no tuvo trades en el mes
|
|
Y el balance no cambió
|
|
CUANDO se ejecuta distribución
|
|
ENTONCES se registra utilidad = $0 (0%)
|
|
Y NO se crea transacción
|
|
Y NO se envía email
|
|
```
|
|
|
|
**Escenario 5: Ver historial de distribuciones**
|
|
```gherkin
|
|
DADO que el usuario tiene cuenta con 6 meses de historial
|
|
CUANDO navega a /investment/distributions/:accountId
|
|
ENTONCES se muestra lista de distribuciones mensuales
|
|
Y cada distribución muestra: mes, utilidad, porcentaje, desglose
|
|
Y se muestra gráfico de evolución
|
|
```
|
|
|
|
**Escenario 6: Cuenta cerrada durante el mes**
|
|
```gherkin
|
|
DADO que la cuenta se cerró el día 15 del mes
|
|
CUANDO se ejecuta distribución mensual
|
|
ENTONCES se calcula utilidad solo hasta día 15
|
|
Y se procesa distribución proporcional
|
|
Y se marca la cuenta como "final distribution"
|
|
```
|
|
|
|
## Criterios Adicionales
|
|
|
|
- [ ] Calcular métricas detalladas (win rate, total trades, etc.)
|
|
- [ ] Guardar snapshot del balance al inicio de cada mes
|
|
- [ ] Permitir re-ejecutar distribución si falla
|
|
- [ ] Dashboard de admin para monitorear distribuciones
|
|
- [ ] Alertas si alguna distribución falla
|
|
|
|
---
|
|
|
|
## Tareas Técnicas
|
|
|
|
**Database:**
|
|
- [ ] DB-INV-001: Tabla investment.distributions
|
|
- [ ] DB-INV-002: Tabla investment.monthly_snapshots
|
|
- [ ] DB-INV-003: Función PL/pgSQL para calcular utilidades
|
|
- [ ] DB-INV-004: Índices en (account_id, period)
|
|
|
|
**Backend:**
|
|
- [ ] BE-INV-001: Implementar DistributionService.executeMonthly()
|
|
- [ ] BE-INV-002: Implementar DistributionService.calculateProfit()
|
|
- [ ] BE-INV-003: Cron job (node-cron) ejecutar primer día de mes
|
|
- [ ] BE-INV-004: Endpoint GET /investment/accounts/:id/distributions
|
|
- [ ] BE-INV-005: Crear transacciones de distribución
|
|
- [ ] BE-INV-006: Enviar emails de distribución
|
|
- [ ] BE-INV-007: Endpoint POST /admin/distributions/rerun (manual)
|
|
- [ ] BE-INV-008: Logging y monitoreo de distribuciones
|
|
|
|
**Frontend:**
|
|
- [ ] FE-INV-001: Crear página DistributionsPage.tsx
|
|
- [ ] FE-INV-002: Crear componente DistributionCard.tsx
|
|
- [ ] FE-INV-003: Crear componente MonthlyBreakdown.tsx
|
|
- [ ] FE-INV-004: Crear componente DistributionHistory.tsx
|
|
- [ ] FE-INV-005: Notificación toast para nueva distribución
|
|
- [ ] FE-INV-006: Implementar distributionsStore
|
|
|
|
**Tests:**
|
|
- [ ] TEST-INV-001: Test cálculo de utilidades
|
|
- [ ] TEST-INV-002: Test cron job execution
|
|
- [ ] TEST-INV-003: Test distribución con pérdidas
|
|
- [ ] TEST-INV-004: Test cuenta cerrada mid-month
|
|
- [ ] TEST-INV-005: Test email sending
|
|
- [ ] TEST-INV-006: Test E2E flujo completo
|
|
|
|
---
|
|
|
|
## Dependencias
|
|
|
|
**Depende de:**
|
|
- [ ] US-INV-004: Ver dashboard portfolio - Estado: Pendiente
|
|
- [ ] US-INV-007: Ver transacciones - Estado: Pendiente
|
|
- [ ] Email service configurado
|
|
|
|
**Bloquea:**
|
|
- [ ] US-INV-011: Exportar reporte PDF
|
|
|
|
---
|
|
|
|
## Notas Técnicas
|
|
|
|
**Endpoints involucrados:**
|
|
| Método | Endpoint | Descripción |
|
|
|--------|----------|-------------|
|
|
| GET | /investment/accounts/:id/distributions | Lista de distribuciones |
|
|
| GET | /investment/distributions/:id | Detalle de distribución |
|
|
| POST | /admin/distributions/execute | Ejecutar manualmente |
|
|
|
|
**Entidades/Tablas:**
|
|
- `investment.distributions`: Registro de distribuciones
|
|
- `investment.monthly_snapshots`: Snapshots de inicio de mes
|
|
- `investment.transactions`: Transacciones de distribución
|
|
|
|
**Schema investment.distributions:**
|
|
```sql
|
|
CREATE TABLE investment.distributions (
|
|
id UUID PRIMARY KEY DEFAULT gen_random_uuid(),
|
|
account_id UUID NOT NULL REFERENCES investment.accounts(id),
|
|
period VARCHAR(7) NOT NULL, -- "2025-11"
|
|
start_date DATE NOT NULL,
|
|
end_date DATE NOT NULL,
|
|
opening_balance DECIMAL(15,2) NOT NULL,
|
|
closing_balance DECIMAL(15,2) NOT NULL,
|
|
profit_amount DECIMAL(15,2) NOT NULL,
|
|
profit_percentage DECIMAL(5,2) NOT NULL,
|
|
total_trades INTEGER NOT NULL,
|
|
winning_trades INTEGER NOT NULL,
|
|
losing_trades INTEGER NOT NULL,
|
|
total_gains DECIMAL(15,2) NOT NULL,
|
|
total_losses DECIMAL(15,2) NOT NULL,
|
|
total_fees DECIMAL(15,2) NOT NULL,
|
|
transaction_id UUID REFERENCES investment.transactions(id),
|
|
executed_at TIMESTAMP DEFAULT NOW(),
|
|
UNIQUE(account_id, period)
|
|
);
|
|
```
|
|
|
|
**Response GET /distributions:**
|
|
```typescript
|
|
{
|
|
distributions: [
|
|
{
|
|
id: "uuid",
|
|
accountId: "uuid",
|
|
period: "2025-11",
|
|
startDate: "2025-11-01",
|
|
endDate: "2025-11-30",
|
|
openingBalance: 1000,
|
|
closingBalance: 1048,
|
|
profitAmount: 48,
|
|
profitPercentage: 4.8,
|
|
breakdown: {
|
|
totalTrades: 28,
|
|
winningTrades: 22,
|
|
losingTrades: 6,
|
|
winRate: 78.6,
|
|
totalGains: 125.30,
|
|
totalLosses: -45.20,
|
|
totalFees: -32.10
|
|
},
|
|
executedAt: "2025-12-01T00:00:00Z"
|
|
}
|
|
]
|
|
}
|
|
```
|
|
|
|
**Cron Schedule:**
|
|
```javascript
|
|
// Ejecutar el día 1 de cada mes a las 00:00 UTC
|
|
cron.schedule('0 0 1 * *', async () => {
|
|
await DistributionService.executeMonthlyDistribution();
|
|
});
|
|
```
|
|
|
|
**Cálculo de Utilidad:**
|
|
```typescript
|
|
profit = closingBalance - openingBalance - depositsInMonth + withdrawalsInMonth
|
|
profitPercentage = (profit / openingBalance) * 100
|
|
```
|
|
|
|
**Email Template:**
|
|
```
|
|
Subject: 📊 Distribución Mensual - Noviembre 2025
|
|
|
|
Hola {userName},
|
|
|
|
¡Tu agente {agentName} completó otro mes de trading!
|
|
|
|
Resumen del Mes:
|
|
- Balance inicial: ${openingBalance}
|
|
- Balance final: ${closingBalance}
|
|
- Utilidad: ${profit} ({profitPercentage}%)
|
|
|
|
Estadísticas:
|
|
- Total trades: {totalTrades}
|
|
- Win rate: {winRate}%
|
|
|
|
[Ver detalle completo →]
|
|
```
|
|
|
|
**Manejo de Errores:**
|
|
- Si falla distribución para una cuenta, continuar con las demás
|
|
- Registrar error en tabla `distribution_errors`
|
|
- Enviar alerta a admin
|
|
- Permitir re-ejecución manual desde admin panel
|
|
|
|
---
|
|
|
|
## Definition of Ready (DoR)
|
|
|
|
- [x] Historia claramente escrita
|
|
- [x] Criterios de aceptación definidos
|
|
- [x] Story points estimados
|
|
- [x] Dependencias identificadas
|
|
- [x] Fórmula de cálculo definida
|
|
- [ ] Email templates diseñados
|
|
- [x] API spec disponible
|
|
|
|
## Definition of Done (DoD)
|
|
|
|
- [ ] Código implementado según criterios
|
|
- [ ] Tests unitarios escritos y pasando
|
|
- [ ] Tests de integración pasando
|
|
- [ ] Cron job configurado y testeado
|
|
- [ ] Email service funcionando
|
|
- [ ] Manejo de errores robusto
|
|
- [ ] Logging completo
|
|
- [ ] Code review aprobado
|
|
- [ ] Documentación actualizada
|
|
- [ ] Tested en staging con fecha simulada
|
|
- [ ] 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
|