Initial commit
This commit is contained in:
17
server/scripts/init-db.sql
Normal file
17
server/scripts/init-db.sql
Normal file
@@ -0,0 +1,17 @@
|
||||
-- Database initialization script for Docker
|
||||
-- This script sets up the initial database structure
|
||||
|
||||
-- Enable extensions
|
||||
CREATE EXTENSION IF NOT EXISTS "uuid-ossp";
|
||||
|
||||
-- Set timezone
|
||||
SET timezone = 'Europe/Stockholm';
|
||||
|
||||
-- Create indexes for better performance
|
||||
-- (These will be created by Sequelize, but we can optimize here)
|
||||
|
||||
-- Log successful initialization
|
||||
INSERT INTO pg_stat_statements_info (dealloc) VALUES (0) ON CONFLICT DO NOTHING;
|
||||
|
||||
-- Grant necessary permissions
|
||||
GRANT ALL PRIVILEGES ON DATABASE drone_detection TO postgres;
|
||||
331
server/scripts/setup-database.js
Normal file
331
server/scripts/setup-database.js
Normal file
@@ -0,0 +1,331 @@
|
||||
const { Sequelize } = require('sequelize');
|
||||
const bcrypt = require('bcrypt');
|
||||
|
||||
// Import models
|
||||
const Device = require('../models/Device');
|
||||
const DroneDetection = require('../models/DroneDetection');
|
||||
const Heartbeat = require('../models/Heartbeat');
|
||||
const User = require('../models/User');
|
||||
const AlertRule = require('../models/AlertRule');
|
||||
const AlertLog = require('../models/AlertLog');
|
||||
|
||||
const setupDatabase = async () => {
|
||||
try {
|
||||
console.log('🚀 Starting database setup...\n');
|
||||
|
||||
// Load environment variables
|
||||
require('dotenv').config();
|
||||
|
||||
// Create Sequelize instance
|
||||
const sequelize = new Sequelize(
|
||||
process.env.DB_NAME,
|
||||
process.env.DB_USER,
|
||||
process.env.DB_PASSWORD,
|
||||
{
|
||||
host: process.env.DB_HOST,
|
||||
port: process.env.DB_PORT,
|
||||
dialect: 'postgres',
|
||||
logging: console.log,
|
||||
}
|
||||
);
|
||||
|
||||
// Test database connection
|
||||
console.log('📡 Testing database connection...');
|
||||
await sequelize.authenticate();
|
||||
console.log('✅ Database connection established successfully.\n');
|
||||
|
||||
// Initialize models
|
||||
console.log('📋 Initializing models...');
|
||||
Device.init(Device.getAttributes(), { sequelize, modelName: 'Device' });
|
||||
DroneDetection.init(DroneDetection.getAttributes(), { sequelize, modelName: 'DroneDetection' });
|
||||
Heartbeat.init(Heartbeat.getAttributes(), { sequelize, modelName: 'Heartbeat' });
|
||||
User.init(User.getAttributes(), { sequelize, modelName: 'User' });
|
||||
AlertRule.init(AlertRule.getAttributes(), { sequelize, modelName: 'AlertRule' });
|
||||
AlertLog.init(AlertLog.getAttributes(), { sequelize, modelName: 'AlertLog' });
|
||||
|
||||
// Define associations
|
||||
console.log('🔗 Setting up model associations...');
|
||||
|
||||
// Device associations
|
||||
Device.hasMany(DroneDetection, { foreignKey: 'device_id', as: 'detections' });
|
||||
Device.hasMany(Heartbeat, { foreignKey: 'device_id', as: 'heartbeats' });
|
||||
|
||||
// Detection associations
|
||||
DroneDetection.belongsTo(Device, { foreignKey: 'device_id', as: 'device' });
|
||||
|
||||
// Heartbeat associations
|
||||
Heartbeat.belongsTo(Device, { foreignKey: 'device_id', as: 'device' });
|
||||
|
||||
// User associations
|
||||
User.hasMany(AlertRule, { foreignKey: 'user_id', as: 'alertRules' });
|
||||
User.hasMany(AlertLog, { foreignKey: 'user_id', as: 'alertLogs' });
|
||||
|
||||
// Alert associations
|
||||
AlertRule.belongsTo(User, { foreignKey: 'user_id', as: 'user' });
|
||||
AlertRule.hasMany(AlertLog, { foreignKey: 'alert_rule_id', as: 'logs' });
|
||||
|
||||
AlertLog.belongsTo(User, { foreignKey: 'user_id', as: 'user' });
|
||||
AlertLog.belongsTo(AlertRule, { foreignKey: 'alert_rule_id', as: 'alertRule' });
|
||||
AlertLog.belongsTo(DroneDetection, { foreignKey: 'detection_id', as: 'detection' });
|
||||
|
||||
// Sync database (create tables)
|
||||
console.log('🏗️ Creating database tables...');
|
||||
await sequelize.sync({ force: true }); // WARNING: This will drop existing tables
|
||||
console.log('✅ Database tables created successfully.\n');
|
||||
|
||||
// Create sample data
|
||||
console.log('📊 Creating sample data...\n');
|
||||
|
||||
// Create admin user
|
||||
console.log('👤 Creating admin user...');
|
||||
const adminUser = await User.create({
|
||||
username: 'admin',
|
||||
email: 'admin@example.com',
|
||||
password: await bcrypt.hash('admin123', 10),
|
||||
role: 'admin'
|
||||
});
|
||||
console.log(`✅ Admin user created: ${adminUser.username}`);
|
||||
|
||||
// Create operator user
|
||||
console.log('👤 Creating operator user...');
|
||||
const operatorUser = await User.create({
|
||||
username: 'operator',
|
||||
email: 'operator@example.com',
|
||||
password: await bcrypt.hash('operator123', 10),
|
||||
role: 'operator'
|
||||
});
|
||||
console.log(`✅ Operator user created: ${operatorUser.username}`);
|
||||
|
||||
// Create sample devices
|
||||
console.log('📡 Creating sample devices...');
|
||||
const devices = await Device.bulkCreate([
|
||||
{
|
||||
device_id: 1941875381,
|
||||
name: 'Drone Detector Alpha',
|
||||
location: 'Stockholm Central',
|
||||
geo_lat: 59.3293,
|
||||
geo_lon: 18.0686,
|
||||
status: 'online',
|
||||
last_seen: new Date()
|
||||
},
|
||||
{
|
||||
device_id: 1941875382,
|
||||
name: 'Drone Detector Beta',
|
||||
location: 'Gothenburg Port',
|
||||
geo_lat: 57.7089,
|
||||
geo_lon: 11.9746,
|
||||
status: 'online',
|
||||
last_seen: new Date()
|
||||
},
|
||||
{
|
||||
device_id: 1941875383,
|
||||
name: 'Drone Detector Gamma',
|
||||
location: 'Malmö Airport',
|
||||
geo_lat: 55.6050,
|
||||
geo_lon: 13.0038,
|
||||
status: 'offline',
|
||||
last_seen: new Date(Date.now() - 2 * 60 * 60 * 1000) // 2 hours ago
|
||||
}
|
||||
]);
|
||||
console.log(`✅ Created ${devices.length} sample devices`);
|
||||
|
||||
// Create sample heartbeats
|
||||
console.log('💓 Creating sample heartbeats...');
|
||||
const heartbeats = await Heartbeat.bulkCreate([
|
||||
{
|
||||
device_id: 1941875381,
|
||||
battery_level: 85,
|
||||
signal_strength: -45,
|
||||
temperature: 22.5,
|
||||
status: 'active',
|
||||
timestamp: new Date()
|
||||
},
|
||||
{
|
||||
device_id: 1941875382,
|
||||
battery_level: 72,
|
||||
signal_strength: -38,
|
||||
temperature: 24.1,
|
||||
status: 'active',
|
||||
timestamp: new Date()
|
||||
}
|
||||
]);
|
||||
console.log(`✅ Created ${heartbeats.length} sample heartbeats`);
|
||||
|
||||
// Create sample drone detections
|
||||
console.log('🚁 Creating sample drone detections...');
|
||||
const detections = await DroneDetection.bulkCreate([
|
||||
{
|
||||
device_id: 1941875381,
|
||||
geo_lat: 59.3293,
|
||||
geo_lon: 18.0686,
|
||||
device_timestamp: Math.floor(Date.now() / 1000),
|
||||
drone_type: 0,
|
||||
rssi: -45,
|
||||
freq: 20,
|
||||
drone_id: 1001,
|
||||
timestamp: new Date(),
|
||||
threat_level: 'high',
|
||||
estimated_distance: 150,
|
||||
requires_action: true
|
||||
},
|
||||
{
|
||||
device_id: 1941875382,
|
||||
geo_lat: 57.7089,
|
||||
geo_lon: 11.9746,
|
||||
device_timestamp: Math.floor(Date.now() / 1000) - 3600,
|
||||
drone_type: 1,
|
||||
rssi: -52,
|
||||
freq: 25,
|
||||
drone_id: 1002,
|
||||
timestamp: new Date(Date.now() - 60 * 60 * 1000),
|
||||
threat_level: 'medium',
|
||||
estimated_distance: 800,
|
||||
requires_action: false
|
||||
},
|
||||
{
|
||||
device_id: 1941875381,
|
||||
geo_lat: 59.3295,
|
||||
geo_lon: 18.0690,
|
||||
device_timestamp: Math.floor(Date.now() / 1000) - 7200,
|
||||
drone_type: 0,
|
||||
rssi: -75,
|
||||
freq: 22,
|
||||
drone_id: 1003,
|
||||
timestamp: new Date(Date.now() - 2 * 60 * 60 * 1000),
|
||||
threat_level: 'low',
|
||||
estimated_distance: 2500,
|
||||
requires_action: false
|
||||
}
|
||||
]);
|
||||
console.log(`✅ Created ${detections.length} sample drone detections`);
|
||||
|
||||
// Create sample alert rules
|
||||
console.log('🚨 Creating sample alert rules...');
|
||||
const alertRules = await AlertRule.bulkCreate([
|
||||
{
|
||||
user_id: adminUser.id,
|
||||
name: 'Critical Security Threat',
|
||||
description: 'Immediate alert for critical and high threats to government facilities',
|
||||
conditions: {
|
||||
min_threat_level: 'high',
|
||||
rssi_threshold: -55,
|
||||
max_distance: 200,
|
||||
drone_types: [0, 1, 2],
|
||||
device_ids: []
|
||||
},
|
||||
actions: {
|
||||
sms: true,
|
||||
phone_number: '+46701234567',
|
||||
email: true,
|
||||
channels: ['sms', 'email']
|
||||
},
|
||||
cooldown_minutes: 2,
|
||||
is_active: true
|
||||
},
|
||||
{
|
||||
user_id: operatorUser.id,
|
||||
name: 'Medium Threat Monitoring',
|
||||
description: 'Monitor medium threat drones in facility vicinity',
|
||||
conditions: {
|
||||
min_threat_level: 'medium',
|
||||
rssi_threshold: -70,
|
||||
max_distance: 1000,
|
||||
drone_types: [1, 2],
|
||||
device_ids: [1941875381, 1941875382]
|
||||
},
|
||||
actions: {
|
||||
sms: true,
|
||||
phone_number: '+46709876543',
|
||||
channels: ['sms']
|
||||
},
|
||||
cooldown_minutes: 10,
|
||||
is_active: true
|
||||
},
|
||||
{
|
||||
user_id: adminUser.id,
|
||||
name: 'Device Offline Alert',
|
||||
description: 'Alert when security devices go offline',
|
||||
conditions: {
|
||||
device_offline: true,
|
||||
device_ids: [1941875381, 1941875382, 1941875383]
|
||||
},
|
||||
actions: {
|
||||
sms: true,
|
||||
phone_number: '+46701234567',
|
||||
channels: ['sms']
|
||||
},
|
||||
cooldown_minutes: 30,
|
||||
is_active: true
|
||||
}
|
||||
]);
|
||||
console.log(`✅ Created ${alertRules.length} sample alert rules`);
|
||||
|
||||
// Create sample alert logs
|
||||
console.log('📝 Creating sample alert logs...');
|
||||
const alertLogs = await AlertLog.bulkCreate([
|
||||
{
|
||||
user_id: adminUser.id,
|
||||
alert_rule_id: alertRules[0].id,
|
||||
detection_id: detections[0].id,
|
||||
message: 'Drone detected with strong signal',
|
||||
status: 'sent',
|
||||
sent_at: new Date()
|
||||
},
|
||||
{
|
||||
user_id: operatorUser.id,
|
||||
alert_rule_id: alertRules[1].id,
|
||||
detection_id: null,
|
||||
message: 'Device 1941875383 went offline',
|
||||
status: 'sent',
|
||||
sent_at: new Date(Date.now() - 30 * 60 * 1000)
|
||||
}
|
||||
]);
|
||||
console.log(`✅ Created ${alertLogs.length} sample alert logs\n`);
|
||||
|
||||
// Create database indexes for performance
|
||||
console.log('🚀 Creating database indexes...');
|
||||
|
||||
await sequelize.query(`
|
||||
CREATE INDEX IF NOT EXISTS idx_drone_detections_device_timestamp
|
||||
ON "DroneDetections" (device_id, timestamp);
|
||||
`);
|
||||
|
||||
await sequelize.query(`
|
||||
CREATE INDEX IF NOT EXISTS idx_heartbeats_device_timestamp
|
||||
ON "Heartbeats" (device_id, timestamp);
|
||||
`);
|
||||
|
||||
await sequelize.query(`
|
||||
CREATE INDEX IF NOT EXISTS idx_alert_logs_user_created
|
||||
ON "AlertLogs" (user_id, "createdAt");
|
||||
`);
|
||||
|
||||
console.log('✅ Database indexes created\n');
|
||||
|
||||
console.log('🎉 Database setup completed successfully!\n');
|
||||
console.log('📋 Summary:');
|
||||
console.log(` • Users created: 2 (admin, operator)`);
|
||||
console.log(` • Devices created: ${devices.length}`);
|
||||
console.log(` • Heartbeats created: ${heartbeats.length}`);
|
||||
console.log(` • Detections created: ${detections.length}`);
|
||||
console.log(` • Alert rules created: ${alertRules.length}`);
|
||||
console.log(` • Alert logs created: ${alertLogs.length}`);
|
||||
console.log('\n📝 Default login credentials:');
|
||||
console.log(' Admin: admin / admin123');
|
||||
console.log(' Operator: operator / operator123\n');
|
||||
|
||||
// Close connection
|
||||
await sequelize.close();
|
||||
|
||||
} catch (error) {
|
||||
console.error('❌ Database setup failed:', error);
|
||||
process.exit(1);
|
||||
}
|
||||
};
|
||||
|
||||
// Run setup if called directly
|
||||
if (require.main === module) {
|
||||
setupDatabase();
|
||||
}
|
||||
|
||||
module.exports = setupDatabase;
|
||||
Reference in New Issue
Block a user