# ET-INV-001: Modelo de Datos Investment

**Epic:** OQI-004 Cuentas de Inversión
**Versión:** 1.0
**Fecha:** 2025-12-05
**Responsable:** Requirements-Analyst

---

## 1. Descripción

Define el modelo de datos completo para el schema `investment` en PostgreSQL 15+, incluyendo:
- Productos de inversión (agentes ML)
- Cuentas de inversión de usuarios
- Transacciones (depósitos, retiros, distribuciones)
- Solicitudes de retiro
- Performance diaria de cuentas
- Distribuciones mensuales de utilidades

---

## 2. Arquitectura de Base de Datos

```
┌─────────────────────────────────────────────────────────────────┐
│                     SCHEMA: investment                           │
├─────────────────────────────────────────────────────────────────┤
│                                                                   │
│  ┌──────────────┐         ┌─────────────────┐                   │
│  │   products   │◄────────│    accounts     │                   │
│  └──────────────┘         └─────────────────┘                   │
│         │                          │                             │
│         │                          ▼                             │
│         │                  ┌─────────────────┐                   │
│         │                  │  transactions   │                   │
│         │                  └─────────────────┘                   │
│         │                          │                             │
│         │                          ▼                             │
│         │                  ┌─────────────────┐                   │
│         └─────────────────►│ daily_performance│                  │
│                            └─────────────────┘                   │
│                                     │                             │
│                                     ▼                             │
│                            ┌─────────────────┐                   │
│                            │ distributions   │                   │
│                            └─────────────────┘                   │
│                                                                   │
│                            ┌──────────────────┐                  │
│                            │withdrawal_requests│                 │
│                            └──────────────────┘                  │
│                                                                   │
└─────────────────────────────────────────────────────────────────┘
```

---

## 3. Especificación de Tablas

### 3.1 Tabla: `products`

Productos de inversión basados en agentes ML.

```sql
CREATE TABLE investment.products (
    id UUID PRIMARY KEY DEFAULT gen_random_uuid(),

    -- Información básica
    name VARCHAR(100) NOT NULL,
    description TEXT,
    agent_type VARCHAR(50) NOT NULL, -- 'swing', 'day', 'scalping', 'arbitrage'

    -- Configuración financiera
    min_investment DECIMAL(15, 2) NOT NULL DEFAULT 100.00,
    max_investment DECIMAL(15, 2), -- NULL = sin límite
    performance_fee_percentage DECIMAL(5, 2) NOT NULL DEFAULT 20.00, -- 20%
    target_annual_return DECIMAL(5, 2), -- Estimado, opcional
    risk_level VARCHAR(20) NOT NULL, -- 'low', 'medium', 'high', 'very_high'

    -- ML Engine
    ml_agent_id VARCHAR(100) NOT NULL UNIQUE, -- ID del agente en ML Engine
    ml_config JSONB, -- Configuración específica del agente

    -- Estado
    status VARCHAR(20) NOT NULL DEFAULT 'active', -- 'active', 'paused', 'closed'
    is_accepting_new_investors BOOLEAN NOT NULL DEFAULT true,
    total_aum DECIMAL(15, 2) NOT NULL DEFAULT 0.00, -- Assets Under Management
    total_investors INTEGER NOT NULL DEFAULT 0,

    -- Metadata
    created_at TIMESTAMP WITH TIME ZONE NOT NULL DEFAULT NOW(),
    updated_at TIMESTAMP WITH TIME ZONE NOT NULL DEFAULT NOW(),

    -- Constraints
    CONSTRAINT chk_min_investment_positive CHECK (min_investment > 0),
    CONSTRAINT chk_max_investment_valid CHECK (max_investment IS NULL OR max_investment >= min_investment),
    CONSTRAINT chk_performance_fee_range CHECK (performance_fee_percentage >= 0 AND performance_fee_percentage <= 100),
    CONSTRAINT chk_risk_level CHECK (risk_level IN ('low', 'medium', 'high', 'very_high')),
    CONSTRAINT chk_status CHECK (status IN ('active', 'paused', 'closed'))
);

-- Índices
CREATE INDEX idx_products_agent_type ON investment.products(agent_type);
CREATE INDEX idx_products_status ON investment.products(status);
CREATE INDEX idx_products_ml_agent_id ON investment.products(ml_agent_id);

-- Trigger para updated_at
CREATE TRIGGER update_products_updated_at BEFORE UPDATE ON investment.products
    FOR EACH ROW EXECUTE FUNCTION update_updated_at_column();
```

