# RECOMENDACIONES DE MODELADO - Trading Platform **Tarea:** TASK-2026-02-05-ANALISIS-VALIDACION-MODELADO-BD **Fecha:** 2026-02-05 **Perfil:** Especialista en Base de Datos y Modelado de Datos --- ## R1. Consolidar Catalogos de Simbolos (PRIORIDAD ALTA) **Problema:** `trading.symbols` (UUID PK) y `market_data.tickers` (SERIAL PK) son catalogos paralelos del mismo concepto con PKs incompatibles. **Recomendacion:** 1. Designar `trading.symbols` como tabla maestra (ya usa UUID, mas campos) 2. Agregar campos ML de tickers a symbols: `is_ml_enabled`, `polygon_ticker`, `supported_timeframes` 3. Migrar `market_data.tickers` a vista o tabla dependiente con FK a `trading.symbols` 4. Actualizar todas las referencias de `market_data.tickers.id` (SERIAL) a usar `trading.symbols.id` (UUID) **Impacto:** Afecta ml schema, market_data schema, data-service Python **Esfuerzo:** 12h (4h analisis + 8h implementacion) --- ## R2. Ejecutar Migraciones de Enums (PRIORIDAD ALTA) **Problema:** Existen archivos de migracion para 2 de 3 conflictos, pero estan comentados y nunca se ejecutaron. **Hallazgo clave:** Ambos archivos de migracion existen pero son **solo documentacion** (SQL comentado). `public.trading_timeframe` ya fue creado en `00-global-types.sql` pero las tablas no fueron migradas. **Recomendacion por conflicto:** 1. **transaction_type (CONF-001, ALTA):** NO renombrar (breaking change). Mantener separados con calificacion de schema estricta. Los schemas son separados y sirven propositos distintos. Documentar la distincion en backend y enforcer `schema.enum` en todas las queries. 2. **timeframe (DUP-001, MEDIA):** `public.trading_timeframe` ya existe con 9 valores. Ejecutar migracion de columnas en 3 tablas: `trading.bots`, `trading.signals`, `trading.drawing_tools`. Non-breaking change (valores compatibles). Luego DROP tipos viejos. 3. **risk_profile (DUP-002, BAJA):** Valores identicos en ambos schemas. Opcional: crear `public.risk_profile` para consistencia. No es urgente. **Secuencia de ejecucion (solo timeframe - unico ejecutable sin riesgo):** ```sql -- Paso 1: Migrar trading.bots.timeframe ALTER TABLE trading.bots ADD COLUMN timeframe_new public.trading_timeframe; UPDATE trading.bots SET timeframe_new = timeframe::text::public.trading_timeframe; ALTER TABLE trading.bots DROP COLUMN timeframe; ALTER TABLE trading.bots RENAME COLUMN timeframe_new TO timeframe; -- Paso 2: Repetir para trading.signals y trading.drawing_tools -- Paso 3: DROP TYPE trading.timeframe; DROP TYPE market_data.timeframe; ``` --- ## R3. Agregar Foreign Keys Cross-Schema (PRIORIDAD ALTA) **Problema:** Relaciones logicas entre schemas no estan formalizadas con FK. **Recomendacion:** ### R3.1 investment.accounts -> financial.wallets ```sql ALTER TABLE investment.accounts ADD COLUMN wallet_id UUID REFERENCES financial.wallets(id); ``` Nota: La columna `wallet_id` ya existe en el DDL actual de `investment.accounts`. Verificar si el FK esta creado. ### R3.2 trading.bots -> financial.wallets ```sql ALTER TABLE trading.bots ADD COLUMN wallet_id UUID REFERENCES financial.wallets(id); ``` Para vincular capital de bots con wallets formalmente. ### R3.3 market_data.tickers -> trading.symbols ```sql ALTER TABLE market_data.tickers ADD COLUMN symbol_id UUID REFERENCES trading.symbols(id); ``` Vincula catalogos hasta que se consoliden (R1). --- ## R4. Documentar feature_flags Schema (PRIORIDAD ALTA) **Problema:** Schema completo invisible para backend y documentacion. **Recomendacion:** 1. Agregar a CLAUDE.md del proyecto en la seccion de schemas 2. Crear entity `Flag` en backend 3. Crear servicio `FeatureFlagService` con cache Redis 4. Documentar tabla `flags` en docs/ con ET (especificacion tecnica) 5. Integrar en middleware de Express para feature gating **Patron sugerido:** ```typescript // Middleware const featureFlag = async (flagName: string) => { const flag = await featureFlagService.getFlag(flagName); return flag?.is_enabled ?? false; }; ``` --- ## R5. Estandarizar Nomenclatura (PRIORIDAD MEDIA) **Problema:** Inconsistencias en nombres de campos entre schemas. | Caso | Tabla A | Tabla B | Recomendacion | |------|---------|---------|---------------| | asset_type vs asset_class | market_data.tickers | trading.symbols | Usar `asset_class` | | strategy_type (VARCHAR) | trading.bots | - | Considerar FK a catalogo | | timeframe (multiples) | public, trading, market_data | - | Consolidar en 1 enum | --- ## R6. Crear Servicios para audit Schema (PRIORIDAD MEDIA) **Problema:** 7 tablas de audit sin ningun servicio backend (0% coherencia). **Recomendacion:** Crear un modulo audit con: 1. `AuditService` - queries sobre audit_logs, data_access_logs 2. `SecurityEventService` - queries sobre security_events 3. `TradingAuditService` - queries sobre trading_audit 4. `ComplianceService` - queries sobre compliance_logs 5. `AuditController` - endpoints admin-only con paginacion **Endpoints sugeridos:** ``` GET /api/admin/audit/logs?user_id=&event_type=&from=&to=&page=&limit= GET /api/admin/audit/security?severity=&from=&to= GET /api/admin/audit/trading?bot_id=&from=&to= GET /api/admin/audit/compliance?type=&status= GET /api/admin/audit/export?format=csv|json&from=&to= ``` --- ## R7. Patron de Soft Delete (PRIORIDAD BAJA) **Problema:** `financial.wallets` usa `ON DELETE RESTRICT` en FK a `auth.users`, lo que impide eliminar usuarios con wallet. **Recomendacion:** 1. Documentar como decision arquitectural (no es bug) 2. Implementar soft delete: agregar `deleted_at TIMESTAMPTZ` a `auth.users` 3. Actualizar queries para filtrar `WHERE deleted_at IS NULL` 4. Mantener RESTRICT para proteger integridad financiera --- ## R8. Indices Compuestos para Performance (PRIORIDAD BAJA) **Recomendacion de indices adicionales:** ```sql -- Alertas activas por usuario y simbolo (query frecuente) CREATE INDEX idx_price_alerts_user_symbol_active ON trading.price_alerts(user_id, symbol_id) WHERE status = 'active'; -- Predicciones recientes por simbolo y tipo CREATE INDEX idx_predictions_symbol_type_created ON ml.predictions(symbol, prediction_type, created_at DESC); -- Enrollments activos por usuario CREATE INDEX idx_enrollments_user_active ON education.enrollments(user_id) WHERE status IN ('active', 'in_progress'); -- OHLCV queries recientes CREATE INDEX idx_ohlcv_5m_recent ON market_data.ohlcv_5m(symbol, timestamp DESC); ``` --- ## R9. Considerar Particionamiento para Tablas de Alto Volumen (FUTURO) Las siguientes tablas pueden beneficiarse de particionamiento por fecha: | Tabla | Razon | Estrategia | |-------|-------|------------| | market_data.ohlcv_5m | Alto volumen (288 registros/dia/simbolo) | Range partition por mes | | market_data.ohlcv_15m | Alto volumen (96 registros/dia/simbolo) | Range partition por mes | | audit.audit_logs | Crecimiento continuo | Range partition por mes | | audit.api_request_logs | Alto volumen por request | Range partition por semana | --- ## Resumen de Prioridades | # | Recomendacion | Prioridad | Esfuerzo | Impacto | |---|---------------|-----------|----------|---------| | R1 | Consolidar catalogos simbolos | ALTA | 12h | Elimina duplicacion | | R2 | Ejecutar migraciones enums | ALTA | 5h | Elimina 3 conflictos | | R3 | Agregar FKs cross-schema | ALTA | 4h | Integridad referencial | | R4 | Documentar feature_flags | ALTA | 8h | Schema invisible | | R5 | Estandarizar nomenclatura | MEDIA | 2h | Consistencia | | R6 | Servicios audit | MEDIA | 32h | 0% -> 100% coherencia | | R7 | Soft delete pattern | BAJA | 4h | Mejora UX admin | | R8 | Indices compuestos | BAJA | 2h | Performance | | R9 | Particionamiento | FUTURO | 16h | Escalabilidad | --- *Generado por Claude Code (Opus 4.6) - TASK-2026-02-05-ANALISIS-VALIDACION-MODELADO-BD*