lock

BGnius VITA

Panel de Administración

{{ loginError }}

{{ currentPageTitle }}

{{ health.status==='healthy'?'Online':'Degradado' }}
devices
Dispositivos
{{ devices.length }}
group
Clientes
{{ clients.length }}
engineering
Instaladores
{{ installers.length }}
vpn_key
Activaciones
{{ activations.length }}
support_agent {{ openSupportCount }} abiertos
Tickets de soporte
{{ supportRequests.length }}
notifications {{ unreadNotifsCount }} sin leer
Notificaciones
{{ notifications.length }}
fact_check {{ commandsTodayCount }} hoy
Comandos auditados
{{ commandLog.length }}

Gestión de Personas

search {{ filteredPersons.length }} resultado(s)
ID Identificación Nombre Email Tel Roles Acciones
No se encontraron personas
{{ person.id }} {{ person.identify }} {{ person.name }} {{ person.email }} {{ person.tel || 'N/A' }} sin cuenta {{ r }}

Asignación de Roles

Solo aparecen personas con cuenta de usuario asociada. Para crear una cuenta, agregá la persona desde "Personas" o "Instaladores/Clientes" con la opción "create_user".
ID Persona Email Roles asignados Acciones
Sin coincidencias.
{{ person.id }} {{ person.name }} {{ person.email }} {{ r }}

notifications Notificaciones del sistema

ID Fecha Tipo Título Mensaje Usuario Device Leída
{{ n.id }} {{ formatDate(n.created_at) }} {{ n.type }} {{ n.title }} {{ n.body }} {{ n.user_email || ('#' + n.user_id) }} {{ n.device_name || (n.device_id ? '#' + n.device_id : '—') }} leída nueva
No hay notificaciones para los filtros aplicados.

support_agent Tickets de Soporte

ID Fecha Asunto Usuario Device Categoría Prioridad Estado Acciones
{{ req.id }} {{ formatDate(req.created_at) }} {{ req.subject }} {{ req.user_name || req.user_email || ('#' + req.user_id) }} {{ req.device_name || (req.device_id ? '#' + req.device_id : '—') }} {{ req.category }} {{ req.priority }} {{ req.status }}
No hay tickets para los filtros aplicados.

fact_check Auditoría de Comandos

Fecha Device Acción Actor Estado Flags ms
No hay entradas en el log para los filtros aplicados.
engineering

{{ selectedInstaller.name }}

{{ selectedInstaller.email }}
ID: {{ selectedInstaller.identify }} · {{ countryName(selectedInstaller.country_id) }} · {{ selectedInstaller.tel }}
Sin cuenta 🟢 Activo Inactivo 🛡️ {{ r }}
Cargando datos del instalador...
Error cargando datos: {{ installerDetailData.error }}
Identificación
{{ selectedInstaller.identify }}
Nombre completo
{{ selectedInstaller.name }}
Email
{{ selectedInstaller.email }}
Teléfono
{{ selectedInstaller.tel || '—' }}
País
{{ countryName(selectedInstaller.country_id) }}
Dirección
{{ selectedInstaller.address || '—' }}
Creado
{{ formatDate(selectedInstaller.created_at) }}
{{ installerTrainings.length }} capacitación(es) registrada(s)
Tipo Nombre Fecha Descripción Acciones
Sin capacitaciones registradas para este instalador.
{{ t.type }} {{ t.name }} {{ formatDate(t.training_date) }} {{ t.description || '—' }}
{{ installerMemberships.length }} membresía(s) registrada(s)
ID Pago Vencimiento Tipo Acciones
Sin membresías registradas para este instalador.
{{ m.id }} {{ formatDate(m.payment_date) }} {{ formatDate(m.expiration_date) }} {{ m.type ?? '—' }}
{{ installerValidationsReceived.length }} validación(es) recibida(s). Otros instaladores que respaldaron a este instalador.
ID Validado por Fecha Notas Acciones
Sin validaciones recibidas.
{{ v.id }} {{ personName(v.validator_person_id) }} {{ formatDate(v.validation_date) }} {{ v.notes || '—' }}
{{ installerValidationsMade.length }} validación(es) realizada(s). Instaladores que este instalador respaldó.
ID Validado Fecha Notas Acciones
Sin validaciones realizadas.
{{ v.id }} {{ personName(v.validated_person_id) }} {{ formatDate(v.validation_date) }} {{ v.notes || '—' }}
{{ installerActivations.length }} instalación(es) realizada(s) por este instalador. Una instalación = motor + dispositivo + cliente final + fecha.
Vita ID Motor Dispositivo Cliente Estado Fecha Notas
Sin activaciones registradas.
{{ a.vita_id }} {{ a.engine_model || '#' + a.engine_id }} {{ a.device_id ? '#' + a.device_id : '—' }} {{ a.client_name || (a.client_person_id ? '#' + a.client_person_id : '—') }} {{ a.status }} {{ formatDate(a.activation_date) }} {{ a.notes || '—' }}
{{ installerInstalledDevices.length }} dispositivo(s) físicamente instalado(s) por este instalador (cross-referenciado desde las activaciones, sin duplicados).
Sin devices instalados todavía. Las activaciones del instalador no apuntan a ningún device físico (device_id null).
ID Serial Nombre Cliente owner Estado activación Online
#{{ d.id }} {{ d.serial_number }} {{ d.name }} {{ d.owner_email || '#' + d.owner_id }} {{ d._activation_status }} {{ d.is_online ? 'Online' : 'Offline' }}

