/** * RLS Policies - Usage Examples * * This file demonstrates how to use the centralized RLS policies * in various scenarios across the ERP-Suite. */ import { Pool } from 'pg'; import { applyTenantIsolationPolicy, applyAdminBypassPolicy, applyUserDataPolicy, applyCompleteRlsPolicies, applyCompletePoliciesForSchema, batchApplyRlsPolicies, isRlsEnabled, listRlsPolicies, getSchemaRlsStatus, setRlsContext, clearRlsContext, withRlsContext, RlsPolicyOptions, } from '@erp-suite/core'; // Database connection pool const pool = new Pool({ host: 'localhost', port: 5432, database: 'erp_suite', user: 'postgres', password: 'password', }); /** * EXAMPLE 1: Apply tenant isolation to a single table */ async function example1_singleTable() { console.log('Example 1: Apply tenant isolation to core.partners'); // Apply tenant isolation policy await applyTenantIsolationPolicy(pool, 'core', 'partners'); // Verify it was applied const enabled = await isRlsEnabled(pool, 'core', 'partners'); console.log(`RLS enabled: ${enabled}`); // List policies const status = await listRlsPolicies(pool, 'core', 'partners'); console.log(`Policies: ${status.policies.map(p => p.name).join(', ')}`); } /** * EXAMPLE 2: Apply complete policies (tenant + admin) to a table */ async function example2_completePolicies() { console.log('Example 2: Apply complete policies to inventory.products'); // Apply tenant isolation + admin bypass await applyCompleteRlsPolicies(pool, 'inventory', 'products'); // Check status const status = await listRlsPolicies(pool, 'inventory', 'products'); console.log(`Applied ${status.policies.length} policies:`); status.policies.forEach(p => { console.log(` - ${p.name} (${p.command})`); }); } /** * EXAMPLE 3: Apply policies to multiple tables in a schema */ async function example3_multipleTablesInSchema() { console.log('Example 3: Apply policies to multiple inventory tables'); const tables = ['products', 'warehouses', 'locations', 'lots', 'pickings']; await applyCompletePoliciesForSchema(pool, 'inventory', tables); console.log(`Applied RLS to ${tables.length} tables in inventory schema`); } /** * EXAMPLE 4: Batch apply with different configurations */ async function example4_batchApply() { console.log('Example 4: Batch apply with custom configurations'); const configs: RlsPolicyOptions[] = [ // Standard tables { schema: 'core', table: 'partners' }, { schema: 'core', table: 'addresses' }, { schema: 'core', table: 'notes' }, // Table without admin bypass { schema: 'financial', table: 'audit_logs', includeAdminBypass: false }, // Table with custom tenant column { schema: 'projects', table: 'tasks', tenantColumn: 'company_id' }, ]; await batchApplyRlsPolicies(pool, configs); console.log(`Applied RLS to ${configs.length} tables`); } /** * EXAMPLE 5: Apply user data policy for user-specific tables */ async function example5_userDataPolicy() { console.log('Example 5: Apply user data policy to projects.tasks'); // Apply user data policy (users can only see their own tasks) await applyUserDataPolicy(pool, 'projects', 'tasks', ['created_by', 'assigned_to']); const status = await listRlsPolicies(pool, 'projects', 'tasks'); console.log(`User data policy applied: ${status.policies[0]?.name}`); } /** * EXAMPLE 6: Get RLS status for entire schema */ async function example6_schemaStatus() { console.log('Example 6: Get RLS status for core schema'); const statuses = await getSchemaRlsStatus(pool, 'core'); console.log(`RLS Status for core schema:`); statuses.forEach(status => { const policyCount = status.policies.length; const rlsStatus = status.rlsEnabled ? 'enabled' : 'disabled'; console.log(` ${status.table}: RLS ${rlsStatus}, ${policyCount} policies`); }); } /** * EXAMPLE 7: Query data with RLS context */ async function example7_queryWithContext() { console.log('Example 7: Query data with RLS context'); const tenantId = 'aaaaaaaa-aaaa-aaaa-aaaa-aaaaaaaaaaaa'; const userId = 'bbbbbbbb-bbbb-bbbb-bbbb-bbbbbbbbbbbb'; // Method 1: Manual context setting await setRlsContext(pool, { tenantId, userId, userRole: 'user' }); const result1 = await pool.query('SELECT COUNT(*) FROM core.partners'); console.log(`Partners visible to user: ${result1.rows[0].count}`); await clearRlsContext(pool); // Method 2: Using withRlsContext helper const result2 = await withRlsContext( pool, { tenantId, userId, userRole: 'admin' }, async (client) => { return await client.query('SELECT COUNT(*) FROM core.partners'); } ); console.log(`Partners visible to admin: ${result2.rows[0].count}`); } /** * EXAMPLE 8: Migration script for a vertical */ async function example8_verticalMigration() { console.log('Example 8: Migration script for construccion vertical'); // Tables in construccion vertical const constructionTables = [ { schema: 'construction', table: 'projects' }, { schema: 'construction', table: 'estimates' }, { schema: 'construction', table: 'work_orders' }, { schema: 'construction', table: 'materials' }, { schema: 'hse', table: 'incidents' }, { schema: 'hse', table: 'inspections' }, ]; console.log('Applying RLS to construccion vertical tables...'); for (const { schema, table } of constructionTables) { try { await applyCompleteRlsPolicies(pool, schema, table, 'constructora_id'); console.log(` ✓ ${schema}.${table}`); } catch (error) { console.error(` ✗ ${schema}.${table}: ${error.message}`); } } console.log('Migration complete!'); } /** * EXAMPLE 9: Verify RLS isolation (testing) */ async function example9_testRlsIsolation() { console.log('Example 9: Test RLS isolation between tenants'); const tenant1 = 'tenant-1111-1111-1111-111111111111'; const tenant2 = 'tenant-2222-2222-2222-222222222222'; // Query as tenant 1 const result1 = await withRlsContext( pool, { tenantId: tenant1, userRole: 'user' }, async (client) => { return await client.query('SELECT COUNT(*) FROM core.partners'); } ); // Query as tenant 2 const result2 = await withRlsContext( pool, { tenantId: tenant2, userRole: 'user' }, async (client) => { return await client.query('SELECT COUNT(*) FROM core.partners'); } ); console.log(`Tenant 1 sees: ${result1.rows[0].count} partners`); console.log(`Tenant 2 sees: ${result2.rows[0].count} partners`); console.log('RLS isolation verified!'); } /** * EXAMPLE 10: Apply admin bypass for support team */ async function example10_adminBypass() { console.log('Example 10: Test admin bypass policy'); const tenantId = 'tenant-1111-1111-1111-111111111111'; // Query as regular user const userResult = await withRlsContext( pool, { tenantId, userRole: 'user' }, async (client) => { return await client.query('SELECT COUNT(*) FROM core.partners'); } ); // Query as admin (should see all tenants) const adminResult = await withRlsContext( pool, { userRole: 'admin' }, // No tenantId set async (client) => { return await client.query('SELECT COUNT(*) FROM core.partners'); } ); console.log(`User sees: ${userResult.rows[0].count} partners (own tenant only)`); console.log(`Admin sees: ${adminResult.rows[0].count} partners (all tenants)`); } /** * EXAMPLE 11: Apply RLS to ERP Core tables */ async function example11_erpCoreTables() { console.log('Example 11: Apply RLS to ERP Core tables'); const erpCoreConfigs: RlsPolicyOptions[] = [ // Core schema { schema: 'core', table: 'partners' }, { schema: 'core', table: 'addresses' }, { schema: 'core', table: 'product_categories' }, { schema: 'core', table: 'tags' }, { schema: 'core', table: 'sequences' }, { schema: 'core', table: 'attachments' }, { schema: 'core', table: 'notes' }, // Inventory schema { schema: 'inventory', table: 'products' }, { schema: 'inventory', table: 'warehouses' }, { schema: 'inventory', table: 'locations' }, { schema: 'inventory', table: 'lots' }, { schema: 'inventory', table: 'pickings' }, { schema: 'inventory', table: 'stock_moves' }, // Sales schema { schema: 'sales', table: 'sales_orders' }, { schema: 'sales', table: 'quotations' }, { schema: 'sales', table: 'pricelists' }, // Purchase schema { schema: 'purchase', table: 'purchase_orders' }, { schema: 'purchase', table: 'rfqs' }, { schema: 'purchase', table: 'vendor_pricelists' }, // Financial schema { schema: 'financial', table: 'accounts' }, { schema: 'financial', table: 'invoices' }, { schema: 'financial', table: 'payments' }, { schema: 'financial', table: 'journal_entries' }, // Projects schema { schema: 'projects', table: 'projects' }, { schema: 'projects', table: 'tasks' }, { schema: 'projects', table: 'timesheets' }, ]; console.log(`Applying RLS to ${erpCoreConfigs.length} ERP Core tables...`); let successCount = 0; let errorCount = 0; for (const config of erpCoreConfigs) { try { await applyCompleteRlsPolicies( pool, config.schema, config.table, config.tenantColumn || 'tenant_id', config.includeAdminBypass ?? true ); console.log(` ✓ ${config.schema}.${config.table}`); successCount++; } catch (error) { console.error(` ✗ ${config.schema}.${config.table}: ${error.message}`); errorCount++; } } console.log(`\nComplete! Success: ${successCount}, Errors: ${errorCount}`); } /** * EXAMPLE 12: Cleanup - Remove RLS from a table */ async function example12_cleanup() { console.log('Example 12: Remove RLS from a table'); // Import dropAllRlsPolicies const { dropAllRlsPolicies, disableRls } = await import('@erp-suite/core'); const schema = 'test'; const table = 'temp_table'; // Drop all policies const policyCount = await dropAllRlsPolicies(pool, schema, table); console.log(`Dropped ${policyCount} policies from ${schema}.${table}`); // Disable RLS await disableRls(pool, schema, table); console.log(`Disabled RLS on ${schema}.${table}`); // Verify const enabled = await isRlsEnabled(pool, schema, table); console.log(`RLS enabled: ${enabled}`); } /** * Main function - Run all examples */ async function main() { try { console.log('='.repeat(60)); console.log('RLS POLICIES - USAGE EXAMPLES'); console.log('='.repeat(60)); console.log(); // Uncomment the examples you want to run // await example1_singleTable(); // await example2_completePolicies(); // await example3_multipleTablesInSchema(); // await example4_batchApply(); // await example5_userDataPolicy(); // await example6_schemaStatus(); // await example7_queryWithContext(); // await example8_verticalMigration(); // await example9_testRlsIsolation(); // await example10_adminBypass(); // await example11_erpCoreTables(); // await example12_cleanup(); console.log(); console.log('='.repeat(60)); console.log('Examples completed successfully!'); console.log('='.repeat(60)); } catch (error) { console.error('Error running examples:', error); } finally { await pool.end(); } } // Run if executed directly if (require.main === module) { main(); } // Export examples for individual use export { example1_singleTable, example2_completePolicies, example3_multipleTablesInSchema, example4_batchApply, example5_userDataPolicy, example6_schemaStatus, example7_queryWithContext, example8_verticalMigration, example9_testRlsIsolation, example10_adminBypass, example11_erpCoreTables, example12_cleanup, };