Skip to content

DOSW2025/wise_ia

Repository files navigation

ECIWISE RAG Service

Version Node License Azure Prisma PostgreSQL

Un servicio inteligente para analizar documentos académicos y generar resúmenes útiles.

Swagger UI - Documentación InteractivaCaracterísticasArquitecturaInstalaciónAPIDespliegue


Descripción General

ECIWISE RAG Service es un sistema diseñado para analizar documentos académicos de manera automatizada utilizando inteligencia artificial avanzada. Su objetivo principal es procesar archivos PDF, extraer información clave como temas, etiquetas y resúmenes, y almacenarla de forma organizada para facilitar su consulta posterior.

El servicio utiliza un enfoque eficiente para manejar las solicitudes de análisis. Los documentos se procesan en varias etapas: primero se suben a un almacenamiento seguro, luego se analizan con modelos de lenguaje natural de Google Gemini, y finalmente se guardan los resultados en una base de datos para su uso futuro.

Principales Componentes:

  • Procesamiento de Mensajes: Azure Service Bus gestiona las solicitudes de análisis y asegura que cada tarea se procese de manera ordenada.
  • Análisis Inteligente: Google Gemini se encarga de interpretar el contenido de los documentos y generar resúmenes y etiquetas relevantes.
  • Almacenamiento Seguro: Los archivos se guardan en Azure Blob Storage, mientras que los datos estructurados, como resúmenes y metadatos, se almacenan en PostgreSQL.
  • API Accesible: Una API basada en Express.js permite a los usuarios interactuar con el sistema para subir documentos y consultar resultados.

Este sistema está diseñado para ser confiable, eficiente y fácil de integrar con otras aplicaciones, ofreciendo una solución práctica para gestionar grandes volúmenes de información académica.


Arquitectura del Sistema

alt text

Explicación de los Componentes:

  • Azure Service Bus: Es un sistema de colas que organiza las solicitudes de análisis para que se procesen una por una, evitando sobrecargas.
  • Express API: Es la puerta de entrada al sistema. Aquí los usuarios pueden subir documentos y consultar resultados a través de endpoints.
  • Google Gemini 2.0: Es un modelo de inteligencia artificial que analiza los documentos, extrae información clave y genera resúmenes.
  • Azure Blob Storage: Un lugar seguro para guardar los archivos PDF subidos por los usuarios.
  • PostgreSQL + Prisma ORM: Una base de datos que almacena los resultados del análisis, como resúmenes y etiquetas, para que puedan ser consultados fácilmente.

Componentes Principales:

  • Capa de Ingesta: Azure Service Bus para procesamiento asíncrono mediante colas
  • Capa de Aplicación: Express.js con arquitectura de microservicios
  • Capa de IA: Integración con Google Gemini 2.0 para NLP y generación de resúmenes
  • Capa de Persistencia: PostgreSQL con Prisma ORM para gestión de datos estructurados
  • Capa de Almacenamiento: Azure Blob Storage para archivos binarios

Características Principales

Procesamiento de Documentos

  • Extracción de Texto: Convierte documentos PDF en texto que puede ser analizado.
  • Análisis Semántico: Clasifica los documentos según su contenido y genera etiquetas relevantes.
  • Generación de Resúmenes: Crea resúmenes breves y útiles para cada documento.

Infraestructura y Escalabilidad

  • Procesamiento Asíncrono: Maneja múltiples solicitudes al mismo tiempo sin afectar el rendimiento.
  • Almacenamiento Seguro: Utiliza Azure Blob Storage para guardar archivos y PostgreSQL para datos estructurados.
  • Gestión de Errores: Reintenta automáticamente las operaciones en caso de fallos temporales.

API y Observabilidad

  • Documentación Interactiva: Incluye Swagger UI para explorar y probar los endpoints.
  • Monitoreo: Proporciona endpoints de salud para verificar el estado del sistema.
  • Logs Detallados: Registra todas las operaciones importantes para facilitar la depuración.

Stack Tecnológico

Runtime y Framework

Componente Tecnología Versión Propósito
Runtime Node.js 20.x - 22.x Entorno de ejecución JavaScript
Package Manager npm ≥10.0.0 Gestión de dependencias
Framework Web Express.js ^4.21.2 API RESTful y routing
Language ECMAScript Modules ES2022+ Módulos nativos con import/export

Persistencia y Datos

Componente Tecnología Versión Propósito
ORM Prisma 6.0.1 Query builder type-safe y migraciones
Base de Datos PostgreSQL 13+ Almacenamiento relacional de metadatos
Mensajería Azure Service Bus ^7.9.0 Sistema de colas para procesamiento asíncrono
Blob Storage Azure Blob Storage ^12.25.0 Almacenamiento de archivos PDF

Inteligencia Artificial