Click en una fila para abrir el detalle del device.

Gestión de Instaladores

search {{ filteredInstallers.length }} resultado(s)
ID Identificación Nombre Email País Estado Acciones
{{ installer.id }} {{ installer.identify }} {{ installer.name }} {{ installer.email }} {{ countryName(installer.country_id) }} Sin cuenta Activo Inactivo
badge

{{ selectedClient.name }}

{{ selectedClient.email }}
ID: {{ selectedClient.identify }} · {{ countryName(selectedClient.country_id) }} · {{ selectedClient.tel }}
Sin cuenta 🟢 Activo Inactivo 🛡️ {{ r }}
Cargando datos del cliente...
Error cargando datos: {{ clientDetailData.error }}
Identificación
{{ selectedClient.identify }}
Nombre completo
{{ selectedClient.name }}
Email
{{ selectedClient.email }}
Teléfono
{{ selectedClient.tel || '—' }}
País
{{ countryName(selectedClient.country_id) }}
Dirección
{{ selectedClient.address || '—' }}
{{ clientDevices.length }} dispositivo(s) propiedad de este cliente. ⚠️ Este cliente no tiene cuenta de usuario, no puede tener devices owned.
ID Serial Nombre Tipo Ubicación Estado
Este cliente no tiene dispositivos asignados.
{{ d.id }} {{ d.serial_number }} {{ d.name }} {{ deviceTypeMatIcon(d.device_type) }} {{ deviceTypeName(d.device_type) }} {{ d.location || '—' }}
{{ d.is_online ? 'Online' : 'Offline' }} {{ d.is_test_device ? '🧪 TEST' : '⚠️ PROD' }}
{{ clientActivationsReceived.length }} activación(es) donde este cliente fue el destinatario final de la instalación. Cada una vincula al instalador que hizo el trabajo.
Vita ID Instalador Motor Dispositivo Estado Fecha Notas
Sin activaciones registradas para este cliente.
{{ a.vita_id }} {{ a.installer_name || '#' + a.installer_person_id }} {{ a.engine_model || '#' + a.engine_id }} {{ a.device_id ? '#' + a.device_id : '—' }} {{ a.status }} {{ formatDate(a.activation_date) }} {{ a.notes || '—' }}
{{ clientSharedDevices.length }} dispositivo(s) compartido(s) con este cliente. Otro cliente lo dueño y le dio acceso con un rol específico (admin, operator, viewer, guest).
Sin devices compartidos. Este cliente solo tiene acceso a sus devices propios.
Device Serial Rol Otorgado Vence
{{ s.device_name || '#' + s.device_id }} {{ s.device_serial || '—' }} {{ s.role }} {{ formatDate(s.created_at) }} {{ s.expires_at ? formatDate(s.expires_at) : 'permanente' }}
{{ clientGroups.length }} grupo(s) creado(s) por este cliente desde su app móvil. Cada grupo agrupa N devices propios para organización ("Casa", "Oficina", etc.).
Sin grupos. El cliente aún no organizó sus devices en categorías.
folder {{ g.name }}
{{ g.description }}
{{ g.device_count != null ? g.device_count : (g.devices ? g.devices.length : 0) }} devices
{{ d.serial_number || ('#' + d.id) }}{{ i < g.devices.length - 1 ? ', ' : '' }}
Creado: {{ formatDate(g.created_at) }}

Gestión de Clientes

