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
3 changes: 2 additions & 1 deletion .dockerignore
Original file line number Diff line number Diff line change
@@ -1,4 +1,5 @@
docs/
README.md
node_modules
npm-debug.log
npm-debug.log
.devcontainer
1 change: 1 addition & 0 deletions .gitignore
Original file line number Diff line number Diff line change
Expand Up @@ -154,3 +154,4 @@ vite.config.ts.timestamp-*
# Misc
.DS_Store
*.pem
.devcontainer/
23 changes: 12 additions & 11 deletions apps/backend/ecosystem.config.js
Original file line number Diff line number Diff line change
Expand Up @@ -7,35 +7,35 @@ module.exports = {
exec_mode: 'cluster',
env: {
NODE_ENV: 'development',
PORT: 3000
PORT: 3000,
},
env_production: {
NODE_ENV: 'production',
PORT: 3000
PORT: 3000,
},
// Logging
log_file: './logs/combined.log',
out_file: './logs/out.log',
error_file: './logs/error.log',
log_date_format: 'YYYY-MM-DD HH:mm:ss Z',

// Auto restart configuration
max_memory_restart: '1G',
restart_delay: 4000,
max_restarts: 10,
min_uptime: '10s',

// Health monitoring
kill_timeout: 5000,
listen_timeout: 3000,

// Source map support for better error tracking
source_map_support: true,

// Auto restart when file changes (disable in production)
watch: false,
ignore_watch: ['node_modules', 'logs']
}
ignore_watch: ['node_modules', 'logs'],
},
],

deploy: {
Expand All @@ -45,7 +45,8 @@ module.exports = {
ref: 'origin/main',
repo: 'git@github.com:username/shared-media-streaming.git',
path: '/var/www/production',
'post-deploy': 'pnpm install && pnpm run build:prod && pm2 reload ecosystem.config.js --env production'
}
}
'post-deploy':
'pnpm install && pnpm run build:prod && pm2 reload ecosystem.config.js --env production',
},
},
};
60 changes: 26 additions & 34 deletions apps/backend/package-lock.json

Some generated files are not rendered by default. Learn more about how customized files appear on GitHub.

58 changes: 58 additions & 0 deletions apps/backend/src/app.ts
Original file line number Diff line number Diff line change
Expand Up @@ -5,6 +5,7 @@ import mongoSanitize from 'express-mongo-sanitize';
import globalErrorHandler from './middleware/errorHandler';
import AppError from './utils/appError';
import { HTTP_STATUS } from './constants/httpStatus';
import AWS from 'aws-sdk';

const app = express();

Expand Down Expand Up @@ -176,6 +177,63 @@ app.use('*', (_req, res) => {
});
});

app.post('/upload-test-file', async (_req, res) => {
const bucketName = process.env.S3_BUCKET;
const fileName = `test-file-${Date.now()}.txt`;
const fileContent = 'This is a test file uploaded from my Express app!';

AWS.config.update({
accessKeyId: process.env.S3_USER_KEY,
secretAccessKey: process.env.S3_SECRET,
region: process.env.S3_REGION,
});

const s3 = new AWS.S3();

if (!bucketName) {
return res.status(500).json({
success: false,
message: 'S3_BUCKET environment variable is not set.',
});
}

const params = {
Bucket: bucketName,
Key: fileName,
Body: fileContent,
ContentType: 'text/plain',
ACL: 'private',
};

try {
const data = await s3.upload(params).promise();
res.json({
success: true,
message: 'Test file uploaded successfully to S3!',
fileLocation: data.Location,
fileName: data.Key,
bucket: data.Bucket,
});
} catch (error: unknown) {
if (error instanceof Error) {
console.error('S3 upload failed:', error.message);
res.status(500).json({
success: false,
message: 'Failed to upload test file to S3.',
error: error.message,
});
} else {
// fallback for non-Error types
console.error('S3 upload failed with unknown error:', error);
res.status(500).json({
success: false,
message: 'Failed to upload test file to S3.',
error: String(error),
});
}
}
});

// Global error handler
app.use(globalErrorHandler);

Expand Down
22 changes: 12 additions & 10 deletions apps/backend/src/config/db.ts
Original file line number Diff line number Diff line change
@@ -1,22 +1,24 @@
import mongoose from "mongoose";
import mongoose from 'mongoose';

