erp-mecanicas-diesel-database/init/00.5-workshop-core-tables.sql

159 lines
5.8 KiB
SQL

-- ===========================================
-- MECANICAS DIESEL - Schema workshop_core
-- ===========================================
-- Autenticación y gestión de usuarios
-- Ejecutar después de 00-extensions.sql
-- Crear schema
CREATE SCHEMA IF NOT EXISTS workshop_core;
COMMENT ON SCHEMA workshop_core IS 'Autenticación, usuarios y gestión de talleres multi-tenant';
-- Grants básicos
GRANT USAGE ON SCHEMA workshop_core TO mecanicas_user;
GRANT ALL PRIVILEGES ON ALL TABLES IN SCHEMA workshop_core TO mecanicas_user;
-- Default privileges para tablas futuras
ALTER DEFAULT PRIVILEGES IN SCHEMA workshop_core GRANT ALL ON TABLES TO mecanicas_user;
SET search_path TO workshop_core, public;
-- -------------------------------------------
-- WORKSHOPS - Talleres (tenants)
-- -------------------------------------------
CREATE TABLE workshop_core.workshops (
id UUID PRIMARY KEY DEFAULT gen_random_uuid(),
-- Información general
name VARCHAR(100) NOT NULL,
-- Datos fiscales
rfc VARCHAR(13),
-- Contacto
email VARCHAR(255),
phone VARCHAR(20),
-- Dirección
address TEXT,
city VARCHAR(100),
state VARCHAR(50),
postal_code VARCHAR(10),
-- Branding
logo_url TEXT,
-- Estado
is_active BOOLEAN DEFAULT true,
-- Audit
created_at TIMESTAMP WITH TIME ZONE DEFAULT NOW(),
updated_at TIMESTAMP WITH TIME ZONE DEFAULT NOW()
);
-- Índices
CREATE INDEX idx_workshops_is_active ON workshop_core.workshops(is_active);
CREATE INDEX idx_workshops_rfc ON workshop_core.workshops(rfc) WHERE rfc IS NOT NULL;
-- Trigger updated_at
CREATE TRIGGER trg_workshops_updated_at
BEFORE UPDATE ON workshop_core.workshops
FOR EACH ROW EXECUTE FUNCTION trigger_set_updated_at();
COMMENT ON TABLE workshop_core.workshops IS 'Talleres mecánicos (tenants del sistema multi-tenant)';
COMMENT ON COLUMN workshop_core.workshops.id IS 'Identificador único del taller (tenant_id)';
COMMENT ON COLUMN workshop_core.workshops.name IS 'Nombre comercial del taller';
COMMENT ON COLUMN workshop_core.workshops.rfc IS 'RFC (Registro Federal de Contribuyentes) para facturación';
COMMENT ON COLUMN workshop_core.workshops.is_active IS 'Indica si el taller está activo y puede operar en el sistema';
-- -------------------------------------------
-- USERS - Usuarios del sistema
-- -------------------------------------------
CREATE TABLE workshop_core.users (
id UUID PRIMARY KEY DEFAULT gen_random_uuid(),
-- Multi-tenant
tenant_id UUID NOT NULL REFERENCES workshop_core.workshops(id) ON DELETE CASCADE,
-- Credenciales
email VARCHAR(255) NOT NULL,
password_hash VARCHAR(255) NOT NULL,
-- Información personal
full_name VARCHAR(150) NOT NULL,
avatar_url TEXT,
-- Rol y permisos
role VARCHAR(30) NOT NULL DEFAULT 'mecanico'
CHECK (role IN ('admin', 'jefe_taller', 'mecanico', 'recepcion', 'almacen')),
-- Estado
is_active BOOLEAN DEFAULT true,
email_verified BOOLEAN DEFAULT false,
-- Sesión
last_login_at TIMESTAMP WITH TIME ZONE,
-- Audit
created_at TIMESTAMP WITH TIME ZONE DEFAULT NOW(),
updated_at TIMESTAMP WITH TIME ZONE DEFAULT NOW(),
-- Constraints
CONSTRAINT uq_user_email_global UNIQUE (email),
CONSTRAINT uq_user_email_tenant UNIQUE (tenant_id, email)
);
-- Índices
CREATE INDEX idx_users_tenant ON workshop_core.users(tenant_id);
CREATE INDEX idx_users_email ON workshop_core.users(email);
CREATE INDEX idx_users_role ON workshop_core.users(tenant_id, role);
CREATE INDEX idx_users_is_active ON workshop_core.users(tenant_id, is_active);
CREATE INDEX idx_users_last_login ON workshop_core.users(last_login_at DESC);
-- Trigger updated_at
CREATE TRIGGER trg_users_updated_at
BEFORE UPDATE ON workshop_core.users
FOR EACH ROW EXECUTE FUNCTION trigger_set_updated_at();
-- RLS
SELECT create_tenant_rls_policies('workshop_core', 'users');
COMMENT ON TABLE workshop_core.users IS 'Usuarios del sistema con autenticación y roles';
COMMENT ON COLUMN workshop_core.users.tenant_id IS 'Taller al que pertenece el usuario';
COMMENT ON COLUMN workshop_core.users.email IS 'Correo electrónico único para login';
COMMENT ON COLUMN workshop_core.users.password_hash IS 'Hash bcrypt de la contraseña';
COMMENT ON COLUMN workshop_core.users.role IS 'Rol del usuario: admin, jefe_taller, mecanico, recepcion, almacen';
COMMENT ON COLUMN workshop_core.users.is_active IS 'Indica si el usuario puede acceder al sistema';
COMMENT ON COLUMN workshop_core.users.email_verified IS 'Indica si el email ha sido verificado';
-- -------------------------------------------
-- REFRESH_TOKENS - Tokens de refresco JWT
-- -------------------------------------------
CREATE TABLE workshop_core.refresh_tokens (
id UUID PRIMARY KEY DEFAULT gen_random_uuid(),
-- Usuario
user_id UUID NOT NULL REFERENCES workshop_core.users(id) ON DELETE CASCADE,
-- Token
token VARCHAR(500) NOT NULL,
-- Validez
expires_at TIMESTAMP WITH TIME ZONE NOT NULL,
revoked_at TIMESTAMP WITH TIME ZONE,
-- Audit
created_at TIMESTAMP WITH TIME ZONE DEFAULT NOW()
);
-- Índices
CREATE INDEX idx_refresh_tokens_user ON workshop_core.refresh_tokens(user_id);
CREATE INDEX idx_refresh_tokens_token ON workshop_core.refresh_tokens(token);
CREATE INDEX idx_refresh_tokens_expires ON workshop_core.refresh_tokens(expires_at);
CREATE INDEX idx_refresh_tokens_active ON workshop_core.refresh_tokens(user_id, expires_at)
WHERE revoked_at IS NULL;
COMMENT ON TABLE workshop_core.refresh_tokens IS 'Tokens de refresco para autenticación JWT';
COMMENT ON COLUMN workshop_core.refresh_tokens.token IS 'Token de refresco único para renovar access tokens';
COMMENT ON COLUMN workshop_core.refresh_tokens.expires_at IS 'Fecha de expiración del token';
COMMENT ON COLUMN workshop_core.refresh_tokens.revoked_at IS 'Fecha de revocación (si el token fue invalidado)';