# DIRECTIVA: Arquitectura Híbrida Express.js + FastAPI

**ID**: DOQ-001
**Tipo**: Arquitectura
**Alcance**: OrbiQuant IA (trading-platform)
**Versión**: 2.0
**Fecha**: 2025-12-07
**Actualizado desde**: orbiquantia (NestJS -> Express.js)

## Propósito

Definir la arquitectura híbrida que combina Express.js (TypeScript) para la API principal y FastAPI (Python) para los servicios de Machine Learning.

## Arquitectura General

```
┌─────────────────────────────────────────────────────────────────┐
│                         FRONTEND                                 │
│                    React + TypeScript                           │
│                      (Puerto 5173)                              │
└─────────────────────────────────────────────────────────────────┘
                              │
                              ▼
┌─────────────────────────────────────────────────────────────────┐
│                      API GATEWAY                                 │
│                   Express.js (Puerto 3000)                      │
│  ┌──────────┐ ┌──────────┐ ┌──────────┐ ┌──────────┐           │
│  │   Auth   │ │  Users   │ │ Courses  │ │ Payments │           │
│  └──────────┘ └──────────┘ └──────────┘ └──────────┘           │
│  ┌──────────┐ ┌──────────┐ ┌──────────────────────┐            │
│  │ Trading  │ │  Admin   │ │ ML Proxy (Gateway)   │            │
│  └──────────┘ └──────────┘ └──────────────────────┘            │
└─────────────────────────────────────────────────────────────────┘
         │                              │
         │                              │ HTTP/WebSocket
         ▼                              ▼
┌─────────────────────┐    ┌─────────────────────────────────────┐
│    PostgreSQL       │    │         ML ENGINE                    │
│    (Puerto 5432)    │    │      FastAPI (Puerto 8000)          │
│                     │    │  ┌──────────┐ ┌──────────┐          │
│  - public           │    │  │ Predict  │ │ Signals  │          │
│  - education        │    │  └──────────┘ └──────────┘          │
│  - trading          │    │  ┌──────────┐ ┌──────────┐          │
│  - investment       │    │  │  Models  │ │Backtest  │          │
│  - financial        │    │  └──────────┘ └──────────┘          │
│  - ml               │    │           │                          │
│  - audit            │    │           ▼                          │
└─────────────────────┘    │    ┌──────────────┐                 │
                           │    │    MySQL     │                 │
                           │    │ (Puerto 3306)│                 │
                           │    │ Trading Data │                 │
                           │    └──────────────┘                 │
                           └─────────────────────────────────────┘
```

## Responsabilidades por Servicio

### Express.js Backend (API Principal)
**Responsable de:**
- Autenticación y autorización (JWT + OAuth + 2FA)
- Gestión de usuarios y perfiles
- Sistema de educación (cursos, lecciones, progreso)
- Pagos e integración con Stripe
- Panel de administración
- Proxy/Gateway hacia ML Engine
- CRUD de entidades de negocio
- Validación de datos de entrada (Zod)
- Logging y auditoría (Winston)

**NO responsable de:**
- Ejecución de modelos ML
- Procesamiento de datos de trading
- Cálculo de indicadores técnicos
- Generación de predicciones

### FastAPI ML Engine
**Responsable de:**
- Carga y ejecución de modelos ML (XGBoost, GRU, Transformer)
- Predicción de precios (multi-horizonte)
- Generación de señales de trading
- Cálculo de indicadores técnicos
- WebSocket streaming de predicciones
- Backtesting de estrategias
- Acceso a datos históricos (MySQL)

**NO responsable de:**
- Autenticación de usuarios
- Gestión de permisos
- Lógica de negocio de la aplicación
- Persistencia de datos de usuario

## Comunicación entre Servicios

