Revert generalPartners, fix shareCapital: neither is a Pflichtangabe

Corrected after user feedback: Stammkapital/Grundkapital is only required on business correspondence if voluntarily disclosed in the first place (§35a Abs. 1 S. 2 GmbHG) — not an unconditional Pflichtangabe. shareCapital's Impressum rendering stays (shown only if an admin voluntarily filled it in), but it's dropped from the email/invoice footer.

generalPartners is removed entirely — the legal basis was genuinely unclear on research (§125a HGB's Geschäftsbriefe-naming duty only applies to the narrow case where no partner is a natural person; whether §5 DDG's Impressum-specific "vertretungsberechtigte Person" requirement independently mandates it for the general OHG/KG case wasn't resolved with confidence) — reverted rather than shipped on an uncertain legal basis.

Also fixes stale "§5 TMG" citations to "§5 DDG" (TMG was replaced 14 May 2024).
This commit is contained in:
Marco
2026-07-23 14:12:35 +00:00
parent a3912a47c4
commit b5ad13cf43
5 changed files with 41 additions and 42 deletions
-1
View File
@@ -16,7 +16,6 @@ const FALLBACK: CompanySettings = {
registerNumber: null,
managingDirector: null,
shareCapital: null,
generalPartners: null,
sellerStreet: "",
sellerZip: "",
sellerCity: "",
+26 -26
View File
@@ -4,8 +4,8 @@ import type { CompanySettings } from "../../lib/payload";
import type { TOCSection } from "../../components/SectionTOC";
// Renders "Angaben zum Anbieter"/"Umsatzsteuer"/(conditionally)
// "Handelsregister"/"Geschäftsführung"/"Gesellschafter"/"Verantwortlich für
// den Inhalt" straight from company-settings, matching RichText.tsx's own heading/
// "Handelsregister"/"Geschäftsführung"/"Verantwortlich für den Inhalt"
// straight from company-settings, matching RichText.tsx's own heading/
// paragraph classes so it reads as one continuous page with the CMS
// content below it, not a bolted-on block. This used to be hand-typed
// prose baked into the Impressum's richText (seed-legal-pages.ts on the
@@ -17,21 +17,27 @@ import type { TOCSection } from "../../components/SectionTOC";
// already uses (see page.tsx's comment on that).
//
// Also closes a real compliance gap the old hand-typed text had: it never
// showed Handelsregister/Geschäftsführung/Gesellschafter/Stammkapital at
// all, even though company-settings models all of them (§37a HGB/§35a
// GmbHG/§80 AktG) — those fields just weren't wired into the Impressum. A
// sole proprietorship (this shop's current legalForm) needs none of them,
// so nothing extra shows today, but the moment legalForm changes in
// company-settings (e.g. incorporating as a GmbH), the Impressum picks up
// Handelsregister/Geschäftsführung/Stammkapital automatically — same for
// generalPartners/"Gesellschafter" on an OHG/KG — instead of needing a
// second manual edit here.
// showed Handelsregister/Geschäftsführung at all, even though
// company-settings already models both (§37a HGB/§35a GmbHG) — those
// fields just weren't wired into the Impressum. A sole proprietorship
// (this shop's current legalForm) has neither, so neither section shows
// today, but the moment that changes in company-settings, the Impressum
// picks it up automatically instead of needing a second manual edit.
//
// A "Gesellschafter"/Komplementäre section for OHG/KG was attempted
// 2026-07-23 but reverted the same day — the legal basis turned out
// genuinely unclear on research (§125a HGB's Geschäftsbriefe-naming duty
// only applies to the narrow case where *no* partner is a natural person,
// not the general OHG/KG case; whether §5 DDG's Impressum-specific
// "vertretungsberechtigte Person" requirement independently mandates it
// wasn't resolved with confidence). Deliberately not modeled until that's
// actually clarified — don't rebuild this without re-verifying the legal
// basis first, and don't assume the old attempt's reasoning was correct.
export function anbieterAngabenHeadings(seller: CompanySettings | null): TOCSection[] {
if (!seller) return [];
const sections = ["Angaben zum Anbieter", "Umsatzsteuer"];
if (seller.registerCourt && seller.registerNumber) sections.push("Handelsregister");
if (seller.managingDirector) sections.push("Geschäftsführung");
if (seller.generalPartners && seller.generalPartners.length > 0) sections.push("Gesellschafter");
sections.push("Verantwortlich für den Inhalt");
return sections.map((title) => ({ id: headingId(title), title }));
}
@@ -74,6 +80,9 @@ export function AnbieterAngaben({ seller }: { seller: CompanySettings }) {
<Heading>Handelsregister</Heading>
<P>{seller.registerCourt}</P>
<P>{seller.registerNumber}</P>
{/* Optional/voluntary, not a Pflichtangabe — see
CompanySettings.ts's own comment on shareCapital. Only shows
if an admin deliberately filled it in. */}
{seller.shareCapital ? <P>Stammkapital: {seller.shareCapital.toLocaleString("de-DE")} </P> : null}
</>
)}
@@ -85,22 +94,13 @@ export function AnbieterAngaben({ seller }: { seller: CompanySettings }) {
</>
)}
{seller.generalPartners && seller.generalPartners.length > 0 && (
<>
<Heading>Gesellschafter</Heading>
{seller.generalPartners.map((partner) => (
<P key={partner.name}>{partner.name}</P>
))}
</>
)}
<Heading>Verantwortlich für den Inhalt</Heading>
{/* §18 Abs. 2 MStV wants a natural person — managingDirector first
(Kapitalgesellschaften), falling back to the first named
Gesellschafter (OHG/KG, no separate managingDirector field),
then finally sellerName itself (sole proprietorship/e.K.,
already a natural person's own name). */}
<P>{seller.managingDirector || seller.generalPartners?.[0]?.name || seller.sellerName}</P>
(Kapitalgesellschaften), falling back to sellerName itself (sole
proprietorship/e.K., already a natural person's own name). No
OHG/KG general-partner fallback here — see this file's top
comment on why that field doesn't exist yet. */}
<P>{seller.managingDirector || seller.sellerName}</P>
<P>{seller.sellerStreet}</P>
<P>
{seller.sellerZip} {seller.sellerCity}
+2 -2
View File
@@ -12,7 +12,7 @@ import { AnbieterAngaben, anbieterAngabenHeadings } from "./components/AnbieterA
export const metadata: Metadata = {
title: "Impressum",
description: "Angaben gemäß § 5 TMG für einfach produktiv.",
description: "Angaben gemäß § 5 DDG für einfach produktiv.",
alternates: { canonical: "/impressum" },
};
@@ -39,7 +39,7 @@ export default async function ImpressumPage() {
>
Impressum
</p>
<p className="text-body text-text-muted">Angaben gemäß § 5 TMG</p>
<p className="text-body text-text-muted">Angaben gemäß § 5 DDG</p>
</Reveal>
<div className="flex flex-col lg:flex-row gap-8 lg:gap-12 items-start pb-16 pt-2 px-[var(--layout-padding-x)] w-full">
+6 -5
View File
@@ -79,7 +79,7 @@ export const DEFAULT_LEGAL_FOOTER_LINES: string[] = [
"E-Mail: kontakt@musterfirma.de",
];
// Every business email needs an Anbieterkennzeichnung (§5 TMG-equivalent
// Every business email needs an Anbieterkennzeichnung (§5 DDG-equivalent
// minimum for business correspondence: full name, postal address, contact,
// plus VAT ID once assigned) — not just a friendly "brand · email" line.
// Built from the same company-settings fields the invoice PDFs already
@@ -91,6 +91,11 @@ export const DEFAULT_LEGAL_FOOTER_LINES: string[] = [
// appended here when actually present, so a sole proprietorship's footer
// stays exactly as short as before this field set existed. Keep this in
// sync with the Payload backend's own copy in src/lib/sellerInfo.ts.
// `shareCapital` deliberately does NOT appear here even though it's a
// company-settings field — see CompanySettings.ts's own comment: it's a
// voluntary disclosure, not something safe to auto-inject into every
// outgoing email regardless of whether the business actually wants that
// disclosure made.
export function buildLegalFooterLines(seller: CompanySettings | null): string[] {
if (!seller) return DEFAULT_LEGAL_FOOTER_LINES;
const lines = [
@@ -102,10 +107,6 @@ export function buildLegalFooterLines(seller: CompanySettings | null): string[]
if (seller.vatId) lines.push(`USt-IdNr.: ${seller.vatId}`);
if (seller.registerCourt && seller.registerNumber) lines.push(`${seller.registerCourt} · ${seller.registerNumber}`);
if (seller.managingDirector) lines.push(`Geschäftsführung: ${seller.managingDirector}`);
if (seller.shareCapital) lines.push(`Stammkapital: ${seller.shareCapital.toLocaleString("de-DE")}`);
if (seller.generalPartners && seller.generalPartners.length > 0) {
lines.push(`Gesellschafter: ${seller.generalPartners.map((p) => p.name).join(", ")}`);
}
return lines;
}
+7 -8
View File
@@ -724,19 +724,18 @@ export async function getEmailTemplate(
export type CompanySettings = {
sellerName: string;
// Drives whether registerCourt/registerNumber/managingDirector/
// shareCapital/generalPartners are populated — mirrors Payload's
// CompanySettings.ts collection exactly (same option values), see
// buildLegalFooterLines() in emailTemplates.ts.
// shareCapital are populated — mirrors Payload's CompanySettings.ts
// collection exactly (same option values), see buildLegalFooterLines()
// in emailTemplates.ts.
legalForm: "sole-proprietorship" | "e-k" | "gbr" | "ohg" | "kg" | "gmbh" | "ug" | "ag";
registerCourt: string | null;
registerNumber: string | null;
managingDirector: string | null;
// Stammkapital (GmbH/UG) / Grundkapital (AG) — only present for those
// legal forms, see CompanySettings.ts's SHARE_CAPITAL_REQUIRED_FORMS.
// Stammkapital (GmbH/UG) / Grundkapital (AG) — optional, NOT a
// Pflichtangabe (only shown for legal forms that have this concept at
// all; see CompanySettings.ts's SHARE_CAPITAL_APPLICABLE_FORMS and its
// own comment on why this is voluntary, not required, disclosure).
shareCapital: number | null;
// Komplementäre/Gesellschafter — only present for OHG/KG, see
// CompanySettings.ts's GENERAL_PARTNERS_REQUIRED_FORMS.
generalPartners: { name: string }[] | null;
sellerStreet: string;
sellerZip: string;
sellerCity: string;