feat: Containerize services with Docker Compose (PostgreSQL, Strapi CMS, Express Backend, Nginx Frontend) on custom ports >9000

This commit is contained in:
Vishva
2026-08-03 19:58:10 +05:30
parent 48f8ab9716
commit 6244fd4072
247 changed files with 56672 additions and 169 deletions
+161
View File
@@ -0,0 +1,161 @@
const betterSqlite3 = require('better-sqlite3');
const { Pool } = require('pg');
const path = require('path');
const sqlitePath = path.join(__dirname, '.tmp/data.db');
const sqliteDb = new betterSqlite3(sqlitePath);
const pgPool = new Pool({
host: process.env.DATABASE_HOST || '127.0.0.1',
port: parseInt(process.env.DATABASE_PORT || '9543', 10),
user: process.env.DATABASE_USERNAME || 'strapi',
password: process.env.DATABASE_PASSWORD || 'strapi_password_9000',
database: process.env.DATABASE_NAME || 'strapi',
});
async function migrate() {
console.log('Connecting to PostgreSQL...');
const client = await pgPool.connect();
try {
console.log('Disabling constraints temporarily for migration...');
await client.query("SET session_replication_role = 'replica';");
// 1. Get all public tables in Postgres and TRUNCATE them
const allTablesRes = await client.query(`
SELECT table_name
FROM information_schema.tables
WHERE table_schema = 'public' AND table_type = 'BASE TABLE';
`);
const pgTables = allTablesRes.rows.map(r => r.table_name);
for (const t of pgTables) {
await client.query(`TRUNCATE TABLE "${t}" CASCADE;`);
}
console.log(`Truncated all ${pgTables.length} PostgreSQL tables.`);
// 2. Migrate tables from SQLite
const tablesToMigrate = [
'strapi_database_schema',
'strapi_migrations_internal',
'strapi_core_store_settings',
'i18n_locale',
'files',
'files_related_mph',
'job_roles',
'blogs',
'blogs_author_lnk',
'blogs_editor_lnk',
'admin_roles',
'admin_users',
'admin_users_roles_lnk',
'admin_permissions',
'admin_permissions_role_lnk',
'up_roles',
'up_permissions',
'up_permissions_role_lnk',
'strapi_api_tokens',
'strapi_sessions',
];
for (const table of tablesToMigrate) {
if (!pgTables.includes(table)) {
console.log(`Table ${table} does not exist in Postgres, skipping.`);
continue;
}
const colInfoRes = await client.query(
`SELECT column_name, data_type FROM information_schema.columns WHERE table_name = $1;`,
[table]
);
const colDataTypes = {};
colInfoRes.rows.forEach(r => {
colDataTypes[r.column_name] = r.data_type;
});
const rows = sqliteDb.prepare(`SELECT * FROM "${table}"`).all();
console.log(`Migrating table: ${table} (${rows.length} rows)`);
if (rows.length === 0) continue;
const columns = Object.keys(rows[0]);
const colNames = columns.map((c) => `"${c}"`).join(', ');
for (let index = 0; index < rows.length; index++) {
const row = rows[index];
const values = columns.map((col) => {
let val = row[col];
const dt = colDataTypes[col];
if ((dt === 'timestamp with time zone' || dt === 'timestamp without time zone') && val !== null) {
if (typeof val === 'number' || (typeof val === 'string' && /^\d+$/.test(val))) {
val = new Date(Number(val)).toISOString();
}
}
if (dt === 'json' || dt === 'jsonb') {
if (val === '' || val === undefined) {
val = null;
} else if (typeof val === 'object') {
val = JSON.stringify(val);
}
}
if (dt === 'boolean' && val !== null) {
if (val === 1 || val === '1' || val === 'true') val = true;
if (val === 0 || val === '0' || val === 'false') val = false;
}
return val;
});
const placeholders = values.map((_, i) => `$${i + 1}`).join(', ');
const query = `INSERT INTO "${table}" (${colNames}) VALUES (${placeholders});`;
await client.query(query, values);
}
if (columns.includes('id')) {
const seqRes = await client.query(`
SELECT pg_get_serial_sequence('"${table}"', 'id') AS seq;
`);
const seqName = seqRes.rows[0]?.seq;
if (seqName) {
await client.query(`
SELECT setval('${seqName}', COALESCE((SELECT MAX(id) FROM "${table}"), 1));
`);
}
}
}
// 3. Fix ordinals for all link tables
console.log('Fixing ordinals for link tables...');
await client.query(`
UPDATE public.admin_users_roles_lnk a SET user_ord = b.inv_order FROM (
SELECT id, ROW_NUMBER() OVER (PARTITION BY role_id ORDER BY id) as inv_order FROM public.admin_users_roles_lnk
) b WHERE a.id = b.id;
`);
await client.query(`
UPDATE public.admin_permissions_role_lnk a SET permission_ord = b.inv_order FROM (
SELECT id, ROW_NUMBER() OVER (PARTITION BY role_id ORDER BY id) as inv_order FROM public.admin_permissions_role_lnk
) b WHERE a.id = b.id;
`);
await client.query(`
UPDATE public.up_permissions_role_lnk a SET permission_ord = b.inv_order FROM (
SELECT id, ROW_NUMBER() OVER (PARTITION BY role_id ORDER BY id) as inv_order FROM public.up_permissions_role_lnk
) b WHERE a.id = b.id;
`);
console.log('Re-enabling constraints...');
await client.query("SET session_replication_role = 'origin';");
console.log('Migration completed successfully!');
} catch (err) {
console.error('Migration failed:', err);
} finally {
client.release();
await pgPool.end();
sqliteDb.close();
}
}
migrate();