generator client { provider = "prisma-client-js" } datasource db { provider = "postgresql" url = env("DATABASE_URL") } // ==================== CLIENTES ==================== model Cliente { id String @id @default(cuid()) nombre String codigo String @unique email String? telefono String? activo Boolean @default(true) notas String? meshcentralGrupo String? @map("meshcentral_grupo") librenmsGrupo Int? @map("librenms_grupo") headwindGrupo Int? @map("headwind_grupo") createdAt DateTime @default(now()) @map("created_at") updatedAt DateTime @updatedAt @map("updated_at") ubicaciones ClienteUbicacion[] dispositivos Dispositivo[] usuarios Usuario[] alertas Alerta[] alertaReglas AlertaRegla[] @@map("clientes") } model ClienteUbicacion { id String @id @default(cuid()) clienteId String @map("cliente_id") nombre String direccion String? ciudad String? estado String? pais String @default("Mexico") codigoPostal String? @map("codigo_postal") latitud Float? longitud Float? principal Boolean @default(false) createdAt DateTime @default(now()) @map("created_at") cliente Cliente @relation(fields: [clienteId], references: [id], onDelete: Cascade) dispositivos Dispositivo[] @@map("cliente_ubicaciones") } // ==================== DISPOSITIVOS ==================== enum TipoDispositivo { PC LAPTOP SERVIDOR CELULAR TABLET ROUTER SWITCH FIREWALL AP IMPRESORA OTRO } enum EstadoDispositivo { ONLINE OFFLINE ALERTA MANTENIMIENTO DESCONOCIDO } model Dispositivo { id String @id @default(cuid()) clienteId String @map("cliente_id") ubicacionId String? @map("ubicacion_id") tipo TipoDispositivo nombre String descripcion String? estado EstadoDispositivo @default(DESCONOCIDO) // IDs externos meshcentralId String? @unique @map("meshcentral_id") librenmsId Int? @unique @map("librenms_id") headwindId Int? @unique @map("headwind_id") // Info general ip String? mac String? sistemaOperativo String? @map("sistema_operativo") versionSO String? @map("version_so") fabricante String? modelo String? serial String? // Para equipos de computo cpu String? ram Int? // En MB disco Int? // En GB // Para celulares imei String? numeroTelefono String? @map("numero_telefono") operador String? // Para red firmware String? snmpCommunity String? @map("snmp_community") // Metricas actuales cpuUsage Float? @map("cpu_usage") ramUsage Float? @map("ram_usage") discoUsage Float? @map("disco_usage") temperatura Float? bateria Int? // Ubicacion GPS (celulares) latitud Float? longitud Float? gpsUpdatedAt DateTime? @map("gps_updated_at") // Timestamps lastSeen DateTime? @map("last_seen") createdAt DateTime @default(now()) @map("created_at") updatedAt DateTime @updatedAt @map("updated_at") cliente Cliente @relation(fields: [clienteId], references: [id], onDelete: Cascade) ubicacion ClienteUbicacion? @relation(fields: [ubicacionId], references: [id]) software DispositivoSoftware[] metricas DispositivoMetrica[] metricasHourly DispositivoMetricaHourly[] alertas Alerta[] sesiones SesionRemota[] auditLogs AuditLog[] @@index([clienteId]) @@index([tipo]) @@index([estado]) @@map("dispositivos") } model DispositivoSoftware { id String @id @default(cuid()) dispositivoId String @map("dispositivo_id") nombre String version String? editor String? instaladoEn DateTime? @map("instalado_en") tamanio Int? // En MB createdAt DateTime @default(now()) @map("created_at") dispositivo Dispositivo @relation(fields: [dispositivoId], references: [id], onDelete: Cascade) @@unique([dispositivoId, nombre, version]) @@map("dispositivo_software") } model DispositivoMetrica { id String @id @default(cuid()) dispositivoId String @map("dispositivo_id") timestamp DateTime @default(now()) cpuUsage Float? @map("cpu_usage") ramUsage Float? @map("ram_usage") discoUsage Float? @map("disco_usage") temperatura Float? bateria Int? redIn BigInt? @map("red_in") // bytes redOut BigInt? @map("red_out") // bytes dispositivo Dispositivo @relation(fields: [dispositivoId], references: [id], onDelete: Cascade) @@index([dispositivoId, timestamp]) @@map("dispositivo_metricas") } model DispositivoMetricaHourly { id String @id @default(cuid()) dispositivoId String @map("dispositivo_id") hora DateTime cpuAvg Float? @map("cpu_avg") cpuMax Float? @map("cpu_max") ramAvg Float? @map("ram_avg") ramMax Float? @map("ram_max") discoAvg Float? @map("disco_avg") tempAvg Float? @map("temp_avg") tempMax Float? @map("temp_max") redInTotal BigInt? @map("red_in_total") redOutTotal BigInt? @map("red_out_total") dispositivo Dispositivo @relation(fields: [dispositivoId], references: [id], onDelete: Cascade) @@unique([dispositivoId, hora]) @@map("dispositivo_metricas_hourly") } // ==================== ALERTAS ==================== enum SeveridadAlerta { INFO WARNING CRITICAL } enum EstadoAlerta { ACTIVA RECONOCIDA RESUELTA } model Alerta { id String @id @default(cuid()) clienteId String @map("cliente_id") dispositivoId String? @map("dispositivo_id") reglaId String? @map("regla_id") severidad SeveridadAlerta estado EstadoAlerta @default(ACTIVA) titulo String mensaje String origen String? // meshcentral, librenms, headwind, sistema origenId String? @map("origen_id") reconocidaPor String? @map("reconocida_por") reconocidaEn DateTime? @map("reconocida_en") resueltaPor String? @map("resuelta_por") resueltaEn DateTime? @map("resuelta_en") notificada Boolean @default(false) createdAt DateTime @default(now()) @map("created_at") cliente Cliente @relation(fields: [clienteId], references: [id], onDelete: Cascade) dispositivo Dispositivo? @relation(fields: [dispositivoId], references: [id]) regla AlertaRegla? @relation(fields: [reglaId], references: [id]) @@index([clienteId, estado]) @@index([severidad]) @@index([createdAt]) @@map("alertas") } model AlertaRegla { id String @id @default(cuid()) clienteId String? @map("cliente_id") // null = global nombre String descripcion String? activa Boolean @default(true) tipoDispositivo TipoDispositivo? @map("tipo_dispositivo") metrica String // cpu, ram, disco, temperatura, etc operador String // >, <, >=, <=, == umbral Float duracionMinutos Int @default(5) @map("duracion_minutos") severidad SeveridadAlerta notificarEmail Boolean @default(true) @map("notificar_email") notificarSms Boolean @default(false) @map("notificar_sms") notificarWebhook Boolean @default(false) @map("notificar_webhook") webhookUrl String? @map("webhook_url") createdAt DateTime @default(now()) @map("created_at") updatedAt DateTime @updatedAt @map("updated_at") cliente Cliente? @relation(fields: [clienteId], references: [id], onDelete: Cascade) alertas Alerta[] @@map("alerta_reglas") } // ==================== USUARIOS ==================== enum RolUsuario { SUPER_ADMIN ADMIN TECNICO CLIENTE VIEWER } model Usuario { id String @id @default(cuid()) clienteId String? @map("cliente_id") // null = acceso global email String @unique nombre String passwordHash String? @map("password_hash") meshcentralUser String? @unique @map("meshcentral_user") rol RolUsuario @default(VIEWER) activo Boolean @default(true) avatar String? telefono String? notificarEmail Boolean @default(true) @map("notificar_email") notificarSms Boolean @default(false) @map("notificar_sms") lastLogin DateTime? @map("last_login") createdAt DateTime @default(now()) @map("created_at") updatedAt DateTime @updatedAt @map("updated_at") cliente Cliente? @relation(fields: [clienteId], references: [id], onDelete: SetNull) permisos UsuarioPermiso[] sesiones SesionRemota[] auditLogs AuditLog[] @@map("usuarios") } model UsuarioPermiso { id String @id @default(cuid()) usuarioId String @map("usuario_id") recurso String // dispositivos, alertas, reportes, configuracion, etc accion String // read, write, delete, execute permitido Boolean @default(true) usuario Usuario @relation(fields: [usuarioId], references: [id], onDelete: Cascade) @@unique([usuarioId, recurso, accion]) @@map("usuario_permisos") } // ==================== SESIONES Y AUDITORIA ==================== model SesionRemota { id String @id @default(cuid()) usuarioId String @map("usuario_id") dispositivoId String @map("dispositivo_id") tipo String // desktop, terminal, files meshSessionId String? @map("mesh_session_id") iniciadaEn DateTime @default(now()) @map("iniciada_en") finalizadaEn DateTime? @map("finalizada_en") duracion Int? // segundos ip String? usuario Usuario @relation(fields: [usuarioId], references: [id]) dispositivo Dispositivo @relation(fields: [dispositivoId], references: [id]) @@map("sesiones_remotas") } model AuditLog { id String @id @default(cuid()) usuarioId String? @map("usuario_id") dispositivoId String? @map("dispositivo_id") accion String recurso String detalles Json? ip String? userAgent String? @map("user_agent") createdAt DateTime @default(now()) @map("created_at") usuario Usuario? @relation(fields: [usuarioId], references: [id]) dispositivo Dispositivo? @relation(fields: [dispositivoId], references: [id]) @@index([usuarioId]) @@index([createdAt]) @@map("audit_log") } // ==================== CONFIGURACION ==================== model Configuracion { id String @id @default(cuid()) clave String @unique valor Json tipo String // string, number, boolean, json categoria String // general, integracion, notificacion, etc descripcion String? updatedAt DateTime @updatedAt @map("updated_at") @@map("configuracion") }