Componente Tecnología Versión Propósito
LLM SDK @google/generative-ai ^0.21.0 Cliente para Google Gemini API
Modelo Chat gemini-2.0-flash Latest Conversación y búsqueda semántica
Modelo Análisis gemini-2.0-flash-lite Latest Análisis de documentos con JSON schema
PDF Parser pdf-parse ^1.1.1 Extracción de texto de documentos PDF

Desarrollo y Testing

Componente Tecnología Versión Propósito
Testing Framework Jest ^30.2.0 Tests unitarios e integración
HTTP Testing Supertest ^7.1.4 Tests de endpoints HTTP
Dev Server Nodemon ^3.1.9 Hot-reload en desarrollo
Documentación Swagger UI Express ^5.0.1 Documentación interactiva de API

Utilidades y Seguridad

Componente Tecnología Versión Propósito
Logging Winston ^3.17.0 Logging estructurado con transportes
Validation Zod ^3.24.1 Validación de esquemas runtime
Security Headers Helmet ^8.0.0 Headers de seguridad HTTP
CORS cors ^2.8.5 Cross-Origin Resource Sharing
File Upload Multer ^1.4.5-lts.1 Manejo de multipart/form-data

Instalación

Requisitos Previos

Software Requerido:

  • Node.js 20.x o superior (LTS recomendado)
  • PostgreSQL 13+ con extensiones habilitadas
  • npm 10.0.0 o superior
  • Git para control de versiones

Cuentas y Credenciales:

  • Suscripción de Azure con:
    • Azure Service Bus namespace creado
    • Azure Storage Account con contenedor configurado
  • Google Cloud Project con:
    • Gemini API habilitada
    • API Key generada con permisos de generativelanguage.models.generateContent

Configuración Local

# Clonar el repositorio
git clone https://github.com/DOSW2025/wise_ia.git
cd wise_ia

# Instalar dependencias
npm install

# Copiar archivo de configuración
cp .env.example .env

# Editar variables de entorno (ver sección siguiente)
nano .env  # o usar editor preferido

# Generar cliente de Prisma
npx prisma generate

# Ejecutar migraciones de base de datos
npx prisma migrate deploy

# Verificar configuración con smoke test
npm run smoke:gemini

# Iniciar servidor en modo desarrollo
npm run dev

# O en modo producción
npm start

Scripts Disponibles

{
  "start": "npx prisma generate && node src/server.js",
  "dev": "nodemon src/server.js",
  "test": "node --experimental-vm-modules node_modules/jest/bin/jest.js",
  "test:cov": "node --experimental-vm-modules node_modules/jest/bin/jest.js --coverage",
  "smoke:gemini": "node scripts/smoke-gemini.mjs",
  "prisma:generate": "npx prisma generate",
  "prisma:migrate": "npx prisma migrate deploy",
  "prisma:studio": "npx prisma studio"
}

Configuración

Variables de Entorno

Crear archivo .env en la raíz del proyecto:

# ===========================================
# DATABASE CONFIGURATION
# ===========================================
# PostgreSQL connection string
# Formato: postgresql://[user]:[password]@[host]:[port]/[database]?[params]
# IMPORTANTE: Prisma 6.x requiere 'postgresql://' (NO 'postgres://')
DATABASE_URL="postgresql://user:password@localhost:5432/eciwise?sslmode=prefer&schema=public"

# ===========================================
# AZURE SERVICE BUS
# ===========================================
# Connection string desde Azure Portal > Service Bus > Shared access policies
SERVICE_BUS_CONNECTION_STRING="Endpoint=sb://your-namespace.servicebus.windows.net/;SharedAccessKeyName=RootManageSharedAccessKey;SharedAccessKey=your-key"

# Nombres de colas (deben existir previamente en Azure)
SERVICE_BUS_INPUT_QUEUE="material.process"
SERVICE_BUS_OUTPUT_QUEUE="material.responses"

# Configuración de rendimiento
SERVICE_BUS_MAX_CONCURRENCY="1"                    # Mensajes procesados en paralelo
SERVICE_BUS_MAX_RETRIES="3"                        # Reintentos en caso de fallo
SERVICE_BUS_RETRY_DELAY_MS="1000"                  # Delay entre reintentos (ms)
SERVICE_BUS_AUTO_COMPLETE="false"                  # Completado manual de mensajes
SERVICE_BUS_MAX_LOCK_RENEW_MS="300000"            # Renovación de lock (5 min)

# ===========================================
# AZURE BLOB STORAGE
# ===========================================
# Connection string desde Azure Portal > Storage Account > Access keys
AZURE_STORAGE_CONNECTION_STRING="DefaultEndpointsProtocol=https;AccountName=your-account;AccountKey=your-key;EndpointSuffix=core.windows.net"

