Rewrite README.md, DOCUMENTATION.md, ESTADO_ACTUAL.md and CAMBIOS_SESION.md to accurately document the full-stack architecture, all modules, API endpoints, JWT auth, database schema, and features added in February 2026. Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
23 KiB
Documentacion Tecnica - GRH (Gestion de Recursos Hidricos)
Documentacion tecnica detallada de la arquitectura, componentes, API y patrones del sistema.
Tabla de Contenidos
- Arquitectura del Sistema
- Frontend - Componentes y Paginas
- Backend - API REST
- Base de Datos
- Autenticacion y Autorizacion
- Capa de API del Frontend
- Hooks Personalizados
- Sistema de Temas
- Conectores Externos
- Tareas Programadas
- Guia de Desarrollo
Arquitectura del Sistema
Vision General
El proyecto es una aplicacion full-stack con tres componentes principales:
┌─────────────────────────────────────────────────────────────┐
│ Capa de Presentacion │
│ React SPA: Pages, Components, Layout │
├─────────────────────────────────────────────────────────────┤
│ Capa de Logica (Frontend) │
│ Custom Hooks, API Client con JWT, Estado Local │
├─────────────────────────────────────────────────────────────┤
│ Capa de API (Backend) │
│ Express Routes → Controllers → Services → PostgreSQL │
├─────────────────────────────────────────────────────────────┤
│ Capa de Datos │
│ PostgreSQL: 10 tablas, 2 vistas, triggers, indices │
├─────────────────────────────────────────────────────────────┤
│ Integraciones Externas │
│ The Things Stack (LoRaWAN), SH-Meters, XMeters │
└─────────────────────────────────────────────────────────────┘
Patrones de Diseno
- Container/Presentational - Paginas manejan logica, componentes renderizan UI
- Custom Hooks - Logica reutilizable en hooks (
useMeters,useConcentrators,useNotifications) - Module Pattern - Codigo organizado por dominio (
meters/,concentrators/,analytics/) - Service Layer (Backend) - Routes → Controllers → Services → Database
- Repository Pattern - Cada servicio encapsula las queries SQL de su dominio
- Middleware Pipeline - Auth, audit logging, webhook verification
Frontend - Componentes y Paginas
App.tsx - Componente Raiz
Maneja autenticacion global, routing por estado interno y modales globales.
export type Page =
| "home" | "projects" | "meters" | "concentrators"
| "consumption" | "auditoria" | "users" | "roles"
| "sh-meters" | "xmeters" | "tts"
| "analytics-map" | "analytics-reports" | "analytics-server";
La navegacion es state-based (sin React Router). El estado currentPage determina que pagina se renderiza.
Paginas Principales
| Pagina | Archivo | Descripcion |
|---|---|---|
| Dashboard | Home.tsx |
KPIs, graficos Recharts, selector de organismos, alertas |
| Login | LoginPage.tsx |
Formulario de autenticacion |
| Medidores | meters/MeterPage.tsx |
CRUD con tabla, sidebar, filtros, carga masiva |
| Concentradores | concentrators/ConcentratorsPage.tsx |
CRUD con tabla y sidebar |
| Proyectos | projects/ProjectsPage.tsx |
Tabla de proyectos con estados |
| Consumo | consumption/ConsumptionPage.tsx |
Lecturas con filtros y estadisticas |
| Usuarios | UsersPage.tsx |
Gestion de usuarios (admin) |
| Roles | RolesPage.tsx |
Gestion de roles y permisos |
| Auditoria | AuditoriaPage.tsx |
Visor de logs de actividad |
| Mapa | analytics/AnalyticsMapPage.tsx |
Mapa Leaflet con ubicaciones de medidores |
| Reportes | analytics/AnalyticsReportsPage.tsx |
Reportes de consumo |
| Servidor | analytics/AnalyticsServerPage.tsx |
Metricas CPU, memoria, requests |
| SH-Meters | conectores/SHMetersPage.tsx |
Conector SH-Meters |
| XMeters | conectores/XMetersPage.tsx |
Conector XMeters |
| TTS | conectores/TTSPage.tsx |
Conector The Things Stack |
Componentes de Layout
Sidebar.tsx
- Menu lateral colapsable con hover expansion
- Soporte para pin/unpin
- Menu jerarquico con submenus (Analytics, Conectores)
- Indicadores visuales de pagina activa
TopMenu.tsx
- Breadcrumb de navegacion
- Dropdown de notificaciones con conteo de no leidas
- Menu de usuario: perfil, configuracion, logout
Componentes Comunes
ProfileModal.tsx- Edicion de perfil con avatar localConfirmModal.tsx- Confirmacion de acciones destructivasWatermark.tsx- Marca de agua GRHProjectBadge.tsx- Badge visual de proyectoSettingsModals.tsx- Configuracion de tema y modo compactoNotificationDropdown.tsx- Panel de notificaciones
Backend - API REST
Estructura de Archivos
water-api/src/
├── index.ts # Setup Express: CORS, Helmet, body-parser, rutas
├── config/
│ ├── index.ts # Variables de entorno centralizadas
│ └── database.ts # Pool de conexiones pg
├── routes/ # Definicion de rutas (17 archivos)
├── controllers/ # Controladores HTTP
├── services/ # Logica de negocio (18 modulos)
├── middleware/
│ ├── auth.middleware.ts # Verificacion JWT + extraccion de rol
│ ├── audit.middleware.ts # Auto-logging de acciones
│ └── ttsWebhook.middleware.ts # Verificacion de secreto webhook
├── validators/ # Schemas de validacion Zod
├── utils/
│ ├── jwt.ts # sign/verify de tokens
│ ├── password.ts # hash/compare con bcrypt
│ └── logger.ts # Winston con formato timestamp
├── jobs/
│ └── negativeFlowDetection.ts # Cron de deteccion de flujo negativo
└── types/ # Interfaces TypeScript
Endpoints Detallados
Autenticacion (/api/auth)
| Metodo | Ruta | Descripcion | Auth |
|---|---|---|---|
| POST | /login |
Autenticar usuario | No |
| POST | /refresh |
Renovar access token | No (usa refresh token) |
| POST | /logout |
Cerrar sesion | Si |
| GET | /me |
Obtener perfil actual | Si |
| PATCH | /me |
Actualizar perfil | Si |
Proyectos (/api/projects)
| Metodo | Ruta | Descripcion | Auth |
|---|---|---|---|
| GET | / |
Listar proyectos | Si |
| GET | /:id |
Obtener proyecto | Si |
| GET | /:id/stats |
Estadisticas del proyecto | Si |
| POST | / |
Crear proyecto | Si (ADMIN/OPERATOR) |
| PUT | /:id |
Actualizar proyecto | Si (ADMIN/OPERATOR) |
| DELETE | /:id |
Eliminar proyecto | Si (ADMIN) |
Medidores (/api/meters)
| Metodo | Ruta | Descripcion | Auth |
|---|---|---|---|
| GET | / |
Listar medidores (filtros: project, status, type) | Si |
| GET | /:id |
Obtener medidor | Si |
| GET | /:id/readings |
Historial de lecturas del medidor | Si |
| POST | / |
Crear medidor | Si (ADMIN/OPERATOR) |
| PUT | /:id |
Actualizar medidor | Si (ADMIN/OPERATOR) |
| DELETE | /:id |
Eliminar medidor | Si (ADMIN) |
Concentradores (/api/concentrators)
| Metodo | Ruta | Descripcion | Auth |
|---|---|---|---|
| GET | / |
Listar concentradores | Si |
| GET | /:id |
Obtener concentrador | Si |
| POST | / |
Crear concentrador | Si (ADMIN/OPERATOR) |
| PUT | /:id |
Actualizar concentrador | Si (ADMIN/OPERATOR) |
| DELETE | /:id |
Eliminar concentrador | Si (ADMIN) |
Gateways (/api/gateways)
| Metodo | Ruta | Descripcion | Auth |
|---|---|---|---|
| GET | / |
Listar gateways | Si |
| GET | /:id |
Obtener gateway | Si |
| GET | /:id/devices |
Dispositivos del gateway | Si |
| POST | / |
Crear gateway | Si (ADMIN/OPERATOR) |
| PUT | /:id |
Actualizar gateway | Si (ADMIN/OPERATOR) |
| DELETE | /:id |
Eliminar gateway | Si (ADMIN) |
Dispositivos (/api/devices)
| Metodo | Ruta | Descripcion | Auth |
|---|---|---|---|
| GET | / |
Listar dispositivos | Si |
| GET | /:id |
Obtener dispositivo | Si |
| GET | /dev-eui/:devEui |
Buscar por DevEUI | Si |
| POST | / |
Crear dispositivo | Si (ADMIN/OPERATOR) |
| PUT | /:id |
Actualizar dispositivo | Si (ADMIN/OPERATOR) |
| DELETE | /:id |
Eliminar dispositivo | Si (ADMIN) |
Usuarios (/api/users) - Solo ADMIN
| Metodo | Ruta | Descripcion | Auth |
|---|---|---|---|
| GET | / |
Listar usuarios | Si (ADMIN) |
| GET | /:id |
Obtener usuario | Si (ADMIN o self) |
| POST | / |
Crear usuario | Si (ADMIN) |
| PUT | /:id |
Actualizar usuario | Si (ADMIN o self) |
| DELETE | /:id |
Desactivar usuario | Si (ADMIN) |
| PUT | /:id/password |
Cambiar contrasena | Si (self) |
Roles (/api/roles)
| Metodo | Ruta | Descripcion | Auth |
|---|---|---|---|
| GET | / |
Listar roles | Si |
| GET | /:id |
Obtener rol con conteo de usuarios | Si |
| POST | / |
Crear rol | Si (ADMIN) |
| PUT | /:id |
Actualizar rol | Si (ADMIN) |
| DELETE | /:id |
Eliminar rol | Si (ADMIN) |
Tipos de Medidor (/api/meter-types)
| Metodo | Ruta | Descripcion | Auth |
|---|---|---|---|
| GET | / |
Listar tipos | Si |
| GET | /:id |
Obtener por ID | Si |
| GET | /code/:code |
Obtener por codigo | Si |
| POST | / |
Crear tipo | Si (ADMIN) |
| PUT | /:id |
Actualizar tipo | Si (ADMIN) |
| DELETE | /:id |
Eliminar tipo | Si (ADMIN) |
Lecturas (/api/readings)
| Metodo | Ruta | Descripcion | Auth |
|---|---|---|---|
| GET | / |
Listar lecturas (filtros: proyecto, fecha, medidor) | Si |
| GET | /summary |
Resumen de consumo | Si |
| GET | /:id |
Obtener lectura | Si |
| POST | / |
Crear lectura | Si |
| DELETE | /:id |
Eliminar lectura | Si (ADMIN) |
Notificaciones (/api/notifications)
| Metodo | Ruta | Descripcion | Auth |
|---|---|---|---|
| GET | / |
Listar notificaciones del usuario | Si |
| GET | /unread-count |
Conteo de no leidas | Si |
| GET | /:id |
Obtener notificacion | Si |
| PATCH | /:id/read |
Marcar como leida | Si |
| PATCH | /read-all |
Marcar todas como leidas | Si |
| DELETE | /:id |
Eliminar notificacion | Si |
Auditoria (/api/audit-logs) - Solo ADMIN
| Metodo | Ruta | Descripcion | Auth |
|---|---|---|---|
| GET | / |
Listar logs | Si (ADMIN) |
| GET | /my-activity |
Actividad del usuario actual | Si |
| GET | /statistics |
Estadisticas de auditoria | Si (ADMIN) |
| GET | /:id |
Detalle de un log | Si (ADMIN) |
| GET | /record/:tableName/:recordId |
Logs de un registro especifico | Si (ADMIN) |
Carga Masiva
| Metodo | Ruta | Descripcion | Auth |
|---|---|---|---|
| POST | /bulk-upload/meters |
Subir Excel de medidores | Si |
| GET | /bulk-upload/meters/template |
Descargar plantilla Excel | Si |
| POST | /csv-upload/meters |
Subir CSV de medidores (upsert) | No |
| POST | /csv-upload/readings |
Subir CSV de lecturas | No |
| GET | /csv-upload/meters/template |
Plantilla CSV medidores | No |
| GET | /csv-upload/readings/template |
Plantilla CSV lecturas | No |
TTS Webhooks (/api/webhooks/tts)
| Metodo | Ruta | Descripcion | Auth |
|---|---|---|---|
| GET | /health |
Health check del webhook | No |
| POST | /uplink |
Recibir mensajes uplink | Webhook secret |
| POST | /join |
Recibir eventos de join | Webhook secret |
| POST | /downlink/ack |
Recibir acks de downlink | Webhook secret |
Sistema (/api/system) - Solo ADMIN
| Metodo | Ruta | Descripcion | Auth |
|---|---|---|---|
| GET | /metrics |
Metricas del servidor (CPU, memoria, requests) | Si (ADMIN) |
| GET | /health |
Health check detallado | Si (ADMIN) |
| GET | /meters-locations |
Coordenadas de medidores para mapa | Si (ADMIN) |
| GET | /report-stats |
Estadisticas para reportes | Si (ADMIN) |
Base de Datos
Esquema Relacional
roles ←─── users ←─── refresh_tokens
│
▼
projects
╱ │ ╲
╱ │ ╲
▼ ▼ ▼
concentrators gateways meters ──→ meter_readings
│ │
▼ │
devices ─────┘
│
▼
tts_uplink_logs
ENUMs de PostgreSQL
role_name: ADMIN, OPERATOR, VIEWERproject_status: ACTIVE, INACTIVE, COMPLETEDdevice_status: ACTIVE, INACTIVE, OFFLINE, MAINTENANCE, ERRORmeter_type: WATER, GAS, ELECTRICreading_type: AUTOMATIC, MANUAL, SCHEDULED
Migraciones SQL
Ejecutar en orden despues del schema principal:
schema.sql- Schema principal con 10 tablas, 2 vistas, seed de roles y adminadd_audit_logs.sql- Tabla de logs de auditoriaadd_notifications.sql- Tabla de notificacionesadd_meter_extended_fields.sql- Campos extendidos para medidorescreate_meter_types.sql- Tabla de tipos de medidoradd_meter_project_relation.sql- Relacion meter-proyectoadd_user_project_relation.sql- Relacion user-proyecto
Autenticacion y Autorizacion
Flujo JWT
┌──────────┐ POST /auth/login ┌──────────┐
│ Cliente │ ───────────────────→ │ Backend │
│ │ ←─────────────────── │ │
└──────────┘ {accessToken, └──────────┘
refreshToken} │
│ │ bcrypt.compare()
│ Authorization: Bearer <token> │ jwt.sign()
│ ───────────────────────────→ │
│ │ jwt.verify()
│ │
│ 401 Unauthorized │
│ ←─────────────────────────── │
│ │
│ POST /auth/refresh │
│ {refreshToken} │
│ ───────────────────────────→ │
│ ←─────────────────────────── │
│ {newAccessToken} │
Tokens
- Access Token - JWT con userId, roleId, roleName, projectId. Expira en 15 minutos.
- Refresh Token - JWT almacenado hasheado en BD. Expira en 7 dias. Revocable.
Token Refresh Automatico (Frontend)
El cliente HTTP (src/api/client.ts) intercepta respuestas 401 y automaticamente:
- Pone en cola las peticiones pendientes
- Llama a
/auth/refreshcon el refresh token - Reintenta las peticiones con el nuevo access token
Almacenamiento en localStorage
grh_access_token → JWT access token
grh_refresh_token → JWT refresh token
water_project_settings_v1 → {theme, compactMode}
mock_avatar → Avatar en base64
Control de Acceso por Rol
| Recurso | ADMIN | OPERATOR | VIEWER |
|---|---|---|---|
| Usuarios | CRUD completo | Solo lectura | Sin acceso |
| Proyectos | CRUD completo | Crear/Leer/Actualizar | Solo lectura |
| Dispositivos | CRUD completo | Crear/Leer/Actualizar | Solo lectura |
| Medidores | CRUD completo | Crear/Leer/Actualizar | Solo lectura |
| Lecturas | CRUD + eliminar | Crear/Leer | Solo lectura |
| Configuracion | Completa | Solo lectura | Sin acceso |
| Reportes | Crear/Leer/Exportar | Crear/Leer/Exportar | Solo lectura |
Helpers del Frontend
getCurrentUserRole() // → "ADMIN" | "OPERATOR" | "VIEWER"
getCurrentUserId() // → UUID string
getCurrentUserProjectId() // → UUID string | undefined
isCurrentUserAdmin() // → boolean
Capa de API del Frontend
Cliente HTTP (src/api/client.ts)
Wrapper de fetch con:
- Inyeccion automatica de
Authorization: Bearer <token> - Refresh automatico de tokens en 401
- Cola de peticiones durante el refresh (previene race conditions)
- Buffer de 30 segundos antes de expirar
- Transformacion de snake_case (backend) a camelCase (frontend)
Modulos de API
| Archivo | Descripcion |
|---|---|
auth.ts |
Login, logout, refresh, getMe, helpers de roles |
client.ts |
Cliente HTTP base con JWT |
meters.ts |
CRUD medidores + lecturas |
readings.ts |
Lecturas y resumen de consumo |
projects.ts |
CRUD proyectos + nombres |
concentrators.ts |
CRUD concentradores |
users.ts |
CRUD usuarios |
roles.ts |
CRUD roles |
analytics.ts |
Metricas, ubicaciones, reportes |
notifications.ts |
Notificaciones del usuario |
audit.ts |
Logs de auditoria |
me.ts |
Perfil de usuario actual |
meterTypes.ts |
Tipos de medidor |
types.ts |
Interfaces compartidas |
Hooks Personalizados
useMeters
Gestiona el estado completo del modulo de medidores.
interface UseMetersReturn {
// Datos
meters: Meter[];
filteredMeters: Meter[];
projectNames: string[];
// Estado
loading: boolean;
selectedMeter: Meter | null;
selectedProject: string | null;
searchTerm: string;
// Acciones
setSelectedMeter: (meter: Meter | null) => void;
setSelectedProject: (project: string | null) => void;
setSearchTerm: (term: string) => void;
refreshData: () => Promise<void>;
loadMeters: () => Promise<void>;
// CRUD
handleCreate: (data: Partial<Meter>) => Promise<void>;
handleUpdate: (id: string, data: Partial<Meter>) => Promise<void>;
handleDelete: (id: string) => Promise<void>;
}
useConcentrators
Estructura equivalente a useMeters para el modulo de concentradores.
useNotifications
Gestiona notificaciones del usuario con polling periodico.
interface UseNotificationsReturn {
notifications: Notification[];
unreadCount: number;
loading: boolean;
markAsRead: (id: string) => Promise<void>;
markAllAsRead: () => Promise<void>;
deleteNotification: (id: string) => Promise<void>;
refresh: () => Promise<void>;
}
Flujo de Datos
API Layer (fetch + JWT)
│
▼
Custom Hook (useMeters, etc.)
│
▼
Page Component (MeterPage, etc.)
│
├──────────────┬──────────────┐
▼ ▼ ▼
Sidebar Table Modal
Sistema de Temas
Configuracion
Tres modos disponibles: system, light, dark.
type Theme = "system" | "light" | "dark";
// Aplicacion del tema
document.documentElement.classList.toggle("dark", isDark);
Paleta de Colores (Dark Mode)
El dark mode usa la paleta Zinc de Tailwind:
- Fondo principal:
bg-zinc-900 - Fondo de tarjetas:
bg-zinc-800 - Bordes:
border-zinc-700 - Texto primario:
text-zinc-100 - Texto secundario:
text-zinc-400
Persistencia
const SETTINGS_KEY = "water_project_settings_v1";
interface Settings {
theme: "system" | "light" | "dark";
compactMode: boolean;
}
Conectores Externos
SH-Meters
Conector para sistema de medidores SH. Muestra estado de conexion, ultima sincronizacion y datos sincronizados.
XMeters
Conector para sistema XMeters con funcionalidad similar a SH-Meters.
The Things Stack (TTS)
Integracion con LoRaWAN via webhooks:
- Uplink (
POST /api/webhooks/tts/uplink): Recibe lecturas de sensores, decodifica payload, crea readings automaticamente - Join (
POST /api/webhooks/tts/join): Registra eventos de conexion de dispositivos - Downlink Ack (
POST /api/webhooks/tts/downlink/ack): Confirma envio de comandos a dispositivos
Los webhooks usan verificacion por secreto en lugar de JWT.
Sincronizacion
Los conectores tienen sincronizacion programada a las 9:00 AM.
Tareas Programadas
Deteccion de Flujo Negativo
Job de node-cron que:
- Revisa lecturas recientes de medidores
- Detecta valores negativos o anomalias
- Genera notificaciones automaticas para los usuarios
Guia de Desarrollo
Agregar una Nueva Pagina
- Crear el componente en
src/pages/nueva/NuevaPage.tsx - Agregar al tipo Page en
App.tsx - Agregar al Sidebar en
Sidebar.tsx(menuItems) - Agregar al renderizado en
App.tsx(switch enrenderPage())
Agregar un Nuevo Endpoint en el Backend
- Crear servicio en
water-api/src/services/nuevo.service.ts - Crear controlador en
water-api/src/controllers/nuevo.controller.ts - Crear validador (opcional) en
water-api/src/validators/nuevo.validator.ts - Crear rutas en
water-api/src/routes/nuevo.routes.ts - Registrar rutas en
water-api/src/routes/index.ts
Agregar un Modulo de API en el Frontend
- Crear archivo en
src/api/nuevo.ts - Usar el cliente HTTP importando de
./client.ts - Crear hook (opcional) en
src/pages/nueva/useNuevo.ts
Convenciones de Codigo
| Elemento | Convencion | Ejemplo |
|---|---|---|
| Componentes React | PascalCase.tsx | MeterPage.tsx |
| Hooks | camelCase con prefijo use |
useMeters.ts |
| Servicios backend | camelCase.service.ts | meter.service.ts |
| Rutas backend | camelCase.routes.ts | meter.routes.ts |
| Constantes | UPPER_SNAKE_CASE | API_BASE_URL |
| DB columnas | snake_case | serial_number |
| API response → Frontend | snake_case → camelCase | serial_number → serialNumber |
| CSS | Tailwind utility classes | bg-zinc-800 dark:text-white |
Seguridad
- Helmet.js para headers HTTP seguros
- CORS configurado para origenes especificos
- Bcrypt (12 rounds) para hash de contrasenas
- JWT con access + refresh tokens
- Queries parametrizadas para prevenir SQL injection
- Zod para validacion de inputs
- Audit logging automatico de acciones
Testing
El proyecto actualmente no tiene suite de tests. Para agregar:
# Frontend
npm install -D vitest @testing-library/react @testing-library/jest-dom
# Backend
cd water-api
npm install -D vitest supertest @types/supertest