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 <noreply@anthropic.com>
This commit is contained in:
Exteban08
2026-02-03 11:27:51 +00:00
parent 6118ec2813
commit 71623d667f
6 changed files with 2230 additions and 0 deletions

563
docs/API.md Normal file
View File

@@ -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"
}
```

496
docs/ARQUITECTURA.md Normal file
View File

@@ -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
```

390
docs/INSTALACION.md Normal file
View File

@@ -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 <PID>`
### Permisos de archivo
```
EACCES: permission denied
```
- Verificar permisos del directorio
- Ejecutar: `chown -R $USER:$USER /path/to/water-project`

358
docs/MANUAL_USUARIO.md Normal file
View File

@@ -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`

126
docs/README.md Normal file
View File

@@ -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)

297
docs/UPLOAD_PANEL.md Normal file
View File

@@ -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/`