# OQI-004: Contratos de API - Cuentas de Inversión

**Módulo:** OQI-004 - Cuentas de Inversión
**Ubicación:** `apps/frontend/src/modules/investment/`
**Fecha:** 2026-01-25
**Status:** ESPECIFICACIÓN DE CONTRATOS

---

## 1. ENDPOINTS DOCUMENTADOS (10)

### 1.1 GET /investment/accounts/summary
**Resumen del Portafolio del Usuario**

| Parámetro | Tipo | Requerido | Descripción |
|-----------|------|----------|-------------|
| N/A | N/A | N/A | Sin parámetros |

**Headers Requeridos:**
```
Authorization: Bearer <JWT_TOKEN>
Content-Type: application/json
```

**Response 200 OK:**
```json
{
  "data": {
    "totalBalance": 50000.00,
    "totalEarnings": 5000.00,
    "totalDeposited": 45000.00,
    "totalWithdrawn": 0.00,
    "overallReturn": 5000.00,
    "overallReturnPercent": 11.11,
    "accounts": [
      {
        "id": "acc-001",
        "productId": "prod-001",
        "product": {
          "code": "atlas",
          "name": "Cuenta Rendimiento Objetivo",
          "riskProfile": "conservative"
        },
        "status": "active",
        "balance": 50000.00,
        "initialInvestment": 1000.00,
        "totalDeposited": 45000.00,
        "totalWithdrawn": 0.00,
        "totalEarnings": 5000.00,
        "unrealizedPnl": 500.00,
        "unrealizedPnlPercent": 1.00,
        "openedAt": "2025-12-15T10:30:00Z"
      }
    ]
  }
}
```

**Error 401 Unauthorized:**
```json
{ "error": "Invalid or missing token" }
```

**Usado Por:** `Portfolio.tsx`

---

### 1.2 GET /investment/products
**Listado de Productos de Inversión**

| Parámetro | Tipo | Requerido | Descripción |
|-----------|------|----------|-------------|
| N/A | N/A | N/A | Sin parámetros |

**Headers Requeridos:**
```
Content-Type: application/json
```

**Response 200 OK:**
```json
{
  "data": [
    {
      "id": "prod-001",
      "code": "atlas",
      "name": "Cuenta Rendimiento Objetivo",
      "description": "Objetivo de 5% mensual con estrategia conservadora",
      "riskProfile": "conservative",
      "targetReturnMin": 3,
      "targetReturnMax": 5,
      "maxDrawdown": 5,
      "minInvestment": 500,
      "managementFee": 1.5,
      "performanceFee": 15,
      "features": [
        "Rebalancing automático",
        "Distribuciones mensuales",
        "Acceso 24/7"
      ],
      "strategy": "Value Investing",
      "assets": [
        "Acciones",
        "Bonos",
        "Efectivo"
      ],
      "tradingFrequency": "Semanal"
    },
    {
      "id": "prod-002",
      "code": "orion",
      "name": "Cuenta Variable",
      "description": "Rendimiento variable con reparto 50/50",
      "riskProfile": "moderate",
      "targetReturnMin": 5,
      "targetReturnMax": 10,
      "maxDrawdown": 10,
      "minInvestment": 1000,
      "managementFee": 2.0,
      "performanceFee": 20,
      "features": [
        "Estrategia mixta",
        "Distribuciones mensuales",
        "Flexible"
      ],
      "strategy": "Growth + Value",
      "assets": [
        "Acciones",
        "Criptomonedas",
        "Derivados"
      ],
      "tradingFrequency": "Diaria"
    },
    {
      "id": "prod-003",
      "code": "nova",
      "name": "Cuenta Alta Volatilidad",
      "description": "Máximo rendimiento para agresivos",
      "riskProfile": "aggressive",
      "targetReturnMin": 10,
      "targetReturnMax": 50,
      "maxDrawdown": 20,
      "minInvestment": 5000,
      "managementFee": 3.0,
      "performanceFee": 30,
      "features": [
        "Estrategia especulativa",
        "Apalancamiento permitido",
        "Distribuciones trimestrales"
      ],
      "strategy": "Momentum + Technical",
      "assets": [
        "Criptomonedas",
        "Futuros",
        "Opciones"
      ],
      "tradingFrequency": "Intraday"
    }
  ]
}
```

**Usado Por:** `Products.tsx`

