workspace-v1/core/catalog/websocket
rckrdmrd 66161b1566 feat: Workspace-v1 complete migration with NEXUS v3.4
Sistema NEXUS v3.4 migrado con:

Estructura principal:
- core/orchestration: Sistema SIMCO + CAPVED (27 directivas, 28 perfiles)
- core/catalog: Catalogo de funcionalidades reutilizables
- shared/knowledge-base: Base de conocimiento compartida
- devtools/scripts: Herramientas de desarrollo
- control-plane/registries: Control de servicios y CI/CD
- orchestration/: Configuracion de orquestacion de agentes

Proyectos incluidos (11):
- gamilit (submodule -> GitHub)
- trading-platform (OrbiquanTIA)
- erp-suite con 5 verticales:
  - erp-core, construccion, vidrio-templado
  - mecanicas-diesel, retail, clinicas
- betting-analytics
- inmobiliaria-analytics
- platform_marketing_content
- pos-micro, erp-basico

Configuracion:
- .gitignore completo para Node.js/Python/Docker
- gamilit como submodule (git@github.com:rckrdmrd/gamilit-workspace.git)
- Sistema de puertos estandarizado (3005-3199)

Generated with NEXUS v3.4 Migration System
EPIC-010: Configuracion Git y Repositorios
2026-01-04 03:37:42 -06:00
..
_reference feat: Workspace-v1 complete migration with NEXUS v3.4 2026-01-04 03:37:42 -06:00
IMPLEMENTATION.md feat: Workspace-v1 complete migration with NEXUS v3.4 2026-01-04 03:37:42 -06:00
README.md feat: Workspace-v1 complete migration with NEXUS v3.4 2026-01-04 03:37:42 -06:00

Comunicación WebSocket

Versión: 1.0.0 Origen: projects/gamilit, projects/trading-platform Estado: Producción Última actualización: 2025-12-08


Descripción

Sistema de comunicación en tiempo real via Socket.IO:

  • Conexiones WebSocket autenticadas con JWT
  • Rooms por usuario para mensajes privados
  • Broadcasting para eventos globales
  • Tracking de usuarios conectados
  • Multi-dispositivo (un usuario, múltiples sockets)
  • Integración con sistema de notificaciones

Características

Característica Descripción
Autenticación JWT en handshake
Rooms Por usuario (user:{userId})
Multi-socket Un usuario puede tener múltiples conexiones
Broadcast Eventos a todos los conectados
Typed events Enum de eventos tipados
CORS Configuración flexible
Transports WebSocket + polling fallback

Stack Tecnológico

backend:
  framework: NestJS
  library: Socket.IO
  auth: JWT

frontend:
  library: socket.io-client

packages:
  - "@nestjs/websockets"
  - "@nestjs/platform-socket.io"
  - "socket.io"
  - "socket.io-client"

Dependencias NPM

{
  "@nestjs/websockets": "^10.x",
  "@nestjs/platform-socket.io": "^10.x",
  "socket.io": "^4.x",
  "@nestjs/jwt": "^10.x"
}

Frontend:

{
  "socket.io-client": "^4.x"
}

Tablas Requeridas

No requiere tablas adicionales. Usa autenticación existente (JWT).


Estructura del Módulo

websocket/
├── websocket.module.ts
├── gateways/
│   └── notifications.gateway.ts    # Gateway principal
├── services/
│   └── websocket.service.ts        # API para otros módulos
├── guards/
│   └── ws-jwt.guard.ts             # Autenticación JWT
└── types/
    └── websocket.types.ts          # Eventos y tipos

Arquitectura

┌─────────────────┐      ┌─────────────────┐
│   Frontend      │      │   Frontend      │
│   (User A)      │      │   (User A)      │
│   Device 1      │      │   Device 2      │
└────────┬────────┘      └────────┬────────┘
         │                        │
         │ WebSocket              │ WebSocket
         │                        │
         ▼                        ▼
┌─────────────────────────────────────────────┐
│           Socket.IO Server                  │
│  ┌───────────────────────────────────────┐  │
│  │  Room: user:user-a-uuid               │  │
│  │  - socket-id-1                        │  │
│  │  - socket-id-2                        │  │
│  └───────────────────────────────────────┘  │
│                                             │
│  userSockets Map:                           │
│  user-a-uuid → Set(socket-id-1, socket-id-2)│
└─────────────────────────────────────────────┘

Eventos Disponibles

Eventos del Servidor (Server → Client)

Evento Descripción Payload
authenticated Conexión autenticada { success, userId, email }
error Error en operación { message }
notification:new Nueva notificación { notification, timestamp }
notification:read Notificación leída { notificationId, success }
notification:deleted Notificación eliminada { notificationId }
notification:unread_count Contador actualizado { unreadCount }
achievement:unlocked Logro desbloqueado { achievementId, title, ... }
rank:updated Cambio de rango { newRank, oldRank }
xp:gained XP ganado { amount, source, totalXp }
leaderboard:updated Leaderboard actualizado { leaderboard[] }

Eventos del Cliente (Client → Server)

Evento Descripción Payload
notification:mark_read Marcar como leída { notificationId }

Uso Rápido

1. Emitir desde otro servicio

import { WebSocketService } from '@/modules/websocket';

@Injectable()
export class NotificationService {
  constructor(private readonly wsService: WebSocketService) {}

  async sendNotification(userId: string, notification: any) {
    // Guardar en DB...

    // Emitir en tiempo real
    this.wsService.emitNotificationToUser(userId, notification);
  }
}

2. Frontend - Conectar

import { io, Socket } from 'socket.io-client';

const socket: Socket = io('http://localhost:3000', {
  path: '/socket.io/',
  transports: ['websocket', 'polling'],
  auth: {
    token: localStorage.getItem('accessToken'),
  },
});

