Vigtrack

05:30 · antes del primer relevo

Vigtrack

Control de asistencia y novedades para empresas de vigilancia privada

Una jornada entera —de la primera entrada al cierre del reporte— dentro de una sola aplicación web, con el rastro de quién decidió qué y cuándo.

Web app empresarial · Operaciones y control de personal2026
RolDesarrollador frontend y arquitecto de la aplicación
EstadoEn desarrollo activo — maqueta completa y migración progresiva del mock a la API real

Sistema interno de una empresa de vigilancia · sin acceso público

Riel de fichaje · 01/04/2026Región Miranda
05:58Nieves, José G.CC Líder · Guarenasentrada
06:00Rangel, María C.Torre Mirandaentrada
07:12Chirinos, Ander J.Planta Charallaverelevo
09:45Bastidas, Luis E.Sede Higuerotenovedad
12:30Mendoza, Rosa M.CC Líder · Guarenasrelevo
14:03Salazar, Deivis A.Depósito Santa Teresapuesto sin cubrir
18:00Pacheco, Eglee R.Torre Mirandaentrada
22:40Ojeda, Carlos D.Planta Charallavenovedad
06:00 → 18:00rol de guardias de 24 h
04:40 · antes de la aplicación

Toda una operación dentro de un Excel

Decenas de sedes, varias regiones y una única cuadrícula que todos miraban igual.

parte_cecom_abril.xlsx6 pestañas
ABCDEFG
Categoría010203040506
Ausencias3172
Vacaciones121211111010
Egresos21
Reasignados436
Sin cubrir12

Una empresa de vigilancia privada con oficiales repartidos en decenas de sedes y varias regiones controlaba la asistencia con hojas de cálculo: un parte numérico mensual de categorías por día, listados de ausencias, egresos, ingresos, reasignaciones y vacaciones en pestañas separadas. Nadie podía saber en el momento cuántos puestos estaban descubiertos, quién tenía justificativo pendiente ni en qué manos estaba la decisión sobre una incidencia. Cada rol —supervisor en campo, analista, coordinador, administración— necesitaba una vista distinta de la misma realidad, y el Excel obligaba a todos a mirar la misma cuadrícula.

la traducción

Cada rol mira su propia realidad

Vigtrack traduce esa operación a una aplicación web con control de acceso por rol. El supervisor abre la jornada del día sobre un roster regional que asume presencia por defecto y solo pide marcar la novedad; el analista revisa justificativos y valida inconsistencias; el coordinador aprueba o rechaza y la decisión queda registrada con observación y fecha; el administrador mantiene los catálogos (clientes, sucursales, regiones, tipos de servicio, estatus de oficial, tipos de novedad) y consulta el histórico nacional. El parte numérico deja de ser una hoja y se convierte en un mapa de calor navegable por mes con exportación a CSV. Todo ello con tema claro/oscuro, interfaz bilingüe español/inglés y navegación inferior propia en móvil.

Hoja de cálculoAplicación por rolNadie sabía el estadoJornada con estadoDecisiones sobre hojas de cálculoTres firmas auditables
05:30 · quién entra

Un solo login, cinco aplicaciones

El mismo dominio se comporta como cinco productos distintos: menú, dashboard y rutas protegidas propias.

vigtrack.app/login

Vigtrack

Sistema de Gestión de Seguridad

Correo
usuario@vigtrack.app
Contraseña
••••••••••
Credenciales inválidas
Iniciando sesión…

Bearer inyectado por interceptor · 401 ⇒ logout

Login

AdministradorRequireRole(["admin"])

Mantiene los catálogos y mira el histórico nacional.

DashboardPersonalCatálogosUsuariosReportesHistórico
08:10Alta de sucursal
11:32Nuevo tipo de novedad
16:44Reporte por cliente · CSV
Supervisor regionalRequireRole(["supervisor"])

Abre la jornada y registra lo que pasa en campo.

DashboardAsistencia diariaPlantilla mensualNovedadesJustificativos
05:50Abrir jornada · Miranda
09:45Novedad · ausencia
18:02Cerrar reporte
Analista de operacionesRequireRole(["analyst"])

Revisa justificativos y cruza inconsistencias.

