193 lines
7.9 KiB
PL/PgSQL
193 lines
7.9 KiB
PL/PgSQL
-- ================================================================
|
|
-- SCHEMA - App Recolección Inteligente · Hackathon Celaya 2026
|
|
-- ================================================================
|
|
|
|
CREATE EXTENSION IF NOT EXISTS postgis;
|
|
CREATE EXTENSION IF NOT EXISTS pgcrypto;
|
|
|
|
-- ----------------------------------------------------------------
|
|
-- 1. USERS
|
|
-- ----------------------------------------------------------------
|
|
CREATE TABLE users (
|
|
id UUID PRIMARY KEY DEFAULT gen_random_uuid(),
|
|
email VARCHAR(255) UNIQUE,
|
|
phone VARCHAR(20) UNIQUE,
|
|
password_hash VARCHAR(255) NOT NULL,
|
|
fcm_token VARCHAR(500),
|
|
rol VARCHAR(20) NOT NULL DEFAULT 'ciudadano',
|
|
activo BOOLEAN NOT NULL DEFAULT TRUE,
|
|
created_at TIMESTAMPTZ NOT NULL DEFAULT NOW(),
|
|
updated_at TIMESTAMPTZ NOT NULL DEFAULT NOW(),
|
|
CONSTRAINT chk_contacto CHECK (email IS NOT NULL OR phone IS NOT NULL)
|
|
);
|
|
|
|
-- ----------------------------------------------------------------
|
|
-- 2. RUTAS
|
|
-- ----------------------------------------------------------------
|
|
CREATE TABLE rutas (
|
|
id SERIAL PRIMARY KEY,
|
|
route_id VARCHAR(20) NOT NULL UNIQUE,
|
|
nombre VARCHAR(255) NOT NULL,
|
|
truck_id SMALLINT NOT NULL,
|
|
hora_inicio TIME NOT NULL,
|
|
hora_fin_ref TIME NOT NULL,
|
|
activa BOOLEAN NOT NULL DEFAULT TRUE,
|
|
created_at TIMESTAMPTZ NOT NULL DEFAULT NOW()
|
|
);
|
|
|
|
-- ----------------------------------------------------------------
|
|
-- 3. RUTA_POSICIONES
|
|
-- ----------------------------------------------------------------
|
|
CREATE TABLE ruta_posiciones (
|
|
id BIGSERIAL PRIMARY KEY,
|
|
ruta_id INT NOT NULL REFERENCES rutas(id) ON DELETE CASCADE,
|
|
position_id SMALLINT NOT NULL,
|
|
lat DECIMAL(9,6) NOT NULL,
|
|
lng DECIMAL(9,6) NOT NULL,
|
|
speed_kmh SMALLINT NOT NULL DEFAULT 0,
|
|
ts_referencia TIMESTAMPTZ NOT NULL,
|
|
offset_seg INT NOT NULL DEFAULT 0,
|
|
punto GEOGRAPHY(POINT, 4326) NOT NULL,
|
|
CONSTRAINT uq_ruta_posicion UNIQUE (ruta_id, position_id)
|
|
);
|
|
|
|
CREATE INDEX idx_ruta_pos_ruta ON ruta_posiciones (ruta_id, position_id);
|
|
CREATE INDEX idx_ruta_pos_punto ON ruta_posiciones USING GIST (punto);
|
|
|
|
-- ----------------------------------------------------------------
|
|
-- 4. COLONIAS
|
|
-- ----------------------------------------------------------------
|
|
CREATE TABLE colonias (
|
|
id SERIAL PRIMARY KEY,
|
|
nombre VARCHAR(255) NOT NULL UNIQUE,
|
|
ruta_id INT NOT NULL REFERENCES rutas(id),
|
|
horario_turno VARCHAR(20) NOT NULL,
|
|
hora_inicio_est TIME NOT NULL,
|
|
hora_fin_est TIME NOT NULL,
|
|
poligono GEOGRAPHY(POLYGON, 4326),
|
|
created_at TIMESTAMPTZ NOT NULL DEFAULT NOW()
|
|
);
|
|
|
|
CREATE INDEX idx_colonias_ruta ON colonias (ruta_id);
|
|
CREATE INDEX idx_colonias_pol ON colonias USING GIST (poligono) WHERE poligono IS NOT NULL;
|
|
|
|
-- ----------------------------------------------------------------
|
|
-- 5. DOMICILIOS
|
|
-- ----------------------------------------------------------------
|
|
CREATE TABLE domicilios (
|
|
id UUID PRIMARY KEY DEFAULT gen_random_uuid(),
|
|
user_id UUID NOT NULL REFERENCES users(id) ON DELETE CASCADE,
|
|
alias VARCHAR(50) NOT NULL,
|
|
direccion_texto TEXT NOT NULL,
|
|
lat DECIMAL(9,6) NOT NULL,
|
|
lng DECIMAL(9,6) NOT NULL,
|
|
coordenada GEOGRAPHY(POINT, 4326) NOT NULL,
|
|
colonia_id INT REFERENCES colonias(id) ON DELETE SET NULL,
|
|
validado BOOLEAN NOT NULL DEFAULT FALSE,
|
|
created_at TIMESTAMPTZ NOT NULL DEFAULT NOW(),
|
|
CONSTRAINT uq_domicilio_alias UNIQUE (user_id, alias)
|
|
);
|
|
|
|
CREATE INDEX idx_domicilios_user ON domicilios (user_id);
|
|
CREATE INDEX idx_domicilios_col ON domicilios (colonia_id);
|
|
CREATE INDEX idx_domicilios_coord ON domicilios USING GIST (coordenada);
|
|
|
|
-- ----------------------------------------------------------------
|
|
-- 6. ESTADO_RUTA (actualizado por el simulador/cron)
|
|
-- ----------------------------------------------------------------
|
|
CREATE TABLE estado_ruta (
|
|
ruta_id INT PRIMARY KEY REFERENCES rutas(id) ON DELETE CASCADE,
|
|
estado VARCHAR(20) NOT NULL DEFAULT 'INACTIVA',
|
|
position_id_actual SMALLINT NOT NULL DEFAULT 1,
|
|
lat_actual DECIMAL(9,6),
|
|
lng_actual DECIMAL(9,6),
|
|
hora_real_inicio TIMESTAMPTZ,
|
|
hora_estim_fin TIMESTAMPTZ,
|
|
minutos_retraso SMALLINT NOT NULL DEFAULT 0,
|
|
motivo_retraso TEXT,
|
|
actualizado_at TIMESTAMPTZ NOT NULL DEFAULT NOW()
|
|
);
|
|
|
|
-- ----------------------------------------------------------------
|
|
-- 7. NOTIFICACION_TEMPLATES
|
|
-- ----------------------------------------------------------------
|
|
CREATE TABLE notificacion_templates (
|
|
id SERIAL PRIMARY KEY,
|
|
trigger_event VARCHAR(30) NOT NULL UNIQUE,
|
|
position_id_trigger SMALLINT NOT NULL,
|
|
titulo VARCHAR(150) NOT NULL,
|
|
cuerpo TEXT NOT NULL,
|
|
activo BOOLEAN NOT NULL DEFAULT TRUE,
|
|
created_at TIMESTAMPTZ NOT NULL DEFAULT NOW()
|
|
);
|
|
|
|
-- ----------------------------------------------------------------
|
|
-- 8. NOTIFICACIONES
|
|
-- ----------------------------------------------------------------
|
|
CREATE TABLE notificaciones (
|
|
id UUID PRIMARY KEY DEFAULT gen_random_uuid(),
|
|
user_id UUID NOT NULL REFERENCES users(id) ON DELETE CASCADE,
|
|
domicilio_id UUID REFERENCES domicilios(id) ON DELETE SET NULL,
|
|
template_id INT REFERENCES notificacion_templates(id),
|
|
ruta_id INT REFERENCES rutas(id),
|
|
titulo VARCHAR(150) NOT NULL,
|
|
mensaje TEXT NOT NULL,
|
|
enviada_at TIMESTAMPTZ NOT NULL DEFAULT NOW(),
|
|
leida BOOLEAN NOT NULL DEFAULT FALSE,
|
|
leida_at TIMESTAMPTZ
|
|
);
|
|
|
|
CREATE INDEX idx_notif_user ON notificaciones (user_id, enviada_at DESC);
|
|
CREATE INDEX idx_notif_no_leida ON notificaciones (user_id) WHERE leida = FALSE;
|
|
|
|
-- ----------------------------------------------------------------
|
|
-- 9. REPORTES
|
|
-- ----------------------------------------------------------------
|
|
CREATE TABLE reportes (
|
|
id UUID PRIMARY KEY DEFAULT gen_random_uuid(),
|
|
user_id UUID NOT NULL REFERENCES users(id) ON DELETE CASCADE,
|
|
domicilio_id UUID REFERENCES domicilios(id) ON DELETE SET NULL,
|
|
ruta_id INT REFERENCES rutas(id),
|
|
tipo VARCHAR(40) NOT NULL,
|
|
descripcion TEXT,
|
|
calificacion SMALLINT CHECK (calificacion BETWEEN 1 AND 5),
|
|
estado VARCHAR(20) NOT NULL DEFAULT 'abierto',
|
|
creado_at TIMESTAMPTZ NOT NULL DEFAULT NOW()
|
|
);
|
|
|
|
CREATE INDEX idx_reportes_user ON reportes (user_id);
|
|
CREATE INDEX idx_reportes_ruta ON reportes (ruta_id, creado_at);
|
|
|
|
-- ----------------------------------------------------------------
|
|
-- 10. GUÍA DE SEPARACIÓN
|
|
-- ----------------------------------------------------------------
|
|
CREATE TABLE residuos_categorias (
|
|
id SERIAL PRIMARY KEY,
|
|
nombre VARCHAR(50) NOT NULL,
|
|
descripcion TEXT,
|
|
color_hex CHAR(7),
|
|
icono VARCHAR(100)
|
|
);
|
|
|
|
CREATE TABLE residuos_ejemplos (
|
|
id SERIAL PRIMARY KEY,
|
|
categoria_id INT NOT NULL REFERENCES residuos_categorias(id) ON DELETE CASCADE,
|
|
nombre VARCHAR(255) NOT NULL,
|
|
descripcion TEXT
|
|
);
|
|
|
|
-- ----------------------------------------------------------------
|
|
-- TRIGGERS
|
|
-- ----------------------------------------------------------------
|
|
CREATE OR REPLACE FUNCTION fn_set_updated_at()
|
|
RETURNS TRIGGER LANGUAGE plpgsql AS $$
|
|
BEGIN
|
|
NEW.updated_at = NOW();
|
|
RETURN NEW;
|
|
END;
|
|
$$;
|
|
|
|
CREATE TRIGGER trg_users_updated_at
|
|
BEFORE UPDATE ON users
|
|
FOR EACH ROW EXECUTE FUNCTION fn_set_updated_at();
|