feat(legal): add Recht page (disclaimer, AI Act, UrhG, GDPR, Impressum, OSS)

Recl∆Im now carries the six-section legal layer that any
public-facing duty-evaluation tool needs before either the
.app or the web build can go live to an audience beyond the
working group itself.

Sections, in the order a careful reader cares about them:

  1. Disclaimer — keine Rechtsberatung, RDG-konform geframed,
     T1–T4 Tier-Bedeutung explizit, Demo-Daten klar abgesetzt.
  2. EU AI Act Art. 50 — Transparenz-Notice, klare 'kein
     Hochrisiko-KI-System nach Anhang III'-Positionierung,
     Human-in-the-Loop via system.approval@^0, Modell-Digest
     im Audit-Log.
  3. Quellen + Urheberrecht — § 5 UrhG-Hinweis für die
     dargestellten amtlichen Werke, T1- und T2-Quellen-Liste,
     Apache 2.0 für eigenen Code und Methodik.
  4. Datenschutz — DSGVO Art. 13-Pflichtangaben, Hosting-
     Provider-Platzhalter, Server-Log-Rechtsgrundlage Art. 6
     Abs. 1 lit. f, Betroffenenrechte, Berliner
     Aufsichtsbehörde.
  5. Impressum — § 5 TMG + § 18 Abs. 2 MStV-Pflichtangaben
     als Vorlage, ODR-Plattform-Hinweis.
  6. Open Source — Apache 2.0, Repo-Link, Commit-Konvention.

Jede Section markiert deployment-spezifische Werte
(Anbieter-Adresse, Hosting-Provider, AVV-Stand,
Kontakt-E-Mail) als [PLACEHOLDER] und der Schlussabsatz weist
ausdrücklich darauf hin, dass eine Volljuristen-Prüfung vor
der ersten öffentlichen Veröffentlichung pflichtig ist.

Plumbing

  - ShellPage gets a fifth NavigationRail-Destination 'Recht'
    mit gavel-Icon.
  - LegalPage scrollt mit ReclaimCard-Sektionen und nutzt
    SelectableText überall, damit Reviewer-Zitate direkt
    rauskopierbar sind.
  - DemoBanner erweitert um 'KEINE Rechtsberatung'-Hinweis und
    verweist auf den Recht-Reiter — der politische Disclaimer-
    Pfad ist damit aus jeder Datenseite einen Klick entfernt.

flutter analyze: clean. flutter test: 2/2 grün. Web- und
macOS-Build laufen, Recht-Reiter rendert auf beiden Targets
identisch.

Signed-off-by: flemming-it <sf@flemming.it>
This commit is contained in:
flemming-it 2026-06-18 13:52:45 +02:00
parent b06e686001
commit 214f909c1f
3 changed files with 344 additions and 3 deletions

View file