DashboardIncidencias · análisisJustificativosReasignacionesInconsistencias
10:20Justificativo recibido
15:20Incidencia analizada
CoordinadorRequireRole(["coordinator"])

Decide: escala a RRHH o muere en auditoría.

DashboardDecisión de incidenciasAsignación de supervisoresResumen por regiónAlertas
08:05Aprobada · escala a RRHH
08:19Rechazada · auditoría
Centro de coordinaciónRequireRole(["coordination_center"])

Vigila el día entero desde una sola pantalla.

DashboardIncidencias en cursoEventos del díaAlertasNotificaciones
14:03Puesto sin cubrir · alta
14:11Cobertura asignada
07:00 · lo que sostiene la operación

Cinco piezas que no se pueden saltar

01

Cinco roles, cinco aplicaciones

admin, supervisor, analyst, coordinator y coordination_center comparten login y layout, pero cada uno recibe su menú lateral, su barra inferior móvil y su dashboard. Los guards RequireAuth y RequireRole cierran cada ruta a la lista de roles que la pueden ver.

02

Jornada con estado explícito

La asistencia diaria no es una tabla editable suelta: la jornada pasa por sin abrir, abierta y cerrada. Cerrar dispara una confirmación y envía el reporte al coordinador; reabrir exige otra confirmación. El estado es visible como pastilla en la cabecera.

03

Incidencias con tres firmas

Cada novedad recorre pendiente de análisis → analizada → aprobada (escala a RRHH) o rechazada (queda en auditoría). El modal de detalle dibuja el recorrido paso a paso con el rol responsable y la fecha de cada decisión.

04

El parte numérico como mapa de calor

Veinte categorías por treinta días en una cuadrícula con columna fija, leyenda de rangos (0, 1–5, 6–15, 16+) y navegador de mes. Sustituye la hoja de cálculo original sin perder la lectura de un vistazo.

05

Bilingüe, con tema y sesión persistidos

191 claves de traducción en español e inglés, tema claro/oscuro/sistema conmutado desde la barra superior y redux-persist guardando auth, tema e idioma en el navegador para que la sesión sobreviva a la recarga.

09:45 · una novedad en curso

El recorrido de una incidencia

Registrar no es decidir. Entre el campo y RRHH hay tres firmas, y todas quedan con fecha.

1Supervisor Regional

Registra la novedad en campo

Pendiente análisis

01/04 · 09:45

2Analista de Operaciones

Revisa el justificativo

Analizada — por decidir

01/04 · 15:20

3Coordinador

Decisión final con observación

Decisión registrada

02/04 · 08:05

Aprobada · escalada a RRHH

La decisión sale del sistema operativo y entra en el expediente del oficial.

Rechazada · auditoría

La incidencia muere aquí, pero queda registrada con su observación y su fecha.

El modal que dibuja el expediente completo

Los datos del evento arriba en pares etiqueta-valor y, debajo, la línea vertical de pasos: círculo relleno con check para lo hecho, círculo hueco para lo pendiente y círculo rojo con aspa cuando la incidencia se rechaza. Al pie, aprobar en verde, rechazar en rojo contorneado y una observación que no se puede dejar vacía.

Pendiente análisisAnalizada — por decidirAprobada · escalada a RRHHRechazada · auditoría

Detalle de novedad con línea de aprobación

Detalle de la novedad
OficialBastidas, Luis E.CédulaV-12.997.140SedeCC Líder · GuarenasRegiónMirandaTipo de novedadIncidenciaTipo de incidenciaAusencia injustificadaFecha01/04/2026
Recorrido de la aprobación
Supervisor RegionalRegistró la novedad01/04 · 09:45
Analista de OperacionesAnalizó el justificativo01/04 · 15:20
CoordinadorDecisión final— pendiente
Observación (obligatoria)
Escribe el motivo de la decisión…
Aprobar · escala a RRHHRechazar · auditoría
05:59 → 06:00

La jornada se abre.

A partir de aquí todo ocurre a la luz del día: el roster, el parte numérico, la plantilla del mes. Las mismas pantallas que sustituyeron a la hoja de cálculo.

12:00 · la jornada abierta

Las pantallas donde se trabaja

Recreadas aquí en HTML y CSS, con los mismos colores, pastillas y disposición del producto.

vigtrack.app/attendance/daily

Asistencia diaria

