mirror of
https://github.com/R0m1k3/LogiFlow.git
synced 2026-10-12 01:37:40 +02:00
Implement a new announcement system with priority levels, role-based access, and store-specific filtering, replacing the customer order statistics card on the dashboard. Replit-Commit-Author: Agent Replit-Commit-Session-Id: e437ffed-c31b-44eb-9fd5-b6f9faa8e7ce Replit-Commit-Checkpoint-Type: full_checkpoint Replit-Commit-Screenshot-Url: https://storage.googleapis.com/screenshot-production-us-central1/1957c339-2757-4d1f-8e92-e9f71a1ce58e/e437ffed-c31b-44eb-9fd5-b6f9faa8e7ce/biGr9ER
98 lines
2.7 KiB
JavaScript
98 lines
2.7 KiB
JavaScript
#!/usr/bin/env node
|
|
|
|
/**
|
|
* Database Migration Script
|
|
* Automatically runs database migrations for production deployment
|
|
*/
|
|
|
|
const { Pool } = require('pg');
|
|
const fs = require('fs');
|
|
const path = require('path');
|
|
|
|
// Database connection
|
|
const pool = new Pool({
|
|
connectionString: process.env.DATABASE_URL,
|
|
ssl: process.env.NODE_ENV === 'production' ? { rejectUnauthorized: false } : false
|
|
});
|
|
|
|
async function runMigrations() {
|
|
console.log('🔄 Starting database migrations...');
|
|
|
|
try {
|
|
// Create migrations table if it doesn't exist
|
|
await pool.query(`
|
|
CREATE TABLE IF NOT EXISTS migrations (
|
|
id SERIAL PRIMARY KEY,
|
|
filename VARCHAR(255) UNIQUE NOT NULL,
|
|
executed_at TIMESTAMP WITH TIME ZONE DEFAULT NOW()
|
|
);
|
|
`);
|
|
console.log('✅ Migrations table ready');
|
|
|
|
// Get list of executed migrations
|
|
const { rows: executedMigrations } = await pool.query(
|
|
'SELECT filename FROM migrations ORDER BY executed_at'
|
|
);
|
|
const executedSet = new Set(executedMigrations.map(row => row.filename));
|
|
|
|
// Read migration files
|
|
const migrationsDir = path.join(__dirname);
|
|
const files = fs.readdirSync(migrationsDir)
|
|
.filter(file => file.endsWith('.sql'))
|
|
.sort();
|
|
|
|
console.log(`📁 Found ${files.length} migration files`);
|
|
|
|
let appliedCount = 0;
|
|
|
|
for (const file of files) {
|
|
if (executedSet.has(file)) {
|
|
console.log(`⏭️ Skipping ${file} (already executed)`);
|
|
continue;
|
|
}
|
|
|
|
console.log(`🔄 Executing migration: ${file}`);
|
|
|
|
const filePath = path.join(migrationsDir, file);
|
|
const sql = fs.readFileSync(filePath, 'utf8');
|
|
|
|
// Execute migration in a transaction
|
|
const client = await pool.connect();
|
|
try {
|
|
await client.query('BEGIN');
|
|
await client.query(sql);
|
|
await client.query(
|
|
'INSERT INTO migrations (filename) VALUES ($1)',
|
|
[file]
|
|
);
|
|
await client.query('COMMIT');
|
|
console.log(`✅ Successfully executed: ${file}`);
|
|
appliedCount++;
|
|
} catch (error) {
|
|
await client.query('ROLLBACK');
|
|
throw new Error(`Failed to execute ${file}: ${error.message}`);
|
|
} finally {
|
|
client.release();
|
|
}
|
|
}
|
|
|
|
if (appliedCount === 0) {
|
|
console.log('✅ All migrations are up to date');
|
|
} else {
|
|
console.log(`✅ Successfully applied ${appliedCount} migration(s)`);
|
|
}
|
|
|
|
} catch (error) {
|
|
console.error('❌ Migration failed:', error.message);
|
|
process.exit(1);
|
|
} finally {
|
|
await pool.end();
|
|
}
|
|
}
|
|
|
|
// Run migrations if this file is executed directly
|
|
if (require.main === module) {
|
|
runMigrations();
|
|
}
|
|
|
|
module.exports = { runMigrations }; |