From 71623d667f25e1db7bf01a3e63195d3df81ee33b Mon Sep 17 00:00:00 2001 From: Exteban08 Date: Tue, 3 Feb 2026 11:27:51 +0000 Subject: [PATCH] Add complete project documentation Documentation includes: - README.md: Project overview and architecture - API.md: Complete API reference with endpoints - MANUAL_USUARIO.md: User manual in Spanish - INSTALACION.md: Installation and deployment guide - ARQUITECTURA.md: Architecture and database schema - UPLOAD_PANEL.md: CSV upload panel documentation Co-Authored-By: Claude Opus 4.5 --- docs/API.md | 563 +++++++++++++++++++++++++++++++++++++++++ docs/ARQUITECTURA.md | 496 ++++++++++++++++++++++++++++++++++++ docs/INSTALACION.md | 390 ++++++++++++++++++++++++++++ docs/MANUAL_USUARIO.md | 358 ++++++++++++++++++++++++++ docs/README.md | 126 +++++++++ docs/UPLOAD_PANEL.md | 297 ++++++++++++++++++++++ 6 files changed, 2230 insertions(+) create mode 100644 docs/API.md create mode 100644 docs/ARQUITECTURA.md create mode 100644 docs/INSTALACION.md create mode 100644 docs/MANUAL_USUARIO.md create mode 100644 docs/README.md create mode 100644 docs/UPLOAD_PANEL.md diff --git a/docs/API.md b/docs/API.md new file mode 100644 index 0000000..fe21e5a --- /dev/null +++ b/docs/API.md @@ -0,0 +1,563 @@ +# Documentacion API + +## Informacion General + +- **URL Base**: `https://api.gestionrecursoshidricos.com/api` +- **Formato**: JSON +- **Autenticacion**: Bearer Token (JWT) + +## Autenticacion + +### Login +```http +POST /auth/login +Content-Type: application/json + +{ + "email": "usuario@ejemplo.com", + "password": "contraseña" +} +``` + +**Respuesta exitosa:** +```json +{ + "success": true, + "data": { + "user": { + "id": "uuid", + "email": "usuario@ejemplo.com", + "name": "Nombre", + "role": "ADMIN" + }, + "accessToken": "jwt_token", + "refreshToken": "refresh_token" + } +} +``` + +### Refresh Token +```http +POST /auth/refresh +Content-Type: application/json + +{ + "refreshToken": "refresh_token" +} +``` + +### Logout +```http +POST /auth/logout +Authorization: Bearer {accessToken} +``` + +### Obtener Perfil +```http +GET /auth/me +Authorization: Bearer {accessToken} +``` + +--- + +## Proyectos + +### Listar Proyectos +```http +GET /projects?page=1&pageSize=10 +Authorization: Bearer {accessToken} +``` + +**Parametros de consulta:** +| Parametro | Tipo | Descripcion | +|-----------|------|-------------| +| page | number | Numero de pagina (default: 1) | +| pageSize | number | Registros por pagina (default: 10) | +| status | string | Filtrar por estado (ACTIVE, INACTIVE) | +| search | string | Buscar por nombre | + +### Obtener Proyecto +```http +GET /projects/:id +Authorization: Bearer {accessToken} +``` + +### Estadisticas del Proyecto +```http +GET /projects/:id/stats +Authorization: Bearer {accessToken} +``` + +### Crear Proyecto +```http +POST /projects +Authorization: Bearer {accessToken} +Content-Type: application/json + +{ + "name": "Nombre del Proyecto", + "description": "Descripcion", + "area_name": "Nombre del Area", + "location": "Ubicacion", + "meter_type_id": "uuid-tipo-medidor" +} +``` + +### Actualizar Proyecto +```http +PUT /projects/:id +Authorization: Bearer {accessToken} +Content-Type: application/json + +{ + "name": "Nuevo Nombre", + "status": "ACTIVE" +} +``` + +### Eliminar Proyecto +```http +DELETE /projects/:id +Authorization: Bearer {accessToken} +``` +*Requiere rol ADMIN* + +--- + +## Concentradores + +### Listar Concentradores +```http +GET /concentrators?project_id=uuid +Authorization: Bearer {accessToken} +``` + +**Parametros de consulta:** +| Parametro | Tipo | Descripcion | +|-----------|------|-------------| +| project_id | uuid | Filtrar por proyecto | +| status | string | Filtrar por estado | +| search | string | Buscar por serial o nombre | + +### Obtener Concentrador +```http +GET /concentrators/:id +Authorization: Bearer {accessToken} +``` + +### Crear Concentrador +```http +POST /concentrators +Authorization: Bearer {accessToken} +Content-Type: application/json + +{ + "serial_number": "CONC001", + "name": "Concentrador Principal", + "project_id": "uuid-proyecto", + "location": "Ubicacion", + "ip_address": "192.168.1.100" +} +``` + +### Actualizar Concentrador +```http +PUT /concentrators/:id +Authorization: Bearer {accessToken} +Content-Type: application/json + +{ + "name": "Nuevo Nombre", + "status": "ACTIVE" +} +``` + +### Eliminar Concentrador +```http +DELETE /concentrators/:id +Authorization: Bearer {accessToken} +``` + +--- + +## Medidores + +### Listar Medidores +```http +GET /meters?page=1&pageSize=50 +Authorization: Bearer {accessToken} +``` + +**Parametros de consulta:** +| Parametro | Tipo | Descripcion | +|-----------|------|-------------| +| page | number | Numero de pagina | +| pageSize | number | Registros por pagina | +| project_id | uuid | Filtrar por proyecto | +| concentrator_id | uuid | Filtrar por concentrador | +| status | string | ACTIVE, INACTIVE, OFFLINE, MAINTENANCE, ERROR | +| type | string | LORA, LORAWAN, GRANDES CONSUMIDORES | +| search | string | Buscar por serial o nombre | + +### Obtener Medidor +```http +GET /meters/:id +``` + +### Lecturas del Medidor +```http +GET /meters/:id/readings?page=1&pageSize=50 +``` + +### Crear Medidor +```http +POST /meters +Authorization: Bearer {accessToken} +Content-Type: application/json + +{ + "serial_number": "MED001", + "name": "Medidor 001", + "concentrator_id": "uuid-concentrador", + "project_id": "uuid-proyecto", + "area_name": "Zona A", + "location": "Depto 101", + "type": "LORA", + "status": "ACTIVE", + "installation_date": "2024-01-15" +} +``` + +### Actualizar Medidor +```http +PUT /meters/:id +Authorization: Bearer {accessToken} +Content-Type: application/json + +{ + "name": "Nuevo Nombre", + "status": "MAINTENANCE" +} +``` + +### Actualizar Parcial (PATCH) +```http +PATCH /meters/:id +Authorization: Bearer {accessToken} +Content-Type: application/json + +{ + "status": "ACTIVE" +} +``` + +### Eliminar Medidor +```http +DELETE /meters/:id +Authorization: Bearer {accessToken} +``` +*Requiere rol ADMIN* + +--- + +## Lecturas + +### Listar Lecturas +```http +GET /readings?page=1&pageSize=50 +``` + +**Parametros de consulta:** +| Parametro | Tipo | Descripcion | +|-----------|------|-------------| +| meter_id | uuid | Filtrar por medidor | +| project_id | uuid | Filtrar por proyecto | +| concentrator_id | uuid | Filtrar por concentrador | +| start_date | date | Fecha inicio (YYYY-MM-DD) | +| end_date | date | Fecha fin (YYYY-MM-DD) | +| reading_type | string | AUTOMATIC, MANUAL, SCHEDULED | + +### Resumen de Consumo +```http +GET /readings/summary?project_id=uuid +``` + +**Respuesta:** +```json +{ + "success": true, + "data": { + "totalReadings": 1500, + "totalMeters": 50, + "avgReading": 125.5, + "lastReadingDate": "2024-01-20T10:30:00Z" + } +} +``` + +### Crear Lectura +```http +POST /readings +Authorization: Bearer {accessToken} +Content-Type: application/json + +{ + "meter_id": "uuid-medidor", + "reading_value": 1234.56, + "reading_type": "MANUAL", + "battery_level": 85, + "signal_strength": -45, + "received_at": "2024-01-20T10:30:00Z" +} +``` + +### Eliminar Lectura +```http +DELETE /readings/:id +Authorization: Bearer {accessToken} +``` +*Requiere rol ADMIN* + +--- + +## Carga CSV (Sin Autenticacion) + +### Subir Medidores CSV +```http +POST /csv-upload/meters +Content-Type: multipart/form-data + +file: archivo.csv +``` + +**Formato CSV:** +```csv +serial_number,name,concentrator_serial,area_name,location,meter_type,status,installation_date +MED001,Medidor 1,CONC001,Zona A,Depto 101,LORA,ACTIVE,2024-01-15 +``` + +**Respuesta:** +```json +{ + "success": true, + "message": "Procesamiento completado: 10 insertados, 5 actualizados, 2 errores", + "data": { + "total": 17, + "inserted": 10, + "updated": 5, + "errors": [ + { + "row": 15, + "field": "concentrator_serial", + "message": "Concentrador no encontrado" + } + ] + } +} +``` + +### Subir Lecturas CSV +```http +POST /csv-upload/readings +Content-Type: multipart/form-data + +file: archivo.csv +``` + +**Formato CSV:** +```csv +meter_serial,reading_value,received_at,reading_type,battery_level,signal_strength +MED001,1234.56,2024-01-20 10:30:00,MANUAL,85,-45 +``` + +### Descargar Plantilla Medidores +```http +GET /csv-upload/meters/template +``` + +### Descargar Plantilla Lecturas +```http +GET /csv-upload/readings/template +``` + +--- + +## Usuarios + +### Listar Usuarios +```http +GET /users +Authorization: Bearer {accessToken} +``` +*Requiere rol ADMIN* + +### Crear Usuario +```http +POST /users +Authorization: Bearer {accessToken} +Content-Type: application/json + +{ + "email": "nuevo@ejemplo.com", + "password": "contraseña123", + "name": "Nombre Usuario", + "role_id": "uuid-rol", + "project_id": "uuid-proyecto" +} +``` +*Requiere rol ADMIN* + +### Actualizar Usuario +```http +PUT /users/:id +Authorization: Bearer {accessToken} +Content-Type: application/json + +{ + "name": "Nuevo Nombre", + "is_active": true +} +``` + +### Cambiar Contraseña +```http +PUT /users/:id/password +Authorization: Bearer {accessToken} +Content-Type: application/json + +{ + "currentPassword": "actual", + "newPassword": "nueva123" +} +``` + +--- + +## Roles + +### Listar Roles +```http +GET /roles +Authorization: Bearer {accessToken} +``` + +**Roles disponibles:** +| Rol | Descripcion | +|-----|-------------| +| ADMIN | Acceso completo al sistema | +| OPERATOR | Gestion de medidores y lecturas de su proyecto | +| VIEWER | Solo lectura | + +--- + +## Notificaciones + +### Listar Notificaciones +```http +GET /notifications?page=1&pageSize=20 +Authorization: Bearer {accessToken} +``` + +### Contador No Leidas +```http +GET /notifications/unread-count +Authorization: Bearer {accessToken} +``` + +### Marcar como Leida +```http +PATCH /notifications/:id/read +Authorization: Bearer {accessToken} +``` + +### Marcar Todas como Leidas +```http +PATCH /notifications/read-all +Authorization: Bearer {accessToken} +``` + +--- + +## Auditoria + +### Listar Logs de Auditoria +```http +GET /audit-logs?page=1&pageSize=50 +Authorization: Bearer {accessToken} +``` +*Requiere rol ADMIN* + +**Parametros de consulta:** +| Parametro | Tipo | Descripcion | +|-----------|------|-------------| +| user_id | uuid | Filtrar por usuario | +| action | string | CREATE, UPDATE, DELETE, LOGIN, etc. | +| table_name | string | Filtrar por tabla | +| start_date | date | Fecha inicio | +| end_date | date | Fecha fin | + +### Mi Actividad +```http +GET /audit-logs/my-activity +Authorization: Bearer {accessToken} +``` + +--- + +## Webhooks TTS (The Things Stack) + +### Health Check +```http +GET /webhooks/tts/health +``` + +### Uplink (Datos de Dispositivos) +```http +POST /webhooks/tts/uplink +X-Downlink-Apikey: {webhook_secret} +Content-Type: application/json + +{ + "end_device_ids": { + "device_id": "device-001", + "dev_eui": "0004A30B001C1234" + }, + "uplink_message": { + "decoded_payload": { + "reading": 1234.56, + "battery": 85 + } + } +} +``` + +### Join Accept +```http +POST /webhooks/tts/join +X-Downlink-Apikey: {webhook_secret} +``` + +--- + +## Codigos de Respuesta + +| Codigo | Descripcion | +|--------|-------------| +| 200 | Exito | +| 201 | Creado exitosamente | +| 400 | Error en la solicitud | +| 401 | No autorizado | +| 403 | Prohibido (sin permisos) | +| 404 | No encontrado | +| 409 | Conflicto (duplicado) | +| 500 | Error interno del servidor | + +## Formato de Error + +```json +{ + "success": false, + "message": "Descripcion del error", + "error": "CODIGO_ERROR" +} +``` diff --git a/docs/ARQUITECTURA.md b/docs/ARQUITECTURA.md new file mode 100644 index 0000000..5f93631 --- /dev/null +++ b/docs/ARQUITECTURA.md @@ -0,0 +1,496 @@ +# Arquitectura y Base de Datos + +## Arquitectura General + +### Diagrama de Componentes + +``` +┌─────────────────────────────────────────────────────────────────────────┐ +│ CLIENTES │ +├─────────────────────────────────────────────────────────────────────────┤ +│ │ +│ ┌──────────────────┐ ┌──────────────────┐ ┌──────────────────┐ │ +│ │ Navegador Web │ │ Navegador Web │ │ Dispositivos │ │ +│ │ (App Principal)│ │ (Panel Carga) │ │ LoRaWAN │ │ +│ └────────┬─────────┘ └────────┬─────────┘ └────────┬─────────┘ │ +│ │ │ │ │ +└────────────┼───────────────────────┼───────────────────────┼────────────┘ + │ │ │ + ▼ ▼ ▼ +┌─────────────────────────────────────────────────────────────────────────┐ +│ CAPA DE PRESENTACION │ +├─────────────────────────────────────────────────────────────────────────┤ +│ │ +│ ┌──────────────────────────────────────────────────────────────────┐ │ +│ │ NGINX (Reverse Proxy) │ │ +│ │ - SSL/TLS Termination │ │ +│ │ - Load Balancing │ │ +│ │ - Static File Serving │ │ +│ └──────────────────────────────────────────────────────────────────┘ │ +│ │ +│ ┌────────────────────┐ ┌────────────────────┐ │ +│ │ Frontend React │ │ Upload Panel │ │ +│ │ (sistema.grh.com) │ │ (panel.grh.com) │ │ +│ │ Puerto: 5173 │ │ Puerto: 5174 │ │ +│ └────────────────────┘ └────────────────────┘ │ +│ │ +└─────────────────────────────────────────────────────────────────────────┘ + │ + ▼ +┌─────────────────────────────────────────────────────────────────────────┐ +│ CAPA DE SERVICIOS │ +├─────────────────────────────────────────────────────────────────────────┤ +│ │ +│ ┌──────────────────────────────────────────────────────────────────┐ │ +│ │ Express.js API Server │ │ +│ │ (api.grh.com - Puerto 3000) │ │ +│ ├──────────────────────────────────────────────────────────────────┤ │ +│ │ │ │ +│ │ ┌─────────────┐ ┌─────────────┐ ┌─────────────┐ │ │ +│ │ │ Routes │ │ Controllers │ │ Services │ │ │ +│ │ │ │ │ │ │ │ │ │ +│ │ │ - auth │ │ - auth │ │ - auth │ │ │ +│ │ │ - projects │ │ - project │ │ - project │ │ │ +│ │ │ - meters │ │ - meter │ │ - meter │ │ │ +│ │ │ - readings │ │ - reading │ │ - reading │ │ │ +│ │ │ - users │ │ - user │ │ - user │ │ │ +│ │ │ - csv-upload│ │ - etc... │ │ - csv-upload│ │ │ +│ │ │ - webhooks │ │ │ │ - tts │ │ │ +│ │ └─────────────┘ └─────────────┘ └─────────────┘ │ │ +│ │ │ │ +│ │ ┌─────────────┐ ┌─────────────┐ ┌─────────────┐ │ │ +│ │ │ Middleware │ │ Validators │ │ Jobs │ │ │ +│ │ │ │ │ │ │ │ │ │ +│ │ │ - auth │ │ - zod │ │ - cron │ │ │ +│ │ │ - audit │ │ - schemas │ │ - negative │ │ │ +│ │ │ - tts verify│ │ │ │ flow │ │ │ +│ │ └─────────────┘ └─────────────┘ └─────────────┘ │ │ +│ │ │ │ +│ └──────────────────────────────────────────────────────────────────┘ │ +│ │ +└─────────────────────────────────────────────────────────────────────────┘ + │ + ▼ +┌─────────────────────────────────────────────────────────────────────────┐ +│ CAPA DE DATOS │ +├─────────────────────────────────────────────────────────────────────────┤ +│ │ +│ ┌──────────────────────────────────────────────────────────────────┐ │ +│ │ PostgreSQL Database │ │ +│ │ Puerto: 5432 │ │ +│ ├──────────────────────────────────────────────────────────────────┤ │ +│ │ │ │ +│ │ ┌─────────────┐ ┌─────────────┐ ┌─────────────┐ │ │ +│ │ │ users │ │ projects │ │concentrators│ │ │ +│ │ │ roles │ │ gateways │ │ meters │ │ │ +│ │ └─────────────┘ └─────────────┘ └─────────────┘ │ │ +│ │ │ │ +│ │ ┌─────────────┐ ┌─────────────┐ ┌─────────────┐ │ │ +│ │ │ readings │ │ devices │ │ audit_logs │ │ │ +│ │ │ (meter_ │ │ tts_uplink │ │notifications│ │ │ +│ │ │ readings) │ │ _logs │ │ │ │ │ +│ │ └─────────────┘ └─────────────┘ └─────────────┘ │ │ +│ │ │ │ +│ └──────────────────────────────────────────────────────────────────┘ │ +│ │ +└─────────────────────────────────────────────────────────────────────────┘ + │ + ▼ +┌─────────────────────────────────────────────────────────────────────────┐ +│ SERVICIOS EXTERNOS │ +├─────────────────────────────────────────────────────────────────────────┤ +│ │ +│ ┌──────────────────────────────────────────────────────────────────┐ │ +│ │ The Things Stack (TTS) │ │ +│ │ Plataforma LoRaWAN │ │ +│ ├──────────────────────────────────────────────────────────────────┤ │ +│ │ - Recepcion de uplinks de dispositivos │ │ +│ │ - Gestion de dispositivos LoRaWAN │ │ +│ │ - Webhooks hacia la API │ │ +│ └──────────────────────────────────────────────────────────────────┘ │ +│ │ +└─────────────────────────────────────────────────────────────────────────┘ +``` + +--- + +## Modelo de Datos + +### Diagrama Entidad-Relacion + +``` +┌─────────────┐ ┌─────────────────┐ ┌─────────────────┐ +│ roles │ │ users │ │ projects │ +├─────────────┤ ├─────────────────┤ ├─────────────────┤ +│ id (PK) │──┐ │ id (PK) │ ┌──│ id (PK) │ +│ name │ └───▶│ role_id (FK) │ │ │ name │ +│ description │ │ project_id (FK) │◀───┤ │ description │ +│ permissions │ │ email │ │ │ area_name │ +└─────────────┘ │ password_hash │ │ │ status │ + │ name │ │ │ created_by (FK) │──▶ users + │ is_active │ │ │ meter_type_id │──▶ meter_types + └─────────────────┘ │ └─────────────────┘ + │ │ + │ │ + ┌─────────────────┐ │ │ + │ concentrators │◀───┘ │ + ├─────────────────┤ │ + │ id (PK) │ │ + │ serial_number │ │ + │ name │ │ + │ project_id (FK) │◀───────────────┘ + │ status │ + │ ip_address │ + └─────────────────┘ + │ + │ + ┌────────┴────────┐ + ▼ ▼ + ┌─────────────────┐ ┌─────────────────┐ + │ gateways │ │ meters │ + ├─────────────────┤ ├─────────────────┤ + │ id (PK) │ │ id (PK) │ + │ gateway_id │ │ serial_number │ + │ name │ │ name │ + │ project_id (FK) │ │ project_id (FK) │ + │ concentrator_id │ │ concentrator_id │ + │ status │ │ device_id (FK) │──▶ devices + └─────────────────┘ │ type │ + │ │ status │ + │ │ last_reading │ + ▼ └─────────────────┘ + ┌─────────────────┐ │ + │ devices │ │ + ├─────────────────┤ ▼ + │ id (PK) │ ┌─────────────────┐ + │ dev_eui │ │ meter_readings │ + │ name │ ├─────────────────┤ + │ project_id (FK) │ │ id (PK) │ + │ gateway_id (FK) │ │ meter_id (FK) │ + │ status │ │ reading_value │ + └─────────────────┘ │ reading_type │ + │ │ battery_level │ + │ │ signal_strength │ + ▼ │ received_at │ + ┌─────────────────┐ └─────────────────┘ + │ tts_uplink_logs │ + ├─────────────────┤ + │ id (PK) │ + │ device_id (FK) │ + │ raw_payload │ + │ decoded_payload │ + │ processed │ + └─────────────────┘ + + + ┌─────────────────┐ ┌─────────────────┐ ┌─────────────────┐ + │ audit_logs │ │ notifications │ │ meter_types │ + ├─────────────────┤ ├─────────────────┤ ├─────────────────┤ + │ id (PK) │ │ id (PK) │ │ id (PK) │ + │ user_id (FK) │ │ user_id (FK) │ │ name │ + │ action │ │ meter_id (FK) │ │ code │ + │ table_name │ │ type │ │ description │ + │ record_id │ │ title │ │ is_active │ + │ old_values │ │ message │ └─────────────────┘ + │ new_values │ │ is_read │ + └─────────────────┘ └─────────────────┘ +``` + +--- + +## Descripcion de Tablas + +### Tablas de Autenticacion y Usuarios + +#### `roles` +| Campo | Tipo | Descripcion | +|-------|------|-------------| +| id | UUID | Identificador unico | +| name | ENUM | ADMIN, OPERATOR, VIEWER | +| description | TEXT | Descripcion del rol | +| permissions | JSONB | Permisos detallados | + +#### `users` +| Campo | Tipo | Descripcion | +|-------|------|-------------| +| id | UUID | Identificador unico | +| email | VARCHAR | Email unico (login) | +| password_hash | VARCHAR | Hash bcrypt de contraseña | +| name | VARCHAR | Nombre completo | +| role_id | UUID FK | Rol asignado | +| project_id | UUID FK | Proyecto asignado (OPERATOR) | +| is_active | BOOLEAN | Estado de la cuenta | +| last_login | TIMESTAMP | Ultimo acceso | + +#### `refresh_tokens` +| Campo | Tipo | Descripcion | +|-------|------|-------------| +| id | UUID | Identificador unico | +| user_id | UUID FK | Usuario propietario | +| token_hash | VARCHAR | Hash del token | +| expires_at | TIMESTAMP | Fecha de expiracion | +| revoked_at | TIMESTAMP | Fecha de revocacion | + +--- + +### Tablas de Estructura + +#### `projects` +| Campo | Tipo | Descripcion | +|-------|------|-------------| +| id | UUID | Identificador unico | +| name | VARCHAR | Nombre del proyecto | +| description | TEXT | Descripcion | +| area_name | VARCHAR | Nombre del area | +| location | TEXT | Ubicacion | +| status | ENUM | ACTIVE, INACTIVE, COMPLETED | +| meter_type_id | UUID FK | Tipo de medidor por defecto | +| created_by | UUID FK | Usuario creador | + +#### `concentrators` +| Campo | Tipo | Descripcion | +|-------|------|-------------| +| id | UUID | Identificador unico | +| serial_number | VARCHAR | Numero de serie unico | +| name | VARCHAR | Nombre descriptivo | +| project_id | UUID FK | Proyecto asociado | +| location | TEXT | Ubicacion fisica | +| status | ENUM | Estado del concentrador | +| ip_address | VARCHAR | Direccion IP | +| firmware_version | VARCHAR | Version de firmware | +| last_communication | TIMESTAMP | Ultima comunicacion | + +#### `gateways` +| Campo | Tipo | Descripcion | +|-------|------|-------------| +| id | UUID | Identificador unico | +| gateway_id | VARCHAR | ID unico del gateway | +| name | VARCHAR | Nombre descriptivo | +| project_id | UUID FK | Proyecto asociado | +| concentrator_id | UUID FK | Concentrador asociado | +| location | TEXT | Ubicacion | +| status | ENUM | Estado | +| tts_gateway_id | VARCHAR | ID en The Things Stack | + +--- + +### Tablas de Medicion + +#### `meters` +| Campo | Tipo | Descripcion | +|-------|------|-------------| +| id | UUID | Identificador unico | +| serial_number | VARCHAR | Numero de serie unico | +| name | VARCHAR | Nombre descriptivo | +| project_id | UUID FK | Proyecto asociado | +| concentrator_id | UUID FK | Concentrador asociado | +| device_id | UUID FK | Dispositivo LoRaWAN asociado | +| area_name | VARCHAR | Nombre del area | +| location | TEXT | Ubicacion especifica | +| type | VARCHAR | LORA, LORAWAN, GRANDES CONSUMIDORES | +| status | ENUM | ACTIVE, INACTIVE, OFFLINE, MAINTENANCE, ERROR | +| last_reading_value | NUMERIC | Ultima lectura registrada | +| last_reading_at | TIMESTAMP | Fecha de ultima lectura | +| installation_date | DATE | Fecha de instalacion | + +**Campos extendidos:** +| Campo | Tipo | Descripcion | +|-------|------|-------------| +| protocol | VARCHAR | Protocolo de comunicacion | +| mac | VARCHAR | Direccion MAC | +| voltage | DECIMAL | Voltaje | +| signal | INTEGER | Intensidad de senal | +| leakage_status | VARCHAR | Estado de fuga | +| burst_status | VARCHAR | Estado de ruptura | +| current_flow | DECIMAL | Flujo actual | +| latitude | DECIMAL | Latitud GPS | +| longitude | DECIMAL | Longitud GPS | +| data | JSONB | Datos adicionales flexibles | + +#### `meter_readings` +| Campo | Tipo | Descripcion | +|-------|------|-------------| +| id | UUID | Identificador unico | +| meter_id | UUID FK | Medidor asociado | +| device_id | UUID FK | Dispositivo origen | +| reading_value | NUMERIC | Valor de la lectura | +| reading_type | ENUM | AUTOMATIC, MANUAL, SCHEDULED | +| battery_level | SMALLINT | Nivel de bateria (0-100) | +| signal_strength | SMALLINT | Intensidad de senal (dBm) | +| raw_payload | TEXT | Payload crudo del dispositivo | +| received_at | TIMESTAMP | Fecha/hora de recepcion | + +#### `meter_types` +| Campo | Tipo | Descripcion | +|-------|------|-------------| +| id | UUID | Identificador unico | +| name | VARCHAR | Nombre del tipo | +| code | VARCHAR | Codigo unico | +| description | TEXT | Descripcion | +| is_active | BOOLEAN | Estado activo | + +--- + +### Tablas de IoT (The Things Stack) + +#### `devices` +| Campo | Tipo | Descripcion | +|-------|------|-------------| +| id | UUID | Identificador unico | +| dev_eui | VARCHAR | DevEUI unico del dispositivo | +| name | VARCHAR | Nombre descriptivo | +| device_type | VARCHAR | Tipo de dispositivo | +| project_id | UUID FK | Proyecto asociado | +| gateway_id | UUID FK | Gateway asociado | +| status | ENUM | Estado del dispositivo | +| tts_device_id | VARCHAR | ID en TTS | +| tts_status | VARCHAR | Estado en TTS | +| app_key | VARCHAR | Application Key | +| join_eui | VARCHAR | Join EUI | + +#### `tts_uplink_logs` +| Campo | Tipo | Descripcion | +|-------|------|-------------| +| id | UUID | Identificador unico | +| device_id | UUID FK | Dispositivo origen | +| dev_eui | VARCHAR | DevEUI | +| raw_payload | JSONB | Payload completo | +| decoded_payload | JSONB | Payload decodificado | +| gateway_ids | TEXT[] | IDs de gateways | +| rssi | INTEGER | RSSI | +| snr | FLOAT | SNR | +| processed | BOOLEAN | Indica si fue procesado | +| error_message | TEXT | Mensaje de error si aplica | + +--- + +### Tablas de Sistema + +#### `audit_logs` +| Campo | Tipo | Descripcion | +|-------|------|-------------| +| id | UUID | Identificador unico | +| user_id | UUID FK | Usuario que realizo la accion | +| user_email | VARCHAR | Email del usuario | +| user_name | VARCHAR | Nombre del usuario | +| action | ENUM | CREATE, UPDATE, DELETE, LOGIN, etc. | +| table_name | VARCHAR | Tabla afectada | +| record_id | UUID | ID del registro afectado | +| old_values | JSONB | Valores anteriores | +| new_values | JSONB | Valores nuevos | +| description | TEXT | Descripcion de la accion | +| ip_address | VARCHAR | IP del cliente | +| user_agent | TEXT | User Agent del navegador | +| success | BOOLEAN | Resultado de la operacion | +| error_message | TEXT | Mensaje de error si fallo | + +#### `notifications` +| Campo | Tipo | Descripcion | +|-------|------|-------------| +| id | UUID | Identificador unico | +| user_id | UUID FK | Usuario destinatario | +| meter_id | UUID FK | Medidor relacionado (opcional) | +| notification_type | ENUM | NEGATIVE_FLOW, SYSTEM_ALERT, MAINTENANCE | +| title | VARCHAR | Titulo de la notificacion | +| message | TEXT | Mensaje detallado | +| meter_serial_number | VARCHAR | Serial del medidor (si aplica) | +| flow_value | DECIMAL | Valor de flujo (si aplica) | +| is_read | BOOLEAN | Estado de lectura | +| read_at | TIMESTAMP | Fecha de lectura | + +--- + +## Indices + +### Indices Principales + +```sql +-- Meters +CREATE INDEX idx_meters_serial_number ON meters(serial_number); +CREATE INDEX idx_meters_project_id ON meters(project_id); +CREATE INDEX idx_meters_concentrator_id ON meters(concentrator_id); +CREATE INDEX idx_meters_status ON meters(status); +CREATE INDEX idx_meters_type ON meters(type); + +-- Readings +CREATE INDEX idx_meter_readings_meter_id ON meter_readings(meter_id); +CREATE INDEX idx_meter_readings_received_at ON meter_readings(received_at); +CREATE INDEX idx_meter_readings_meter_id_received_at ON meter_readings(meter_id, received_at); + +-- Devices +CREATE INDEX idx_devices_dev_eui ON devices(dev_eui); +CREATE INDEX idx_devices_project_id ON devices(project_id); + +-- Audit +CREATE INDEX idx_audit_logs_user_id ON audit_logs(user_id); +CREATE INDEX idx_audit_logs_created_at ON audit_logs(created_at); +CREATE INDEX idx_audit_logs_table_name ON audit_logs(table_name); + +-- Notifications +CREATE INDEX idx_notifications_user_id ON notifications(user_id); +CREATE INDEX idx_notifications_is_read ON notifications(is_read); +``` + +--- + +## Flujo de Datos + +### Flujo de Lectura Automatica (TTS) + +``` +1. Dispositivo LoRaWAN envia uplink + │ + ▼ +2. The Things Stack recibe el mensaje + │ + ▼ +3. TTS envia webhook a /api/webhooks/tts/uplink + │ + ▼ +4. API verifica firma del webhook (X-Downlink-Apikey) + │ + ▼ +5. API guarda en tts_uplink_logs + │ + ▼ +6. API busca device por dev_eui + │ + ▼ +7. API busca meter asociado al device + │ + ▼ +8. API crea registro en meter_readings + │ + ▼ +9. API actualiza last_reading en meters + │ + ▼ +10. Job de deteccion de flujo negativo evalua la lectura + │ + ▼ +11. Si detecta anomalia, crea notification +``` + +### Flujo de Carga CSV + +``` +1. Usuario sube archivo CSV + │ + ▼ +2. API parsea el CSV + │ + ▼ +3. Por cada fila: + │ + ├─▶ Validar campos requeridos + │ + ├─▶ Buscar concentrador por serial + │ + ├─▶ Si meter existe: UPDATE + │ Si no existe: INSERT + │ + └─▶ Registrar resultado (exito/error) + │ + ▼ +4. Retornar resumen de procesamiento +``` diff --git a/docs/INSTALACION.md b/docs/INSTALACION.md new file mode 100644 index 0000000..5fc52ac --- /dev/null +++ b/docs/INSTALACION.md @@ -0,0 +1,390 @@ +# Guia de Instalacion + +## Requisitos Previos + +### Software Requerido +- **Node.js** 18.x o superior +- **npm** 9.x o superior +- **PostgreSQL** 14.x o superior +- **Git** + +### Puertos Utilizados +| Servicio | Puerto | +|----------|--------| +| Frontend Principal | 5173 | +| Panel de Carga CSV | 5174 | +| Backend API | 3000 | +| PostgreSQL | 5432 | + +--- + +## Instalacion del Backend (water-api) + +### 1. Clonar el Repositorio +```bash +git clone https://git.consultoria-as.com/consultoria-as/water-project.git +cd water-project +``` + +### 2. Configurar la Base de Datos + +#### Crear la base de datos: +```bash +sudo -u postgres psql +``` + +```sql +CREATE DATABASE water_project; +CREATE USER water_user WITH PASSWORD 'tu_password_seguro'; +GRANT ALL PRIVILEGES ON DATABASE water_project TO water_user; +\q +``` + +#### Ejecutar los scripts SQL: +```bash +cd water-api/sql +psql -U water_user -d water_project -f schema.sql +psql -U water_user -d water_project -f add_audit_logs.sql +psql -U water_user -d water_project -f add_notifications.sql +psql -U water_user -d water_project -f add_meter_extended_fields.sql +psql -U water_user -d water_project -f add_meter_project_relation.sql +psql -U water_user -d water_project -f add_meter_types.sql +``` + +### 3. Configurar Variables de Entorno + +```bash +cd water-api +cp .env.example .env +``` + +Editar `.env`: +```env +# Server +PORT=3000 +NODE_ENV=production + +# Database +DB_HOST=localhost +DB_PORT=5432 +DB_NAME=water_project +DB_USER=water_user +DB_PASSWORD=tu_password_seguro + +# JWT (generar claves seguras) +JWT_ACCESS_SECRET=clave_secreta_acceso_minimo_32_caracteres +JWT_REFRESH_SECRET=clave_secreta_refresh_minimo_32_caracteres +JWT_ACCESS_EXPIRES_IN=15m +JWT_REFRESH_EXPIRES_IN=7d + +# CORS (URLs del frontend separadas por coma) +CORS_ORIGIN=http://localhost:5173,http://localhost:5174,https://sistema.gestionrecursoshidricos.com,https://panel.gestionrecursoshidricos.com + +# TTS (The Things Stack) - Opcional +TTS_ENABLED=false +TTS_BASE_URL=https://your-tts-server.com +TTS_APPLICATION_ID=your-app-id +TTS_API_KEY=your-api-key +TTS_WEBHOOK_SECRET=your-webhook-secret +``` + +### 4. Instalar Dependencias y Ejecutar + +```bash +npm install +npm run dev # Desarrollo con hot-reload +# o +npm run build # Compilar para produccion +npm start # Ejecutar version compilada +``` + +### 5. Verificar Instalacion +```bash +curl http://localhost:3000/health +``` + +Respuesta esperada: +```json +{ + "status": "ok", + "timestamp": "2024-01-20T10:30:00.000Z", + "environment": "production" +} +``` + +--- + +## Instalacion del Frontend Principal + +### 1. Configurar Variables de Entorno + +```bash +cd /path/to/water-project +cp .env.example .env +``` + +Editar `.env`: +```env +VITE_API_BASE_URL=http://localhost:3000 +``` + +Para produccion: +```env +VITE_API_BASE_URL=https://api.gestionrecursoshidricos.com +``` + +### 2. Instalar Dependencias y Ejecutar + +```bash +npm install +npm run dev # Desarrollo +# o +npm run build # Compilar para produccion +npm run preview # Vista previa de produccion +``` + +### 3. Verificar Instalacion +Abrir en el navegador: http://localhost:5173 + +--- + +## Instalacion del Panel de Carga CSV + +### 1. Configurar Variables de Entorno + +```bash +cd upload-panel +cp .env.example .env # Si existe, o crear manualmente +``` + +Crear `.env`: +```env +VITE_API_URL=http://localhost:3000/api +``` + +Para produccion: +```env +VITE_API_URL=https://api.gestionrecursoshidricos.com/api +``` + +### 2. Instalar Dependencias y Ejecutar + +```bash +npm install +npm run dev # Desarrollo (puerto 5174) +# o +npm run build # Compilar para produccion +``` + +### 3. Verificar Instalacion +Abrir en el navegador: http://localhost:5174 + +--- + +## Despliegue en Produccion + +### Opcion 1: PM2 (Recomendado) + +#### Instalar PM2: +```bash +npm install -g pm2 +``` + +#### Configurar ecosystem.config.js: +```javascript +module.exports = { + apps: [ + { + name: 'water-api', + cwd: '/path/to/water-project/water-api', + script: 'npm', + args: 'start', + env: { + NODE_ENV: 'production', + PORT: 3000 + } + } + ] +}; +``` + +#### Iniciar con PM2: +```bash +pm2 start ecosystem.config.js +pm2 save +pm2 startup # Configurar inicio automatico +``` + +### Opcion 2: Systemd Service + +Crear `/etc/systemd/system/water-api.service`: +```ini +[Unit] +Description=Water API Server +After=network.target postgresql.service + +[Service] +Type=simple +User=www-data +WorkingDirectory=/path/to/water-project/water-api +ExecStart=/usr/bin/node dist/index.js +Restart=on-failure +Environment=NODE_ENV=production + +[Install] +WantedBy=multi-user.target +``` + +```bash +sudo systemctl enable water-api +sudo systemctl start water-api +``` + +### Configurar Nginx (Reverse Proxy) + +```nginx +# /etc/nginx/sites-available/water-project + +# API +server { + listen 443 ssl; + server_name api.gestionrecursoshidricos.com; + + ssl_certificate /path/to/cert.pem; + ssl_certificate_key /path/to/key.pem; + + location / { + proxy_pass http://localhost:3000; + proxy_http_version 1.1; + proxy_set_header Upgrade $http_upgrade; + proxy_set_header Connection 'upgrade'; + proxy_set_header Host $host; + proxy_set_header X-Real-IP $remote_addr; + proxy_cache_bypass $http_upgrade; + } +} + +# Frontend Principal +server { + listen 443 ssl; + server_name sistema.gestionrecursoshidricos.com; + + ssl_certificate /path/to/cert.pem; + ssl_certificate_key /path/to/key.pem; + + root /path/to/water-project/dist; + index index.html; + + location / { + try_files $uri $uri/ /index.html; + } +} + +# Panel de Carga +server { + listen 443 ssl; + server_name panel.gestionrecursoshidricos.com; + + ssl_certificate /path/to/cert.pem; + ssl_certificate_key /path/to/key.pem; + + root /path/to/water-project/upload-panel/dist; + index index.html; + + location / { + try_files $uri $uri/ /index.html; + } +} +``` + +--- + +## Crear Usuario Administrador Inicial + +### Via SQL: +```sql +-- Primero obtener el ID del rol ADMIN +SELECT id FROM roles WHERE name = 'ADMIN'; + +-- Crear usuario (password debe ser hash bcrypt) +-- Puedes usar: https://bcrypt-generator.com/ para generar el hash +INSERT INTO users (email, password_hash, name, role_id, is_active) +VALUES ( + 'admin@ejemplo.com', + '$2b$10$xxxxx...', -- Hash bcrypt de la contraseña + 'Administrador', + 'uuid-del-rol-admin', + true +); +``` + +### Via API (si ya tienes un admin): +```bash +curl -X POST http://localhost:3000/api/users \ + -H "Authorization: Bearer {token}" \ + -H "Content-Type: application/json" \ + -d '{ + "email": "nuevo@ejemplo.com", + "password": "password123", + "name": "Nuevo Admin", + "role_id": "uuid-rol-admin" + }' +``` + +--- + +## Configuracion de The Things Stack (TTS) + +### 1. Configurar Variables de Entorno + +```env +TTS_ENABLED=true +TTS_BASE_URL=https://tu-servidor-tts.com +TTS_APPLICATION_ID=tu-aplicacion +TTS_API_KEY=tu-api-key +TTS_WEBHOOK_SECRET=tu-webhook-secret +``` + +### 2. Configurar Webhook en TTS + +En la consola de TTS, configurar webhook apuntando a: +- **URL Base**: `https://api.gestionrecursoshidricos.com/api/webhooks/tts` +- **Eventos**: + - Uplink: `/uplink` + - Join: `/join` + - Downlink ACK: `/downlink/ack` + +### 3. Configurar Header de Autenticacion +- **Header**: `X-Downlink-Apikey` +- **Valor**: El mismo que `TTS_WEBHOOK_SECRET` + +--- + +## Solucion de Problemas + +### Error de conexion a la base de datos +``` +Error: connect ECONNREFUSED 127.0.0.1:5432 +``` +- Verificar que PostgreSQL esta corriendo: `sudo systemctl status postgresql` +- Verificar credenciales en `.env` + +### Error CORS +``` +Access-Control-Allow-Origin +``` +- Verificar que la URL del frontend esta en `CORS_ORIGIN` + +### Puerto en uso +``` +Error: listen EADDRINUSE :::3000 +``` +- Verificar si hay otro proceso: `lsof -i :3000` +- Terminar proceso: `kill -9 ` + +### Permisos de archivo +``` +EACCES: permission denied +``` +- Verificar permisos del directorio +- Ejecutar: `chown -R $USER:$USER /path/to/water-project` diff --git a/docs/MANUAL_USUARIO.md b/docs/MANUAL_USUARIO.md new file mode 100644 index 0000000..6c43c6e --- /dev/null +++ b/docs/MANUAL_USUARIO.md @@ -0,0 +1,358 @@ +# Manual de Usuario - Sistema GRH + +## Indice + +1. [Acceso al Sistema](#acceso-al-sistema) +2. [Dashboard Principal](#dashboard-principal) +3. [Gestion de Proyectos](#gestion-de-proyectos) +4. [Gestion de Concentradores](#gestion-de-concentradores) +5. [Gestion de Medidores](#gestion-de-medidores) +6. [Consumo y Lecturas](#consumo-y-lecturas) +7. [Panel de Carga CSV](#panel-de-carga-csv) +8. [Notificaciones](#notificaciones) +9. [Administracion de Usuarios](#administracion-de-usuarios) +10. [Auditoria](#auditoria) + +--- + +## Acceso al Sistema + +### URL de Acceso +- **Sistema Principal**: https://sistema.gestionrecursoshidricos.com +- **Panel de Carga CSV**: https://panel.gestionrecursoshidricos.com + +### Inicio de Sesion + +1. Ingrese a la URL del sistema +2. Introduzca su correo electronico +3. Introduzca su contraseña +4. Haga clic en "Iniciar Sesion" + +### Roles de Usuario + +| Rol | Permisos | +|-----|----------| +| **ADMIN** | Acceso completo a todas las funciones | +| **OPERATOR** | Gestion de medidores y lecturas de su proyecto asignado | +| **VIEWER** | Solo visualizacion de datos | + +--- + +## Dashboard Principal + +El dashboard muestra un resumen general del sistema: + +### Indicadores Clave (KPIs) +- **Total de Medidores**: Cantidad total de medidores registrados +- **Lecturas del Dia**: Numero de lecturas recibidas hoy +- **Alertas Activas**: Notificaciones pendientes de atencion +- **Proyectos Activos**: Proyectos en estado activo + +### Alertas Recientes +Lista de las ultimas alertas del sistema, incluyendo: +- Flujo negativo detectado +- Medidores sin comunicacion +- Alertas de mantenimiento + +### Actividad Reciente +Historial de las ultimas acciones realizadas en el sistema. + +--- + +## Gestion de Proyectos + +### Ver Proyectos +1. Navegue a **Proyectos** en el menu lateral +2. Vera la lista de todos los proyectos +3. Use los filtros para buscar proyectos especificos + +### Crear Proyecto +1. Haga clic en **"Nuevo Proyecto"** +2. Complete los campos: + - **Nombre**: Nombre del proyecto (requerido) + - **Descripcion**: Descripcion detallada + - **Area**: Nombre del area geografica + - **Ubicacion**: Direccion o coordenadas + - **Tipo de Medidor**: Tipo por defecto para el proyecto +3. Haga clic en **"Guardar"** + +### Editar Proyecto +1. Haga clic en el icono de edicion del proyecto +2. Modifique los campos necesarios +3. Haga clic en **"Guardar"** + +### Estadisticas del Proyecto +- Haga clic en un proyecto para ver sus estadisticas +- Incluye: total de medidores, lecturas, consumo promedio + +--- + +## Gestion de Concentradores + +Los concentradores son dispositivos que agrupan multiples medidores. + +### Ver Concentradores +1. Navegue a **Concentradores** en el menu lateral +2. Filtre por proyecto si es necesario + +### Crear Concentrador +1. Haga clic en **"Nuevo Concentrador"** +2. Complete los campos: + - **Serial**: Numero de serie unico (requerido) + - **Nombre**: Nombre descriptivo (requerido) + - **Proyecto**: Proyecto al que pertenece (requerido) + - **Ubicacion**: Ubicacion fisica + - **IP**: Direccion IP (opcional) +3. Haga clic en **"Guardar"** + +### Estados del Concentrador +| Estado | Descripcion | +|--------|-------------| +| ACTIVE | Funcionando correctamente | +| INACTIVE | Desactivado manualmente | +| OFFLINE | Sin comunicacion | +| MAINTENANCE | En mantenimiento | +| ERROR | Con fallas | + +--- + +## Gestion de Medidores + +### Ver Medidores +1. Navegue a **Medidores** en el menu lateral +2. Use los filtros disponibles: + - Por proyecto + - Por concentrador + - Por estado + - Por tipo + - Busqueda por serial/nombre + +### Crear Medidor Individual +1. Haga clic en **"Nuevo Medidor"** +2. Complete los campos: + - **Serial**: Numero de serie unico (requerido) + - **Nombre**: Nombre descriptivo (requerido) + - **Concentrador**: Concentrador asociado (requerido) + - **Area**: Nombre del area + - **Ubicacion**: Ubicacion especifica (ej: "Depto 101") + - **Tipo**: LORA, LORAWAN, o GRANDES CONSUMIDORES + - **Estado**: Estado inicial + - **Fecha Instalacion**: Fecha de instalacion +3. Haga clic en **"Guardar"** + +### Carga Masiva de Medidores (Excel) +1. Haga clic en **"Carga Masiva"** +2. Descargue la plantilla Excel +3. Complete la plantilla con los datos +4. Suba el archivo Excel +5. Revise los resultados + +### Tipos de Medidor +| Tipo | Descripcion | +|------|-------------| +| LORA | Medidores con comunicacion LoRa | +| LORAWAN | Medidores LoRaWAN | +| GRANDES CONSUMIDORES | Medidores de alto consumo | + +### Ver Detalle del Medidor +- Haga clic en un medidor para ver: + - Informacion general + - Ultima lectura + - Historial de lecturas + - Graficos de consumo + +--- + +## Consumo y Lecturas + +### Ver Lecturas +1. Navegue a **Consumo** en el menu lateral +2. Filtre por: + - Proyecto + - Concentrador + - Medidor especifico + - Rango de fechas + - Tipo de lectura + +### Tipos de Lectura +| Tipo | Descripcion | +|------|-------------| +| AUTOMATIC | Lectura automatica del dispositivo | +| MANUAL | Lectura ingresada manualmente | +| SCHEDULED | Lectura programada | + +### Crear Lectura Manual +1. Haga clic en **"Nueva Lectura"** +2. Seleccione el medidor +3. Ingrese el valor de lectura +4. Opcionalmente ingrese: + - Nivel de bateria (0-100) + - Intensidad de senal (dBm) +5. Haga clic en **"Guardar"** + +### Carga Masiva de Lecturas (Excel) +1. Haga clic en **"Carga Masiva"** +2. Descargue la plantilla +3. Complete con los datos +4. Suba el archivo +5. Revise los resultados + +### Graficos de Consumo +- Visualice el consumo historico en graficos +- Filtre por periodo de tiempo +- Exporte datos si es necesario + +--- + +## Panel de Carga CSV + +El panel de carga CSV permite subir datos de medidores y lecturas sin necesidad de autenticacion. + +### Acceso +- URL: https://panel.gestionrecursoshidricos.com + +### Cargar Medidores + +1. En la seccion **"Tomas de Agua"** +2. Descargue la plantilla CSV haciendo clic en "Descargar plantilla CSV" +3. Complete el archivo con los datos: + +```csv +serial_number,name,concentrator_serial,area_name,location,meter_type,status,installation_date +MED001,Medidor 1,Mexico-GRH,ZONA A,Depto 101,LORA,ACTIVE,2024-01-15 +MED002,Medidor 2,Mexico-GRH,ZONA A,Depto 102,LORA,ACTIVE,2024-01-15 +``` + +**Campos:** +| Campo | Requerido | Descripcion | +|-------|-----------|-------------| +| serial_number | Si | Numero de serie unico del medidor | +| name | Si | Nombre descriptivo | +| concentrator_serial | Si | Serial del concentrador existente | +| area_name | No | Nombre del area | +| location | No | Ubicacion especifica | +| meter_type | No | LORA (default), LORAWAN, GRANDES CONSUMIDORES | +| status | No | ACTIVE (default), INACTIVE, MAINTENANCE | +| installation_date | No | Fecha YYYY-MM-DD | + +4. Arrastre el archivo o haga clic para seleccionarlo +5. Haga clic en **"Subir Archivo"** +6. Revise los resultados: + - Registros insertados (nuevos) + - Registros actualizados (existentes) + - Errores encontrados + +**Logica de Upsert:** +- Si el `serial_number` ya existe: se **actualiza** el medidor +- Si el `serial_number` no existe: se **crea** un nuevo medidor + +### Cargar Lecturas + +1. En la seccion **"Lecturas"** +2. Descargue la plantilla CSV +3. Complete el archivo: + +```csv +meter_serial,reading_value,received_at,reading_type,battery_level,signal_strength +MED001,1234.56,2024-01-20 10:30:00,MANUAL,85,-45 +MED002,567.89,2024-01-20 10:35:00,MANUAL,90,-42 +``` + +**Campos:** +| Campo | Requerido | Descripcion | +|-------|-----------|-------------| +| meter_serial | Si | Serial del medidor existente | +| reading_value | Si | Valor numerico de la lectura | +| received_at | No | Fecha/hora (default: ahora) | +| reading_type | No | AUTOMATIC, MANUAL, SCHEDULED | +| battery_level | No | Nivel de bateria 0-100 | +| signal_strength | No | Intensidad de senal en dBm | + +4. Suba el archivo +5. Revise los resultados + +**Nota:** El medidor debe existir previamente para poder cargar lecturas. + +--- + +## Notificaciones + +### Ver Notificaciones +1. Haga clic en el icono de campana en la barra superior +2. Vera las notificaciones recientes + +### Tipos de Notificacion +| Tipo | Descripcion | +|------|-------------| +| NEGATIVE_FLOW | Flujo negativo detectado en un medidor | +| SYSTEM_ALERT | Alerta general del sistema | +| MAINTENANCE | Recordatorio de mantenimiento | + +### Gestionar Notificaciones +- **Marcar como leida**: Haga clic en la notificacion +- **Marcar todas como leidas**: Boton en la parte superior +- **Eliminar**: Icono de eliminar en cada notificacion + +--- + +## Administracion de Usuarios + +*Solo disponible para usuarios con rol ADMIN* + +### Ver Usuarios +1. Navegue a **Usuarios** en el menu lateral +2. Vera la lista de todos los usuarios + +### Crear Usuario +1. Haga clic en **"Nuevo Usuario"** +2. Complete los campos: + - **Email**: Correo electronico (sera el usuario de login) + - **Nombre**: Nombre completo + - **Contraseña**: Contraseña inicial + - **Rol**: ADMIN, OPERATOR, o VIEWER + - **Proyecto**: Solo para OPERATOR - proyecto asignado +3. Haga clic en **"Guardar"** + +### Editar Usuario +1. Haga clic en el icono de edicion +2. Modifique los campos necesarios +3. Haga clic en **"Guardar"** + +### Desactivar Usuario +1. Haga clic en el icono de desactivar +2. Confirme la accion +- El usuario no podra iniciar sesion pero sus datos se conservan + +--- + +## Auditoria + +*Solo disponible para usuarios con rol ADMIN* + +### Ver Logs de Auditoria +1. Navegue a **Auditoria** en el menu lateral +2. Vera el historial de acciones del sistema + +### Filtros Disponibles +- Por usuario +- Por accion (CREATE, UPDATE, DELETE, LOGIN, etc.) +- Por tabla/entidad +- Por rango de fechas + +### Informacion del Log +Cada registro muestra: +- Fecha y hora +- Usuario que realizo la accion +- Tipo de accion +- Entidad afectada +- Valores anteriores y nuevos (para updates) +- Direccion IP +- Resultado (exito/error) + +--- + +## Soporte + +Para soporte tecnico o reportar problemas: +- Contacte al administrador del sistema +- Revise la documentacion tecnica en `/docs` diff --git a/docs/README.md b/docs/README.md new file mode 100644 index 0000000..13c0cb3 --- /dev/null +++ b/docs/README.md @@ -0,0 +1,126 @@ +# Sistema de Gestion de Recursos Hidricos (GRH) + +## Descripcion General + +Sistema web para la gestion y monitoreo de medidores de agua, integrando dispositivos LoRaWAN a traves de The Things Stack (TTS). Permite el seguimiento de consumo, deteccion de anomalias y gestion de proyectos de medicion. + +## Arquitectura del Sistema + +``` +┌─────────────────────────────────────────────────────────────────┐ +│ FRONTEND │ +├─────────────────────────────────────────────────────────────────┤ +│ App Principal (React) │ Panel de Carga (React) │ +│ Puerto: 5173 │ Puerto: 5174 │ +│ - Dashboard │ - Carga CSV Medidores │ +│ - Gestion Medidores │ - Carga CSV Lecturas │ +│ - Gestion Proyectos │ │ +│ - Consumo/Lecturas │ │ +│ - Usuarios/Roles │ │ +│ - Auditoria │ │ +└─────────────────────────────────────────────────────────────────┘ + │ + ▼ +┌─────────────────────────────────────────────────────────────────┐ +│ BACKEND API │ +│ Puerto: 3000 │ +├─────────────────────────────────────────────────────────────────┤ +│ Express.js + TypeScript │ +│ - Autenticacion JWT │ +│ - Control de Acceso por Roles │ +│ - Webhooks TTS (LoRaWAN) │ +│ - Jobs Programados (Cron) │ +└─────────────────────────────────────────────────────────────────┘ + │ + ▼ +┌─────────────────────────────────────────────────────────────────┐ +│ BASE DE DATOS │ +│ PostgreSQL │ +├─────────────────────────────────────────────────────────────────┤ +│ - users, roles │ +│ - projects, concentrators, gateways │ +│ - meters, meter_readings, devices │ +│ - notifications, audit_logs │ +│ - tts_uplink_logs │ +└─────────────────────────────────────────────────────────────────┘ + │ + ▼ +┌─────────────────────────────────────────────────────────────────┐ +│ SERVICIOS EXTERNOS │ +├─────────────────────────────────────────────────────────────────┤ +│ The Things Stack (TTS) │ +│ - Recepcion de datos LoRaWAN │ +│ - Gestion de dispositivos IoT │ +└─────────────────────────────────────────────────────────────────┘ +``` + +## Estructura del Proyecto + +``` +water-project/ +├── src/ # Frontend principal (React + Vite) +│ ├── api/ # Clientes API +│ ├── components/ # Componentes React +│ ├── hooks/ # Custom hooks +│ ├── pages/ # Paginas de la aplicacion +│ └── types/ # Tipos TypeScript +│ +├── water-api/ # Backend API (Express + TypeScript) +│ ├── src/ +│ │ ├── config/ # Configuracion (DB, etc.) +│ │ ├── controllers/ # Controladores HTTP +│ │ ├── middleware/ # Middlewares (auth, audit) +│ │ ├── routes/ # Definicion de rutas +│ │ ├── services/ # Logica de negocio +│ │ ├── validators/ # Validacion de datos +│ │ ├── jobs/ # Tareas programadas +│ │ └── utils/ # Utilidades +│ └── sql/ # Scripts SQL +│ +├── upload-panel/ # Panel de carga CSV (React + Vite) +│ └── src/ +│ ├── api/ # Cliente API +│ └── components/ # Componentes de carga +│ +└── docs/ # Documentacion +``` + +## Tecnologias Utilizadas + +### Frontend +- **React 18** - Framework UI +- **Vite 5** - Build tool +- **TypeScript** - Tipado estatico +- **Tailwind CSS 4** - Estilos +- **Material UI** - Componentes UI +- **Recharts** - Graficos +- **Lucide React** - Iconos + +### Backend +- **Node.js** - Runtime +- **Express 4** - Framework web +- **TypeScript** - Tipado estatico +- **PostgreSQL** - Base de datos +- **JWT** - Autenticacion +- **Multer** - Upload de archivos +- **node-cron** - Tareas programadas +- **Zod** - Validacion de schemas + +### Servicios Externos +- **The Things Stack (TTS)** - Integracion LoRaWAN + +## URLs de Produccion + +| Servicio | URL | +|----------|-----| +| App Principal | https://sistema.gestionrecursoshidricos.com | +| Panel de Carga | https://panel.gestionrecursoshidricos.com | +| API | https://api.gestionrecursoshidricos.com | + +## Documentacion Detallada + +- [Manual de Usuario](./MANUAL_USUARIO.md) +- [Documentacion API](./API.md) +- [Guia de Instalacion](./INSTALACION.md) +- [Panel de Carga CSV](./UPLOAD_PANEL.md) +- [Arquitectura y Base de Datos](./ARQUITECTURA.md) diff --git a/docs/UPLOAD_PANEL.md b/docs/UPLOAD_PANEL.md new file mode 100644 index 0000000..e334ba6 --- /dev/null +++ b/docs/UPLOAD_PANEL.md @@ -0,0 +1,297 @@ +# Panel de Carga CSV + +## Descripcion + +El Panel de Carga CSV es una aplicacion web independiente que permite subir datos de medidores y lecturas mediante archivos CSV, sin necesidad de autenticacion. Esta diseñado para uso interno y facilita la carga masiva de datos. + +## Acceso + +- **URL**: https://panel.gestionrecursoshidricos.com +- **Puerto local**: 5174 +- **Autenticacion**: No requerida + +--- + +## Interfaz de Usuario + +``` +┌─────────────────────────────────────────────────────────────────┐ +│ Panel de Carga de Datos - GRH │ +│ Sistema de Gestion de Recursos Hidricos │ +├─────────────────────────────────────────────────────────────────┤ +│ │ +│ ┌─────────────────────────┐ ┌─────────────────────────┐ │ +│ │ TOMAS DE AGUA │ │ LECTURAS │ │ +│ │ (Medidores) │ │ │ │ +│ │ │ │ │ │ +│ │ Campos requeridos: │ │ Campos requeridos: │ │ +│ │ - serial_number │ │ - meter_serial │ │ +│ │ - name │ │ - reading_value │ │ +│ │ - concentrator_serial │ │ │ │ +│ │ │ │ │ │ +│ │ [Descargar plantilla] │ │ [Descargar plantilla] │ │ +│ │ │ │ │ │ +│ │ ┌───────────────────┐ │ │ ┌───────────────────┐ │ │ +│ │ │ Arrastra CSV aqui │ │ │ │ Arrastra CSV aqui │ │ │ +│ │ │ o haz clic │ │ │ │ o haz clic │ │ │ +│ │ └───────────────────┘ │ │ └───────────────────┘ │ │ +│ │ │ │ │ │ +│ │ [ SUBIR ARCHIVO ] │ │ [ SUBIR ARCHIVO ] │ │ +│ └─────────────────────────┘ └─────────────────────────┘ │ +│ │ +│ ┌───────────────────────────────────────────────────────────┐ │ +│ │ Resultado de la carga: │ │ +│ │ Total: 100 | Insertados: 95 | Actualizados: 3 | Errores: 2│ │ +│ │ │ │ +│ │ Errores: │ │ +│ │ - Fila 15: Concentrador "XXX" no encontrado │ │ +│ │ - Fila 42: Valor de lectura invalido │ │ +│ └───────────────────────────────────────────────────────────┘ │ +│ │ +└─────────────────────────────────────────────────────────────────┘ +``` + +--- + +## Carga de Medidores (Tomas de Agua) + +### Formato del CSV + +```csv +serial_number,name,concentrator_serial,area_name,location,meter_type,status,installation_date +MED001,Medidor 001,Mexico-GRH,ZONA A,Depto 101,LORA,ACTIVE,2024-01-15 +MED002,Medidor 002,Mexico-GRH,ZONA A,Depto 102,LORA,ACTIVE,2024-01-15 +MED003,Medidor 003,Mexico-GRH,ZONA B,Depto 201,LORAWAN,ACTIVE,2024-01-16 +``` + +### Campos + +| Campo | Requerido | Tipo | Descripcion | Ejemplo | +|-------|-----------|------|-------------|---------| +| serial_number | **Si** | Texto | Numero de serie unico del medidor | MED001 | +| name | **Si** | Texto | Nombre descriptivo | Medidor Depto 101 | +| concentrator_serial | **Si** | Texto | Serial del concentrador existente | Mexico-GRH | +| area_name | No | Texto | Nombre del area o zona | ZONA A | +| location | No | Texto | Ubicacion especifica | Depto 101, Piso 1 | +| meter_type | No | Texto | Tipo de medidor (default: LORA) | LORA | +| status | No | Texto | Estado inicial (default: ACTIVE) | ACTIVE | +| installation_date | No | Fecha | Fecha de instalacion (YYYY-MM-DD) | 2024-01-15 | + +### Tipos de Medidor Validos +- `LORA` (default) +- `LORAWAN` +- `GRANDES CONSUMIDORES` +- `WATER` +- `GAS` +- `ELECTRIC` + +### Estados Validos +- `ACTIVE` (default) +- `INACTIVE` +- `OFFLINE` +- `MAINTENANCE` +- `ERROR` + +### Logica de Upsert + +El sistema utiliza el campo `serial_number` como identificador unico: + +- **Si el serial_number YA EXISTE**: Se **actualiza** el medidor con los nuevos valores +- **Si el serial_number NO EXISTE**: Se **crea** un nuevo medidor + +Esto permite: +1. Agregar nuevos medidores +2. Actualizar medidores existentes +3. Hacer ambas operaciones en un solo archivo + +### Ejemplo de CSV para Actualizacion + +```csv +serial_number,name,concentrator_serial,area_name,location,meter_type,status,installation_date +MED001,Medidor Actualizado,Mexico-GRH,ZONA B,Nueva Ubicacion,LORA,MAINTENANCE,2024-01-15 +``` + +Solo se actualizaran los campos proporcionados (no vacios). + +--- + +## Carga de Lecturas + +### Formato del CSV + +```csv +meter_serial,reading_value,received_at,reading_type,battery_level,signal_strength +MED001,1234.56,2024-01-20 10:30:00,MANUAL,85,-45 +MED002,567.89,2024-01-20 10:35:00,MANUAL,90,-42 +MED003,890.12,2024-01-20 10:40:00,AUTOMATIC,78,-50 +``` + +### Campos + +| Campo | Requerido | Tipo | Descripcion | Ejemplo | +|-------|-----------|------|-------------|---------| +| meter_serial | **Si** | Texto | Serial del medidor existente | MED001 | +| reading_value | **Si** | Numero | Valor de la lectura | 1234.56 | +| received_at | No | Fecha/Hora | Fecha y hora de la lectura | 2024-01-20 10:30:00 | +| reading_type | No | Texto | Tipo de lectura (default: MANUAL) | MANUAL | +| battery_level | No | Entero | Nivel de bateria (0-100) | 85 | +| signal_strength | No | Entero | Intensidad de senal (dBm) | -45 | + +### Tipos de Lectura Validos +- `AUTOMATIC` - Lectura automatica del dispositivo +- `MANUAL` - Lectura ingresada manualmente (default) +- `SCHEDULED` - Lectura programada + +### Notas Importantes + +1. **El medidor debe existir**: El `meter_serial` debe corresponder a un medidor ya registrado en el sistema +2. **Fecha por defecto**: Si no se especifica `received_at`, se usa la fecha/hora actual +3. **Actualizacion automatica**: Al insertar una lectura, se actualiza automaticamente el `last_reading_value` del medidor + +--- + +## Proceso de Carga + +### Paso 1: Descargar Plantilla +1. Haga clic en "Descargar plantilla CSV" +2. Se descargara un archivo con los encabezados correctos y una fila de ejemplo + +### Paso 2: Preparar el Archivo +1. Abra la plantilla en Excel, Google Sheets o cualquier editor de texto +2. Complete los datos manteniendo el formato CSV +3. Guarde el archivo como `.csv` (valores separados por comas) + +### Paso 3: Subir el Archivo +1. Arrastre el archivo al area de carga, o haga clic para seleccionarlo +2. Verifique que aparezca el nombre del archivo +3. Haga clic en "Subir Archivo" + +### Paso 4: Revisar Resultados +El sistema mostrara: +- **Total**: Numero total de filas procesadas +- **Insertados**: Registros nuevos creados +- **Actualizados**: Registros existentes modificados +- **Errores**: Filas que no pudieron procesarse + +### Errores Comunes + +| Error | Causa | Solucion | +|-------|-------|----------| +| "serial_number es requerido" | Celda vacia | Agregar serial | +| "concentrator_serial es requerido" | Celda vacia | Agregar serial del concentrador | +| "Concentrador no encontrado" | Serial incorrecto | Verificar serial del concentrador | +| "Medidor no encontrado" | Serial de medidor incorrecto (lecturas) | Verificar que el medidor exista | +| "Valor de lectura invalido" | No es numero | Usar formato numerico (ej: 1234.56) | +| "Nivel de bateria invalido" | Fuera de rango | Usar valor entre 0 y 100 | + +--- + +## Ejemplos Practicos + +### Ejemplo 1: Cargar 3 Medidores Nuevos + +```csv +serial_number,name,concentrator_serial,area_name,location,meter_type,status,installation_date +RES-001,Departamento 101,Mexico-GRH,TORRE A,Piso 1,LORA,ACTIVE,2024-01-15 +RES-002,Departamento 102,Mexico-GRH,TORRE A,Piso 1,LORA,ACTIVE,2024-01-15 +RES-003,Departamento 201,Mexico-GRH,TORRE A,Piso 2,LORA,ACTIVE,2024-01-15 +``` + +### Ejemplo 2: Actualizar Ubicacion de Medidores + +```csv +serial_number,name,concentrator_serial,area_name,location,meter_type,status,installation_date +RES-001,,Mexico-GRH,,Nueva Ubicacion,,, +RES-002,,Mexico-GRH,,Bodega 1,,, +``` + +Solo los campos con valor seran actualizados. + +### Ejemplo 3: Cargar Lecturas Diarias + +```csv +meter_serial,reading_value,received_at,reading_type,battery_level,signal_strength +RES-001,125.50,2024-01-20 08:00:00,MANUAL,95,-40 +RES-002,89.75,2024-01-20 08:05:00,MANUAL,92,-38 +RES-003,156.25,2024-01-20 08:10:00,MANUAL,88,-45 +``` + +### Ejemplo 4: Cargar Lecturas sin Fecha (Usa Fecha Actual) + +```csv +meter_serial,reading_value,received_at,reading_type,battery_level,signal_strength +RES-001,130.25,,,85, +RES-002,92.50,,,90, +RES-003,161.00,,,85, +``` + +--- + +## API Endpoints + +El panel utiliza los siguientes endpoints de la API: + +### Medidores + +**Subir CSV:** +```http +POST /api/csv-upload/meters +Content-Type: multipart/form-data + +file: archivo.csv +``` + +**Descargar plantilla:** +```http +GET /api/csv-upload/meters/template +``` + +### Lecturas + +**Subir CSV:** +```http +POST /api/csv-upload/readings +Content-Type: multipart/form-data + +file: archivo.csv +``` + +**Descargar plantilla:** +```http +GET /api/csv-upload/readings/template +``` + +--- + +## Configuracion Tecnica + +### Variables de Entorno + +Crear archivo `.env` en `upload-panel/`: + +```env +VITE_API_URL=https://api.gestionrecursoshidricos.com/api +``` + +Para desarrollo local: +```env +VITE_API_URL=http://localhost:3000/api +``` + +### Ejecutar Localmente + +```bash +cd upload-panel +npm install +npm run dev +``` + +El panel estara disponible en: http://localhost:5174 + +### Compilar para Produccion + +```bash +npm run build +``` + +Los archivos compilados estaran en `upload-panel/dist/`