### 3.2 Tabla: `accounts`

Cuentas de inversión de usuarios en productos específicos.

```sql
CREATE TABLE investment.accounts (
    id UUID PRIMARY KEY DEFAULT gen_random_uuid(),

    -- Relaciones
    user_id UUID NOT NULL REFERENCES auth.users(id) ON DELETE CASCADE,
    product_id UUID NOT NULL REFERENCES investment.products(id) ON DELETE RESTRICT,

    -- Balance y performance
    current_balance DECIMAL(15, 2) NOT NULL DEFAULT 0.00,
    initial_investment DECIMAL(15, 2) NOT NULL DEFAULT 0.00,
    total_deposited DECIMAL(15, 2) NOT NULL DEFAULT 0.00,
    total_withdrawn DECIMAL(15, 2) NOT NULL DEFAULT 0.00,
    total_profit_distributed DECIMAL(15, 2) NOT NULL DEFAULT 0.00,

    -- Performance
    total_return_percentage DECIMAL(10, 4), -- Retorno total %
    annualized_return_percentage DECIMAL(10, 4), -- Retorno anualizado %

    -- Estado
    status VARCHAR(20) NOT NULL DEFAULT 'active', -- 'active', 'paused', 'closed'
    opened_at TIMESTAMP WITH TIME ZONE NOT NULL DEFAULT NOW(),
    closed_at TIMESTAMP WITH TIME ZONE,

    -- Metadata
    created_at TIMESTAMP WITH TIME ZONE NOT NULL DEFAULT NOW(),
    updated_at TIMESTAMP WITH TIME ZONE NOT NULL DEFAULT NOW(),

    -- Constraints
    CONSTRAINT uq_user_product UNIQUE (user_id, product_id),
    CONSTRAINT chk_current_balance_positive CHECK (current_balance >= 0),
    CONSTRAINT chk_account_status CHECK (status IN ('active', 'paused', 'closed'))
);

-- Índices
CREATE INDEX idx_accounts_user_id ON investment.accounts(user_id);
CREATE INDEX idx_accounts_product_id ON investment.accounts(product_id);
CREATE INDEX idx_accounts_status ON investment.accounts(status);
CREATE INDEX idx_accounts_opened_at ON investment.accounts(opened_at DESC);

-- Trigger para updated_at
CREATE TRIGGER update_accounts_updated_at BEFORE UPDATE ON investment.accounts
    FOR EACH ROW EXECUTE FUNCTION update_updated_at_column();
```

### 3.3 Tabla: `transactions`

Registro de todas las transacciones de cuentas de inversión.