search {{ filteredClients.length }} resultado(s)
ID Identificación Nombre Email Teléfono País Estado Acciones
{{ client.id }} {{ client.identify }} {{ client.name }} {{ client.email }} {{ client.tel || '—' }} {{ countryName(client.country_id) }} Sin cuenta Activo Inactivo
No hay clientes registrados todavía. Apretá "Agregar Cliente" para crear uno.

Gestión de Motores

search {{ filteredEngines.length }} resultado(s)
ID Modelo Tipo Marca PCB Acciones
{{ engine.id }} {{ engine.model }} {{ engineTypeName(engine.engine_type_id) }} {{ engine.brand || 'N/A' }} {{ engine.pcb || 'N/A' }}

Tipos de Motor

ID Nombre Creado Acciones
{{ type.id }} {{ type.description }} {{ formatDate(type.created_at) }}

Comandos por modelo de motor

menu_book Spec MQTT (PROTOCOL.md)
Payload canónico: los comandos físicos del motor viajan como {"AC":"command","value":N} (N = 0 OPEN, 1 CLOSE, 2 STOP, 3 OCS, 4 PEDESTRIAN, 5 RELE, 6 LOCK, 7 KEEP_OPEN, 8 LAMP). El backend inyecta idInstaller en runtime. Otros comandos (GE, SE, sesión, etc.) usan su AC literal. Ver PROTOCOL.md §2–§11.
Seleccioná un modelo de motor para ver los comandos disponibles.
Orden Código Etiqueta Payload (firmware) Rol Sesión inst. Estado Acciones
Sin acciones definidas para este motor.
{{ action.sort_order }} {{ action.icon }} {{ action.code }} spec ✓ ? {{ action.label }} {{ JSON.stringify(action.mqtt_payload) }} {{ action.role_required }} {{ action.requires_installer_session ? 'Sí' : 'No' }} {{ action.enabled ? 'Activa' : 'Inactiva' }}

Activaciones de Dispositivos

ID Instalador Motor Serial VITA Fecha Acciones
{{ activation.id }} {{ activation.installer_name }} {{ activation.engine_model }} {{ activation.vita_id || 'N/A' }} {{ formatDate(activation.activation_date) }}

Países

ID Nombre Código Regional Acciones
{{ country.id }} {{ country.name }} {{ country.region_code || 'N/A' }}

Membresías

ID Instalador Tipo Pago Vencimiento Acciones
{{ membership.id }} {{ personName(membership.person_id) }} {{ membership.type ?? 'N/A' }} {{ formatDate(membership.payment_date) }} {{ formatDate(membership.expiration_date) }}

Capacitaciones

ID Instalador Tipo Capacitación Fecha Acciones
{{ training.id }} {{ personName(training.person_id) }} {{ training.type || 'N/A' }} {{ training.name || 'N/A' }} {{ formatDate(training.training_date) }}

Validaciones

ID Instalador Validado por Fecha Acciones
{{ validation.id }} {{ personName(validation.validated_person_id) }} {{ personName(validation.validator_person_id) }} {{ formatDate(validation.validation_date) }}
{{ deviceTypeMatIcon(selectedDeviceForDetail.device_type) }}

{{ selectedDeviceForDetail.name }}

