Files
GRH/docs/ARQUITECTURA.md
Exteban08 71623d667f 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>
2026-02-03 11:27:51 +00:00

28 KiB

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

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