From 61dafa83acb3257b2efe4ae90251fa5f41512c91 Mon Sep 17 00:00:00 2001 From: Exteban08 Date: Mon, 9 Feb 2026 07:48:54 +0000 Subject: [PATCH] Update all project documentation to reflect current state 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 --- CAMBIOS_SESION.md | 258 ++++++------ DOCUMENTATION.md | 969 +++++++++++++++++++++++----------------------- ESTADO_ACTUAL.md | 327 +++++++++------- README.md | 598 +++++++++++++++------------- 4 files changed, 1127 insertions(+), 1025 deletions(-) diff --git a/CAMBIOS_SESION.md b/CAMBIOS_SESION.md index d7c0b47..2efbf19 100644 --- a/CAMBIOS_SESION.md +++ b/CAMBIOS_SESION.md @@ -1,171 +1,143 @@ -# Cambios Realizados - Sesión 2026-01-23 +# Historial de Cambios - Proyecto GRH -## Resumen -Corrección de errores críticos que causaban pantalla blanca y mejoras en el sistema de carga masiva. +Registro cronologico de cambios significativos realizados al proyecto. --- -## Problema 1: Pantalla Blanca en Water Meters y Consumo +## 2026-02-09: Actualizacion de documentacion -### Síntoma -Al navegar a "Water Meters" o "Consumo", la página se quedaba en blanco. - -### Causa -PostgreSQL devuelve valores DECIMAL como strings (ej: `"300.0000"`). El código llamaba `.toFixed()` directamente sobre estos strings, pero `.toFixed()` es un método de números, no de strings. - -### Solución -Convertir los valores a número con `Number()` antes de llamar `.toFixed()`. +### Resumen +Actualizacion completa de los 4 archivos de documentacion para reflejar el estado real del proyecto. ### Archivos Modificados +| Archivo | Cambio | +|---------|--------| +| `README.md` | Reescrito completamente: arquitectura full-stack, backend Express, PostgreSQL, todos los modulos, endpoints API, variables de entorno, estructura de directorios actualizada | +| `DOCUMENTATION.md` | Reescrito completamente: documentacion tecnica con JWT real, todos los endpoints del backend, esquema relacional, hooks, sistema de temas, conectores, guia de desarrollo actualizada | +| `ESTADO_ACTUAL.md` | Actualizado con todas las funcionalidades implementadas en febrero 2026: Analytics, Conectores, Dark mode, Notificaciones, Auditoria, Upload Panel, historial de correcciones | +| `CAMBIOS_SESION.md` | Convertido a historial cronologico completo de cambios | -**`src/pages/meters/MetersTable.tsx` (línea 75)** -```typescript -// ANTES: -r.lastReadingValue?.toFixed(2) - -// DESPUÉS: -r.lastReadingValue != null ? Number(r.lastReadingValue).toFixed(2) : "-" -``` - -**`src/pages/consumption/ConsumptionPage.tsx` (líneas 133, 213, 432)** -```typescript -// ANTES: -r.readingValue.toFixed(2) -summary?.avgReading.toFixed(1) -reading.readingValue.toFixed(2) - -// DESPUÉS: -Number(r.readingValue).toFixed(2) -summary?.avgReading != null ? Number(summary.avgReading).toFixed(1) : "0" -Number(reading.readingValue).toFixed(2) -``` +### Motivo +La documentacion previa describia una version temprana del proyecto (solo frontend, API externa NocoDB, auth con token simple) y no reflejaba el backend Express propio, JWT con refresh tokens, ni los modulos agregados en febrero 2026. --- -## Problema 2: Modal de Carga Masiva se Cerraba sin Mostrar Resultados +## 2026-02-05: Sincronizacion de conectores -### Síntoma -Al subir un archivo Excel para carga masiva, el modal se cerraba inmediatamente sin mostrar cuántos registros se insertaron o qué errores hubo. +### Cambio +Cambio de hora de sincronizacion de conectores de 2:00 AM a 9:00 AM. -### Causa -El callback `onSuccess` cerraba el modal automáticamente: -```typescript -onSuccess={() => { - m.loadMeters(); - setShowBulkUpload(false); // ← Cerraba antes de ver resultados -}} -``` - -### Solución -Separar la recarga de datos del cierre del modal. Ahora el modal solo se cierra cuando el usuario hace clic en "Cerrar". - -### Archivo Modificado - -**`src/pages/meters/MeterPage.tsx` (líneas 332-340)** -```typescript -// ANTES: - setShowBulkUpload(false)} - onSuccess={() => { - m.loadMeters(); - setShowBulkUpload(false); - }} -/> - -// DESPUÉS: - { - m.loadMeters(); - setShowBulkUpload(false); - }} - onSuccess={() => { - m.loadMeters(); - }} -/> -``` +### Archivos Modificados (2) +- `src/pages/conectores/SHMetersPage.tsx` +- `src/pages/conectores/XMetersPage.tsx` --- -## Problema 3: Error de Fecha Inválida en Carga Masiva +## 2026-02-04: Favicon y conectores -### Síntoma -Al subir medidores, aparecía el error: -``` -Fila X: invalid input syntax for type date: "Installed" -``` +### Cambios +- Actualizacion de favicon del sistema +- Mejoras en la visualizacion de tiempo de ultima conexion en paginas de conectores +- Agregado plan de implementacion para rol ORGANISMOS_OPERADORES -### Causa -El archivo Excel tenía columnas con valores como "Installed" o "New_LoRa" que el sistema interpretaba como fechas porque no estaban mapeadas correctamente. - -### Solución -1. **Validar fechas**: Verificar que `installation_date` sea realmente una fecha válida antes de usarla. -2. **Más mapeos de columnas**: Agregar mapeos para columnas comunes como `device_status`, `device_name`, etc. -3. **Normalizar status**: Convertir valores como "Installed", "New_LoRa" a "ACTIVE". - -### Archivo Modificado - -**`water-api/src/services/bulk-upload.service.ts`** - -Validación de fechas (líneas 183-195): -```typescript -let installationDate: string | undefined = undefined; -if (row.installation_date) { - const dateStr = String(row.installation_date).trim(); - if (/^\d{4}[-/]\d{1,2}[-/]\d{1,2}/.test(dateStr) || /^\d{1,2}[-/]\d{1,2}[-/]\d{2,4}/.test(dateStr)) { - const parsed = new Date(dateStr); - if (!isNaN(parsed.getTime())) { - installationDate = parsed.toISOString().split('T')[0]; - } - } -} -``` - -Mapeos de columnas adicionales (líneas 65-90): -```typescript -const mappings: Record = { - // Serial number - 'device_s/n': 'serial_number', - 'device_sn': 'serial_number', - // Name - 'device_name': 'name', - 'meter_name': 'name', - // Status - 'device_status': 'status', - // ... más mapeos -}; -``` - -Normalización de status (líneas 210-225): -```typescript -const statusMappings: Record = { - 'INSTALLED': 'ACTIVE', - 'NEW_LORA': 'ACTIVE', - 'NEW': 'ACTIVE', - 'ENABLED': 'ACTIVE', - 'DISABLED': 'INACTIVE', - // ... -}; -``` +### Archivos Modificados (4+1) +- Favicon actualizado +- Paginas de conectores actualizadas +- `PLAN_ORGANISMOS_OPERADORES.md` (plan de implementacion) --- -## Archivos Modificados en Esta Sesión +## 2026-02-03: Dark mode, Analytics, Conectores y CSV Upload +### Resumen +Sesion mayor con multiples funcionalidades nuevas implementadas en una serie de 12 commits. + +### Nuevas Funcionalidades + +**Dark Mode Completo** +- Toggle dark/light/system en configuracion +- Paleta Zinc de Tailwind aplicada a todas las paginas +- Soporte en tablas, modales, formularios, sidebars +- Cards de ConsumptionPage y tabla de AuditoriaPage + +**Seccion Analytics (3 paginas)** +- `AnalyticsMapPage.tsx` - Mapa Leaflet con ubicaciones de medidores +- `AnalyticsReportsPage.tsx` - Dashboard de reportes y estadisticas +- `AnalyticsServerPage.tsx` - Metricas del servidor (CPU, memoria, requests) +- `MapComponents.tsx` - Componentes auxiliares del mapa + +**Seccion Conectores (3 paginas)** +- `SHMetersPage.tsx` - Conector para sistema SH-Meters +- `XMetersPage.tsx` - Conector para sistema XMeters +- `TTSPage.tsx` - Conector para The Things Stack (LoRaWAN) + +**Upload Panel (app separada)** +- Nueva aplicacion en `upload-panel/` con React + Vite + Tailwind +- `MetersUpload.tsx` - Carga de medidores via CSV (upsert) +- `ReadingsUpload.tsx` - Carga de lecturas via CSV +- `FileDropzone.tsx` - Componente de dropzone para archivos +- `ResultsDisplay.tsx` - Visualizacion de resultados + +**Otros** +- Nuevos tipos de medidor: LORA, LORAWAN, GRANDES CONSUMIDORES +- Documentacion completa del proyecto (6 archivos) + +### Archivos Modificados +Aproximadamente 50+ archivos en 12 commits. + +--- + +## 2026-01-23: Fix pantalla blanca y carga masiva + +### Resumen +Correccion de errores criticos que causaban pantalla blanca y mejoras en el sistema de carga masiva. + +### Problema 1: Pantalla Blanca en Water Meters y Consumo + +**Sintoma:** Al navegar a "Water Meters" o "Consumo", la pagina se quedaba en blanco. + +**Causa:** PostgreSQL devuelve valores DECIMAL como strings (ej: `"300.0000"`). El codigo llamaba `.toFixed()` directamente sobre estos strings. + +**Solucion:** Convertir a numero con `Number()` antes de `.toFixed()`. + +**Archivos:** +- `src/pages/meters/MetersTable.tsx:75` +- `src/pages/consumption/ConsumptionPage.tsx:133, 213, 432` + +### Problema 2: Modal de Carga Masiva se Cerraba sin Resultados + +**Sintoma:** El modal se cerraba automaticamente despues de la carga sin mostrar resultados. + +**Causa:** El callback `onSuccess` cerraba el modal automaticamente. + +**Solucion:** Separar recarga de datos (`onSuccess`) del cierre del modal (`onClose`). + +**Archivo:** `src/pages/meters/MeterPage.tsx:332-340` + +### Problema 3: Error de Fecha Invalida en Carga Masiva + +**Sintoma:** Error `invalid input syntax for type date: "Installed"` al subir medidores. + +**Causa:** Columnas con valores como "Installed" o "New_LoRa" se interpretaban como fechas. + +**Solucion:** +1. Validar formato de fecha con regex antes de usarla +2. Agregar mapeos de columnas comunes (`device_s/n` → `serial_number`, etc.) +3. Normalizar status ("Installed" → ACTIVE, "New_LoRa" → ACTIVE, etc.) + +**Archivo:** `water-api/src/services/bulk-upload.service.ts` + +### Archivos Modificados | Archivo | Cambio | |---------|--------| | `src/pages/meters/MetersTable.tsx` | Fix `.toFixed()` en lastReadingValue | | `src/pages/consumption/ConsumptionPage.tsx` | Fix `.toFixed()` en readingValue y avgReading | | `src/pages/meters/MeterPage.tsx` | Fix modal de carga masiva | -| `water-api/src/services/bulk-upload.service.ts` | Validación de fechas, mapeos de columnas, normalización de status | -| `ESTADO_ACTUAL.md` | Documentación actualizada | -| `CAMBIOS_SESION.md` | Este archivo | +| `water-api/src/services/bulk-upload.service.ts` | Validacion de fechas, mapeos, normalizacion | ---- - -## Verificación - -1. ✅ La página de Water Meters carga correctamente -2. ✅ La página de Consumo carga correctamente -3. ✅ El modal de carga masiva muestra resultados -4. ✅ Errores de carga masiva se muestran claramente -5. ✅ Valores como "Installed" no causan error de fecha +### Verificacion +- La pagina de Water Meters carga correctamente +- La pagina de Consumo carga correctamente +- El modal de carga masiva muestra resultados +- Errores de carga masiva se muestran claramente +- Valores como "Installed" no causan error de fecha diff --git a/DOCUMENTATION.md b/DOCUMENTATION.md index 1057eea..b9be16e 100644 --- a/DOCUMENTATION.md +++ b/DOCUMENTATION.md @@ -1,19 +1,22 @@ -# Documentacion Tecnica - Water Project GRH +# Documentacion Tecnica - GRH (Gestion de Recursos Hidricos) -Documentacion tecnica detallada del Sistema de Gestion de Recursos Hidricos. +Documentacion tecnica detallada de la arquitectura, componentes, API y patrones del sistema. --- ## Tabla de Contenidos 1. [Arquitectura del Sistema](#arquitectura-del-sistema) -2. [Componentes Principales](#componentes-principales) -3. [Capa de API](#capa-de-api) -4. [Hooks Personalizados](#hooks-personalizados) -5. [Sistema de Autenticacion](#sistema-de-autenticacion) -6. [Gestion de Estado](#gestion-de-estado) -7. [Sistema de Temas](#sistema-de-temas) -8. [Guia de Desarrollo](#guia-de-desarrollo) +2. [Frontend - Componentes y Paginas](#frontend---componentes-y-paginas) +3. [Backend - API REST](#backend---api-rest) +4. [Base de Datos](#base-de-datos) +5. [Autenticacion y Autorizacion](#autenticacion-y-autorizacion) +6. [Capa de API del Frontend](#capa-de-api-del-frontend) +7. [Hooks Personalizados](#hooks-personalizados) +8. [Sistema de Temas](#sistema-de-temas) +9. [Conectores Externos](#conectores-externos) +10. [Tareas Programadas](#tareas-programadas) +11. [Guia de Desarrollo](#guia-de-desarrollo) --- @@ -21,591 +24,605 @@ Documentacion tecnica detallada del Sistema de Gestion de Recursos Hidricos. ### Vision General -El proyecto sigue una arquitectura **frontend SPA (Single Page Application)** con las siguientes capas: +El proyecto es una aplicacion **full-stack** con tres componentes principales: ``` -┌─────────────────────────────────────────────────────────┐ -│ Capa de Presentacion │ -│ (React Components, Pages, Layout) │ -├─────────────────────────────────────────────────────────┤ -│ Capa de Logica │ -│ (Custom Hooks, State Management) │ -├─────────────────────────────────────────────────────────┤ -│ Capa de Datos │ -│ (API Services, localStorage) │ -├─────────────────────────────────────────────────────────┤ -│ API Externa │ -│ (REST API Backend) │ -└─────────────────────────────────────────────────────────┘ +┌─────────────────────────────────────────────────────────────┐ +│ 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 │ +└─────────────────────────────────────────────────────────────┘ ``` -### Patron de Diseno +### Patrones de Diseno -El proyecto utiliza varios patrones de diseno: - -1. **Container/Presentational Pattern**: Separacion entre componentes con logica (pages) y componentes de UI puros (components) -2. **Custom Hooks Pattern**: Encapsulacion de logica reutilizable en hooks (`useMeters`, `useConcentrators`) -3. **Module Pattern**: Organizacion de codigo relacionado en modulos (meters/, concentrators/) +1. **Container/Presentational** - Paginas manejan logica, componentes renderizan UI +2. **Custom Hooks** - Logica reutilizable en hooks (`useMeters`, `useConcentrators`, `useNotifications`) +3. **Module Pattern** - Codigo organizado por dominio (`meters/`, `concentrators/`, `analytics/`) +4. **Service Layer (Backend)** - Routes → Controllers → Services → Database +5. **Repository Pattern** - Cada servicio encapsula las queries SQL de su dominio +6. **Middleware Pipeline** - Auth, audit logging, webhook verification --- -## Componentes Principales +## Frontend - Componentes y Paginas ### App.tsx - Componente Raiz -El componente raiz maneja: -- Autenticacion global -- Routing interno (sin react-router) -- Estado de pagina actual -- Modales globales (perfil, configuracion, logout) +Maneja autenticacion global, routing por estado interno y modales globales. ```typescript -// Estados principales -const [isAuth, setIsAuth] = useState(() => { - return Boolean(localStorage.getItem(AUTH_KEY)); -}); -const [currentPage, setCurrentPage] = useState("home"); -const [currentSubpage, setCurrentSubpage] = useState(null); +export type Page = + | "home" | "projects" | "meters" | "concentrators" + | "consumption" | "auditoria" | "users" | "roles" + | "sh-meters" | "xmeters" | "tts" + | "analytics-map" | "analytics-reports" | "analytics-server"; ``` -### Sidebar.tsx - Menu Lateral +La navegacion es **state-based** (sin React Router). El estado `currentPage` determina que pagina se renderiza. -Caracteristicas: -- Estados: colapsado/expandido -- Hover expansion con delay -- Pin/unpin para mantener expandido -- Menu jerarquico con submenus +### Paginas Principales -```typescript -interface SidebarProps { - currentPage: string; - setCurrentPage: (page: string) => void; - currentSubpage: string | null; - setCurrentSubpage: (subpage: string | null) => void; -} -``` +| 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 | -### TopMenu.tsx - Barra Superior +### Componentes de Layout -Funcionalidades: +**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 -- Notificaciones (placeholder) -- Menu de usuario con dropdown -- Acciones: perfil, configuracion, logout +- Dropdown de notificaciones con conteo de no leidas +- Menu de usuario: perfil, configuracion, logout + +**Componentes Comunes** +- `ProfileModal.tsx` - Edicion de perfil con avatar local +- `ConfirmModal.tsx` - Confirmacion de acciones destructivas +- `Watermark.tsx` - Marca de agua GRH +- `ProjectBadge.tsx` - Badge visual de proyecto +- `SettingsModals.tsx` - Configuracion de tema y modo compacto +- `NotificationDropdown.tsx` - Panel de notificaciones --- -## Capa de API +## Backend - API REST ### Estructura de Archivos ``` -src/api/ -├── me.ts # Perfil de usuario -├── meters.ts # Operaciones CRUD de medidores -├── concentrators.ts # Operaciones CRUD de concentradores -└── projects.ts # Operaciones CRUD de proyectos +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 ``` -### Configuracion +### 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, VIEWER +- `project_status`: ACTIVE, INACTIVE, COMPLETED +- `device_status`: ACTIVE, INACTIVE, OFFLINE, MAINTENANCE, ERROR +- `meter_type`: WATER, GAS, ELECTRIC +- `reading_type`: AUTOMATIC, MANUAL, SCHEDULED + +### Migraciones SQL + +Ejecutar en orden despues del schema principal: + +1. `schema.sql` - Schema principal con 10 tablas, 2 vistas, seed de roles y admin +2. `add_audit_logs.sql` - Tabla de logs de auditoria +3. `add_notifications.sql` - Tabla de notificaciones +4. `add_meter_extended_fields.sql` - Campos extendidos para medidores +5. `create_meter_types.sql` - Tabla de tipos de medidor +6. `add_meter_project_relation.sql` - Relacion meter-proyecto +7. `add_user_project_relation.sql` - Relacion user-proyecto + +--- + +## Autenticacion y Autorizacion + +### Flujo JWT + +``` +┌──────────┐ POST /auth/login ┌──────────┐ +│ Cliente │ ───────────────────→ │ Backend │ +│ │ ←─────────────────── │ │ +└──────────┘ {accessToken, └──────────┘ + refreshToken} │ + │ │ bcrypt.compare() + │ Authorization: Bearer │ 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: +1. Pone en cola las peticiones pendientes +2. Llama a `/auth/refresh` con el refresh token +3. 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 ```typescript -const API_BASE_URL = import.meta.env.VITE_API_BASE_URL; -const API_TOKEN = import.meta.env.VITE_API_TOKEN; +getCurrentUserRole() // → "ADMIN" | "OPERATOR" | "VIEWER" +getCurrentUserId() // → UUID string +getCurrentUserProjectId() // → UUID string | undefined +isCurrentUserAdmin() // → boolean ``` -### Funciones de API - Medidores +--- -```typescript -// meters.ts +## Capa de API del Frontend -// Obtener todos los medidores -export async function fetchMeters(): Promise +### Cliente HTTP (`src/api/client.ts`) -// Crear medidor -export async function createMeter(meterData: Partial): Promise +Wrapper de `fetch` con: +- Inyeccion automatica de `Authorization: Bearer ` +- 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) -// Actualizar medidor -export async function updateMeter( - id: string, - meterData: Partial -): Promise +### Modulos de API -// Eliminar medidor -export async function deleteMeter(id: string): Promise -``` - -### Funciones de API - Concentradores - -```typescript -// concentrators.ts - -export async function fetchConcentrators(): Promise -export async function createConcentrator(data: Partial): Promise -export async function updateConcentrator(id: string, data: Partial): Promise -export async function deleteConcentrator(id: string): Promise -``` - -### Funciones de API - Proyectos - -```typescript -// projects.ts - -export async function fetchProjects(): Promise -export async function fetchProjectNames(): Promise -export async function createProject(data: Partial): Promise -export async function updateProject(id: string, data: Partial): Promise -export async function deleteProject(id: string): Promise -``` - -### Manejo de Errores - -Todas las funciones de API siguen el patron: - -```typescript -try { - const response = await fetch(url, options); - if (!response.ok) { - throw new Error(`Error: ${response.status}`); - } - return await response.json(); -} catch (error) { - console.error("API Error:", error); - throw error; -} -``` +| 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.ts +### useMeters -Hook para gestion completa del modulo de medidores. +Gestiona el estado completo del modulo de medidores. ```typescript interface UseMetersReturn { - // Data + // Datos meters: Meter[]; filteredMeters: Meter[]; projectNames: string[]; - // State + // Estado loading: boolean; selectedMeter: Meter | null; selectedProject: string | null; searchTerm: string; - // Actions + // Acciones setSelectedMeter: (meter: Meter | null) => void; setSelectedProject: (project: string | null) => void; setSearchTerm: (term: string) => void; refreshData: () => Promise; + loadMeters: () => Promise; // CRUD handleCreate: (data: Partial) => Promise; handleUpdate: (id: string, data: Partial) => Promise; handleDelete: (id: string) => Promise; } - -export function useMeters(): UseMetersReturn ``` -### useConcentrators.ts +### useConcentrators -Hook similar para concentradores con estructura equivalente. +Estructura equivalente a `useMeters` para el modulo de concentradores. + +### useNotifications + +Gestiona notificaciones del usuario con polling periodico. ```typescript -interface UseConcentratorsReturn { - concentrators: Concentrator[]; - filteredConcentrators: Concentrator[]; - projectNames: string[]; +interface UseNotificationsReturn { + notifications: Notification[]; + unreadCount: number; loading: boolean; - selectedConcentrator: Concentrator | null; - // ... similar a useMeters + markAsRead: (id: string) => Promise; + markAllAsRead: () => Promise; + deleteNotification: (id: string) => Promise; + refresh: () => Promise; } - -export function useConcentrators(): UseConcentratorsReturn ``` ---- - -## Sistema de Autenticacion - -### Flujo de Autenticacion +### Flujo de Datos ``` -┌──────────────┐ ┌─────────────┐ ┌──────────────┐ -│ LoginPage │────>│ Validacion │────>│ localStorage│ -└──────────────┘ └─────────────┘ └──────────────┘ - │ - ▼ - ┌─────────────┐ - │ App.tsx │ - │ (isAuth) │ - └─────────────┘ -``` - -### Almacenamiento de Token - -```typescript -const AUTH_KEY = "grh_auth"; - -interface AuthData { - token: string; - ts: number; // timestamp de login -} - -// Guardar -localStorage.setItem(AUTH_KEY, JSON.stringify({ token: "demo", ts: Date.now() })); - -// Verificar -const isAuth = Boolean(localStorage.getItem(AUTH_KEY)); - -// Eliminar (logout) -localStorage.removeItem(AUTH_KEY); -``` - -### Proteccion de Rutas - -```typescript -// App.tsx -if (!isAuth) { - return ; -} - -// Si esta autenticado, renderiza la aplicacion -return ( -
- -
{renderPage()}
-
-); -``` - ---- - -## Gestion de Estado - -### Estado Local (useState) - -La aplicacion utiliza principalmente `useState` de React para gestion de estado local: - -```typescript -// Ejemplo en MeterPage.tsx -const [meters, setMeters] = useState([]); -const [selectedMeter, setSelectedMeter] = useState(null); -const [isModalOpen, setIsModalOpen] = useState(false); -const [modalMode, setModalMode] = useState<"add" | "edit">("add"); -``` - -### Estado Persistente (localStorage) - -Para datos que deben persistir entre sesiones: - -```typescript -// Configuraciones de usuario -const SETTINGS_KEY = "water_project_settings_v1"; - -interface Settings { - theme: "system" | "light" | "dark"; - compactMode: boolean; -} - -// Guardar -localStorage.setItem(SETTINGS_KEY, JSON.stringify(settings)); - -// Cargar -const settings = JSON.parse(localStorage.getItem(SETTINGS_KEY) || "{}"); -``` - -### Flujo de Datos en Modulos - -``` -┌─────────────┐ -│ API Layer │ -└──────┬──────┘ +API Layer (fetch + JWT) │ ▼ -┌─────────────┐ -│ Custom Hook │ (useMeters, useConcentrators) -└──────┬──────┘ +Custom Hook (useMeters, etc.) │ ▼ -┌─────────────┐ -│ Page │ (MeterPage, ConcentratorsPage) -└──────┬──────┘ +Page Component (MeterPage, etc.) │ - ├────────────────┬────────────────┐ - ▼ ▼ ▼ -┌───────────┐ ┌───────────┐ ┌───────────┐ -│ Sidebar │ │ Table │ │ Modal │ -└───────────┘ └───────────┘ └───────────┘ + ├──────────────┬──────────────┐ + ▼ ▼ ▼ + Sidebar Table Modal ``` --- ## Sistema de Temas -### Configuracion de Tema +### Configuracion + +Tres modos disponibles: `system`, `light`, `dark`. ```typescript type Theme = "system" | "light" | "dark"; -const applyTheme = (theme: Theme) => { - if (theme === "system") { - const prefersDark = window.matchMedia("(prefers-color-scheme: dark)").matches; - document.documentElement.classList.toggle("dark", prefersDark); - } else { - document.documentElement.classList.toggle("dark", theme === "dark"); - } -}; +// Aplicacion del tema +document.documentElement.classList.toggle("dark", isDark); ``` -### Clases CSS con Tailwind +### Paleta de Colores (Dark Mode) -```css -/* Ejemplo de clases con soporte dark mode */ -.card { - @apply bg-white dark:bg-gray-800; - @apply text-gray-900 dark:text-white; - @apply border-gray-200 dark:border-gray-700; -} -``` +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` -### Modal de Configuracion +### Persistencia ```typescript -// SettingsModals.tsx -interface SettingsModalsProps { - open: boolean; - onClose: () => void; -} +const SETTINGS_KEY = "water_project_settings_v1"; -// Opciones de tema -const themeOptions = [ - { value: "system", label: "Sistema" }, - { value: "light", label: "Claro" }, - { value: "dark", label: "Oscuro" }, -]; +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: +1. Revisa lecturas recientes de medidores +2. Detecta valores negativos o anomalias +3. Genera notificaciones automaticas para los usuarios + +--- + ## Guia de Desarrollo ### Agregar una Nueva Pagina -1. **Crear el archivo de pagina** +1. **Crear el componente** en `src/pages/nueva/NuevaPage.tsx` +2. **Agregar al tipo Page** en `App.tsx` +3. **Agregar al Sidebar** en `Sidebar.tsx` (menuItems) +4. **Agregar al renderizado** en `App.tsx` (switch en `renderPage()`) -```typescript -// src/pages/nueva/NuevaPage.tsx -export default function NuevaPage() { - return ( -
-