```sql
CREATE TABLE investment.transactions (
    id UUID PRIMARY KEY DEFAULT gen_random_uuid(),

    -- Relaciones
    account_id UUID NOT NULL REFERENCES investment.accounts(id) ON DELETE CASCADE,
    user_id UUID NOT NULL REFERENCES auth.users(id) ON DELETE CASCADE,

    -- Tipo y estado
    type VARCHAR(30) NOT NULL, -- 'deposit', 'withdrawal', 'profit_distribution', 'fee'
    status VARCHAR(20) NOT NULL DEFAULT 'pending', -- 'pending', 'completed', 'failed', 'cancelled'

    -- Montos
    amount DECIMAL(15, 2) NOT NULL,
    balance_before DECIMAL(15, 2) NOT NULL,
    balance_after DECIMAL(15, 2),

    -- Integración con payments
    payment_id UUID, -- Referencia a financial.payments para depósitos
    stripe_payment_intent_id VARCHAR(255),

    -- Retiros
    withdrawal_request_id UUID, -- Referencia a withdrawal_requests
    withdrawal_method VARCHAR(50), -- 'bank_transfer', 'stripe_payout'
    withdrawal_destination_id VARCHAR(255), -- bank_account_id o stripe_payout_id

    -- Distribuciones
    distribution_id UUID, -- Referencia a distributions
    distribution_period VARCHAR(20), -- '2025-01', '2025-02'

    -- Metadata
    notes TEXT,
    processed_at TIMESTAMP WITH TIME ZONE,
    created_at TIMESTAMP WITH TIME ZONE NOT NULL DEFAULT NOW(),

    -- Constraints
    CONSTRAINT chk_amount_positive CHECK (amount > 0),
    CONSTRAINT chk_transaction_type CHECK (type IN ('deposit', 'withdrawal', 'profit_distribution', 'fee')),
    CONSTRAINT chk_transaction_status CHECK (status IN ('pending', 'completed', 'failed', 'cancelled'))
);

-- Índices
CREATE INDEX idx_transactions_account_id ON investment.transactions(account_id);
CREATE INDEX idx_transactions_user_id ON investment.transactions(user_id);
CREATE INDEX idx_transactions_type ON investment.transactions(type);
CREATE INDEX idx_transactions_status ON investment.transactions(status);
CREATE INDEX idx_transactions_created_at ON investment.transactions(created_at DESC);
CREATE INDEX idx_transactions_payment_id ON investment.transactions(payment_id);
```

### 3.4 Tabla: `withdrawal_requests`

Solicitudes de retiro pendientes de aprobación.

```sql
CREATE TABLE investment.withdrawal_requests (
    id UUID PRIMARY KEY DEFAULT gen_random_uuid(),

    -- Relaciones
    account_id UUID NOT NULL REFERENCES investment.accounts(id) ON DELETE CASCADE,
    user_id UUID NOT NULL REFERENCES auth.users(id) ON DELETE CASCADE,

    -- Monto y método
    amount DECIMAL(15, 2) NOT NULL,
    withdrawal_method VARCHAR(50) NOT NULL, -- 'bank_transfer', 'stripe_payout'
    destination_details JSONB NOT NULL, -- { "bank_account": "...", "routing": "..." }

    -- Estado y procesamiento
    status VARCHAR(20) NOT NULL DEFAULT 'pending', -- 'pending', 'approved', 'rejected', 'completed', 'cancelled'
    requested_at TIMESTAMP WITH TIME ZONE NOT NULL DEFAULT NOW(),
    reviewed_at TIMESTAMP WITH TIME ZONE,
    reviewed_by UUID REFERENCES auth.users(id),
    processed_at TIMESTAMP WITH TIME ZONE,

    -- Razones
    rejection_reason TEXT,
    admin_notes TEXT,

    -- Referencia a transacción
    transaction_id UUID REFERENCES investment.transactions(id),

    -- Metadata
    created_at TIMESTAMP WITH TIME ZONE NOT NULL DEFAULT NOW(),
    updated_at TIMESTAMP WITH TIME ZONE NOT NULL DEFAULT NOW(),

    -- Constraints
    CONSTRAINT chk_withdrawal_amount_positive CHECK (amount > 0),
    CONSTRAINT chk_withdrawal_status CHECK (status IN ('pending', 'approved', 'rejected', 'completed', 'cancelled')),
    CONSTRAINT chk_withdrawal_method CHECK (withdrawal_method IN ('bank_transfer', 'stripe_payout'))
);

-- Índices
CREATE INDEX idx_withdrawal_requests_account_id ON investment.withdrawal_requests(account_id);
CREATE INDEX idx_withdrawal_requests_user_id ON investment.withdrawal_requests(user_id);
CREATE INDEX idx_withdrawal_requests_status ON investment.withdrawal_requests(status);
CREATE INDEX idx_withdrawal_requests_requested_at ON investment.withdrawal_requests(requested_at DESC);
```

### 3.5 Tabla: `daily_performance`

Registro diario del rendimiento de cada cuenta.