---

### 1.3 GET /investment/products/:productId
**Detalles de un Producto Específico**

| Parámetro | Tipo | Requerido | Descripción |
|-----------|------|----------|-------------|
| productId | path | Sí | ID del producto (ej: prod-001) |

**Response 200 OK:**
```json
{
  "data": {
    "id": "prod-001",
    "code": "atlas",
    "name": "Cuenta Rendimiento Objetivo",
    "description": "Gestión pasiva con rebalanceo automático...",
    "riskProfile": "conservative",
    "targetReturnMin": 3,
    "targetReturnMax": 5,
    "maxDrawdown": 5,
    "minInvestment": 500,
    "managementFee": 1.5,
    "performanceFee": 15,
    "features": [
      "Rebalancing automático",
      "Distribuciones mensuales",
      "Acceso 24/7",
      "Soporte 24/7"
    ],
    "strategy": "Value Investing",
    "assets": ["Acciones", "Bonos", "Efectivo"],
    "tradingFrequency": "Semanal",
    "historicalReturn": 4.5,
    "activeAccounts": 1250
  }
}
```

**Error 404 Not Found:**
```json
{ "error": "Product not found" }
```

**Usado Por:** `ProductDetail.tsx`

---

### 1.4 GET /investment/products/:productId/performance
**Histórico de Rendimiento del Producto**

| Parámetro | Tipo | Requerido | Descripción |
|-----------|------|----------|-------------|
| productId | path | Sí | ID del producto |
| period | query | No | 'week' \| 'month' \| '3months' \| 'year' (default: 'month') |

**Response 200 OK:**
```json
{
  "data": [
    {
      "date": "2026-01-01T00:00:00Z",
      "cumulativeReturn": 0.00
    },
    {
      "date": "2026-01-05T00:00:00Z",
      "cumulativeReturn": 0.015
    },
    {
      "date": "2026-01-10T00:00:00Z",
      "cumulativeReturn": 0.032
    },
    {
      "date": "2026-01-15T00:00:00Z",
      "cumulativeReturn": 0.048
    },
    {
      "date": "2026-01-20T00:00:00Z",
      "cumulativeReturn": 0.042
    },
    {
      "date": "2026-01-25T00:00:00Z",
      "cumulativeReturn": 0.045
    }
  ]
}
```

**Usado Por:** `ProductDetail.tsx`

---

### 1.5 GET /investment/accounts/:accountId
**Detalles Completos de una Cuenta de Inversión**

| Parámetro | Tipo | Requerido | Descripción |
|-----------|------|----------|-------------|
| accountId | path | Sí | ID de la cuenta |

**Headers Requeridos:**
```
Authorization: Bearer <JWT_TOKEN>
```

**Response 200 OK:**
```json
{
  "data": {
    "id": "acc-001",
    "accountNumber": "ACC-2025-001",
    "productId": "prod-001",
    "product": {
      "code": "atlas",
      "name": "Cuenta Rendimiento Objetivo",
      "riskProfile": "conservative"
    },
    "status": "active",
    "balance": 50000.00,
    "totalDeposited": 45000.00,
    "totalWithdrawn": 0.00,
    "totalEarnings": 5000.00,
    "initialInvestment": 1000.00,
    "unrealizedPnl": 500.00,
    "unrealizedPnlPercent": 1.00,
    "openedAt": "2025-12-15T10:30:00Z",
    "performanceHistory": [
      {
        "date": "2025-12-15T10:30:00Z",
        "balance": 1000.00,
        "pnl": 0.00
      },
      {
        "date": "2025-12-20T10:30:00Z",
        "balance": 1040.00,
        "pnl": 40.00
      },
      {
        "date": "2025-12-25T10:30:00Z",
        "balance": 1100.00,
        "pnl": 100.00
      }
    ],
    "recentTransactions": [
      {
        "id": "tx-001",
        "type": "deposit",
        "amount": 10000.00,
        "status": "completed",
        "createdAt": "2025-12-20T10:00:00Z",
        "balanceAfter": 11000.00
      }
    ],
    "recentDistributions": [
      {
        "id": "dist-001",
        "amount": 150.00,
        "rate": 0.0015,
        "distributedAt": "2025-12-31T23:59:59Z",
        "balanceAfter": 1150.00
      }
    ]
  }
}
```

