diff --git a/.env.development b/.env.development new file mode 100644 index 0000000..933b0e9 --- /dev/null +++ b/.env.development @@ -0,0 +1,37 @@ +# Development Environment Configuration +# SMS alerts are disabled by default in development + +# Database Configuration +DB_HOST=localhost +DB_PORT=5433 +DB_NAME=drone_detection +DB_USER=postgres +DB_PASSWORD=your_secure_password_here + +# Redis Configuration +REDIS_HOST=localhost +REDIS_PORT=6380 + +# JWT Configuration +JWT_SECRET=dev_jwt_secret_change_in_production + +# Server Configuration +PORT=3002 +NODE_ENV=development + +# CORS Configuration +CORS_ORIGIN=http://localhost:3001 + +# Rate Limiting +RATE_LIMIT_WINDOW_MS=900000 +RATE_LIMIT_MAX_REQUESTS=100 + +# Twilio SMS Configuration (Disabled for development) +# Uncomment and fill these to enable SMS alerts: +# TWILIO_ACCOUNT_SID=ACxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxx +# TWILIO_AUTH_TOKEN=your_auth_token +# TWILIO_PHONE_NUMBER=+1234567890 + +# Frontend Configuration +VITE_API_URL=http://localhost:3002/api +VITE_WS_URL=ws://localhost:3002 diff --git a/.env.docker b/.env.docker index aa0f54f..1e09ba2 100644 --- a/.env.docker +++ b/.env.docker @@ -1,22 +1,44 @@ # Docker Environment Configuration # Copy this file to .env and update with your actual values +# Database Configuration (automatically set by docker-compose) +DB_HOST=drone-detection-db +DB_PORT=5432 +DB_NAME=drone_detection +DB_USER=postgres +DB_PASSWORD=your_secure_password_here + +# Redis Configuration (automatically set by docker-compose) +REDIS_HOST=drone-detection-redis +REDIS_PORT=6379 + # JWT Configuration JWT_SECRET=your-super-secret-jwt-key-change-in-production-make-it-long-and-random +# Server Configuration +PORT=3002 NODE_ENV=development -# Twilio Configuration (for SMS alerts) +# CORS Configuration +CORS_ORIGIN=http://localhost:3001 + +# Rate Limiting +RATE_LIMIT_WINDOW_MS=900000 +RATE_LIMIT_MAX_REQUESTS=100 + +# Twilio SMS Configuration (Optional - leave empty to disable SMS) +# Get these from https://console.twilio.com/ TWILIO_ACCOUNT_SID= TWILIO_AUTH_TOKEN= TWILIO_PHONE_NUMBER= +# Email Configuration (Optional - for future implementation) SMTP_HOST= SMTP_PORT=587 SMTP_USER= SMTP_PASSWORD= SMTP_FROM= -# Optional: Override default settings -# NODE_ENV=production -# CORS_ORIGIN=http://localhost:3000 +# Frontend Configuration +VITE_API_URL=http://localhost:3002/api +VITE_WS_URL=ws://localhost:3002 diff --git a/server/index.js b/server/index.js index a9b57d6..0cb51de 100644 --- a/server/index.js +++ b/server/index.js @@ -11,6 +11,7 @@ require('dotenv').config(); const { sequelize } = require('./models'); const routes = require('./routes'); const { initializeSocketHandlers } = require('./services/socketService'); +const AlertService = require('./services/alertService'); const errorHandler = require('./middleware/errorHandler'); const app = express(); @@ -81,8 +82,24 @@ async function startServer() { } server.listen(PORT, () => { - console.log(`Server running on port ${PORT}`); - console.log(`Environment: ${process.env.NODE_ENV}`); + console.log('\nšŸš€ Drone Detection System Started Successfully!'); + console.log('================================================'); + console.log(`šŸ“Š Environment: ${process.env.NODE_ENV || 'development'}`); + console.log(`🌐 Server Port: ${PORT}`); + console.log(`šŸ’¾ Database: ${process.env.DB_HOST}:${process.env.DB_PORT}`); + console.log(`šŸ”“ Redis: ${process.env.REDIS_HOST || 'localhost'}:${process.env.REDIS_PORT || 6379}`); + + // Initialize AlertService to check SMS status + const alertService = new AlertService(); + if (alertService.twilioEnabled) { + console.log('šŸ“± SMS Alerts: āœ… Enabled'); + } else { + console.log('šŸ“± SMS Alerts: āš ļø Disabled (no Twilio credentials)'); + } + + console.log(`šŸ“Š Health check: http://localhost:${PORT}/health`); + console.log(`🌐 API endpoint: http://localhost:${PORT}/api`); + console.log('================================================\n'); }); } catch (error) { console.error('Unable to start server:', error); diff --git a/server/services/alertService.js b/server/services/alertService.js index 050a008..ef18066 100644 --- a/server/services/alertService.js +++ b/server/services/alertService.js @@ -5,6 +5,8 @@ const { Op } = require('sequelize'); class AlertService { constructor() { this.twilioClient = null; + this.twilioPhone = null; + this.twilioEnabled = false; this.initializeTwilio(); } @@ -89,13 +91,40 @@ class AlertService { } initializeTwilio() { - if (process.env.TWILIO_ACCOUNT_SID && process.env.TWILIO_AUTH_TOKEN) { - this.twilioClient = twilio( - process.env.TWILIO_ACCOUNT_SID, - process.env.TWILIO_AUTH_TOKEN - ); - } else { - console.warn('Twilio credentials not configured. SMS alerts will be disabled.'); + // Check if Twilio credentials are provided + const accountSid = process.env.TWILIO_ACCOUNT_SID; + const authToken = process.env.TWILIO_AUTH_TOKEN; + const phoneNumber = process.env.TWILIO_PHONE_NUMBER; + + // If any Twilio credential is missing, disable SMS functionality + if (!accountSid || !authToken || !phoneNumber || + accountSid.trim() === '' || authToken.trim() === '' || phoneNumber.trim() === '') { + console.log('šŸ“± Twilio credentials not configured - SMS alerts disabled'); + console.log('ā„¹ļø To enable SMS alerts, set TWILIO_ACCOUNT_SID, TWILIO_AUTH_TOKEN, and TWILIO_PHONE_NUMBER'); + this.twilioEnabled = false; + this.twilioClient = null; + return; + } + + // Validate Twilio Account SID format + if (!accountSid.startsWith('AC')) { + console.log('āš ļø Invalid Twilio Account SID format - SMS alerts disabled'); + console.log('ā„¹ļø Account SID must start with "AC"'); + this.twilioEnabled = false; + this.twilioClient = null; + return; + } + + try { + this.twilioClient = twilio(accountSid, authToken); + this.twilioPhone = phoneNumber; + this.twilioEnabled = true; + console.log('šŸ“± Twilio SMS service initialized successfully'); + } catch (error) { + console.error('āŒ Failed to initialize Twilio:', error.message); + console.log('šŸ“± SMS alerts disabled due to Twilio initialization error'); + this.twilioEnabled = false; + this.twilioClient = null; } } @@ -343,27 +372,63 @@ class AlertService { } async sendSMSAlert(phoneNumber, message, rule, detection) { - if (!this.twilioClient) { - throw new Error('Twilio not configured'); + // Check if Twilio is enabled + if (!this.twilioEnabled || !this.twilioClient) { + console.log('šŸ“± SMS alert skipped - Twilio not configured'); + console.log(`šŸ“± Would have sent to ${phoneNumber}: ${message}`); + + return await AlertLog.create({ + alert_rule_id: rule.id, + detection_id: detection.id, + alert_type: 'sms', + recipient: phoneNumber, + message: message, + status: 'failed', + sent_at: new Date(), + external_id: null, + priority: rule.priority, + error_message: 'SMS service not configured' + }); } - const twilioMessage = await this.twilioClient.messages.create({ - body: message, - from: process.env.TWILIO_PHONE_NUMBER, - to: phoneNumber - }); + try { + console.log(`šŸ“± Sending SMS alert to ${phoneNumber}`); + + const twilioMessage = await this.twilioClient.messages.create({ + body: message, + from: this.twilioPhone, + to: phoneNumber + }); - return await AlertLog.create({ - alert_rule_id: rule.id, - detection_id: detection.id, - alert_type: 'sms', - recipient: phoneNumber, - message: message, - status: 'sent', - sent_at: new Date(), - external_id: twilioMessage.sid, - priority: rule.priority - }); + console.log(`āœ… SMS sent successfully: ${twilioMessage.sid}`); + + return await AlertLog.create({ + alert_rule_id: rule.id, + detection_id: detection.id, + alert_type: 'sms', + recipient: phoneNumber, + message: message, + status: 'sent', + sent_at: new Date(), + external_id: twilioMessage.sid, + priority: rule.priority + }); + } catch (error) { + console.error('āŒ Failed to send SMS:', error.message); + + return await AlertLog.create({ + alert_rule_id: rule.id, + detection_id: detection.id, + alert_type: 'sms', + recipient: phoneNumber, + message: message, + status: 'failed', + sent_at: new Date(), + external_id: null, + priority: rule.priority, + error_message: error.message + }); + } } async sendEmailAlert(email, message, rule, detection) {