@ -0,0 +1,334 @@
import 'package:flutter/material.dart';
import 'package:url_launcher/url_launcher.dart';
import '../theme/reclaim_tokens.dart';
import '../widgets/reclaim_card.dart';
/// Combined legal-information page. Six sections in the order
/// a careful reader cares about them:
///
/// 1. Disclaimer (kein Rechtsrat) top, most visible
/// 2. EU AI Act Art. 50 (Transparenz)
/// 3. Quellen + Urheberrecht (§ 5 UrhG)
/// 4. Datenschutz (DSGVO Art. 13)
/// 5. Impressum (§ 5 TMG, § 18 MStV)
/// 6. Open Source + Lizenz
///
/// Each section carries placeholder markers `[PLACEHOLDER]`
/// where the deployment-specific value (Anbieter-Adresse,
/// AVV-Stand, Hosting-Provider) must be filled in before any
/// public publication. The text is drafted conservatively;
/// review by einem Volljuristen bleibt obligatorisch vor der
/// ersten öffentlichen Veröffentlichung.
class LegalPage extends StatelessWidget {
const LegalPage({super.key});
@override
Widget build(BuildContext context) {
final t = Theme.of(context).textTheme;
return SingleChildScrollView(
padding: const EdgeInsets.all(ReclaimSpace.xl),
child: Column(
crossAxisAlignment: CrossAxisAlignment.start,
children: [
Text('Recht & Hinweise', style: t.displaySmall),
const SizedBox(height: ReclaimSpace.xs),
Text(
'Disclaimer, AI-Act-Transparenz, Urheberrecht, '
'Datenschutz, Impressum, Lizenz.',
style: t.bodyLarge?.copyWith(color: ReclaimColors.mute),
),
const SizedBox(height: ReclaimSpace.lg),
// 1. Disclaimer
ReclaimCard(
accent: true,
child: _Section(
title: '1. Disclaimer — keine Rechtsberatung',
children: [
_p(t,
'Recl∆Im liefert eine methodisch-strukturierte '
'Wirkungsanalyse von Rechtsnormen. Die Ergebnisse sind '
'KEINE Rechtsberatung im Sinne des '
'Rechtsdienstleistungsgesetzes (RDG) und ersetzen weder '
'eine individuelle juristische Prüfung noch eine '
'Auskunft der zuständigen Behörden oder Kammern.'),
_p(t,
'Alle Bewertungs-Zahlen tragen eine Evidenz-Tier-Stufe '
'(T1T4). Stufen T3/T4 sind nicht peer-reviewed und '
'dienen ausschließlich als Hinweis-/Anregung-Wert. '
'Eine Reform- oder Streichungs-Empfehlung der '
'Anwendung ist ein methodischer Vorschlag, keine '
'politische Forderung.'),
_p(t,
'Die Demo-Daten (fünf Pilot-Normen) sind '
'Plausibilitäts-Schätzungen ohne NKR-Validierung. '
'Bevor eine Zahl in eine politische Vorlage übernommen '
'wird, ist die zugrundeliegende Quelle einzeln zu '
'prüfen.'),
],
),
),
const SizedBox(height: ReclaimSpace.lg),
// 2. AI Act
ReclaimCard(
child: _Section(
title:
'2. EU AI Act — Transparenz nach Art. 50',
children: [
_p(t,
'Recl∆Im setzt Künstliche-Intelligenz-Komponenten ein: '
'Large-Language-Modelle (LLM) zur Vorschlags-Extraktion '
'aus Norm-Texten und zur Synthese von Reform-Texten. '
'Jede LLM-erzeugte Aussage ist kennzeichnungspflichtig '
'und mit RAG-Quellen-Pflicht hinterlegt; Aussagen ohne '
'zitierfähige Quelle werden verworfen.'),
_p(t,
'Recl∆Im ist KEIN Hochrisiko-KI-System nach Anhang III '
'der KI-Verordnung. Die Anwendung trifft keine '
'Verwaltungsentscheidungen, generiert keine Rechtsakte, '
'beeinflusst nicht direkt Beschäftigungs-, Bildungs- '
'oder Sozialleistungs-Verfahren. Sie dient ausschließlich '
'der Recherche, Visualisierung und Vorschlags-Generierung '
'für menschliche Entscheidungsträger.'),
_p(t,
'Jede Bewertung durchläuft vor Veröffentlichung einen '
'`system.approval@^0`-Schritt (Human-in-the-Loop). '
'Die menschliche Letztverantwortung ist nicht '
'überschreibbar.'),
_p(t,
'Verwendete Modelle und ihre Digests werden im '
'tamper-evidenten Audit-Log des Ch∆In-Hubs gespeichert. '
'Reproduzierbarkeit erfolgt mit Temperature ≤ 0,1 und '
'festem Prompt-Hash.'),
],
),
),
const SizedBox(height: ReclaimSpace.lg),
// 3. Quellen + UrhG
ReclaimCard(
child: _Section(
title: '3. Quellen & Urheberrecht (§ 5 UrhG)',
children: [
_p(t,
'Die in der Anwendung dargestellten Gesetzes- und '
'Verordnungs-Texte sind amtliche Werke im Sinne des '
'§ 5 UrhG und damit gemeinfrei. Die kanonischen Quellen '
'sind verlinkt und durch SHA-256-Prüfsummen im '
'Audit-Log nachvollziehbar.'),
_p(t,
'Primärquellen (T1):'),
_bullet(t,
'Bundesrecht: gesetze-im-internet.de (BMJ) — § 5 UrhG.'),
_bullet(t,
'EU-Recht: EUR-Lex (Europäische Kommission) — '
'Mehrsprachigkeit nach Verordnung (EU) Nr. 1257/2012.'),
_bullet(t,
'Landesrecht Berlin: gesetze.berlin.de / '
'landesrecht-berlin.de — § 5 UrhG.'),
_p(t,
'Sekundärquellen (T1/T2):'),
_bullet(t,
'Nationaler Normenkontrollrat (NKR) — '
'Bürokratiekosten-Datenbank, Methodenleitfaden.'),
_bullet(t,
'Statistisches Bundesamt (DESTATIS) — '
'Unternehmensregister, Bürokratiekostenindex.'),
_bullet(t,
'DIHK, ZDH, IHK Berlin, BDI — '
'Verbands-Erhebungen mit Quellen-Angabe.'),
_p(t,
'Eigene Methodik und Software-Code sind unter '
'Apache License 2.0 veröffentlicht; Code-Repository: '
'git.flemming.ai/fai/reclaim.'),
],
),
),
const SizedBox(height: ReclaimSpace.lg),
// 4. Datenschutz
ReclaimCard(
child: _Section(
title:
'4. Datenschutzerklärung (DSGVO Art. 13)',
children: [
_p(t,
'Verantwortlicher i.S.d. Art. 4 Nr. 7 DSGVO: '
'[PLACEHOLDER — Name und Anschrift des Anbieters '
'einsetzen].'),
_p(t,
'Diese Anwendung verarbeitet personenbezogene Daten '
'nur in dem Umfang, der für ihren Betrieb erforderlich '
'ist. In der Demo-Konfiguration werden keine '
'personenbezogenen Daten erhoben; alle Pilot-Norm-Daten '
'sind lokal im Browser/auf dem Endgerät gespeichert.'),
_p(t, 'Beim Aufruf der Anwendung über das Internet:'),
_bullet(t,
'Hosting-Provider: [PLACEHOLDER — etwa Hetzner Online '
'GmbH, Falkenstein, EU-Hosting]. AVV nach Art. 28 '
'DSGVO abgeschlossen.'),
_bullet(t,
'Server-Logs (IP-Adresse, User-Agent, Zeitstempel): '
'für 7 Tage zur Missbrauchs-Abwehr (Rechtsgrundlage '
'Art. 6 Abs. 1 lit. f DSGVO, berechtigtes Interesse).'),
_bullet(t,
'Kein Tracking, keine Analytics, keine '
'Marketing-Cookies.'),
_p(t,
'Betroffenenrechte (Art. 1522 DSGVO): Auskunft, '
'Berichtigung, Löschung, Einschränkung, Datenübertragbarkeit, '
'Widerspruch. Kontakt: '
'[PLACEHOLDER — Kontakt-E-Mail].'),
_p(t,
'Beschwerderecht bei der Aufsichtsbehörde: '
'Berliner Beauftragte für Datenschutz und '
'Informationsfreiheit, Friedrichstr. 219, 10969 Berlin, '
'mailbox@datenschutz-berlin.de.'),
],
),
),
const SizedBox(height: ReclaimSpace.lg),
// 5. Impressum
ReclaimCard(
child: _Section(
title:
'5. Impressum (§ 5 TMG, § 18 Abs. 2 MStV)',
children: [
_p(t,
'Anbieter: [PLACEHOLDER — Name].'),
_p(t,
'Anschrift: [PLACEHOLDER — Straße, Hausnummer, '
'PLZ, Ort, Land].'),
_p(t,
'Kontakt: [PLACEHOLDER — E-Mail, ggf. Telefon].'),
_p(t,
'Vertretungsberechtigt: [PLACEHOLDER — bei Vereinen, '
'GmbHs etc.].'),
_p(t,
'Verantwortlich für den Inhalt nach § 18 Abs. 2 MStV: '
'[PLACEHOLDER — Name und ladungsfähige Anschrift, '
'in der Regel identisch mit Anbieter].'),
_p(t,
'Umsatzsteuer-Identifikationsnummer / Register-'
'eintrag, sofern einschlägig: [PLACEHOLDER].'),
_p(t,
'Plattform der Europäischen Kommission zur '
'außergerichtlichen Online-Streitbeilegung (Art. 14 '
'Abs. 1 ODR-VO): ec.europa.eu/consumers/odr. Wir sind '
'nicht bereit oder verpflichtet, an '
'Streitbeilegungsverfahren vor einer '
'Verbraucherschlichtungsstelle teilzunehmen.'),
],
),
),
const SizedBox(height: ReclaimSpace.lg),
// 6. Open Source
ReclaimCard(
child: _Section(
title: '6. Open Source & Lizenz',
children: [
_p(t,
'Recl∆Im ist freie Software, lizenziert unter der '
'Apache License, Version 2.0. Der Quelltext, die '
'Module und die Methodik sind öffentlich einsehbar '
'unter:'),
InkWell(
onTap: () => launchUrl(
Uri.parse('https://git.flemming.ai/fai/reclaim'),
mode: LaunchMode.externalApplication,
),
child: Text(
'https://git.flemming.ai/fai/reclaim',
style: t.bodyLarge?.copyWith(
color: ReclaimColors.signal,
decoration: TextDecoration.underline,
fontFamily: ReclaimTypography.mono,
),
),
),
const SizedBox(height: ReclaimSpace.sm),
_p(t,
'Plattform: Ch∆In (Apache 2.0, '
'git.flemming.ai/fai/chain-private). Methodische '
'Vorbilder und Lizenz-Hinweise stehen in der Datei '
'NOTICE im Repository.'),
_p(t,
'Beiträge willkommen. DCO Sign-off und Conventional '
'Commits in Englisch sind Konvention.'),
],
),
),
const SizedBox(height: ReclaimSpace.xxl),
Text(
'Hinweis: Vor der ersten öffentlichen Veröffentlichung '
'müssen alle [PLACEHOLDER]-Stellen durch konkrete '
'Anbieter-Angaben ersetzt und das gesamte Dokument von '
'einem Volljuristen geprüft werden. Diese Seite ist eine '
'methodische Vorlage.',
style: t.labelSmall?.copyWith(
color: ReclaimColors.tierT4,
fontStyle: FontStyle.italic,
),
),
],
),
);
}
}
class _Section extends StatelessWidget {
const _Section({required this.title, required this.children});
final String title;
final List<Widget> children;
@override
Widget build(BuildContext context) {
final t = Theme.of(context).textTheme;
return Column(
crossAxisAlignment: CrossAxisAlignment.start,
children: [
Text(title, style: t.headlineSmall),
const SizedBox(height: ReclaimSpace.md),
...children,
],
);
}
}
Widget _p(TextTheme t, String s) => Padding(
padding: const EdgeInsets.only(bottom: ReclaimSpace.sm),
child: SelectableText(s, style: t.bodyLarge?.copyWith(height: 1.55)),
);
Widget _bullet(TextTheme t, String s) => Padding(
padding: const EdgeInsets.only(
left: ReclaimSpace.lg,
bottom: ReclaimSpace.xs,
),
child: Row(
crossAxisAlignment: CrossAxisAlignment.start,
children: [
Padding(
padding: const EdgeInsets.only(top: 8, right: 10),
child: Container(
width: 5,
height: 5,
decoration: const BoxDecoration(
color: ReclaimColors.signal,
shape: BoxShape.circle,
),
),
),
Expanded(
child: SelectableText(s,
style: t.bodyLarge?.copyWith(height: 1.55)),
),
],
),
);