```sql
CREATE TABLE investment.daily_performance (
    id UUID PRIMARY KEY DEFAULT gen_random_uuid(),

    -- Relaciones
    account_id UUID NOT NULL REFERENCES investment.accounts(id) ON DELETE CASCADE,
    product_id UUID NOT NULL REFERENCES investment.products(id) ON DELETE CASCADE,

    -- Fecha
    date DATE NOT NULL,

    -- Valores del día
    opening_balance DECIMAL(15, 2) NOT NULL,
    closing_balance DECIMAL(15, 2) NOT NULL,
    daily_return DECIMAL(15, 2) NOT NULL, -- Ganancia/pérdida del día
    daily_return_percentage DECIMAL(10, 4),

    -- Métricas acumuladas
    cumulative_return DECIMAL(15, 2),
    cumulative_return_percentage DECIMAL(10, 4),

    -- Datos del agente ML
    trades_executed INTEGER DEFAULT 0,
    winning_trades INTEGER DEFAULT 0,
    losing_trades INTEGER DEFAULT 0,
    ml_agent_data JSONB, -- Datos adicionales del agente

    -- Metadata
    calculated_at TIMESTAMP WITH TIME ZONE NOT NULL DEFAULT NOW(),
    created_at TIMESTAMP WITH TIME ZONE NOT NULL DEFAULT NOW(),

    -- Constraints
    CONSTRAINT uq_account_date UNIQUE (account_id, date)
);

-- Índices
CREATE INDEX idx_daily_performance_account_id ON investment.daily_performance(account_id);
CREATE INDEX idx_daily_performance_product_id ON investment.daily_performance(product_id);
CREATE INDEX idx_daily_performance_date ON investment.daily_performance(date DESC);
CREATE INDEX idx_daily_performance_account_date ON investment.daily_performance(account_id, date DESC);
```

### 3.6 Tabla: `distributions`

Distribuciones mensuales de utilidades (performance fee).

```sql
CREATE TABLE investment.distributions (
    id UUID PRIMARY KEY DEFAULT gen_random_uuid(),

    -- Relaciones
    account_id UUID NOT NULL REFERENCES investment.accounts(id) ON DELETE CASCADE,
    product_id UUID NOT NULL REFERENCES investment.products(id) ON DELETE CASCADE,
    user_id UUID NOT NULL REFERENCES auth.users(id) ON DELETE CASCADE,

    -- Período
    period VARCHAR(20) NOT NULL, -- '2025-01', '2025-02'
    period_start DATE NOT NULL,
    period_end DATE NOT NULL,

    -- Cálculos
    opening_balance DECIMAL(15, 2) NOT NULL,
    closing_balance DECIMAL(15, 2) NOT NULL,
    gross_profit DECIMAL(15, 2) NOT NULL,
    performance_fee_percentage DECIMAL(5, 2) NOT NULL,
    performance_fee_amount DECIMAL(15, 2) NOT NULL,
    net_profit DECIMAL(15, 2) NOT NULL, -- gross_profit - performance_fee_amount

    -- Estado
    status VARCHAR(20) NOT NULL DEFAULT 'pending', -- 'pending', 'distributed', 'failed'
    distributed_at TIMESTAMP WITH TIME ZONE,

    -- Referencia a transacción
    transaction_id UUID REFERENCES investment.transactions(id),

    -- Metadata
    created_at TIMESTAMP WITH TIME ZONE NOT NULL DEFAULT NOW(),
    updated_at TIMESTAMP WITH TIME ZONE NOT NULL DEFAULT NOW(),

    -- Constraints
    CONSTRAINT uq_account_period UNIQUE (account_id, period),
    CONSTRAINT chk_distribution_status CHECK (status IN ('pending', 'distributed', 'failed')),
    CONSTRAINT chk_net_profit CHECK (net_profit >= 0)
);

-- Índices
CREATE INDEX idx_distributions_account_id ON investment.distributions(account_id);
CREATE INDEX idx_distributions_product_id ON investment.distributions(product_id);
CREATE INDEX idx_distributions_user_id ON investment.distributions(user_id);
CREATE INDEX idx_distributions_period ON investment.distributions(period);
CREATE INDEX idx_distributions_status ON investment.distributions(status);
```

