Skip to main content
PsicoScan ML está compuesto por dos servicios independientes que se comunican via HTTP:
  1. Frontend Next.js — interfaz de usuario, autenticación, lógica de negocio y acceso a base de datos.
  2. API de clasificación FastAPI — servicio Python que recibe las escalas SENA y devuelve el tipo de caso y semáforo de riesgo.
┌─────────────────────────────────┐        ┌───────────────────────────────┐
│        Frontend Next.js         │        │      ML API (FastAPI)         │
│        localhost:3000           │──────▶ │      localhost:8000           │
│                                 │  HTTP  │                               │
│  App Router + NextAuth + Prisma │        │  POST /api/v1/clasificar      │
└──────────────┬──────────────────┘        └───────────────────────────────┘


   ┌───────────────────────┐
   │   PostgreSQL          │
   │   (Supabase)          │
   └───────────────────────┘

Stack tecnológico

TecnologíaVersiónUso
Next.js16.1.6Framework full-stack (App Router)
React19.2.3Interfaz de usuario
TypeScript5Tipado estático
Tailwind CSS4Estilos
Recharts3.7Gráficas interactivas del dashboard
NextAuth4.24Autenticación JWT con sesiones
Prisma7.4ORM para PostgreSQL
bcryptjs3.0Hash de contraseñas
ExcelJS4.4Exportación de reportes

Estructura del proyecto

Frontend (app/)

El frontend sigue la convención App Router de Next.js con grupos de rutas:
app/
├── (auth)/
│   └── login/              # Página de inicio de sesión
├── (dashboard)/            # Rutas protegidas (requieren sesión activa)
│   ├── layout.tsx          # Sidebar + shell compartido
│   ├── dashboard/          # Panel principal con gráficas de riesgo
│   ├── estudiantes/        # Tabla de todos los estudiantes
│   ├── estudiantes/[id]/   # Expediente individual del estudiante
│   ├── cuestionario/       # Aplicación digital del SENA (en desarrollo)
│   ├── citas/              # Gestión de citas
│   ├── respuestas/         # Respuestas crudas del cuestionario
│   ├── expediente/         # Vista de expediente clínico
│   ├── historico/          # Histórico de tamizajes
│   └── usuarios/           # Gestión de usuarios (solo ADMIN)
└── api/
    └── auth/               # Endpoints NextAuth (signIn, session, CSRF)

Componentes (components/)

components/
├── dashboard/              # Gráficas y tarjetas del panel principal
├── semaforo/               # Badge de nivel de riesgo (VERDE/AMARILLO/ROJO/ROJO_URGENTE)
└── ui/                     # Sidebar, botones y componentes base

Capa lib (lib/)

lib/
├── auth.ts                 # Configuración de NextAuth (providers, callbacks, rol en JWT)
├── db.ts                   # Singleton del cliente Prisma
├── types.ts                # Tipos TypeScript, colores y labels del semáforo
├── enums.ts                # Enums Rol, Semaforo, TipoCaso (seguros para Client Components)
└── data/mock.ts            # 5 casos tipo para desarrollo sin base de datos

ML API (ml-api/)

ml-api/
├── main.py                 # App FastAPI, CORS, router mounting
├── routers/
│   └── clasificacion.py    # POST /api/v1/clasificar, GET /api/v1/modelo/info
├── schemas/
│   └── tamizaje.py         # Modelos Pydantic TamizajeInput / TamizajeOutput
├── services/
│   └── clasificador.py     # Motor de clasificación (reglas + XGBoost)
└── requirements.txt

Esquema de base de datos

El esquema completo está definido en prisma/schema.prisma. Los modelos principales son:
ModeloDescripción
UsuarioCuenta de acceso con rol (ESTUDIANTE, PSICOLOGO, ORIENTADOR, DIRECTOR, ADMIN)
EstudiantePerfil del alumno con CURP, grado, grupo y token de encuesta único
TamizajeResultado de una aplicación SENA: 31 escalas en puntuación T + tipoCaso + semaforo + ítems críticos
CitaCita agendada para un estudiante con estado PENDIENTE/CONFIRMADA/COMPLETADA/CANCELADA
ExpedienteClinicoExpediente clínico con motivo de consulta, antecedentes, diagnóstico y plan de intervención
SesionRegistro de sesión clínica vinculada a una cita y al expediente del estudiante
CanalizacionDerivación a institución externa con estado de seguimiento
HistoricoSENACorpus de tamizajes históricos usado para entrenamiento del modelo XGBoost
EntrenamientoMLRegistro de cada ciclo de entrenamiento con métricas (accuracy, CV, feature importance)

Motor de clasificación

El servicio ClasificadorML en services/clasificador.py aplica la siguiente lógica al recibir un TamizajeInput:
  1. Evalúa primero las escalas de control (INC, NEG, POS) para detectar inconsistencias o sesgos de respuesta.
  2. Si las escalas de control son válidas, evalúa el índice global GLO y los ítems críticos para determinar el nivel de riesgo.
  3. Devuelve un TamizajeOutput con tipo_caso, semaforo, confianza y observaciones.
Motor de reglas vs. modelo XGBoost. En la versión actual (0.1.0-reglas), el endpoint GET /api/v1/modelo/info reporta "modelo_cargado": false. Esto indica que el sistema está operando con el motor de reglas heurísticas como fallback. El modelo XGBoost se activará automáticamente una vez entrenado con el dataset real de ~2,000 tamizajes históricos y guardado como artefacto. No es necesario ningún cambio en el frontend ni en los endpoints.

Flujo de datos de un tamizaje

Estudiante responde SENA


 Frontend captura 31 escalas T


 POST /api/v1/clasificar  ──▶  Motor de reglas / XGBoost
        │                              │
        │          ◀────────────────── tipo_caso + semáforo + confianza

 Prisma guarda Tamizaje en PostgreSQL


 Dashboard actualiza distribución de riesgo

Build docs developers (and LLMs) love