### HTTP (Request/Response)
```typescript
// Express.js -> FastAPI
// Endpoint: GET /api/ml/predict/:symbol

// routes/ml.routes.ts
router.get('/predict/:symbol', authenticate, async (req, res, next) => {
  try {
    const { symbol } = req.params;
    const prediction = await mlGatewayService.predict(symbol);
    res.json(prediction);
  } catch (error) {
    next(error);
  }
});

// services/ml-gateway.service.ts
import axios from 'axios';

class MLGatewayService {
  private mlServiceUrl = process.env.ML_SERVICE_URL || 'http://localhost:8000';

  async predict(symbol: string): Promise<PredictionDto> {
    const response = await axios.get(
      `${this.mlServiceUrl}/api/predict/${symbol}`,
      { timeout: 30000 }
    );
    return response.data;
  }
}
```

### WebSocket (Streaming)
```typescript
// Frontend conecta directamente a FastAPI para streaming
// ws://localhost:8000/ws/{symbol}

// O mediante proxy en Express.js con socket.io:
import { Server } from 'socket.io';

const io = new Server(server, {
  cors: { origin: 'http://localhost:5173' }
});

io.on('connection', (socket) => {
  socket.on('subscribe', (symbol: string) => {
    // Proxy a FastAPI WebSocket
  });
});
```

## Reglas de Diseño

### 1. Separación de Concerns
- Express.js maneja TODO lo relacionado con usuarios y negocio
- FastAPI maneja EXCLUSIVAMENTE ML y datos de trading
- Frontend NUNCA accede directamente a MySQL

### 2. Autenticación
- JWT generado por Express.js (Passport.js)
- FastAPI valida tokens mediante endpoint interno de Express.js
- O FastAPI confía en requests desde Express.js (red interna)

### 3. Base de Datos
- PostgreSQL: Fuente de verdad para entidades de negocio (7 schemas)
- MySQL: Solo datos históricos de trading (OHLCV, indicadores)
- NO replicar datos entre bases de datos

### 4. Contratos de API
- Definir tipos compartidos en `shared/types/`
- Pydantic schemas en FastAPI deben coincidir con tipos TypeScript
- Documentar con OpenAPI/Swagger en ambos servicios

### 5. Manejo de Errores
```typescript
// Express.js captura errores de ML Engine
// middleware/error-handler.ts
import { Request, Response, NextFunction } from 'express';

export const errorHandler = (
  error: Error,
  req: Request,
  res: Response,
  next: NextFunction
) => {
  if (error.name === 'MLServiceUnavailableError') {
    return res.status(503).json({
      error: 'ML service unavailable',
      message: 'Please try again later'
    });
  }

  // Default error handling
  res.status(500).json({
    error: 'Internal server error',
    message: error.message
  });
};
```

## Estructura de Directorios

### Express.js Backend
```
apps/backend/src/
├── modules/
│   ├── auth/
│   │   ├── auth.routes.ts
│   │   ├── auth.controller.ts
│   │   ├── services/
│   │   │   ├── oauth.service.ts
│   │   │   ├── email.service.ts
│   │   │   ├── phone.service.ts
│   │   │   ├── token.service.ts
│   │   │   └── twofa.service.ts
│   │   └── validators/
│   ├── users/
│   ├── education/
│   ├── trading/
│   │   ├── trading.routes.ts
│   │   ├── trading.controller.ts
│   │   └── services/
│   │       └── ml-gateway.service.ts  # Comunicación con FastAPI
│   ├── investment/
│   ├── payments/
│   └── admin/
├── middleware/
│   ├── authenticate.ts
│   ├── error-handler.ts
│   └── rate-limiter.ts
├── config/
│   └── index.ts
└── index.ts
```

