Compare commits

2 Commits
Author SHA1 Message Date
rootandClaude Opus 5.5 72f278b478 AGB § 9: Zeiterfassung in 15-Minuten-Schritten und Unterstützung
Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
2026-09-30 15:27:33 +00:00
rootandClaude Opus 5.5 034892c899 AGB § 11 Haftung: wirksame Regel nach dem Muster der Abo-Bedingungen
Die alte Fassung schloss die Haftung für Umsatzausfälle, Datenverlust,
Systemausfälle und externe Dienste aus, haftete nur bei Vorsatz und
grober Fahrlässigkeit und deckelte auf den Auftragswert. Gegenüber
Verbrauchern unwirksam (§ 309 Nr. 7 a/b BGB), bei wesentlichen
Vertragspflichten auch gegenüber Unternehmern (§ 307 BGB).

Neu, wie § 13 der Abo-Bedingungen (v4-Entwurf): unbeschränkt bei
Vorsatz, grober Fahrlässigkeit, Leben/Körper/Gesundheit, nach dem
Produkthaftungsgesetz und bei Garantie; bei leichter Fahrlässigkeit
nur für wesentliche Vertragspflichten und nur für den vertragstypischen,
vorhersehbaren Schaden; Datenverlust außer in den Fällen von Absatz 1
nur in Höhe des Wiederherstellungsaufwands aus den Kopien, die der
Kunde aufbewahrt; gilt auch zugunsten von Mitarbeitern und Beauftragten.

src/test/agb-haftung.test.tsx hält die Kernsätze und die Reihenfolge
der Absätze fest. vitest.config.ts lädt @vitejs/plugin-react statt des
nicht installierten @vitejs/plugin-react-swc (vitest startete auf main
nicht); dieselbe Änderung wie auf feature/hosting-abo.

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
2026-09-30 15:26:43 +00:00
3 changed files with 126 additions and 10 deletions

No files matched your search

