29 KiB
29 KiB
DDL Specification: core_rbac Schema
Identificacion
| Campo | Valor |
|---|---|
| Schema | core_rbac |
| Modulo | MGN-003 Roles/RBAC |
| Version | 1.0 |
| Fecha | 2025-12-05 |
| Estado | Ready |
Diagrama ER
erDiagram
roles ||--o{ role_permissions : has
roles ||--o{ user_roles : assigned_to
permissions ||--o{ role_permissions : granted_to
users ||--o{ user_roles : has
tenants ||--o{ roles : owns
roles {
uuid id PK
uuid tenant_id FK
string name
string slug
string description
boolean is_built_in
boolean is_active
timestamp created_at
timestamp updated_at
uuid created_by FK
uuid updated_by FK
timestamp deleted_at
uuid deleted_by FK
}
permissions {
uuid id PK
string code UK
string name
string description
string module
string parent_code FK
boolean is_deprecated
int sort_order
timestamp created_at
}
role_permissions {
uuid id PK
uuid role_id FK
uuid permission_id FK
timestamp created_at
uuid created_by FK
}
user_roles {
uuid id PK
uuid user_id FK
uuid role_id FK
timestamp assigned_at
uuid assigned_by FK
timestamp expires_at
}
Tablas
1. roles
Almacena los roles del sistema, tanto built-in como personalizados por tenant.
CREATE TABLE core_rbac.roles (
id UUID PRIMARY KEY DEFAULT gen_random_uuid(),
tenant_id UUID NOT NULL REFERENCES core_tenants.tenants(id),
name VARCHAR(50) NOT NULL,
slug VARCHAR(50) NOT NULL,
description VARCHAR(500),
is_built_in BOOLEAN NOT NULL DEFAULT false,
is_active BOOLEAN NOT NULL DEFAULT true,
created_at TIMESTAMPTZ NOT NULL DEFAULT CURRENT_TIMESTAMP,
updated_at TIMESTAMPTZ NOT NULL DEFAULT CURRENT_TIMESTAMP,
created_by UUID REFERENCES core_users.users(id),
updated_by UUID REFERENCES core_users.users(id),
deleted_at TIMESTAMPTZ,
deleted_by UUID REFERENCES core_users.users(id),
CONSTRAINT uq_roles_tenant_name UNIQUE (tenant_id, name) WHERE deleted_at IS NULL,
CONSTRAINT uq_roles_tenant_slug UNIQUE (tenant_id, slug) WHERE deleted_at IS NULL,
CONSTRAINT chk_roles_name_length CHECK (char_length(name) >= 3),
CONSTRAINT chk_roles_slug_format CHECK (slug ~ '^[a-z0-9_-]+$')
);
-- Indices
CREATE INDEX idx_roles_tenant_id ON core_rbac.roles(tenant_id) WHERE deleted_at IS NULL;
CREATE INDEX idx_roles_slug ON core_rbac.roles(slug) WHERE deleted_at IS NULL;
CREATE INDEX idx_roles_is_built_in ON core_rbac.roles(is_built_in);
CREATE INDEX idx_roles_created_at ON core_rbac.roles(created_at DESC);
-- Trigger para updated_at
CREATE TRIGGER trg_roles_updated_at
BEFORE UPDATE ON core_rbac.roles
FOR EACH ROW
EXECUTE FUNCTION update_updated_at_column();
-- Comentarios
COMMENT ON TABLE core_rbac.roles IS 'Roles del sistema para RBAC';
COMMENT ON COLUMN core_rbac.roles.is_built_in IS 'true para roles del sistema (admin, user, etc.)';
COMMENT ON COLUMN core_rbac.roles.slug IS 'Identificador URL-friendly, unico por tenant';
2. permissions
Catalogo maestro de permisos del sistema. Son globales (no por tenant).
CREATE TABLE core_rbac.permissions (
id UUID PRIMARY KEY DEFAULT gen_random_uuid(),
code VARCHAR(100) NOT NULL UNIQUE,
name VARCHAR(100) NOT NULL,
description VARCHAR(500),
module VARCHAR(50) NOT NULL,
parent_code VARCHAR(100) REFERENCES core_rbac.permissions(code),
is_deprecated BOOLEAN NOT NULL DEFAULT false,
sort_order INT NOT NULL DEFAULT 0,
created_at TIMESTAMPTZ NOT NULL DEFAULT CURRENT_TIMESTAMP,
CONSTRAINT chk_permissions_code_format CHECK (code ~ '^[a-z]+:[a-z_]+(:?:[a-z_]+)?$|^[a-z]+:\*$')
);
-- Indices
CREATE INDEX idx_permissions_module ON core_rbac.permissions(module);
CREATE INDEX idx_permissions_parent ON core_rbac.permissions(parent_code);
CREATE INDEX idx_permissions_deprecated ON core_rbac.permissions(is_deprecated);
-- Comentarios
COMMENT ON TABLE core_rbac.permissions IS 'Catalogo de permisos del sistema';
COMMENT ON COLUMN core_rbac.permissions.code IS 'Formato: modulo:accion o modulo:recurso:accion';
COMMENT ON COLUMN core_rbac.permissions.parent_code IS 'Para permisos wildcard (users:* -> users:read)';
3. role_permissions
Tabla de union entre roles y permisos (M:N).
CREATE TABLE core_rbac.role_permissions (
id UUID PRIMARY KEY DEFAULT gen_random_uuid(),
role_id UUID NOT NULL REFERENCES core_rbac.roles(id) ON DELETE CASCADE,
permission_id UUID NOT NULL REFERENCES core_rbac.permissions(id) ON DELETE CASCADE,
created_at TIMESTAMPTZ NOT NULL DEFAULT CURRENT_TIMESTAMP,
created_by UUID REFERENCES core_users.users(id),
CONSTRAINT uq_role_permissions UNIQUE (role_id, permission_id)
);
-- Indices
CREATE INDEX idx_role_permissions_role ON core_rbac.role_permissions(role_id);
CREATE INDEX idx_role_permissions_permission ON core_rbac.role_permissions(permission_id);
-- Comentarios
COMMENT ON TABLE core_rbac.role_permissions IS 'Asignacion de permisos a roles';
4. user_roles
Tabla de union entre usuarios y roles (M:N).
CREATE TABLE core_rbac.user_roles (
id UUID PRIMARY KEY DEFAULT gen_random_uuid(),
user_id UUID NOT NULL REFERENCES core_users.users(id) ON DELETE CASCADE,
role_id UUID NOT NULL REFERENCES core_rbac.roles(id) ON DELETE CASCADE,
assigned_at TIMESTAMPTZ NOT NULL DEFAULT CURRENT_TIMESTAMP,
assigned_by UUID REFERENCES core_users.users(id),
expires_at TIMESTAMPTZ,
CONSTRAINT uq_user_roles UNIQUE (user_id, role_id)
);
-- Indices
CREATE INDEX idx_user_roles_user ON core_rbac.user_roles(user_id);
CREATE INDEX idx_user_roles_role ON core_rbac.user_roles(role_id);
CREATE INDEX idx_user_roles_expires ON core_rbac.user_roles(expires_at) WHERE expires_at IS NOT NULL;
-- Comentarios
COMMENT ON TABLE core_rbac.user_roles IS 'Asignacion de roles a usuarios';
COMMENT ON COLUMN core_rbac.user_roles.expires_at IS 'Roles temporales con fecha de expiracion';
Data Seed: Roles Built-in
-- Roles del sistema (se crean para cada tenant nuevo)
-- Ref: Odoo base_groups.xml - group_user, group_portal, group_public, group_system, group_erp_manager
INSERT INTO core_rbac.roles (tenant_id, name, slug, description, is_built_in) VALUES
(:tenant_id, 'Super Administrador', 'super_admin', 'Acceso total al sistema (Ref: Odoo group_system)', true),
(:tenant_id, 'Propietario', 'tenant_owner', 'Propietario de la cuenta, gestiona billing y usuarios (MGN-015)', true),
(:tenant_id, 'Administrador', 'admin', 'Gestion completa del tenant (Ref: Odoo group_erp_manager)', true),
(:tenant_id, 'Gerente', 'manager', 'Supervision operativa y reportes', true),
(:tenant_id, 'Usuario', 'user', 'Acceso basico al sistema (Ref: Odoo group_user)', true),
(:tenant_id, 'Agente WhatsApp', 'whatsapp_agent', 'Atiende conversaciones de WhatsApp (MGN-017)', true),
(:tenant_id, 'Usuario Portal', 'portal_user', 'Usuario externo con acceso limitado (Ref: Odoo group_portal)', true),
(:tenant_id, 'Invitado', 'guest', 'Acceso de solo lectura limitado (Ref: Odoo group_public)', true);
Data Seed: Permisos del Sistema
-- Permisos de Auth (MGN-001)
INSERT INTO core_rbac.permissions (code, name, description, module, sort_order) VALUES
('auth:sessions:read', 'Ver sesiones', 'Ver sesiones activas del usuario', 'auth', 10),
('auth:sessions:revoke', 'Revocar sesiones', 'Cerrar sesiones activas', 'auth', 20);
-- Permisos de Users (MGN-002)
INSERT INTO core_rbac.permissions (code, name, description, module, sort_order) VALUES
('users:*', 'Todos los permisos de usuarios', 'Acceso completo a gestion de usuarios', 'users', 0),
('users:read', 'Leer usuarios', 'Ver listado y detalle de usuarios', 'users', 10),
('users:create', 'Crear usuarios', 'Crear nuevos usuarios', 'users', 20),
('users:update', 'Actualizar usuarios', 'Modificar datos de usuarios', 'users', 30),
('users:delete', 'Eliminar usuarios', 'Eliminar usuarios (soft delete)', 'users', 40),
('users:activate', 'Activar/Desactivar', 'Cambiar estado de usuarios', 'users', 50),
('users:export', 'Exportar usuarios', 'Exportar lista de usuarios a CSV', 'users', 60),
('users:import', 'Importar usuarios', 'Importar usuarios desde CSV', 'users', 70);
-- Establecer parent para wildcards
UPDATE core_rbac.permissions SET parent_code = 'users:*' WHERE module = 'users' AND code != 'users:*';
-- Permisos de Roles (MGN-003)
INSERT INTO core_rbac.permissions (code, name, description, module, sort_order) VALUES
('roles:*', 'Todos los permisos de roles', 'Acceso completo a gestion de roles', 'roles', 0),
('roles:read', 'Leer roles', 'Ver listado y detalle de roles', 'roles', 10),
('roles:create', 'Crear roles', 'Crear nuevos roles personalizados', 'roles', 20),
('roles:update', 'Actualizar roles', 'Modificar roles existentes', 'roles', 30),
('roles:delete', 'Eliminar roles', 'Eliminar roles personalizados', 'roles', 40),
('roles:assign', 'Asignar roles', 'Asignar roles a usuarios', 'roles', 50),
('permissions:read', 'Ver permisos', 'Ver catalogo de permisos', 'roles', 60);
UPDATE core_rbac.permissions SET parent_code = 'roles:*' WHERE module = 'roles' AND code NOT IN ('roles:*', 'permissions:read');
-- Permisos de Tenants (MGN-004)
INSERT INTO core_rbac.permissions (code, name, description, module, sort_order) VALUES
('tenants:read', 'Ver tenant', 'Ver configuracion del tenant', 'tenants', 10),
('tenants:update', 'Actualizar tenant', 'Modificar configuracion del tenant', 'tenants', 20),
('tenants:billing', 'Facturacion', 'Gestionar facturacion del tenant', 'tenants', 30);
-- Permisos de Settings (MGN-006)
INSERT INTO core_rbac.permissions (code, name, description, module, sort_order) VALUES
('settings:read', 'Ver configuracion', 'Ver configuracion del sistema', 'settings', 10),
('settings:update', 'Modificar configuracion', 'Cambiar configuracion del sistema', 'settings', 20);
-- Permisos de Audit (MGN-007)
INSERT INTO core_rbac.permissions (code, name, description, module, sort_order) VALUES
('audit:read', 'Ver auditoria', 'Ver logs de auditoria', 'audit', 10),
('audit:export', 'Exportar auditoria', 'Exportar logs de auditoria', 'audit', 20);
-- Permisos de Reports (MGN-009)
INSERT INTO core_rbac.permissions (code, name, description, module, sort_order) VALUES
('reports:*', 'Todos los permisos de reportes', 'Acceso completo a reportes', 'reports', 0),
('reports:read', 'Ver reportes', 'Ver reportes del sistema', 'reports', 10),
('reports:create', 'Crear reportes', 'Crear reportes personalizados', 'reports', 20),
('reports:export', 'Exportar reportes', 'Exportar reportes a PDF/Excel', 'reports', 30),
('reports:schedule', 'Programar reportes', 'Programar envio de reportes', 'reports', 40);
UPDATE core_rbac.permissions SET parent_code = 'reports:*' WHERE module = 'reports' AND code != 'reports:*';
-- Permisos de Financial (MGN-010)
INSERT INTO core_rbac.permissions (code, name, description, module, sort_order) VALUES
('financial:*', 'Todos los permisos financieros', 'Acceso completo a modulo financiero', 'financial', 0),
('financial:accounts:read', 'Ver cuentas', 'Ver plan de cuentas', 'financial', 10),
('financial:accounts:manage', 'Gestionar cuentas', 'Administrar plan de cuentas', 'financial', 20),
('financial:transactions:read', 'Ver transacciones', 'Ver movimientos contables', 'financial', 30),
('financial:transactions:create', 'Crear transacciones', 'Registrar movimientos', 'financial', 40),
('financial:transactions:approve', 'Aprobar transacciones', 'Aprobar movimientos pendientes', 'financial', 50),
('financial:reports:read', 'Reportes financieros', 'Ver reportes financieros', 'financial', 60);
UPDATE core_rbac.permissions SET parent_code = 'financial:*' WHERE module = 'financial' AND code != 'financial:*';
-- Permisos de Inventory (MGN-011)
INSERT INTO core_rbac.permissions (code, name, description, module, sort_order) VALUES
('inventory:*', 'Todos los permisos de inventario', 'Acceso completo a inventario', 'inventory', 0),
('inventory:products:read', 'Ver productos', 'Ver catalogo de productos', 'inventory', 10),
('inventory:products:create', 'Crear productos', 'Agregar productos al catalogo', 'inventory', 20),
('inventory:products:update', 'Actualizar productos', 'Modificar productos', 'inventory', 30),
('inventory:products:delete', 'Eliminar productos', 'Eliminar productos del catalogo', 'inventory', 40),
('inventory:stock:read', 'Ver stock', 'Ver niveles de inventario', 'inventory', 50),
('inventory:stock:adjust', 'Ajustar stock', 'Realizar ajustes de inventario', 'inventory', 60),
('inventory:movements:read', 'Ver movimientos', 'Ver historial de movimientos', 'inventory', 70),
('inventory:movements:create', 'Crear movimientos', 'Registrar entradas/salidas', 'inventory', 80);
UPDATE core_rbac.permissions SET parent_code = 'inventory:*' WHERE module = 'inventory' AND code != 'inventory:*';
-- Permisos de Portal (para usuarios externos) - Ref: Odoo portal module
INSERT INTO core_rbac.permissions (code, name, description, module, sort_order) VALUES
('portal:profile:read', 'Ver perfil propio', 'Ver datos del propio perfil', 'portal', 10),
('portal:profile:update', 'Actualizar perfil propio', 'Modificar datos del propio perfil', 'portal', 20),
('portal:documents:read', 'Ver documentos propios', 'Ver documentos asociados al usuario', 'portal', 30),
('portal:orders:read', 'Ver ordenes propias', 'Ver historial de ordenes', 'portal', 40),
('portal:invoices:read', 'Ver facturas propias', 'Ver facturas emitidas', 'portal', 50),
('portal:tickets:read', 'Ver tickets propios', 'Ver tickets de soporte', 'portal', 60),
('portal:tickets:create', 'Crear tickets', 'Crear nuevos tickets de soporte', 'portal', 70);
-- Permisos de Billing (MGN-015)
INSERT INTO core_rbac.permissions (code, name, description, module, sort_order) VALUES
('billing:*', 'Todos los permisos de billing', 'Acceso completo a facturacion SaaS', 'billing', 0),
('billing:subscription:read', 'Ver suscripcion', 'Ver plan y suscripcion actual', 'billing', 10),
('billing:subscription:manage', 'Gestionar suscripcion', 'Cambiar plan, cancelar, reactivar', 'billing', 20),
('billing:seats:manage', 'Gestionar asientos', 'Agregar/remover usuarios del plan', 'billing', 30),
('billing:payment_methods:read', 'Ver metodos de pago', 'Ver tarjetas y metodos guardados', 'billing', 40),
('billing:payment_methods:manage', 'Gestionar metodos de pago', 'Agregar/eliminar metodos de pago', 'billing', 50),
('billing:invoices:read', 'Ver facturas SaaS', 'Ver historial de facturas de la plataforma', 'billing', 60),
('billing:invoices:download', 'Descargar facturas', 'Descargar PDF/CFDI de facturas', 'billing', 70),
('billing:usage:read', 'Ver uso', 'Ver metricas de consumo del plan', 'billing', 80);
UPDATE core_rbac.permissions SET parent_code = 'billing:*' WHERE module = 'billing' AND code != 'billing:*';
-- Permisos de Payment Integrations (MGN-016)
INSERT INTO core_rbac.permissions (code, name, description, module, sort_order) VALUES
('payments:*', 'Todos los permisos de pagos', 'Acceso completo a integraciones de pago', 'payments', 0),
('payments:providers:read', 'Ver proveedores', 'Ver integraciones de pago configuradas', 'payments', 10),
('payments:providers:configure', 'Configurar proveedores', 'Conectar MercadoPago, Clip, Stripe', 'payments', 20),
('payments:terminals:read', 'Ver terminales', 'Ver terminales registradas', 'payments', 30),
('payments:terminals:manage', 'Gestionar terminales', 'Agregar/configurar terminales', 'payments', 40),
('payments:transactions:read', 'Ver transacciones', 'Ver historial de cobros', 'payments', 50),
('payments:transactions:process', 'Procesar pagos', 'Cobrar en terminal/gateway', 'payments', 60),
('payments:transactions:refund', 'Reembolsar', 'Procesar devoluciones', 'payments', 70),
('payments:reconciliation:read', 'Ver conciliacion', 'Ver estado de conciliacion', 'payments', 80),
('payments:reconciliation:manage', 'Gestionar conciliacion', 'Conciliar transacciones', 'payments', 90);
UPDATE core_rbac.permissions SET parent_code = 'payments:*' WHERE module = 'payments' AND code != 'payments:*';
-- Permisos de WhatsApp (MGN-017)
INSERT INTO core_rbac.permissions (code, name, description, module, sort_order) VALUES
('whatsapp:*', 'Todos los permisos de WhatsApp', 'Acceso completo a WhatsApp Business', 'whatsapp', 0),
('whatsapp:accounts:read', 'Ver cuentas', 'Ver cuentas de WhatsApp conectadas', 'whatsapp', 10),
('whatsapp:accounts:configure', 'Configurar cuentas', 'Conectar/desconectar cuentas WA', 'whatsapp', 20),
('whatsapp:templates:read', 'Ver templates', 'Ver plantillas de mensajes', 'whatsapp', 30),
('whatsapp:templates:manage', 'Gestionar templates', 'Crear/editar plantillas', 'whatsapp', 40),
('whatsapp:conversations:read', 'Ver conversaciones', 'Ver inbox de mensajes', 'whatsapp', 50),
('whatsapp:conversations:reply', 'Responder mensajes', 'Enviar mensajes en conversaciones', 'whatsapp', 60),
('whatsapp:conversations:assign', 'Asignar conversaciones', 'Asignar a otros agentes', 'whatsapp', 70),
('whatsapp:bulk:send', 'Envio masivo', 'Enviar campanas de marketing', 'whatsapp', 80),
('whatsapp:chatbot:read', 'Ver chatbot', 'Ver flujos de chatbot', 'whatsapp', 90),
('whatsapp:chatbot:manage', 'Gestionar chatbot', 'Crear/editar flujos', 'whatsapp', 100),
('whatsapp:analytics:read', 'Ver analiticas', 'Ver metricas de WhatsApp', 'whatsapp', 110);
UPDATE core_rbac.permissions SET parent_code = 'whatsapp:*' WHERE module = 'whatsapp' AND code != 'whatsapp:*';
-- Permisos de AI Agents (MGN-018)
INSERT INTO core_rbac.permissions (code, name, description, module, sort_order) VALUES
('ai_agents:*', 'Todos los permisos de IA', 'Acceso completo a agentes de IA', 'ai_agents', 0),
('ai_agents:agents:read', 'Ver agentes', 'Ver agentes configurados', 'ai_agents', 10),
('ai_agents:agents:manage', 'Gestionar agentes', 'Crear/editar/eliminar agentes', 'ai_agents', 20),
('ai_agents:kb:read', 'Ver bases de conocimiento', 'Ver KBs del tenant', 'ai_agents', 30),
('ai_agents:kb:manage', 'Gestionar KB', 'Crear/editar KBs y documentos', 'ai_agents', 40),
('ai_agents:kb:upload', 'Subir documentos', 'Agregar documentos a KB', 'ai_agents', 50),
('ai_agents:tools:read', 'Ver herramientas', 'Ver tools disponibles', 'ai_agents', 60),
('ai_agents:tools:manage', 'Gestionar herramientas', 'Configurar tools para agentes', 'ai_agents', 70),
('ai_agents:conversations:read', 'Ver conversaciones IA', 'Ver historial de chats con IA', 'ai_agents', 80),
('ai_agents:feedback:read', 'Ver feedback', 'Ver calificaciones de respuestas', 'ai_agents', 90),
('ai_agents:feedback:manage', 'Gestionar feedback', 'Corregir/entrenar agente', 'ai_agents', 100),
('ai_agents:analytics:read', 'Ver analiticas IA', 'Ver metricas de agentes', 'ai_agents', 110),
('ai_agents:usage:read', 'Ver consumo tokens', 'Ver uso de tokens de IA', 'ai_agents', 120);
UPDATE core_rbac.permissions SET parent_code = 'ai_agents:*' WHERE module = 'ai_agents' AND code != 'ai_agents:*';
Data Seed: Permisos por Rol Built-in
-- Funcion helper para asignar permisos
CREATE OR REPLACE FUNCTION core_rbac.assign_permissions_to_role(
p_tenant_id UUID,
p_role_slug VARCHAR,
p_permission_codes TEXT[]
) RETURNS void AS $$
DECLARE
v_role_id UUID;
v_permission_id UUID;
v_code TEXT;
BEGIN
SELECT id INTO v_role_id FROM core_rbac.roles
WHERE tenant_id = p_tenant_id AND slug = p_role_slug;
FOREACH v_code IN ARRAY p_permission_codes LOOP
SELECT id INTO v_permission_id FROM core_rbac.permissions WHERE code = v_code;
IF v_permission_id IS NOT NULL THEN
INSERT INTO core_rbac.role_permissions (role_id, permission_id)
VALUES (v_role_id, v_permission_id)
ON CONFLICT DO NOTHING;
END IF;
END LOOP;
END;
$$ LANGUAGE plpgsql;
-- Super Admin: Todos los permisos (wildcard)
SELECT core_rbac.assign_permissions_to_role(:tenant_id, 'super_admin', ARRAY[
'users:*', 'roles:*', 'permissions:read', 'tenants:read', 'tenants:update', 'tenants:billing',
'settings:read', 'settings:update', 'audit:read', 'audit:export',
'reports:*', 'financial:*', 'inventory:*',
'billing:*', 'payments:*', 'whatsapp:*', 'ai_agents:*'
]);
-- Tenant Owner: Propietario de cuenta (MGN-015)
SELECT core_rbac.assign_permissions_to_role(:tenant_id, 'tenant_owner', ARRAY[
'users:*', 'roles:read', 'roles:assign',
'tenants:read', 'tenants:update', 'tenants:billing',
'billing:*',
'payments:providers:read', 'payments:providers:configure',
'whatsapp:accounts:read', 'whatsapp:accounts:configure', 'whatsapp:analytics:read',
'ai_agents:agents:read', 'ai_agents:usage:read', 'ai_agents:analytics:read'
]);
-- Admin: Gestion del tenant
SELECT core_rbac.assign_permissions_to_role(:tenant_id, 'admin', ARRAY[
'users:*', 'roles:read', 'roles:create', 'roles:update', 'roles:delete', 'roles:assign',
'permissions:read', 'tenants:read', 'tenants:update',
'settings:read', 'settings:update', 'audit:read',
'reports:read', 'reports:export',
'payments:*', 'whatsapp:*', 'ai_agents:*'
]);
-- Manager: Supervision
SELECT core_rbac.assign_permissions_to_role(:tenant_id, 'manager', ARRAY[
'users:read', 'roles:read', 'permissions:read',
'audit:read', 'reports:read', 'reports:export',
'financial:accounts:read', 'financial:transactions:read', 'financial:reports:read',
'inventory:products:read', 'inventory:stock:read', 'inventory:movements:read',
'payments:transactions:read', 'payments:reconciliation:read',
'whatsapp:conversations:read', 'whatsapp:analytics:read',
'ai_agents:conversations:read', 'ai_agents:feedback:read', 'ai_agents:analytics:read'
]);
-- User: Acceso basico
SELECT core_rbac.assign_permissions_to_role(:tenant_id, 'user', ARRAY[
'reports:read',
'payments:transactions:read'
]);
-- WhatsApp Agent: Atiende conversaciones (MGN-017)
SELECT core_rbac.assign_permissions_to_role(:tenant_id, 'whatsapp_agent', ARRAY[
'whatsapp:conversations:read', 'whatsapp:conversations:reply',
'whatsapp:templates:read'
]);
-- Portal User: Acceso limitado para usuarios externos (Ref: Odoo group_portal)
SELECT core_rbac.assign_permissions_to_role(:tenant_id, 'portal_user', ARRAY[
'portal:profile:read', 'portal:profile:update',
'portal:documents:read', 'portal:orders:read',
'portal:invoices:read', 'portal:tickets:read', 'portal:tickets:create'
]);
-- Guest: Solo lectura minima (Ref: Odoo group_public)
SELECT core_rbac.assign_permissions_to_role(:tenant_id, 'guest', ARRAY[
-- Sin permisos especificos, solo acceso a dashboard publico
]);
Row Level Security (RLS)
-- Habilitar RLS
ALTER TABLE core_rbac.roles ENABLE ROW LEVEL SECURITY;
ALTER TABLE core_rbac.role_permissions ENABLE ROW LEVEL SECURITY;
ALTER TABLE core_rbac.user_roles ENABLE ROW LEVEL SECURITY;
-- Politicas para roles
CREATE POLICY roles_tenant_isolation ON core_rbac.roles
FOR ALL
USING (tenant_id = current_setting('app.tenant_id')::uuid);
CREATE POLICY roles_select_built_in ON core_rbac.roles
FOR SELECT
USING (is_built_in = true);
-- Politicas para role_permissions (via rol)
CREATE POLICY role_permissions_tenant_isolation ON core_rbac.role_permissions
FOR ALL
USING (
role_id IN (
SELECT id FROM core_rbac.roles
WHERE tenant_id = current_setting('app.tenant_id')::uuid
)
);
-- Politicas para user_roles (via usuario)
CREATE POLICY user_roles_tenant_isolation ON core_rbac.user_roles
FOR ALL
USING (
user_id IN (
SELECT id FROM core_users.users
WHERE tenant_id = current_setting('app.tenant_id')::uuid
)
);
Funciones de Utilidad
Verificar Permiso de Usuario
CREATE OR REPLACE FUNCTION core_rbac.user_has_permission(
p_user_id UUID,
p_permission_code VARCHAR
) RETURNS BOOLEAN AS $$
DECLARE
v_has_permission BOOLEAN;
v_module VARCHAR;
BEGIN
-- Verificar permiso directo
SELECT EXISTS (
SELECT 1
FROM core_rbac.user_roles ur
JOIN core_rbac.role_permissions rp ON rp.role_id = ur.role_id
JOIN core_rbac.permissions p ON p.id = rp.permission_id
WHERE ur.user_id = p_user_id
AND (ur.expires_at IS NULL OR ur.expires_at > NOW())
AND p.code = p_permission_code
) INTO v_has_permission;
IF v_has_permission THEN
RETURN true;
END IF;
-- Verificar wildcard del modulo
v_module := split_part(p_permission_code, ':', 1);
SELECT EXISTS (
SELECT 1
FROM core_rbac.user_roles ur
JOIN core_rbac.role_permissions rp ON rp.role_id = ur.role_id
JOIN core_rbac.permissions p ON p.id = rp.permission_id
WHERE ur.user_id = p_user_id
AND (ur.expires_at IS NULL OR ur.expires_at > NOW())
AND p.code = v_module || ':*'
) INTO v_has_permission;
RETURN v_has_permission;
END;
$$ LANGUAGE plpgsql STABLE;
Obtener Permisos Efectivos de Usuario
CREATE OR REPLACE FUNCTION core_rbac.get_user_permissions(
p_user_id UUID
) RETURNS TABLE (permission_code VARCHAR, source_role VARCHAR) AS $$
BEGIN
RETURN QUERY
SELECT DISTINCT p.code, r.name
FROM core_rbac.user_roles ur
JOIN core_rbac.roles r ON r.id = ur.role_id
JOIN core_rbac.role_permissions rp ON rp.role_id = r.id
JOIN core_rbac.permissions p ON p.id = rp.permission_id
WHERE ur.user_id = p_user_id
AND (ur.expires_at IS NULL OR ur.expires_at > NOW())
AND r.is_active = true
AND p.is_deprecated = false
ORDER BY p.code;
END;
$$ LANGUAGE plpgsql STABLE;
Vistas
Vista: Roles con Conteo de Usuarios
CREATE VIEW core_rbac.vw_roles_summary AS
SELECT
r.id,
r.tenant_id,
r.name,
r.slug,
r.description,
r.is_built_in,
r.is_active,
COUNT(DISTINCT ur.user_id) AS users_count,
COUNT(DISTINCT rp.permission_id) AS permissions_count,
r.created_at
FROM core_rbac.roles r
LEFT JOIN core_rbac.user_roles ur ON ur.role_id = r.id
LEFT JOIN core_rbac.role_permissions rp ON rp.role_id = r.id
WHERE r.deleted_at IS NULL
GROUP BY r.id;
Vista: Permisos Agrupados por Modulo
CREATE VIEW core_rbac.vw_permissions_by_module AS
SELECT
module,
jsonb_agg(
jsonb_build_object(
'id', id,
'code', code,
'name', name,
'description', description,
'isDeprecated', is_deprecated
) ORDER BY sort_order
) AS permissions
FROM core_rbac.permissions
WHERE is_deprecated = false
GROUP BY module
ORDER BY module;
Resumen de Tablas
| Tabla | Columnas | Descripcion |
|---|---|---|
| roles | 12 | Roles del sistema (built-in y custom) |
| permissions | 9 | Catalogo maestro de permisos |
| role_permissions | 5 | Union M:N roles-permisos |
| user_roles | 6 | Union M:N usuarios-roles |
Total: 4 tablas, 32 columnas
Resumen de Roles Built-in
| Rol | Slug | Descripcion |
|---|---|---|
| Super Administrador | super_admin | Acceso total al sistema |
| Propietario | tenant_owner | Gestiona billing y usuarios (MGN-015) |
| Administrador | admin | Gestion completa del tenant |
| Gerente | manager | Supervision operativa y reportes |
| Usuario | user | Acceso basico al sistema |
| Agente WhatsApp | whatsapp_agent | Atiende conversaciones (MGN-017) |
| Usuario Portal | portal_user | Usuario externo con acceso limitado |
| Invitado | guest | Solo lectura limitada |
Resumen de Permisos por Modulo
| Modulo | Permisos | Descripcion |
|---|---|---|
| auth | 2 | Sesiones y tokens |
| users | 8 | Gestion de usuarios |
| roles | 7 | Roles y permisos |
| tenants | 3 | Configuracion tenant |
| settings | 2 | Configuracion sistema |
| audit | 2 | Logs de auditoria |
| reports | 5 | Reportes |
| financial | 7 | Modulo financiero |
| inventory | 9 | Inventario |
| portal | 7 | Usuarios externos |
| billing | 9 | Billing SaaS (MGN-015) |
| payments | 10 | Pagos POS (MGN-016) |
| 12 | WhatsApp Business (MGN-017) | |
| ai_agents | 13 | AI Agents (MGN-018) |
Total: 96 permisos
Historial
| Version | Fecha | Autor | Cambios |
|---|---|---|---|
| 1.0 | 2025-12-05 | System | Creacion inicial |
| 1.1 | 2025-12-05 | System | Agregar rol portal_user y permisos portal:* (Ref: Odoo group_portal) |
| 1.2 | 2025-12-05 | System | Roles: tenant_owner, whatsapp_agent. Permisos: billing:, payments:, whatsapp:, ai_agents: (MGN-015/016/017/018) |