Nueva Pagina

-
- ); -} -``` +### Agregar un Nuevo Endpoint en el Backend -2. **Agregar al Sidebar** +1. **Crear servicio** en `water-api/src/services/nuevo.service.ts` +2. **Crear controlador** en `water-api/src/controllers/nuevo.controller.ts` +3. **Crear validador** (opcional) en `water-api/src/validators/nuevo.validator.ts` +4. **Crear rutas** en `water-api/src/routes/nuevo.routes.ts` +5. **Registrar rutas** en `water-api/src/routes/index.ts` -```typescript -// Sidebar.tsx - agregar al menuItems -{ - label: "Nueva Pagina", - page: "nueva", - icon: , -} -``` +### Agregar un Modulo de API en el Frontend -3. **Agregar al renderizado en App.tsx** +1. **Crear archivo** en `src/api/nuevo.ts` +2. **Usar el cliente HTTP** importando de `./client.ts` +3. **Crear hook** (opcional) en `src/pages/nueva/useNuevo.ts` -```typescript -// App.tsx - agregar case en renderPage() -case "nueva": - return ; -``` +### Convenciones de Codigo -### Agregar un Nuevo Endpoint de API +| 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` | -1. **Crear archivo de API** +### Seguridad -```typescript -// src/api/nuevo.ts -const API_BASE_URL = import.meta.env.VITE_API_BASE_URL; -const API_TOKEN = import.meta.env.VITE_API_TOKEN; +- **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 -export interface NuevoItem { - id: string; - // ... campos -} +### Testing -export async function fetchNuevos(): Promise { - const response = await fetch(`${API_BASE_URL}/endpoint`, { - headers: { - Authorization: `Bearer ${API_TOKEN}`, - "Content-Type": "application/json", - }, - }); - - if (!response.ok) throw new Error("Error fetching data"); - - const data = await response.json(); - return data.records.map((r: any) => ({ id: r.id, ...r.fields })); -} -``` - -2. **Crear hook personalizado (opcional)** - -```typescript -// src/pages/nuevo/useNuevo.ts -export function useNuevo() { - const [items, setItems] = useState([]); - const [loading, setLoading] = useState(true); - - useEffect(() => { - fetchNuevos() - .then(setItems) - .finally(() => setLoading(false)); - }, []); - - return { items, loading }; -} -``` - -### Agregar un Nuevo Componente Reutilizable - -```typescript -// src/components/layout/common/NuevoComponente.tsx -interface NuevoComponenteProps { - title: string; - onAction: () => void; - children?: React.ReactNode; -} - -export default function NuevoComponente({ - title, - onAction, - children, -}: NuevoComponenteProps) { - return ( -
-