Región Miranda · presente-por-defecto: todos laboran salvo novedad

TodosSin novedadCon novedad
2026-04-01
Sin abrir Abrir jornada
Jornada no iniciada — abre la jornada para registrar el estado del día
34 oficiales · miércoles, 1 de abril31 presentes3 con novedad
NNieves, José G.V-14.208.771Presente
RRangel, María C.V-19.443.902Presente
BBastidas, Luis E.V-12.997.140Cita médica · cubierta
CChirinos, Ander J.V-21.008.365Presente
SSalazar, Deivis A.V-17.554.881Ausencia · sin justificativo
PPacheco, Eglee R.V-23.117.409Presente

Asistencia diaria del supervisor

Presente por defecto: solo se marca la excepción.

vigtrack.app/incidencias/decision
Decisión de incidencias7 por decidir

Región Miranda · decisión final tras el análisis. El Analista analiza primero; aquí apruebas (escala a RRHH) o rechazas (muere en auditoría).

Buscar oficial / motivo…
Todos los clientes Todos los motivos Todos los estados Limpiar
OficialSede / clienteMotivoFechaEstado
Bastidas, Luis E.CC Líder · GuarenasCentro LíderAusencia injustificada01/04/2026Analizada — por decidir
Salazar, Deivis A.Depósito Santa TeresaAlimentos Santa TeresaAbandono de puesto01/04/2026Analizada — por decidir
Ojeda, Carlos D.Planta CharallaveIndustrias CharallaveRetardo reiterado31/03/2026Pendiente análisis
Mendoza, Rosa M.Torre MirandaCorporación MirandaFalta de uniforme30/03/2026Aprobada · escalada a RRHH
Chirinos, Ander J.Sede HigueroteMarina HigueroteAusencia justificada29/03/2026Rechazada · auditoría
Mostrando 1–10 de 34123

Incidencias — decisión del coordinador

Una sola ruta, tres experiencias según el rol del store.

Las maquetas reproducen la interfaz real; los datos que muestran son de ejemplo.

16:20 · el parte del día

La hoja de cálculo, convertida en color

Veinte categorías por treinta días y un damero de turnos de 24 horas: dos cuadrículas que se leen de un vistazo y se exportan a CSV.

Parte Numérica

20 categorías · 30 días

Abril
01–56–1516+ CSV
Categoría123456789101112131415161718192021222324252627282930
Ausencia injustificada6111621381823510152071217224919161116218
Reposo médico81420915214101651117236121713192820391521
Cita médica15226132041829162372151219310181522613411
Vacaciones22723816191710183111942051321614715238161
Permiso legal61511019142391841381731221721120615119514
Ingreso de personal1310207174141121818515122291961613231020717
Egreso de personal20819761751641514213112232210219208718617
Reasignación165176187820921102223121132141541651767
Cobertura por backup11114177201023131661992212155188211114417720
Puesto sin cubrir189231451911562011272112317813418923141910
Retardo21711682315714621135204191131810179116823
Cambio de turno9218114136221581103191252172316921842013
Suspensión164211593208219137112623171151610421159
Servicio extra2318138211611611994221712720151052318832116
Capacitación3221814106211713951161284231911732218146
Incidencia disciplinaria1411822219161310412118151263232017148522219
Abandono de puesto21191715131175312220161412108622321191715119
Traslado temporal5421232221201817161514131110987643212322
Reposo post-vacacional1212121212121212121212121212121212121212121212121212
Renuncia19212223123567891012131415161719202122231

Parte numérica (mapa de calor)

Plantilla mensual

30 días por oficial · damero de 24 horas