+11 -10
View File
@@ -192,6 +192,13 @@ const AGB = () => {
</h2>
<ol className="list-decimal list-inside space-y-2 text-muted-foreground leading-relaxed [&>li]:pl-2">
<li>Die Vergütung ergibt sich aus dem Angebot.</li>
<li>
Wird nach Aufwand abgerechnet, erfasst WEBklar die Arbeitszeit je Arbeitsschritt in Schritten von
15 Minuten; angefangene 15 Minuten werden aufgerundet. Wirkt eine weitere Person unterstützend mit,
rechnet WEBklar für sie die Hälfte der Arbeitszeit des Arbeitsschritts an, aufgerundet auf volle
15 Minuten; bei mehreren unterstützenden Personen gilt das für jede. Jeder Arbeitsschritt und jede
Unterstützung ist im Kundenportal einsehbar.
</li>
<li>Projektleistungen sind nach Vereinbarung fällig.</li>
<li>Für die Abos gelten die Vertragsbedingungen für die WEBklar-Abos.</li>
</ol>
@@ -222,16 +229,10 @@ const AGB = () => {
11. Haftung
</h2>
<ol className="list-decimal list-inside space-y-2 text-muted-foreground leading-relaxed [&>li]:pl-2">
<li>WEBklar haftet nur bei Vorsatz und grober Fahrlässigkeit.</li>
<li>Keine Haftung für:
<ul className="list-disc list-inside mt-2 space-y-1 pl-2">
<li>Umsatzausfälle</li>
<li>Datenverlust</li>
<li>Systemausfälle</li>
<li>externe Dienste</li>
</ul>
</li>
<li>Die Haftung ist der Höhe nach auf den Auftragswert begrenzt.</li>
<li>WEBklar haftet unbeschränkt bei Vorsatz und grober Fahrlässigkeit, bei Verletzung von Leben, Körper oder Gesundheit, nach dem Produkthaftungsgesetz und soweit WEBklar eine Garantie übernommen hat.</li>
<li>Bei leicht fahrlässiger Verletzung einer wesentlichen Vertragspflicht haftet WEBklar nur für den vertragstypischen, vorhersehbaren Schaden. Wesentlich sind Pflichten, deren Erfüllung die ordnungsgemäße Durchführung des Vertrags überhaupt erst ermöglicht und auf deren Einhaltung der Kunde regelmäßig vertrauen darf. Im Übrigen ist die Haftung für leichte Fahrlässigkeit ausgeschlossen.</li>
<li>Der Kunde bewahrt Kopien der Inhalte und Daten auf, die er WEBklar übergibt oder selbst einpflegt. Für den Verlust solcher Inhalte und Daten haftet WEBklar außer in den Fällen von Absatz 1 nur in Höhe des Aufwands, der für ihre Wiederherstellung nötig gewesen wäre, wenn der Kunde diese Kopien aufbewahrt hätte.</li>
<li>Diese Regeln gelten auch zugunsten der Mitarbeiter und Beauftragten von WEBklar.</li>
</ol>
</section>
{contractDivider}
+74
View File
@@ -0,0 +1,74 @@
import { describe, it, expect } from "vitest";
import { render, screen, within } from "@testing-library/react";
import { MemoryRouter } from "react-router-dom";
import AGB from "@/pages/AGB";
// Dieselben Future-Flags wie der BrowserRouter in App.tsx, sonst warnt React Router in der Testausgabe.
const routerFuture = { v7_startTransition: true, v7_relativeSplatPath: true };
/** Rendert die AGB und liefert § 11 mit seinen Absätzen in der angezeigten Reihenfolge. */
const haftung = () => {
render(
<MemoryRouter future={routerFuture}>
<AGB />
</MemoryRouter>,
);
const section = screen.getByRole("heading", { name: "11. Haftung" }).closest("section");
if (!section) throw new Error("Abschnitt 11. Haftung fehlt");
return { section, absaetze: within(section).getAllByRole("listitem") };
};
describe("AGB § 11 Haftung", () => {
it("hat genau vier Absätze, damit der Verweis auf Absatz 1 stimmt", () => {
expect(haftung().absaetze).toHaveLength(4);
});
it("Absatz 1: unbeschränkte Haftung für Vorsatz, grobe Fahrlässigkeit, Leben/Körper/Gesundheit, ProdHaftG, Garantie", () => {
// § 309 Nr. 7 a und b BGB, § 14 ProdHaftG, § 276 Abs. 1 BGB (Garantie).
expect(haftung().absaetze[0]).toHaveTextContent(
"WEBklar haftet unbeschränkt bei Vorsatz und grober Fahrlässigkeit, bei Verletzung von Leben, Körper oder Gesundheit, nach dem Produkthaftungsgesetz und soweit WEBklar eine Garantie übernommen hat.",
);
});
it("Absatz 2: leichte Fahrlässigkeit nur bei wesentlichen Vertragspflichten und nur für den vorhersehbaren Schaden", () => {
// § 307 Abs. 2 Nr. 2 BGB: Kardinalpflichten, mit der vom BGH geforderten Erklärung des Begriffs.
const absatz = haftung().absaetze[1];
expect(absatz).toHaveTextContent(
"Bei leicht fahrlässiger Verletzung einer wesentlichen Vertragspflicht haftet WEBklar nur für den vertragstypischen, vorhersehbaren Schaden.",
);
expect(absatz).toHaveTextContent(
"Wesentlich sind Pflichten, deren Erfüllung die ordnungsgemäße Durchführung des Vertrags überhaupt erst ermöglicht und auf deren Einhaltung der Kunde regelmäßig vertrauen darf.",
);
expect(absatz).toHaveTextContent("Im Übrigen ist die Haftung für leichte Fahrlässigkeit ausgeschlossen.");
});
it("Absatz 3: Datenverlust nur in Höhe des Wiederherstellungsaufwands, nie in den Fällen von Absatz 1", () => {
const absatz = haftung().absaetze[2];
expect(absatz).toHaveTextContent(
"Der Kunde bewahrt Kopien der Inhalte und Daten auf, die er WEBklar übergibt oder selbst einpflegt.",
);
expect(absatz).toHaveTextContent(
"Für den Verlust solcher Inhalte und Daten haftet WEBklar außer in den Fällen von Absatz 1 nur in Höhe des Aufwands, der für ihre Wiederherstellung nötig gewesen wäre, wenn der Kunde diese Kopien aufbewahrt hätte.",
);
});
it("Absatz 4: gilt auch zugunsten der Mitarbeiter und Beauftragten", () => {
expect(haftung().absaetze[3]).toHaveTextContent(
"Diese Regeln gelten auch zugunsten der Mitarbeiter und Beauftragten von WEBklar.",
);
});
it("enthält die unwirksamen Ausschlüsse und die Höchstgrenze der alten Fassung nicht mehr", () => {
const { section } = haftung();
for (const alt of [
/nur bei Vorsatz/,
/keine Haftung/i,
/Umsatzausfälle/,
/Systemausfälle/,
/externe Dienste/,
/Auftragswert/,
]) {
expect(section).not.toHaveTextContent(alt);
}
});
});
+41
View File
@@ -0,0 +1,41 @@
import { describe, it, expect } from "vitest";
import { render, screen, within } from "@testing-library/react";
import { MemoryRouter } from "react-router-dom";
import AGB from "@/pages/AGB";
// Dieselben Future-Flags wie der BrowserRouter in App.tsx, sonst warnt React Router in der Testausgabe.
const routerFuture = { v7_startTransition: true, v7_relativeSplatPath: true };
/** Rendert die AGB und liefert die Absätze von § 9 in der angezeigten Reihenfolge. */
const verguetung = () => {
render(
<MemoryRouter future={routerFuture}>
<AGB />
</MemoryRouter>,
);
const section = screen.getByRole("heading", { name: "9. Vergütung und Zahlung" }).closest("section");
if (!section) throw new Error("Abschnitt 9. Vergütung und Zahlung fehlt");
return within(section).getAllByRole("listitem");
};
describe("AGB § 9 Vergütung und Zahlung", () => {
it("hat vier Absätze", () => {
expect(verguetung()).toHaveLength(4);
});
it("Absatz 1 bleibt: Vergütung aus dem Angebot", () => {
expect(verguetung()[0]).toHaveTextContent("Die Vergütung ergibt sich aus dem Angebot.");
});
it("Absatz 2: 15-Minuten-Schritte und Unterstützung bei Abrechnung nach Aufwand", () => {
expect(verguetung()[1]).toHaveTextContent(
"Wird nach Aufwand abgerechnet, erfasst WEBklar die Arbeitszeit je Arbeitsschritt in Schritten von 15 Minuten; angefangene 15 Minuten werden aufgerundet. Wirkt eine weitere Person unterstützend mit, rechnet WEBklar für sie die Hälfte der Arbeitszeit des Arbeitsschritts an, aufgerundet auf volle 15 Minuten; bei mehreren unterstützenden Personen gilt das für jede. Jeder Arbeitsschritt und jede Unterstützung ist im Kundenportal einsehbar.",
);
});
it("Absatz 3 und 4: Fälligkeit und Abos wie bisher", () => {
const absaetze = verguetung();
expect(absaetze[2]).toHaveTextContent("Projektleistungen sind nach Vereinbarung fällig.");
expect(absaetze[3]).toHaveTextContent("Für die Abos gelten die Vertragsbedingungen für die WEBklar-Abos.");
});
});