Skip to content

Commit 6e7f6b2

Browse files
committed
creates collections
1 parent 13fbedd commit 6e7f6b2

File tree

5 files changed

+203
-3
lines changed

5 files changed

+203
-3
lines changed

client/src/cyber-forensics-platform/.gitignore

Lines changed: 2 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -207,4 +207,5 @@ generated-images/
207207

208208
# Lock files (choose one)
209209
# package-lock.json # uncomment if using yarn
210-
yarn.lock # uncomment if using npm
210+
yarn.lock # uncomment if using npm
211+
.do/app.yaml

client/src/cyber-forensics-platform/package.json

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -10,6 +10,7 @@
1010
"lint": "next lint",
1111
"db:init": "node scripts/init-db.js",
1212
"db:init:postgres": "node scripts/init-db-postgres.js",
13+
"db:init:production": "node scripts/init-production-db.js",
1314
"db:migrate": "node scripts/migrate-db.js",
1415
"db:seed": "node scripts/seed-db.js"
1516
},

client/src/cyber-forensics-platform/scripts/build-hook.js

Lines changed: 12 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -11,13 +11,23 @@ async function buildHook() {
1111
// Only initialize database if DATABASE_URL is present (production)
1212
if (process.env.DATABASE_URL) {
1313
console.log('🗄️ Initializing production database...');
14+
console.log('🔍 DATABASE_URL present:', !!process.env.DATABASE_URL);
15+
console.log('🔍 NODE_ENV:', process.env.NODE_ENV);
16+
1417
try {
1518
await initializeDatabase();
1619
console.log('✅ Database initialization successful');
1720
} catch (error) {
1821
console.error('❌ Database initialization failed:', error);
19-
// Don't exit - let the build continue, database might already be initialized
20-
console.log('⚠️ Continuing with build despite database error');
22+
console.error('❌ Full error details:', {
23+
message: error.message,
24+
code: error.code,
25+
detail: error.detail,
26+
stack: error.stack
27+
});
28+
// Exit with error to prevent deployment with broken database
29+
console.error('🚨 Stopping build due to database initialization failure');
30+
process.exit(1);
2131
}
2232
} else {
2333
console.log('⚠️ DATABASE_URL not found, skipping database initialization');
Lines changed: 107 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,107 @@
1+
#!/usr/bin/env node
2+
3+
// Manual database initialization script for production
4+
// This can be run manually if the build hook fails
5+
6+
const { Pool } = require('pg');
7+
const fs = require('fs').promises;
8+
const path = require('path');
9+
10+
async function initProductionDatabase() {
11+
console.log('🚀 Manual PostgreSQL database initialization...');
12+
13+
if (!process.env.DATABASE_URL) {
14+
console.error('❌ DATABASE_URL environment variable is required');
15+
process.exit(1);
16+
}
17+
18+
// Parse DATABASE_URL
19+
const url = new URL(process.env.DATABASE_URL);
20+
const config = {
21+
user: url.username,
22+
password: url.password,
23+
host: url.hostname,
24+
port: parseInt(url.port),
25+
database: url.pathname.slice(1),
26+
ssl: {
27+
rejectUnauthorized: false
28+
},
29+
connectionTimeoutMillis: 15000,
30+
idleTimeoutMillis: 30000,
31+
max: 5
32+
};
33+
34+
console.log('📊 Connecting to PostgreSQL:', {
35+
host: config.host,
36+
port: config.port,
37+
database: config.database,
38+
user: config.user
39+
});
40+
41+
const pool = new Pool(config);
42+
43+
try {
44+
// Test connection
45+
const connectionTest = await pool.query('SELECT NOW() as current_time, version() as pg_version');
46+
console.log('✅ Database connection successful');
47+
console.log('🔍 Database info:', {
48+
current_time: connectionTest.rows[0].current_time,
49+
version: connectionTest.rows[0].pg_version.split(' ')[0]
50+
});
51+
52+
// Check if tables already exist
53+
try {
54+
await pool.query('SELECT 1 FROM competitions LIMIT 1');
55+
console.log('✅ Database schema already exists');
56+
return;
57+
} catch (error) {
58+
if (error.code !== '42P01') {
59+
throw error;
60+
}
61+
console.log('🔧 Database schema missing, creating tables...');
62+
}
63+
64+
// Read and execute schema
65+
const schemaPath = path.join(__dirname, '../database_schema_postgres.sql');
66+
console.log('📄 Reading schema from:', schemaPath);
67+
const schema = await fs.readFile(schemaPath, 'utf8');
68+
69+
console.log('🚀 Executing database schema...');
70+
await pool.query(schema);
71+
console.log('✅ Database schema created successfully');
72+
73+
// Create default competition
74+
const existingCompetitions = await pool.query('SELECT COUNT(*) as count FROM competitions');
75+
if (parseInt(existingCompetitions.rows[0].count) === 0) {
76+
await pool.query(`
77+
INSERT INTO competitions (name, description, metadata)
78+
VALUES ($1, $2, $3)
79+
`, [
80+
'Default Competition',
81+
'Default competition for cyber forensics challenges',
82+
JSON.stringify({ theme: 'default', difficulty: 'mixed' })
83+
]);
84+
console.log('✅ Default competition created');
85+
}
86+
87+
console.log('🎉 Database initialization completed successfully');
88+
89+
} catch (error) {
90+
console.error('❌ Database initialization failed:', error);
91+
console.error('❌ Error details:', {
92+
code: error.code,
93+
message: error.message,
94+
detail: error.detail
95+
});
96+
process.exit(1);
97+
} finally {
98+
await pool.end();
99+
}
100+
}
101+
102+
// Run if called directly
103+
if (require.main === module) {
104+
initProductionDatabase();
105+
}
106+
107+
module.exports = { initProductionDatabase };

client/src/cyber-forensics-platform/src/lib/database-postgres.js

Lines changed: 81 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -49,12 +49,93 @@ class PostgresDatabaseManager {
4949

5050
await this.pool.query('SELECT NOW()');
5151
console.log('📊 Connected to PostgreSQL database');
52+
console.log('🔍 Database info:', {
53+
current_time: result.rows[0].current_time,
54+
version: result.rows[0].pg_version.split(' ')[0]
55+
});
5256
} catch (err) {
5357
console.error('Database connection error:', err);
5458
throw err;
5559
}
5660
}
5761

62+
// Ensure database schema exists
63+
async ensureSchema() {
64+
try {
65+
// Test if competitions table exists
66+
await this.pool.query('SELECT 1 FROM competitions LIMIT 1');
67+
console.log('📊 Database schema verified');
68+
} catch (error) {
69+
if (error.code === '42P01') {
70+
console.log('🔧 Database schema missing, creating tables...');
71+
try {
72+
await this.initializeSchema();
73+
} catch (initError) {
74+
console.error('❌ Failed to initialize schema:', initError);
75+
// Re-throw with more context
76+
throw new Error(`Schema initialization failed: ${initError.message}`);
77+
}
78+
} else {
79+
console.error('❌ Unexpected error checking schema:', error);
80+
throw error;
81+
}
82+
}
83+
}
84+
85+
// Initialize database schema
86+
async initializeSchema() {
87+
try {
88+
const fs = require('fs').promises;
89+
const path = require('path');
90+
91+
const schemaPath = path.join(process.cwd(), 'database_schema_postgres.sql');
92+
console.log('📄 Reading schema from:', schemaPath);
93+
94+
let schema;
95+
try {
96+
schema = await fs.readFile(schemaPath, 'utf8');
97+
} catch (fileError) {
98+
console.error('❌ Failed to read schema file:', fileError);
99+
throw new Error(`Could not read schema file: ${fileError.message}`);
100+
}
101+
102+
console.log('🚀 Executing database schema...');
103+
try {
104+
// Execute schema creation - PostgreSQL can handle the entire script at once
105+
await this.pool.query(schema);
106+
console.log('✅ Database schema created successfully');
107+
} catch (schemaError) {
108+
console.error('❌ Failed to execute schema:', schemaError);
109+
throw new Error(`Schema execution failed: ${schemaError.message}`);
110+
}
111+
112+
// Create default competition if none exists
113+
try {
114+
const existingCompetitions = await this.pool.query('SELECT COUNT(*) as count FROM competitions');
115+
if (parseInt(existingCompetitions.rows[0].count) === 0) {
116+
await this.pool.query(`
117+
INSERT INTO competitions (name, description, metadata)
118+
VALUES ($1, $2, $3)
119+
`, [
120+
'Default Competition',
121+
'Default competition for cyber forensics challenges',
122+
JSON.stringify({ theme: 'default', difficulty: 'mixed' })
123+
]);
124+
console.log('✅ Default competition created');
125+
} else {
126+
console.log('ℹ️ Database already contains competitions');
127+
}
128+
} catch (compError) {
129+
console.error('❌ Failed to create default competition:', compError);
130+
// Don't throw here - schema is created, just default data failed
131+
console.log('⚠️ Schema created but default competition creation failed');
132+
}
133+
} catch (error) {
134+
console.error('❌ Schema initialization failed:', error);
135+
throw error;
136+
}
137+
}
138+
58139
// Close database connection - for PostgreSQL with connection pooling, we don't actually close
59140
async close() {
60141
try {

0 commit comments

Comments
 (0)