# Documentacion Tecnica - GRH (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. [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) --- ## 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: 11 tablas, 2 vistas, triggers, indices │ ├─────────────────────────────────────────────────────────────┤ │ Integraciones Externas │ │ The Things Stack (LoRaWAN), SH-Meters, XMeters │ └─────────────────────────────────────────────────────────────┘ ``` ### Patrones de Diseno 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 --- ## Frontend - Componentes y Paginas ### App.tsx - Componente Raiz Maneja autenticacion global, routing por estado interno y modales globales. ```typescript export type Page = | "home" | "projects" | "meters" | "concentrators" | "consumption" | "auditoria" | "users" | "roles" | "sh-meters" | "xmeters" | "tts" | "analytics-map" | "analytics-reports" | "analytics-server" | "organismos" | "historico"; ``` 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 | | Organismos | `OrganismosPage.tsx` | Gestion de organismos operadores (ADMIN) | | Historico | `historico/HistoricoPage.tsx` | Historico de lecturas por medidor con grafica, estadisticas y tabla | ### Componentes de Layout **Sidebar.tsx** - Menu lateral colapsable con hover expansion - Soporte para pin/unpin - Menu jerarquico con submenus (Analytics, Conectores) - Visibilidad por rol de 3 niveles: - ADMIN: ve todo (incluye Organismos, Conectores, Auditoria) - ORGANISMO_OPERADOR: ve Dashboard, Project Management, Users, Analytics - OPERATOR: ve Dashboard y Project Management **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 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 --- ## 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 (18 archivos) │ └── organismo-operador.routes.ts # Rutas CRUD organismos ├── controllers/ # Controladores HTTP │ └── organismo-operador.controller.ts ├── services/ # Logica de negocio (19 modulos) │ └── organismo-operador.service.ts ├── middleware/ │ ├── auth.middleware.ts # Verificacion JWT + extraccion de rol + requireRole │ ├── 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 (incluye organismoOperadorId) │ ├── password.ts # hash/compare con bcrypt │ ├── logger.ts # Winston con formato timestamp │ └── scope.ts # Filtrado por scope de rol (ADMIN/ORGANISMO/OPERATOR) ├── 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) | #### Organismos Operadores (`/api/organismos-operadores`) - Solo ADMIN | Metodo | Ruta | Descripcion | Auth | |--------|------|-------------|------| | GET | `/` | Listar organismos operadores | Si (ADMIN) | | GET | `/:id` | Obtener organismo operador | Si (ADMIN) | | POST | `/` | Crear organismo operador | Si (ADMIN) | | PUT | `/:id` | Actualizar organismo operador | Si (ADMIN) | | DELETE | `/:id` | Eliminar organismo operador | Si (ADMIN) | #### Usuarios (`/api/users`) - ADMIN y ORGANISMO_OPERADOR | Metodo | Ruta | Descripcion | Auth | |--------|------|-------------|------| | GET | `/` | Listar usuarios (filtrado por scope) | Si (ADMIN/ORGANISMO_OPERADOR) | | GET | `/:id` | Obtener usuario | Si (ADMIN o self) | | POST | `/` | Crear usuario | Si (ADMIN/ORGANISMO_OPERADOR) | | 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, ORGANISMO_OPERADOR, OPERATOR - `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 tablas base, 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 8. `add_organismos_operadores.sql` - Tabla organismos_operadores, FK en projects y users, rol ORGANISMO_OPERADOR 9. `add_user_meter_fields.sql` - Campos adicionales en users y meters (cespt_account, cadastral_key) --- ## 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, organismoOperadorId. 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 (Jerarquia de 3 niveles) | Recurso | ADMIN | ORGANISMO_OPERADOR | OPERATOR | |---------|-------|-------------------|----------| | Organismos | CRUD completo | Sin acceso | Sin acceso | | Usuarios | CRUD completo | CRUD (su organismo) | Sin acceso | | Proyectos | CRUD completo | Leer (su organismo) | Leer (su proyecto) | | Medidores | CRUD completo | Leer (su organismo) | Leer (su proyecto) | | Lecturas | CRUD + eliminar | Leer (su organismo) | Leer (su proyecto) | | Historico | Todos los medidores | Medidores de su organismo | Medidores de su proyecto | | Analytics | Completo | Completo | Sin acceso | | Conectores | Completo | Sin acceso | Sin acceso | | Auditoria | Completa | Sin acceso | Sin acceso | ### Scope Filtering (Backend) Todos los servicios aplican filtrado automatico basado en el rol del usuario: ``` ADMIN → Sin filtro (ve todos los datos) ORGANISMO_OP. → project_id IN (SELECT id FROM projects WHERE organismo_operador_id = $N) OPERATOR → project_id = $N (solo su proyecto asignado) ``` El utility `water-api/src/utils/scope.ts` centraliza esta logica. ### Helpers del Frontend ```typescript getCurrentUserRole() // → "ADMIN" | "ORGANISMO_OPERADOR" | "OPERATOR" getCurrentUserId() // → UUID string getCurrentUserProjectId() // → UUID string | undefined getCurrentUserOrganismoId() // → UUID string | undefined isCurrentUserAdmin() // → boolean isCurrentUserOrganismo() // → boolean isCurrentUserOperator() // → boolean ``` --- ## Capa de API del Frontend ### Cliente HTTP (`src/api/client.ts`) 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) ### Modulos de API | Archivo | Descripcion | |---------|-------------| | `auth.ts` | Login, logout, refresh, getMe, helpers de roles (3 niveles) | | `client.ts` | Cliente HTTP base con JWT | | `meters.ts` | CRUD medidores + lecturas historicas paginadas | | `readings.ts` | Lecturas y resumen de consumo | | `projects.ts` | CRUD proyectos + nombres | | `concentrators.ts` | CRUD concentradores | | `users.ts` | CRUD usuarios | | `roles.ts` | CRUD roles | | `organismos.ts` | CRUD organismos operadores | | `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. ```typescript 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; loadMeters: () => Promise; // CRUD handleCreate: (data: Partial) => Promise; handleUpdate: (id: string, data: Partial) => Promise; handleDelete: (id: string) => Promise; } ``` ### useConcentrators Estructura equivalente a `useMeters` para el modulo de concentradores. ### useNotifications Gestiona notificaciones del usuario con polling periodico. ```typescript interface UseNotificationsReturn { notifications: Notification[]; unreadCount: number; loading: boolean; markAsRead: (id: string) => Promise; markAllAsRead: () => Promise; deleteNotification: (id: string) => Promise; refresh: () => Promise; } ``` ### 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`. ```typescript 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 ```typescript 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: 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 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()`) ### Agregar un Nuevo Endpoint en el Backend 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` ### Agregar un Modulo de API en el Frontend 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` ### 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: ```bash # Frontend npm install -D vitest @testing-library/react @testing-library/jest-dom # Backend cd water-api npm install -D vitest supertest @types/supertest ```