Migrar backend a PostgreSQL + Node.js/Express con nuevas funcionalidades
Backend (water-api/): - Crear API REST completa con Express + TypeScript - Implementar autenticación JWT con refresh tokens - CRUD completo para: projects, concentrators, meters, gateways, devices, users, roles - Agregar validación con Zod para todas las entidades - Implementar webhooks para The Things Stack (LoRaWAN) - Agregar endpoint de lecturas con filtros y resumen de consumo - Implementar carga masiva de medidores via Excel (.xlsx) Frontend: - Crear cliente HTTP con manejo automático de JWT y refresh - Actualizar todas las APIs para usar nuevo backend - Agregar sistema de autenticación real (login, logout, me) - Agregar selector de tipo (LORA, LoRaWAN, Grandes) en concentradores y medidores - Agregar campo Meter ID en medidores - Crear modal de carga masiva para medidores - Agregar página de consumo con gráficas y filtros - Corregir carga de proyectos independiente de datos existentes Co-Authored-By: Claude Opus 4.5 <noreply@anthropic.com>
This commit is contained in:
434
water-api/sql/schema.sql
Normal file
434
water-api/sql/schema.sql
Normal file
@@ -0,0 +1,434 @@
|
||||
-- ============================================================================
|
||||
-- Water Project Database Schema
|
||||
-- PostgreSQL Migration Script
|
||||
-- ============================================================================
|
||||
|
||||
-- Enable required extensions
|
||||
CREATE EXTENSION IF NOT EXISTS "pgcrypto";
|
||||
|
||||
-- ============================================================================
|
||||
-- TRIGGER FUNCTION: Auto-update updated_at timestamp
|
||||
-- ============================================================================
|
||||
CREATE OR REPLACE FUNCTION update_updated_at_column()
|
||||
RETURNS TRIGGER AS $$
|
||||
BEGIN
|
||||
NEW.updated_at = CURRENT_TIMESTAMP;
|
||||
RETURN NEW;
|
||||
END;
|
||||
$$ LANGUAGE plpgsql;
|
||||
|
||||
-- ============================================================================
|
||||
-- ENUM TYPES
|
||||
-- ============================================================================
|
||||
CREATE TYPE role_name AS ENUM ('ADMIN', 'OPERATOR', 'VIEWER');
|
||||
CREATE TYPE project_status AS ENUM ('ACTIVE', 'INACTIVE', 'COMPLETED');
|
||||
CREATE TYPE device_status AS ENUM ('ACTIVE', 'INACTIVE', 'OFFLINE', 'MAINTENANCE', 'ERROR');
|
||||
CREATE TYPE meter_type AS ENUM ('WATER', 'GAS', 'ELECTRIC');
|
||||
CREATE TYPE reading_type AS ENUM ('AUTOMATIC', 'MANUAL', 'SCHEDULED');
|
||||
|
||||
-- ============================================================================
|
||||
-- TABLE 1: roles
|
||||
-- ============================================================================
|
||||
CREATE TABLE roles (
|
||||
id UUID PRIMARY KEY DEFAULT gen_random_uuid(),
|
||||
name role_name NOT NULL UNIQUE,
|
||||
description TEXT,
|
||||
permissions JSONB NOT NULL DEFAULT '{}',
|
||||
created_at TIMESTAMP WITH TIME ZONE NOT NULL DEFAULT CURRENT_TIMESTAMP,
|
||||
updated_at TIMESTAMP WITH TIME ZONE NOT NULL DEFAULT CURRENT_TIMESTAMP
|
||||
);
|
||||
|
||||
CREATE INDEX idx_roles_name ON roles(name);
|
||||
|
||||
CREATE TRIGGER trigger_roles_updated_at
|
||||
BEFORE UPDATE ON roles
|
||||
FOR EACH ROW
|
||||
EXECUTE FUNCTION update_updated_at_column();
|
||||
|
||||
COMMENT ON TABLE roles IS 'User roles with associated permissions';
|
||||
|
||||
-- ============================================================================
|
||||
-- TABLE 2: users
|
||||
-- ============================================================================
|
||||
CREATE TABLE users (
|
||||
id UUID PRIMARY KEY DEFAULT gen_random_uuid(),
|
||||
email VARCHAR(255) NOT NULL UNIQUE,
|
||||
password_hash VARCHAR(255) NOT NULL,
|
||||
name VARCHAR(255) NOT NULL,
|
||||
avatar_url TEXT,
|
||||
role_id UUID NOT NULL REFERENCES roles(id) ON DELETE RESTRICT,
|
||||
is_active BOOLEAN NOT NULL DEFAULT TRUE,
|
||||
last_login TIMESTAMP WITH TIME ZONE,
|
||||
created_at TIMESTAMP WITH TIME ZONE NOT NULL DEFAULT CURRENT_TIMESTAMP,
|
||||
updated_at TIMESTAMP WITH TIME ZONE NOT NULL DEFAULT CURRENT_TIMESTAMP
|
||||
);
|
||||
|
||||
CREATE INDEX idx_users_email ON users(email);
|
||||
CREATE INDEX idx_users_role_id ON users(role_id);
|
||||
CREATE INDEX idx_users_is_active ON users(is_active);
|
||||
|
||||
CREATE TRIGGER trigger_users_updated_at
|
||||
BEFORE UPDATE ON users
|
||||
FOR EACH ROW
|
||||
EXECUTE FUNCTION update_updated_at_column();
|
||||
|
||||
COMMENT ON TABLE users IS 'Application users with authentication credentials';
|
||||
|
||||
-- ============================================================================
|
||||
-- TABLE 3: projects
|
||||
-- ============================================================================
|
||||
CREATE TABLE projects (
|
||||
id UUID PRIMARY KEY DEFAULT gen_random_uuid(),
|
||||
name VARCHAR(255) NOT NULL,
|
||||
description TEXT,
|
||||
area_name VARCHAR(255),
|
||||
location TEXT,
|
||||
status project_status NOT NULL DEFAULT 'ACTIVE',
|
||||
created_by UUID NOT NULL REFERENCES users(id) ON DELETE RESTRICT,
|
||||
created_at TIMESTAMP WITH TIME ZONE NOT NULL DEFAULT CURRENT_TIMESTAMP,
|
||||
updated_at TIMESTAMP WITH TIME ZONE NOT NULL DEFAULT CURRENT_TIMESTAMP
|
||||
);
|
||||
|
||||
CREATE INDEX idx_projects_status ON projects(status);
|
||||
CREATE INDEX idx_projects_created_by ON projects(created_by);
|
||||
CREATE INDEX idx_projects_name ON projects(name);
|
||||
|
||||
CREATE TRIGGER trigger_projects_updated_at
|
||||
BEFORE UPDATE ON projects
|
||||
FOR EACH ROW
|
||||
EXECUTE FUNCTION update_updated_at_column();
|
||||
|
||||
COMMENT ON TABLE projects IS 'Water monitoring projects';
|
||||
|
||||
-- ============================================================================
|
||||
-- TABLE 4: concentrators
|
||||
-- ============================================================================
|
||||
CREATE TABLE concentrators (
|
||||
id UUID PRIMARY KEY DEFAULT gen_random_uuid(),
|
||||
serial_number VARCHAR(100) NOT NULL UNIQUE,
|
||||
name VARCHAR(255) NOT NULL,
|
||||
project_id UUID NOT NULL REFERENCES projects(id) ON DELETE CASCADE,
|
||||
location TEXT,
|
||||
status device_status NOT NULL DEFAULT 'ACTIVE',
|
||||
ip_address INET,
|
||||
firmware_version VARCHAR(50),
|
||||
last_communication TIMESTAMP WITH TIME ZONE,
|
||||
created_at TIMESTAMP WITH TIME ZONE NOT NULL DEFAULT CURRENT_TIMESTAMP,
|
||||
updated_at TIMESTAMP WITH TIME ZONE NOT NULL DEFAULT CURRENT_TIMESTAMP
|
||||
);
|
||||
|
||||
CREATE INDEX idx_concentrators_serial_number ON concentrators(serial_number);
|
||||
CREATE INDEX idx_concentrators_project_id ON concentrators(project_id);
|
||||
CREATE INDEX idx_concentrators_status ON concentrators(status);
|
||||
|
||||
CREATE TRIGGER trigger_concentrators_updated_at
|
||||
BEFORE UPDATE ON concentrators
|
||||
FOR EACH ROW
|
||||
EXECUTE FUNCTION update_updated_at_column();
|
||||
|
||||
COMMENT ON TABLE concentrators IS 'Data concentrators that aggregate gateway communications';
|
||||
|
||||
-- ============================================================================
|
||||
-- TABLE 5: gateways
|
||||
-- ============================================================================
|
||||
CREATE TABLE gateways (
|
||||
id UUID PRIMARY KEY DEFAULT gen_random_uuid(),
|
||||
gateway_id VARCHAR(100) NOT NULL UNIQUE,
|
||||
name VARCHAR(255) NOT NULL,
|
||||
project_id UUID NOT NULL REFERENCES projects(id) ON DELETE CASCADE,
|
||||
concentrator_id UUID REFERENCES concentrators(id) ON DELETE SET NULL,
|
||||
location TEXT,
|
||||
status device_status NOT NULL DEFAULT 'ACTIVE',
|
||||
tts_gateway_id VARCHAR(255),
|
||||
tts_status VARCHAR(50),
|
||||
tts_last_seen TIMESTAMP WITH TIME ZONE,
|
||||
created_at TIMESTAMP WITH TIME ZONE NOT NULL DEFAULT CURRENT_TIMESTAMP,
|
||||
updated_at TIMESTAMP WITH TIME ZONE NOT NULL DEFAULT CURRENT_TIMESTAMP
|
||||
);
|
||||
|
||||
CREATE INDEX idx_gateways_gateway_id ON gateways(gateway_id);
|
||||
CREATE INDEX idx_gateways_project_id ON gateways(project_id);
|
||||
CREATE INDEX idx_gateways_concentrator_id ON gateways(concentrator_id);
|
||||
CREATE INDEX idx_gateways_status ON gateways(status);
|
||||
|
||||
CREATE TRIGGER trigger_gateways_updated_at
|
||||
BEFORE UPDATE ON gateways
|
||||
FOR EACH ROW
|
||||
EXECUTE FUNCTION update_updated_at_column();
|
||||
|
||||
COMMENT ON TABLE gateways IS 'LoRaWAN gateways for device communication';
|
||||
|
||||
-- ============================================================================
|
||||
-- TABLE 6: devices
|
||||
-- ============================================================================
|
||||
CREATE TABLE devices (
|
||||
id UUID PRIMARY KEY DEFAULT gen_random_uuid(),
|
||||
dev_eui VARCHAR(16) NOT NULL UNIQUE,
|
||||
name VARCHAR(255) NOT NULL,
|
||||
device_type VARCHAR(100),
|
||||
project_id UUID NOT NULL REFERENCES projects(id) ON DELETE CASCADE,
|
||||
gateway_id UUID REFERENCES gateways(id) ON DELETE SET NULL,
|
||||
status device_status NOT NULL DEFAULT 'ACTIVE',
|
||||
tts_device_id VARCHAR(255),
|
||||
tts_status VARCHAR(50),
|
||||
tts_last_seen TIMESTAMP WITH TIME ZONE,
|
||||
app_key VARCHAR(32),
|
||||
join_eui VARCHAR(16),
|
||||
created_at TIMESTAMP WITH TIME ZONE NOT NULL DEFAULT CURRENT_TIMESTAMP,
|
||||
updated_at TIMESTAMP WITH TIME ZONE NOT NULL DEFAULT CURRENT_TIMESTAMP
|
||||
);
|
||||
|
||||
CREATE INDEX idx_devices_dev_eui ON devices(dev_eui);
|
||||
CREATE INDEX idx_devices_project_id ON devices(project_id);
|
||||
CREATE INDEX idx_devices_gateway_id ON devices(gateway_id);
|
||||
CREATE INDEX idx_devices_status ON devices(status);
|
||||
CREATE INDEX idx_devices_device_type ON devices(device_type);
|
||||
|
||||
CREATE TRIGGER trigger_devices_updated_at
|
||||
BEFORE UPDATE ON devices
|
||||
FOR EACH ROW
|
||||
EXECUTE FUNCTION update_updated_at_column();
|
||||
|
||||
COMMENT ON TABLE devices IS 'LoRaWAN end devices (sensors/transmitters)';
|
||||
|
||||
-- ============================================================================
|
||||
-- TABLE 7: meters
|
||||
-- ============================================================================
|
||||
CREATE TABLE meters (
|
||||
id UUID PRIMARY KEY DEFAULT gen_random_uuid(),
|
||||
serial_number VARCHAR(100) NOT NULL UNIQUE,
|
||||
name VARCHAR(255) NOT NULL,
|
||||
project_id UUID NOT NULL REFERENCES projects(id) ON DELETE CASCADE,
|
||||
device_id UUID REFERENCES devices(id) ON DELETE SET NULL,
|
||||
area_name VARCHAR(255),
|
||||
location TEXT,
|
||||
meter_type meter_type NOT NULL DEFAULT 'WATER',
|
||||
status device_status NOT NULL DEFAULT 'ACTIVE',
|
||||
last_reading_value NUMERIC(15, 4),
|
||||
last_reading_at TIMESTAMP WITH TIME ZONE,
|
||||
installation_date DATE,
|
||||
created_at TIMESTAMP WITH TIME ZONE NOT NULL DEFAULT CURRENT_TIMESTAMP,
|
||||
updated_at TIMESTAMP WITH TIME ZONE NOT NULL DEFAULT CURRENT_TIMESTAMP
|
||||
);
|
||||
|
||||
CREATE INDEX idx_meters_serial_number ON meters(serial_number);
|
||||
CREATE INDEX idx_meters_project_id ON meters(project_id);
|
||||
CREATE INDEX idx_meters_device_id ON meters(device_id);
|
||||
CREATE INDEX idx_meters_status ON meters(status);
|
||||
CREATE INDEX idx_meters_meter_type ON meters(meter_type);
|
||||
CREATE INDEX idx_meters_area_name ON meters(area_name);
|
||||
|
||||
CREATE TRIGGER trigger_meters_updated_at
|
||||
BEFORE UPDATE ON meters
|
||||
FOR EACH ROW
|
||||
EXECUTE FUNCTION update_updated_at_column();
|
||||
|
||||
COMMENT ON TABLE meters IS 'Physical water meters associated with devices';
|
||||
|
||||
-- ============================================================================
|
||||
-- TABLE 8: meter_readings
|
||||
-- ============================================================================
|
||||
CREATE TABLE meter_readings (
|
||||
id UUID PRIMARY KEY DEFAULT gen_random_uuid(),
|
||||
meter_id UUID NOT NULL REFERENCES meters(id) ON DELETE CASCADE,
|
||||
device_id UUID REFERENCES devices(id) ON DELETE SET NULL,
|
||||
reading_value NUMERIC(15, 4) NOT NULL,
|
||||
reading_type reading_type NOT NULL DEFAULT 'AUTOMATIC',
|
||||
battery_level SMALLINT,
|
||||
signal_strength SMALLINT,
|
||||
raw_payload TEXT,
|
||||
received_at TIMESTAMP WITH TIME ZONE NOT NULL DEFAULT CURRENT_TIMESTAMP,
|
||||
created_at TIMESTAMP WITH TIME ZONE NOT NULL DEFAULT CURRENT_TIMESTAMP
|
||||
);
|
||||
|
||||
CREATE INDEX idx_meter_readings_meter_id ON meter_readings(meter_id);
|
||||
CREATE INDEX idx_meter_readings_device_id ON meter_readings(device_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 DESC);
|
||||
|
||||
COMMENT ON TABLE meter_readings IS 'Historical meter reading values';
|
||||
|
||||
-- ============================================================================
|
||||
-- TABLE 9: tts_uplink_logs
|
||||
-- ============================================================================
|
||||
CREATE TABLE tts_uplink_logs (
|
||||
id UUID PRIMARY KEY DEFAULT gen_random_uuid(),
|
||||
device_id UUID REFERENCES devices(id) ON DELETE SET NULL,
|
||||
dev_eui VARCHAR(16) NOT NULL,
|
||||
raw_payload JSONB NOT NULL,
|
||||
decoded_payload JSONB,
|
||||
gateway_ids TEXT[],
|
||||
rssi SMALLINT,
|
||||
snr NUMERIC(5, 2),
|
||||
processed BOOLEAN NOT NULL DEFAULT FALSE,
|
||||
error_message TEXT,
|
||||
received_at TIMESTAMP WITH TIME ZONE NOT NULL DEFAULT CURRENT_TIMESTAMP,
|
||||
created_at TIMESTAMP WITH TIME ZONE NOT NULL DEFAULT CURRENT_TIMESTAMP
|
||||
);
|
||||
|
||||
CREATE INDEX idx_tts_uplink_logs_device_id ON tts_uplink_logs(device_id);
|
||||
CREATE INDEX idx_tts_uplink_logs_dev_eui ON tts_uplink_logs(dev_eui);
|
||||
CREATE INDEX idx_tts_uplink_logs_received_at ON tts_uplink_logs(received_at);
|
||||
CREATE INDEX idx_tts_uplink_logs_processed ON tts_uplink_logs(processed);
|
||||
CREATE INDEX idx_tts_uplink_logs_raw_payload ON tts_uplink_logs USING GIN (raw_payload);
|
||||
|
||||
COMMENT ON TABLE tts_uplink_logs IS 'The Things Stack uplink message logs';
|
||||
|
||||
-- ============================================================================
|
||||
-- TABLE 10: refresh_tokens
|
||||
-- ============================================================================
|
||||
CREATE TABLE refresh_tokens (
|
||||
id UUID PRIMARY KEY DEFAULT gen_random_uuid(),
|
||||
user_id UUID NOT NULL REFERENCES users(id) ON DELETE CASCADE,
|
||||
token_hash VARCHAR(255) NOT NULL UNIQUE,
|
||||
expires_at TIMESTAMP WITH TIME ZONE NOT NULL,
|
||||
created_at TIMESTAMP WITH TIME ZONE NOT NULL DEFAULT CURRENT_TIMESTAMP,
|
||||
revoked_at TIMESTAMP WITH TIME ZONE
|
||||
);
|
||||
|
||||
CREATE INDEX idx_refresh_tokens_user_id ON refresh_tokens(user_id);
|
||||
CREATE INDEX idx_refresh_tokens_token_hash ON refresh_tokens(token_hash);
|
||||
CREATE INDEX idx_refresh_tokens_expires_at ON refresh_tokens(expires_at);
|
||||
|
||||
COMMENT ON TABLE refresh_tokens IS 'JWT refresh tokens for user sessions';
|
||||
|
||||
-- ============================================================================
|
||||
-- VIEW: meter_stats_by_project
|
||||
-- ============================================================================
|
||||
CREATE OR REPLACE VIEW meter_stats_by_project AS
|
||||
SELECT
|
||||
p.id AS project_id,
|
||||
p.name AS project_name,
|
||||
p.status AS project_status,
|
||||
COUNT(m.id) AS total_meters,
|
||||
COUNT(CASE WHEN m.status = 'ACTIVE' THEN 1 END) AS active_meters,
|
||||
COUNT(CASE WHEN m.status = 'INACTIVE' THEN 1 END) AS inactive_meters,
|
||||
COUNT(CASE WHEN m.status = 'OFFLINE' THEN 1 END) AS offline_meters,
|
||||
COUNT(CASE WHEN m.status = 'MAINTENANCE' THEN 1 END) AS maintenance_meters,
|
||||
COUNT(CASE WHEN m.status = 'ERROR' THEN 1 END) AS error_meters,
|
||||
ROUND(AVG(m.last_reading_value)::NUMERIC, 2) AS avg_last_reading,
|
||||
MAX(m.last_reading_at) AS most_recent_reading,
|
||||
COUNT(DISTINCT m.area_name) AS unique_areas
|
||||
FROM projects p
|
||||
LEFT JOIN meters m ON p.id = m.project_id
|
||||
GROUP BY p.id, p.name, p.status;
|
||||
|
||||
COMMENT ON VIEW meter_stats_by_project IS 'Aggregated meter statistics per project';
|
||||
|
||||
-- ============================================================================
|
||||
-- VIEW: device_status_summary
|
||||
-- ============================================================================
|
||||
CREATE OR REPLACE VIEW device_status_summary AS
|
||||
SELECT
|
||||
p.id AS project_id,
|
||||
p.name AS project_name,
|
||||
'concentrator' AS device_category,
|
||||
c.status,
|
||||
COUNT(*) AS count
|
||||
FROM projects p
|
||||
LEFT JOIN concentrators c ON p.id = c.project_id
|
||||
WHERE c.id IS NOT NULL
|
||||
GROUP BY p.id, p.name, c.status
|
||||
|
||||
UNION ALL
|
||||
|
||||
SELECT
|
||||
p.id AS project_id,
|
||||
p.name AS project_name,
|
||||
'gateway' AS device_category,
|
||||
g.status,
|
||||
COUNT(*) AS count
|
||||
FROM projects p
|
||||
LEFT JOIN gateways g ON p.id = g.project_id
|
||||
WHERE g.id IS NOT NULL
|
||||
GROUP BY p.id, p.name, g.status
|
||||
|
||||
UNION ALL
|
||||
|
||||
SELECT
|
||||
p.id AS project_id,
|
||||
p.name AS project_name,
|
||||
'device' AS device_category,
|
||||
d.status,
|
||||
COUNT(*) AS count
|
||||
FROM projects p
|
||||
LEFT JOIN devices d ON p.id = d.project_id
|
||||
WHERE d.id IS NOT NULL
|
||||
GROUP BY p.id, p.name, d.status
|
||||
|
||||
UNION ALL
|
||||
|
||||
SELECT
|
||||
p.id AS project_id,
|
||||
p.name AS project_name,
|
||||
'meter' AS device_category,
|
||||
m.status,
|
||||
COUNT(*) AS count
|
||||
FROM projects p
|
||||
LEFT JOIN meters m ON p.id = m.project_id
|
||||
WHERE m.id IS NOT NULL
|
||||
GROUP BY p.id, p.name, m.status;
|
||||
|
||||
COMMENT ON VIEW device_status_summary IS 'Summary of device statuses across all device types per project';
|
||||
|
||||
-- ============================================================================
|
||||
-- SEED DATA: Default Roles
|
||||
-- ============================================================================
|
||||
INSERT INTO roles (name, description, permissions) VALUES
|
||||
(
|
||||
'ADMIN',
|
||||
'Full system administrator with all permissions',
|
||||
'{
|
||||
"users": {"create": true, "read": true, "update": true, "delete": true},
|
||||
"projects": {"create": true, "read": true, "update": true, "delete": true},
|
||||
"devices": {"create": true, "read": true, "update": true, "delete": true},
|
||||
"meters": {"create": true, "read": true, "update": true, "delete": true},
|
||||
"readings": {"create": true, "read": true, "update": true, "delete": true},
|
||||
"settings": {"create": true, "read": true, "update": true, "delete": true},
|
||||
"reports": {"create": true, "read": true, "export": true}
|
||||
}'::JSONB
|
||||
),
|
||||
(
|
||||
'OPERATOR',
|
||||
'Operator with management permissions but no system settings',
|
||||
'{
|
||||
"users": {"create": false, "read": true, "update": false, "delete": false},
|
||||
"projects": {"create": true, "read": true, "update": true, "delete": false},
|
||||
"devices": {"create": true, "read": true, "update": true, "delete": false},
|
||||
"meters": {"create": true, "read": true, "update": true, "delete": false},
|
||||
"readings": {"create": true, "read": true, "update": false, "delete": false},
|
||||
"settings": {"create": false, "read": true, "update": false, "delete": false},
|
||||
"reports": {"create": true, "read": true, "export": true}
|
||||
}'::JSONB
|
||||
),
|
||||
(
|
||||
'VIEWER',
|
||||
'Read-only access to view data and reports',
|
||||
'{
|
||||
"users": {"create": false, "read": false, "update": false, "delete": false},
|
||||
"projects": {"create": false, "read": true, "update": false, "delete": false},
|
||||
"devices": {"create": false, "read": true, "update": false, "delete": false},
|
||||
"meters": {"create": false, "read": true, "update": false, "delete": false},
|
||||
"readings": {"create": false, "read": true, "update": false, "delete": false},
|
||||
"settings": {"create": false, "read": false, "update": false, "delete": false},
|
||||
"reports": {"create": false, "read": true, "export": false}
|
||||
}'::JSONB
|
||||
);
|
||||
|
||||
-- ============================================================================
|
||||
-- SEED DATA: Default Admin User
|
||||
-- Password: admin123 (bcrypt hashed)
|
||||
-- ============================================================================
|
||||
INSERT INTO users (email, password_hash, name, role_id, is_active)
|
||||
SELECT
|
||||
'admin@waterproject.com',
|
||||
'$2b$12$RrlEdRsUiiQYxtUmjOjX.uZU/IpXUFsXsWxDcMny1RUl6RFc.etDm',
|
||||
'System Administrator',
|
||||
r.id,
|
||||
TRUE
|
||||
FROM roles r
|
||||
WHERE r.name = 'ADMIN';
|
||||
|
||||
-- ============================================================================
|
||||
-- END OF SCHEMA
|
||||
-- ============================================================================
|
||||
Reference in New Issue
Block a user