### FastAPI ML Engine
```
apps/ml-engine/src/
├── api/
│   ├── main.py              # FastAPI app
│   ├── routes/
│   │   ├── predict.py
│   │   ├── signals.py
│   │   ├── indicators.py
│   │   └── backtest.py
│   └── schemas/               # Pydantic models
├── models/
│   ├── base/
│   ├── ensemble/
│   └── predictors/
│       ├── range_predictor.py
│       ├── tpsl_classifier.py
│       └── signal_generator.py
├── data/
│   ├── pipeline.py
│   ├── database.py
│   ├── features.py
│   └── indicators.py
└── config/
    ├── trading.yaml
    └── models.yaml
```

## Endpoints ML Engine (FastAPI)

```yaml
# Predicciones
GET  /api/predict/{symbol}
     ?horizon=all|scalping|intraday|swing|position

# Señales
GET  /api/signals/{symbol}
     ?timeframe=5m|15m|1h

# Indicadores
GET  /api/indicators/{symbol}
     ?indicators=rsi,macd,atr

# Datos históricos
GET  /api/history/{symbol}
     ?limit=500&timeframe=5m

# Backtesting
POST /api/backtest
     Body: { strategy, symbol, start_date, end_date }

# Health
GET  /health
GET  /api/stats

# WebSocket
WS   /ws/{symbol}
```

## Configuración de Puertos

| Servicio | Puerto | Protocolo |
|----------|--------|-----------|
| Frontend | 5173 | HTTP |
| Express.js API | 3000 | HTTP |
| FastAPI ML | 8000 | HTTP |
| FastAPI WS | 8000 | WebSocket |
| PostgreSQL | 5432 | TCP |
| MySQL | 3306 | TCP |
| Redis | 6379 | TCP |

## Variables de Entorno

### Express.js (.env)
```env
# Server
PORT=3000
NODE_ENV=development

# Database
DATABASE_URL=postgresql://user:pass@localhost:5432/orbiquantia

# JWT
JWT_SECRET=your-secret-key
JWT_EXPIRES_IN=15m
JWT_REFRESH_SECRET=your-refresh-secret
JWT_REFRESH_EXPIRES_IN=7d

# ML Services
ML_SERVICE_URL=http://localhost:8000
ML_SERVICE_TIMEOUT=30000

# OAuth
GOOGLE_CLIENT_ID=
GOOGLE_CLIENT_SECRET=
FACEBOOK_APP_ID=
FACEBOOK_APP_SECRET=
GITHUB_CLIENT_ID=
GITHUB_CLIENT_SECRET=

# Twilio (Phone Auth)
TWILIO_ACCOUNT_SID=
TWILIO_AUTH_TOKEN=
TWILIO_PHONE_NUMBER=

# Stripe
STRIPE_SECRET_KEY=
STRIPE_WEBHOOK_SECRET=

# Redis
REDIS_URL=redis://localhost:6379
```

### FastAPI (.env)
```env
# API Configuration
API_HOST=0.0.0.0
API_PORT=8000

# MySQL Trading Data
MYSQL_HOST=localhost
MYSQL_PORT=3306
MYSQL_DATABASE=orbiquantia_trading
MYSQL_USER=trading_user
MYSQL_PASSWORD=secure_password

# Models
MODEL_PATH=./models
MODEL_VERSION=1.0.0

# GPU
CUDA_VISIBLE_DEVICES=0
USE_GPU=true

# Internal Auth (opcional)
EXPRESS_INTERNAL_URL=http://localhost:3000
INTERNAL_API_KEY=shared_secret_key

# Logging
LOG_LEVEL=INFO
```

## Validaciones Obligatorias

1. [ ] Express.js puede alcanzar FastAPI en `/health`
2. [ ] Tokens JWT son validados correctamente
3. [ ] Timeouts configurados apropiadamente
4. [ ] Errores de ML Engine se manejan gracefully
5. [ ] WebSocket streaming funciona end-to-end
6. [ ] Tipos TypeScript coinciden con Pydantic schemas
7. [ ] Rate limiting configurado en ambos servicios
8. [ ] CORS configurado correctamente

---
*Migrado desde orbiquantia y actualizado para Express.js*