---

## 4. Interfaces TypeScript

### 4.1 Types del Modelo

```typescript
// src/types/investment.types.ts

export type AgentType = 'swing' | 'day' | 'scalping' | 'arbitrage';
export type RiskLevel = 'low' | 'medium' | 'high' | 'very_high';
export type ProductStatus = 'active' | 'paused' | 'closed';
export type AccountStatus = 'active' | 'paused' | 'closed';
export type TransactionType = 'deposit' | 'withdrawal' | 'profit_distribution' | 'fee';
export type TransactionStatus = 'pending' | 'completed' | 'failed' | 'cancelled';
export type WithdrawalStatus = 'pending' | 'approved' | 'rejected' | 'completed' | 'cancelled';
export type WithdrawalMethod = 'bank_transfer' | 'stripe_payout';
export type DistributionStatus = 'pending' | 'distributed' | 'failed';

export interface Product {
  id: string;
  name: string;
  description: string | null;
  agent_type: AgentType;
  min_investment: number;
  max_investment: number | null;
  performance_fee_percentage: number;
  target_annual_return: number | null;
  risk_level: RiskLevel;
  ml_agent_id: string;
  ml_config: Record<string, any> | null;
  status: ProductStatus;
  is_accepting_new_investors: boolean;
  total_aum: number;
  total_investors: number;
  created_at: string;
  updated_at: string;
}

export interface Account {
  id: string;
  user_id: string;
  product_id: string;
  current_balance: number;
  initial_investment: number;
  total_deposited: number;
  total_withdrawn: number;
  total_profit_distributed: number;
  total_return_percentage: number | null;
  annualized_return_percentage: number | null;
  status: AccountStatus;
  opened_at: string;
  closed_at: string | null;
  created_at: string;
  updated_at: string;
}

export interface Transaction {
  id: string;
  account_id: string;
  user_id: string;
  type: TransactionType;
  status: TransactionStatus;
  amount: number;
  balance_before: number;
  balance_after: number | null;
  payment_id: string | null;
  stripe_payment_intent_id: string | null;
  withdrawal_request_id: string | null;
  withdrawal_method: WithdrawalMethod | null;
  withdrawal_destination_id: string | null;
  distribution_id: string | null;
  distribution_period: string | null;
  notes: string | null;
  processed_at: string | null;
  created_at: string;
}

export interface WithdrawalRequest {
  id: string;
  account_id: string;
  user_id: string;
  amount: number;
  withdrawal_method: WithdrawalMethod;
  destination_details: Record<string, any>;
  status: WithdrawalStatus;
  requested_at: string;
  reviewed_at: string | null;
  reviewed_by: string | null;
  processed_at: string | null;
  rejection_reason: string | null;
  admin_notes: string | null;
  transaction_id: string | null;
  created_at: string;
  updated_at: string;
}

export interface DailyPerformance {
  id: string;
  account_id: string;
  product_id: string;
  date: string;
  opening_balance: number;
  closing_balance: number;
  daily_return: number;
  daily_return_percentage: number | null;
  cumulative_return: number | null;
  cumulative_return_percentage: number | null;
  trades_executed: number;
  winning_trades: number;
  losing_trades: number;
  ml_agent_data: Record<string, any> | null;
  calculated_at: string;
  created_at: string;
}

export interface Distribution {
  id: string;
  account_id: string;
  product_id: string;
  user_id: string;
  period: string;
  period_start: string;
  period_end: string;
  opening_balance: number;
  closing_balance: number;
  gross_profit: number;
  performance_fee_percentage: number;
  performance_fee_amount: number;
  net_profit: number;
  status: DistributionStatus;
  distributed_at: string | null;
  transaction_id: string | null;
  created_at: string;
  updated_at: string;
}
```

### 4.2 DTOs para Creación