export const connectDB = async () => {
console.log("🔍 Debug - Environment variables:");
console.log("MONGO_URI:", process.env.MONGO_URI);
console.log("PORT:", process.env.PORT);
console.log('Debug - Environment variables:');
console.log('MONGO_URI:', process.env.MONGO_URI);
console.log('PORT:', process.env.PORT);

if (!process.env.MONGO_URI) {
console.error("❌ MONGO_URI is not defined in environment variables");
console.error("💡 Make sure your .env file is in the correct location and contains MONGO_URI");
console.error('MONGO_URI is not defined in environment variables');
console.error(
'💡 Make sure your .env file is in the correct location and contains MONGO_URI',
);
process.exit(1);
}

try {
console.log(`🔄 Connecting to MongoDB...`);
console.log(`Connecting to MongoDB...`);
await mongoose.connect(process.env.MONGO_URI as string);
console.log("✅ MongoDB connected successfully");
console.log('MongoDB connected successfully');
} catch (err) {
console.error("❌ MongoDB connection error:", err);
console.error('MongoDB connection error:', err);
process.exit(1);
}
};
51 changes: 27 additions & 24 deletions apps/backend/src/index.ts
Original file line number Diff line number Diff line change
@@ -1,40 +1,43 @@
import fs from "node:fs";
import path from "node:path";
import dotenv from "dotenv";

import app from "./app";
import { connectDB } from "./config/db";
import fs from 'node:fs';
import path from 'node:path';
import dotenv from 'dotenv';

import app from './app';
import { connectDB } from './config/db';

// Load environment variables based on NODE_ENV
const nodeEnv = process.env.NODE_ENV || "development";
const envFiles = [`.env.${nodeEnv}.local`, `.env.${nodeEnv}`, ".env.local", ".env"];
const nodeEnv = process.env.NODE_ENV || 'development';
const envFiles = [
`.env.${nodeEnv}.local`,
`.env.${nodeEnv}`,
'.env.local',
'.env',
];

console.log(`🌍 Environment: ${nodeEnv}`);

// Load the first existing environment file
for (const envFile of envFiles) {
const envPath = path.resolve(process.cwd(), envFile);
if (fs.existsSync(envPath)) {
dotenv.config({ path: envPath });
console.log(`🔧 Loading environment from: ${envPath}`);
break;
}
const envPath = path.resolve(process.cwd(), envFile);
if (fs.existsSync(envPath)) {
dotenv.config({ path: envPath });
console.log(`🔧 Loading environment from: ${envPath}`);
break;
}
}


const port = process.env.PORT || 3000;

async function startServer() {
try {
await connectDB();
app.listen(port, () => {
console.log(`application running on port ${port}`);
});
} catch (error) {
console.error("failed to start the server", error);
process.exit(1);
}
try {
await connectDB();
app.listen(port, () => {
console.log(`application running on port ${port}`);
});
} catch (error) {
console.error('failed to start the server', error);
process.exit(1);
}
}

startServer();
8 changes: 4 additions & 4 deletions apps/backend/src/middleware/errorHandler.ts
Original file line number Diff line number Diff line change
Expand Up @@ -3,12 +3,12 @@ import AppError from '../utils/appError';
import mongoose from 'mongoose';
import { HTTP_STATUS } from '../constants/httpStatus';

const handleCastErroDB = (err: mongoose.Error.CastError) => {
const handleCastErrorDB = (err: mongoose.Error.CastError) => {
const message = `Invalid ${err.path}: ${err.value}.`;
return new AppError(message, HTTP_STATUS.BAD_REQUEST);
};

const handleDublicateFieldsDB = (err: any) => {
const handleDuplicateFieldsDB = (err: any) => {
const value = err.errorResponse.errmsg.match(/(["'])(\\?.)*?\1/)[0];

const message = `The value '${value}' is already in use. Please choose a different value.`;
Expand Down Expand Up @@ -64,8 +64,8 @@ const globalErrorHandler = (
} else if (process.env.NODE_ENV === 'production') {
let error = Object.create(err);

if (error.name === 'CastError') error = handleCastErroDB(error);
if (error.code === 11000) error = handleDublicateFieldsDB(error);
if (error.name === 'CastError') error = handleCastErrorDB(error);
if (error.code === 11000) error = handleDuplicateFieldsDB(error);
if (error.name === 'ValidationError')
error = handleValidationErrorDB(error);

Expand Down
Loading