{title}

- {children} - -
- ); -} -``` - -### Convenios de Codigo - -1. **Nombres de archivos**: PascalCase para componentes, camelCase para utilidades -2. **Interfaces**: Prefijo descriptivo (ej: `MeterFormData`, `UserSettings`) -3. **Hooks**: Prefijo `use` (ej: `useMeters`, `useAuth`) -4. **Constantes**: UPPER_SNAKE_CASE (ej: `API_BASE_URL`) -5. **CSS**: Utilizar Tailwind CSS, evitar CSS custom - -### Testing (Pendiente de Implementacion) - -El proyecto actualmente no tiene tests configurados. Para agregar: +El proyecto actualmente no tiene suite de tests. Para agregar: ```bash +# Frontend npm install -D vitest @testing-library/react @testing-library/jest-dom + +# Backend +cd water-api +npm install -D vitest supertest @types/supertest ``` - -```typescript -// vitest.config.ts -import { defineConfig } from "vitest/config"; - -export default defineConfig({ - test: { - environment: "jsdom", - globals: true, - }, -}); -``` - ---- - -## Variables de Entorno - -| Variable | Descripcion | Requerida | -|----------|-------------|-----------| -| `VITE_API_BASE_URL` | URL base de la API | Si | -| `VITE_API_TOKEN` | Token de autenticacion API | Si | - -### Ejemplo .env - -```env -VITE_API_BASE_URL=https://api.example.com -VITE_API_TOKEN=your-api-token-here -``` - ---- - -## Dependencias Principales - -| Paquete | Version | Uso | -|---------|---------|-----| -| react | 18.2.0 | Framework UI | -| react-dom | 18.2.0 | Renderizado DOM | -| typescript | 5.2.2 | Type safety | -| vite | 5.2.0 | Build tool | -| tailwindcss | 4.1.18 | Estilos | -| @mui/material | 7.3.6 | Componentes UI | -| @material-table/core | 6.5.2 | Tablas avanzadas | -| recharts | 3.6.0 | Graficas | -| lucide-react | 0.559.0 | Iconos | - ---- - -## Comandos Utiles - -```bash -# Desarrollo -npm run dev - -# Build produccion -npm run build - -# Preview del build -npm run preview - -# Linting -npm run lint - -# Type check -npx tsc --noEmit -``` - ---- - -## Troubleshooting - -### Error: CORS al conectar con API - -Verificar que el backend tenga configurados los headers CORS correctos o usar un proxy en desarrollo. - -### Error: Module not found - -```bash -rm -rf node_modules -npm install -``` - -### Error: TypeScript type errors - -```bash -npx tsc --noEmit -``` - -Revisar los errores y corregir los tipos. - -### La aplicacion no carga - -1. Verificar que las variables de entorno estan configuradas -2. Verificar la consola del navegador por errores -3. Verificar que la API esta accesible diff --git a/ESTADO_ACTUAL.md b/ESTADO_ACTUAL.md index 66a28d9..9ae0de5 100644 --- a/ESTADO_ACTUAL.md +++ b/ESTADO_ACTUAL.md @@ -1,55 +1,72 @@ -# Estado Actual del Proyecto Water Project GRH +# Estado Actual del Proyecto GRH -**Fecha:** 2026-01-23 -**Última actualización:** Corrección de errores y mejoras en carga masiva +**Fecha:** 2026-02-09 +**Ultima actualizacion:** Documentacion actualizada para reflejar el estado completo del proyecto --- ## Resumen del Proyecto -Sistema de gestión de medidores de agua con: -- **Frontend:** React + TypeScript + Vite (puerto 5173) +Sistema full-stack de gestion de medidores de agua con: +- **Frontend:** React 18 + TypeScript + Vite (puerto 5173) - **Backend:** Node.js + Express + TypeScript (puerto 3000) - **Base de datos:** PostgreSQL +- **Upload Panel:** App separada para carga CSV masiva -### Jerarquía de datos: +### Jerarquia de datos: ``` Projects → Concentrators → Meters → Readings + → Gateways → Devices ↗ ``` +### URLs de produccion: +- **Frontend:** https://sistema.gestionrecursoshidricos.com +- **Backend:** https://api.gestionrecursoshidricos.com + +### Repositorios: +- **Gitea:** https://git.consultoria-as.com/consultoria-as/GRH +- **GitHub:** git@github.com:luanngel/water-project.git + --- ## Arquitectura del Sistema ``` ┌─────────────────────────────────────────────────────────────┐ -│ FRONTEND (React) │ -│ http://localhost:5173 │ +│ FRONTEND (React SPA) │ +│ http://localhost:5173 │ ├─────────────────────────────────────────────────────────────┤ -│ - React 18 + TypeScript + Vite │ -│ - Tailwind CSS + Material-UI │ -│ - Recharts para gráficos │ -│ - Cliente API con JWT automático │ -└─────────────────────────────────────────────────────────────┘ - │ - ▼ +│ React 18 + TypeScript + Vite │ +│ Tailwind CSS (paleta Zinc) + Material-UI 7 │ +│ Recharts (graficos) + Leaflet (mapas) │ +│ Cliente API con JWT + refresh automatico │ +│ Dark mode / Light mode / System │ +└──────────────────────────┬──────────────────────────────────┘ + │ REST API + JWT Bearer + ▼ ┌─────────────────────────────────────────────────────────────┐ -│ BACKEND (Node.js) │ -│ http://localhost:3000 │ +│ BACKEND (Express) │ +│ http://localhost:3000 │ ├─────────────────────────────────────────────────────────────┤ -│ - Express + TypeScript │ -│ - Autenticación JWT con refresh tokens │ -│ - CRUD completo para todas las entidades │ -│ - Carga masiva via Excel (xlsx) │ -└─────────────────────────────────────────────────────────────┘ - │ - ▼ +│ Express + TypeScript + Zod (validacion) │ +│ JWT access (15m) + refresh (7d) tokens │ +│ 17 archivos de rutas, 18 servicios │ +│ Helmet, CORS, Bcrypt, Winston logging │ +│ node-cron (deteccion flujo negativo) │ +│ Multer + XLSX (carga masiva) │ +│ Webhooks TTS (The Things Stack / LoRaWAN) │ +└──────────────────────────┬──────────────────────────────────┘ + │ + ▼ ┌─────────────────────────────────────────────────────────────┐ -│ BASE DE DATOS │ -│ PostgreSQL │ +│ PostgreSQL │ ├─────────────────────────────────────────────────────────────┤ -│ Tablas: users, roles, projects, concentrators, │ -│ meters, meter_readings, refresh_tokens │ +│ 10 tablas: roles, users, projects, concentrators, │ +│ gateways, devices, meters, meter_readings, │ +│ tts_uplink_logs, refresh_tokens │ +│ 2 vistas: meter_stats_by_project, device_status_summary │ +│ 7 archivos SQL (schema + 6 migraciones) │ +│ Triggers de updated_at, indices compuestos, JSONB │ └─────────────────────────────────────────────────────────────┘ ``` @@ -57,58 +74,128 @@ Projects → Concentrators → Meters → Readings ## Funcionalidades Implementadas -### 1. Autenticación -- Login con JWT + refresh tokens -- Manejo automático de renovación de tokens -- Roles: ADMIN, USER +### 1. Autenticacion y Autorizacion +- Login con JWT: access token (15 min) + refresh token (7 dias) +- Refresh automatico de tokens en el cliente (cola de peticiones) +- 3 roles con permisos JSONB: ADMIN, OPERATOR, VIEWER +- Relacion usuario-proyecto para acceso por scope +- Hash de contrasenas con bcrypt (12 rounds) +- Proteccion de rutas por rol en backend y frontend -### 2. Gestión de Proyectos +### 2. Dashboard (Home) +- KPIs: Total medidores, medidores activos, consumo promedio, alertas +- Grafico de barras: Medidores por proyecto (Recharts) +- Selector de organismos operadores (CESPT Tijuana, Tecate, Mexicali) +- Historial reciente de actividades +- Panel de ultimas alertas +- Soporte por rol (ADMIN, OPERATOR, VIEWER) + +### 3. Gestion de Proyectos - CRUD completo -- Estados: ACTIVE/INACTIVE +- Estados: ACTIVE, INACTIVE, COMPLETED +- Estadisticas por proyecto (medidores, lecturas, areas) -### 3. Gestión de Concentradores +### 4. Gestion de Concentradores - CRUD completo - Vinculados a proyectos -- Tipos: Gateway LoRa/LoRaWAN +- Estado: ACTIVE, INACTIVE, OFFLINE, MAINTENANCE, ERROR +- IP, firmware, ultima comunicacion -### 4. Gestión de Medidores -- CRUD completo -- Tipos: LORA, LORAWAN, GRANDES -- Estados: ACTIVE, INACTIVE, MAINTENANCE, FAULTY, REPLACED -- **Carga masiva via Excel** -- Última lectura visible en tabla +### 5. Gestion de Medidores +- CRUD completo con tabla, sidebar de detalle y modal de edicion +- Tipos de medidor: WATER, GAS, ELECTRIC +- Protocolos: GENERAL, LORA, LORAWAN +- Estados: ACTIVE, INACTIVE, OFFLINE, MAINTENANCE, ERROR +- Carga masiva via Excel y CSV +- Busqueda, filtros por proyecto/tipo/estado +- Ultima lectura visible en tabla +- Campos extendidos: protocolo, MAC, gateway, voltaje, senal, flujo, coordenadas +- Tipos adicionales: LORA, LORAWAN, GRANDES CONSUMIDORES -### 5. Gestión de Lecturas (Consumo) -- CRUD completo +### 6. Consumo y Lecturas +- CRUD de lecturas - Tipos: AUTOMATIC, MANUAL, SCHEDULED -- **Carga masiva via Excel** -- Filtros por proyecto, fecha -- Exportación a CSV -- Indicadores de batería y señal +- Carga masiva via Excel y CSV +- Filtros por proyecto, medidor, rango de fechas +- Resumen de consumo (total, promedio, min, max) +- Indicadores de bateria y senal +- Exportacion -### 6. Dashboard -- KPIs: Total lecturas, medidores activos, consumo promedio -- Gráficos por proyecto -- Últimas alertas +### 7. Analytics +- **Mapa:** Visualizacion de medidores con coordenadas en mapa Leaflet interactivo +- **Reportes:** Dashboard de estadisticas y reportes de consumo +- **Servidor:** Metricas del sistema (CPU, memoria, uptime, requests) + +### 8. Conectores Externos +- **SH-Meters:** Integracion con sistema de medidores SH +- **XMeters:** Integracion con sistema XMeters +- **The Things Stack (TTS):** Webhooks LoRaWAN para uplink, join y downlink/ack +- Sincronizacion programada a las 9:00 AM +- Seguimiento de ultima conexion y estado + +### 9. Gestion de Usuarios +- CRUD completo (solo ADMIN) +- Asignacion de roles +- Asignacion de proyecto +- Estados: activo/inactivo +- Cambio de contrasena + +### 10. Gestion de Roles +- 3 roles predefinidos: ADMIN, OPERATOR, VIEWER +- Permisos granulares JSONB por recurso +- CRUD de roles (solo ADMIN) +- Conteo de usuarios por rol + +### 11. Auditoria +- Registro automatico de todas las acciones via middleware +- Visor de logs con filtros (solo ADMIN) +- Actividad del usuario actual (todos los roles) +- Estadisticas de auditoria +- Busqueda por registro especifico + +### 12. Notificaciones +- Notificaciones in-app +- Conteo de no leidas en tiempo real +- Marcar como leida (individual y masiva) +- Generacion automatica por flujo negativo (cron job) +- Dropdown en TopMenu + +### 13. Dark Mode +- Soporte completo: Dark / Light / System +- Paleta Zinc de Tailwind +- Aplicado a todas las paginas, modales, tablas, formularios +- Persistencia en localStorage + +### 14. Upload Panel +- Aplicacion separada (`upload-panel/`) para carga CSV +- Dropzone para archivos +- Carga de medidores (upsert) +- Carga de lecturas +- Descarga de plantillas +- Visualizacion de resultados y errores --- ## Carga Masiva -### Medidores (Excel) +### Medidores (Excel / CSV) Columnas requeridas: -- `serial_number` - Número de serie del medidor (único) +- `serial_number` - Numero de serie del medidor (unico) - `name` - Nombre del medidor - `concentrator_serial` - Serial del concentrador existente Columnas opcionales: - `meter_id` - ID del medidor -- `location` - Ubicación +- `location` - Ubicacion - `type` - LORA, LORAWAN, GRANDES (default: LORA) - `status` - ACTIVE, INACTIVE, etc. (default: ACTIVE) -- `installation_date` - Fecha de instalación (YYYY-MM-DD) +- `installation_date` - Fecha de instalacion (YYYY-MM-DD) -### Lecturas (Excel) +Mapeos automaticos de columnas: `device_s/n` → `serial_number`, `device_name` → `name`, `device_status` → `status`, etc. + +Normalizacion de status: "Installed" → ACTIVE, "New_LoRa" → ACTIVE, "Enabled" → ACTIVE, "Disabled" → INACTIVE. + +### Lecturas (Excel / CSV) Columnas requeridas: - `meter_serial` - Serial del medidor existente - `reading_value` - Valor de la lectura @@ -116,21 +203,12 @@ Columnas requeridas: Columnas opcionales: - `reading_type` - AUTOMATIC, MANUAL, SCHEDULED (default: MANUAL) - `received_at` - Fecha/hora (default: ahora) -- `battery_level` - Nivel de batería (%) -- `signal_strength` - Intensidad de señal (dBm) +- `battery_level` - Nivel de bateria (%) +- `signal_strength` - Intensidad de senal (dBm) --- -## Credenciales - -### Usuario Admin -- **Nombre:** Ivan Alcaraz -- **Email:** ialcarazsalazar@consultoria-as.com -- **Password:** Aasi940812 - ---- - -## Datos Actuales en BD +## Datos en Base de Datos ### Proyectos - ADAMANT @@ -152,98 +230,65 @@ Columnas opcionales: --- -## Correcciones Recientes (2026-01-23) +## Historial de Correcciones -### 1. Error `.toFixed()` con valores string -**Problema:** PostgreSQL devuelve DECIMAL como string, causando error al llamar `.toFixed()`. -**Solución:** Convertir a número con `Number()` antes de llamar `.toFixed()`. -**Archivos:** -- `src/pages/meters/MetersTable.tsx:75` -- `src/pages/consumption/ConsumptionPage.tsx:133, 213, 432` +### 2026-01-23: Fix pantalla blanca y carga masiva +1. **Fix `.toFixed()` con strings** - PostgreSQL devuelve DECIMAL como string. Se envuelve con `Number()`. +2. **Fix modal de carga masiva** - Separar recarga de datos del cierre del modal. +3. **Fix fechas invalidas en carga masiva** - Validacion de formato con regex + mapeos de columnas + normalizacion de status. -### 2. Modal de carga masiva se cerraba sin mostrar resultados -**Problema:** El modal se cerraba automáticamente después de la carga. -**Solución:** El modal ahora permanece abierto para mostrar resultados y errores. -**Archivo:** `src/pages/meters/MeterPage.tsx:332-340` +### 2026-02-03: Dark mode, Analytics, Conectores, CSV Upload +- Implementacion completa de dark mode con paleta Zinc +- Seccion Analytics: mapa, reportes, servidor +- Seccion Conectores: SH-Meters, XMeters, TTS +- Toggle dark/light theme +- Panel CSV para carga masiva +- Nuevos tipos de medidor: LORA, LORAWAN, GRANDES CONSUMIDORES +- Documentacion completa del proyecto -### 3. Validación de fechas en carga masiva -**Problema:** Valores como "Installed" en columnas no mapeadas causaban error de fecha inválida. -**Solución:** Validar que `installation_date` sea realmente una fecha antes de insertarla. -**Archivo:** `water-api/src/services/bulk-upload.service.ts:183-195` +### 2026-02-04: Favicon y conectores +- Actualizacion de favicon +- Mejoras en tiempo de ultima conexion de conectores +- Plan de implementacion para rol ORGANISMOS_OPERADORES -### 4. Mapeo de columnas mejorado -**Mejora:** Agregados más mapeos de columnas comunes (device_status, device_name, etc.) -**Archivo:** `water-api/src/services/bulk-upload.service.ts:65-90` - -### 5. Normalización de status -**Mejora:** Valores como "Installed", "New_LoRa" se convierten automáticamente a "ACTIVE". -**Archivo:** `water-api/src/services/bulk-upload.service.ts:210-225` +### 2026-02-05: Sincronizacion de conectores +- Cambio de hora de sincronizacion de 2:00 AM a 9:00 AM --- -## Comandos Útiles +## Comandos Utiles ```bash -# Iniciar backend +# Iniciar backend (desarrollo) cd /home/GRH/water-project/water-api npm run dev -# Iniciar frontend +# Iniciar frontend (desarrollo) cd /home/GRH/water-project npm run dev -# Compilar backend +# Iniciar upload panel (desarrollo) +cd /home/GRH/water-project/upload-panel +npm run dev + +# Compilar backend para produccion cd /home/GRH/water-project/water-api +npm run build && npm run start + +# Compilar frontend para produccion +cd /home/GRH/water-project npm run build -# Ver logs del backend -tail -f /tmp/water-api.log +# Ejecutar schema de base de datos +psql -d water_project -f water-api/sql/schema.sql ``` --- -## Estructura de Archivos +## Proximos Pasos Sugeridos -``` -water-project/ -├── src/ # Frontend React -│ ├── api/ # Cliente API -│ │ ├── client.ts # Cliente HTTP con JWT -│ │ ├── meters.ts # API de medidores -│ │ ├── readings.ts # API de lecturas -│ │ ├── projects.ts # API de proyectos -│ │ └── concentrators.ts # API de concentradores -│ ├── pages/ # Páginas -│ │ ├── meters/ # Módulo de medidores -│ │ │ ├── MeterPage.tsx -│ │ │ ├── MetersTable.tsx -│ │ │ ├── MetersModal.tsx -│ │ │ ├── MetersSidebar.tsx -│ │ │ ├── MetersBulkUploadModal.tsx -│ │ │ └── useMeters.ts -│ │ ├── consumption/ # Módulo de consumo -│ │ │ ├── ConsumptionPage.tsx -│ │ │ └── ReadingsBulkUploadModal.tsx -│ │ └── ... -│ └── components/ # Componentes reutilizables -│ -└── water-api/ # Backend Node.js - ├── src/ - │ ├── controllers/ # Controladores REST - │ ├── services/ # Lógica de negocio - │ │ ├── bulk-upload.service.ts - │ │ └── ... - │ ├── routes/ # Definición de rutas - │ ├── middleware/ # Middlewares (auth, etc.) - │ └── config/ # Configuración (DB, etc.) - └── sql/ # Scripts SQL -``` - ---- - -## Próximos Pasos Sugeridos - -1. **Integración TTS** - Webhooks para The Things Stack -2. **Alertas automáticas** - Notificaciones por consumo anormal -3. **Reportes** - Generación de reportes PDF -4. **Despliegue** - Configurar para producción +1. **Rol ORGANISMOS_OPERADORES** - Implementar nuevo rol segun plan existente +2. **Reportes PDF** - Generacion y descarga de reportes en PDF +3. **Tests** - Suite de tests con Vitest (frontend) y Supertest (backend) +4. **CI/CD** - Pipeline de integracion continua +5. **Docker** - Containerizacion del proyecto completo diff --git a/README.md b/README.md index 9ae7b0f..45977c1 100644 --- a/README.md +++ b/README.md @@ -1,23 +1,55 @@ -# Water Project - Sistema de Gestion de Recursos Hidricos (GRH) +# GRH - Sistema de Gestion de Recursos Hidricos -Sistema de gestion y monitoreo de infraestructura hidrica desarrollado con React, TypeScript y Vite. +Sistema full-stack de gestion y monitoreo de infraestructura hidrica. Permite administrar medidores de agua, concentradores, proyectos, consumo, lecturas y conectarse con sistemas IoT (LoRaWAN / The Things Stack). + +--- ## Descripcion General -El **Sistema de Gestion de Recursos Hidricos (GRH)** es una aplicacion web frontend disenada para el monitoreo, administracion y control de infraestructura de toma de agua. Permite gestionar medidores, concentradores, proyectos, usuarios y roles a traves de una interfaz moderna y responsiva. +El **Sistema GRH** es una aplicacion web completa para organismos operadores de agua (CESPT Tijuana, Tecate, Mexicali, etc.) que incluye: -### Caracteristicas Principales - -- **Dashboard interactivo** con KPIs, alertas e historial de actividades -- **Gestion de Medidores (Tomas de Agua)** - CRUD completo con filtros por proyecto +- **Dashboard interactivo** con KPIs, graficos y alertas +- **Gestion de Medidores** - CRUD completo con carga masiva Excel/CSV - **Gestion de Concentradores** - Configuracion de gateways LoRa/LoRaWAN - **Gestion de Proyectos** - Administracion de proyectos de infraestructura -- **Gestion de Usuarios y Roles** - Control de acceso al sistema +- **Consumo y Lecturas** - Seguimiento historico de lecturas con filtros y exportacion +- **Analytics** - Mapa de medidores, reportes y metricas del servidor +- **Conectores** - Integracion con SH-Meters, XMeters y The Things Stack +- **Usuarios y Roles** - Control de acceso basado en roles (ADMIN, OPERATOR, VIEWER) +- **Auditoria** - Registro completo de actividad del sistema +- **Notificaciones** - Alertas en tiempo real (flujo negativo, etc.) - **Tema claro/oscuro** - Personalizacion de la interfaz - **Diseno responsive** - Compatible con desktop, tablet y movil --- +## Arquitectura + +``` +┌─────────────────────────────────────────────────────────────┐ +│ FRONTEND (React SPA) │ +│ http://localhost:5173 │ +│ React 18 + TypeScript + Vite + Tailwind CSS + MUI │ +└──────────────────────────┬──────────────────────────────────┘ + │ REST API (JWT) + ▼ +┌─────────────────────────────────────────────────────────────┐ +│ BACKEND (Express API) │ +│ http://localhost:3000 │ +│ Express + TypeScript + Zod + Winston + node-cron │ +└──────────────────────────┬──────────────────────────────────┘ + │ + ▼ +┌─────────────────────────────────────────────────────────────┐ +│ PostgreSQL │ +│ 10 tablas + 2 vistas + triggers + indices │ +└─────────────────────────────────────────────────────────────┘ +``` + +Adicionalmente existe un **Upload Panel** (`upload-panel/`) como aplicacion separada para carga masiva de datos via CSV. + +--- + ## Stack Tecnologico ### Frontend @@ -27,13 +59,26 @@ El **Sistema de Gestion de Recursos Hidricos (GRH)** es una aplicacion web front | TypeScript | 5.2.2 | Type safety | | Vite | 5.2.0 | Build tool y dev server | | Tailwind CSS | 4.1.18 | Estilos utility-first | -| Material-UI | 7.3.6 | Componentes UI | +| Material-UI (MUI) | 7.3.6 | Componentes UI | +| MUI X Data Grid | 8.21.0 | Tablas de datos avanzadas | | Recharts | 3.6.0 | Visualizacion de datos | +| Leaflet / React-Leaflet | 1.9.4 / 4.2.1 | Mapas interactivos | | Lucide React | 0.559.0 | Iconos SVG | -### Herramientas de Desarrollo -- **ESLint** - Linting de codigo -- **TypeScript ESLint** - Analisis estatico +### Backend +| Tecnologia | Version | Proposito | +|------------|---------|-----------| +| Express.js | 4.18.2 | Framework HTTP | +| TypeScript | 5.3.3 | Type safety | +| PostgreSQL (pg) | 8.11.3 | Driver de base de datos | +| JWT (jsonwebtoken) | 9.0.2 | Autenticacion con tokens | +| Bcrypt | 5.1.1 | Hash de contrasenas | +| Zod | 3.22.4 | Validacion de datos | +| Helmet | 7.1.0 | Headers de seguridad | +| Winston | 3.11.0 | Logging | +| Multer | 2.0.2 | Subida de archivos | +| XLSX | 0.18.5 | Parseo de archivos Excel | +| node-cron | 3.0.3 | Tareas programadas | --- @@ -42,334 +87,357 @@ El **Sistema de Gestion de Recursos Hidricos (GRH)** es una aplicacion web front ### Prerrequisitos - Node.js >= 18.x -- npm >= 9.x o yarn >= 1.22 +- npm >= 9.x +- PostgreSQL >= 14.x -### Pasos de Instalacion +### 1. Clonar el repositorio -1. **Clonar el repositorio** ```bash -git clone -cd water-project +git clone https://git.consultoria-as.com/consultoria-as/GRH.git +cd GRH ``` -2. **Instalar dependencias** +### 2. Configurar la base de datos + ```bash +# Crear la base de datos +createdb water_project + +# Ejecutar el schema principal +psql -d water_project -f water-api/sql/schema.sql + +# Ejecutar migraciones adicionales +psql -d water_project -f water-api/sql/add_audit_logs.sql +psql -d water_project -f water-api/sql/add_notifications.sql +psql -d water_project -f water-api/sql/add_meter_extended_fields.sql +psql -d water_project -f water-api/sql/create_meter_types.sql +psql -d water_project -f water-api/sql/add_meter_project_relation.sql +psql -d water_project -f water-api/sql/add_user_project_relation.sql +``` + +### 3. Configurar el backend + +```bash +cd water-api +cp .env.example .env +# Editar .env con las credenciales de PostgreSQL y secretos JWT npm install ``` -3. **Configurar variables de entorno** +### 4. Configurar el frontend + ```bash +cd .. cp .env.example .env +# Editar .env con la URL del backend +npm install ``` -Editar el archivo `.env`: -```env -VITE_API_BASE_URL=https://tu-api-url.com -VITE_API_TOKEN=tu-token-de-api -``` +### 5. Iniciar en desarrollo -4. **Iniciar servidor de desarrollo** ```bash +# Terminal 1 - Backend +cd water-api +npm run dev + +# Terminal 2 - Frontend +cd .. npm run dev ``` -La aplicacion estara disponible en `http://localhost:5173` +El frontend estara disponible en `http://localhost:5173` y el backend en `http://localhost:3000`. + +--- + +## Variables de Entorno + +### Frontend (`.env`) +| Variable | Descripcion | Ejemplo | +|----------|-------------|---------| +| `VITE_API_BASE_URL` | URL base del backend | `http://localhost:3000` | + +### Backend (`water-api/.env`) +| Variable | Descripcion | Ejemplo | +|----------|-------------|---------| +| `PORT` | Puerto del servidor | `3000` | +| `NODE_ENV` | Entorno | `development` | +| `DB_HOST` | Host de PostgreSQL | `localhost` | +| `DB_PORT` | Puerto de PostgreSQL | `5432` | +| `DB_NAME` | Nombre de la base de datos | `water_project` | +| `DB_USER` | Usuario de PostgreSQL | `postgres` | +| `DB_PASSWORD` | Contrasena de PostgreSQL | `your_password` | +| `JWT_ACCESS_SECRET` | Secreto para access tokens | `random_string` | +| `JWT_REFRESH_SECRET` | Secreto para refresh tokens | `random_string` | +| `JWT_ACCESS_EXPIRES` | Expiracion access token | `15m` | +| `JWT_REFRESH_EXPIRES` | Expiracion refresh token | `7d` | +| `CORS_ORIGIN` | Origenes permitidos | `http://localhost:5173` | +| `TTS_ENABLED` | Habilitar The Things Stack | `false` | +| `TTS_BASE_URL` | URL de TTS | `https://...` | +| `TTS_WEBHOOK_SECRET` | Secreto para webhooks TTS | `random_string` | --- ## Scripts Disponibles +### Frontend | Comando | Descripcion | |---------|-------------| -| `npm run dev` | Inicia el servidor de desarrollo | -| `npm run build` | Compila TypeScript y genera build de produccion | -| `npm run preview` | Previsualiza el build de produccion | -| `npm run lint` | Ejecuta ESLint en el codigo | +| `npm run dev` | Servidor de desarrollo (puerto 5173) | +| `npm run build` | Compilar TypeScript + build de produccion | +| `npm run preview` | Previsualizar build de produccion | +| `npm run lint` | Ejecutar ESLint | + +### Backend (`water-api/`) +| Comando | Descripcion | +|---------|-------------| +| `npm run dev` | Servidor de desarrollo con hot-reload | +| `npm run build` | Compilar TypeScript | +| `npm run start` | Ejecutar build compilado | +| `npm run watch` | Desarrollo con nodemon | + +### Upload Panel (`upload-panel/`) +| Comando | Descripcion | +|---------|-------------| +| `npm run dev` | Servidor de desarrollo | +| `npm run build` | Build de produccion | --- ## Estructura del Proyecto ``` -water-project/ -├── public/ # Assets estaticos -│ └── grhWatermark.jpg -│ -├── src/ -│ ├── api/ # Capa de comunicacion con API -│ │ ├── me.ts # Endpoints de perfil -│ │ ├── meters.ts # CRUD de medidores -│ │ ├── concentrators.ts # CRUD de concentradores -│ │ └── projects.ts # CRUD de proyectos +GRH/ +├── src/ # Frontend React SPA +│ ├── api/ # Cliente API (14 modulos) +│ │ ├── client.ts # Cliente HTTP con JWT y refresh automatico +│ │ ├── auth.ts # Autenticacion y gestion de tokens +│ │ ├── meters.ts # CRUD de medidores +│ │ ├── readings.ts # Lecturas de consumo +│ │ ├── projects.ts # Proyectos +│ │ ├── concentrators.ts # Concentradores +│ │ ├── users.ts # Usuarios +│ │ ├── roles.ts # Roles +│ │ ├── analytics.ts # Analytics y metricas +│ │ ├── notifications.ts # Notificaciones +│ │ ├── audit.ts # Auditoria +│ │ ├── me.ts # Perfil de usuario +│ │ ├── meterTypes.ts # Tipos de medidor +│ │ └── types.ts # Tipos compartidos │ │ -│ ├── components/ -│ │ ├── layout/ # Componentes de layout -│ │ │ ├── Sidebar.tsx # Menu lateral -│ │ │ ├── TopMenu.tsx # Barra superior -│ │ │ └── common/ # Componentes reutilizables -│ │ │ ├── ProfileModal.tsx -│ │ │ ├── ConfirmModal.tsx -│ │ │ └── Watermark.tsx -│ │ └── SettingsModals.tsx +│ ├── components/ # Componentes reutilizables +│ │ ├── layout/ +│ │ │ ├── Sidebar.tsx # Menu lateral (colapsable, pin) +│ │ │ ├── TopMenu.tsx # Barra superior con breadcrumb +│ │ │ └── common/ +│ │ │ ├── ProfileModal.tsx # Editar perfil y avatar +│ │ │ ├── ConfirmModal.tsx # Confirmacion de acciones +│ │ │ ├── Watermark.tsx # Marca de agua GRH +│ │ │ └── ProjectBadge.tsx # Badge de proyecto +│ │ ├── SettingsModals.tsx # Configuracion de tema/UI +│ │ └── NotificationDropdown.tsx # Panel de notificaciones │ │ -│ ├── pages/ # Paginas principales -│ │ ├── Home.tsx # Dashboard -│ │ ├── LoginPage.tsx # Login -│ │ ├── UsersPage.tsx # Gestion de usuarios -│ │ ├── RolesPage.tsx # Gestion de roles +│ ├── pages/ +│ │ ├── Home.tsx # Dashboard con KPIs y graficos +│ │ ├── LoginPage.tsx # Inicio de sesion +│ │ ├── UsersPage.tsx # Gestion de usuarios +│ │ ├── RolesPage.tsx # Gestion de roles +│ │ ├── AuditoriaPage.tsx # Visor de logs de auditoria │ │ ├── projects/ │ │ │ └── ProjectsPage.tsx -│ │ ├── meters/ # Modulo de medidores +│ │ ├── meters/ # Modulo de medidores │ │ │ ├── MeterPage.tsx -│ │ │ ├── useMeters.ts # Hook personalizado │ │ │ ├── MetersTable.tsx │ │ │ ├── MetersModal.tsx -│ │ │ └── MetersSidebar.tsx -│ │ └── concentrators/ # Modulo de concentradores -│ │ ├── ConcentratorsPage.tsx -│ │ ├── useConcentrators.ts -│ │ ├── ConcentratorsTable.tsx -│ │ ├── ConcentratorsModal.tsx -│ │ └── ConcentratorsSidebar.tsx +│ │ │ ├── MetersSidebar.tsx +│ │ │ ├── MetersBulkUploadModal.tsx +│ │ │ └── useMeters.ts +│ │ ├── concentrators/ # Modulo de concentradores +│ │ │ ├── ConcentratorsPage.tsx +│ │ │ ├── ConcentratorsTable.tsx +│ │ │ ├── ConcentratorsModal.tsx +│ │ │ ├── ConcentratorsSidebar.tsx +│ │ │ └── useConcentrators.ts +│ │ ├── consumption/ # Modulo de consumo +│ │ │ ├── ConsumptionPage.tsx +│ │ │ └── ReadingsBulkUploadModal.tsx +│ │ ├── analytics/ # Modulo de analytics +│ │ │ ├── AnalyticsMapPage.tsx +│ │ │ ├── AnalyticsReportsPage.tsx +│ │ │ ├── AnalyticsServerPage.tsx +│ │ │ └── MapComponents.tsx +│ │ └── conectores/ # Conectores externos +│ │ ├── SHMetersPage.tsx +│ │ ├── XMetersPage.tsx +│ │ └── TTSPage.tsx │ │ -│ ├── assets/ -│ │ └── images/ -│ │ -│ ├── App.tsx # Componente raiz -│ ├── main.tsx # Punto de entrada -│ └── index.css # Estilos globales +│ ├── hooks/ +│ │ └── useNotifications.ts +│ ├── App.tsx # Componente raiz (routing + auth) +│ ├── main.tsx # Punto de entrada React +│ └── index.css # Estilos globales (Tailwind) │ -├── index.html -├── package.json -├── tsconfig.json -├── vite.config.ts -└── .env.example +├── water-api/ # Backend Express API +│ ├── src/ +│ │ ├── index.ts # Setup del servidor Express +│ │ ├── config/ +│ │ │ ├── index.ts # Carga de configuracion +│ │ │ └── database.ts # Pool de conexiones PostgreSQL +│ │ ├── routes/ # 17 archivos de rutas +│ │ ├── controllers/ # Controladores REST +│ │ ├── services/ # Logica de negocio (18 modulos) +│ │ ├── middleware/ +│ │ │ ├── auth.middleware.ts # Verificacion JWT +│ │ │ ├── audit.middleware.ts # Logging de actividad +│ │ │ └── ttsWebhook.middleware.ts +│ │ ├── validators/ # Validacion con Zod +│ │ ├── utils/ +│ │ │ ├── jwt.ts # Generacion/verificacion de tokens +│ │ │ ├── password.ts # Wrappers de bcrypt +│ │ │ └── logger.ts # Configuracion Winston +│ │ ├── jobs/ +│ │ │ └── negativeFlowDetection.ts # Tarea programada +│ │ └── types/ # Interfaces TypeScript +│ │ +│ ├── sql/ # Schema y migraciones +│ │ ├── schema.sql # Schema principal (10 tablas + 2 vistas) +│ │ ├── add_audit_logs.sql +│ │ ├── add_notifications.sql +│ │ ├── add_meter_extended_fields.sql +│ │ ├── create_meter_types.sql +│ │ ├── add_meter_project_relation.sql +│ │ └── add_user_project_relation.sql +│ │ +│ ├── package.json +│ ├── tsconfig.json +│ └── .env.example +│ +├── upload-panel/ # App separada para carga CSV +│ ├── src/ +│ │ ├── App.tsx +│ │ ├── components/ +│ │ │ ├── MetersUpload.tsx +│ │ │ ├── ReadingsUpload.tsx +│ │ │ ├── FileDropzone.tsx +│ │ │ └── ResultsDisplay.tsx +│ │ └── api/upload.ts +│ ├── package.json +│ └── vite.config.ts +│ +├── package.json # Dependencias frontend +├── vite.config.ts # Configuracion Vite +├── tsconfig.json # Configuracion TypeScript +├── index.html # HTML de entrada +├── DOCUMENTATION.md # Documentacion tecnica +├── ESTADO_ACTUAL.md # Estado actual del proyecto +└── CAMBIOS_SESION.md # Historial de cambios ``` --- -## Modulos Funcionales +## Base de Datos -### 1. Dashboard (Home) +### Jerarquia de datos +``` +Projects → Concentrators → Meters → Readings + → Gateways → Devices ↗ +``` -El dashboard principal ofrece: -- Selector de organismos operadores (CESPT TIJUANA, TECATE, MEXICALI) -- Grafico de barras: "Numero de Medidores por Proyecto" -- Tarjetas de acceso rapido: Tomas, Alertas, Mantenimiento, Reportes -- Historial reciente de actividades -- Panel de ultimas alertas +### Tablas principales -### 2. Gestion de Medidores +| Tabla | Descripcion | +|-------|-------------| +| `roles` | Roles del sistema (ADMIN, OPERATOR, VIEWER) con permisos JSONB | +| `users` | Usuarios con email, password hash, rol y estado | +| `projects` | Proyectos de infraestructura hidrica | +| `concentrators` | Concentradores de datos vinculados a proyectos | +| `gateways` | Gateways LoRaWAN con integracion TTS | +| `devices` | Dispositivos LoRaWAN (sensores/transmisores) | +| `meters` | Medidores de agua con ubicacion y ultima lectura | +| `meter_readings` | Historial de lecturas con bateria y senal | +| `tts_uplink_logs` | Logs de mensajes uplink de The Things Stack | +| `refresh_tokens` | Tokens de refresco JWT para sesiones | -Modulo completo para administrar medidores/tomas de agua: - -**Funcionalidades:** -- Listado con busqueda y filtros -- Filtrado por proyecto -- Tipos de toma: GENERAL, LORA, LORAWAN, GRANDES -- CRUD completo (Crear, Leer, Actualizar, Eliminar) - -**Campos principales:** -- Area, Numero de cuenta, Usuario, Direccion -- Serial del medidor, Nombre, Estado -- Tipo de protocolo, Particion DMA -- Configuracion de dispositivo (Device EUI, AppKey, etc.) - -### 3. Gestion de Concentradores - -Administracion de concentradores y gateways: - -**Funcionalidades:** -- Listado con filtros por proyecto -- Configuracion de Gateway (ID, EUI, Nombre) -- Seleccion de ubicacion de antena (Indoor/Outdoor) -- CRUD completo - -### 4. Gestion de Proyectos - -Administracion de proyectos de infraestructura: -- Tabla con busqueda integrada -- Estados: ACTIVE/INACTIVE -- Informacion de operador y tiempos - -### 5. Gestion de Usuarios - -Control de usuarios del sistema: -- Listado de usuarios -- Asignacion de roles -- Estados: ACTIVE/INACTIVE - -### 6. Gestion de Roles - -Administracion de roles de acceso: -- Roles predefinidos: SUPER_ADMIN, USER -- Descripcion de permisos +### Vistas +- `meter_stats_by_project` - Estadisticas agregadas de medidores por proyecto +- `device_status_summary` - Resumen de estados de dispositivos por proyecto --- -## API y Comunicacion +## API Endpoints -### Configuracion +Todos los endpoints estan bajo el prefijo `/api/`. La mayoria requieren autenticacion JWT. -La aplicacion se conecta a una API REST externa. Configurar en `.env`: - -```env -VITE_API_BASE_URL=https://tu-api.com -VITE_API_TOKEN=tu-token -``` - -### Endpoints Principales - -| Recurso | Endpoint Base | -|---------|---------------| -| Medidores | `/api/v3/data/.../m4hzpnopjkppaav/records` | -| Concentradores | `/api/v3/data/.../mheif1vdgnyt8x2/records` | -| Proyectos | `/api/v3/data/.../m9882vn3xb31e29/records` | - -### Estructura de Respuesta - -```typescript -interface ApiResponse { - records: Array<{ - id: string; - fields: T; - }>; - next?: string; - prev?: string; -} -``` - ---- - -## Modelos de Datos - -### Meter (Medidor) - -```typescript -interface Meter { - id: string; - createdAt: string; - updatedAt: string; - areaName: string; - accountNumber: string | null; - userName: string | null; - userAddress: string | null; - meterSerialNumber: string; - meterName: string; - meterStatus: string; - protocolType: string; - priceNo: string | null; - priceName: string | null; - dmaPartition: string | null; - supplyTypes: string; - deviceId: string; - deviceName: string; - deviceType: string; - usageAnalysisType: string; - installedTime: string; -} -``` - -### Concentrator - -```typescript -interface Concentrator { - id: string; - "Area Name": string; - "Device S/N": string; - "Device Name": string; - "Device Time": string; - "Device Status": string; - "Operator": string; - "Installed Time": string; - "Communication Time": string; - "Instruction Manual": string; -} -``` - -### Project - -```typescript -interface Project { - id: string; - areaName: string; - deviceSN: string; - deviceName: string; - deviceType: string; - deviceStatus: "ACTIVE" | "INACTIVE"; - operator: string; - installedTime: string; - communicationTime: string; -} -``` +| Grupo | Prefijo | Descripcion | +|-------|---------|-------------| +| Auth | `/api/auth` | Login, refresh, logout, perfil | +| Projects | `/api/projects` | CRUD de proyectos + estadisticas | +| Meters | `/api/meters` | CRUD de medidores + lecturas | +| Meter Types | `/api/meter-types` | Tipos de medidor | +| Concentrators | `/api/concentrators` | CRUD de concentradores | +| Gateways | `/api/gateways` | CRUD de gateways + dispositivos | +| Devices | `/api/devices` | CRUD de dispositivos LoRaWAN | +| Users | `/api/users` | Gestion de usuarios (admin) | +| Roles | `/api/roles` | Gestion de roles | +| Readings | `/api/readings` | Lecturas y resumen de consumo | +| Notifications | `/api/notifications` | Notificaciones del usuario | +| Audit | `/api/audit-logs` | Logs de auditoria (admin) | +| Bulk Upload | `/api/bulk-upload` | Carga masiva Excel | +| CSV Upload | `/api/csv-upload` | Carga masiva CSV | +| TTS Webhooks | `/api/webhooks/tts` | Webhooks The Things Stack | +| System | `/api/system` | Metricas y salud del servidor (admin) | --- ## Autenticacion -### Flujo de Login +El sistema usa **JWT con refresh tokens**: -1. Usuario ingresa credenciales -2. Validacion del checkbox "No soy un robot" -3. Token almacenado en `localStorage` (`grh_auth`) -4. Redireccion al Dashboard +1. El usuario envia email/password a `POST /api/auth/login` +2. El backend valida credenciales con bcrypt y genera: + - **Access token** (15 minutos) + - **Refresh token** (7 dias) +3. Los tokens se almacenan en `localStorage` +4. El cliente HTTP envia el access token en `Authorization: Bearer ` +5. Al expirar, el cliente automaticamente llama a `POST /api/auth/refresh` -### Almacenamiento - -```javascript -// localStorage keys -grh_auth: { token: string, ts: number } -water_project_settings_v1: { theme: string, compactMode: boolean } -``` - ---- - -## Configuracion de Temas - -El sistema soporta tres modos de tema: -- **Sistema** - Detecta preferencia del OS -- **Claro** - Tema light -- **Oscuro** - Tema dark - -Configuracion persistida en `localStorage` bajo `water_project_settings_v1`. +### Roles y permisos +| Rol | Descripcion | +|-----|-------------| +| `ADMIN` | Acceso completo al sistema | +| `OPERATOR` | Gestiona proyectos, dispositivos, medidores (sin configuracion del sistema) | +| `VIEWER` | Solo lectura de datos y reportes | --- ## Despliegue -### Build de Produccion +### Build de produccion ```bash -npm run build +# Frontend +npm run build # Genera dist/ + +# Backend +cd water-api +npm run build # Genera dist/ +npm run start # Ejecuta el build ``` -Los archivos compilados se generan en la carpeta `dist/`. - -### Configuracion de Vite - -El servidor de desarrollo esta configurado para: -- Puerto: 5173 -- Host: habilitado para acceso remoto -- Hosts permitidos: localhost, 127.0.0.1, dominios personalizados +### URLs de produccion +- **Frontend:** `https://sistema.gestionrecursoshidricos.com` +- **Backend:** `https://api.gestionrecursoshidricos.com` --- -## Contribucion +## Repositorios -1. Fork del repositorio -2. Crear rama feature (`git checkout -b feature/nueva-funcionalidad`) -3. Commit de cambios (`git commit -m 'Agregar nueva funcionalidad'`) -4. Push a la rama (`git push origin feature/nueva-funcionalidad`) -5. Crear Pull Request +| Remote | URL | +|--------|-----| +| Gitea | `https://git.consultoria-as.com/consultoria-as/GRH` | +| GitHub | `git@github.com:luanngel/water-project.git` | --- ## Licencia -Este proyecto es privado y pertenece a GRH - Gestion de Recursos Hidricos. - ---- - -## Contacto - -Para soporte o consultas sobre el sistema, contactar al equipo de desarrollo. +Este proyecto es privado y pertenece a GRH - Gestion de Recursos Hidricos / Consultoria AS.