```typescript
// src/types/investment.dtos.ts

export interface CreateProductDto {
  name: string;
  description?: string;
  agent_type: AgentType;
  min_investment: number;
  max_investment?: number;
  performance_fee_percentage: number;
  target_annual_return?: number;
  risk_level: RiskLevel;
  ml_agent_id: string;
  ml_config?: Record<string, any>;
}

export interface CreateAccountDto {
  user_id: string;
  product_id: string;
  initial_investment: number;
}

export interface CreateTransactionDto {
  account_id: string;
  user_id: string;
  type: TransactionType;
  amount: number;
  payment_id?: string;
  stripe_payment_intent_id?: string;
  notes?: string;
}

export interface CreateWithdrawalRequestDto {
  account_id: string;
  user_id: string;
  amount: number;
  withdrawal_method: WithdrawalMethod;
  destination_details: Record<string, any>;
}
```

---

## 5. Funciones SQL Auxiliares

### 5.1 Función: `update_updated_at_column()`

```sql
CREATE OR REPLACE FUNCTION update_updated_at_column()
RETURNS TRIGGER AS $$
BEGIN
    NEW.updated_at = NOW();
    RETURN NEW;
END;
$$ LANGUAGE plpgsql;
```

### 5.2 Función: Actualizar AUM de producto

```sql
CREATE OR REPLACE FUNCTION update_product_aum()
RETURNS TRIGGER AS $$
BEGIN
    UPDATE investment.products
    SET total_aum = (
        SELECT COALESCE(SUM(current_balance), 0)
        FROM investment.accounts
        WHERE product_id = NEW.product_id
        AND status = 'active'
    )
    WHERE id = NEW.product_id;

    RETURN NEW;
END;
$$ LANGUAGE plpgsql;

CREATE TRIGGER trigger_update_product_aum
AFTER INSERT OR UPDATE OF current_balance ON investment.accounts
FOR EACH ROW
EXECUTE FUNCTION update_product_aum();
```

---

## 6. Scripts de Migración

### 6.1 Up Migration

```sql
-- migrations/20250101_create_investment_schema.up.sql

-- Crear schema
CREATE SCHEMA IF NOT EXISTS investment;

-- Habilitar extensiones necesarias
CREATE EXTENSION IF NOT EXISTS "uuid-ossp";

-- Crear función update_updated_at
CREATE OR REPLACE FUNCTION update_updated_at_column()
RETURNS TRIGGER AS $$
BEGIN
    NEW.updated_at = NOW();
    RETURN NEW;
END;
$$ LANGUAGE plpgsql;

-- Crear tablas (ver secciones 3.1 a 3.6)
-- ... (incluir todas las sentencias CREATE TABLE)

-- Crear funciones auxiliares
-- ... (incluir funciones de la sección 5)

COMMENT ON SCHEMA investment IS 'Schema para gestión de cuentas de inversión y productos ML';
```

### 6.2 Down Migration

```sql
-- migrations/20250101_create_investment_schema.down.sql

DROP SCHEMA IF EXISTS investment CASCADE;
DROP FUNCTION IF EXISTS update_updated_at_column() CASCADE;
```

---

## 7. Validaciones y Constraints

### 7.1 Reglas de Negocio Implementadas

1. **Productos:**
   - `min_investment` debe ser mayor a 0
   - `max_investment` debe ser mayor o igual a `min_investment`
   - `performance_fee_percentage` entre 0 y 100
   - Un usuario solo puede tener una cuenta por producto (`uq_user_product`)

2. **Cuentas:**
   - `current_balance` no puede ser negativo
   - No se puede eliminar un producto si tiene cuentas asociadas (`ON DELETE RESTRICT`)

3. **Transacciones:**
   - `amount` debe ser positivo
   - El tipo debe ser uno de los permitidos

4. **Retiros:**
   - Solo se permite `bank_transfer` o `stripe_payout`
   - Monto debe ser positivo y no exceder balance disponible

5. **Distribuciones:**
   - Una sola distribución por cuenta por período (`uq_account_period`)
   - `net_profit` no puede ser negativo

---

## 8. Seguridad

### 8.1 Row Level Security (RLS)

