trading-platform/docs/90-transversal/inventarios/BACKEND_INVENTORY.yml
Adrian Flores Cortes a01b03393f docs: Complete Sprint 4 (ARCH-001, ARCH-002) documentation
- Update PROXIMA-ACCION.md with Sprint 4 completion
- Add checkpoints for architecture unification
- Update metrics (Coherencia Backend-Frontend: 90%)
- Update inventory files with new modules

Sprint 4 completed:
- ARCH-001: Express proxy gateway (1,132 LOC backend)
- ARCH-002: Frontend services migration (4 services, 32 endpoints)

Co-Authored-By: Claude Opus 4.5 <noreply@anthropic.com>
2026-01-28 15:44:39 -06:00

1063 lines
31 KiB
YAML

# ============================================================================
# BACKEND_INVENTORY.yml - Trading Platform Trading Platform
# ============================================================================
# Proposito: Inventario consolidado de todos los componentes del backend
# Ultima actualizacion: 2026-01-28
# Version: 1.2.0
# ============================================================================
version: "1.2.0"
project: "Trading Platform"
framework: "Express.js + TypeScript"
node_version: "20.x"
last_updated: "2026-01-28"
# ============================================================================
# RESUMEN EJECUTIVO
# ============================================================================
summary:
total_modules: 17 # +5 nuevos: market-data, audit, currency, risk, reviews
total_routes_files: 17
total_services: 39 # +5 nuevos
total_controllers: 28 # +5 nuevos
total_middlewares: 5
total_guards: 1
total_background_jobs: 1
total_endpoints_estimated: 78 # +21 nuevos
status: "En desarrollo activo"
# ============================================================================
# ESTRUCTURA DE DIRECTORIOS
# ============================================================================
structure:
root: "apps/backend/src"
directories:
- path: config/
purpose: "Configuracion de la aplicacion"
- path: core/
purpose: "Componentes core (middleware, guards, filters, interceptors)"
- path: modules/
purpose: "Modulos de negocio"
- path: shared/
purpose: "Utilidades, tipos y constantes compartidas"
# ============================================================================
# MODULOS
# ============================================================================
modules:
# --------------------------------------------------------------------------
# AUTH - Autenticacion y autorizacion
# --------------------------------------------------------------------------
- name: auth
path: modules/auth/
epic: OQI-001
status: implemented
description: "Autenticacion multi-metodo, OAuth, 2FA, sesiones"
routes_file: auth.routes.ts
endpoints:
- method: POST
path: /auth/register
description: "Registro de usuario con email/password"
rf: RF-AUTH-002
- method: POST
path: /auth/login
description: "Login con email/password"
rf: RF-AUTH-002
- method: POST
path: /auth/logout
description: "Cerrar sesion"
rf: RF-AUTH-004
- method: POST
path: /auth/refresh
description: "Renovar access token"
rf: RF-AUTH-004
- method: POST
path: /auth/forgot-password
description: "Solicitar reset de password"
rf: RF-AUTH-002
- method: POST
path: /auth/reset-password
description: "Completar reset de password"
rf: RF-AUTH-002
- method: GET
path: /auth/oauth/:provider
description: "Iniciar flujo OAuth"
rf: RF-AUTH-001
- method: GET
path: /auth/oauth/:provider/callback
description: "Callback de OAuth"
rf: RF-AUTH-001
- method: POST
path: /auth/phone/send-code
description: "Enviar codigo SMS"
rf: RF-AUTH-002
- method: POST
path: /auth/phone/verify
description: "Verificar codigo SMS"
rf: RF-AUTH-002
- method: POST
path: /auth/2fa/setup
description: "Configurar 2FA TOTP"
rf: RF-AUTH-003
- method: POST
path: /auth/2fa/verify
description: "Verificar codigo 2FA"
rf: RF-AUTH-003
- method: POST
path: /auth/2fa/disable
description: "Deshabilitar 2FA"
rf: RF-AUTH-003
services:
- name: token.service.ts
purpose: "Manejo de JWT y refresh tokens"
methods:
- generateAccessToken()
- generateRefreshToken()
- verifyAccessToken()
- verifyRefreshToken()
- name: oauth.service.ts
purpose: "Integracion con proveedores OAuth"
methods:
- getAuthorizationUrl()
- handleCallback()
- linkAccount()
- unlinkAccount()
- name: email.service.ts
purpose: "Autenticacion por email"
methods:
- register()
- login()
- sendConfirmation()
- confirmEmail()
- name: phone.service.ts
purpose: "Autenticacion por telefono"
methods:
- sendVerificationCode()
- verifyCode()
- name: twofa.service.ts
purpose: "Two-Factor Authentication"
methods:
- generateSecret()
- generateQRCode()
- verifyToken()
- generateBackupCodes()
controllers:
- name: auth.controller.ts
purpose: "Controlador principal de auth"
validators:
- name: auth.validators.ts
purpose: "Validacion de requests de auth"
types:
- name: auth.types.ts
purpose: "Tipos e interfaces de auth"
# --------------------------------------------------------------------------
# USERS - Gestion de usuarios
# --------------------------------------------------------------------------
- name: users
path: modules/users/
epic: OQI-001
status: structure_only
description: "Gestion de perfiles, settings y KYC"
routes_file: users.routes.ts
endpoints_planned:
- method: GET
path: /users/me
description: "Obtener perfil actual"
- method: PATCH
path: /users/me
description: "Actualizar perfil"
- method: GET
path: /users/me/settings
description: "Obtener configuracion"
- method: PATCH
path: /users/me/settings
description: "Actualizar configuracion"
- method: POST
path: /users/me/kyc
description: "Enviar documentos KYC"
- method: GET
path: /users/me/kyc/status
description: "Estado de verificacion KYC"
# --------------------------------------------------------------------------
# EDUCATION - Modulo educativo
# --------------------------------------------------------------------------
- name: education
path: modules/education/
epic: OQI-002
status: structure_only
description: "Cursos, lecciones, quizzes y progreso"
routes_file: education.routes.ts
endpoints_planned:
- method: GET
path: /education/courses
description: "Listar cursos"
- method: GET
path: /education/courses/:slug
description: "Detalle de curso"
- method: POST
path: /education/courses/:id/enroll
description: "Inscribirse a curso"
- method: GET
path: /education/courses/:id/lessons
description: "Listar lecciones"
- method: GET
path: /education/lessons/:id
description: "Detalle de leccion"
- method: POST
path: /education/lessons/:id/progress
description: "Actualizar progreso"
- method: GET
path: /education/quizzes/:id
description: "Obtener quiz"
- method: POST
path: /education/quizzes/:id/submit
description: "Enviar respuestas"
# --------------------------------------------------------------------------
# TRADING - Trading y charts
# --------------------------------------------------------------------------
- name: trading
path: modules/trading/
epic: OQI-003
status: structure_only
description: "Watchlists, paper trading, senales"
routes_file: trading.routes.ts
endpoints_planned:
- method: GET
path: /trading/symbols
description: "Listar simbolos disponibles"
- method: GET
path: /trading/candles/:symbol
description: "Obtener velas OHLCV"
- method: GET
path: /trading/ticker/:symbol
description: "Precio actual"
- method: GET
path: /trading/watchlists
description: "Listar watchlists"
- method: POST
path: /trading/watchlists
description: "Crear watchlist"
- method: GET
path: /trading/paper/balance
description: "Balance paper trading"
- method: POST
path: /trading/paper/orders
description: "Crear orden paper"
- method: GET
path: /trading/signals
description: "Listar senales"
- method: GET
path: /trading/ml/overlay/:symbol
description: "ML overlay para charts"
# --------------------------------------------------------------------------
# INVESTMENT - Cuentas de inversion
# --------------------------------------------------------------------------
- name: investment
path: modules/investment/
epic: OQI-004
status: structure_only
description: "Productos, cuentas, depositos, retiros"
routes_file: investment.routes.ts
endpoints_planned:
- method: GET
path: /investment/products
description: "Listar productos"
- method: GET
path: /investment/accounts
description: "Mis cuentas de inversion"
- method: POST
path: /investment/accounts
description: "Abrir cuenta"
- method: GET
path: /investment/accounts/:id
description: "Detalle de cuenta"
- method: POST
path: /investment/accounts/:id/deposit
description: "Solicitar deposito"
- method: POST
path: /investment/accounts/:id/withdraw
description: "Solicitar retiro"
- method: GET
path: /investment/accounts/:id/performance
description: "Rendimiento de cuenta"
# --------------------------------------------------------------------------
# PAYMENTS - Pagos y suscripciones
# --------------------------------------------------------------------------
- name: payments
path: modules/payments/
epic: OQI-005
status: structure_only
description: "Suscripciones, pagos, wallet, Stripe"
routes_file: payments.routes.ts
endpoints_planned:
- method: GET
path: /payments/plans
description: "Listar planes"
- method: POST
path: /payments/checkout
description: "Crear sesion de checkout"
- method: GET
path: /payments/subscription
description: "Mi suscripcion"
- method: POST
path: /payments/subscription/cancel
description: "Cancelar suscripcion"
- method: GET
path: /payments/wallet
description: "Mi wallet"
- method: POST
path: /payments/wallet/deposit
description: "Depositar a wallet"
- method: POST
path: /payments/webhook
description: "Webhook de Stripe"
# --------------------------------------------------------------------------
# ADMIN - Administracion
# --------------------------------------------------------------------------
- name: admin
path: modules/admin/
epic: OQI-001
status: structure_only
description: "Panel de administracion"
routes_file: admin.routes.ts
endpoints_planned:
- method: GET
path: /admin/users
description: "Listar usuarios"
- method: GET
path: /admin/users/:id
description: "Detalle de usuario"
- method: PATCH
path: /admin/users/:id/status
description: "Cambiar estado de usuario"
- method: GET
path: /admin/kyc/pending
description: "KYC pendientes"
- method: POST
path: /admin/kyc/:id/approve
description: "Aprobar KYC"
- method: GET
path: /admin/dashboard
description: "Metricas del sistema"
# ============================================================================
# NUEVOS MODULOS (Sprint 2-3, 2026-01-28)
# ============================================================================
# --------------------------------------------------------------------------
# MARKET-DATA - Datos de mercado OHLCV
# --------------------------------------------------------------------------
- name: market-data
path: modules/market-data/
epic: OQI-003
status: implemented
description: "Datos OHLCV con cache Redis y PostgreSQL"
created: "2026-01-28"
sprint: "Sprint 2 - P1"
routes_file: market-data.routes.ts
endpoints:
- method: GET
path: /market-data/ohlcv/:symbol/:timeframe
description: "Obtener velas OHLCV"
- method: GET
path: /market-data/historical/:symbol
description: "Datos historicos"
- method: GET
path: /market-data/symbols
description: "Listar simbolos disponibles"
- method: GET
path: /market-data/health
description: "Health check del servicio"
services:
- name: marketData.service.ts
purpose: "Servicio con Redis cache y PostgreSQL queries"
lines: 320
methods:
- getOHLCV(symbol, timeframe, limit)
- getHistoricalData(symbol, start, end)
- getAvailableSymbols()
- cacheOHLCV(key, data, ttl)
controllers:
- name: market-data.controller.ts
purpose: "REST API para datos de mercado"
lines: 156
types:
- name: market-data.types.ts
purpose: "Interfaces OHLCV y DTOs"
lines: 85
# --------------------------------------------------------------------------
# AUDIT - Sistema de auditoria
# --------------------------------------------------------------------------
- name: audit
path: modules/audit/
epic: OQI-001
status: implemented
description: "Sistema de consultas de auditoria con estadisticas"
created: "2026-01-28"
sprint: "Sprint 3 - P2"
routes_file: audit.routes.ts
endpoints:
- method: GET
path: /audit/logs
description: "Listar logs de auditoria con filtros"
- method: GET
path: /audit/logs/:id
description: "Detalle de log especifico"
- method: GET
path: /audit/stats
description: "Estadisticas de auditoria"
- method: GET
path: /audit/users/:userId/activity
description: "Actividad de usuario especifico"
- method: GET
path: /audit/export
description: "Exportar logs (CSV, JSON)"
services:
- name: audit.service.ts
purpose: "Servicio de consultas y estadisticas"
lines: 713
methods:
- getLogs(filters, pagination)
- getLogById(id)
- getStatistics(dateRange)
- getUserActivity(userId)
- exportLogs(format, filters)
controllers:
- name: audit.controller.ts
purpose: "REST API para auditoria"
lines: 262
types:
- name: audit.types.ts
purpose: "Interfaces y DTOs de auditoria"
lines: 243
# --------------------------------------------------------------------------
# CURRENCY - Tasas de cambio
# --------------------------------------------------------------------------
- name: currency
path: modules/currency/
epic: OQI-004
status: implemented
description: "Tasas de cambio multi-moneda con cache Redis"
created: "2026-01-28"
sprint: "Sprint 3 - P2"
commit: "8f2b929"
routes_file: currency.routes.ts
endpoints:
- method: GET
path: /currency/rates
description: "Obtener tasas actuales"
- method: GET
path: /currency/convert
description: "Convertir entre monedas"
- method: GET
path: /currency/historical/:pair
description: "Historico de tasas"
- method: GET
path: /currency/supported
description: "Monedas soportadas"
services:
- name: currency.service.ts
purpose: "Servicio con Redis cache (TTL 5min)"
lines: 320
methods:
- getRates(baseCurrency)
- convert(from, to, amount)
- getHistoricalRates(pair, dateRange)
- getSupportedCurrencies()
controllers:
- name: currency.controller.ts
purpose: "REST API para monedas"
lines: 156
types:
- name: currency.types.ts
purpose: "Interfaces de monedas y tasas"
lines: 49
# --------------------------------------------------------------------------
# RISK - Evaluacion de riesgo
# --------------------------------------------------------------------------
- name: risk
path: modules/risk/
epic: OQI-004
status: implemented
description: "Cuestionario de perfil de riesgo con 15 preguntas"
created: "2026-01-28"
sprint: "Sprint 3 - P2"
routes_file: risk.routes.ts
endpoints:
- method: GET
path: /risk/questionnaire
description: "Obtener cuestionario"
- method: POST
path: /risk/questionnaire/submit
description: "Enviar respuestas"
- method: GET
path: /risk/profile
description: "Obtener perfil de riesgo"
- method: GET
path: /risk/history
description: "Historico de evaluaciones"
- method: GET
path: /risk/recommendations
description: "Recomendaciones por perfil"
services:
- name: risk.service.ts
purpose: "Logica de evaluacion con 15 preguntas"
lines: 353
methods:
- getQuestionnaire()
- submitAnswers(userId, answers)
- calculateRiskProfile(answers)
- getRiskProfile(userId)
- getAssessmentHistory(userId)
repositories:
- name: risk.repository.ts
purpose: "Acceso a datos PostgreSQL"
lines: 272
controllers:
- name: risk.controller.ts
purpose: "REST API para riesgo"
lines: 266
types:
- name: risk.types.ts
purpose: "Interfaces de cuestionario y perfil"
lines: 97
# --------------------------------------------------------------------------
# REVIEWS - Resenas de cursos (en education module)
# --------------------------------------------------------------------------
- name: reviews
path: modules/education/
epic: OQI-002
status: implemented
description: "Sistema de resenas de cursos con votos utiles"
created: "2026-01-28"
sprint: "Sprint 3 - P2"
commits:
- "b99953b (backend)"
- "70c201d (DDL)"
endpoints:
- method: GET
path: /education/courses/:courseId/reviews
description: "Listar resenas de curso"
- method: POST
path: /education/courses/:courseId/reviews
description: "Crear resena (requiere enrollment)"
- method: PATCH
path: /education/reviews/:id
description: "Actualizar resena propia"
- method: DELETE
path: /education/reviews/:id
description: "Eliminar resena propia"
- method: POST
path: /education/reviews/:id/helpful
description: "Marcar como util"
- method: GET
path: /education/courses/:courseId/reviews/stats
description: "Estadisticas de resenas"
services:
- name: reviews.service.ts
purpose: "Servicio con validacion de enrollment"
lines: 280
methods:
- getCourseReviews(courseId, filters)
- createReview(userId, courseId, data)
- updateReview(reviewId, userId, data)
- deleteReview(reviewId, userId)
- markHelpful(reviewId, userId)
- getReviewStats(courseId)
controllers:
- name: reviews.controller.ts
purpose: "REST API para resenas"
lines: 220
types:
- name: reviews.types.ts
purpose: "Interfaces de resenas"
lines: 85
ddl:
- name: 16-review_helpful_votes.sql
path: apps/database/ddl/schemas/education/tables/
purpose: "Tabla para votos utiles"
lines: 25
# ============================================================================
# CORE COMPONENTS
# ============================================================================
core:
middleware:
- name: auth.middleware.ts
path: core/middleware/auth.middleware.ts
purpose: "Verificacion de autenticacion JWT"
rf: RF-AUTH-004
- name: error-handler.ts
path: core/middleware/error-handler.ts
purpose: "Manejo global de errores"
- name: not-found.ts
path: core/middleware/not-found.ts
purpose: "Handler para rutas no encontradas"
- name: rate-limiter.ts
path: core/middleware/rate-limiter.ts
purpose: "Rate limiting por IP/usuario"
rf: RF-AUTH-005
guards:
- name: auth.guard.ts
path: core/guards/auth.guard.ts
purpose: "Guard de autenticacion"
filters:
- name: http-exception.filter.ts
path: core/filters/http-exception.filter.ts
purpose: "Filtro de excepciones HTTP"
interceptors:
- name: transform-response.interceptor.ts
path: core/interceptors/transform-response.interceptor.ts
purpose: "Transformacion de respuestas"
# ============================================================================
# SHARED COMPONENTS
# ============================================================================
shared:
database:
- name: index.ts
path: shared/database/index.ts
purpose: "Conexion a PostgreSQL"
constants:
- name: database.constants.ts
purpose: "Constantes de base de datos"
- name: enums.constants.ts
purpose: "ENUMs sincronizados con BD"
note: "DEBE mantenerse sincronizado con DATABASE_INVENTORY"
- name: routes.constants.ts
purpose: "Constantes de rutas"
types:
- name: common.types.ts
purpose: "Tipos comunes compartidos"
utils:
- name: logger.ts
purpose: "Logger de la aplicacion"
# ============================================================================
# CONFIGURACION
# ============================================================================
config:
file: config/index.ts
variables:
- name: DATABASE_URL
required: true
purpose: "URL de conexion a PostgreSQL"
- name: JWT_SECRET
required: true
purpose: "Secret para JWT"
- name: JWT_EXPIRES_IN
required: false
default: "1d"
purpose: "Expiracion de access token"
- name: REFRESH_TOKEN_EXPIRES_IN
required: false
default: "7d"
purpose: "Expiracion de refresh token"
- name: STRIPE_SECRET_KEY
required: true
purpose: "API key de Stripe"
- name: STRIPE_WEBHOOK_SECRET
required: true
purpose: "Secret para webhooks de Stripe"
- name: ML_SERVICE_URL
required: true
default: "http://localhost:8000"
purpose: "URL del servicio ML"
- name: FRONTEND_URL
required: true
purpose: "URL del frontend para CORS"
- name: PORT
required: false
default: 3000
purpose: "Puerto del servidor"
# ============================================================================
# MAPEO A EPICAS
# ============================================================================
epic_mapping:
OQI-001:
modules: [auth, users, admin]
status: "Parcialmente implementado"
services_count: 5
OQI-002:
modules: [education]
status: "Estructura creada"
services_count: 0
OQI-003:
modules: [trading]
status: "Estructura creada"
services_count: 0
OQI-004:
modules: [investment]
status: "Estructura creada"
services_count: 0
OQI-005:
modules: [payments]
status: "Estructura creada"
services_count: 0
OQI-006:
modules: []
status: "Pendiente"
note: "Integracion con ML Engine existente"
OQI-007:
modules: []
status: "Planificado"
note: "Modulo llm-agent a crear"
OQI-008:
modules: []
status: "Planificado"
note: "Modulo portfolio a crear"
# ============================================================================
# DEPENDENCIAS PRINCIPALES
# ============================================================================
dependencies:
production:
- express: "^4.18.x"
- typescript: "^5.x"
- pg: "^8.x"
- jsonwebtoken: "^9.x"
- bcryptjs: "^2.x"
- stripe: "^14.x"
- express-rate-limit: "^7.x"
- helmet: "^7.x"
- cors: "^2.x"
- winston: "^3.x"
- joi: "^17.x"
development:
- "@types/node": "^20.x"
- "@types/express": "^4.x"
- ts-node-dev: "^2.x"
- nodemon: "^3.x"
# ============================================================================
# SCRIPTS
# ============================================================================
scripts:
- name: "start:dev"
command: "ts-node-dev --respawn src/index.ts"
purpose: "Desarrollo con hot reload"
- name: "build"
command: "tsc"
purpose: "Compilar a JavaScript"
- name: "start"
command: "node dist/index.js"
purpose: "Produccion"
- name: "test"
command: "jest"
purpose: "Ejecutar tests"
# ============================================================================
# ARCHIVOS CLAVE
# ============================================================================
key_files:
- path: apps/backend/src/index.ts
purpose: "Entry point de la aplicacion"
- path: apps/backend/src/config/index.ts
purpose: "Configuracion centralizada"
- path: apps/backend/package.json
purpose: "Dependencias y scripts"
- path: apps/backend/tsconfig.json
purpose: "Configuracion de TypeScript"
# ============================================================================
# NOTAS Y PENDIENTES
# ============================================================================
notes:
- "Modulo auth completamente implementado (OQI-001)"
- "Modulo notifications agregado (2026-01-25) - multi-canal: email, push, in-app, WebSocket"
- "Distribution job implementado para rendimientos de inversion (00:00 UTC)"
- "Trading module con export service implementado (CSV, Excel, PDF, JSON)"
- "Investment module con repositories PostgreSQL"
- "Modulos ML, LLM, Portfolio en desarrollo"
- "Tests unitarios pendientes"
# ============================================================================
# MODULO NOTIFICATIONS (Agregado 2026-01-25)
# ============================================================================
notifications_module:
name: notifications
path: modules/notifications/
status: implemented
description: "Sistema de notificaciones multi-canal"
components:
services:
- name: notification.service.ts
purpose: "Servicio unificado de notificaciones"
methods:
- sendNotification(userId, payload, options)
- sendBulkNotification(userIds, payload)
- broadcastNotification(payload)
- sendInAppNotification(userId, notification)
- sendEmailNotification(userId, payload)
- sendPushNotification(userId, payload)
- getUserNotifications(userId, options)
- markAsRead(notificationId, userId)
- markAllAsRead(userId)
- getUnreadCount(userId)
- deleteNotification(notificationId, userId)
- getUserPreferences(userId)
- updateUserPreferences(userId, updates)
- sendAlertNotification(userId, alert)
- sendTradeNotification(userId, trade)
- sendDistributionNotification(userId, distribution)
controllers:
- name: notification.controller.ts
purpose: "REST API para notificaciones"
routes:
- name: notification.routes.ts
base_path: /api/v1/notifications
endpoints:
- method: GET
path: /notifications
description: "Listar notificaciones del usuario"
auth: required
- method: GET
path: /notifications/unread-count
description: "Obtener conteo de no leidas"
auth: required
- method: GET
path: /notifications/preferences
description: "Obtener preferencias de notificacion"
auth: required
- method: PATCH
path: /notifications/preferences
description: "Actualizar preferencias"
auth: required
- method: POST
path: /notifications/read-all
description: "Marcar todas como leidas"
auth: required
- method: PATCH
path: /notifications/:id/read
description: "Marcar una como leida"
auth: required
- method: DELETE
path: /notifications/:id
description: "Eliminar notificacion"
auth: required
- method: POST
path: /notifications/push-token
description: "Registrar token de push notification"
auth: required
added: "2026-01-25"
- method: DELETE
path: /notifications/push-token
description: "Eliminar token de push notification"
auth: required
added: "2026-01-25"
notification_types:
- alert_triggered
- trade_executed
- deposit_confirmed
- withdrawal_completed
- distribution_received
- system_announcement
- security_alert
- account_update
delivery_channels:
- in_app (WebSocket real-time)
- email (Nodemailer templates)
- push (FCM/APNS - implemented 2026-01-25)
- sms (Twilio ready)
tests:
- path: services/__tests__/notification.service.spec.ts
lines: ~450
added: "2026-01-25"
integrations:
- name: Firebase Cloud Messaging
client: shared/clients/firebase.client.ts
added: "2026-01-25"
- name: Web Push (VAPID)
added: "2026-01-25"
# ============================================================================
# BACKGROUND JOBS (Agregado 2026-01-25)
# ============================================================================
background_jobs:
- name: distribution.job.ts
module: investment
test: jobs/__tests__/distribution.job.spec.ts
test_added: "2026-01-25"
path: modules/investment/jobs/distribution.job.ts
schedule: "Daily at 00:00 UTC"
purpose: "Calcular y distribuir rendimientos de inversion"
features:
- Calculo de retornos diarios por producto
- Aplicacion de performance fees
- Actualizacion atomica de balances
- Registro en distribution_history
- Notificacion a usuarios
- Auditoria en distribution_runs
# ============================================================================
# FIN DEL INVENTARIO
# ============================================================================