// Conexión establecida
socket.on('authenticated', (data) => {
  console.log('Conectado:', data.email);
});

// Escuchar notificaciones
socket.on('notification:new', (data) => {
  showToast(data.notification.title);
  updateNotificationBadge();
});

// Error de autenticación
socket.on('error', (data) => {
  console.error('Error:', data.message);
});

// Desconexión
socket.on('disconnect', (reason) => {
  console.log('Desconectado:', reason);
});

3. Frontend - Enviar eventos

// Marcar notificación como leída
socket.emit('notification:mark_read', { notificationId: 'uuid' });

4. Verificar si usuario está conectado

// En cualquier servicio
const isOnline = this.wsService.isUserConnected(userId);

if (isOnline) {
  // Enviar por WebSocket (instantáneo)
  this.wsService.emitNotificationToUser(userId, notification);
} else {
  // Enviar por email o push (asíncrono)
  await this.emailService.send(userId, notification);
}

Flujo de Autenticación

1. Cliente conecta con token JWT
   │
   ▼
2. WsJwtGuard verifica token
   │
   ├─► Token inválido → disconnect()
   │
   └─► Token válido
       │
       ▼
3. Extraer userId, email, role del payload
   │
   ▼
4. Adjuntar userData al socket
   │
   ▼
5. Join room: user:{userId}
   │
   ▼
6. Registrar en userSockets Map
   │
   ▼
7. Emitir 'authenticated' al cliente

Patrones de Uso

Notificación a un usuario

// El usuario recibe en todos sus dispositivos conectados
this.wsService.emitNotificationToUser(userId, {
  id: notification.id,
  title: notification.title,
  message: notification.message,
});

Notificación a múltiples usuarios

// Ejemplo: notificar a todos los miembros de un grupo
const memberIds = ['uuid1', 'uuid2', 'uuid3'];
this.wsService.emitNotificationToUsers(memberIds, {
  type: 'group_message',
  groupId: group.id,
  message: 'Nuevo mensaje en el grupo',
});

Broadcast global

// Ejemplo: actualización del leaderboard
this.wsService.broadcastLeaderboardUpdate(newLeaderboard);

Eventos de gamificación

// Logro desbloqueado
this.wsService.emitAchievementUnlocked(userId, {
  achievementId: 'ach-001',
  title: 'Primer Login',
  description: 'Has iniciado sesión por primera vez',
  icon: '/icons/first-login.png',
});

// XP ganado
this.wsService.emitXpGained(userId, {
  amount: 100,
  source: 'daily_mission',
  totalXp: 1500,
});

// Subida de rango
this.wsService.emitRankUpdated(userId, {
  oldRank: 'Novato',
  newRank: 'Aprendiz',
  xpRequired: 2000,
});

Variables de Entorno

# WebSocket
WS_PORT=3000                    # Puerto (mismo que HTTP)
WS_PATH=/socket.io/             # Path del endpoint

# CORS
CORS_ORIGIN=http://localhost:3000,http://localhost:5173

# JWT (compartido con auth)
JWT_SECRET=your-secret-key

Frontend React Hook

// hooks/useSocket.ts
import { useEffect, useRef, useCallback } from 'react';
import { io, Socket } from 'socket.io-client';
import { useAuth } from './useAuth';

export function useSocket() {
  const { token } = useAuth();
  const socketRef = useRef<Socket | null>(null);

  useEffect(() => {
    if (!token) return;

    socketRef.current = io(import.meta.env.VITE_API_URL, {
      path: '/socket.io/',
      transports: ['websocket', 'polling'],
      auth: { token },
    });

    socketRef.current.on('connect', () => {
      console.log('Socket connected');
    });

    socketRef.current.on('disconnect', (reason) => {
      console.log('Socket disconnected:', reason);
    });

    return () => {
      socketRef.current?.disconnect();
    };
  }, [token]);

  const on = useCallback((event: string, handler: (data: any) => void) => {
    socketRef.current?.on(event, handler);
    return () => socketRef.current?.off(event, handler);
  }, []);

  const emit = useCallback((event: string, data: any) => {
    socketRef.current?.emit(event, data);
  }, []);

  return { socket: socketRef.current, on, emit };
}

// Uso en componente
function NotificationBell() {
  const { on } = useSocket();
  const [unread, setUnread] = useState(0);

  useEffect(() => {
    return on('notification:unread_count', (data) => {
      setUnread(data.unreadCount);
    });
  }, [on]);

  return <Badge count={unread}><BellIcon /></Badge>;
}

Consideraciones de Escalabilidad

Múltiples instancias (Horizontal Scaling)

Para escalar horizontalmente con múltiples instancias del servidor:

// Usar Redis adapter para Socket.IO
import { createAdapter } from '@socket.io/redis-adapter';
import { createClient } from 'redis';

const pubClient = createClient({ url: process.env.REDIS_URL });
const subClient = pubClient.duplicate();

io.adapter(createAdapter(pubClient, subClient));

Sticky Sessions

Con load balancer, configurar sticky sessions para que un cliente siempre llegue a la misma instancia:

upstream websocket {
    ip_hash;  # Sticky sessions por IP
    server backend1:3000;
    server backend2:3000;
}

Adaptaciones Necesarias

  1. Eventos: Definir eventos específicos de tu aplicación
  2. Rooms: Agregar rooms adicionales (grupos, chats, etc.)
  3. Auth: Ajustar extracción de datos del JWT
  4. Scaling: Configurar Redis adapter si múltiples instancias
  5. CORS: Ajustar orígenes permitidos

Referencias


Mantenido por: Sistema NEXUS Proyectos origen: Gamilit Platform, Trading Platform