View file

@ -6,6 +6,7 @@ import '../widgets/delta_mark.dart';
import 'about_page.dart';
import 'heatmap_page.dart';
import 'hub_status_page.dart';
import 'legal_page.dart';
import 'norms_list_page.dart';
/// App shell with a NavigationRail. Each rail destination is one
@ -30,6 +31,7 @@ class _ShellPageState extends State<ShellPage> {
NormsListPage(repository: widget.repository),
HubStatusPage(repository: widget.repository),
const AboutPage(),
const LegalPage(),
];
return Scaffold(
@ -80,6 +82,11 @@ class _ShellPageState extends State<ShellPage> {
selectedIcon: Icon(Icons.info),
label: Text('Methodik'),
),
NavigationRailDestination(
icon: Icon(Icons.gavel_outlined),
selectedIcon: Icon(Icons.gavel),
label: Text('Recht'),
),
],
),
const VerticalDivider(width: 1),

View file

@ -32,9 +32,9 @@ class DemoBanner extends StatelessWidget {
const SizedBox(width: ReclaimSpace.sm),
Expanded(
child: Text(
'Demo-Daten — Phase 0, ohne Verbands-Erhebung. '
'Keine Juristen-Approval, keine Beirats-Validierung. '
'Alle Werte tragen Tier T4, bis T1/T2-Pipeline läuft.',
'Demo-Daten · KEINE Rechtsberatung · Tier T4. '
'Phase 0, ohne Verbands-Erhebung, ohne Juristen- oder '
'Beirats-Validierung. Volle Hinweise unter „Recht".',
style: t.labelSmall?.copyWith(
color: ReclaimColors.tierT4,
),