{{ selectedDeviceForDetail.serial_number }} · {{ selectedDeviceForDetail.mac_address }}
{{ selectedDeviceForDetail.is_online ? 'Online' : 'Offline' }} {{ selectedDeviceForDetail.is_test_device ? '🧪 TEST' : '⚠️ PROD' }} {{ selectedDeviceForDetail.engine_model || 'sin engine' }}
ID
{{ selectedDeviceForDetail.id }}
Tipo
{{ deviceTypeName(selectedDeviceForDetail.device_type) }}
Serial
{{ selectedDeviceForDetail.serial_number }}
MAC
{{ selectedDeviceForDetail.mac_address }}
Modelo
{{ selectedDeviceForDetail.model || '—' }}
Engine (catálogo)
#{{ selectedDeviceForDetail.engine_id }} {{ selectedDeviceForDetail.engine_model || '' }}
Owner
{{ selectedDeviceForDetail.owner_email || '#' + selectedDeviceForDetail.owner_id }}
Instalador
{{ selectedDeviceForDetail.installer_name || (selectedDeviceForDetail.installer_id ? '#' + selectedDeviceForDetail.installer_id : '—') }}
Ubicación
{{ selectedDeviceForDetail.location || '—' }}
Descripción
{{ selectedDeviceForDetail.description || '—' }}
Última conexión
{{ formatDate(selectedDeviceForDetail.last_seen) }}
Creado
{{ formatDate(selectedDeviceForDetail.created_at) }}
Todos los comandos ejecutados sobre este dispositivo: desde Flutter del cliente, webadmin, o cualquier fuente.
sync Cargando historial...
No hay comandos registrados para este dispositivo.
Fecha Acción Actor Estado Flags ms
Le pregunta al firmware del motor en qué estado está ahora mismo: ciclos, fotoceldas, lámpara, mantenimiento, versión. · Última consulta: {{ formatDate(deviceDetailData.lastStateAt) }}
Error: {{ deviceDetailData.stateError }}
Posibles causas: el motor está apagado o sin internet, el broker MQTT está caído, o el motor no soporta esta consulta.
Tocá "Consultar estado del motor" para ver qué reporta el firmware ahora mismo.
Estado motor
{{ motorStatusLabel(deviceDetailData.lastState.Cur_MotorStatus) }}
Total ciclos
{{ deviceDetailData.lastState.Total_Cycles ?? '—' }}
Lámpara
{{ deviceDetailData.lastState.Lamp_Status === 1 ? 'ON' : 'OFF' }}
Relé
{{ deviceDetailData.lastState.Relay_Status === 1 ? 'ON' : 'OFF' }}
Foto celdas
Apertura
{{ deviceDetailData.lastState.Fc_OpenState === 1 ? '⚠ Interrumpida' : '✓ Sin interrupción' }}
Batería: {{ deviceDetailData.lastState.fc_Open_Battery ?? '—' }}%
Cierre
{{ deviceDetailData.lastState.Fc_CloseState === 1 ? '⚠ Interrumpida' : '✓ Sin interrupción' }}
Batería: {{ deviceDetailData.lastState.fc_Close_Battery ?? '—' }}%
Mantenimiento
Mantenimientos
{{ deviceDetailData.lastState.Maintenance_Count ?? '—' }}
Ciclos desde último
{{ deviceDetailData.lastState.Cycles_SinceMaintenance ?? '—' }}
Límite
{{ deviceDetailData.lastState.Par_MaintenanceLimit ?? '—' }}
Identidad firmware
Version FW
{{ deviceDetailData.lastState.FV || '—' }}
Etiqueta del instalador
{{ deviceDetailData.lastState.labalVIta || '—' }}
SSID actual
{{ deviceDetailData.lastState.ssid || '—' }}
idVita
{{ deviceDetailData.lastState.idVita || '—' }}
Ver respuesta cruda del firmware (debug)
{{ JSON.stringify(deviceDetailData.lastState, null, 2) }}

Esto es lo que devolvió el firmware al comando MQTT GE (Get state). Útil cuando soporte necesita pasarle el detalle al equipo de firmware.

Disparar manualmente cualquier acción del catálogo de este device. Útil para soporte y debugging. Va por el path de override de superadmin (queda en command_log con override=true).
warning
Este device NO está marcado como TEST. El backend va a rechazar comandos a menos que mandes force_production:true + reason (no implementado en este panel). Marcalo como test desde el form de edición si querés probar.

Este engine no tiene acciones definidas en el catálogo.

Resultado: {{ deviceDetailData.testResult.status }} {{ deviceDetailData.testResult._elapsed_ms }}ms
{{ JSON.stringify(deviceDetailData.testResult, null, 2) }}
Error: {{ deviceDetailData.testError }}

Gestión de Dispositivos

ID Serial Nombre Tipo Ubicación Estado Acciones
{{ device.id }} {{ device.serial_number }} {{ device.name }} {{ deviceTypeMatIcon(device.device_type) }} {{ deviceTypeName(device.device_type) }} {{ device.location || 'N/A' }}
{{ device.is_online ? 'Online' : 'Offline' }} {{ device.is_test_device ? '🧪 TEST' : '⚠️ PROD' }}
No se encontraron dispositivos

Click en una fila para ver el detalle completo (datos, estado en vivo, probar comandos).

{{ toast.type==='error' ? 'error' : 'check_circle' }} {{ toast.msg }}
warning

Confirmar eliminación

¿Eliminar {{ deleteConfirm.name }}?

vpn_key

Clave temporal

Para {{ tempPasswordModal.name }} ({{ tempPasswordModal.email }})

Pasásela al instalador. Va a tener que cambiarla en el primer login. El email automático todavía no está wireado, así que esta es la única vez que vas a ver esta clave.

{{ tempPasswordModal.password }}