# Configuración de almacenamiento
AZURE_STORAGE_ACCOUNT_NAME="eciwise"
AZURE_STORAGE_CONTAINER_NAME="academic-documents"

# ===========================================
# GOOGLE GEMINI API
# ===========================================
# API Key desde Google AI Studio (https://makersuite.google.com/app/apikey)
GOOGLE_GEMINI_API_KEY="AIzaSy..."

# Modelos a utilizar (opcional, valores por defecto)
GEMINI_CHAT_MODEL="gemini-2.0-flash"
GEMINI_ANALYSIS_MODEL="gemini-2.0-flash-lite"

# ===========================================
# SERVER CONFIGURATION
# ===========================================
PORT="8080"
NODE_ENV="production"  # o "development"

# ===========================================
# FILE UPLOAD LIMITS
# ===========================================
MAX_FILE_SIZE_MB="10"
ALLOWED_FILE_TYPES="application/pdf"

Configuración de Prisma Schema

Configuración de Prisma Schema

El modelo de datos utiliza PostgreSQL con Prisma ORM 6.0.1. La entidad principal Summary almacena metadatos extraídos de documentos PDF mediante análisis con Gemini.

Estructura del Schema:

model Summary {
  id            String   @id @default(uuid())
  correlationId String   @unique
  docId         String   @unique
  fileName      String
  summary       String   @db.Text
  materia       String
  tema          String
  tags          String
  createdAt     DateTime @default(now())
  updatedAt     DateTime @updatedAt

  @@index([correlationId])
  @@index([docId])
  @@index([materia, tema])
}

Características Clave:

  • Identificadores únicos para correlación de mensajes asíncronos
  • Campo docId con estado PENDING_ hasta confirmación del backend principal
  • Índices compuestos optimizados para búsquedas por materia/tema
  • Timestamps automáticos para auditoría

Flujo de Procesamiento

Arquitectura de Mensajería

El sistema implementa un patrón de procesamiento asíncrono basado en dos colas:

  1. Cola de Entrada (material.process): Recibe solicitudes de análisis
  2. Cola de Salida (material.responses): Publica resultados procesados

Diagrama de Secuencia

alt text

Paso 1: Mensaje de Análisis

Cola: material.process
Action: analyze

{
  "action": "analyze",
  "fileUrl": "https://storageaccount.blob.core.windows.net/academic-documents/uuid.pdf",
  "fileName": "matematicas-algebra-lineal.pdf"
}

Headers:

{
  "correlationId": "550e8400-e29b-41d4-a716-446655440000",
  "contentType": "application/json"
}

Paso 2: Procesamiento con Gemini

Pipeline de Análisis:

  1. Descarga del archivo desde Azure Blob Storage
  2. Extracción de texto con pdf-parse (límite 30,000 caracteres)
  3. Envío a Gemini 2.0 Flash Lite con schema JSON estructurado
  4. Validación y parsing de respuesta

Sistema de Prompts:

El servicio utiliza prompts especializados que clasifican documentos académicos según criterios predefinidos (relevancia universitaria, dominio educativo, estructura formal). Gemini responde con un schema JSON que incluye validación booleana, clasificación taxonomica (materia/tema), array de etiquetas descriptivas, y resumen de 500 caracteres máximo.

Paso 3: Persistencia en PostgreSQL

Operación: INSERT en tabla Summary

INSERT INTO "Summary" (
  "id", 
  "correlationId", 
  "docId", 
  "fileName", 
  "summary", 
  "materia", 
  "tema", 
  "tags",
  "createdAt",
  "updatedAt"
) VALUES (
  gen_random_uuid(),
  '550e8400-e29b-41d4-a716-446655440000',
  'PENDING_550e8400-e29b-41d4-a716-446655440000',
  'matematicas-algebra-lineal.pdf',
  'Documento que introduce conceptos fundamentales de álgebra lineal...',
  'Matemáticas',
  'Álgebra Lineal',
  '["matrices","vectores","transformaciones lineales","espacios vectoriales"]',
  NOW(),
  NOW()
);

Nota: El campo docId se inicializa con prefijo PENDING_ hasta recibir confirmación del backend principal.

Paso 4: Publicación de Resultado

Cola: material.responses
Message Body:

{
  "correlationId": "550e8400-e29b-41d4-a716-446655440000",
  "valid": true,
  "materia": "Matemáticas",
  "tema": "Álgebra Lineal",
  "tags": ["matrices", "vectores", "transformaciones lineales", "espacios vectoriales"],
  "summary": "Documento que introduce conceptos fundamentales de álgebra lineal incluyendo espacios vectoriales, transformaciones lineales, matrices y sus propiedades algebraicas."
}

Headers:

{
  "correlationId": "550e8400-e29b-41d4-a716-446655440000",
  "subject": "analysis",
  "contentType": "application/json"
}

