feat: Containerize services with Docker Compose (PostgreSQL, Strapi CMS, Express Backend, Nginx Frontend) on custom ports >9000

This commit is contained in:
Vishva
2026-08-03 19:58:10 +05:30
parent 48f8ab9716
commit 6244fd4072
247 changed files with 56672 additions and 169 deletions
+42 -14
View File
@@ -1,8 +1,10 @@
import express from 'express';
import multer from 'multer';
import { saveLead, getLeads } from '../db.js';
import { sendContactEmail } from '../services/mailService.js';
import { sendContactEmail, sendCareersEmail, sendStrategyEmail } from '../services/mailService.js';
const router = express.Router();
const upload = multer({ storage: multer.memoryStorage(), limits: { fileSize: 10 * 1024 * 1024 } });
async function verifyTurnstile(token, remoteip) {
const secretKey = process.env.TURNSTILE_SECRET_KEY || '1x000000000000000000000000000000AA';
@@ -25,10 +27,10 @@ async function verifyTurnstile(token, remoteip) {
}
}
// POST /api/contact - Handle Contact Us Form submission via SMTP
router.post('/', async (req, res) => {
// POST /api/contact - Handle Contact, Careers, and Strategy Call form submissions via SMTP
router.post('/', upload.single('resume'), async (req, res) => {
try {
const { name, email, phone, mobile, subject, message, interests, type, turnstileToken } = req.body;
const { name, email, phone, mobile, subject, message, interests, type, designation, dateTime, resumeName, turnstileToken } = req.body;
const contactName = name?.trim();
const contactEmail = email?.trim();
@@ -55,17 +57,43 @@ router.post('/', async (req, res) => {
phone: contactPhone,
subject: contactSubject,
message: contactMessage,
designation,
dateTime,
resumeName,
type: type || 'contact'
});
// Attempt sending email via SMTP service
const mailResult = await sendContactEmail({
name: contactName,
email: contactEmail,
phone: contactPhone,
subject: contactSubject,
message: contactMessage
});
// Attempt sending email via SMTP service based on form type
let mailResult = { success: false };
if (type === 'careers') {
mailResult = await sendCareersEmail({
name: contactName,
email: contactEmail,
phone: contactPhone,
resumeName: req.file ? req.file.originalname : (resumeName || 'Resume Uploaded'),
message: contactMessage,
file: req.file
});
} else if (type === 'strategy') {
mailResult = await sendStrategyEmail({
name: contactName,
email: contactEmail,
phone: contactPhone,
designation: designation || 'N/A',
dateTime: dateTime || 'N/A',
interests: interests || 'General Strategy Consultation',
message: contactMessage
});
} else {
mailResult = await sendContactEmail({
name: contactName,
email: contactEmail,
phone: contactPhone,
subject: contactSubject,
message: contactMessage
});
}
if (!mailResult.success) {
// If SMTP is not yet configured or fails, return 200 with lead saved & warning
@@ -74,7 +102,7 @@ router.post('/', async (req, res) => {
saved: true,
leadId: lead.id,
smtpError: mailResult.error,
message: 'Your message was saved successfully. Note: SMTP email dispatch requires SMTP credentials in .env.'
message: 'Your request was saved successfully. Note: SMTP email dispatch requires SMTP credentials in .env.'
});
}
@@ -83,7 +111,7 @@ router.post('/', async (req, res) => {
saved: true,
leadId: lead.id,
messageId: mailResult.messageId,
message: 'Message sent successfully via SMTP!'
message: 'Request sent successfully via SMTP!'
});
} catch (error) {
console.error('[Contact Route Error]', error);
+12 -1
View File
@@ -1,17 +1,28 @@
import { Router } from 'express';
import { getContent, updateSection, updateAllContent } from '../db.js';
import { requireAuth } from '../auth.js';
import { getStrapiBlogs } from '../strapi.js';
import seedContent from '../seed/default-content.json' with { type: 'json' };
const VALID_SECTIONS = Object.keys(seedContent);
const router = Router();
router.get('/', (_req, res) => {
router.get('/', async (_req, res) => {
const { content, updatedAt } = getContent();
const strapiItems = await getStrapiBlogs();
if (strapiItems && content.insights) {
content.insights.items = strapiItems;
}
res.json({ ...content, _updatedAt: updatedAt });
});
router.get('/blogs', async (_req, res) => {
const { content } = getContent();
const strapiItems = await getStrapiBlogs();
res.json(strapiItems || content.insights?.items || []);
});
router.put('/', requireAuth, (req, res) => {
const { _updatedAt, ...content } = req.body;
const updatedAt = updateAllContent(content);