-- =========================================== -- 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)';