Paso 5: Confirmación Final

Cola: material.process
Action: save

{
  "action": "save",
  "fileName": "matematicas-algebra-lineal.pdf"
}

Operación en Base de Datos:

UPDATE "Summary"
SET 
  "docId" = '550e8400-e29b-41d4-a716-446655440000',
  "updatedAt" = NOW()
WHERE 
  "correlationId" = '550e8400-e29b-41d4-a716-446655440000';

Comportamiento: No se publica respuesta en la cola de salida (código HTTP 204).


API Endpoints

Documentación Interactiva

Swagger UI: http://localhost:8080/api-docs

La documentación incluye:

  • Esquemas de request/response
  • Ejemplos de payloads
  • Códigos de estado HTTP
  • Try-it-out interactivo

Health Check

GET /health

Response 200 OK:

{
  "status": "healthy",
  "timestamp": "2025-12-05T14:23:45.678Z",
  "uptime": 3600,
  "services": {
    "database": "connected",
    "serviceBus": "connected",
    "gemini": "available"
  },
  "version": "1.0.0"
}

Response 503 Service Unavailable:

{
  "status": "degraded",
  "timestamp": "2025-12-05T14:23:45.678Z",
  "services": {
    "database": "connected",
    "serviceBus": "disconnected",
    "gemini": "available"
  },
  "errors": [
    {
      "service": "serviceBus",
      "message": "Connection timeout after 30s"
    }
  ]
}

Chat Académico

POST /api/chat
Content-Type: application/json

{
  "query": "¿Qué documentos tengo sobre álgebra lineal?",
  "chatId": "session-123"
}

Response 200 OK:

{
  "answer": "Encontré 3 documentos sobre álgebra lineal en la base de datos: ...",
  "relatedDocuments": [
    {
      "docId": "550e8400-e29b-41d4-a716-446655440000",
      "fileName": "matematicas-algebra-lineal.pdf",
      "materia": "Matemáticas",
      "tema": "Álgebra Lineal"
    }
  ],
  "timestamp": "2025-12-05T14:25:30.123Z"
}

Recomendaciones Personalizadas

POST /api/chat/recommendations
Content-Type: application/json

{
  "materias": ["Matemáticas", "Física"],
  "temas": ["Álgebra", "Mecánica"],
  "descripcion": "Necesito material sobre transformaciones lineales aplicadas a física"
}

Response 200 OK:

{
  "message": "Basado en tu búsqueda, te recomiendo los siguientes documentos...",
  "recommendations": [
    {
      "docId": "uuid-1",
      "fileName": "algebra-fisica-aplicada.pdf",
      "materia": "Matemáticas",
      "tema": "Álgebra Lineal",
      "summary": "Aplicaciones de transformaciones lineales en mecánica clásica..."
    }
  ],
  "matchedKeywords": ["transformaciones", "lineales", "física"]
}

Testing

Estructura de Pruebas

src/services/__tests__/
├── gemini.service.test.js         # 15 tests - Integración con Gemini API
├── serviceBus.service.test.js     # 12 tests - Procesamiento de mensajes
└── prisma.service.test.js         # 8 tests - Operaciones de base de datos

coverage/
├── lcov.info                      # Cobertura en formato LCOV
└── lcov-report/                   # Reporte HTML de cobertura

Ejecutar Suite de Tests

# Tests unitarios completos
npm test

# Tests con reporte de cobertura
npm run test:cov

# Tests en modo watch (desarrollo)
npm test -- --watch

# Tests específicos por archivo
npm test -- gemini.service.test.js

# Tests con output verbose
npm test -- --verbose

# Smoke test de conectividad Gemini
npm run smoke:gemini

Configuración de Jest

Características:

  • Test environment: Node.js (no DOM)
  • Soporte nativo para ES Modules
  • Coverage thresholds: 70% branches, 75% functions, 80% lines/statements
  • Test pattern: **/__tests__/**/*.test.js

