153 lines
4.9 KiB
TypeScript
153 lines
4.9 KiB
TypeScript
/**
|
|
* Migration Example: Applying Centralized RLS Policies
|
|
*
|
|
* This migration demonstrates how to replace vertical-specific RLS policies
|
|
* with the centralized shared library policies.
|
|
*
|
|
* BEFORE: Each vertical had duplicated RLS functions and policies
|
|
* AFTER: Use shared-libs centralized RLS policies
|
|
*/
|
|
|
|
import { Pool } from 'pg';
|
|
import {
|
|
applyCompleteRlsPolicies,
|
|
applyCompletePoliciesForSchema,
|
|
batchApplyRlsPolicies,
|
|
getSchemaRlsStatus,
|
|
} from '@erp-suite/core';
|
|
|
|
/**
|
|
* Migration UP: Apply RLS policies to all tables
|
|
*/
|
|
export async function up(pool: Pool): Promise<void> {
|
|
console.log('Starting RLS migration...');
|
|
|
|
// STEP 1: Install RLS helper functions (run once per database)
|
|
console.log('Installing RLS helper functions...');
|
|
// Note: This would be done via SQL file first:
|
|
// psql -d database -f apps/shared-libs/core/database/policies/rls-policies.sql
|
|
|
|
// STEP 2: Apply RLS to ERP Core tables
|
|
console.log('Applying RLS to ERP Core tables...');
|
|
|
|
const coreSchemas = [
|
|
{
|
|
schema: 'core',
|
|
tables: ['partners', 'addresses', 'product_categories', 'tags', 'sequences', 'attachments', 'notes'],
|
|
},
|
|
{
|
|
schema: 'inventory',
|
|
tables: ['products', 'warehouses', 'locations', 'lots', 'pickings', 'stock_moves'],
|
|
},
|
|
{
|
|
schema: 'sales',
|
|
tables: ['sales_orders', 'quotations', 'pricelists'],
|
|
},
|
|
{
|
|
schema: 'purchase',
|
|
tables: ['purchase_orders', 'rfqs', 'vendor_pricelists'],
|
|
},
|
|
{
|
|
schema: 'financial',
|
|
tables: ['accounts', 'invoices', 'payments', 'journal_entries'],
|
|
},
|
|
];
|
|
|
|
for (const { schema, tables } of coreSchemas) {
|
|
await applyCompletePoliciesForSchema(pool, schema, tables);
|
|
console.log(` Applied RLS to ${schema} schema (${tables.length} tables)`);
|
|
}
|
|
|
|
// STEP 3: Apply RLS to vertical-specific tables
|
|
console.log('Applying RLS to vertical tables...');
|
|
|
|
// Example: Construccion vertical
|
|
const construccionTables = [
|
|
{ schema: 'construction', table: 'projects', tenantColumn: 'constructora_id' },
|
|
{ schema: 'construction', table: 'estimates', tenantColumn: 'constructora_id' },
|
|
{ schema: 'construction', table: 'work_orders', tenantColumn: 'constructora_id' },
|
|
{ schema: 'hse', table: 'incidents', tenantColumn: 'constructora_id' },
|
|
];
|
|
|
|
await batchApplyRlsPolicies(pool, construccionTables);
|
|
console.log(` Applied RLS to construccion vertical (${construccionTables.length} tables)`);
|
|
|
|
// Example: Mecanicas-diesel vertical
|
|
const mecanicasTables = [
|
|
{ schema: 'mechanics', table: 'work_orders' },
|
|
{ schema: 'mechanics', table: 'vehicles' },
|
|
{ schema: 'mechanics', table: 'parts' },
|
|
];
|
|
|
|
await batchApplyRlsPolicies(pool, mecanicasTables);
|
|
console.log(` Applied RLS to mecanicas-diesel vertical (${mecanicasTables.length} tables)`);
|
|
|
|
// STEP 4: Verify RLS application
|
|
console.log('Verifying RLS policies...');
|
|
const coreStatus = await getSchemaRlsStatus(pool, 'core');
|
|
const enabledCount = coreStatus.filter(s => s.rlsEnabled).length;
|
|
console.log(` Core schema: ${enabledCount}/${coreStatus.length} tables have RLS enabled`);
|
|
|
|
console.log('RLS migration completed successfully!');
|
|
}
|
|
|
|
/**
|
|
* Migration DOWN: Remove RLS policies
|
|
*/
|
|
export async function down(pool: Pool): Promise<void> {
|
|
console.log('Rolling back RLS migration...');
|
|
|
|
// Import cleanup functions
|
|
const { dropAllRlsPolicies, disableRls } = await import('@erp-suite/core');
|
|
|
|
// Remove RLS from all tables
|
|
const schemas = ['core', 'inventory', 'sales', 'purchase', 'financial', 'construction', 'hse', 'mechanics'];
|
|
|
|
for (const schema of schemas) {
|
|
const tablesQuery = `
|
|
SELECT table_name
|
|
FROM information_schema.tables
|
|
WHERE table_schema = $1
|
|
AND table_type = 'BASE TABLE'
|
|
`;
|
|
const result = await pool.query(tablesQuery, [schema]);
|
|
|
|
for (const row of result.rows) {
|
|
const table = row.table_name;
|
|
try {
|
|
const count = await dropAllRlsPolicies(pool, schema, table);
|
|
if (count > 0) {
|
|
await disableRls(pool, schema, table);
|
|
console.log(` Removed RLS from ${schema}.${table} (${count} policies)`);
|
|
}
|
|
} catch (error) {
|
|
console.error(` Error removing RLS from ${schema}.${table}:`, error.message);
|
|
}
|
|
}
|
|
}
|
|
|
|
console.log('RLS migration rollback completed!');
|
|
}
|
|
|
|
/**
|
|
* Example usage in a migration framework
|
|
*/
|
|
export default {
|
|
up,
|
|
down,
|
|
};
|
|
|
|
// TypeORM migration class format
|
|
export class ApplyRlsPolicies1234567890123 {
|
|
public async up(queryRunner: any): Promise<void> {
|
|
// Get pool from queryRunner or create one
|
|
const pool = queryRunner.connection.driver.master;
|
|
await up(pool);
|
|
}
|
|
|
|
public async down(queryRunner: any): Promise<void> {
|
|
const pool = queryRunner.connection.driver.master;
|
|
await down(pool);
|
|
}
|
|
}
|