293c58d0dd
Build + Deploy / build-admin-compliance (push) Successful in 1m40s
Build + Deploy / build-backend-compliance (push) Successful in 7s
Build + Deploy / build-ai-sdk (push) Successful in 35s
Build + Deploy / build-developer-portal (push) Successful in 8s
Build + Deploy / build-tts (push) Successful in 7s
Build + Deploy / build-document-crawler (push) Successful in 8s
Build + Deploy / build-dsms-gateway (push) Successful in 7s
Build + Deploy / build-dsms-node (push) Successful in 8s
CI / branch-name (push) Has been skipped
CI / guardrail-integrity (push) Has been skipped
CI / loc-budget (push) Failing after 16s
CI / secret-scan (push) Has been skipped
CI / go-lint (push) Has been skipped
CI / python-lint (push) Has been skipped
CI / nodejs-lint (push) Has been skipped
CI / nodejs-build (push) Successful in 2m50s
CI / dep-audit (push) Has been skipped
CI / sbom-scan (push) Has been skipped
CI / test-go (push) Failing after 40s
CI / test-python-backend (push) Successful in 37s
CI / test-python-document-crawler (push) Successful in 25s
CI / test-python-dsms-gateway (push) Successful in 23s
CI / validate-canonical-controls (push) Successful in 15s
Build + Deploy / trigger-orca (push) Successful in 2m28s
Each check now has a "hint" field explaining what is missing and what the customer should do to fix it. Hints are shown in the frontend below failed checks in red text. Examples: - "Bei Verarbeitung auf Basis von Art. 6(1)(f) muss dokumentiert werden, warum Ihr berechtigtes Interesse die Rechte der Betroffenen ueberwiegt." - "Die ladungsfaehige Anschrift fehlt. Erforderlich: Strasse, Hausnummer, PLZ und Ort." Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
202 lines
8.9 KiB
Python
202 lines
8.9 KiB
Python
"""
|
|
Impressum checks — §5 TMG / §18 MStV.
|
|
|
|
Level 1: Pflichtangabe erwaehnt?
|
|
Level 2: Pflichtangabe korrekt/vollstaendig?
|
|
"""
|
|
|
|
IMPRESSUM_CHECKLIST = [
|
|
# ── L1: Name des Anbieters ────────────────────────────────────────
|
|
{
|
|
"id": "name",
|
|
"label": "Name des Anbieters",
|
|
"level": 1, "parent": None,
|
|
"patterns": [
|
|
r"(?:gmbh|ag|e\.v\.|ohg|kg|gbr|ug|mbh|inc|ltd)",
|
|
r"firma", r"unternehmen",
|
|
],
|
|
"severity": "HIGH",
|
|
"hint": "Der vollstaendige Name des Unternehmens oder der Person muss im Impressum stehen (z.B. 'Musterfirma GmbH'). Bei Einzelunternehmen genuegt der vollstaendige Vor- und Nachname.",
|
|
},
|
|
|
|
# ── L1: Anschrift ─────────────────────────────────────────────────
|
|
{
|
|
"id": "address",
|
|
"label": "Anschrift",
|
|
"level": 1, "parent": None,
|
|
"patterns": [
|
|
r"(?:str(?:asse|\.)|weg|platz|allee)\s*\d",
|
|
r"d-\d{5}", r"\d{5}\s+\w+",
|
|
],
|
|
"severity": "HIGH",
|
|
"hint": "Eine vollstaendige ladungsfaehige Anschrift (Strasse, Hausnummer, PLZ, Ort) muss im Impressum angegeben werden. Ein Postfach genuegt nicht.",
|
|
},
|
|
{
|
|
"id": "address_zip_city",
|
|
"label": "PLZ + Ort vorhanden",
|
|
"level": 2, "parent": "address",
|
|
"patterns": [
|
|
r"(?:d[\-\s]?)?\d{5}\s+[a-z\u00c0-\u017e]\w{2,}",
|
|
],
|
|
"severity": "MEDIUM",
|
|
"hint": "Die Anschrift muss eine fuenfstellige Postleitzahl und den Ortsnamen enthalten (z.B. '10115 Berlin').",
|
|
},
|
|
{
|
|
"id": "address_street_number",
|
|
"label": "Strasse + Hausnummer vorhanden",
|
|
"level": 2, "parent": "address",
|
|
"patterns": [
|
|
r"[a-z\u00c0-\u017e]\w+(?:str|stra(?:ss|ß)e|weg|platz|allee|gasse|ring|damm|ufer)\s*\.?\s*\d+",
|
|
r"\w+\s+(?:str|stra(?:ss|ß)e|weg|platz|allee)\s*\.?\s*\d+",
|
|
],
|
|
"severity": "MEDIUM",
|
|
"hint": "Bitte den Strassennamen und die Hausnummer angeben (z.B. 'Musterstrasse 12'). Ohne Hausnummer ist die Anschrift nicht ladungsfaehig.",
|
|
},
|
|
|
|
# ── L1: Kontaktdaten ──────────────────────────────────────────────
|
|
{
|
|
"id": "contact",
|
|
"label": "Kontaktdaten (E-Mail + Telefon)",
|
|
"level": 1, "parent": None,
|
|
"patterns": [
|
|
r"(?:e-?mail|mail).*@", r"telefon|phone|tel\.",
|
|
r"\+?\d[\d\s/\-]{8,}",
|
|
],
|
|
"severity": "HIGH",
|
|
"hint": "Das Impressum muss mindestens eine E-Mail-Adresse und eine Telefonnummer enthalten, damit Nutzer schnell Kontakt aufnehmen koennen.",
|
|
},
|
|
{
|
|
"id": "contact_email_format",
|
|
"label": "E-Mail-Adresse im korrekten Format",
|
|
"level": 2, "parent": "contact",
|
|
"patterns": [
|
|
r"[a-z0-9._%+\-]+@[a-z0-9.\-]+\.[a-z]{2,}",
|
|
],
|
|
"severity": "MEDIUM",
|
|
"hint": "Die E-Mail-Adresse muss in einem gueltigen Format vorliegen (z.B. 'info@beispiel.de'). Bitte pruefen Sie, ob ein '@'-Zeichen und eine Domain vorhanden sind.",
|
|
},
|
|
{
|
|
"id": "contact_phone_format",
|
|
"label": "Telefonnummer vorhanden",
|
|
"level": 2, "parent": "contact",
|
|
"patterns": [
|
|
r"(?:tel(?:efon)?|phone|fon)\s*[.:]\s*[\+\d][\d\s/\-]{6,}",
|
|
r"\+49\s*[\d\s/\-]{8,}",
|
|
r"0\d{2,4}\s*[/\-\s]\s*\d{4,}",
|
|
],
|
|
"severity": "MEDIUM",
|
|
"hint": "Bitte eine Telefonnummer mit Vorwahl angeben (z.B. '+49 30 12345678' oder '030 / 12345678'). Ein reines Kontaktformular reicht nicht aus.",
|
|
},
|
|
|
|
# ── L1: Handelsregister ───────────────────────────────────────────
|
|
{
|
|
"id": "register",
|
|
"label": "Handelsregister / Registernummer",
|
|
"level": 1, "parent": None,
|
|
"patterns": [
|
|
r"(?:handelsregister|hrb|hra|registergericht|amtsgericht)",
|
|
r"register.*(?:nr|nummer)",
|
|
],
|
|
"severity": "MEDIUM",
|
|
"hint": "Falls das Unternehmen im Handelsregister eingetragen ist, muessen Registergericht und Registernummer angegeben werden (z.B. 'Amtsgericht Muenchen, HRB 12345').",
|
|
},
|
|
{
|
|
"id": "register_court",
|
|
"label": "Registergericht benannt (Amtsgericht X)",
|
|
"level": 2, "parent": "register",
|
|
"patterns": [
|
|
r"(?:amtsgericht|registergericht)\s+[A-Z\u00c0-\u017e]\w+",
|
|
r"ag\s+[A-Z\u00c0-\u017e]\w+",
|
|
],
|
|
"severity": "LOW",
|
|
"hint": "Bitte das zustaendige Registergericht benennen (z.B. 'Amtsgericht Muenchen'). Die alleinige Angabe der Registernummer ohne Gericht ist unvollstaendig.",
|
|
},
|
|
{
|
|
"id": "register_number",
|
|
"label": "Registernummer (HRB/HRA + Nummer)",
|
|
"level": 2, "parent": "register",
|
|
"patterns": [
|
|
r"(?:hrb|hra)\s*\d+",
|
|
],
|
|
"severity": "LOW",
|
|
"hint": "Die Registernummer muss mit dem Praefix HRB oder HRA und der zugehoerigen Nummer angegeben werden (z.B. 'HRB 12345').",
|
|
},
|
|
|
|
# ── L1: USt-IdNr ──────────────────────────────────────────────────
|
|
{
|
|
"id": "vat",
|
|
"label": "USt-IdNr.",
|
|
"level": 1, "parent": None,
|
|
"patterns": [
|
|
r"ust.*id", r"umsatzsteuer.*identifikation",
|
|
r"vat.*id", r"de\s*\d{9}",
|
|
],
|
|
"severity": "MEDIUM",
|
|
"hint": "Falls eine Umsatzsteuer-Identifikationsnummer vorhanden ist, muss diese im Impressum angegeben werden. Die Steuernummer allein genuegt nicht als Ersatz.",
|
|
},
|
|
{
|
|
"id": "vat_de_format",
|
|
"label": "USt-IdNr. im Format DE + 9 Ziffern",
|
|
"level": 2, "parent": "vat",
|
|
"patterns": [
|
|
r"de\s*\d{9}",
|
|
],
|
|
"severity": "LOW",
|
|
"hint": "Die USt-IdNr. muss im Format 'DE' gefolgt von 9 Ziffern angegeben werden (z.B. 'DE123456789'). Bitte pruefen Sie, ob die Nummer vollstaendig ist.",
|
|
},
|
|
|
|
# ── L1: Vertretungsberechtigte ────────────────────────────────────
|
|
{
|
|
"id": "representative",
|
|
"label": "Vertretungsberechtigte",
|
|
"level": 1, "parent": None,
|
|
"patterns": [
|
|
r"vertretungsberechtigt", r"gesch(?:ae|ä)ftsf(?:ue|ü)hr",
|
|
r"vorstand", r"inhaber",
|
|
],
|
|
"severity": "MEDIUM",
|
|
"hint": "Bei juristischen Personen (GmbH, AG etc.) muss die vertretungsberechtigte Person namentlich genannt werden (z.B. 'Geschaeftsfuehrer: Max Mustermann').",
|
|
},
|
|
{
|
|
"id": "representative_person",
|
|
"label": "Name der vertretungsberechtigten Person",
|
|
"level": 2, "parent": "representative",
|
|
"patterns": [
|
|
r"(?:gesch(?:ae|ä)ftsf(?:ue|ü)hr|vorstand|inhaber)\w*\s*:\s*[A-Z\u00c0-\u017e]",
|
|
r"(?:vertreten\s+durch|repr(?:ae|ä)sentiert)\s*:?\s*[A-Z\u00c0-\u017e]",
|
|
],
|
|
"severity": "LOW",
|
|
"hint": "Bitte den vollstaendigen Vor- und Nachnamen der vertretungsberechtigten Person angeben (z.B. 'Geschaeftsfuehrer: Max Mustermann'). Eine reine Funktionsbezeichnung reicht nicht.",
|
|
},
|
|
|
|
# ── Neue L1: Redaktionell Verantwortlicher ────────────────────────
|
|
{
|
|
"id": "editorial_visdp",
|
|
"label": "V.i.S.d.P. / Redaktionell Verantwortlicher (§18 MStV)",
|
|
"level": 1, "parent": None,
|
|
"patterns": [
|
|
r"v\.?\s*i\.?\s*s\.?\s*d\.?\s*p",
|
|
r"(?:redaktionell|inhaltlich)\s+verantwortlich",
|
|
r"§\s*18\s+m(?:edien)?st(?:aat)?v",
|
|
],
|
|
"severity": "LOW",
|
|
"hint": "Wenn die Website journalistisch-redaktionelle Inhalte enthaelt, muss ein inhaltlich Verantwortlicher mit Name und Anschrift benannt werden (§18 MStV, 'V.i.S.d.P.').",
|
|
},
|
|
|
|
# ── Neue L1: Streitbeilegung ──────────────────────────────────────
|
|
{
|
|
"id": "dispute_resolution",
|
|
"label": "Verbraucherstreitbeilegung / OS-Plattform",
|
|
"level": 1, "parent": None,
|
|
"patterns": [
|
|
r"verbraucherstreitbeilegung|streitschlichtung",
|
|
r"(?:os|odr)[\-\s]plattform",
|
|
r"ec\.europa\.eu.*odr",
|
|
r"vsbg|verbraucherstreitbeilegungsgesetz",
|
|
r"alternative\s+streitbeilegung",
|
|
],
|
|
"severity": "LOW",
|
|
"hint": "Online-Haendler muessen einen Link zur EU-Streitbeilegungsplattform (https://ec.europa.eu/consumers/odr) angeben und erklaeren, ob sie zur Teilnahme an Streitbeilegungsverfahren bereit oder verpflichtet sind.",
|
|
},
|
|
]
|