Coverage Exclusions: src/server.js, src/config/*.js, archivos de test

Cobertura de Tests

Alcance:

  • Procesamiento completo de análisis (PDF → Gemini → PostgreSQL → Service Bus)
  • Manejo de documentos válidos e inválidos
  • Retry logic para errores transitorios de APIs externas
  • Timeout handling y validación de schemas con Zod
  • Integration tests con mocks de servicios Azure y Gemini

Comandos:

npm test              # Suite completa
npm run test:cov      # Con reporte de cobertura
npm run smoke:gemini  # Smoke test de conectividad Gemini

Configuración Inicial del App Service Plan (si no existe)

az appservice plan create
--name "${APP_NAME}-plan"
--resource-group $RESOURCE_GROUP
--location $LOCATION
--is-linux
--sku B1

Crear Web App

az webapp create
--name $APP_NAME
--resource-group $RESOURCE_GROUP
--plan "${APP_NAME}-plan"
--runtime $RUNTIME

Configurar startup command

az webapp config set
--resource-group $RESOURCE_GROUP
--name $APP_NAME
--startup-file "npm start"

Habilitar logging

az webapp log config
--resource-group $RESOURCE_GROUP
--name $APP_NAME
--application-logging filesystem
--detailed-error-messages true
--failed-request-tracing true
--web-server-logging filesystem


#### Configuración de Variables de Entorno

```bash
az webapp config appsettings set \
  --resource-group $RESOURCE_GROUP \
  --name $APP_NAME \
  --settings \
    NODE_ENV="production" \
    PORT="8080" \
    SCM_DO_BUILD_DURING_DEPLOYMENT="true" \
    ENABLE_ORYX_BUILD="true" \
    PRE_BUILD_COMMAND="npx prisma generate" \
    POST_BUILD_COMMAND="npx prisma migrate deploy" \
    DATABASE_URL="postgresql://user@host:5432/db?sslmode=require" \
    SERVICE_BUS_CONNECTION_STRING="Endpoint=sb://namespace.servicebus.windows.net/..." \
    SERVICE_BUS_INPUT_QUEUE="material.process" \
    SERVICE_BUS_OUTPUT_QUEUE="material.responses" \
    AZURE_STORAGE_CONNECTION_STRING="DefaultEndpointsProtocol=https;..." \
    AZURE_STORAGE_ACCOUNT_NAME="storageaccount" \
    AZURE_STORAGE_CONTAINER_NAME="academic-documents" \
    GOOGLE_GEMINI_API_KEY="AIzaSy..."

Importante: Usar Azure Key Vault para secrets sensibles en producción:

# Habilitar managed identity
az webapp identity assign \
  --resource-group $RESOURCE_GROUP \
  --name $APP_NAME

# Obtener el principal ID
PRINCIPAL_ID=$(az webapp identity show \
  --resource-group $RESOURCE_GROUP \
  --name $APP_NAME \
  --query principalId \
  --output tsv)

# Dar permisos al Key Vault
az keyvault set-policy \
  --name your-keyvault \
  --object-id $PRINCIPAL_ID \
  --secret-permissions get list

# Referenciar secrets
az webapp config appsettings set \
  --resource-group $RESOURCE_GROUP \
  --name $APP_NAME \
  --settings \
    DATABASE_URL="@Microsoft.KeyVault(SecretUri=https://vault.vault.azure.net/secrets/db-url/)" \
    GOOGLE_GEMINI_API_KEY="@Microsoft.KeyVault(SecretUri=https://vault.vault.azure.net/secrets/gemini-key/)"

Despliegue desde GitHub

# Opción 1: GitHub Actions (recomendado)
az webapp deployment github-actions add \
  --resource-group $RESOURCE_GROUP \
  --name $APP_NAME \
  --repo "DOSW2025/wise_ia" \
  --branch "main" \
  --login-with-github

# Opción 2: Local Git
az webapp deployment source config-local-git \
  --resource-group $RESOURCE_GROUP \
  --name $APP_NAME

# Obtener URL del repositorio Git
GIT_URL=$(az webapp deployment source config-local-git \
  --resource-group $RESOURCE_GROUP \
  --name $APP_NAME \
  --query url \
  --output tsv)

# Agregar remote y push
git remote add azure $GIT_URL
git push azure main:master

# Opción 3: Deployment Center (ZIP)
az webapp deploy \
  --resource-group $RESOURCE_GROUP \
  --name $APP_NAME \
  --src-path ./dist.zip \
  --type zip

Configuración de Networking

Configuración Inicial del App Service

Comandos de Setup:

# Crear App Service Plan y Web App
az appservice plan create --name "plan-name" --resource-group ia_test --is-linux --sku B1
az webapp create --name eciwiseIaTest --resource-group ia_test --runtime "NODE:22-lts"

# Configurar startup y logging
az webapp config set --startup-file "npm start"
az webapp log config --application-logging filesystem --detailed-error-messages true

Variables de Entorno Críticas:

  • DATABASE_URL: PostgreSQL connection string con postgresql:// protocol
  • SERVICE_BUS_CONNECTION_STRING: Endpoint con SharedAccessKey
  • GOOGLE_GEMINI_API_KEY: API key desde Google AI Studio
  • SCM_DO_BUILD_DURING_DEPLOYMENT=true: Ejecuta build en Azurewebapp vnet-integration remove
    --resource-group $RESOURCE_GROUP
    --name $APP_NAME

#### Verificación de Conectividad

```bash
# Abrir SSH en App Service
az webapp ssh \
  --resource-group $RESOURCE_GROUP \
  --name $APP_NAME

# Dentro del contenedor SSH, ejecutar:

# Test 1: Verificar conectividad a Gemini API
curl -v "https://generativelanguage.googleapis.com/v1beta/models/gemini-2.0-flash:generateContent?key=$GOOGLE_GEMINI_API_KEY" \
  -H "Content-Type: application/json" \
  -d '{"contents":[{"parts":[{"text":"ping"}]}]}'

# Test 2: Verificar conectividad a PostgreSQL
npx prisma db execute --stdin <<< "SELECT 1;"

# Test 3: Verificar conectividad a Service Bus
az servicebus queue show \
  --resource-group $RESOURCE_GROUP \
  --namespace-name your-namespace \
  --name material.process

Configuración de Variables de Entorno

Configure las siguientes variables mediante az webapp config appsettings set o directamente en el portal de Azure:

Aplicación:

  • NODE_ENV=production
  • PORT=8080
  • DATABASE_URL=postgresql://... (formato Prisma 6.x con postgresql://)
  • GOOGLE_GEMINI_API_KEY=AIza...

Azure Services:

  • SERVICE_BUS_CONNECTION_STRING y queues (material.process, material.responses)
  • AZURE_STORAGE_CONNECTION_STRING y container name

Build Configuration:

  • SCM_DO_BUILD_DURING_DEPLOYMENT=true
  • PRE_BUILD_COMMAND="npx prisma generate"

Seguridad Recomendada:

Utilice Azure Key Vault con Managed Identity para secrets sensibles. Habilite la identidad del App Service y referencie secrets con:

DATABASE_URL="@Microsoft.KeyVault(SecretUri=https://vault.vault.azure.net/secrets/db-url/)"
```-condition "Percentage CPU < 30 avg 5m" \
  --scale in 1

Connection Pooling (Prisma)

Configurar en código (prisma.service.js):

import { PrismaClient } from '@prisma/client';

const prisma = new PrismaClient({
  datasources: {
    db: {
      url: process.env.DATABASE_URL,
    },
  },
  log: ['error', 'warn'],
  // Connection pool configuration
  // Recomendado: (num_cpu_cores * 2) + effective_spindle_count
  // Para App Service B1 (1 core): 2-5 conexiones
  // Para App Service P1V2 (2 cores): 5-10 conexiones
});

// Graceful shutdown
process.on('SIGTERM', async () => {
  await prisma.$disconnect();
  process.exit(0);
});
#### Despliegue desde GitHub

**Opciones de Despliegue:**

1. **GitHub Actions** (recomendado): Integración automática con workflows CI/CD
2. **Local Git**: Push directo desde repositorio local mediante remote de Azure
3. **ZIP Deploy**: Deployment manual desde archivo comprimido

Configure el despliegue mediante `az webapp deployment` o directamente desde el Deployment Center del portal de Azure.-output tsv)

# Configurar en App Service
az webapp config.appsettings.set \
  --resource-group $RESOURCE_GROUP \
  --name $APP_NAME \
  --settings APPINSIGHTS_INSTRUMENTATIONKEY=$INSTRUMENTATION_KEY

Configuración:

Habilitar mediante variable APPINSIGHTS_INSTRUMENTATIONKEY. El SDK autoconfigura:

  • Dependency correlation (distributed tracing W3C)
  • Auto-collection de requests, performance, exceptions, dependencies
  • Live metrics streaming
  • Disk retry caching para reliability

Custom Tracking:

  • trackEvent(): Eventos de negocio (DocumentAnalyzed)
  • trackMetric(): Métricas de rendimiento (GeminiResponseTime)
  • trackDependency(): Llamadas externas (Gemini API, PostgreSQL)
  • trackException(): Errores con stack trace

Alertas Críticas

Métrica Threshold Window Descripción
Http5xx avg > 5% 5min Error rate excede umbral
ResponseTime avg > 5000ms 5min Latencia de respuesta alta
CpuPercentage avg > 80% 10min Uso de CPU crítico
MemoryPercentage avg > 85% 10min Presión de memoria

Configurar via az monitor metrics alert create con actions para notificaciones (email, webhook, Logic App).

Structured Logging con Winston

Configuración:

  • Formato JSON con timestamps ISO 8601
  • Metadata de servicio (nombre, versión, environment)
  • Transports: Console (desarrollo), Application Insights (producción)
  • Niveles configurables via LOG_LEVEL env var

Contexto de Logging: Todos los logs incluyen correlationId para trazabilidad de requests asíncronos, metadatos de archivo (nombre, tamaño), y stack traces completos para errores.


Seguridad

Mejores Prácticas Implementadas

1. Secrets Management

Azure Key Vault Integration:

Almacenar secrets en Key Vault y referenciarlos en App Settings mediante sintaxis:

@Microsoft.KeyVault(SecretUri=https://vault-name.vault.azure.net/secrets/secret-name/)

Habilitar Managed Identity en App Service y otorgar permisos Get y List en Key Vault policies.

2. Network Security

Headers de Seguridad con Helmet:

  • Content Security Policy (CSP)
  • HTTP Strict Transport Security (HSTS)
  • X-Frame-Options: DENY
  • X-Content-Type-Options: nosniff

Custom Metrics

Application Insights permite tracking de eventos personalizados, métricas de rendimiento, y dependencias externas. El servicio registra automáticamente:

  • Eventos: Documentos analizados con metadatos (materia, tema, validez)
  • Métricas: Tiempo de respuesta de Gemini API, latencia de Service Bus
  • Dependencias: Llamadas HTTP a Gemini, queries a PostgreSQL, operaciones de Blob Storage
  • Excepciones: Errores con stack trace completo para debugging

4. Rate Limiting

Implementación con express-rate-limit:

import rateLimit from 'express-rate-limit';

export const apiLimiter = rateLimit({
  windowMs: 15 * 60 * 1000, // 15 minutes
  max: 100, // limit each IP to 100 requests per windowMs
  message: 'Too many requests from this IP, please try again later.',
  standardHeaders: true,
  legacyHeaders: false,
});

export const chatLimiter = rateLimit({
  windowMs: 1 * 60 * 1000, // 1 minute
  max: 10, // 10 requests per minute
  message: 'Too many chat requests, please slow down.',
});

// src/server.js
import { apiLimiter, chatLimiter } from './middleware/rateLimit.middleware.js';

app.use('/api/', apiLimiter);
app.use('/api/chat', chatLimiter);

5. SQL Injection Prevention

Prisma ORM previene SQL injection automáticamente mediante prepared statements:

// SEGURO (Prisma escapa automáticamente)
const summaries = await prisma.summary.findMany({
  where: {
    materia: userInput  // Prisma maneja el escaping
  }
});

// EVITAR raw queries cuando sea posible
const result = await prisma.$queryRaw`
  SELECT * FROM "Summary" 
  WHERE materia = ${userInput}  // Usa template literals parameterizados
`;

Troubleshooting

Error: Gemini NetworkError

Error Code:

TypeError: NetworkError when attempting to fetch resource
    at callGeminiREST (gemini.service.js:320:15)

Diagnóstico:

# Verificar conectividad desde App Service SSH
az webapp ssh --resource-group ia_test --name eciwiseIaTest
curl -v https://generativelanguage.googleapis.com

Causas y Resolución:

Causa Código Error Solución
VNet sin NAT Gateway ETIMEDOUT / ECONNREFUSED Crear NAT Gateway en subnet
WEBSITE_VNET_ROUTE_ALL=1 Connection refused Configurar variable a 0
NSG bloqueando egress Connection timeout Permitir regla salida puerto 443

Solución 1: Configurar NAT Gateway

az network nat gateway create --resource-group ia_test --name eciwise-nat --public-ip-addresses eciwise-nat-pip
az network vnet subnet update --vnet-name eciwise-vnet --name app-subnet --nat-gateway eciwise-nat

Solución 2: Deshabilitar VNet Route All

az webapp config appsettings set --name eciwiseIaTest --settings WEBSITE_VNET_ROUTE_ALL="0"

Error: Prisma P1012 (Invalid Protocol)

Error Code:

PrismaClientInitializationError: Invalid connection string: URL protocol "postgres" is not supported
Error code: P1012

Causa: Prisma 6.x requiere protocolo postgresql:// (no postgres://)

Resolución:

# Formato requerido para Prisma 6.x+
DATABASE_URL="postgresql://user:pass@host:5432/db?sslmode=require"

az webapp config appsettings set --name eciwiseIaTest --settings DATABASE_URL="postgresql://..."

2. Network Security

Implementaciones:

  • Helmet: Headers de seguridad HTTP (CSP, HSTS, X-Frame-Options)
  • CORS: Whitelist de orígenes permitidos configurable via ALLOWED_ORIGINS
  • HTTPS Only: Redirección automática de HTTP a HTTPS en producción
  • Rate Limiting: Límite de requests por IP para prevenir abuse

Error: Service Bus Connection Timeout

Causas Técnicas:

Causa Resolución
NSG bloqueando puertos 5671/5672 Crear regla NSG permitiendo egress a ServiceBus service tag
Firewall de Service Bus Agregar outbound IPs del App Service a allowlist
SAS policy sin permisos Otorgar permisos Send, Listen en Shared Access Policy

3. Input Validation con Zod

Todos los payloads entrantes se validan mediante schemas Zod antes de procesamiento. Esto previene injection attacks y asegura integridad de datos.

Schemas Implementados:

  • AnalyzeMessageSchema: Valida URLs de blob storage, nombres de archivo PDF
  • ChatQuerySchema: Valida queries de chat (longitud, formato, chatId UUID)
  • RecommendationSchema: Valida parámetros de búsqueda y filtros

Errores de validación retornan 400 Bad Request con detalles específicos del campo inválido.

Error: Azure Storage Access Denied

Resolución recomendada: Usar Managed Identity para autenticación sin connection strings

import { BlobServiceClient } from '@azure/storage-blob';
import { DefaultAzureCredential } from '@azure/identity';

const blobServiceClient = new BlobServiceClient(
  `https://${process.env.AZURE_STORAGE_ACCOUNT_NAME}.blob.core.windows.net`,
  new DefaultAzureCredential()
);
az webapp identity assign --resource-group ia_test --name eciwiseIaTest

4. Rate Limiting

Implementación de express-rate-limit para prevenir abuse y ataques DDoS:

  • API Global: 100 requests por IP cada 15 minutos
  • Chat Endpoint: 10 requests por IP por minuto
  • Headers estándar: Incluye RateLimit-* headers en responses

Error: PostgreSQL Connection Refused

Resolución: Configurar firewall rules en PostgreSQL Flexible Server

az postgres flexible-server firewall-rule create --name pgserver --rule-name AllowAzureServices --start-ip-address 0.0.0.0 --end-ip-address 0.0.0.0

SSL Issues: Agregar ?sslmode=require al DATABASE_URL

5. SQL Injection Prevention

Prisma ORM utiliza prepared statements automáticamente, eliminando riesgo de SQL injection. Todas las queries usan el query builder type-safe. En casos excepcionales de raw SQL, se utilizan template literals parameterizados ($queryRaw) que escapan valores automáticamente.


Error: Memory Heap Limit

Error Code:

FATAL ERROR: Reached heap limit Allocation failed - JavaScript heap out of memory

Causas: PDFs grandes en memoria, concurrent requests sin límite, heap insuficiente

Resolución:

# Aumentar heap de Node.js
az webapp config appsettings set --name eciwiseIaTest --settings NODE_OPTIONS="--max-old-space-size=2048"

# Limitar concurrencia de Service Bus
SERVICE_BUS_MAX_CONCURRENCY="1"

Límite de tamaño: Configurar MAX_FILE_SIZE_MB=10 en variables de entorno


Error: Deployment Failed

Causas comunes:

Causa Resolución
Build timeout SCM_COMMAND_IDLE_TIMEOUT="3600"
Prisma no genera PRE_BUILD_COMMAND="npx prisma generate"
Node version mismatch "engines": {"node": "22.x"} en package.json

Roadmap

v2.0 - Multi-Model LLM Support (Q1 2026)

  • Soporte para Claude 3.5 Sonnet (Anthropic) y GPT-4 Turbo (OpenAI)
  • Abstracción de LLM provider mediante patrón Strategy
  • Fallback automático entre modelos con health checks
  • A/B testing para evaluación de calidad

v2.1 - Vector Embeddings & Semantic Search (Q2 2026)

  • Azure Cognitive Search con vector indexing
  • Embeddings con text-embedding-004
  • Clustering de documentos por similitud semántica
  • Stack: @azure/search-documents, PostgreSQL pgvector extension

v2.2 - OCR para Documentos Escaneados (Q3 2026)

  • Azure Computer Vision para OCR de imágenes embebidas
  • Post-procesamiento de texto con LLM para corrección de errores
  • Soporte para layouts multi-columna

v3.0 - Internacionalización (Q4 2026)

  • Detección automática de idioma del documento
  • Soporte para inglés, portugués, francés
  • Traducción de resúmenes on-demand
  • Búsqueda cross-language

v3.1 - Auto-Assessment Generation (Q1 2027)

  • Generación de quizzes desde contenido de documentos
  • MCQ con distractores plausibles
  • Open-ended questions con rúbricas de evaluación

v4.0 - Advanced RAG Pipeline (Q2 2027)

  • Chunking con overlapping windows
  • Reranking con Cross-Encoder models
  • Query expansion con sinónimos académicos
  • Chain-of-Thought prompting para queries complejos
  • Sistema de citas automáticas

Licencia

ISC License

Copyright (c) 2025 ECIWISE Development Team

Permission to use, copy, modify, and/or distribute this software for any purpose with or without fee is hereby granted, provided that the above copyright notice and this permission notice appear in all copies.

THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.


Versión: 1.0.0 | Repositorio: github.com/DOSW2025/wise_ia

About

Modulo de intelegencia artificial

Resources

Stars

Watchers

Forks

Releases

No releases published

Packages

 
 
 

Contributors