**Error 403 Forbidden:**
```json
{ "error": "Account does not belong to user" }
```

**Usado Por:** `AccountDetail.tsx`

---

### 1.6 GET /investment/accounts/:accountId/transactions
**Historial de Transacciones de una Cuenta**

| Parámetro | Tipo | Requerido | Descripción |
|-----------|------|----------|-------------|
| accountId | path | Sí | ID de la cuenta |
| type | query | No | 'deposit' \| 'withdrawal' \| 'distribution' \| 'fee' \| 'adjustment' |
| limit | query | No | Número de registros (default: 50) |
| offset | query | No | Offset para paginación (default: 0) |

**Response 200 OK:**
```json
{
  "data": {
    "transactions": [
      {
        "id": "tx-001",
        "type": "deposit",
        "amount": 10000.00,
        "status": "completed",
        "createdAt": "2025-12-20T10:00:00Z",
        "description": "Initial deposit",
        "balanceAfter": 10000.00
      },
      {
        "id": "tx-002",
        "type": "distribution",
        "amount": 150.00,
        "status": "completed",
        "createdAt": "2025-12-31T23:59:59Z",
        "description": "Monthly distribution",
        "balanceAfter": 10150.00
      },
      {
        "id": "tx-003",
        "type": "fee",
        "amount": 15.00,
        "status": "completed",
        "createdAt": "2026-01-01T00:00:00Z",
        "description": "Management fee",
        "balanceAfter": 10135.00
      }
    ],
    "total": 150,
    "limit": 50,
    "offset": 0
  }
}
```

**Usado Por:** `AccountDetail.tsx`, `Transactions.tsx`

---

### 1.7 GET /investment/accounts/:accountId/withdrawals
**Solicitudes de Retiro de una Cuenta**

| Parámetro | Tipo | Requerido | Descripción |
|-----------|------|----------|-------------|
| accountId | path | Sí | ID de la cuenta |
| status | query | No | 'pending' \| 'approved' \| 'processing' \| 'completed' \| 'rejected' |

**Response 200 OK:**
```json
{
  "data": [
    {
      "id": "wd-001",
      "accountId": "acc-001",
      "amount": 5000.00,
      "status": "completed",
      "requestedAt": "2025-12-25T12:00:00Z",
      "processedAt": "2025-12-27T14:30:00Z",
      "bankInfo": {
        "bankName": "Chase Bank",
        "accountLast4": "1234"
      },
      "cryptoInfo": null,
      "rejectionReason": null
    },
    {
      "id": "wd-002",
      "accountId": "acc-001",
      "amount": 2000.00,
      "status": "pending",
      "requestedAt": "2026-01-20T10:15:00Z",
      "processedAt": null,
      "bankInfo": {
        "bankName": "Bank of America",
        "accountLast4": "5678"
      },
      "cryptoInfo": null,
      "rejectionReason": null
    }
  ]
}
```

**Usado Por:** `Withdrawals.tsx`

---

### 1.8 POST /investment/accounts/:accountId/deposits
**Crear Depósito en Cuenta de Inversión**

| Parámetro | Tipo | Requerido | Descripción |
|-----------|------|----------|-------------|
| accountId | path | Sí | ID de la cuenta |

**Headers Requeridos:**
```
Authorization: Bearer <JWT_TOKEN>
Content-Type: application/json
```

**Body Requerido:**
```json
{
  "amount": 10000.00,
  "paymentMethodId": "pm_123456",
  "description": "Additional investment deposit"
}
```

**Response 201 Created:**
```json
{
  "data": {
    "id": "tx-004",
    "transactionId": "txn_abc123",
    "type": "deposit",
    "amount": 10000.00,
    "status": "completed",
    "createdAt": "2026-01-25T15:30:00Z",
    "balanceAfter": 60000.00,
    "message": "Deposit processed successfully"
  }
}
```

**Error 400 Bad Request:**
```json
{
  "error": "Invalid amount or account",
  "details": {
    "amount": "Minimum deposit is $10"
  }
}
```

**Error 402 Payment Required:**
```json
{ "error": "Payment failed - insufficient funds" }
```

**Usado Por:** `DepositForm.tsx`

---

### 1.9 POST /investment/accounts/:accountId/withdrawals
**Solicitar Retiro de Cuenta de Inversión**

