Replace static Hello World with KenJim Technologies React app

- Vite + React frontend: hero, services grid, contact form
- Express + nodemailer backend for contact form → kenji@kenjim.com
- Multi-stage Docker builds; nginx inside frontend proxies /api to backend
- SMTP config via .env (see .env.example)

Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
This commit is contained in:
2026-06-19 15:18:16 +00:00
parent bcb354d074
commit e802f03f02
25 changed files with 809 additions and 40 deletions

48
backend/server.js Normal file
View File

@@ -0,0 +1,48 @@
const express = require('express')
const nodemailer = require('nodemailer')
const cors = require('cors')
const app = express()
app.use(cors())
app.use(express.json())
const transporter = nodemailer.createTransport({
host: process.env.SMTP_HOST,
port: parseInt(process.env.SMTP_PORT || '587'),
secure: process.env.SMTP_SECURE === 'true',
auth: {
user: process.env.SMTP_USER,
pass: process.env.SMTP_PASS,
},
})
app.post('/contact', async (req, res) => {
const { name, email, service, message } = req.body
if (!name || !email || !message) {
return res.status(400).json({ error: 'Name, email, and message are required.' })
}
try {
await transporter.sendMail({
from: `"KenJim Technologies" <${process.env.SMTP_USER}>`,
to: process.env.CONTACT_TO,
replyTo: email,
subject: `[kenjim.com] ${service || 'General Inquiry'}${name}`,
text: `Name: ${name}\nEmail: ${email}\nService: ${service || 'General Inquiry'}\n\n${message}`,
html: `
<p><strong>Name:</strong> ${name}</p>
<p><strong>Email:</strong> <a href="mailto:${email}">${email}</a></p>
<p><strong>Service:</strong> ${service || 'General Inquiry'}</p>
<hr/>
<p>${message.replace(/\n/g, '<br>')}</p>
`,
})
res.json({ ok: true })
} catch (err) {
console.error('Mail error:', err)
res.status(500).json({ error: 'Failed to send message. Please try again.' })
}
})
app.listen(3001, () => console.log('API listening on :3001'))