```sql
-- Habilitar RLS en todas las tablas
ALTER TABLE investment.products ENABLE ROW LEVEL SECURITY;
ALTER TABLE investment.accounts ENABLE ROW LEVEL SECURITY;
ALTER TABLE investment.transactions ENABLE ROW LEVEL SECURITY;
ALTER TABLE investment.withdrawal_requests ENABLE ROW LEVEL SECURITY;
ALTER TABLE investment.daily_performance ENABLE ROW LEVEL SECURITY;
ALTER TABLE investment.distributions ENABLE ROW LEVEL SECURITY;

-- Políticas para usuarios
CREATE POLICY users_view_products ON investment.products
    FOR SELECT USING (status = 'active');

CREATE POLICY users_view_own_accounts ON investment.accounts
    FOR SELECT USING (user_id = auth.uid());

CREATE POLICY users_view_own_transactions ON investment.transactions
    FOR SELECT USING (user_id = auth.uid());

CREATE POLICY users_view_own_withdrawals ON investment.withdrawal_requests
    FOR SELECT USING (user_id = auth.uid());

-- Políticas para admins (asumiendo rol 'admin')
CREATE POLICY admins_all_access ON investment.products
    FOR ALL USING (auth.jwt() ->> 'role' = 'admin');
```

---

## 9. Testing

### 9.1 Datos de Prueba

```sql
-- Seed data para testing
INSERT INTO investment.products (
    name, description, agent_type, min_investment,
    performance_fee_percentage, risk_level, ml_agent_id
) VALUES
(
    'Swing Trader Pro',
    'Agente de swing trading con estrategias de mediano plazo',
    'swing',
    500.00,
    20.00,
    'medium',
    'ml-agent-swing-001'
),
(
    'Day Trader Elite',
    'Trading intradía con alta frecuencia',
    'day',
    1000.00,
    25.00,
    'high',
    'ml-agent-day-001'
);
```

### 9.2 Tests de Integridad

```sql
-- Verificar constraints
DO $$
BEGIN
    -- Test: min_investment positivo
    BEGIN
        INSERT INTO investment.products (name, agent_type, min_investment, risk_level, ml_agent_id)
        VALUES ('Test', 'swing', -100, 'low', 'test-agent');
        RAISE EXCEPTION 'Should not allow negative min_investment';
    EXCEPTION WHEN check_violation THEN
        -- Expected
    END;

    -- Test: unique user_product
    BEGIN
        INSERT INTO investment.accounts (user_id, product_id)
        VALUES ('user-1', 'product-1');
        INSERT INTO investment.accounts (user_id, product_id)
        VALUES ('user-1', 'product-1');
        RAISE EXCEPTION 'Should not allow duplicate user-product';
    EXCEPTION WHEN unique_violation THEN
        -- Expected
    END;
END $$;
```

---

## 10. Dependencias

### 10.1 Dependencias de Schemas

- `auth.users`: Para relaciones de usuarios
- `financial.payments`: Para integración con pagos (opcional)

### 10.2 Extensiones PostgreSQL

- `uuid-ossp`: Generación de UUIDs
- `pg_trgm`: Para búsquedas de texto (opcional)

---

## 11. Configuración

### 11.1 Variables de Entorno

```bash
# Database
DATABASE_URL=postgresql://user:password@localhost:5432/orbiquant
DATABASE_POOL_MIN=2
DATABASE_POOL_MAX=10

# Investment Schema
INVESTMENT_DEFAULT_PERFORMANCE_FEE=20.00
INVESTMENT_MIN_WITHDRAWAL_AMOUNT=50.00
```

---

## 12. Mantenimiento

### 12.1 Índices y Performance

```sql
-- Analizar uso de índices
SELECT schemaname, tablename, indexname, idx_scan
FROM pg_stat_user_indexes
WHERE schemaname = 'investment'
ORDER BY idx_scan ASC;

-- Vacuum y analyze periódicos
VACUUM ANALYZE investment.daily_performance;
VACUUM ANALYZE investment.transactions;
```

### 12.2 Respaldos

- Backup diario de schema `investment`
- Retention: 30 días
- Point-in-time recovery habilitado

---

## 13. Referencias

- PostgreSQL 15 Documentation
- Schema de Stripe para payments
- ML Engine API para integración de agentes
