Some checks are pending
Bidi Control Character Guard / bidi-control-guard (push) Waiting to run
Circular Dependency Check / Check for new circular dependencies (push) Waiting to run
Citus Migration Smoke / Combined migrations on single-node Citus (push) Waiting to run
E2E Fresh Install Tests / fresh-install-e2e (push) Waiting to run
ext-v2 guardrails / Run ext-v2 guard and ESLint (push) Waiting to run
Integration Tests / Check for relevant changes (push) Waiting to run
Integration Tests / ${{ (github.event_name == 'schedule' || github.event.inputs.suite == 'full') && 'Full integration suite' || 'Tier-1 integration subset' }} (push) Blocked by required conditions
Mobile checks / Mobile lint + typecheck (push) Waiting to run
Mobile checks / Mobile unit tests (push) Waiting to run
Mobile checks / Mobile dependency audit (report) (push) Waiting to run
Mobile checks / Mobile reproducibility checks (push) Waiting to run
Secrets guard (env backups) / Ensure no tracked env backup files (push) Waiting to run
Temporal Readiness / fast-readiness (push) Waiting to run
Temporal Readiness / docker-parity (push) Waiting to run
TypeScript Type Check / Nx affected typecheck (push) Waiting to run
Unit Tests / Skipped-test budget (push) Waiting to run
Unit Tests / Nx affected unit tests (push) Waiting to run
Unit Tests / Server unit coverage (informational) (push) Waiting to run
Validate Tenant Management Schema / Check for relevant changes (push) Waiting to run
Validate Tenant Management Schema / Validate Tenant Management Schema (push) Blocked by required conditions
EE Workflows Build Guard / ee-workflows-build-guard (push) Waiting to run
Excluded: .git, node_modules, secrets/, compose.env, assemblyscript tgz Source: /opt/alga-psa on psa.joliet.tech
218 lines
7.4 KiB
JavaScript
218 lines
7.4 KiB
JavaScript
/**
|
|
* Create reference tables for lookup/configuration data
|
|
* This must run early to avoid foreign key dependency issues
|
|
* Reference tables are small lookup tables that are replicated to all worker nodes
|
|
*/
|
|
exports.config = { transaction: false };
|
|
|
|
exports.up = async function(knex) {
|
|
// Check if Citus is enabled
|
|
const citusEnabled = await knex.raw(`
|
|
SELECT EXISTS (
|
|
SELECT 1 FROM pg_extension WHERE extname = 'citus'
|
|
) as enabled
|
|
`);
|
|
|
|
if (!citusEnabled.rows[0].enabled) {
|
|
console.log('Citus not enabled, skipping reference table creation');
|
|
return;
|
|
}
|
|
|
|
console.log('Creating reference tables for lookup/configuration data...');
|
|
|
|
// List of reference tables that need to be created early
|
|
// These are lookup/configuration tables that are shared across all tenants
|
|
// Ordered to handle dependencies (notification tables first, then system tables that reference them)
|
|
const referenceTables = [
|
|
// Notification tables - BOTH are needed as a pair
|
|
'notification_categories', // Must come first
|
|
'notification_subtypes', // Depends on notification_categories
|
|
|
|
// Document-related tables (only truly shared ones)
|
|
'shared_document_types',
|
|
|
|
// Standard lookup tables (without tenant columns)
|
|
'countries',
|
|
'standard_categories',
|
|
'standard_channels',
|
|
'standard_invoice_templates',
|
|
'standard_priorities',
|
|
'standard_service_types',
|
|
// 'standard_statuses', - Has tenant column and FKs to distributed tables, must remain distributed
|
|
'standard_task_types',
|
|
|
|
// System workflow tables - order matters for dependencies
|
|
'system_workflow_registrations', // Must come first
|
|
'system_workflow_registration_versions', // Depends on registrations
|
|
'system_workflow_event_attachments', // Depends on registrations
|
|
'system_workflow_form_definitions',
|
|
'system_workflow_task_definitions',
|
|
|
|
// System configuration tables
|
|
'system_email_templates', // Now after notification tables
|
|
// 'system_event_catalog', - Has triggers, cannot be distributed with Citus
|
|
'system_interaction_types',
|
|
|
|
// Other configuration tables
|
|
'workflow_event_mappings',
|
|
// 'time_period_settings', - Has tenant column, moved to distributed tables
|
|
// 'verification_tokens', - Has tenant column, moved to distributed tables
|
|
// 'tenant_companies', - Has tenant_id column, moved to distributed tables
|
|
];
|
|
let successCount = 0;
|
|
let failedTables = [];
|
|
|
|
for (const tableName of referenceTables) {
|
|
try {
|
|
// Check if table exists
|
|
const tableExists = await knex.raw(`
|
|
SELECT EXISTS (
|
|
SELECT 1 FROM information_schema.tables
|
|
WHERE table_schema = 'public'
|
|
AND table_name = ?
|
|
) as exists
|
|
`, [tableName]);
|
|
|
|
if (!tableExists.rows[0].exists) {
|
|
console.log(` - ${tableName} does not exist, skipping`);
|
|
continue;
|
|
}
|
|
|
|
// Check if already distributed
|
|
const isDistributed = await knex.raw(`
|
|
SELECT EXISTS (
|
|
SELECT 1 FROM pg_dist_partition
|
|
WHERE logicalrelid = ?::regclass
|
|
) as distributed
|
|
`, [tableName]);
|
|
|
|
if (isDistributed.rows[0].distributed) {
|
|
console.log(` - ${tableName} already distributed`);
|
|
continue;
|
|
}
|
|
|
|
// Try to create as reference table
|
|
await knex.raw(`SELECT create_reference_table('${tableName}')`);
|
|
console.log(` ✓ Created ${tableName} as reference table`);
|
|
successCount++;
|
|
|
|
} catch (e) {
|
|
console.log(` - Could not create ${tableName} as reference table: ${e.message}`);
|
|
failedTables.push({table: tableName, error: e.message});
|
|
// Continue with next table instead of aborting
|
|
}
|
|
}
|
|
|
|
// Try failed tables again in case dependencies are now resolved
|
|
if (failedTables.length > 0) {
|
|
console.log('\n Retrying failed tables...');
|
|
for (const {table: tableName} of failedTables) {
|
|
try {
|
|
// Check if still not distributed
|
|
const isDistributed = await knex.raw(`
|
|
SELECT EXISTS (
|
|
SELECT 1 FROM pg_dist_partition
|
|
WHERE logicalrelid = ?::regclass
|
|
) as distributed
|
|
`, [tableName]);
|
|
|
|
if (!isDistributed.rows[0].distributed) {
|
|
await knex.raw(`SELECT create_reference_table('${tableName}')`);
|
|
console.log(` ✓ Created ${tableName} as reference table (on retry)`);
|
|
successCount++;
|
|
}
|
|
} catch (e) {
|
|
console.log(` - Still could not create ${tableName} as reference table: ${e.message}`);
|
|
}
|
|
}
|
|
}
|
|
|
|
console.log(`\n ✓ Reference tables setup complete (${successCount} tables created)`);
|
|
};
|
|
|
|
exports.down = async function(knex) {
|
|
// Check if Citus is enabled
|
|
const citusEnabled = await knex.raw(`
|
|
SELECT EXISTS (
|
|
SELECT 1 FROM pg_extension WHERE extname = 'citus'
|
|
) as enabled
|
|
`);
|
|
|
|
if (!citusEnabled.rows[0].enabled) {
|
|
console.log('Citus not enabled, nothing to undo');
|
|
return;
|
|
}
|
|
|
|
console.log('Undistributing reference tables...');
|
|
|
|
try {
|
|
const tablesToUndistribute = [
|
|
// Document-related tables (only truly shared ones)
|
|
'shared_document_types',
|
|
|
|
// Standard lookup tables (without tenant columns)
|
|
'countries',
|
|
// 'invoice_templates', - Has tenant column, moved to distributed tables
|
|
'standard_categories',
|
|
'standard_channels',
|
|
'standard_invoice_templates',
|
|
'standard_priorities',
|
|
'standard_service_types',
|
|
// 'standard_statuses', - Has tenant column and FKs to distributed tables, must remain distributed
|
|
'standard_task_types',
|
|
|
|
// System configuration tables
|
|
'system_email_templates',
|
|
// 'system_event_catalog', - Has triggers, cannot be distributed with Citus
|
|
'system_interaction_types',
|
|
'system_workflow_event_attachments',
|
|
'system_workflow_form_definitions',
|
|
'system_workflow_registration_versions',
|
|
'system_workflow_registrations',
|
|
'system_workflow_task_definitions',
|
|
|
|
// Notification tables
|
|
'notification_categories',
|
|
'notification_subtypes',
|
|
|
|
// Other configuration tables
|
|
// 'time_period_settings', - Has tenant column, moved to distributed tables
|
|
// 'verification_tokens', - Has tenant column, moved to distributed tables
|
|
'workflow_event_mappings',
|
|
// 'tenant_companies', - Has tenant_id column, moved to distributed tables
|
|
];
|
|
|
|
for (const tableName of tablesToUndistribute) {
|
|
// Check if table exists and is distributed
|
|
const tableExists = await knex.raw(`
|
|
SELECT EXISTS (
|
|
SELECT 1 FROM information_schema.tables
|
|
WHERE table_schema = 'public'
|
|
AND table_name = ?
|
|
) as exists
|
|
`, [tableName]);
|
|
|
|
if (tableExists.rows[0].exists) {
|
|
const isDistributed = await knex.raw(`
|
|
SELECT EXISTS (
|
|
SELECT 1 FROM pg_dist_partition
|
|
WHERE logicalrelid = ?::regclass
|
|
) as distributed
|
|
`, [tableName]);
|
|
|
|
if (isDistributed.rows[0].distributed) {
|
|
try {
|
|
await knex.raw(`SELECT undistribute_table('${tableName}')`);
|
|
console.log(` ✓ Undistributed ${tableName} table`);
|
|
} catch (e) {
|
|
console.log(` - Could not undistribute ${tableName}: ${e.message}`);
|
|
}
|
|
}
|
|
}
|
|
}
|
|
|
|
} catch (error) {
|
|
console.error(` ✗ Failed to undistribute: ${error.message}`);
|
|
}
|
|
};
|