Impressum mit den Anbieterdaten der GEFIM UG
Daten aus gefim.de/impressum als zentrale Konstante (src/lib/marketing/imprint.ts), Seite /impressum öffentlich und in der Fußzeile verlinkt. Der dort abgeschnittene Satz zur Verbraucherstreitbeilegung ist mit der Standardformulierung vervollständigt. Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
This commit is contained in:
@@ -398,5 +398,22 @@
|
|||||||
},
|
},
|
||||||
"shotFrame": {
|
"shotFrame": {
|
||||||
"label": "Bildschirmfoto aus Craftvia"
|
"label": "Bildschirmfoto aus Craftvia"
|
||||||
|
},
|
||||||
|
"imprint": {
|
||||||
|
"title": "Impressum",
|
||||||
|
"intro": "Angaben gemäß § 5 Digitale-Dienste-Gesetz (DDG).",
|
||||||
|
"provider": "Anbieter",
|
||||||
|
"represented": "Vertreten durch",
|
||||||
|
"contact": "Kontakt",
|
||||||
|
"phone": "Telefon",
|
||||||
|
"email": "E-Mail",
|
||||||
|
"register": "Registereintrag",
|
||||||
|
"registerCourt": "Registergericht",
|
||||||
|
"registerNumber": "Handelsregister",
|
||||||
|
"vat": "Umsatzsteuer-ID",
|
||||||
|
"vatText": "Umsatzsteuer-Identifikationsnummer gemäß § 27 a Umsatzsteuergesetz:",
|
||||||
|
"editorial": "Redaktionell verantwortlich",
|
||||||
|
"dispute": "Verbraucherstreitbeilegung / Universalschlichtungsstelle",
|
||||||
|
"disputeText": "Wir sind nicht bereit oder verpflichtet, an Streitbeilegungsverfahren vor einer Verbraucherschlichtungsstelle teilzunehmen."
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -398,5 +398,22 @@
|
|||||||
},
|
},
|
||||||
"shotFrame": {
|
"shotFrame": {
|
||||||
"label": "Screenshot from Craftvia"
|
"label": "Screenshot from Craftvia"
|
||||||
|
},
|
||||||
|
"imprint": {
|
||||||
|
"title": "Imprint",
|
||||||
|
"intro": "Information pursuant to § 5 of the German Digital Services Act (DDG).",
|
||||||
|
"provider": "Provider",
|
||||||
|
"represented": "Represented by",
|
||||||
|
"contact": "Contact",
|
||||||
|
"phone": "Phone",
|
||||||
|
"email": "E-mail",
|
||||||
|
"register": "Commercial register",
|
||||||
|
"registerCourt": "Register court",
|
||||||
|
"registerNumber": "Register number",
|
||||||
|
"vat": "VAT ID",
|
||||||
|
"vatText": "VAT identification number pursuant to § 27 a of the German VAT Act:",
|
||||||
|
"editorial": "Editorially responsible",
|
||||||
|
"dispute": "Consumer dispute resolution",
|
||||||
|
"disputeText": "We are neither willing nor obliged to take part in dispute resolution proceedings before a consumer arbitration board."
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -0,0 +1,70 @@
|
|||||||
|
import type { Metadata } from "next";
|
||||||
|
import { getTranslations } from "next-intl/server";
|
||||||
|
import { IMPRINT } from "@/lib/marketing/imprint";
|
||||||
|
|
||||||
|
export async function generateMetadata(): Promise<Metadata> {
|
||||||
|
const t = await getTranslations("marketing.imprint");
|
||||||
|
return { title: t("title"), robots: { index: true, follow: true } };
|
||||||
|
}
|
||||||
|
|
||||||
|
/** Impressum der Produktseite — Daten aus src/lib/marketing/imprint.ts. */
|
||||||
|
export default async function ImprintPage() {
|
||||||
|
const t = await getTranslations("marketing.imprint");
|
||||||
|
const block = "mt-8 font-heading text-[17px] font-semibold";
|
||||||
|
|
||||||
|
return (
|
||||||
|
<article className="mx-auto max-w-3xl px-4 py-12 sm:px-6">
|
||||||
|
<h1 className="font-heading text-[30px] font-bold text-[var(--ui-primary)]">{t("title")}</h1>
|
||||||
|
<p className="mt-2 text-[14px] text-muted-foreground">{t("intro")}</p>
|
||||||
|
|
||||||
|
<h2 className={block}>{t("provider")}</h2>
|
||||||
|
<address className="mt-2 text-[15px] leading-relaxed not-italic">
|
||||||
|
{IMPRINT.company}
|
||||||
|
<br />
|
||||||
|
{IMPRINT.street}
|
||||||
|
<br />
|
||||||
|
{IMPRINT.city}
|
||||||
|
<br />
|
||||||
|
{IMPRINT.country}
|
||||||
|
</address>
|
||||||
|
|
||||||
|
<h2 className={block}>{t("represented")}</h2>
|
||||||
|
<p className="mt-2 text-[15px]">{IMPRINT.representatives.join(", ")}</p>
|
||||||
|
|
||||||
|
<h2 className={block}>{t("contact")}</h2>
|
||||||
|
<dl className="mt-2 grid grid-cols-[max-content_1fr] gap-x-4 gap-y-1 text-[15px]">
|
||||||
|
<dt className="text-muted-foreground">{t("phone")}</dt>
|
||||||
|
<dd>
|
||||||
|
<a href={IMPRINT.phoneHref} className="underline-offset-2 hover:underline">
|
||||||
|
{IMPRINT.phone}
|
||||||
|
</a>
|
||||||
|
</dd>
|
||||||
|
<dt className="text-muted-foreground">{t("email")}</dt>
|
||||||
|
<dd>
|
||||||
|
<a href={`mailto:${IMPRINT.email}`} className="underline-offset-2 hover:underline">
|
||||||
|
{IMPRINT.email}
|
||||||
|
</a>
|
||||||
|
</dd>
|
||||||
|
</dl>
|
||||||
|
|
||||||
|
<h2 className={block}>{t("register")}</h2>
|
||||||
|
<dl className="mt-2 grid grid-cols-[max-content_1fr] gap-x-4 gap-y-1 text-[15px]">
|
||||||
|
<dt className="text-muted-foreground">{t("registerCourt")}</dt>
|
||||||
|
<dd>{IMPRINT.registerCourt}</dd>
|
||||||
|
<dt className="text-muted-foreground">{t("registerNumber")}</dt>
|
||||||
|
<dd>{IMPRINT.registerNumber}</dd>
|
||||||
|
</dl>
|
||||||
|
|
||||||
|
<h2 className={block}>{t("vat")}</h2>
|
||||||
|
<p className="mt-2 text-[15px]">
|
||||||
|
{t("vatText")} {IMPRINT.vatId}
|
||||||
|
</p>
|
||||||
|
|
||||||
|
<h2 className={block}>{t("editorial")}</h2>
|
||||||
|
<p className="mt-2 text-[15px]">{IMPRINT.editorial}</p>
|
||||||
|
|
||||||
|
<h2 className={block}>{t("dispute")}</h2>
|
||||||
|
<p className="mt-2 text-[15px] leading-relaxed">{t("disputeText")}</p>
|
||||||
|
</article>
|
||||||
|
);
|
||||||
|
}
|
||||||
@@ -70,7 +70,7 @@ export async function MarketingShell({ children }: { children: React.ReactNode }
|
|||||||
<nav aria-labelledby="footer-legal">
|
<nav aria-labelledby="footer-legal">
|
||||||
<h2 id="footer-legal" className="text-[13px] font-semibold tracking-wide uppercase">{t("footer.company")}</h2>
|
<h2 id="footer-legal" className="text-[13px] font-semibold tracking-wide uppercase">{t("footer.company")}</h2>
|
||||||
<ul className="mt-2 grid">
|
<ul className="mt-2 grid">
|
||||||
<li><Link href="/login" className="inline-flex min-h-11 items-center text-[14px] text-muted-foreground hover:text-foreground">{t("footer.login")}</Link></li>
|
<li><Link href="/impressum" className="inline-flex min-h-11 items-center text-[14px] text-muted-foreground hover:text-foreground">{t("footer.imprint")}</Link></li>
|
||||||
<li><Link href="/testen/nutzungsbedingungen" className="inline-flex min-h-11 items-center text-[14px] text-muted-foreground hover:text-foreground">{t("footer.terms")}</Link></li>
|
<li><Link href="/testen/nutzungsbedingungen" className="inline-flex min-h-11 items-center text-[14px] text-muted-foreground hover:text-foreground">{t("footer.terms")}</Link></li>
|
||||||
<li><Link href="/testen/datenschutz" className="inline-flex min-h-11 items-center text-[14px] text-muted-foreground hover:text-foreground">{t("footer.privacy")}</Link></li>
|
<li><Link href="/testen/datenschutz" className="inline-flex min-h-11 items-center text-[14px] text-muted-foreground hover:text-foreground">{t("footer.privacy")}</Link></li>
|
||||||
</ul>
|
</ul>
|
||||||
|
|||||||
@@ -0,0 +1,19 @@
|
|||||||
|
/**
|
||||||
|
* Anbieterkennzeichnung (§ 5 DDG) — übernommen aus https://gefim.de/impressum (Stand 21.09.2026).
|
||||||
|
* Einzige Quelle für Impressum und ggf. Mail-Fußzeilen; Beschriftungen stehen im Message-Katalog.
|
||||||
|
*/
|
||||||
|
export const IMPRINT = {
|
||||||
|
company: "GEFIM UG (haftungsbeschränkt)",
|
||||||
|
street: "Neckarstraße 7",
|
||||||
|
city: "38120 Braunschweig",
|
||||||
|
country: "Deutschland",
|
||||||
|
registerNumber: "211852",
|
||||||
|
registerCourt: "Braunschweig",
|
||||||
|
representatives: ["Martin Solarczek", "Marcel Martin Hofmann"],
|
||||||
|
phone: "+49 531 180 540 80",
|
||||||
|
phoneHref: "tel:+4953118054080",
|
||||||
|
email: "info@gefim.de",
|
||||||
|
vatId: "DE449952428",
|
||||||
|
/** Redaktionell verantwortlich (§ 18 Abs. 2 MStV) — wie auf gefim.de angegeben */
|
||||||
|
editorial: "GEFIM UG (haftungsbeschränkt), Neckarstraße 7, 38120 Braunschweig",
|
||||||
|
} as const;
|
||||||
+1
-1
@@ -12,7 +12,7 @@ import { NextResponse, type NextRequest } from "next/server";
|
|||||||
// L15 Testphase: `/testen` (Wizard, Bestätigung, Nutzungsbedingungen, Datenschutz) ist öffentlich —
|
// L15 Testphase: `/testen` (Wizard, Bestätigung, Nutzungsbedingungen, Datenschutz) ist öffentlich —
|
||||||
// abgesichert über Rate-Limit je IP/E-Mail, Honeypot, Double-Opt-in und Enumeration-Neutralität.
|
// abgesichert über Rate-Limit je IP/E-Mail, Honeypot, Double-Opt-in und Enumeration-Neutralität.
|
||||||
// Startseite ist die öffentliche Produktseite; angemeldete Nutzer leitet page.tsx weiter.
|
// Startseite ist die öffentliche Produktseite; angemeldete Nutzer leitet page.tsx weiter.
|
||||||
const PUBLIC_PATHS = ["/", "/funktionen", "/sicherheit", "/preise", "/login", "/api/auth", "/forgot-password", "/reset", "/invite", "/verify-email", "/platform/login", "/api/platform-auth", "/testen"];
|
const PUBLIC_PATHS = ["/", "/funktionen", "/sicherheit", "/preise", "/impressum", "/login", "/api/auth", "/forgot-password", "/reset", "/invite", "/verify-email", "/platform/login", "/api/platform-auth", "/testen"];
|
||||||
|
|
||||||
// Plattform-Bereich (getrennte Session/Login): diese Routen werden über das
|
// Plattform-Bereich (getrennte Session/Login): diese Routen werden über das
|
||||||
// Plattform-Cookie gegatet und leiten anonyme Besucher auf /platform/login —
|
// Plattform-Cookie gegatet und leiten anonyme Besucher auf /platform/login —
|
||||||
|
|||||||
Reference in New Issue
Block a user