Files
mb-grid-solutions.com/app/api/contact/route.ts
Marc Mintel 42295c3c41
Some checks failed
Build & Deploy / 🔍 Prepare Environment (push) Successful in 5s
Build & Deploy / 🧪 QA (push) Failing after 36s
Build & Deploy / 🏗️ Build (push) Failing after 1m56s
Build & Deploy / 🚀 Deploy (push) Has been skipped
Build & Deploy / 🔔 Notifications (push) Successful in 2s
feat: improved analytics
2026-02-09 23:36:05 +01:00

150 lines
4.9 KiB
TypeScript

import { NextResponse } from "next/server";
import * as nodemailer from "nodemailer";
import directus, { ensureAuthenticated } from "@/lib/directus";
import { createItem } from "@directus/sdk";
import { getServerAppServices } from "@/lib/services/create-services.server";
export async function POST(req: Request) {
const services = getServerAppServices();
const logger = services.logger.child({ action: "contact_submission" });
// Set analytics context from request headers for high-fidelity server-side tracking
// This fulfills the "server-side via nextjs proxy" requirement
if ("setServerContext" in services.analytics) {
(services.analytics as any).setServerContext({
userAgent: req.headers.get("user-agent") || undefined,
language: req.headers.get("accept-language")?.split(",")[0] || undefined,
referrer: req.headers.get("referer") || undefined,
ip: req.headers.get("x-forwarded-for")?.split(",")[0] || undefined,
});
}
try {
const { name, email, company, message, website } = await req.json();
// Track attempt
services.analytics.track("contact-form-attempt");
// Honeypot check
if (website) {
logger.info("Spam detected (honeypot)");
return NextResponse.json({ message: "Ok" });
}
// Validation
if (!name || name.length < 2 || name.length > 100) {
return NextResponse.json({ error: "Ungültiger Name" }, { status: 400 });
}
if (!email || !/^\S+@\S+\.\S+$/.test(email)) {
return NextResponse.json({ error: "Ungültige E-Mail" }, { status: 400 });
}
if (!message || message.length < 20) {
return NextResponse.json({ error: "message_too_short" }, { status: 400 });
}
if (message.length > 4000) {
return NextResponse.json({ error: "message_too_long" }, { status: 400 });
}
// 1. Directus save
let directusSaved = false;
try {
await ensureAuthenticated();
await directus.request(
createItem("contact_submissions", {
name,
email,
company: company || "Nicht angegeben",
message,
}),
);
logger.info("Contact submission saved to Directus");
directusSaved = true;
} catch (directusError) {
const errorMessage =
directusError instanceof Error
? directusError.message
: String(directusError);
logger.error("Failed to save to Directus", {
error: errorMessage,
details: directusError,
});
services.errors.captureException(directusError, {
phase: "directus_save",
});
// We still try to send the email even if Directus fails
}
// 2. Email sending
try {
const { config } = await import("@/lib/config");
const transporter = nodemailer.createTransport({
host: config.mail.host,
port: config.mail.port,
secure: config.mail.port === 465,
auth: {
user: config.mail.user,
pass: config.mail.pass,
},
});
await transporter.sendMail({
from: config.mail.from,
to: config.mail.recipients.join(",") || "info@mb-grid-solutions.com",
replyTo: email,
subject: `Kontaktanfrage von ${name}`,
text: `
Name: ${name}
Firma: ${company || "Nicht angegeben"}
E-Mail: ${email}
Zeitpunkt: ${new Date().toISOString()}
Nachricht:
${message}
`,
});
logger.info("Email sent successfully");
// Notify success for important leads
await services.notifications.notify({
title: "📩 Neue Kontaktanfrage",
message: `Anfrage von ${name} (${email}) erhalten.\nFirma: ${company || "Nicht angegeben"}`,
priority: 5,
});
} catch (smtpError) {
logger.error("SMTP Error", { error: smtpError });
services.errors.captureException(smtpError, { phase: "smtp_send" });
// If Directus failed AND SMTP failed, then we really have a problem
if (!directusSaved) {
return NextResponse.json(
{ error: "Systemfehler (Speicherung und Versand fehlgeschlagen)" },
{ status: 500 },
);
}
// If Directus was successful, we tell the user "Ok" but we know internally it was a partial failure
await services.notifications.notify({
title: "🚨 SMTP Fehler (Kontaktformular)",
message: `Anfrage von ${name} (${email}) in Directus gespeichert, aber E-Mail-Versand fehlgeschlagen: ${smtpError instanceof Error ? smtpError.message : String(smtpError)}`,
priority: 8,
});
}
// Track success
services.analytics.track("contact-form-success", {
has_company: Boolean(company),
});
return NextResponse.json({ message: "Ok" });
} catch (error) {
logger.error("Global API Error", { error });
services.errors.captureException(error, { phase: "api_global" });
return NextResponse.json(
{ error: "Interner Serverfehler" },
{ status: 500 },
);
}
}