Abril
CSV
24hdía laboradoLlibreAausenciaVvacaciones
Oficial123456789101112131415161718192021222324252627282930
Nieves, José G.GRP-A24hL24hL24hL24hL24hL24hL24hL24hL24hL24hL24hL24hL24hL24hL24hL
Rangel, María C.GRP-BL24hL24hL24hL24hL24hL24hA24hL24hL24hL24hL24hL24hL24hL24hL24h
Chirinos, Ander J.GRP-A24hL24hL24hL24hL24hL24hL24hL24hL24hL24hL24hL24hL24hL24hL24hL
Bastidas, Luis E.GRP-C24hL24hL24hL24hL24hL24hA24hL24hL24hL24hL24hL24hL24hL24hL24hL
Mendoza, Rosa M.GRP-BL24hL24hL24hL24hL24hL24hL24hL24hLVVVVVVVL24hL24hL24h
Salazar, Deivis A.GRP-C24hL24hL24hL24hL24hL24hL24hA24hL24hL24hL24hL24hL24hL24hL24hL
Pacheco, Eglee R.GRP-A24hL24hL24hL24hL24hL24hL24hL24hL24hL24hL24hL24hL24hL24hL24hL
Ojeda, Carlos D.GRP-BL24hL24hL24hL24hL24hL24hA24hL24hL24hL24hL24hL24hL24hL24hL24h

Plantilla mensual

Columna fija

position sticky con fondo propio en claro y oscuro: al desplazarse treinta días no se pierde de vista la fila.

Color por rango

0, 1–5, 6–15 y 16+ con su leyenda, para interpretar la cuadrícula sin leer un solo número.

CSV con BOM UTF-8

El utilitario exportCsv escribe el BOM, escapa comillas y usa CRLF: Excel en español respeta ñ y tildes.

18:00 · cambio de turno

El tamaño real de la maqueta

25

rutas registradas

15

módulos feature-first

24

páginas con carga diferida

5

roles con navegación propia

6

dashboards por rol

42

funciones de API tipadas

11

recursos REST consumidos

2

idiomas (es / en)

191

claves de traducción

9

tipos de evento operativo

20:00 · el turno completo

Quince marcas en la misma jornada

Cada funcionalidad, fichada a su hora. Es todo lo que hoy hace la aplicación.

06:00

Login con email y contraseña contra la API real, token Bearer inyectado por interceptor y expulsión automática al recibir un 401

07:15

Dashboards diferenciados por rol con tarjetas KPI (oficiales activos, presentes, con novedad, cubiertos por backup, puestos sin cubrir, vacaciones, reasignaciones)

08:30

Asistencia diaria por región con filtros Todos / Sin novedad / Con novedad, navegador de fecha y apertura y cierre de jornada

09:45

Plantilla mensual de 30 días por oficial con celdas de estado (24h, L de libre, A de ausencia, V de vacaciones) y columna de nombre fija al hacer scroll horizontal

11:00

Módulo de novedades y eventos con nueve tipos (ingreso, egreso, reasignación, vacación, ausencia, reposo médico, cobertura, incidencia y asignación de supervisor)

12:15

Flujo de incidencias con vistas separadas para coordinador, analista y centro de coordinación, modales de decisión y de detalle, y filtros por cliente, motivo y estado

13:30

Justificativos, reasignaciones y validación cruzada de inconsistencias para el analista de operaciones

14:45

Asignación de supervisores a sedes con selección múltiple, buscador de sede y aplicación inmediata o programada a una fecha

16:00

CRUD de personal con búsqueda con debounce, filtros por estatus, cliente y sede, cambio de estatus mediante modal y paginación servidor

17:15

Catálogos en pestañas: tipos de novedad e incidencia, estatus de oficiales, tipos de servicio y regiones

18:30

Parte numérica, resumen por región y reporte por cliente, todos exportables a CSV con BOM UTF-8 para que Excel respete los acentos

19:45

Tablero de alertas con severidad alta, media y baja, marcado individual y marcar todo como leído

21:00

Centro de notificaciones con feed, cajón lateral y contador de no leídas

22:15

Tema claro, oscuro o del sistema y conmutador de idioma es/en desde la barra superior

23:30

Layout responsive: barra lateral fija en escritorio, cajón deslizante y navegación inferior por rol en móvil

21:10 · con qué está hecho

El cuadro de turnos técnico

InterfazReact 18.3TypeScript 5.5 (strict)Tailwind CSS 3.4clsxtailwind-mergeclass-variance-authoritylucide-react
Estado y datosRedux Toolkit 2react-redux 9redux-persist 6Axios 1.13 con interceptores
Rutas y formulariosReact Router 7 con lazy loadingReact Hook Form 7Zod 3@hookform/resolvers
HerramientasVite 7@vitejs/plugin-react-swcPostCSSAutoprefixerESLint 10typescript-eslintPrettier
Retroalimentación al usuarioSonner (toasts)Modales de confirmación e información propios sobre Redux
22:00 · bajo el capó

