-- ============================================================================ -- RBAC Schema: Roles Table -- Role-Based Access Control for Trading Platform SaaS -- ============================================================================ -- Create RBAC schema if not exists CREATE SCHEMA IF NOT EXISTS rbac; -- Grant usage GRANT USAGE ON SCHEMA rbac TO trading_user; -- ============================================================================ -- ROLES TABLE -- Defines roles within a tenant organization -- ============================================================================ CREATE TABLE IF NOT EXISTS rbac.roles ( -- Primary key id UUID PRIMARY KEY DEFAULT gen_random_uuid(), -- Tenant relationship (multi-tenancy) tenant_id UUID NOT NULL REFERENCES tenants.tenants(id) ON DELETE CASCADE, -- Role information name VARCHAR(100) NOT NULL, slug VARCHAR(100) NOT NULL, description TEXT, -- Role type: system (predefined) or custom (tenant-created) role_type VARCHAR(20) NOT NULL DEFAULT 'custom' CHECK (role_type IN ('system', 'custom')), -- Hierarchy level (lower = more permissions, 0 = super admin) hierarchy_level INTEGER NOT NULL DEFAULT 100, -- Status is_active BOOLEAN NOT NULL DEFAULT true, -- Role settings (JSON for extensibility) settings JSONB NOT NULL DEFAULT '{}'::jsonb, -- Audit fields created_at TIMESTAMPTZ NOT NULL DEFAULT CURRENT_TIMESTAMP, updated_at TIMESTAMPTZ NOT NULL DEFAULT CURRENT_TIMESTAMP, created_by UUID REFERENCES users.users(id), updated_by UUID REFERENCES users.users(id), -- Constraints CONSTRAINT uq_roles_tenant_slug UNIQUE (tenant_id, slug), CONSTRAINT uq_roles_tenant_name UNIQUE (tenant_id, name) ); -- ============================================================================ -- INDEXES -- ============================================================================ CREATE INDEX IF NOT EXISTS idx_roles_tenant_id ON rbac.roles(tenant_id); CREATE INDEX IF NOT EXISTS idx_roles_slug ON rbac.roles(slug); CREATE INDEX IF NOT EXISTS idx_roles_role_type ON rbac.roles(role_type); CREATE INDEX IF NOT EXISTS idx_roles_is_active ON rbac.roles(is_active); CREATE INDEX IF NOT EXISTS idx_roles_hierarchy ON rbac.roles(tenant_id, hierarchy_level); -- ============================================================================ -- ROW LEVEL SECURITY -- ============================================================================ ALTER TABLE rbac.roles ENABLE ROW LEVEL SECURITY; -- Policy: Users can only see roles in their tenant CREATE POLICY roles_tenant_isolation ON rbac.roles FOR ALL USING (tenant_id = current_setting('app.current_tenant_id', true)::uuid); -- ============================================================================ -- TRIGGERS -- ============================================================================ -- Auto-update updated_at timestamp CREATE OR REPLACE FUNCTION rbac.update_roles_timestamp() RETURNS TRIGGER AS $$ BEGIN NEW.updated_at = CURRENT_TIMESTAMP; RETURN NEW; END; $$ LANGUAGE plpgsql; CREATE TRIGGER trg_roles_updated_at BEFORE UPDATE ON rbac.roles FOR EACH ROW EXECUTE FUNCTION rbac.update_roles_timestamp(); -- ============================================================================ -- DEFAULT SYSTEM ROLES (inserted per tenant) -- These will be created when a new tenant is created -- ============================================================================ -- Function to create default roles for a tenant CREATE OR REPLACE FUNCTION rbac.create_default_roles(p_tenant_id UUID, p_owner_id UUID) RETURNS void AS $$ BEGIN -- Owner role (highest level) INSERT INTO rbac.roles (tenant_id, name, slug, description, role_type, hierarchy_level, created_by) VALUES ( p_tenant_id, 'Owner', 'owner', 'Full access to all features and settings. Can manage billing and delete organization.', 'system', 0, p_owner_id ); -- Admin role INSERT INTO rbac.roles (tenant_id, name, slug, description, role_type, hierarchy_level, created_by) VALUES ( p_tenant_id, 'Admin', 'admin', 'Administrative access. Can manage users, roles, and most settings.', 'system', 10, p_owner_id ); -- Manager role INSERT INTO rbac.roles (tenant_id, name, slug, description, role_type, hierarchy_level, created_by) VALUES ( p_tenant_id, 'Manager', 'manager', 'Can manage team members and view reports.', 'system', 50, p_owner_id ); -- Member role INSERT INTO rbac.roles (tenant_id, name, slug, description, role_type, hierarchy_level, created_by) VALUES ( p_tenant_id, 'Member', 'member', 'Standard user access. Can use platform features.', 'system', 100, p_owner_id ); -- Viewer role (read-only) INSERT INTO rbac.roles (tenant_id, name, slug, description, role_type, hierarchy_level, created_by) VALUES ( p_tenant_id, 'Viewer', 'viewer', 'Read-only access. Can view but not modify.', 'system', 200, p_owner_id ); END; $$ LANGUAGE plpgsql; -- ============================================================================ -- GRANTS -- ============================================================================ GRANT SELECT, INSERT, UPDATE, DELETE ON rbac.roles TO trading_user; -- ============================================================================ -- COMMENTS -- ============================================================================ COMMENT ON TABLE rbac.roles IS 'Roles for Role-Based Access Control within tenant organizations'; COMMENT ON COLUMN rbac.roles.role_type IS 'system = predefined roles, custom = tenant-created roles'; COMMENT ON COLUMN rbac.roles.hierarchy_level IS 'Lower value = higher permissions. Owner=0, Admin=10, etc.'; COMMENT ON COLUMN rbac.roles.settings IS 'JSON settings for role customization';