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:
563
docs/API.md
Normal file
563
docs/API.md
Normal 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
496
docs/ARQUITECTURA.md
Normal 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
390
docs/INSTALACION.md
Normal 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
358
docs/MANUAL_USUARIO.md
Normal 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
126
docs/README.md
Normal 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
297
docs/UPLOAD_PANEL.md
Normal 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/`
|
||||||
Reference in New Issue
Block a user