181 lines
6.8 KiB
PL/PgSQL
181 lines
6.8 KiB
PL/PgSQL
-- ============================================================================
|
|
-- RBAC Schema: Role Permissions Table
|
|
-- Maps permissions to roles
|
|
-- ============================================================================
|
|
|
|
-- ============================================================================
|
|
-- ROLE_PERMISSIONS TABLE
|
|
-- Junction table linking roles to their permissions
|
|
-- ============================================================================
|
|
|
|
CREATE TABLE IF NOT EXISTS rbac.role_permissions (
|
|
-- Primary key
|
|
id UUID PRIMARY KEY DEFAULT gen_random_uuid(),
|
|
|
|
-- Role reference
|
|
role_id UUID NOT NULL REFERENCES rbac.roles(id) ON DELETE CASCADE,
|
|
|
|
-- Permission reference
|
|
permission_id UUID NOT NULL REFERENCES rbac.permissions(id) ON DELETE CASCADE,
|
|
|
|
-- Grant type: allow or deny (for permission inheritance override)
|
|
grant_type VARCHAR(10) NOT NULL DEFAULT 'allow'
|
|
CHECK (grant_type IN ('allow', 'deny')),
|
|
|
|
-- Conditions for permission (JSON for field-level or conditional access)
|
|
conditions JSONB DEFAULT NULL,
|
|
|
|
-- Audit fields
|
|
created_at TIMESTAMPTZ NOT NULL DEFAULT CURRENT_TIMESTAMP,
|
|
created_by UUID REFERENCES users.users(id),
|
|
|
|
-- Constraints
|
|
CONSTRAINT uq_role_permission UNIQUE (role_id, permission_id)
|
|
);
|
|
|
|
-- ============================================================================
|
|
-- INDEXES
|
|
-- ============================================================================
|
|
|
|
CREATE INDEX IF NOT EXISTS idx_role_permissions_role_id ON rbac.role_permissions(role_id);
|
|
CREATE INDEX IF NOT EXISTS idx_role_permissions_permission_id ON rbac.role_permissions(permission_id);
|
|
CREATE INDEX IF NOT EXISTS idx_role_permissions_grant_type ON rbac.role_permissions(grant_type);
|
|
|
|
-- ============================================================================
|
|
-- FUNCTION: Assign default permissions to system roles
|
|
-- ============================================================================
|
|
|
|
CREATE OR REPLACE FUNCTION rbac.assign_default_role_permissions(p_tenant_id UUID)
|
|
RETURNS void AS $$
|
|
DECLARE
|
|
v_owner_role_id UUID;
|
|
v_admin_role_id UUID;
|
|
v_manager_role_id UUID;
|
|
v_member_role_id UUID;
|
|
v_viewer_role_id UUID;
|
|
v_perm RECORD;
|
|
BEGIN
|
|
-- Get role IDs
|
|
SELECT id INTO v_owner_role_id FROM rbac.roles WHERE tenant_id = p_tenant_id AND slug = 'owner';
|
|
SELECT id INTO v_admin_role_id FROM rbac.roles WHERE tenant_id = p_tenant_id AND slug = 'admin';
|
|
SELECT id INTO v_manager_role_id FROM rbac.roles WHERE tenant_id = p_tenant_id AND slug = 'manager';
|
|
SELECT id INTO v_member_role_id FROM rbac.roles WHERE tenant_id = p_tenant_id AND slug = 'member';
|
|
SELECT id INTO v_viewer_role_id FROM rbac.roles WHERE tenant_id = p_tenant_id AND slug = 'viewer';
|
|
|
|
-- Owner gets ALL permissions
|
|
FOR v_perm IN SELECT id FROM rbac.permissions WHERE is_active = true
|
|
LOOP
|
|
INSERT INTO rbac.role_permissions (role_id, permission_id)
|
|
VALUES (v_owner_role_id, v_perm.id)
|
|
ON CONFLICT (role_id, permission_id) DO NOTHING;
|
|
END LOOP;
|
|
|
|
-- Admin gets all except org:delete and org:billing:manage
|
|
FOR v_perm IN
|
|
SELECT id FROM rbac.permissions
|
|
WHERE is_active = true
|
|
AND code NOT IN ('org:delete', 'org:billing:manage')
|
|
LOOP
|
|
INSERT INTO rbac.role_permissions (role_id, permission_id)
|
|
VALUES (v_admin_role_id, v_perm.id)
|
|
ON CONFLICT (role_id, permission_id) DO NOTHING;
|
|
END LOOP;
|
|
|
|
-- Manager gets user viewing, role viewing, and standard features
|
|
FOR v_perm IN
|
|
SELECT id FROM rbac.permissions
|
|
WHERE is_active = true
|
|
AND code IN (
|
|
'org:read',
|
|
'users:read', 'users:invite',
|
|
'roles:read',
|
|
'wallet:read', 'wallet:deposit', 'wallet:withdraw',
|
|
'products:read', 'products:purchase',
|
|
'vip:read', 'vip:subscribe',
|
|
'agents:read', 'agents:allocate',
|
|
'predictions:read', 'predictions:purchase',
|
|
'reports:read'
|
|
)
|
|
LOOP
|
|
INSERT INTO rbac.role_permissions (role_id, permission_id)
|
|
VALUES (v_manager_role_id, v_perm.id)
|
|
ON CONFLICT (role_id, permission_id) DO NOTHING;
|
|
END LOOP;
|
|
|
|
-- Member gets standard user features
|
|
FOR v_perm IN
|
|
SELECT id FROM rbac.permissions
|
|
WHERE is_active = true
|
|
AND code IN (
|
|
'org:read',
|
|
'wallet:read', 'wallet:deposit', 'wallet:withdraw',
|
|
'products:read', 'products:purchase',
|
|
'vip:read', 'vip:subscribe',
|
|
'agents:read', 'agents:allocate',
|
|
'predictions:read', 'predictions:purchase'
|
|
)
|
|
LOOP
|
|
INSERT INTO rbac.role_permissions (role_id, permission_id)
|
|
VALUES (v_member_role_id, v_perm.id)
|
|
ON CONFLICT (role_id, permission_id) DO NOTHING;
|
|
END LOOP;
|
|
|
|
-- Viewer gets read-only access
|
|
FOR v_perm IN
|
|
SELECT id FROM rbac.permissions
|
|
WHERE is_active = true
|
|
AND code IN (
|
|
'org:read',
|
|
'wallet:read',
|
|
'products:read',
|
|
'vip:read',
|
|
'agents:read',
|
|
'predictions:read'
|
|
)
|
|
LOOP
|
|
INSERT INTO rbac.role_permissions (role_id, permission_id)
|
|
VALUES (v_viewer_role_id, v_perm.id)
|
|
ON CONFLICT (role_id, permission_id) DO NOTHING;
|
|
END LOOP;
|
|
END;
|
|
$$ LANGUAGE plpgsql;
|
|
|
|
-- ============================================================================
|
|
-- VIEW: Role with permissions
|
|
-- ============================================================================
|
|
|
|
CREATE OR REPLACE VIEW rbac.v_role_permissions AS
|
|
SELECT
|
|
r.id AS role_id,
|
|
r.tenant_id,
|
|
r.name AS role_name,
|
|
r.slug AS role_slug,
|
|
r.hierarchy_level,
|
|
p.id AS permission_id,
|
|
p.code AS permission_code,
|
|
p.name AS permission_name,
|
|
p.module,
|
|
p.action,
|
|
p.resource,
|
|
rp.grant_type,
|
|
rp.conditions
|
|
FROM rbac.roles r
|
|
JOIN rbac.role_permissions rp ON r.id = rp.role_id
|
|
JOIN rbac.permissions p ON rp.permission_id = p.id
|
|
WHERE r.is_active = true AND p.is_active = true;
|
|
|
|
-- ============================================================================
|
|
-- GRANTS
|
|
-- ============================================================================
|
|
|
|
GRANT SELECT, INSERT, DELETE ON rbac.role_permissions TO trading_user;
|
|
GRANT SELECT ON rbac.v_role_permissions TO trading_user;
|
|
|
|
-- ============================================================================
|
|
-- COMMENTS
|
|
-- ============================================================================
|
|
|
|
COMMENT ON TABLE rbac.role_permissions IS 'Junction table mapping permissions to roles';
|
|
COMMENT ON COLUMN rbac.role_permissions.grant_type IS 'allow = grants permission, deny = explicitly denies (for override)';
|
|
COMMENT ON COLUMN rbac.role_permissions.conditions IS 'JSON conditions for field-level or conditional access control';
|