159 lines
5.8 KiB
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)';
|