ML Engine Updates: - Updated BTCUSD with Polygon API data (2024-2025): 215,699 new records - Re-trained all ML models: Attention (R²: 0.223), Base, Metamodel (87.3% confidence) - Backtest results: +176.71R profit with aggressive_filter strategy Documentation Consolidation: - Created docs/99-analisis/_MAP.md index with 13 new analysis documents - Consolidated inventories: removed duplicates from orchestration/inventarios/ - Updated ML_INVENTORY.yml with BTCUSD metrics and training results - Added execution reports: FASE11-BTCUSD, correction issues, alignment validation Architecture & Integration: - Updated all module documentation with NEXUS v3.4 frontmatter - Fixed _MAP.md indexes across all folders - Updated orchestration plans and traces Files: 229 changed, 5064 insertions(+), 1872 deletions(-) 🤖 Generated with [Claude Code](https://claude.com/claude-code) Co-Authored-By: Claude Opus 4.5 <noreply@anthropic.com>
819 lines
26 KiB
Markdown
819 lines
26 KiB
Markdown
---
|
|
id: "ET-INV-001"
|
|
title: "Modelo de Datos Investment"
|
|
type: "Technical Specification"
|
|
status: "Done"
|
|
priority: "Alta"
|
|
epic: "OQI-004"
|
|
project: "trading-platform"
|
|
version: "1.0.0"
|
|
created_date: "2025-12-05"
|
|
updated_date: "2026-01-04"
|
|
---
|
|
|
|
# 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/trading
|
|
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
|