Feature-first, y un solo contrato

Quince módulos autónomos, una capa HTTP tipada y un mock poblado con la exportación real del Excel.

estructura del proyecto
src/
├─ app/App · routes.tsx · providers
├─ shared/
│ ├─ api/cliente Axios · interceptores · ApiResult
│ ├─ components/ui · data · form · feedback · pagination · layout
│ ├─ hooks/usePagination · useApi · useDebounce · useT · useAuth
│ ├─ store/auth · theme · lang · ui · notifications · incidencias
│ ├─ i18n/es · en · 191 claves
│ ├─ mock/db.ts — exportación real del Excel operativo
│ └─ utils/notify · exportCsv · applyServerErrors · cn
└─ features/15 módulos autónomos · 25 rutas diferidas

type ApiResult<T> =

| { ok: true; data: T }

| { ok: false; status; detail; fieldErrors }

Arquitectura feature-first sobre Vite + SWC. En src/app viven el bootstrap (App, routes y providers); en src/shared, todo lo transversal: la capa api (cliente Axios con interceptores de request y response, handlers y el tipo ApiResult<T> que devuelve {ok:true,data} o {ok:false,status,detail,fieldErrors}), los componentes reutilizables agrupados en ui, data, form, feedback, pagination y layout, los hooks (usePagination, useApi, useDebounce, useT, useAuth, useTheme, useMediaQuery), el store de Redux Toolkit con seis slices (auth, theme, lang, ui, notifications e incidencias), la i18n con dos ficheros de locales y las utilidades (notify, exportCsv, applyServerErrors, cn). En src/features hay quince módulos autónomos —auth, dashboard, personal, attendance, events, incidencias, justifications, reports, assignments, catalogs, users, admin, operator, notifications y profile— cada uno con sus carpetas pages, components, api, schemas, types, hooks y store según necesite. Las veinticinco rutas se declaran en un único routes.tsx con carga diferida por página y se envuelven en guards RequireAuth y RequireRole. El cliente HTTP compone la baseURL con las variables VITE_PUBLIC_URL_API y VITE_PUBLIC_URL_VERSION, añade el token del store y la cabecera Accept-Language según el idioma activo, fuerza logout ante un 401 fuera del login y levanta un modal de error ante cualquier 5xx. Once módulos de API cubren cuarenta y dos operaciones tipadas sobre once recursos REST (auth, users, clients, sites, regions, officers, positions, incident-types, officer-statuses, service-types y events); los módulos aún no migrados leen del mock DB de src/shared/mock/db.ts, poblado con la exportación real del Excel operativo, de modo que el cambio de mock a red no toca los componentes.

Los quince módulos

authdashboardpersonalattendanceeventsincidenciasjustificationsreportsassignmentscatalogsusersadminoperatornotificationsprofile

42

funciones de API tipadas

11

recursos REST

6

slices de Redux

22:40 · lo que costó

Cinco novedades del propio proyecto

Registradas, analizadas y resueltas — el mismo ciclo que aplica la aplicación, aplicado al código.

Registrada#01

El mismo dominio tenía que comportarse como cinco productos distintos sin duplicar el layout ni dejar rutas abiertas por descuido.

Resuelta

Un único AppLayout con Sidebar y Topbar, y un mapa navByRole que define la navegación de cada rol. Las rutas se envuelven en RequireRole con la lista explícita de roles permitidos, y páginas como Incidencias delegan en un componente distinto según el rol leído del store, de modo que una sola ruta sirve tres experiencias.

Registrada#02

Diseñar contra datos ficticios habría producido pantallas que se rompen con la operación real: nombres largos, decenas de sedes, meses completos de parte numérico.

Resuelta

Se exportó el Excel operativo a un mock tipado con ochenta y siete oficiales, setenta y un ausencias, cincuenta vacaciones, veintiocho ingresos, veintitrés egresos, veintidós reasignaciones y veinte categorías de parte numérico. Cada tabla, mapa de calor y modal se ajustó contra ese volumen antes de existir el backend.

Registrada#03

Había que empezar a consumir la API real sin bloquear el desarrollo de los módulos que todavía no tenían endpoint.

Resuelta