| Parámetro | Tipo | Requerido | Descripción |
|-----------|------|----------|-------------|
| accountId | path | Sí | ID de la cuenta |

**Headers Requeridos:**
```
Authorization: Bearer <JWT_TOKEN>
Content-Type: application/json
```

**Body Requerido:**
```json
{
  "amount": 5000.00,
  "method": "bank_transfer",
  "bankInfo": {
    "bankName": "Chase Bank",
    "accountNumber": "****1234",
    "routingNumber": "021000021",
    "accountHolderName": "John Doe"
  },
  "verificationCode": "123456"
}
```

**O para Crypto:**
```json
{
  "amount": 5000.00,
  "method": "crypto",
  "cryptoInfo": {
    "network": "ethereum",
    "address": "0x1234567890abcdef"
  },
  "verificationCode": "123456"
}
```

**Response 201 Created:**
```json
{
  "data": {
    "id": "wd-003",
    "accountId": "acc-001",
    "amount": 5000.00,
    "status": "pending",
    "requestedAt": "2026-01-25T15:45:00Z",
    "method": "bank_transfer",
    "message": "Withdrawal request submitted. Expected processing: 1-3 business days"
  }
}
```

**Error 400 Bad Request:**
```json
{
  "error": "Invalid withdrawal request",
  "details": {
    "amount": "Exceeds daily limit of $10,000",
    "insufficient": "Account balance too low"
  }
}
```

**Error 429 Too Many Requests:**
```json
{ "error": "Daily withdrawal limit exceeded" }
```

**Usado Por:** `WithdrawForm.tsx`

---

### 1.10 GET /investment/accounts/user/all
**Listar Todas las Cuentas del Usuario**

| Parámetro | Tipo | Requerido | Descripción |
|-----------|------|----------|-------------|
| N/A | N/A | N/A | Sin parámetros |

**Headers Requeridos:**
```
Authorization: Bearer <JWT_TOKEN>
```

**Response 200 OK:**
```json
{
  "data": [
    {
      "id": "acc-001",
      "accountNumber": "ACC-2025-001",
      "product": {
        "code": "atlas",
        "name": "Cuenta Rendimiento Objetivo"
      },
      "status": "active",
      "balance": 50000.00,
      "totalDeposited": 45000.00,
      "totalWithdrawn": 0.00,
      "totalEarnings": 5000.00,
      "openedAt": "2025-12-15T10:30:00Z"
    },
    {
      "id": "acc-002",
      "accountNumber": "ACC-2025-002",
      "product": {
        "code": "orion",
        "name": "Cuenta Variable"
      },
      "status": "active",
      "balance": 25000.00,
      "totalDeposited": 20000.00,
      "totalWithdrawn": 0.00,
      "totalEarnings": 5000.00,
      "openedAt": "2025-12-20T14:15:00Z"
    }
  ]
}
```

**Usado Por:** `Transactions.tsx`, `Portfolio.tsx`

---

## 2. PAYMENT API ENDPOINTS (Integración Stripe)

### 2.1 POST /payments/wallet/deposit
**Crear Intención de Pago para Depósito**

| Parámetro | Tipo | Requerido | Descripción |
|-----------|------|----------|-------------|
| N/A | N/A | N/A | Body JSON |

**Headers Requeridos:**
```
Authorization: Bearer <JWT_TOKEN>
Content-Type: application/json
```

**Body Requerido:**
```json
{
  "amount": 10000,
  "currency": "USD",
  "description": "Deposit to investment account ACC-2025-001",
  "metadata": {
    "accountId": "acc-001",
    "type": "investment_deposit"
  }
}
```

**Response 200 OK:**
```json
{
  "data": {
    "clientSecret": "pi_123456_secret_789",
    "transactionId": "txn_001",
    "status": "requires_action",
    "amount": 10000,
    "currency": "USD"
  }
}
```

**Usado Por:** `DepositForm.tsx`

---

## 3. TABLA COMPARATIVA DE CONTRATOS

