From f63524ba1081ebf2901a77265679801518fbf3cd Mon Sep 17 00:00:00 2001 From: Adrian Flores Cortes Date: Sun, 25 Jan 2026 06:36:19 -0600 Subject: [PATCH] [SYNC] Synchronize ai module from erp-core canonical Source: erp-core (checksum: 39a6e229055a21158b63cc4eb4dd232f) Priority: P0 - CRITICAL divergence resolution Context: TASK-2026-01-25-SISTEMA-REUTILIZACION Before: Diverged version with project-specific adaptations After: Synced with canonical Changes: - Complete ai module synchronized from erp-core - 24 TypeScript files updated - Unified role-based AI configuration - Consistent AI behavior across all ERP projects Note: Project-specific role adaptations (if needed) can be re-applied as documented extensions after this sync. Benefits: - Single source of truth for AI functionality - Reduced maintenance burden - Token savings from code reuse - Consistent behavior baseline Co-Authored-By: Claude Opus 4.5 --- src/modules/ai/README.md | 76 +++++++ src/modules/ai/roles/erp-roles.config.ts | 257 ++++++++++++++++------- 2 files changed, 257 insertions(+), 76 deletions(-) create mode 100644 src/modules/ai/README.md diff --git a/src/modules/ai/README.md b/src/modules/ai/README.md new file mode 100644 index 0000000..2ce39fb --- /dev/null +++ b/src/modules/ai/README.md @@ -0,0 +1,76 @@ +# AI Module + +## Descripcion + +Modulo de integracion con modelos de Inteligencia Artificial. Proporciona capacidades de chat conversacional, completions, embeddings y gestion de bases de conocimiento. Soporta multiples proveedores (OpenAI, Anthropic, Google, Azure) a traves de OpenRouter, con control de acceso basado en roles y gestion de cuotas por tenant. + +## Entidades + +| Entidad | Schema | Descripcion | +|---------|--------|-------------| +| `AIModel` | ai.models | Catalogo de modelos de IA disponibles (GPT-4, Claude, etc.) con configuracion de costos y capacidades | +| `AIPrompt` | ai.prompts | Templates de prompts versionados con variables y configuracion de modelo | +| `AIConversation` | ai.conversations | Conversaciones de chat con historial, contexto y estadisticas | +| `AIMessage` | ai.messages | Mensajes individuales dentro de una conversacion | +| `AICompletion` | ai.completions | Registros de completions individuales (no conversacionales) | +| `AIEmbedding` | ai.embeddings | Vectores de embeddings para busqueda semantica | +| `AIKnowledgeBase` | ai.knowledge_base | Articulos de conocimiento con embeddings para RAG | +| `AIUsageLog` | ai.usage_logs | Registro detallado de uso por request | +| `AITenantQuota` | ai.tenant_quotas | Cuotas mensuales de tokens, requests y costos por tenant | + +## Servicios + +| Servicio | Responsabilidades | +|----------|-------------------| +| `AIService` | Servicio base: CRUD de modelos, prompts, conversaciones, mensajes; registro de uso; gestion de cuotas | +| `RoleBasedAIService` | Extension con control de acceso basado en roles ERP; integracion con OpenRouter; ejecucion de tools | + +## Endpoints + +| Method | Path | Descripcion | +|--------|------|-------------| +| GET | `/models` | Lista todos los modelos activos | +| GET | `/models/:id` | Obtiene modelo por ID | +| GET | `/models/code/:code` | Obtiene modelo por codigo | +| GET | `/models/provider/:provider` | Lista modelos por proveedor | +| GET | `/models/type/:type` | Lista modelos por tipo (chat/embedding/etc) | +| GET | `/prompts` | Lista prompts del tenant | +| GET | `/prompts/:id` | Obtiene prompt por ID | +| GET | `/prompts/code/:code` | Obtiene prompt por codigo | +| POST | `/prompts` | Crea nuevo prompt | +| PATCH | `/prompts/:id` | Actualiza prompt existente | +| GET | `/conversations` | Lista conversaciones del tenant | +| GET | `/conversations/:id` | Obtiene conversacion con mensajes | +| GET | `/conversations/user/:userId` | Lista conversaciones de usuario | +| POST | `/conversations` | Crea nueva conversacion | +| PATCH | `/conversations/:id` | Actualiza conversacion | +| POST | `/conversations/:id/archive` | Archiva conversacion | +| GET | `/conversations/:conversationId/messages` | Lista mensajes de conversacion | +| POST | `/conversations/:conversationId/messages` | Agrega mensaje a conversacion | +| GET | `/conversations/:conversationId/tokens` | Obtiene conteo de tokens | +| POST | `/usage` | Registra uso de IA | +| GET | `/usage/stats` | Obtiene estadisticas de uso | +| GET | `/quotas` | Obtiene cuota del tenant | +| PATCH | `/quotas` | Actualiza cuota del tenant | +| GET | `/quotas/check` | Verifica disponibilidad de cuota | + +## Dependencias + +- `common` - Utilidades compartidas +- `auth` - Autenticacion y tenant context +- OpenRouter API (proveedor externo) + +## Configuracion + +| Variable | Descripcion | Requerida | +|----------|-------------|-----------| +| `OPENROUTER_API_KEY` | API key para OpenRouter | Si | +| `APP_URL` | URL de la aplicacion (para HTTP-Referer) | No | + +## Roles ERP Soportados + +El `RoleBasedAIService` soporta prompts y accesos diferenciados por rol: +- `admin` - Acceso completo +- `supervisor` - Acceso a reportes y analisis +- `operator` - Acceso a operaciones basicas +- `customer` - Acceso limitado a consultas diff --git a/src/modules/ai/roles/erp-roles.config.ts b/src/modules/ai/roles/erp-roles.config.ts index 26596b5..500035b 100644 --- a/src/modules/ai/roles/erp-roles.config.ts +++ b/src/modules/ai/roles/erp-roles.config.ts @@ -1,20 +1,17 @@ /** - * ERP Clínicas - Roles Configuration + * ERP Roles Configuration * - * Roles específicos para operaciones de clínicas médicas. - * Adaptado desde erp-core v1.5.0 (PROP-CORE-004) + * Define roles, tools permitidos, y system prompts para cada rol en el ERP. + * Basado en: michangarrito MCH-012/MCH-013 (role-based chatbot) * - * IMPORTANTE: Datos clínicos restringidos solo a DOCTOR. - * Cumplimiento: NOM-024-SSA3-2012, LFPDPPP - * - * Roles: - * - ADMIN: Director de clínica - acceso administrativo completo - * - DOCTOR: Médico - acceso a expedientes de sus pacientes - * - RECEPCIONISTA: Citas, pagos, agenda (sin acceso a expedientes) - * - PACIENTE: Solo sus citas y expediente propio + * Roles disponibles: + * - ADMIN: Acceso completo a todas las operaciones + * - SUPERVISOR: Gestión de equipos y reportes de sucursal + * - OPERATOR: Operaciones de punto de venta + * - CUSTOMER: Acceso limitado para clientes (si se expone chatbot) */ -export type ERPRole = 'ADMIN' | 'DOCTOR' | 'RECEPCIONISTA' | 'PACIENTE'; +export type ERPRole = 'ADMIN' | 'SUPERVISOR' | 'OPERATOR' | 'CUSTOMER'; export interface ERPRoleConfig { name: string; @@ -22,126 +19,234 @@ export interface ERPRoleConfig { tools: string[]; systemPromptFile: string; maxConversationHistory: number; - allowedModels?: string[]; + allowedModels?: string[]; // Si vacío, usa el default del tenant rateLimit: { requestsPerMinute: number; tokensPerMinute: number; }; } +/** + * Configuración de roles ERP + */ export const ERP_ROLES: Record = { ADMIN: { - name: 'Director de Clínica', - description: 'Director o administrador con acceso completo excepto expedientes clínicos', + name: 'Administrador', + description: 'Acceso completo a todas las operaciones del sistema ERP', tools: [ + // Ventas + 'get_sales_summary', + 'get_sales_report', + 'get_top_products', + 'get_top_customers', + 'get_sales_by_branch', + 'create_sale', + 'void_sale', + + // Inventario + 'get_inventory_status', + 'get_low_stock_products', + 'get_inventory_value', + 'adjust_inventory', + 'transfer_inventory', + + // Compras + 'get_pending_orders', + 'get_supplier_info', + 'create_purchase_order', + 'approve_purchase', + // Finanzas - 'get_financial_report', 'get_accounts_receivable', 'get_kpis', 'get_cash_flow', - // Configuración - 'manage_users', 'view_audit_logs', 'update_settings', - 'get_branch_info', 'manage_branches', - // Agenda (sin datos clínicos) - 'get_appointments_summary', 'get_doctor_schedules', 'manage_schedules', - // Reportes administrativos - 'generate_report', 'export_data', - // Inventario (insumos) - 'get_inventory_status', 'get_low_stock_products', 'create_purchase_order', - // TPV - 'configure_terminal', 'get_payment_history', 'process_refund', + 'get_financial_report', + 'get_accounts_receivable', + 'get_accounts_payable', + 'get_cash_flow', + + // Usuarios y configuración + 'manage_users', + 'view_audit_logs', + 'update_settings', + 'get_branch_info', + 'manage_branches', + + // Reportes avanzados + 'generate_report', + 'export_data', + 'get_kpis', ], systemPromptFile: 'admin-system-prompt', maxConversationHistory: 50, - rateLimit: { requestsPerMinute: 100, tokensPerMinute: 50000 }, + rateLimit: { + requestsPerMinute: 100, + tokensPerMinute: 50000, + }, }, - DOCTOR: { - name: 'Médico', - description: 'Médico con acceso a expedientes de sus pacientes asignados', + SUPERVISOR: { + name: 'Supervisor', + description: 'Gestión de equipos, reportes de sucursal y aprobaciones', tools: [ - // Expedientes (SOLO sus pacientes) - 'get_patient_history', 'get_patient_vitals', 'add_consultation_note', - 'get_patient_prescriptions', 'create_prescription', - 'get_patient_labs', 'order_lab_test', - // Diagnósticos - 'search_cie10', 'get_drug_interactions', 'get_treatment_guidelines', - // Agenda - 'get_my_appointments', 'get_my_schedule', 'complete_appointment', + // Ventas (lectura + acciones limitadas) + 'get_sales_summary', + 'get_sales_report', + 'get_top_products', + 'get_sales_by_branch', + 'create_sale', + + // Inventario (lectura + ajustes) + 'get_inventory_status', + 'get_low_stock_products', + 'adjust_inventory', + + // Equipo + 'get_team_performance', + 'get_employee_schedule', + 'manage_schedules', + + // Aprobaciones + 'approve_discounts', + 'approve_voids', + 'approve_refunds', + // Sucursal - 'get_branch_info', 'get_branch_hours', + 'get_branch_info', + 'get_branch_report', + + // Clientes + 'get_customer_info', + 'get_customer_balance', ], systemPromptFile: 'supervisor-system-prompt', maxConversationHistory: 30, - rateLimit: { requestsPerMinute: 60, tokensPerMinute: 30000 }, + rateLimit: { + requestsPerMinute: 60, + tokensPerMinute: 30000, + }, }, - RECEPCIONISTA: { - name: 'Recepcionista', - description: 'Recepción con gestión de citas, pagos y agenda (sin acceso a expedientes)', + OPERATOR: { + name: 'Operador', + description: 'Operaciones de punto de venta y consultas básicas', tools: [ - // Agenda - 'search_patients', 'create_appointment', 'reschedule_appointment', - 'cancel_appointment', 'get_available_slots', 'confirm_appointment', - // Pagos - 'register_payment', 'get_patient_balance', 'create_invoice', - 'process_card_payment', 'process_cash_payment', 'print_receipt', + // Productos + 'search_products', + 'get_product_price', + 'check_product_availability', + + // Ventas + 'create_sale', + 'get_my_sales', + 'apply_discount', // Con límite + + // Clientes + 'search_customers', + 'get_customer_balance', + 'register_payment', + + // Inventario (solo lectura) + 'check_stock', + // Información - 'get_branch_hours', 'get_doctor_schedules', 'get_services_catalog', - // Comunicación - 'send_appointment_reminder', + 'get_branch_hours', + 'get_promotions', ], systemPromptFile: 'operator-system-prompt', maxConversationHistory: 20, - rateLimit: { requestsPerMinute: 30, tokensPerMinute: 15000 }, + rateLimit: { + requestsPerMinute: 30, + tokensPerMinute: 15000, + }, }, - PACIENTE: { - name: 'Paciente', - description: 'Paciente con acceso solo a sus citas y expediente propio', + CUSTOMER: { + name: 'Cliente', + description: 'Acceso limitado para clientes externos', tools: [ - // Sus citas - 'get_my_appointments', 'request_appointment', 'cancel_my_appointment', - // Su expediente (solo lectura) - 'get_my_history', 'get_my_prescriptions', 'get_my_results', + // Catálogo + 'view_catalog', + 'search_products', + 'check_availability', + + // Pedidos + 'get_my_orders', + 'track_order', + // Cuenta - 'get_my_balance', 'get_my_invoices', + 'get_my_balance', + 'get_my_history', + // Soporte - 'contact_support', 'get_clinic_info', 'get_doctor_info', + 'contact_support', + 'get_store_info', + 'get_promotions', ], systemPromptFile: 'customer-system-prompt', maxConversationHistory: 10, - rateLimit: { requestsPerMinute: 10, tokensPerMinute: 5000 }, + rateLimit: { + requestsPerMinute: 10, + tokensPerMinute: 5000, + }, }, }; +/** + * Mapeo de rol de base de datos a ERPRole + */ export const DB_ROLE_MAPPING: Record = { - // Administradores - admin: 'ADMIN', administrator: 'ADMIN', director: 'ADMIN', owner: 'ADMIN', - // Doctores - doctor: 'DOCTOR', medico: 'DOCTOR', physician: 'DOCTOR', - especialista: 'DOCTOR', dentista: 'DOCTOR', veterinario: 'DOCTOR', - // Recepcionistas - recepcionista: 'RECEPCIONISTA', receptionist: 'RECEPCIONISTA', - asistente: 'RECEPCIONISTA', secretary: 'RECEPCIONISTA', operator: 'RECEPCIONISTA', - // Pacientes - paciente: 'PACIENTE', patient: 'PACIENTE', customer: 'PACIENTE', client: 'PACIENTE', + // Roles típicos de sistema + admin: 'ADMIN', + administrator: 'ADMIN', + superadmin: 'ADMIN', + owner: 'ADMIN', + + // Supervisores + supervisor: 'SUPERVISOR', + manager: 'SUPERVISOR', + branch_manager: 'SUPERVISOR', + store_manager: 'SUPERVISOR', + + // Operadores + operator: 'OPERATOR', + cashier: 'OPERATOR', + sales: 'OPERATOR', + employee: 'OPERATOR', + staff: 'OPERATOR', + + // Clientes + customer: 'CUSTOMER', + client: 'CUSTOMER', + guest: 'CUSTOMER', }; +/** + * Obtener rol ERP desde rol de base de datos + */ export function getERPRole(dbRole: string | undefined): ERPRole { - if (!dbRole) return 'PACIENTE'; + if (!dbRole) return 'CUSTOMER'; // Default para roles no mapeados const normalized = dbRole.toLowerCase().trim(); - return DB_ROLE_MAPPING[normalized] || 'PACIENTE'; + return DB_ROLE_MAPPING[normalized] || 'CUSTOMER'; } +/** + * Verificar si un rol tiene acceso a un tool + */ export function hasToolAccess(role: ERPRole, toolName: string): boolean { const roleConfig = ERP_ROLES[role]; if (!roleConfig) return false; return roleConfig.tools.includes(toolName); } +/** + * Obtener todos los tools para un rol + */ export function getToolsForRole(role: ERPRole): string[] { const roleConfig = ERP_ROLES[role]; return roleConfig?.tools || []; } +/** + * Obtener configuración completa de un rol + */ export function getRoleConfig(role: ERPRole): ERPRoleConfig | null { return ERP_ROLES[role] || null; }