Todos los servicios devuelven el mismo contrato ApiResult<T> y las páginas consumen datos a través de hooks (useApi, usePagination), no de Axios directamente. Eso permitió migrar auth, usuarios, clientes, sucursales, oficiales, catálogos y eventos uno a uno mientras asistencia, plantilla, reportes y alertas seguían leyendo del mock, sin reescribir componentes.

Registrada#04

Una cuadrícula de treinta días por oficial o por categoría se vuelve ilegible en cuanto se hace scroll horizontal: se pierde de vista a quién pertenece la fila.

Resuelta

Las tablas de plantilla y parte numérica fijan la primera columna con position sticky y fondo propio en claro y oscuro, usan celdas de ancho fijo y color por estado, y añaden una leyenda de rangos para que el color se pueda interpretar sin leer los números.

Registrada#05

Exportar a CSV en un entorno donde todo se abre con Excel en español rompía los acentos de nombres y motivos.

Resuelta

El utilitario exportCsv escribe un BOM UTF-8 al inicio del blob, escapa comillas dobles y usa saltos CRLF, de forma que Excel interpreta correctamente ñ, tildes y comas dentro de los campos.

23:00 · el sistema de color

El color nunca decora: informa

Sobrio, institucional y operativo — azul corporativo sobre gris azulado frío, con una barra lateral casi negra (#0f172a) como ancla visual. El color nunca decora: solo informa. La escala semántica completa es ok #16a34a sobre #dcfce7, warn #d97706 sobre #fef3c7, crit #dc2626 sobre #fee2e2 e info #0891b2 sobre #cffafe. Bordes #e2e8f0, texto secundario #64748b, terciario #94a3b8, radio de 10px y sombras muy suaves.

primary#2563ebacción y estado activo
secondary#0f172abarra lateral · ancla
accent#16a34aok · presente · aprobada
bg#eef2f7fondo de la aplicación
surface#fffffftarjetas y tablas
text#0f172atexto principal

ok

presente · aprobada

warn

novedad · por decidir

crit

sin cubrir · rechazada

info

informativo · relevo

Favicon actual de Vigtrackfavicon.svglo que sirve hoy index.html

Favicon SVG que index.html sirve actualmente: un rayo morado (#863bff) con degradados difuminados heredado de la plantilla de arranque. No es una marca propia de Vigtrack — el proyecto todavía no tiene logotipo definitivo.

es / en · 191 claves claro oscuro sistema
23:30 · cierre de jornada

Vigtrack es el panel web con el que una empresa de seguridad privada deja de llevar la asistencia de sus oficiales en hojas de Excel. Cada día, cada región y cada puesto quedan registrados en una misma aplicación, con un flujo de aprobación que se puede auditar.

La aplicación no es un único tablero: son cinco aplicaciones distintas bajo el mismo dominio. Administrador, supervisor regional, analista de operaciones, coordinador y centro de coordinación entran con el mismo login y reciben su propio menú lateral, su propio dashboard y su propio conjunto de rutas protegidas.

El núcleo del sistema es el ciclo de una novedad: el supervisor la registra en campo, el analista revisa el justificativo, el coordinador decide, y el resultado escala a RRHH o muere en auditoría. Ese recorrido se muestra como una línea de pasos con fechas dentro del detalle de cada evento.

Está construido feature-first sobre React 18, TypeScript en modo estricto y Vite: quince módulos independientes, veinticinco rutas registradas con carga diferida, Redux Toolkit con persistencia, formularios validados con Zod y una capa HTTP tipada que devuelve siempre un ApiResult.

Los datos de la maqueta no son inventados: provienen de la exportación real del Excel operativo (parte CECOM y personal activo), lo que permitió diseñar cada pantalla contra volúmenes y casos reales antes de conectar el backend.

ingresoegresoreasignaciónvacaciónausenciareposo médicocoberturaincidenciaasignación de supervisoringresoegresoreasignaciónvacaciónausenciareposo médicocoberturaincidenciaasignación de supervisor

Vigtrack

¿Quieres algo así para tu producto?

Una operación completa —cinco roles, un ciclo de aprobación auditable y las cuadrículas que sustituyen al Excel— dentro de una sola aplicación React. Si tu empresa lleva su control en hojas de cálculo, éste es exactamente el terreno que conozco.