| Endpoint | Método | Auth | Cache | Rate Limit | Timeout |
|----------|--------|------|-------|-----------|---------|
| /investment/accounts/summary | GET | JWT | 5min | 100/min | 30s |
| /investment/products | GET | N | 24h | 500/min | 10s |
| /investment/products/:id | GET | N | 24h | 500/min | 10s |
| /investment/products/:id/performance | GET | N | 1h | 300/min | 15s |
| /investment/accounts/:id | GET | JWT | 1min | 100/min | 20s |
| /investment/accounts/:id/transactions | GET | JWT | 5min | 100/min | 30s |
| /investment/accounts/:id/withdrawals | GET | JWT | 5min | 100/min | 30s |
| /investment/accounts/:id/deposits | POST | JWT | N | 50/min | 60s |
| /investment/accounts/:id/withdrawals | POST | JWT | N | 50/min | 60s |
| /investment/accounts/user/all | GET | JWT | 1min | 100/min | 20s |

---

## 4. CÓDIGOS DE ERROR ESTÁNDAR

| Código | Descripción | Ejemplo |
|--------|-------------|---------|
| 200 | OK - Solicitud exitosa | GET /investment/products |
| 201 | Created - Recurso creado | POST /investment/accounts/:id/deposits |
| 400 | Bad Request - Datos inválidos | amount < minInvestment |
| 401 | Unauthorized - Token inválido | Missing JWT header |
| 403 | Forbidden - Sin permisos | Account no pertenece al user |
| 404 | Not Found - Recurso inexistente | Product ID no existe |
| 429 | Too Many Requests - Rate limit | Demasiadas solicitudes |
| 500 | Server Error | Error en servidor |

---

## 5. FLUJOS DE AUTENTICACIÓN

### 5.1 Flujo Depósito
```
1. Usuario selecciona ProductDetail
2. Ingresa monto y datos tarjeta
3. DepositForm.tsx POST /payments/wallet/deposit
   → Response: clientSecret
4. stripe.confirmCardPayment(clientSecret)
5. Si exitoso: POST /investment/accounts/:id/deposits
6. Redirigir a Portfolio
```

### 5.2 Flujo Retiro
```
1. Usuario navega a AccountDetail
2. Click "Retirar" → WithdrawForm
3. Ingresa monto, método (bank/crypto)
4. Click "Continuar" → Verification step
5. Ingresa código 2FA
6. POST /investment/accounts/:id/withdrawals
7. Redirigir a Withdrawals page
```

### 5.3 Flujo de Carga de Datos
```
1. Portfolio.tsx monta
2. GET /investment/accounts/summary
3. Renderizar AccountRow para cada cuenta
4. Usuario click en cuenta
5. AccountDetail.tsx GET /investment/accounts/:id
6. Renderizar tabs + datos
```

---

## 6. VALIDACIONES Y REGLAS DE NEGOCIO

| Regla | Validación | Error |
|-------|-----------|-------|
| Depósito mínimo | amount >= $10 | "Minimum deposit is $10" |
| Depósito máximo | amount <= $100,000 | "Maximum deposit is $100,000" |
| Retiro mínimo | amount >= $50 | "Minimum withdrawal is $50" |
| Retiro máximo diario | total <= $10,000 | "Daily limit exceeded" |
| Retiro máximo cuenta | amount <= balance | "Insufficient funds" |
| 2FA requerido | verificationCode válido | "Invalid verification code" |
| Inversión mínima | amount >= product.minInvestment | "Below minimum investment" |

---

## 7. ESTADO DE IMPLEMENTACIÓN

| Endpoint | Frontend | Backend | DB | Status |
|----------|----------|---------|----|----|
| GET /investment/accounts/summary | ✅ | ✅ | ✅ | PROD |
| GET /investment/products | ✅ | ✅ | ✅ | PROD |
| GET /investment/products/:id | ✅ | ✅ | ✅ | PROD |
| GET /investment/products/:id/performance | ✅ | ✅ | ✅ | PROD |
| GET /investment/accounts/:id | ✅ | ✅ | ✅ | PROD |
| GET /investment/accounts/:id/transactions | ✅ | ✅ | ✅ | PROD |
| GET /investment/accounts/:id/withdrawals | ✅ | ✅ | ✅ | PROD |
| POST /investment/accounts/:id/deposits | ✅ | ✅ | ✅ | PROD |
| POST /investment/accounts/:id/withdrawals | ✅ | ✅ | ✅ | PROD |
| POST /payments/wallet/deposit | ✅ | ✅ | ✅ | PROD |

---

**Fecha de Documentación:** 2026-01-25
**Contratos Documentados:** 10
**Coverage:** 100%
**Próximo Paso:** Análisis de Gaps y Mejoras
