Skip to content
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
8 changes: 8 additions & 0 deletions backend/index.js
Original file line number Diff line number Diff line change
@@ -1,9 +1,14 @@
/* eslint-disable no-undef */
const express = require("express");
require("dotenv").config();
const { validateEnv } = require("./utils/envValidator");
const botRouter = require("./routes/botRoutes");
const { errorHandler } = require("./middleware/validation");
const cors = require("cors");

// Validate environment variables on startup
validateEnv();

const app = express();
app.use(
cors({
Expand All @@ -23,6 +28,9 @@ app.get("/", (req, res) => {
res.send("Backend is Running!");
});

// Error handling middleware (must be last)
app.use(errorHandler);

app.listen(port, () => {
console.log(`Server is running at http://localhost:${port}`);
});
214 changes: 214 additions & 0 deletions backend/utils/envValidator.js
Original file line number Diff line number Diff line change
@@ -0,0 +1,214 @@
/**
* Environment Variable Validation Utility
* Validates required environment variables on application startup
*/

/**
* Configuration for required environment variables
*/
const envConfig = {
required: [
{
name: 'NODE_ENV',
description: 'Application environment (development, production, test)',
defaultValue: 'development',
},
{
name: 'SERVER_PORT',
description: 'Port number for the server',
defaultValue: '3000',
},
],
optional: [
{
name: 'FRONTEND_URL',
description: 'URL of the frontend application',
defaultValue: 'http://localhost:5173',
},
{
name: 'GEMINI_API_KEY',
description: 'Google Gemini API key for chatbot',
},
{
name: 'DATABASE_URL',
description: 'Database connection string',
},
{
name: 'JWT_SECRET',
description: 'Secret key for JWT token generation',
},
{
name: 'EMAIL_HOST',
description: 'SMTP host for sending emails',
},
{
name: 'EMAIL_PORT',
description: 'SMTP port',
},
{
name: 'EMAIL_USER',
description: 'Email username',
},
{
name: 'EMAIL_PASSWORD',
description: 'Email password',
},
],
};

/**
* Validate a single environment variable
*/
const validateEnvVar = (config, isRequired) => {
const value = process.env[config.name];

Check failure on line 63 in backend/utils/envValidator.js

View workflow job for this annotation

GitHub Actions / build (18.x)

'process' is not defined

Check failure on line 63 in backend/utils/envValidator.js

View workflow job for this annotation

GitHub Actions / build (20.x)

'process' is not defined

if (!value) {
if (config.defaultValue) {
process.env[config.name] = config.defaultValue;

Check failure on line 67 in backend/utils/envValidator.js

View workflow job for this annotation

GitHub Actions / build (18.x)

'process' is not defined

Check failure on line 67 in backend/utils/envValidator.js

View workflow job for this annotation

GitHub Actions / build (20.x)

'process' is not defined
return {
status: 'default',
name: config.name,
value: config.defaultValue,
description: config.description,
};
}

return {
status: isRequired ? 'missing' : 'optional',
name: config.name,
description: config.description,
};
}

return {
status: 'valid',
name: config.name,
value: value.substring(0, 20) + (value.length > 20 ? '...' : ''),
description: config.description,
};
};

/**
* Validate all environment variables
*/
const validateEnv = () => {
console.log('\n🔍 Validating environment variables...\n');

const results = {
valid: [],
defaults: [],
missing: [],
optional: [],
};

// Check required variables
envConfig.required.forEach((config) => {
const result = validateEnvVar(config, true);

if (result.status === 'valid') {
results.valid.push(result);
} else if (result.status === 'default') {
results.defaults.push(result);
} else if (result.status === 'missing') {
results.missing.push(result);
}
});

// Check optional variables
envConfig.optional.forEach((config) => {
const result = validateEnvVar(config, false);

if (result.status === 'valid') {
results.valid.push(result);
} else if (result.status === 'default') {
results.defaults.push(result);
} else {
results.optional.push(result);
}
});

// Display results
if (results.valid.length > 0) {
console.log('✓ Valid environment variables:');
results.valid.forEach((item) => {
console.log(` ✓ ${item.name} - ${item.description}`);
});
console.log('');
}

if (results.defaults.length > 0) {
console.log('⚠ Using default values:');
results.defaults.forEach((item) => {
console.log(` ⚠ ${item.name} = ${item.value} (${item.description})`);
});
console.log('');
}

if (results.optional.length > 0) {
console.log('ℹ Optional variables not set:');
results.optional.forEach((item) => {
console.log(` ℹ ${item.name} - ${item.description}`);
});
console.log('');
}

if (results.missing.length > 0) {
console.log('✖ Missing required environment variables:');
results.missing.forEach((item) => {
console.log(` ✖ ${item.name} - ${item.description}`);
});
console.log('');
console.log('Please set the missing environment variables in your .env file');
console.log('See .env.example for reference\n');

if (process.env.NODE_ENV === 'production') {
process.exit(1);
} else {
console.log('Running in development mode - continuing with warnings\n');
}
} else {
console.log('✓ All required environment variables are set!\n');
}

return results;
};

/**
* Generate .env.example file based on config
*/
const generateEnvExample = () => {
const lines = [
'# Environment Variables Configuration',
'# Copy this file to .env and fill in your values',
'',
'# Required Variables',
'',
];

envConfig.required.forEach((config) => {
lines.push(`# ${config.description}`);
if (config.defaultValue) {
lines.push(`${config.name}=${config.defaultValue}`);
} else {
lines.push(`${config.name}=`);
}
lines.push('');
});

lines.push('# Optional Variables');
lines.push('');

envConfig.optional.forEach((config) => {
lines.push(`# ${config.description}`);
lines.push(`${config.name}=`);
lines.push('');
});

return lines.join('\n');
};

module.exports = {
validateEnv,
generateEnvExample,
envConfig,
};
Loading