Changes include: - Updated architecture documentation - Enhanced module definitions (OQI-001 to OQI-008) - ML integration documentation updates - Trading strategies documentation - Orchestration and inventory updates - Docker configuration updates 🤖 Generated with [Claude Code](https://claude.com/claude-code) Co-Authored-By: Claude Opus 4.5 <noreply@anthropic.com>
23 KiB
| id | title | type | project | version | updated_date |
|---|---|---|---|---|---|
| MIGRACION-SUPABASE-EXPRESS | Supabase a Express Backend | Documentation | trading-platform | 1.0.0 | 2026-01-04 |
Plan de Migracion: Supabase a Express Backend
Ultima actualizacion: 2025-12-05
Proyecto origen: stc-platform-web (Supabase)
Proyecto destino: trading-platform (Express + pg + PostgreSQL)
Patrones base: shared/catalog/auth/ (inspiración arquitectónica de patrones auth y estructura)
Resumen Ejecutivo
Este documento detalla el plan de migracion del frontend existente en stc-platform-web que usa Supabase como backend hacia una arquitectura con Express.js como backend propio.
Estado Actual del Backend:
El backend de trading-platform (/home/isem/workspace/projects/trading-platform/apps/backend/) ya tiene implementacion funcional con:
- Express.js + TypeScript
- Autenticacion JWT completa (registro, login, refresh tokens, sesiones)
- OAuth multi-proveedor (Google, Facebook, Twitter, Apple, GitHub)
- 2FA con TOTP (speakeasy)
- Autenticacion por telefono (Twilio SMS/WhatsApp)
- PostgreSQL con pg driver nativo
- Estructura modular escalable
- Guards, interceptors, filters adaptados de patrones NestJS
Patrones de Gamilit Adaptados: Se tomaron patrones del proyecto Gamilit y se adaptaron para Express:
- Constantes compartidas (DB_SCHEMAS, enums)
- Estructura de servicios modulares
- Manejo de errores unificado
- Guards de autenticacion y autorizacion
1. Arquitectura Objetivo
Antes (Supabase)
Frontend (React) ──> Supabase Client ──> Supabase (Auth + DB + Storage)
│
├── Auth (Built-in)
├── PostgreSQL
├── Realtime
└── Storage
Despues (Express Backend Propio)
Frontend (React) ──> API Client ──> Express Backend ──> PostgreSQL
│ │
│ ├── JWT Auth (jsonwebtoken + Passport)
│ ├── pg driver (Multi-schema)
│ ├── Redis (Sessions/Cache)
│ ├── S3/MinIO (Storage)
│ └── Socket.io (Realtime)
│
└── WebSocket ──> Realtime Updates
2. Estructura Backend Actual (Express)
apps/backend/src/
├── index.ts # Entry point Express server
├── config/
│ └── index.ts # Configuracion centralizada
├── core/
│ ├── decorators/
│ ├── filters/
│ │ ├── http-exception.filter.ts # Excepciones HTTP unificadas
│ │ └── index.ts
│ ├── guards/
│ │ ├── auth.guard.ts # Guards de autenticacion
│ │ └── index.ts
│ ├── interceptors/
│ │ ├── transform-response.interceptor.ts
│ │ └── index.ts
│ └── middleware/
│ ├── auth.middleware.ts # Middleware JWT
│ ├── error-handler.ts # Manejador de errores
│ ├── not-found.ts # 404 handler
│ └── rate-limiter.ts # Rate limiting
├── modules/
│ ├── auth/
│ │ ├── auth.routes.ts # Rutas de auth
│ │ ├── controllers/
│ │ │ └── auth.controller.ts # Controller principal
│ │ ├── services/
│ │ │ ├── email.service.ts # Auth email/password
│ │ │ ├── oauth.service.ts # OAuth multi-provider
│ │ │ ├── phone.service.ts # SMS/WhatsApp (Twilio)
│ │ │ ├── token.service.ts # JWT tokens
│ │ │ └── twofa.service.ts # 2FA TOTP
│ │ ├── strategies/ # Passport strategies
│ │ ├── types/
│ │ │ └── auth.types.ts # Tipos de auth
│ │ └── validators/
│ │ └── auth.validators.ts # Validacion Zod
│ ├── users/
│ │ └── users.routes.ts
│ ├── education/
│ │ └── education.routes.ts
│ ├── trading/
│ │ └── trading.routes.ts
│ ├── investment/
│ │ └── investment.routes.ts
│ ├── payments/
│ │ └── payments.routes.ts
│ └── admin/
│ └── admin.routes.ts
└── shared/
├── constants/
│ ├── database.constants.ts # DB_SCHEMAS, DB_TABLES
│ ├── enums.constants.ts # UserStatusEnum, etc
│ ├── routes.constants.ts # API_ROUTES
│ └── index.ts
├── database/
│ └── index.ts # Pool de conexiones pg
├── dto/
├── types/
│ ├── common.types.ts # ApiResponse, PaginatedResult
│ └── index.ts
└── utils/
└── logger.ts # Winston logger
Servicios de Auth Implementados
| Servicio | Archivo | Funcionalidades |
|---|---|---|
| EmailService | email.service.ts |
Registro, login, verificacion email, reset password |
| OAuthService | oauth.service.ts |
Google, Facebook, Twitter, Apple, GitHub |
| PhoneService | phone.service.ts |
SMS OTP, WhatsApp OTP (Twilio) |
| TokenService | token.service.ts |
JWT access/refresh, sesiones |
| TwoFAService | twofa.service.ts |
TOTP setup, verify, backup codes |
3. Estructura Backend Gamilit (Referencia)
gamilit/apps/backend/src/
├── main.ts # Bootstrap con Swagger, CORS, ValidationPipe
├── app.module.ts # Root module con multi-schema TypeORM
├── config/
│ ├── app.config.ts # Configuracion de aplicacion
│ ├── database.config.ts # Configuracion PostgreSQL
│ ├── jwt.config.ts # Configuracion JWT
│ └── env.config.ts # Variables de entorno
├── modules/
│ ├── auth/ # ✅ REUTILIZAR PATRON
│ │ ├── auth.module.ts # Module definition
│ │ ├── controllers/
│ │ │ ├── auth.controller.ts # Login, Register, Refresh
│ │ │ ├── password.controller.ts # Forgot/Reset password
│ │ │ └── users.controller.ts # User CRUD
│ │ ├── services/
│ │ │ ├── auth.service.ts # Core auth logic (25KB)
│ │ │ ├── session-management.service.ts
│ │ │ ├── security.service.ts
│ │ │ ├── password-recovery.service.ts
│ │ │ └── email-verification.service.ts
│ │ ├── entities/
│ │ │ ├── user.entity.ts
│ │ │ ├── profile.entity.ts
│ │ │ ├── user-session.entity.ts
│ │ │ ├── auth-attempt.entity.ts
│ │ │ ├── auth-provider.entity.ts # OAuth providers
│ │ │ └── ...
│ │ ├── strategies/
│ │ │ └── jwt.strategy.ts # Passport JWT strategy
│ │ ├── guards/
│ │ │ └── jwt-auth.guard.ts
│ │ ├── dto/
│ │ │ ├── register-user.dto.ts
│ │ │ ├── login.dto.ts
│ │ │ └── ...
│ │ └── decorators/
│ │ └── current-user.decorator.ts
│ ├── educational/ # → Adaptar para courses
│ ├── progress/ # → Adaptar para course progress
│ ├── gamification/ # → Adaptar para trading stats
│ ├── notifications/ # ✅ REUTILIZAR
│ ├── websocket/ # ✅ REUTILIZAR para signals realtime
│ └── health/ # ✅ REUTILIZAR
└── shared/
├── constants/
│ ├── database.constants.ts # DB_SCHEMAS, DB_TABLES
│ ├── routes.constants.ts # API_PREFIX, API_VERSION
│ └── enums.constants.ts # Shared enums
├── decorators/
├── dto/
├── filters/
│ └── http-exception.filter.ts # Global exception handler
├── guards/
├── interceptors/
│ ├── transform-response.interceptor.ts
│ └── rls.interceptor.ts # Row Level Security
├── middleware/
├── pipes/
└── utils/
Archivos Clave a Copiar/Adaptar
| Archivo Gamilit | Destino Trading Platform | Adaptaciones |
|---|---|---|
main.ts |
apps/backend/src/main.ts |
Cambiar nombre app, tags Swagger |
app.module.ts |
apps/backend/src/app.module.ts |
Cambiar schemas y modules |
auth/ (completo) |
modules/auth/ |
Agregar OAuth providers adicionales |
shared/ (completo) |
shared/ |
Adaptar constantes y enums |
websocket/ |
modules/websocket/ |
Adaptar eventos para trading signals |
health/ |
modules/health/ |
Sin cambios |
4. Mapeo de Supabase a Express
4.1 Autenticacion
| Supabase Method | Express Equivalent | Endpoint |
|---|---|---|
supabase.auth.signInWithPassword() |
POST /api/v1/auth/login |
JWT + Refresh Token |
supabase.auth.signUp() |
POST /api/v1/auth/register |
Validacion + Email verification |
supabase.auth.signInWithOAuth() |
GET /api/v1/auth/oauth/:provider/url |
Passport OAuth strategies |
supabase.auth.signOut() |
POST /api/v1/auth/logout |
Invalidar tokens |
supabase.auth.resetPasswordForEmail() |
POST /api/v1/auth/forgot-password |
Nodemailer |
supabase.auth.updateUser() |
PATCH /api/v1/auth/password |
Validacion + bcrypt |
supabase.auth.verifyOtp() |
POST /api/v1/auth/verify-email |
Token validation |
supabase.auth.refreshSession() |
POST /api/v1/auth/refresh |
JWT refresh rotation |
supabase.auth.getUser() |
GET /api/v1/auth/me |
JWT middleware |
supabase.auth.getSession() |
(Client-side localStorage) | JWT decode |
supabase.auth.onAuthStateChange() |
(Client-side event) | Estado local |
4.2 Queries de Base de Datos
| Supabase Query | Express/TypeORM Equivalent |
|---|---|
.from('table').select() |
repository.find() |
.from('table').select('*', { count: 'exact' }) |
repository.findAndCount() |
.from('table').insert() |
repository.save() |
.from('table').update() |
repository.update() |
.from('table').delete() |
repository.delete() |
.eq('column', value) |
{ where: { column: value } } |
.in('column', [values]) |
{ where: { column: In([values]) } } |
.order('column', { ascending: true }) |
{ order: { column: 'ASC' } } |
.range(0, 10) |
{ skip: 0, take: 10 } |
.single() |
repository.findOne() |
.rpc('function_name', params) |
Service method / Raw query |
4.3 Realtime
| Supabase Realtime | Express Equivalent |
|---|---|
.channel() |
Socket.io room |
.on('postgres_changes', ...) |
Socket.io events + DB triggers |
.subscribe() |
socket.join(room) |
supabase.removeChannel() |
socket.leave(room) |
4.4 Storage
| Supabase Storage | Express Equivalent |
|---|---|
supabase.storage.from('bucket').upload() |
Multer + S3/MinIO |
supabase.storage.from('bucket').download() |
S3 signed URLs |
supabase.storage.from('bucket').getPublicUrl() |
CDN URL generation |
5. Servicios a Migrar (Frontend)
5.1 AuthService Migration
Archivo origen: src/features/auth/services/authService.ts
Archivo destino: apps/frontend/src/services/auth.service.ts
// ANTES (Supabase)
async signInWithEmail(email: string, password: string) {
const { data, error } = await supabase.auth.signInWithPassword({
email,
password
});
// ...
}
// DESPUES (Express API)
async signInWithEmail(email: string, password: string) {
const response = await api.post('/auth/login', { email, password });
if (response.data.accessToken) {
tokenService.setTokens(
response.data.accessToken,
response.data.refreshToken
);
}
return response.data;
}
5.2 CourseService Migration
Archivo origen: src/features/courses/services/courseService.ts
Archivo destino: apps/frontend/src/services/course.service.ts
// ANTES (Supabase)
async getCourses(filters, sort, page, perPage) {
let query = supabase
.from('education.courses')
.select(`*, instructor:profiles!instructor_id(...)`)
// ...
}
// DESPUES (Express API)
async getCourses(filters, sort, page, perPage) {
const params = new URLSearchParams({
page: String(page),
per_page: String(perPage),
sort_field: sort.field,
sort_dir: sort.direction,
...filters
});
return api.get(`/courses?${params}`);
}
5.3 SignalService Migration
Archivo origen: src/features/trading/services/signalService.ts
Cambios principales:
- Queries → API calls
- Realtime subscriptions → WebSocket
// DESPUES (WebSocket)
subscribeToSignals(botIds: string[], callback: (signal) => void) {
socket.emit('subscribe:signals', { botIds });
socket.on('signal:new', callback);
return () => socket.off('signal:new', callback);
}
6. Estructura de Carpetas Destino
Nota: La estructura del backend ya está implementada. Ver Sección 2 para el estado actual. La siguiente es la estructura objetivo del frontend.
6.1 Frontend (React)
apps/frontend/src/
├── services/
│ ├── api.ts # Axios instance con interceptores
│ ├── auth.service.ts # Migrado de authService.ts
│ ├── course.service.ts # Migrado de courseService.ts
│ ├── trading.service.ts # Consolidado de trading services
│ ├── payment.service.ts # Migrado de stripeService.ts
│ └── socket.service.ts # NUEVO: WebSocket client
├── stores/
│ └── auth.store.ts # Migrar con cambios de API
├── hooks/
│ ├── useAuth.ts # Mantener logica, cambiar imports
│ └── ...
└── lib/
└── socket.ts # Socket.io client config
7. Backend Endpoints a Implementar
7.1 Auth Module (Prioridad 1) - ✅ IMPLEMENTADO
POST /api/v1/auth/register
POST /api/v1/auth/login
POST /api/v1/auth/logout
POST /api/v1/auth/refresh
GET /api/v1/auth/me
GET /api/v1/auth/oauth/:provider/url
POST /api/v1/auth/oauth/:provider
DELETE /api/v1/auth/oauth/:provider
POST /api/v1/auth/phone/send
POST /api/v1/auth/phone/verify
POST /api/v1/auth/2fa/setup
POST /api/v1/auth/2fa/enable
POST /api/v1/auth/2fa/verify
POST /api/v1/auth/2fa/disable
POST /api/v1/auth/forgot-password
POST /api/v1/auth/reset-password
POST /api/v1/auth/verify-email
POST /api/v1/auth/resend-verification
GET /api/v1/auth/sessions
DELETE /api/v1/auth/sessions/:id
DELETE /api/v1/auth/sessions
7.2 Users Module
GET /api/v1/users
GET /api/v1/users/:id
PATCH /api/v1/users/:id
DELETE /api/v1/users/:id
GET /api/v1/users/:id/profile
PATCH /api/v1/users/:id/profile
POST /api/v1/users/:id/avatar
7.3 Courses Module (Prioridad 2)
GET /api/v1/courses
GET /api/v1/courses/featured
GET /api/v1/courses/search
GET /api/v1/courses/:id
GET /api/v1/courses/:slug
POST /api/v1/courses
PATCH /api/v1/courses/:id
DELETE /api/v1/courses/:id
POST /api/v1/courses/:id/publish
POST /api/v1/courses/:id/archive
GET /api/v1/courses/:id/modules
POST /api/v1/courses/:id/modules
GET /api/v1/courses/:id/modules/:mid/lessons
POST /api/v1/courses/:id/enroll
GET /api/v1/courses/:id/progress
POST /api/v1/courses/:id/lessons/:lid/complete
GET /api/v1/courses/:id/certificate
7.4 Trading Module (Prioridad 3)
GET /api/v1/trading/bots
GET /api/v1/trading/bots/featured
GET /api/v1/trading/bots/:id
POST /api/v1/trading/bots/:id/subscribe
DELETE /api/v1/trading/bots/:id/subscribe
GET /api/v1/trading/bots/:id/reviews
POST /api/v1/trading/bots/:id/reviews
GET /api/v1/trading/signals
GET /api/v1/trading/signals/:id
POST /api/v1/trading/signals/:id/execute
GET /api/v1/trading/portfolio
GET /api/v1/trading/positions
GET /api/v1/trading/history
7.5 Payments Module (Prioridad 4)
GET /api/v1/payments
GET /api/v1/payments/:id
POST /api/v1/payments/checkout
GET /api/v1/payments/credits
POST /api/v1/payments/credits/purchase
GET /api/v1/subscriptions
POST /api/v1/subscriptions
DELETE /api/v1/subscriptions/:id
GET /api/v1/invoices
GET /api/v1/invoices/:id/download
POST /api/v1/webhooks/stripe
8. API Client Configuration
8.1 Axios Instance
// apps/frontend/src/services/api.ts
import axios from 'axios';
import { tokenService } from './token.service';
const api = axios.create({
baseURL: import.meta.env.VITE_API_URL || 'http://localhost:3001/api/v1',
headers: {
'Content-Type': 'application/json'
}
});
// Request interceptor - Add auth header
api.interceptors.request.use((config) => {
const token = tokenService.getAccessToken();
if (token) {
config.headers.Authorization = `Bearer ${token}`;
}
return config;
});
// Response interceptor - Handle 401, refresh token
api.interceptors.response.use(
(response) => response,
async (error) => {
const originalRequest = error.config;
if (error.response?.status === 401 && !originalRequest._retry) {
originalRequest._retry = true;
try {
const refreshToken = tokenService.getRefreshToken();
const response = await axios.post('/auth/refresh', { refreshToken });
tokenService.setTokens(
response.data.accessToken,
response.data.refreshToken
);
originalRequest.headers.Authorization = `Bearer ${response.data.accessToken}`;
return api(originalRequest);
} catch (refreshError) {
tokenService.clearTokens();
window.location.href = '/login';
return Promise.reject(refreshError);
}
}
return Promise.reject(error);
}
);
export { api };
8.2 Socket.io Client
// apps/frontend/src/lib/socket.ts
import { io, Socket } from 'socket.io-client';
import { tokenService } from '@/services/token.service';
let socket: Socket | null = null;
export function getSocket(): Socket {
if (!socket) {
socket = io(import.meta.env.VITE_WS_URL || 'ws://localhost:3001', {
auth: {
token: tokenService.getAccessToken()
},
autoConnect: false
});
}
return socket;
}
export function connectSocket(): void {
const s = getSocket();
if (!s.connected) {
s.connect();
}
}
export function disconnectSocket(): void {
if (socket?.connected) {
socket.disconnect();
}
}
9. Orden de Migracion
Fase 1: Autenticacion (Semana 1-2)
- Backend: Implementar auth endpoints
- Frontend: Migrar authService.ts
- Frontend: Migrar tokenService.ts
- Frontend: Actualizar auth.store.ts
- Frontend: Actualizar hooks de auth
- Testing: Flujos completos de auth
Fase 2: Usuarios y Perfiles (Semana 2)
- Backend: Implementar users endpoints
- Frontend: Crear user.service.ts
- Frontend: Actualizar profileService.ts
- Testing: CRUD de usuarios
Fase 3: Cursos/Educacion (Semana 3-4)
- Backend: Implementar courses endpoints
- Frontend: Migrar courseService.ts
- Frontend: Migrar enrollment/progress services
- Frontend: Migrar quiz/certificate services
- Testing: Flujos de cursos
Fase 4: Trading (Semana 4-5)
- Backend: Implementar trading endpoints
- Backend: Implementar WebSocket para signals
- Frontend: Migrar signalService.ts
- Frontend: Migrar botService.ts
- Frontend: Crear socket.service.ts
- Testing: Trading flows + realtime
Fase 5: Pagos (Semana 5-6)
- Backend: Implementar payment endpoints
- Backend: Stripe webhooks
- Frontend: Migrar stripeService.ts
- Frontend: Migrar webhookService.ts
- Testing: Payment flows
10. Consideraciones Especiales
10.1 Manejo de Errores
// Error response standard
interface ApiError {
code: string;
message: string;
field?: string;
details?: any;
}
// En frontend, mapear a mensajes amigables
const errorMessages: Record<string, string> = {
'AUTH_INVALID_CREDENTIALS': 'Email o contrasena incorrectos',
'AUTH_EMAIL_NOT_VERIFIED': 'Debes verificar tu email',
'AUTH_TOKEN_EXPIRED': 'Tu sesion ha expirado',
// ...
};
10.2 Rate Limiting
El backend implementara rate limiting:
- Auth endpoints: 5 requests/15min
- General API: 100 requests/min
- Heavy endpoints: 10 requests/min
10.3 Cache
- Redis para sessions y tokens
- Redis para cache de queries frecuentes
- Frontend: TanStack Query cache
10.4 Variables de Entorno Frontend
# .env
VITE_API_URL=http://localhost:3001/api/v1
VITE_WS_URL=ws://localhost:3001
VITE_STRIPE_PUBLIC_KEY=pk_test_xxx
VITE_GOOGLE_CLIENT_ID=xxx
VITE_FACEBOOK_APP_ID=xxx
11. Testing Strategy
11.1 Backend Tests
- Unit tests para services
- Integration tests para endpoints
- E2E tests para flujos criticos
11.2 Frontend Tests
- Unit tests para services migrados
- Integration tests con MSW (mocks)
- E2E tests con Playwright
12. Rollback Plan
En caso de problemas:
- Mantener Supabase operativo durante migracion
- Feature flags para cambiar entre backends
- Logs detallados para debugging
- Snapshots de base de datos
13. Referencias
Documentacion Interna
- ADR-001: Stack Tecnologico
- ADR-003: Autenticacion Multi-proveedor
- INVENTARIO-STC-PLATFORM-WEB.md
- OQI-001: Fundamentos y Auth
Catálogo de Patrones Reutilizables
Nota: Los patrones de autenticación fueron inspirados en arquitecturas previas y están documentados en el catálogo central para reutilización.
- Catálogo Auth:
shared/catalog/auth/(patrones de autenticación JWT, OAuth, 2FA) - Catálogo Session:
shared/catalog/session-management/(gestión de sesiones) - Patrones Backend:
shared/catalog/backend-patterns/(interceptors, filters, guards)