merge: sync with origin/main, take upstream on conflicts

# Conflicts:
#	admin-compliance/lib/sdk/types.ts
#	admin-compliance/lib/sdk/vendor-compliance/types.ts
This commit is contained in:
Sharang Parnerkar
2026-04-16 16:26:48 +02:00
352 changed files with 181673 additions and 2188 deletions
File diff suppressed because it is too large Load Diff
+976
View File
@@ -0,0 +1,976 @@
"""
FastAPI routes for the Control Generator Pipeline.
Endpoints:
POST /v1/canonical/generate Start generation run
GET /v1/canonical/generate/status/{job_id} Job status
GET /v1/canonical/generate/jobs All jobs
GET /v1/canonical/generate/review-queue Controls needing review
POST /v1/canonical/generate/review/{control_id} Complete review
GET /v1/canonical/generate/processed-stats Processing stats per collection
GET /v1/canonical/blocked-sources Blocked sources list
POST /v1/canonical/blocked-sources/cleanup Start cleanup workflow
"""
import asyncio
import json
import logging
from typing import Optional, List
from fastapi import APIRouter, HTTPException, Query
from pydantic import BaseModel
from sqlalchemy import text
from database import SessionLocal
from compliance.services.control_generator import (
ControlGeneratorPipeline,
GeneratorConfig,
ALL_COLLECTIONS,
VALID_CATEGORIES,
VALID_DOMAINS,
_detect_category,
_detect_domain,
_llm_local,
_parse_llm_json,
CATEGORY_LIST_STR,
)
from compliance.services.citation_backfill import CitationBackfill, BackfillResult
from compliance.services.rag_client import get_rag_client
logger = logging.getLogger(__name__)
router = APIRouter(prefix="/v1/canonical", tags=["control-generator"])
# =============================================================================
# REQUEST / RESPONSE MODELS
# =============================================================================
class GenerateRequest(BaseModel):
domain: Optional[str] = None
collections: Optional[List[str]] = None
max_controls: int = 50
max_chunks: int = 1000 # Default: process max 1000 chunks per job (respects document boundaries)
batch_size: int = 5
skip_web_search: bool = False
dry_run: bool = False
class GenerateResponse(BaseModel):
job_id: str
status: str
message: str
total_chunks_scanned: int = 0
controls_generated: int = 0
controls_verified: int = 0
controls_needs_review: int = 0
controls_too_close: int = 0
controls_duplicates_found: int = 0
controls_qa_fixed: int = 0
errors: list = []
controls: list = []
class ReviewRequest(BaseModel):
action: str # "approve", "reject", "needs_rework"
release_state: Optional[str] = None # Override release_state
notes: Optional[str] = None
class ProcessedStats(BaseModel):
collection: str
total_chunks_estimated: int
processed_chunks: int
pending_chunks: int
direct_adopted: int
llm_reformed: int
skipped: int
class BlockedSourceResponse(BaseModel):
id: str
regulation_code: str
document_title: str
reason: str
deletion_status: str
qdrant_collection: Optional[str] = None
marked_at: str
# =============================================================================
# ENDPOINTS
# =============================================================================
async def _run_pipeline_background(config: GeneratorConfig, job_id: str):
"""Run the pipeline in the background. Uses its own DB session."""
db = SessionLocal()
try:
config.existing_job_id = job_id
pipeline = ControlGeneratorPipeline(db=db, rag_client=get_rag_client())
result = await pipeline.run(config)
logger.info(
"Background generation job %s completed: %d controls from %d chunks",
job_id, result.controls_generated, result.total_chunks_scanned,
)
except Exception as e:
logger.error("Background generation job %s failed: %s", job_id, e)
# Update job as failed
try:
db.execute(
text("""
UPDATE canonical_generation_jobs
SET status = 'failed', errors = :errors, completed_at = NOW()
WHERE id = CAST(:job_id AS uuid)
"""),
{"job_id": job_id, "errors": json.dumps([str(e)])},
)
db.commit()
except Exception:
pass
finally:
db.close()
@router.post("/generate", response_model=GenerateResponse)
async def start_generation(req: GenerateRequest):
"""Start a control generation run (runs in background).
Returns immediately with job_id. Use GET /generate/status/{job_id} to poll progress.
"""
config = GeneratorConfig(
collections=req.collections,
domain=req.domain,
batch_size=req.batch_size,
max_controls=req.max_controls,
max_chunks=req.max_chunks,
skip_web_search=req.skip_web_search,
dry_run=req.dry_run,
)
if req.dry_run:
# Dry run: execute synchronously and return controls
db = SessionLocal()
try:
pipeline = ControlGeneratorPipeline(db=db, rag_client=get_rag_client())
result = await pipeline.run(config)
return GenerateResponse(
job_id=result.job_id,
status=result.status,
message=f"Dry run: {result.controls_generated} controls from {result.total_chunks_scanned} chunks",
total_chunks_scanned=result.total_chunks_scanned,
controls_generated=result.controls_generated,
controls_verified=result.controls_verified,
controls_needs_review=result.controls_needs_review,
controls_too_close=result.controls_too_close,
controls_duplicates_found=result.controls_duplicates_found,
errors=result.errors,
controls=result.controls,
)
except Exception as e:
logger.error("Dry run failed: %s", e)
raise HTTPException(status_code=500, detail=str(e))
finally:
db.close()
# Create job record first so we can return the ID
db = SessionLocal()
try:
result = db.execute(
text("""
INSERT INTO canonical_generation_jobs (status, config)
VALUES ('running', :config)
RETURNING id
"""),
{"config": json.dumps(config.model_dump())},
)
db.commit()
row = result.fetchone()
job_id = str(row[0]) if row else None
except Exception as e:
logger.error("Failed to create job: %s", e)
raise HTTPException(status_code=500, detail=f"Failed to create job: {e}")
finally:
db.close()
if not job_id:
raise HTTPException(status_code=500, detail="Failed to create job record")
# Launch pipeline in background
asyncio.create_task(_run_pipeline_background(config, job_id))
return GenerateResponse(
job_id=job_id,
status="running",
message="Generation started in background. Poll /generate/status/{job_id} for progress.",
)
@router.get("/generate/status/{job_id}")
async def get_job_status(job_id: str):
"""Get status of a generation job."""
db = SessionLocal()
try:
result = db.execute(
text("SELECT * FROM canonical_generation_jobs WHERE id = CAST(:id AS uuid)"),
{"id": job_id},
)
row = result.fetchone()
if not row:
raise HTTPException(status_code=404, detail="Job not found")
cols = result.keys()
job = dict(zip(cols, row))
# Serialize datetime fields
for key in ("started_at", "completed_at", "created_at"):
if job.get(key):
job[key] = str(job[key])
job["id"] = str(job["id"])
return job
finally:
db.close()
@router.get("/generate/jobs")
async def list_jobs(
limit: int = Query(20, ge=1, le=100),
offset: int = Query(0, ge=0),
):
"""List all generation jobs."""
db = SessionLocal()
try:
result = db.execute(
text("""
SELECT id, status, total_chunks_scanned, controls_generated,
controls_verified, controls_needs_review, controls_too_close,
controls_duplicates_found, created_at, completed_at
FROM canonical_generation_jobs
ORDER BY created_at DESC
LIMIT :limit OFFSET :offset
"""),
{"limit": limit, "offset": offset},
)
jobs = []
cols = result.keys()
for row in result:
job = dict(zip(cols, row))
job["id"] = str(job["id"])
for key in ("created_at", "completed_at"):
if job.get(key):
job[key] = str(job[key])
jobs.append(job)
return {"jobs": jobs, "total": len(jobs)}
finally:
db.close()
@router.get("/generate/review-queue")
async def get_review_queue(
release_state: str = Query("needs_review", regex="^(needs_review|too_close|duplicate)$"),
limit: int = Query(50, ge=1, le=200),
):
"""Get controls that need manual review."""
db = SessionLocal()
try:
result = db.execute(
text("""
SELECT c.id, c.control_id, c.title, c.objective, c.severity,
c.release_state, c.license_rule, c.customer_visible,
c.generation_metadata, c.open_anchors, c.tags,
c.created_at
FROM canonical_controls c
WHERE c.release_state = :state
ORDER BY c.created_at DESC
LIMIT :limit
"""),
{"state": release_state, "limit": limit},
)
controls = []
cols = result.keys()
for row in result:
ctrl = dict(zip(cols, row))
ctrl["id"] = str(ctrl["id"])
ctrl["created_at"] = str(ctrl["created_at"])
# Parse JSON fields
for jf in ("generation_metadata", "open_anchors", "tags"):
if isinstance(ctrl.get(jf), str):
try:
ctrl[jf] = json.loads(ctrl[jf])
except (json.JSONDecodeError, TypeError):
pass
controls.append(ctrl)
return {"controls": controls, "total": len(controls)}
finally:
db.close()
@router.post("/generate/review/{control_id}")
async def review_control(control_id: str, req: ReviewRequest):
"""Complete review of a generated control."""
db = SessionLocal()
try:
# Validate control exists and is in reviewable state
result = db.execute(
text("SELECT id, release_state FROM canonical_controls WHERE control_id = :cid"),
{"cid": control_id},
)
row = result.fetchone()
if not row:
raise HTTPException(status_code=404, detail="Control not found")
current_state = row[1]
if current_state not in ("needs_review", "too_close", "duplicate"):
raise HTTPException(status_code=400, detail=f"Control is in state '{current_state}', not reviewable")
# Determine new state
if req.action == "approve":
new_state = req.release_state or "draft"
elif req.action == "reject":
new_state = "deprecated"
elif req.action == "needs_rework":
new_state = "needs_review"
else:
raise HTTPException(status_code=400, detail=f"Unknown action: {req.action}")
if new_state not in ("draft", "review", "approved", "deprecated", "needs_review", "too_close", "duplicate"):
raise HTTPException(status_code=400, detail=f"Invalid release_state: {new_state}")
db.execute(
text("""
UPDATE canonical_controls
SET release_state = :state, updated_at = NOW()
WHERE control_id = :cid
"""),
{"state": new_state, "cid": control_id},
)
db.commit()
return {"control_id": control_id, "release_state": new_state, "action": req.action}
finally:
db.close()
class BulkReviewRequest(BaseModel):
release_state: str # Filter: which controls to bulk-review
action: str # "approve" or "reject"
new_state: Optional[str] = None # Override target state
@router.post("/generate/bulk-review")
async def bulk_review(req: BulkReviewRequest):
"""Bulk review all controls matching a release_state filter.
Example: reject all needs_review sets them to deprecated.
"""
if req.release_state not in ("needs_review", "too_close", "duplicate"):
raise HTTPException(status_code=400, detail=f"Invalid filter state: {req.release_state}")
if req.action == "approve":
target = req.new_state or "draft"
elif req.action == "reject":
target = "deprecated"
else:
raise HTTPException(status_code=400, detail=f"Unknown action: {req.action}")
if target not in ("draft", "review", "approved", "deprecated", "needs_review"):
raise HTTPException(status_code=400, detail=f"Invalid target state: {target}")
db = SessionLocal()
try:
result = db.execute(
text("""
UPDATE canonical_controls
SET release_state = :target, updated_at = NOW()
WHERE release_state = :source
RETURNING control_id
"""),
{"source": req.release_state, "target": target},
)
affected = [row[0] for row in result]
db.commit()
return {
"action": req.action,
"source_state": req.release_state,
"target_state": target,
"affected_count": len(affected),
}
finally:
db.close()
class QAReclassifyRequest(BaseModel):
limit: int = 100 # How many controls to reclassify per run
dry_run: bool = True # Preview only by default
filter_category: Optional[str] = None # Only reclassify controls of this category
filter_domain_prefix: Optional[str] = None # Only reclassify controls with this prefix
@router.post("/generate/qa-reclassify")
async def qa_reclassify(req: QAReclassifyRequest):
"""Run QA reclassification on existing controls using local LLM.
Finds controls where keyword-detection disagrees with current category/domain,
then uses Ollama to determine the correct classification.
"""
db = SessionLocal()
try:
# Load controls to check
where_clauses = ["release_state NOT IN ('deprecated')"]
params = {"limit": req.limit}
if req.filter_category:
where_clauses.append("category = :cat")
params["cat"] = req.filter_category
if req.filter_domain_prefix:
where_clauses.append("control_id LIKE :prefix")
params["prefix"] = f"{req.filter_domain_prefix}-%"
where_sql = " AND ".join(where_clauses)
rows = db.execute(
text(f"""
SELECT id, control_id, title, objective, category,
COALESCE(requirements::text, '[]') as requirements,
COALESCE(source_original_text, '') as source_text
FROM canonical_controls
WHERE {where_sql}
ORDER BY created_at DESC
LIMIT :limit
"""),
params,
).fetchall()
results = {"checked": 0, "mismatches": 0, "fixes": [], "errors": []}
for row in rows:
results["checked"] += 1
control_id = row[1]
title = row[2]
objective = row[3] or ""
current_category = row[4]
source_text = row[6] or objective
# Keyword detection on source text
kw_category = _detect_category(source_text) or _detect_category(objective)
kw_domain = _detect_domain(source_text)
current_prefix = control_id.split("-")[0] if "-" in control_id else ""
# Skip if keyword detection agrees with current classification
if kw_category == current_category and kw_domain == current_prefix:
continue
results["mismatches"] += 1
# Ask Ollama to arbitrate
try:
reqs_text = ""
try:
reqs = json.loads(row[5])
if isinstance(reqs, list):
reqs_text = ", ".join(str(r) for r in reqs[:3])
except Exception:
pass
prompt = f"""Pruefe dieses Compliance-Control auf korrekte Klassifizierung.
Titel: {title[:100]}
Ziel: {objective[:200]}
Anforderungen: {reqs_text[:200]}
Aktuelle Zuordnung: domain={current_prefix}, category={current_category}
Keyword-Erkennung: domain={kw_domain}, category={kw_category}
Welche Zuordnung ist korrekt? Antworte NUR als JSON:
{{"domain": "KUERZEL", "category": "kategorie_name", "reason": "kurze Begruendung"}}
Domains: AUTH=Authentifizierung, CRYP=Kryptographie, NET=Netzwerk, DATA=Datenschutz, LOG=Logging, ACC=Zugriffskontrolle, SEC=IT-Sicherheit, INC=Vorfallmanagement, AI=KI, COMP=Compliance, GOV=Behoerden, LAB=Arbeitsrecht, FIN=Finanzregulierung, TRD=Gewerbe, ENV=Umwelt, HLT=Gesundheit
Kategorien: {CATEGORY_LIST_STR}"""
raw = await _llm_local(prompt)
data = _parse_llm_json(raw)
if not data:
continue
qa_domain = data.get("domain", "").upper()
qa_category = data.get("category", "")
reason = data.get("reason", "")
fix_entry = {
"control_id": control_id,
"title": title[:80],
"old_category": current_category,
"old_domain": current_prefix,
"new_category": qa_category if qa_category in VALID_CATEGORIES else current_category,
"new_domain": qa_domain if qa_domain in VALID_DOMAINS else current_prefix,
"reason": reason,
}
category_changed = qa_category in VALID_CATEGORIES and qa_category != current_category
if category_changed and not req.dry_run:
db.execute(
text("""
UPDATE canonical_controls
SET category = :category, updated_at = NOW()
WHERE id = :id
"""),
{"id": row[0], "category": qa_category},
)
fix_entry["applied"] = True
else:
fix_entry["applied"] = False
results["fixes"].append(fix_entry)
except Exception as e:
results["errors"].append({"control_id": control_id, "error": str(e)})
if not req.dry_run:
db.commit()
return results
finally:
db.close()
@router.get("/generate/processed-stats")
async def get_processed_stats():
"""Get processing statistics per collection."""
db = SessionLocal()
try:
result = db.execute(
text("""
SELECT
collection,
COUNT(*) as processed_chunks,
COUNT(*) FILTER (WHERE processing_path = 'structured') as direct_adopted,
COUNT(*) FILTER (WHERE processing_path = 'llm_reform') as llm_reformed,
COUNT(*) FILTER (WHERE processing_path = 'skipped') as skipped
FROM canonical_processed_chunks
GROUP BY collection
ORDER BY collection
""")
)
stats = []
cols = result.keys()
for row in result:
stat = dict(zip(cols, row))
stat["total_chunks_estimated"] = 0 # Would need Qdrant API to get total
stat["pending_chunks"] = 0
stats.append(stat)
return {"stats": stats}
finally:
db.close()
# =============================================================================
# BLOCKED SOURCES
# =============================================================================
@router.get("/blocked-sources")
async def list_blocked_sources():
"""List all blocked (Rule 3) sources."""
db = SessionLocal()
try:
result = db.execute(
text("""
SELECT id, regulation_code, document_title, reason,
deletion_status, qdrant_collection, marked_at
FROM canonical_blocked_sources
ORDER BY marked_at DESC
""")
)
sources = []
cols = result.keys()
for row in result:
src = dict(zip(cols, row))
src["id"] = str(src["id"])
src["marked_at"] = str(src["marked_at"])
sources.append(src)
return {"sources": sources}
finally:
db.close()
@router.post("/blocked-sources/cleanup")
async def start_cleanup():
"""Start cleanup workflow for blocked sources.
This marks all pending blocked sources for deletion.
Actual RAG chunk deletion and file removal is a separate manual step.
"""
db = SessionLocal()
try:
result = db.execute(
text("""
UPDATE canonical_blocked_sources
SET deletion_status = 'marked_for_deletion'
WHERE deletion_status = 'pending'
RETURNING regulation_code
""")
)
marked = [row[0] for row in result]
db.commit()
return {
"status": "marked_for_deletion",
"marked_count": len(marked),
"regulation_codes": marked,
"message": "Sources marked for deletion. Run manual cleanup to remove RAG chunks and files.",
}
finally:
db.close()
# =============================================================================
# CUSTOMER VIEW FILTER
# =============================================================================
@router.get("/controls-customer")
async def get_controls_customer_view(
severity: Optional[str] = Query(None),
domain: Optional[str] = Query(None),
):
"""Get controls filtered for customer visibility.
Rule 3 controls have source_citation and source_original_text hidden.
generation_metadata is NEVER shown to customers.
"""
db = SessionLocal()
try:
query = """
SELECT c.id, c.control_id, c.title, c.objective, c.rationale,
c.scope, c.requirements, c.test_procedure, c.evidence,
c.severity, c.risk_score, c.implementation_effort,
c.open_anchors, c.release_state, c.tags,
c.license_rule, c.customer_visible,
c.source_original_text, c.source_citation,
c.created_at, c.updated_at
FROM canonical_controls c
WHERE c.release_state IN ('draft', 'approved')
"""
params: dict = {}
if severity:
query += " AND c.severity = :severity"
params["severity"] = severity
if domain:
query += " AND c.control_id LIKE :domain"
params["domain"] = f"{domain.upper()}-%"
query += " ORDER BY c.control_id"
result = db.execute(text(query), params)
controls = []
cols = result.keys()
for row in result:
ctrl = dict(zip(cols, row))
ctrl["id"] = str(ctrl["id"])
for key in ("created_at", "updated_at"):
if ctrl.get(key):
ctrl[key] = str(ctrl[key])
# Parse JSON fields
for jf in ("scope", "requirements", "test_procedure", "evidence",
"open_anchors", "tags", "source_citation"):
if isinstance(ctrl.get(jf), str):
try:
ctrl[jf] = json.loads(ctrl[jf])
except (json.JSONDecodeError, TypeError):
pass
# Customer visibility rules:
# - NEVER show generation_metadata
# - Rule 3: NEVER show source_citation or source_original_text
ctrl.pop("generation_metadata", None)
if not ctrl.get("customer_visible", True):
ctrl["source_citation"] = None
ctrl["source_original_text"] = None
controls.append(ctrl)
return {"controls": controls, "total": len(controls)}
finally:
db.close()
# =============================================================================
# CITATION BACKFILL
# =============================================================================
class BackfillRequest(BaseModel):
dry_run: bool = True # Default to dry_run for safety
limit: int = 0 # 0 = all controls
class BackfillResponse(BaseModel):
status: str
total_controls: int = 0
matched_hash: int = 0
matched_regex: int = 0
matched_llm: int = 0
unmatched: int = 0
updated: int = 0
errors: list = []
_backfill_status: dict = {}
async def _run_backfill_background(dry_run: bool, limit: int, backfill_id: str):
"""Run backfill in background with own DB session."""
db = SessionLocal()
try:
backfill = CitationBackfill(db=db, rag_client=get_rag_client())
result = await backfill.run(dry_run=dry_run, limit=limit)
_backfill_status[backfill_id] = {
"status": "completed",
"total_controls": result.total_controls,
"matched_hash": result.matched_hash,
"matched_regex": result.matched_regex,
"matched_llm": result.matched_llm,
"unmatched": result.unmatched,
"updated": result.updated,
"errors": result.errors[:50],
}
logger.info("Backfill %s completed: %d updated", backfill_id, result.updated)
except Exception as e:
logger.error("Backfill %s failed: %s", backfill_id, e)
_backfill_status[backfill_id] = {"status": "failed", "errors": [str(e)]}
finally:
db.close()
@router.post("/generate/backfill-citations", response_model=BackfillResponse)
async def start_backfill(req: BackfillRequest):
"""Backfill article/paragraph into existing control source_citations.
Uses 3-tier matching: hash lookup regex parse Ollama LLM.
Default is dry_run=True (preview only, no DB changes).
"""
import uuid
backfill_id = str(uuid.uuid4())[:8]
_backfill_status[backfill_id] = {"status": "running"}
# Always run in background (RAG index build takes minutes)
asyncio.create_task(_run_backfill_background(req.dry_run, req.limit, backfill_id))
return BackfillResponse(
status=f"running (id={backfill_id})",
)
@router.get("/generate/backfill-status/{backfill_id}")
async def get_backfill_status(backfill_id: str):
"""Get status of a backfill job."""
status = _backfill_status.get(backfill_id)
if not status:
raise HTTPException(status_code=404, detail="Backfill job not found")
return status
# =============================================================================
# DOMAIN + TARGET AUDIENCE BACKFILL
# =============================================================================
class DomainBackfillRequest(BaseModel):
dry_run: bool = True
job_id: Optional[str] = None # Only backfill controls from this job
limit: int = 0 # 0 = all
_domain_backfill_status: dict = {}
async def _run_domain_backfill(req: DomainBackfillRequest, backfill_id: str):
"""Backfill domain, category, and target_audience for existing controls using Anthropic."""
import os
import httpx
ANTHROPIC_API_KEY = os.getenv("ANTHROPIC_API_KEY", "")
ANTHROPIC_MODEL = os.getenv("CONTROL_GEN_ANTHROPIC_MODEL", "claude-sonnet-4-6")
if not ANTHROPIC_API_KEY:
_domain_backfill_status[backfill_id] = {
"status": "failed", "error": "ANTHROPIC_API_KEY not set"
}
return
db = SessionLocal()
try:
# Find controls needing backfill
where_clauses = ["(target_audience IS NULL OR target_audience = '[]' OR target_audience = 'null')"]
params: dict = {}
if req.job_id:
where_clauses.append("generation_metadata->>'job_id' = :job_id")
params["job_id"] = req.job_id
query = f"""
SELECT id, control_id, title, objective, category, source_original_text, tags
FROM canonical_controls
WHERE {' AND '.join(where_clauses)}
ORDER BY control_id
"""
if req.limit > 0:
query += f" LIMIT {req.limit}"
result = db.execute(text(query), params)
controls = [dict(zip(result.keys(), row)) for row in result]
total = len(controls)
updated = 0
errors = []
_domain_backfill_status[backfill_id] = {
"status": "running", "total": total, "updated": 0, "errors": []
}
# Process in batches of 10
BATCH_SIZE = 10
for batch_start in range(0, total, BATCH_SIZE):
batch = controls[batch_start:batch_start + BATCH_SIZE]
entries = []
for idx, ctrl in enumerate(batch):
text_for_analysis = ctrl.get("objective") or ctrl.get("title") or ""
original = ctrl.get("source_original_text") or ""
if original:
text_for_analysis += f"\n\nQuelltext-Auszug: {original[:500]}"
entries.append(
f"--- CONTROL {idx + 1}: {ctrl['control_id']} ---\n"
f"Titel: {ctrl.get('title', '')}\n"
f"Objective: {text_for_analysis[:800]}\n"
f"Tags: {json.dumps(ctrl.get('tags', []))}"
)
prompt = f"""Analysiere die folgenden {len(batch)} Controls und bestimme fuer jedes:
1. domain: Das Fachgebiet (AUTH, CRYP, NET, DATA, LOG, ACC, SEC, INC, AI, COMP, GOV, LAB, FIN, TRD, ENV, HLT)
2. category: Die Kategorie (encryption, authentication, network, data_protection, logging, incident, continuity, compliance, supply_chain, physical, personnel, application, system, risk, governance, hardware, identity, public_administration, labor_law, finance, trade_regulation, environmental, health)
3. target_audience: Liste der Zielgruppen (moegliche Werte: "unternehmen", "behoerden", "entwickler", "datenschutzbeauftragte", "geschaeftsfuehrung", "it-abteilung", "rechtsabteilung", "compliance-officer", "personalwesen", "einkauf", "produktion", "vertrieb", "gesundheitswesen", "finanzwesen", "oeffentlicher_dienst")
Antworte mit einem JSON-Array mit {len(batch)} Objekten. Jedes Objekt hat:
- control_index: 1-basierter Index
- domain: Fachgebiet-Kuerzel
- category: Kategorie
- target_audience: Liste der Zielgruppen
{"".join(entries)}"""
try:
headers = {
"x-api-key": ANTHROPIC_API_KEY,
"anthropic-version": "2023-06-01",
"content-type": "application/json",
}
payload = {
"model": ANTHROPIC_MODEL,
"max_tokens": 4096,
"system": "Du bist ein Compliance-Experte. Klassifiziere Controls nach Fachgebiet und Zielgruppe. Antworte NUR mit validem JSON.",
"messages": [{"role": "user", "content": prompt}],
}
async with httpx.AsyncClient(timeout=60.0) as client:
resp = await client.post(
"https://api.anthropic.com/v1/messages",
headers=headers,
json=payload,
)
if resp.status_code != 200:
errors.append(f"Anthropic API {resp.status_code} at batch {batch_start}")
continue
raw = resp.json().get("content", [{}])[0].get("text", "")
# Parse response
import re
bracket_match = re.search(r"\[.*\]", raw, re.DOTALL)
if not bracket_match:
errors.append(f"No JSON array in response at batch {batch_start}")
continue
results_list = json.loads(bracket_match.group(0))
for item in results_list:
idx = item.get("control_index", 0) - 1
if idx < 0 or idx >= len(batch):
continue
ctrl = batch[idx]
ctrl_id = str(ctrl["id"])
new_domain = item.get("domain", "")
new_category = item.get("category", "")
new_audience = item.get("target_audience", [])
if not isinstance(new_audience, list):
new_audience = []
# Build new control_id from domain if domain changed
old_prefix = ctrl["control_id"].split("-")[0] if ctrl["control_id"] else ""
new_prefix = new_domain.upper()[:4] if new_domain else old_prefix
if not req.dry_run:
update_parts = []
update_params: dict = {"ctrl_id": ctrl_id}
if new_category:
update_parts.append("category = :category")
update_params["category"] = new_category
if new_audience:
update_parts.append("target_audience = :target_audience")
update_params["target_audience"] = json.dumps(new_audience)
# Note: We do NOT rename control_ids here — that would
# break references and cause unique constraint violations.
if update_parts:
update_parts.append("updated_at = NOW()")
db.execute(
text(f"UPDATE canonical_controls SET {', '.join(update_parts)} WHERE id = CAST(:ctrl_id AS uuid)"),
update_params,
)
updated += 1
if not req.dry_run:
db.commit()
except Exception as e:
errors.append(f"Batch {batch_start}: {str(e)}")
db.rollback()
_domain_backfill_status[backfill_id] = {
"status": "running", "total": total, "updated": updated,
"progress": f"{min(batch_start + BATCH_SIZE, total)}/{total}",
"errors": errors[-10:],
}
_domain_backfill_status[backfill_id] = {
"status": "completed", "total": total, "updated": updated,
"errors": errors[-50:],
}
logger.info("Domain backfill %s completed: %d/%d updated", backfill_id, updated, total)
except Exception as e:
logger.error("Domain backfill %s failed: %s", backfill_id, e)
_domain_backfill_status[backfill_id] = {"status": "failed", "error": str(e)}
finally:
db.close()
@router.post("/generate/backfill-domain")
async def start_domain_backfill(req: DomainBackfillRequest):
"""Backfill domain, category, and target_audience for controls using Anthropic API.
Finds controls where target_audience is NULL and enriches them.
Default is dry_run=True (preview only).
"""
import uuid
backfill_id = str(uuid.uuid4())[:8]
_domain_backfill_status[backfill_id] = {"status": "starting"}
asyncio.create_task(_run_domain_backfill(req, backfill_id))
return {"status": "running", "backfill_id": backfill_id,
"message": f"Domain backfill started. Poll /generate/backfill-status/{backfill_id}"}
@router.get("/generate/domain-backfill-status/{backfill_id}")
async def get_domain_backfill_status(backfill_id: str):
"""Get status of a domain backfill job."""
status = _domain_backfill_status.get(backfill_id)
if not status:
raise HTTPException(status_code=404, detail="Domain backfill job not found")
return status
+91 -348
View File
@@ -1,15 +1,15 @@
# CI/CD Pipeline
Übersicht über den Deployment-Prozess für Breakpilot.
Uebersicht ueber den Deployment-Prozess fuer BreakPilot Compliance.
## Übersicht
## Uebersicht
| Komponente | Build-Tool | Deployment |
|------------|------------|------------|
| Frontend (Next.js) | Docker | Mac Mini |
| Backend (FastAPI) | Docker | Mac Mini |
| Go Services | Docker (Multi-stage) | Mac Mini |
| Documentation | MkDocs | Docker (Nginx) |
| Frontend (Next.js) | Docker | Coolify (automatisch) |
| Backend (FastAPI) | Docker | Coolify (automatisch) |
| Go Services | Docker (Multi-stage) | Coolify (automatisch) |
| Documentation | MkDocs | Docker (Nginx, lokal) |
## Deployment-Architektur
@@ -17,386 +17,129 @@
┌─────────────────────────────────────────────────────────────────┐
│ Entwickler-MacBook │
│ │
│ breakpilot-pwa/
│ ├── studio-v2/ (Next.js Frontend)
│ ├── admin-v2/ (Next.js Admin)
│ ├── backend/ (Python FastAPI)
│ ├── consent-service/ (Go Service)
── klausur-service/ (Python FastAPI)
│ ├── voice-service/ (Python FastAPI) │
│ ├── ai-compliance-sdk/ (Go Service) │
│ └── docs-src/ (MkDocs) │
│ breakpilot-compliance/
│ ├── admin-compliance/ (Next.js Dashboard)
│ ├── backend-compliance/ (Python FastAPI)
│ ├── ai-compliance-sdk/ (Go/Gin)
│ ├── developer-portal/ (Next.js)
── docs-src/ (MkDocs)
│ │
$ ./sync-and-deploy.sh
git push origin main && git push gitea main
└───────────────────────────────┬─────────────────────────────────┘
rsync + SSH
git push
┌─────────────────────────────────────────────────────────────────┐
Mac Mini Server
Gitea (gitea.meghsakha.com)
│ │
Docker Compose
│ ├── website (Port 3000)
│ ├── studio-v2 (Port 3001)
│ ├── admin-v2 (Port 3002)
│ ├── backend (Port 8000)
── consent-service (Port 8081)
│ ├── klausur-service (Port 8086) │
│ ├── voice-service (Port 8082) │
│ ├── ai-compliance-sdk (Port 8090) │
│ ├── docs (Port 8009) │
│ ├── postgres │
│ ├── valkey (Redis) │
│ ├── qdrant (extern: qdrant-dev.breakpilot.ai) │
│ └── object-storage (extern: nbg1.your-objectstorage.com) │
Gitea Actions CI:
│ ├── test-go-ai-compliance
│ ├── test-python-backend-compliance
│ ├── test-python-document-crawler
│ ├── test-python-dsms-gateway
── validate-canonical-controls
│ │
│ Coolify Webhook → Build + Deploy (automatisch) │
└─────────────────────────────────────────────────────────────────┘
│ auto-deploy
┌─────────────────────────────────────────────────────────────────┐
│ Production (Coolify) │
│ │
│ ├── admin-dev.breakpilot.ai (Admin Compliance) │
│ ├── api-dev.breakpilot.ai (Backend API) │
│ ├── sdk-dev.breakpilot.ai (AI SDK) │
│ └── developers-dev.breakpilot.ai (Developer Portal) │
└─────────────────────────────────────────────────────────────────┘
```
## Sync & Deploy Workflow
## Workflow
### 1. Dateien synchronisieren
### 1. Code entwickeln und committen
```bash
# Sync aller relevanten Verzeichnisse zum Mac Mini
rsync -avz --delete \
--exclude 'node_modules' \
--exclude '.next' \
--exclude '.git' \
--exclude '__pycache__' \
--exclude 'venv' \
--exclude '.pytest_cache' \
/Users/benjaminadmin/Projekte/breakpilot-pwa/ \
macmini:/Users/benjaminadmin/Projekte/breakpilot-pwa/
# Code auf MacBook bearbeiten
# Committen und zu beiden Remotes pushen:
git push origin main && git push gitea main
```
### 2. Container bauen
### 2. Automatische Tests (Gitea Actions)
Push auf gitea triggert automatisch die CI-Pipeline:
- **Go Tests:** `ai-compliance-sdk` Unit Tests
- **Python Tests:** `backend-compliance`, `document-crawler`, `dsms-gateway`
- **Validierung:** Canonical Controls JSON-Validierung
- **Lint:** Go, Python, Node.js (nur bei PRs)
### 3. Automatisches Deployment (Coolify)
Nach erfolgreichem Push baut Coolify automatisch alle Services und deployt sie.
**WICHTIG:** Niemals manuell in Coolify auf "Redeploy" klicken!
### 4. Health Checks
```bash
# Einzelnen Service bauen
ssh macmini "/usr/local/bin/docker compose \
-f /Users/benjaminadmin/Projekte/breakpilot-pwa/docker-compose.yml \
build --no-cache <service-name>"
# Beispiele:
# studio-v2, admin-v2, website, backend, klausur-service, docs
# Production Health pruefen
curl -sf https://api-dev.breakpilot.ai/health
curl -sf https://sdk-dev.breakpilot.ai/health
```
### 3. Container deployen
## CI Pipeline-Konfiguration
```bash
# Container neu starten
ssh macmini "/usr/local/bin/docker compose \
-f /Users/benjaminadmin/Projekte/breakpilot-pwa/docker-compose.yml \
up -d <service-name>"
**Datei:** `.gitea/workflows/ci.yaml`
```yaml
on:
push:
branches: [main, develop]
pull_request:
branches: [main, develop]
jobs:
test-go-ai-compliance: # Go Unit Tests
test-python-backend: # Python Unit Tests
test-python-document-crawler:
test-python-dsms-gateway:
validate-canonical-controls: # JSON Validierung
go-lint: # Nur bei PRs
python-lint: # Nur bei PRs
nodejs-lint: # Nur bei PRs
```
### 4. Logs prüfen
## Lokale Entwicklung (Mac Mini)
Fuer lokale Tests ohne Coolify:
```bash
# Container-Logs anzeigen
ssh macmini "/usr/local/bin/docker compose \
-f /Users/benjaminadmin/Projekte/breakpilot-pwa/docker-compose.yml \
logs -f <service-name>"
```
## Service-spezifische Deployments
### Next.js Frontend (studio-v2, admin-v2, website)
```bash
# 1. Sync
rsync -avz --delete \
--exclude 'node_modules' --exclude '.next' --exclude '.git' \
/Users/benjaminadmin/Projekte/breakpilot-pwa/studio-v2/ \
macmini:/Users/benjaminadmin/Projekte/breakpilot-pwa/studio-v2/
# 2. Build & Deploy
ssh macmini "/usr/local/bin/docker compose \
-f /Users/benjaminadmin/Projekte/breakpilot-pwa/docker-compose.yml \
build --no-cache studio-v2 && \
/usr/local/bin/docker compose \
-f /Users/benjaminadmin/Projekte/breakpilot-pwa/docker-compose.yml \
up -d studio-v2"
```
### Python Services (backend, klausur-service, voice-service)
```bash
# Build mit requirements.txt
ssh macmini "/usr/local/bin/docker compose \
-f /Users/benjaminadmin/Projekte/breakpilot-pwa/docker-compose.yml \
build klausur-service && \
/usr/local/bin/docker compose \
-f /Users/benjaminadmin/Projekte/breakpilot-pwa/docker-compose.yml \
up -d klausur-service"
```
### Go Services (consent-service, ai-compliance-sdk)
```bash
# Multi-stage Build (Go → Alpine)
ssh macmini "/usr/local/bin/docker compose \
-f /Users/benjaminadmin/Projekte/breakpilot-pwa/docker-compose.yml \
build --no-cache consent-service && \
/usr/local/bin/docker compose \
-f /Users/benjaminadmin/Projekte/breakpilot-pwa/docker-compose.yml \
up -d consent-service"
```
### MkDocs Dokumentation
```bash
# Build & Deploy
ssh macmini "/usr/local/bin/docker compose \
-f /Users/benjaminadmin/Projekte/breakpilot-pwa/docker-compose.yml \
build --no-cache docs && \
/usr/local/bin/docker compose \
-f /Users/benjaminadmin/Projekte/breakpilot-pwa/docker-compose.yml \
up -d docs"
# Verfügbar unter: http://macmini:8009
```
## Health Checks
### Service-Status prüfen
```bash
# Alle Container-Status
ssh macmini "docker ps --format 'table {{.Names}}\t{{.Status}}\t{{.Ports}}'"
# Health-Endpoints prüfen
curl -s http://macmini:8000/health
curl -s http://macmini:8081/health
curl -s http://macmini:8086/health
curl -s http://macmini:8090/health
```
### Logs analysieren
```bash
# Letzte 100 Zeilen
ssh macmini "docker logs --tail 100 breakpilot-pwa-backend-1"
# Live-Logs folgen
ssh macmini "docker logs -f breakpilot-pwa-backend-1"
```
## Rollback
### Container auf vorherige Version zurücksetzen
```bash
# 1. Aktuelles Image taggen
ssh macmini "docker tag breakpilot-pwa-backend:latest breakpilot-pwa-backend:backup"
# 2. Altes Image deployen
ssh macmini "/usr/local/bin/docker compose \
-f /Users/benjaminadmin/Projekte/breakpilot-pwa/docker-compose.yml \
up -d backend"
# 3. Bei Problemen: Backup wiederherstellen
ssh macmini "docker tag breakpilot-pwa-backend:backup breakpilot-pwa-backend:latest"
# Auf Mac Mini pullen und bauen
ssh macmini "git -C ~/Projekte/breakpilot-compliance pull --no-rebase origin main"
ssh macmini "/usr/local/bin/docker compose -f ~/Projekte/breakpilot-compliance/docker-compose.yml build --no-cache <service>"
ssh macmini "/usr/local/bin/docker compose -f ~/Projekte/breakpilot-compliance/docker-compose.yml up -d <service>"
```
## Troubleshooting
### Container startet nicht
### CI-Status pruefen
```bash
# 1. Logs prüfen
ssh macmini "docker logs breakpilot-pwa-<service>-1"
# 2. Container manuell starten für Debug-Output
ssh macmini "docker compose -f .../docker-compose.yml run --rm <service>"
# 3. In Container einloggen
ssh macmini "docker exec -it breakpilot-pwa-<service>-1 /bin/sh"
# Im Browser:
# https://gitea.meghsakha.com/Benjamin_Boenisch/breakpilot-compliance/actions
```
### Port bereits belegt
### Container-Logs (lokal)
```bash
# Port-Belegung prüfen
ssh macmini "lsof -i :8000"
# Container mit dem Port finden
ssh macmini "docker ps --filter publish=8000"
ssh macmini "/usr/local/bin/docker logs -f bp-compliance-<service>"
```
### Build-Fehler
```bash
# Cache komplett leeren
ssh macmini "docker builder prune -a"
# Ohne Cache bauen
ssh macmini "docker compose build --no-cache <service>"
```
## Monitoring
### Resource-Nutzung
```bash
# CPU/Memory aller Container
ssh macmini "docker stats --no-stream"
# Disk-Nutzung
ssh macmini "docker system df"
```
### Cleanup
```bash
# Ungenutzte Images/Container entfernen
ssh macmini "docker system prune -a --volumes"
# Nur dangling Images
ssh macmini "docker image prune"
```
## Umgebungsvariablen
Umgebungsvariablen werden über `.env` Dateien und docker-compose.yml verwaltet:
```yaml
# docker-compose.yml
services:
backend:
environment:
- DATABASE_URL=postgresql://...
- REDIS_URL=redis://valkey:6379
- SECRET_KEY=${SECRET_KEY}
```
**Wichtig**: Sensible Werte niemals in Git committen. Stattdessen:
- `.env` Datei auf dem Server pflegen
- Secrets über HashiCorp Vault (siehe unten)
## Woodpecker CI - Automatisierte OAuth Integration
### Überblick
Die OAuth-Integration zwischen Woodpecker CI und Gitea ist **vollständig automatisiert**. Credentials werden in HashiCorp Vault gespeichert und bei Bedarf automatisch regeneriert.
!!! info "Warum automatisiert?"
Diese Automatisierung ist eine DevSecOps Best Practice:
- **Infrastructure-as-Code**: Alles ist reproduzierbar
- **Disaster Recovery**: Verlorene Credentials können automatisch regeneriert werden
- **Security**: Secrets werden zentral in Vault verwaltet
- **Onboarding**: Neue Entwickler müssen nichts manuell konfigurieren
### Architektur
```
┌─────────────────────────────────────────────────────────────────┐
│ Mac Mini Server │
│ │
│ ┌───────────────┐ OAuth 2.0 ┌───────────────┐ │
│ │ Gitea │ ←─────────────────────────→│ Woodpecker │ │
│ │ (Port 3003) │ Client ID + Secret │ (Port 8090) │ │
│ └───────────────┘ └───────────────┘ │
│ │ │ │
│ │ OAuth App │ Env Vars│
│ │ (DB: oauth2_application) │ │
│ │ │ │
│ ▼ ▼ │
│ ┌───────────────────────────────────────────────────────────┐ │
│ │ HashiCorp Vault (Port 8200) │ │
│ │ │ │
│ │ secret/cicd/woodpecker: │ │
│ │ - gitea_client_id │ │
│ │ - gitea_client_secret │ │
│ │ │ │
│ │ secret/cicd/api-tokens: │ │
│ │ - gitea_token (für API-Zugriff) │ │
│ │ - woodpecker_token (für Pipeline-Trigger) │ │
│ └───────────────────────────────────────────────────────────┘ │
└─────────────────────────────────────────────────────────────────┘
```
### Credentials-Speicherorte
| Ort | Pfad | Inhalt |
|-----|------|--------|
| **HashiCorp Vault** | `secret/cicd/woodpecker` | Client ID + Secret (Quelle der Wahrheit) |
| **.env Datei** | `WOODPECKER_GITEA_CLIENT/SECRET` | Für Docker Compose (aus Vault geladen) |
| **Gitea PostgreSQL** | `oauth2_application` Tabelle | OAuth App Registration (gehashtes Secret) |
### Troubleshooting: OAuth Fehler
Falls der Fehler "Client ID not registered" oder "user does not exist [uid: 0]" auftritt:
```bash
# Option 1: Automatisches Regenerieren (empfohlen)
./scripts/sync-woodpecker-credentials.sh --regenerate
# Option 2: Manuelles Vorgehen
# 1. Credentials aus Vault laden
vault kv get secret/cicd/woodpecker
# 2. .env aktualisieren
WOODPECKER_GITEA_CLIENT=<client_id>
WOODPECKER_GITEA_SECRET=<client_secret>
# 3. Zu Mac Mini synchronisieren
rsync .env macmini:~/Projekte/breakpilot-pwa/
# 4. Woodpecker neu starten
ssh macmini "cd ~/Projekte/breakpilot-pwa && \
docker compose up -d --force-recreate woodpecker-server"
```
### Das Sync-Script
Das Script `scripts/sync-woodpecker-credentials.sh` automatisiert den gesamten Prozess:
```bash
# Credentials aus Vault laden und .env aktualisieren
./scripts/sync-woodpecker-credentials.sh
# Neue Credentials generieren (OAuth App in Gitea + Vault + .env)
./scripts/sync-woodpecker-credentials.sh --regenerate
```
Was das Script macht:
1. **Liest** die aktuellen Credentials aus Vault
2. **Aktualisiert** die .env Datei automatisch
3. **Bei `--regenerate`**:
- Löscht alte OAuth Apps in Gitea
- Erstellt neue OAuth App mit neuem Client ID/Secret
- Speichert Credentials in Vault
- Aktualisiert .env
### Vault-Zugriff
```bash
# Vault Token (Development)
export VAULT_TOKEN=breakpilot-dev-token
# Credentials lesen
docker exec -e VAULT_TOKEN=$VAULT_TOKEN breakpilot-pwa-vault \
vault kv get secret/cicd/woodpecker
# Credentials setzen
docker exec -e VAULT_TOKEN=$VAULT_TOKEN breakpilot-pwa-vault \
vault kv put secret/cicd/woodpecker \
gitea_client_id="..." \
gitea_client_secret="..."
```
### Services neustarten nach Credentials-Änderung
```bash
# Wichtig: --force-recreate um neue Env Vars zu laden
cd /Users/benjaminadmin/Projekte/breakpilot-pwa
docker compose up -d --force-recreate woodpecker-server
# Logs prüfen
docker logs breakpilot-pwa-woodpecker-server --tail 50
# Lokalen Build-Cache leeren
ssh macmini "/usr/local/bin/docker builder prune -a"
```
+395
View File
@@ -0,0 +1,395 @@
# QA: Control Quality Pipeline
## Übersicht
Die Control Quality Pipeline prüft und verbessert die Canonical Controls der Compliance-Bibliothek. Sie nutzt **PDF-basierte Verifizierung** als Ground Truth — jeder Control-Originaltext wird direkt im Quelldokument (PDF) lokalisiert.
Alle Scripts liegen in **`scripts/qa/`**. Starten auf dem Mac Mini via Runner-Script:
```bash
# Job starten (laedt .env automatisch, PID-Lock, unbuffered output)
ssh macmini "bash ~/Projekte/breakpilot-compliance/scripts/qa/run_job.sh <script.py> [args...]"
# Status aller Jobs
ssh macmini "bash ~/Projekte/breakpilot-compliance/scripts/qa/run_job.sh --status"
# Log ansehen
ssh macmini "bash ~/Projekte/breakpilot-compliance/scripts/qa/run_job.sh --log <script.py>"
# Job stoppen
ssh macmini "bash ~/Projekte/breakpilot-compliance/scripts/qa/run_job.sh --kill <script.py>"
```
## Architektur
```
Original-PDFs (~/rag-ingestion/pdfs/)
PDF Text-Extraktion (PyMuPDF)
Artikel-Index aufbauen
(Erwägungsgründe → Artikel → Anhänge)
source_original_text im PDF suchen
(Substring-Match, normalisiert)
Artikel/§/Section zuordnen + article_type setzen
Duplikat-Erkennung
(Preamble vs. Artikel: Artikel hat Vorrang)
```
## PDF-basierte Artikelzuordnung
### Konzept
Jeder Control hat ein Feld `source_original_text` — der Chunk-Text aus dem Quelldokument. Statt über Qdrant-Hashes wird dieser Text **direkt im Original-PDF gesucht**. Die Position im PDF bestimmt den Artikel.
### Dokumenttypen
| Typ | Struktur | Beispiel |
|-----|----------|---------|
| EU-Verordnung | Erwägungsgründe → Artikel → Anhänge | DSGVO, KI-VO, CRA |
| Deutsches Gesetz | §-Paragraphen | BDSG, GewO, HGB |
| NIST | Control Families (AC-1, SC-7) | SP 800-53, CSF 2.0 |
| OWASP | Kategorien (A01:2021, V1.1) | Top 10, ASVS, MASVS |
| EDPB/ENISA | Nummerierte Abschnitte | Leitlinien, Guidelines |
### Article Types
| article_type | Bedeutung | Beispiel |
|---|---|---|
| `article` | Gesetzesartikel / Paragraph | Artikel 25 DSGVO |
| `preamble` | Erwägungsgrund | Erwägungsgrund (78) |
| `annex` | Anhang | Anhang III |
| `control` | NIST Control Family | AC-6, SA-7 |
| `section` | Nummerierter Abschnitt | Section 2.1 |
| `category` | OWASP Kategorie | A01:2021 |
| `requirement` | OWASP Requirement | V1.1, MASVS-STORAGE-1 |
### Ergebnisse (Stand 2026-03-20)
| Metrik | Wert |
|---|---|
| Controls mit source_original_text | 5.751 (86%) |
| Im PDF lokalisiert | **5.063 (88%)** |
| Nicht gefunden | 649 |
| Kein PDF vorhanden | 29 |
| Recital_suspect markiert | 648 |
| 100% Match-Rate | 20+ Regulations (inkl. DSGVO, KI-VO, NIS2, NIST 800-53, Blue Guide) |
**Verlauf:** v1 (4.110, 52%) → v2 (6.091, 77%) → v3 (6.259, 79%) → v4 +Blue Guide EN (6.803, 86%) → v5 nach Cleanup (5.063/5.741, 88%)
### Nicht-matchende Controls
| Ursache | Controls | Status |
|---|---|---|
| ~~Blue Guide EN vs. DE PDF~~ | ~~562~~ | ✅ Gelöst — EN-PDF beschafft, 544/544 gematcht |
| ~~OWASP Top 10 multilingual~~ | ~~324~~ | ✅ Als duplicate markiert — Übersetzungen ohne Mehrwert |
| CRA Encoding | ~76 | PDF-Ligaturen/Sonderzeichen-Differenzen |
| CISA Secure by Design | ~113 | Falsches PDF (ENISA statt CISA) |
| OWASP ASVS | ~173 | PDF-Matching-Problem (meist EN) |
## Brute-Force-Suche
Für Controls mit unbekannter Quelle: Text gegen **alle ~100 PDFs** suchen. Findet:
- Korrekte Quelldokument-Zuordnung
- Falsche Source-Zuordnungen (44 entdeckt)
## Erwägungsgrund-Controls (Wettbewerbsvorteil)
Controls aus Erwägungsgründen (`article_type = preamble`) sind **kein Nachteil**. Sie decken Aspekte ab, die reine Artikel-basierte Compliance-Tools übersehen.
**Duplikat-Regel:** Wenn ein Preamble-Control das gleiche Thema wie ein Artikel-Control behandelt (Jaccard-Ähnlichkeit ≥ 0.40), hat der **Artikel Vorrang**. Das Preamble-Control wird als `duplicate` markiert.
### Ergebnis der Preamble-Dedup
| Metrik | Wert |
|---|---|
| Preamble-Controls geprüft | 838 |
| Als Duplikat markiert | 190 |
| **Unique Preamble-Controls** | **648** |
## Pipeline-Versionen
| Version | Controls | Mit Originaltext | Beschreibung |
|---|---|---|---|
| v1 | 5.332 | 4.137 (78%) | Automatisch + manuell erstellt |
| v2 | 2.258 | 2.258 (100%) | Automatisch aus Chunks |
| v3 | 1.570 | 1.548 (99%) | Neueste Pipeline |
Die 1.195 v1-Controls **ohne** Originaltext sind manuell erstellt (`strategy=ungrouped`) und haben keine Chunk-Referenz.
## OWASP Cleanup (2026-03-20)
- **324 OWASP Top 10 multilingual Controls**`duplicate` markiert (ZH, AR, ID, FR, ES, PT — Übersetzungen derselben 10 Kategorien)
- **47 Controls** mit falscher Quellenzuordnung korrigiert (z.B. als "OWASP Top 10" getaggt, aber tatsächlich aus ASVS/SAMM/API/MASVS)
- **~200 OWASP ASVS/SAMM/MASVS EN Controls** behalten — unique Content aus GitHub/Website, nicht im PDF auffindbar
## NIST OSCAL Import (2026-03-20)
**776 neue Controls** aus NIST SP 800-53 Rev 5 OSCAL (Public Domain, maschinenlesbar):
- Quelle: `usnistgov/oscal-content` (JSON Catalog)
- Vor allem **Control Enhancements** (z.B. AC-2(3), SC-7(8)) — die atomaren Unteranforderungen
- Jeder Control enthält: Statement + Guidance + Assessment-Methoden + Cross-References + Parameters
- `pipeline_version = 4`, `generation_strategy = 'oscal_import'`
- Kein Pass 0a/0b nötig — Controls sind **bereits atomar**
| Metrik | Vorher | Nachher |
|---|---|---|
| SP 800-53 Controls (aktiv) | 1.107 | **1.883** |
| OSCAL-Abdeckung | 238/1.014 (23%) | **1.014/1.014 (100%)** |
## Phase 5: RAG-Deduplizierung + Normalisierung (2026-03-20)
### Durchgeführte Schritte
| Schritt | Beschreibung | Controls |
|---|---|---|
| 5.1 | OSCAL Controls: `source_regulation` in generation_metadata gesetzt | 776 |
| 5.2 | v3 Controls ohne Source → `needs_review` mit `missing_source` Flag | 20 |
| 5.3 | Leerer Source-Name korrigiert (AT TKG) | 1 |
| 5.4 | OWASP regulation_code Fehlzuordnungen korrigiert | 47 |
| 5.5 | **duplicate/too_close Controls hart gelöscht** | **3.301** |
| 5.6 | Processed Chunks bereinigt (gelöschte Control-IDs entfernt) | 2.520 |
### Ergebnis
- **Vorher:** 9.936 Controls (6.635 aktiv, 2.998 duplicate, 303 too_close)
- **Nachher:** 6.635 Controls, **alle aktiv** (0 duplicate/too_close)
- Alle regulation_codes haben jetzt einheitliche Source-Namen
- OWASP-Controls sind korrekt ihren Quellen zugeordnet
## DB-Status (Stand 2026-03-20, nach Phase 7.4)
| release_state | Count |
|---|---|
| draft | ~6.030 |
| needs_review | 838 |
| **Gesamt** | **6.868** |
## Scripts (`scripts/qa/`)
### Kern-QA (PDF-Matching)
| Script | Beschreibung |
|---|---|
| `pdf_qa_all.py` | **Haupt-QA**: Controls gegen PDFs matchen, Artikel-Index aufbauen. Enthaelt `SOURCE_FILE_MAP`, alle Index-Builder (EU, DE, NIST, OWASP, generic). 526 Zeilen. |
| `pdf_qa_inventory.py` | Inventar: Welche Regulations haben Controls, wie viele, welche PDFs existieren |
| `apply_pdf_qa_results.py` | Ergebnisse aus `pdf_qa_all.py` in DB schreiben (`article_type`, `recital_suspect`) |
| `pdf_article_lookup_poc.py` | POC: Control-Text in PDF lokalisieren, Headings von Cross-Refs unterscheiden |
### Lueckenanalyse + Control-Generierung
| Script | Beschreibung |
|---|---|
| `gap_analysis.py` | **Phase 7.3**: Artikel im PDF vs. Controls in DB vergleichen, Luecken identifizieren |
| `phase74_generate_gap_controls.py` | **Phase 7.4**: Neue Controls fuer Luecken via Anthropic API generieren. `pipeline_version=5`. 624 Zeilen. |
| `benchmark_llm_controls.py` | LLM-Vergleich: gpt-oss-120b vs. Claude Sonnet fuer Control-Generierung |
| `test_pass0a.py` | **Pass 0a Test**: Obligation Extraction + 3-Tier-Klassifizierung (Pflicht/Empfehlung/Kann). Standalone, speichert JSON. |
### Deduplizierung + Normalisierung
| Script | Beschreibung |
|---|---|
| `preamble_dedup.py` | Preamble vs. Artikel Duplikat-Erkennung (Jaccard >= 0.40) |
| `qa_dedup_controls.py` | Jaccard-basierte Titel-Deduplizierung |
| `qa_apply_and_dedup.py` | Ergebnisse anwenden + Duplikate in einem Schritt markieren |
| `qa_normalize_sources.py` | Source-Namen normalisieren (kanonische Namen) |
| `phase5_normalize_and_cleanup.py` | **Phase 5**: Normalisierung + 3.301 Duplikate hart loeschen |
| `qa_delete_gpsr_dupe.py` | GPSR-Duplikate loeschen |
| `delete_gpsr_prod.py` | GPSR-Duplikate aus Production-Qdrant entfernen |
### Quellen-spezifische Scripts
| Script | Beschreibung |
|---|---|
| `blue_guide_en_match.py` | Blue Guide EN-PDF matchen (544/544 Erfolg) |
| `owasp_cleanup.py` | OWASP multilingual Cleanup (324 Duplikate) + Source-Fix (47 korrigiert) |
| `owasp_github_match.py` | OWASP ASVS/SAMM/MASVS gegen GitHub-Markdown matchen |
| `oscal_import.py` | NIST OSCAL Import (776 Controls aus JSON Catalog) |
| `oscal_analysis.py` | NIST OSCAL Analyse: Abdeckung, fehlende Controls |
### Diagnose + Utilities
| Script | Beschreibung |
|---|---|
| `db_status.py` | DB-Status: release_state Counts, pipeline_version, source Verteilung |
| `debug_low_match.py` | Debugging: Warum matchen Blue Guide / OWASP / CISA schlecht? |
| `qa_article_map_all_chunks.py` | Alle Chunks Artikel-Nummern zuordnen (Bulk) |
| `backfill_job_66228863.py` | Einmaliger Backfill-Job |
| `sync_controls_to_prod.py` | Controls von Dev nach Production synchronisieren |
### Runner
| Script | Beschreibung |
|---|---|
| `run_job.sh` | **Job-Runner**: Laedt `.env`, PID-Lock, Monitoring (`--status`, `--log`, `--kill`) |
## Phase 7: PDF-Validierung + Enrichment (2026-03-20)
### 7.1 + 7.2: Controls gegen PDFs validiert + Ergebnisse angewendet ✅
- 5.063 Controls erfolgreich im Original-PDF lokalisiert (88%)
- `article_type` fuer alle gematchten Controls gesetzt
- 648 Preamble-Controls als `recital_suspect` in `generation_metadata` markiert
- 332 Controls nicht matchbar (OWASP ASVS 132, CISA 72, ENISA 38, OWASP SAMM 31, CRA 28)
### 7.3: Lueckenanalyse ✅
**494 Artikel-Luecken** in 15 Quellen identifiziert. Geschaetzt ~300 davon actionable.
| Source | Luecken | Coverage | Bemerkung |
|---|---:|---:|---|
| AML-Verordnung | 91 | 5% | Kaum ingestiert |
| MiCA | 71 | 52% | Grosse Verordnung |
| NIST SP 800-53 | 59 | 83% | Meist Section-Header, nur SA-15 fehlt |
| OWASP ASVS 4.0 | 47 | 35% | Requirement-Gruppen fehlen |
| Batterieverordnung | 41 | 58% | |
| DSGVO | 35 | 65% | Einige Governance/Aufsicht-Artikel |
| ENISA ICS/SCADA | 34 | 31% | |
| ENISA Supply Chain | 26 | 7% | |
| CRA | 23 | 68% | |
| NIS2 | 16 | 65% | |
| KI-Verordnung | 15 | 87% | Fast komplett |
| Maschinenverordnung | 5 | 91% | Fast komplett |
### 7.4: Neue Controls fuer Luecken generieren ✅ (2026-03-20)
Script: `phase74_generate_gap_controls.py --resume`
- **494 Artikel-Luecken** in 15 Quellen → Anthropic Claude Sonnet 4.6
- `pipeline_version = 5`, `generation_strategy = 'phase74_gap_fill'`
- Direkt PDF-Text als Input (nicht RAG-Chunks)
- Starten via: `run_job.sh phase74_generate_gap_controls.py --resume`
**Ergebnis:**
| Source | Luecken | Generiert |
|---|---:|---:|
| AML-Verordnung | 91 | 97 |
| MiCA | 71 | 68 |
| NIST SP 800-53 | 59 | 19 |
| KI-Verordnung | 15 | 15 |
| OWASP ASVS 4.0 | 47 | 11 |
| Batterieverordnung | 41 | 9 |
| DSGVO | 35 | 4 |
| OWASP Top 10 | 12 | 3 |
| NIS2 | 16 | 3 |
| CRA | 23 | 3 |
| OECD KI-Empfehlung | 4 | 1 |
| **Gesamt** | **494** | **233** |
Nicht generiert: 75 zu kurzer Text, 29 NIST-Intros, 11 Parse-Errors, 162 ID-Konflikte (COMP-1000 etc.).
API-Kosten: ~$7,55 (109 min Laufzeit).
## Pass 0a: Obligation Extraction — 3-Tier-Klassifizierung
### Konzept
Pass 0a zerlegt Rich Controls (~6.000) in **atomare Obligations** per LLM (Claude Sonnet 4.6).
Jede Obligation wird durch den **Quality Gate** klassifiziert — nicht gefiltert:
| obligation_type | Signal | Beispiel |
|---|---|---|
| **pflicht** | müssen, muss, ist zu, hat zu, shall, must, required | "Der Betreiber muss alle Daten verschluesseln" |
| **empfehlung** | soll, sollen, should, sicherstellen, gewaehrleisten, dokumentieren | "Der Betreiber soll regelmaessige Audits durchfuehren" |
| **kann** | kann, koennen, darf, duerfen, may, optional | "Der Betreiber kann zusaetzliche Massnahmen ergreifen" |
**Wichtig:** Nichts wird mehr rejected wegen fehlendem normativem Signal. Obligations ohne Signal werden als `empfehlung` klassifiziert. Rejected werden nur noch: Evidence-Only, zu kurz (<20 Zeichen), fehlender Parent-Link.
### Warum auch Empfehlungen behalten?
Empfehlungen helfen Firmen, ihre Systeme sicherer zu machen — ueber das Pflichtprogramm hinaus. Im Frontend erhalten Kunden einen Marker, der klar anzeigt:
- **Pflicht** = gesetzlich/regulatorisch vorgeschrieben
- **Empfehlung** = Best Practice, freiwillig, aber wertvoll
- **Kann** = optional, weitergehende Massnahme
### Quality Gate — Kritische Flags
| Flag | Kritisch? | Beschreibung |
|---|---|---|
| `has_normative_signal` | Nein | Informativer Check, kein Ablehnungsgrund |
| `obligation_type` | — | Klassifizierung (pflicht/empfehlung/kann) |
| `not_evidence_only` | **Ja** | Kein reiner Nachweis-Eintrag |
| `min_length` | **Ja** | Mindestens 20 Zeichen |
| `has_parent_link` | **Ja** | Verbindung zum Parent-Control |
| `single_action` | Nein | Nur ein Hauptverb (heuristisch) |
| `not_rationale` | Nein | Keine reine Begruendung |
### Normative Signal Detection — Regex-Tiers
```
Tier 1 (Pflicht): muessen, muss, ist/sind/hat/haben zu + Infinitiv,
Compound-Verben (festzustellen, vorzunehmen),
Gerundivum (mitzuteilen, bereitzustellen),
shall, must, required
Tier 2 (Empfehlung): soll, sollen, sollte, sollten,
gewaehrleisten, sicherstellen,
should, ensure, recommend,
dokumentieren, implementieren, ueberpruefen
Tier 3 (Kann): kann, koennen, darf, duerfen, may, optional
```
### Testergebnisse (3 Iterationen, 2026-03-20)
| Run | Controls | Obligations | Validated | Rejected | Kosten |
|---|---:|---:|---:|---:|---:|
| 1 (v0 Regex) | 10 | ~100 | 68% | 32% | $0,28 |
| 2 (v1 Regex) | 50 | ~530 | 78% | 22% | $1,43 |
| 3 (v2 Regex) | 50 | ~530 | 86% | 14% | $1,44 |
| 4 (3-Tier) | 60 | — | — | — | — |
Run 4 laeuft mit dem neuen Klassifizierer — statt PASS/REJECT wird jetzt PFLICHT/EMPFEHLUNG/KANN ausgegeben.
### Scripts
| Script | Beschreibung |
|---|---|
| `test_pass0a.py` | **Test-Script**: Standalone (kein SQLAlchemy), psycopg2 + Anthropic API. Speichert Ergebnisse als JSON. |
```bash
# Test mit 10 Controls
run_job.sh test_pass0a.py --limit 10
# Test mit bestimmter Quelle
run_job.sh test_pass0a.py --limit 20 --source "DSGVO"
# Ergebnisse: /tmp/pass0a_results_<N>controls.json
```
### Backend-Code
- **Klassifizierung:** `backend-compliance/compliance/services/decomposition_pass.py`
- `classify_obligation_type()` — 3-Tier-Klassifizierung
- `quality_gate()` — gibt `obligation_type` in Flags zurueck
- `passes_quality_gate()``has_normative_signal` nicht mehr kritisch
- `ObligationCandidate.obligation_type` — neues Feld
### Hochrechnung (basierend auf 50-Control-Runs)
| Metrik | Wert |
|---|---|
| Kosten pro Control | ~$0,029 |
| Kosten fuer ~6.000 Controls | **~$172** |
| Laufzeit (geschaetzt) | ~25h |
| Obligations pro Control | ~10,5 |
---
## Naechste Schritte
1. ~~**Phase 5 Cleanup** → 3.301 Duplikate geloescht, Source normalisiert~~
2. ~~**Phase 6 Pipeline-Haertung** → Source aus REGULATION_LICENSE_MAP~~
3. ~~**Phase 7.1-7.3** → PDF-Validierung + Enrichment + Lueckenanalyse~~
4. ~~**Phase 7.4** → 233 neue Controls fuer Luecken generiert ($7,55)~~
5. **Pass 0a** → Obligation Extraction mit 3-Tier-Klassifizierung (Tests laufen, ~$172)
6. **Pass 0b** → Atomic Control Composition aus validierten Obligations
7. **Pass 1-5** → Multi-Layer Migration (Code + 500 Tests bereits vorhanden)
8. **Phase 8** → Qdrant Re-Ingestion (Runtime-Betrieb, ZULETZT)
9. **needs_review Triage** — 838 Controls klassifizieren
10. **Frontend**`obligation_type` (Pflicht/Empfehlung/Kann) + `article_type` anzeigen
@@ -0,0 +1,206 @@
# RAG Pipeline Benchmark & Optimierungen
Stand: 2026-03-21. Vergleich unserer Implementierung mit State of the Art. Priorisierte Empfehlungen nach Impact/Effort.
---
## Aktuelle Pipeline (Ist-Zustand)
```mermaid
flowchart LR
A[Dokumente] -->|Document Crawler| B[Chunks 512/50]
B -->|bge-m3| C[Qdrant Dense]
C -->|Cosine Search| D[Control Generator v2]
D -->|LLM| E[Rich Controls 6.373]
E -->|Pass 0a| F[Obligations]
F -->|Pass 0b| G[Atomare Controls]
G -->|4-Stage Dedup| H[Master Controls ~18K]
```
| Komponente | Implementierung | SOTA-Bewertung |
|-----------|----------------|----------------|
| **Chunking** | Rekursiv, 512 Zeichen, 50 Overlap | Zu klein fuer Rechtstexte |
| **Embedding** | bge-m3 (1024-dim, Ollama) | Gut, aber nur Dense genutzt |
| **Vector DB** | Qdrant mit Payload-Filtering | Hybrid Search nicht aktiviert |
| **Retrieval** | Pure Dense Cosine Similarity | Kein Re-Ranking, kein BM25 |
| **Extraktion** | 3-Tier (Exact → Embedding → LLM) | Solide Architektur |
| **Dedup** | 4-Stage (Pattern → Action → Object → Embedding) | Ueberdurchschnittlich |
| **QA** | 5-Metrik Similarity + PDF-QA Matching | Gut, RAGAS fehlt |
---
## Tier 1: Quick Wins (Tage, nicht Wochen)
### 1. Chunk-Groesse erhoehen: 512 → 1024, Overlap 50 → 128
**Problem:** NAACL 2025 Vectara-Studie zeigt: fuer analytische/juristische Queries sind 512-1024 Token optimal. Unsere 512-Zeichen-Chunks (= ~128 Token) sind deutlich zu klein.
**Unsere Lessons Learned:** "Chunks werden mitten im Absatz abgeschnitten. Artikel- und Paragraphennummern fehlen."
**Aenderung:** Config-Parameter in `ingest-phase-h.sh` anpassen.
| Metrik | Vorher | Nachher |
|--------|--------|---------|
| Chunk Size | 512 chars (~128 Token) | 1024 chars (~256 Token) |
| Overlap | 50 chars (10%) | 128 chars (12.5%) |
**Impact:** HOCH | **Effort:** NIEDRIG
### 2. Ollama JSON-Mode fuer Obligation Extraction
**Problem:** `_parse_json` in `decomposition_pass.py` hat Regex-Fallback — das zeigt, dass LLM-Output nicht zuverlaessig JSON ist.
**Aenderung:** `format: "json"` in Ollama-API-Calls setzen.
**Impact:** MITTEL | **Effort:** NIEDRIG (1 Parameter)
### 3. Chain-of-Thought Prompting fuer Pass 0a/0b
**Problem:** LegalGPT-Framework zeigt: explizite Reasoning-Chains ("Erst Addressat identifizieren, dann Aktion, dann normative Staerke") verbessern Extraktionsqualitaet signifikant.
**Impact:** MITTEL | **Effort:** NIEDRIG (Prompt Engineering)
---
## Tier 2: High Impact, Medium Effort (1-2 Wochen)
### 4. Hybrid Search (Dense + Sparse) via Qdrant
**Problem:** Reine Dense-Suche. Juristische Queries enthalten spezifische Begriffe ("DSGVO Art. 35", "Abs. 3"), die BM25/Sparse besser findet.
**Loesungsansatz:** BGE-M3 generiert bereits Sparse Vectors — wir verwerfen sie aktuell!
```
Qdrant Query API:
- Dense: bge-m3 Cosine (wie bisher)
- Sparse: bge-m3 Sparse Vectors (neu)
- Fusion: Reciprocal Rank Fusion (RRF)
```
**Benchmarks (Anthropic):** 49% weniger fehlgeschlagene Retrievals mit Contextual Retrieval, 67% mit Re-Ranking.
**Impact:** SEHR HOCH | **Effort:** MITTEL
### 5. Cross-Encoder Re-Ranking
**Problem:** Top-5 Ergebnisse direkt an LLM — keine Qualitaetspruefung der Retrieval-Ergebnisse.
**Loesungsansatz:** BGE Reranker v2 (MIT-Lizenz) auf Top-20 Ergebnisse, dann Top-5 an LLM.
| Re-Ranker | Lizenz | Empfehlung |
|-----------|--------|------------|
| BGE Reranker v2 | MIT | Empfohlen |
| Jina Reranker v2 | Apache-2.0 | Alternative |
| ColBERT v2 | MIT | Spaeter |
**Impact:** HOCH | **Effort:** MITTEL
### 6. Cross-Regulation Dedup Pass
**Problem:** Dedup filtert immer nach `pattern_id` — Controls aus DSGVO Art. 25 und NIS2 Art. 21 (beide Security-by-Design) werden nie verglichen.
**Loesungsansatz:** Zweiter Qdrant-Search ohne `pattern_id`-Filter nach dem normalen Dedup-Pass.
**Impact:** HOCH | **Effort:** MITTEL
### 7. Automatische Regressionstests (Golden Set)
**Problem:** Keine systematische Qualitaetsmessung nach Pipeline-Aenderungen.
**Loesungsansatz:** 20-Chunk Golden Set → Control-Generation → Output-Stabilitaet pruefen.
**Impact:** HOCH | **Effort:** NIEDRIG
---
## Tier 3: Strategische Investitionen (Wochen bis Monate)
### 8. Artikel-Boundary Chunking
Eigener Splitter fuer EU-Verordnungen und deutsche Gesetze: Split an "Art.", "Artikel", "Paragraph"-Grenzen statt nach Zeichenzahl.
### 9. RAGAS Evaluation Pipeline
[RAGAS](https://docs.ragas.io/) mit Golden Dataset (50-100 manuell verifizierte Control-to-Source Mappings). Metriken: Faithfulness, Answer Relevancy, Context Precision, Context Recall.
### 10. BGE-M3 Fine-Tuning
Fine-Tuning auf Compliance-Corpus (~6.373 Control-Titel/Objective-Paare). Research zeigt +10-30% Domain-Retrieval-Verbesserung.
### 11. LLM-as-Judge
Claude Sonnet bewertet jeden generierten Control auf Faithfulness zum Quelltext (~$0.01/Control).
### 12. Active Learning aus Review-Queue
Menschliche Entscheidungen der Dedup Review-Queue nutzen, um Schwellenwerte ueber die Zeit zu optimieren.
---
## Nicht empfohlen (niedriger ROI oder Konflikte)
| Ansatz | Grund |
|--------|-------|
| Jina v3 Embeddings | **CC-BY-NC-4.0** — verletzt Open Source Policy |
| Voyage-law-2 | API-only, proprietaer — kein Self-Hosting |
| Semantic Chunking | Benchmarks zeigen keinen Vorteil gegenueber Recursive fuer strukturierte Dokumente |
| HyDE als Primaerstrategie | Latenz (+43-60%) + Halluzinationsrisiko |
| Knowledge Graph RAG | Massiver Aufwand, unklarer Gewinn bei strukturiertem Rechtskorpus |
---
## Embedding-Modell Vergleich
| Modell | MTEB Score | Multilingual | Kontext | Lizenz | Bewertung |
|--------|-----------|-------------|---------|--------|-----------|
| **BGE-M3** (aktuell) | 63.0 | 100+ Sprachen | 8192 Token | MIT | Gut, Dense+Sparse+ColBERT |
| Jina v3 | 65.5 | 89 Sprachen | 8192 Token | CC-BY-NC | Nicht nutzbar (Lizenz!) |
| E5-Mistral-7B | ~65 | Gut | 4096 Token | MIT | Gross, hoher RAM |
| Voyage-law-2 | Best Legal | EN Legal | 16K Token | Proprietaer | Nicht nutzbar (API-only) |
**Fazit:** BGE-M3 bleibt die beste Wahl fuer unseren Stack. Sparse-Vectors aktivieren und Fine-Tuning bringen mehr als ein Modellwechsel.
---
## Test-Coverage Analyse
### Pipeline-Module (567 Tests)
| Modul | Tests | Bewertung | Fehlende Tests |
|-------|-------|-----------|----------------|
| Control Generator | 110 | Exzellent | 10-15 Edge Cases |
| Obligation Extractor | 107 | Exzellent | 8-10 Edge Cases |
| Decomposition Pass | 90 | Exzellent | 5-8 Edge Cases |
| Pattern Matcher | 72 | Gut | 10-15 Edge Cases |
| Control Dedup | 56 | Exzellent | 5-8 Edge Cases |
| Control Composer | 54 | Gut | 8-10 Edge Cases |
| Pipeline Adapter | 36 | Gut | 10-15 Edge Cases |
| Citation Backfill | 20 | Moderat | 5-8 Edge Cases |
| License Gate | 12 | Minimal | 5-8 Edge Cases |
| RAG Client | 10 | Minimal | 5-8 Edge Cases |
### Kritische Luecken (fehlende Tests)
| Service | Datei | Prioritaet |
|---------|-------|------------|
| AI Compliance Assistant | `ai_compliance_assistant.py` | HOCH (25-30 Tests noetig) |
| PDF Extractor | `pdf_extractor.py` | HOCH (20-25 Tests noetig) |
| LLM Provider | `llm_provider.py` | HOCH (15-20 Tests noetig) |
| Similarity Detector | `similarity_detector.py` | MITTEL (20-25 Tests noetig) |
| Anchor Finder | `anchor_finder.py` | MITTEL |
### Test-Infrastruktur
**Fehlend:** Shared `conftest.py` mit gemeinsamen Fixtures (LLM-Mock, DB-Mock, Embedding-Mock). Aktuell sind Fixtures in jedem Test-File dupliziert.
---
## Quellen
- [NAACL 2025 Vectara Chunking Study](https://blog.premai.io/rag-chunking-strategies-the-2026-benchmark-guide/)
- [Anthropic Contextual Retrieval](https://www.anthropic.com/news/contextual-retrieval)
- [Qdrant Hybrid Search Query API](https://qdrant.tech/articles/hybrid-search/)
- [Structure-Aware Chunking for Legal (ACL 2025)](https://aclanthology.org/2025.justnlp-main.19/)
- [RAGAS Evaluation Framework](https://docs.ragas.io/)
- [BGE Reranker v2 (MIT)](https://huggingface.co/BAAI/bge-reranker-v2-m3)
- [LegalGPT / CALLM Framework](https://www.emergentmind.com/topics/compliance-alignment-llm-callm)
@@ -0,0 +1,223 @@
# RAG Pipeline: Lessons Learned & Hardening
## Übersicht
Dieses Dokument beschreibt die Erkenntnisse aus dem Aufbau der RAG-Pipeline und die daraus abgeleiteten Maßnahmen zur Härtung. Es dient als Referenz für zukünftige Ingestion-Runs und Pipeline-Erweiterungen.
## Architektur: Wann brauchen wir RAG vs. Direct PDF?
### RAG ist nötig für:
| Use Case | Warum RAG? |
|---|---|
| **Compliance Advisor (Chat)** | Semantische Suche über 38+ Dokumente in Echtzeit |
| **Cross-Regulation Mapping** | "Zeige alle Anforderungen zu Verschlüsselung" über alle Quellen |
| **Customer Scope-Filtering** | Nur Chunks aus relevanten Regulations für den Kunden |
| **Inkrementelle Updates** | Neues Dokument → nur neue Chunks verarbeiten |
### RAG ist NICHT nötig für:
| Use Case | Besser: Direct PDF |
|---|---|
| **Control-Generierung (Batch)** | PDF → PyMuPDF → Strukturparser → Artikel-Index → API |
| **PDF-QA/Verifizierung** | Substring-Match direkt im PDF (schneller, exakter) |
| **Artikel/§-Extraktion** | Regex-basierte Extraktion aus PDF-Text |
### Hybrid-Ansatz (Empfehlung)
```
Control-Generierung: PDF → Strukturparser → Artikel-Index → Anthropic API
(KEIN RAG nötig, direkt aus PDF)
Runtime-Betrieb: Qdrant-RAG für semantische Suche, Chat, Scope-Analyse
(RAG mit angereicherten Chunks + Struktur-Metadaten)
```
## Fehler und Root Causes
### 1. Doppelte Ingestion = Doppelte Controls
**Problem:** Gleiche PDFs unter verschiedenen Namen ingestiert (z.B. "Maschinenverordnung" und "Verordnung (EU) 2023/1230") → unterschiedliche Chunks (anderes Chunking) → anderer Hash → doppelt verarbeitet → doppelte Controls.
**Root Cause:**
- `regulation_name` aus Chunk-Metadaten statt aus kanonischer Quelle
- UNIQUE-Constraint nur `(chunk_hash, collection, document_version)` — nicht global
- Kein Check ob `regulation_code` bereits in einer Collection existiert
**Fix (implementiert):**
- `REGULATION_LICENSE_MAP` enthält jetzt kanonische `name`-Werte die den DB-Einträgen entsprechen
- `source_citation.source` wird aus `REGULATION_LICENSE_MAP.name` genommen, NICHT aus `chunk.regulation_name`
- Phase 5 Cleanup: 3.301 Duplikate hart gelöscht
**Fix (noch offen):**
- Chunk-Hash UNIQUE Constraint global machen: `(chunk_hash, document_version)` statt `(chunk_hash, collection, document_version)`
- Vor Ingestion: Check ob `regulation_code` bereits in einer Collection existiert
### 2. Chunks verlieren Strukturinformation
**Problem:** Chunks werden mitten im Absatz abgeschnitten. § und Artikelnummern fehlen in den Chunk-Metadaten. Kontext des Kapitels/Abschnitts geht verloren.
**Root Cause:**
- `chunk_strategy=recursive` mit `chunk_size=512, chunk_overlap=50` — zu kleine Chunks
- Chunking beachtet keine Dokumentstruktur (Artikel-/Paragraphengrenzen)
- Keine Einleitung/Kapitelkontext als Prefix
**Empfehlung für Re-Ingestion:**
- **Strukturiertes Chunking:** Chunks an Artikel-/Paragraphengrenzen schneiden
- **Kontext-Prefix:** Kapiteleinleitung und übergeordnete Struktur mitliefern
- **Metadaten anreichern:** `article`, `paragraph`, `article_type`, `section_hierarchy`
- **Größere Chunks:** Mindestens 1024 Tokens, besser volle Artikel/Paragraphen
### 3. Cross-Collection-Duplikate
**Problem:** `nist_csf_2_0` in `bp_compliance_ce` (67 Chunks) UND `bp_compliance_datenschutz` (162 Chunks). EU-Verordnungen sowohl in `bp_compliance_ce` als auch `bp_compliance_gesetze`.
**Root Cause:** Keine Collection-Zuordnungsregeln. Manuelle Zuweisung bei Ingestion.
**Fix:** `cleanup-qdrant-duplicates.py` Script bereinigt Cross-Collection-Duplikate.
**Empfehlung:** Klare Collection-Zuordnungsregeln:
- `bp_compliance_ce` = EU-Verordnungen + internationale Standards
- `bp_compliance_gesetze` = Deutsche + österreichische Gesetze (NUR nationale Gesetze)
- `bp_compliance_datenschutz` = EDPB/WP29 Leitlinien + Privacy Frameworks
### 4. OWASP Multilingual Controls
**Problem:** 324 OWASP Top 10 Controls in ZH, AR, ID, FR, ES, PT — Übersetzungen derselben 10 Kategorien. Kein Mehrwert, aber 324 doppelte Controls generiert.
**Root Cause:** Multilingual PDFs/GitHub-Quellen ohne Spracherkennung ingestiert.
**Fix:** 324 als `duplicate` markiert und gelöscht.
**Empfehlung:** Bei Ingestion Spracherkennung + Deduplizierung. Nur DE + EN behalten.
### 5. Fehlende Artikel/Paragraph-Extraktion
**Problem:** Chunks haben `article` und `paragraph` oft leer oder falsch. Die LLM-basierte Extraktion bei der Control-Generierung ist unzuverlässig.
**Root Cause:** Ingestion-Pipeline extrahiert keine Strukturinformation aus dem PDF.
**Fix (implementiert):** PDF-QA-Pipeline (`pdf_qa_all.py`) matched `source_original_text` gegen Original-PDFs und extrahiert korrekte Artikel/Paragraphen — 86% Match-Rate.
**Empfehlung:** Bei Re-Ingestion direkt in den Chunk-Metadaten speichern.
### 6. Job-Tracking nicht persistent
**Problem:** Generation-Jobs laufen als Background-Tasks. Kein Logging, welche Chunks verarbeitet, Status nur über API abfragbar. Bei API-Timeout oder Restart geht der Fortschritt verloren.
**Root Cause:** `asyncio.create_task()` hat keinen Recovery-Mechanismus.
**Fix (teilweise):** `canonical_generation_jobs` Tabelle trackt Jobs. `canonical_processed_chunks` markiert verarbeitete Chunks.
**Empfehlung:**
- Job-Log in DB persistieren (nicht nur stdout)
- Fortschritt in `canonical_generation_jobs.progress` als JSONB speichern
- Chunk-Level-Status: verarbeitet / übersprungen / Fehler
- Recovery-Fähigkeit: Job kann von letztem Checkpoint fortgesetzt werden
## Empfohlene Metadaten für Re-Ingestion
### Chunk-Level Metadaten (Qdrant Payload)
```json
{
"chunk_text": "...",
"regulation_code": "eu_2016_679",
"regulation_name_de": "DSGVO (EU) 2016/679",
"regulation_name_en": "GDPR (EU) 2016/679",
"article": "25",
"article_title": "Datenschutz durch Technikgestaltung und datenschutzfreundliche Voreinstellungen",
"article_type": "article",
"paragraph": "1",
"section_hierarchy": ["Kapitel IV", "Abschnitt 2", "Artikel 25"],
"chapter_context": "Kapitel IV — Verantwortlicher und Auftragsverarbeiter",
"pages": [45, 46],
"effective_date": "2018-05-25",
"publication_date": "2016-04-27",
"document_version": "2016-04-27",
"source_language": "de",
"source_url": "https://eur-lex.europa.eu/...",
"celex": "32016R0679",
"license": "EU_LAW",
"license_rule": 1,
"source_type": "law",
"category": "datenschutz",
"chunk_position": 42,
"total_chunks": 423
}
```
### Dokument-Level Metadaten (Corpus Version)
```json
{
"regulation_code": "eu_2016_679",
"canonical_name_de": "DSGVO (EU) 2016/679",
"canonical_name_en": "GDPR (EU) 2016/679",
"document_type": "eu_regulation",
"effective_date": "2018-05-25",
"publication_date": "2016-04-27",
"supersedes": null,
"superseded_by": null,
"source_pdf": "gdpr_regulation_eu_2016_679.pdf",
"source_pdf_sha256": "abc123...",
"total_articles": 99,
"total_recitals": 173,
"total_annexes": 0,
"ingestion_date": "2026-03-20",
"ingestion_version": "v2"
}
```
## Pipeline-Härtung Checkliste
### Vor Ingestion
- [ ] Prüfen ob `regulation_code` bereits in einer Collection existiert
- [ ] PDF-SHA256 gegen bekannte PDFs prüfen (Duplikat-Erkennung)
- [ ] `regulation_name` aus `REGULATION_LICENSE_MAP` verwenden, NICHT aus Chunk-Metadaten
- [ ] Spracherkennung: Nur DE + EN ingestieren
- [ ] Dokument-Metadaten (effective_date, publication_date) recherchieren
### Während Ingestion
- [ ] Strukturiertes Chunking an Artikel-/Paragraphengrenzen
- [ ] Kontext-Prefix mit Kapiteleinleitung
- [ ] Chunk-Metadaten anreichern (article, paragraph, article_type, section_hierarchy)
- [ ] Fortschritt in DB loggen
### Nach Ingestion
- [ ] Chunk-Count pro `regulation_code` prüfen (Sanity Check)
- [ ] PDF-QA gegen Original-PDF laufen lassen
- [ ] Cross-Collection-Duplikat-Check
- [ ] Corpus-Version in DB eintragen
### Control-Generierung
- [ ] `source_citation.source` aus `REGULATION_LICENSE_MAP.name`, NICHT aus Chunk-Metadaten
- [ ] Harmonisierung: Threshold 0.85 für Duplikate innerhalb gleicher `regulation_code`
- [ ] Cross-Regulation-Harmonisierung bei ähnlichen Themen (z.B. DSGVO Art. 25 ↔ NIS2 Art. 21)
- [ ] Job-Fortschritt persistent in DB speichern
## Workflow: Mac Mini → Production Sync
```
1. Mac Mini: PDF → Qdrant (lokal, http://macmini:6333)
2. Mac Mini: Control-Generierung → PostgreSQL (shared, 46.225.100.82:54321)
3. QA: PDF-Match, Dedup, Source-Normalisierung
4. Qdrant Migration: macmini:6333 → qdrant-dev.breakpilot.ai (scripts/migrate-qdrant.py)
5. Deploy: git push gitea → Coolify Build + Deploy
```
**WICHTIG:** PostgreSQL ist SHARED — Änderungen auf Mac Mini sind sofort in Production sichtbar. Qdrant hat getrennte Instanzen (lokal + production) und muss manuell synchronisiert werden.
## Scripts
| Script | Beschreibung |
|---|---|
| `scripts/ingest-phase-h.sh` | Haupt-Ingestion: 38 Dokumente → Qdrant |
| `scripts/cleanup-qdrant-duplicates.py` | Qdrant Duplikat-Cleanup (8 Schritte) |
| `scripts/migrate-qdrant.py` | Qdrant Migration: lokal → production |
| `scripts/qa/phase5_normalize_and_cleanup.py` | DB Normalisierung + Hard Delete |
| `scripts/qa/pdf_qa_all.py` | PDF-Match QA |
+46
View File
@@ -209,3 +209,49 @@ Wenn du z.B. eine neue `GetUserStats()` Funktion im Go Service hinzufuegst:
```
3. **Tests ausfuehren**: `go test -v ./internal/services/...`
4. **Dokumentation aktualisieren** (siehe [Dokumentation](./documentation.md))
---
## Modul-spezifische Tests
### Canonical Control Generator (98+ Tests)
Die Control Library hat eine umfangreiche Test-Suite ueber 6 Dateien.
Siehe [Canonical Control Library — Tests](../services/sdk-modules/canonical-control-library.md#tests) und [Control Generator Pipeline](../services/sdk-modules/control-generator-pipeline.md) fuer Details.
```bash
# Alle Generator-Tests (98 Tests in 13 Klassen)
cd backend-compliance && pytest -v tests/test_control_generator.py
# Similarity Detector Tests
cd backend-compliance && pytest -v compliance/tests/test_similarity_detector.py
# API Route Tests
cd backend-compliance && pytest -v tests/test_canonical_control_routes.py
# License Gate Tests
cd backend-compliance && pytest -v tests/test_license_gate.py
# CI/CD Validator Tests
cd backend-compliance && pytest -v tests/test_validate_controls.py
```
**Wichtig:** Die Generator-Tests nutzen Mocks fuer Anthropic-API und Qdrant — sie laufen ohne externe Abhaengigkeiten.
**Testklassen in `test_control_generator.py`:**
| Klasse | Tests | Prueft |
|--------|-------|--------|
| `TestLicenseMapping` | 13 | Lizenz-Klassifikation (Rule 1/2/3), Case-Insensitivitaet, source_type |
| `TestDomainDetection` | 5 | Keyword-basierte Domain-Erkennung (AUTH, CRYP, NET, DATA) |
| `TestJsonParsing` | 4 | JSON-Parser fuer LLM-Responses (Markdown-Fencing, Preamble) |
| `TestGeneratedControlRules` | 3 | Rule-spezifische Felder (original_text, citation, source_info) |
| `TestAnchorFinder` | 2 | RAG-Suche + Web-Framework-Erkennung |
| `TestPipelineMocked` | 5 | End-to-End Pipeline mit Mocks (Lizenz, Hash-Dedup, Config) |
| `TestParseJsonArray` | 15 | JSON-Array-Parser (Wrapper-Objekte, Bracket-Extraction, Fallbacks) |
| `TestBatchSizeConfig` | 5 | Batch-Groesse-Konfiguration + Defaults |
| `TestBatchProcessingLoop` | 10 | Batch-Verarbeitung (Rule-Split, Mixed-Rules, Too-Close, Null-Handling) |
| `TestRegulationFilter` | 5 | regulation_filter Prefix-Matching, leere regulation_codes |
| `TestPipelineVersion` | 5 | pipeline_version=2 in DB-Writes, null-Handling in Structure/Reform |
| `TestRecitalDetection` | 10 | Erwaegungsgrund-Erkennung in Quelltexten (Regex, Phrasen, Kombiniert) |
| `TestSourceTypeClassification` | 16 | law/guideline/standard/restricted Klassifizierung aller Quellentypen |
+31 -109
View File
@@ -64,131 +64,39 @@ Module die Compliance-Kunden im SDK sehen und nutzen:
| **Document Crawler** | Automatisches Crawling von Rechtstexten | /sdk/document-crawler |
| **Advisory Board** | KI-Compliance-Beirat | /sdk/advisory-board |
## Admin-Module (Plattform-Verwaltung)
Interne Tools fuer die BreakPilot-Plattformverwaltung:
| Modul | Beschreibung | Frontend |
|-------|--------------|----------|
| **Katalogverwaltung** | SDK-Kataloge & Auswahltabellen | /dashboard/catalog-manager |
| **Mandantenverwaltung** | B2B-Kundenverwaltung & Mandanten | /dashboard/multi-tenant |
| **SSO-Konfiguration** | Single Sign-On & Authentifizierung | /dashboard/sso |
| **DSB Portal** | Datenschutzbeauftragter-Arbeitsbereich | /dashboard/dsb-portal |
---
## URLs
### Production (Coolify-deployed)
| URL | Service | Beschreibung |
|-----|---------|--------------|
| https://macmini:3007/ | Admin Compliance | Compliance-Dashboard |
| https://macmini:3006/ | Developer Portal | API-Dokumentation |
| https://macmini:8002/ | Backend API | Compliance REST API |
| https://macmini:8093/ | AI SDK API | SDK Backend-API |
| https://admin-dev.breakpilot.ai/ | Admin Compliance | Compliance-Dashboard |
| https://developers-dev.breakpilot.ai/ | Developer Portal | API-Dokumentation |
| https://api-dev.breakpilot.ai/ | Backend API | Compliance REST API |
| https://sdk-dev.breakpilot.ai/ | AI SDK API | SDK Backend-API |
### SDK-Module (Admin Compliance)
### Lokal (Mac Mini — nur Dev/Tests)
| URL | Modul |
|-----|-------|
| https://macmini:3007/sdk | SDK Uebersicht |
| https://macmini:3007/sdk/requirements | Requirements |
| https://macmini:3007/sdk/controls | Controls |
| https://macmini:3007/sdk/evidence | Evidence |
| https://macmini:3007/sdk/risks | Risk Matrix |
| https://macmini:3007/sdk/ai-act | AI Act |
| https://macmini:3007/sdk/audit-checklist | Audit Checklist |
| https://macmini:3007/sdk/audit-report | Audit Report |
| https://macmini:3007/sdk/obligations | Obligations v2 |
| https://macmini:3007/sdk/iace | IACE (CE-Risikobeurteilung) |
| https://macmini:3007/sdk/import | Document Import |
| https://macmini:3007/sdk/screening | System Screening |
| https://macmini:3007/sdk/rag | RAG/Quellen |
| https://macmini:3007/sdk/tom | TOM |
| https://macmini:3007/sdk/dsfa | DSFA |
| https://macmini:3007/sdk/vvt | VVT |
| https://macmini:3007/sdk/loeschfristen | Loeschfristen |
| https://macmini:3007/sdk/email-templates | E-Mail-Templates |
| https://macmini:3007/sdk/academy | Academy |
| https://macmini:3007/sdk/training | Training Engine |
| https://macmini:3007/sdk/whistleblower | Whistleblower |
| https://macmini:3007/sdk/incidents | Incidents |
| https://macmini:3007/sdk/reporting | Reporting |
| https://macmini:3007/sdk/vendor-compliance | Vendor Compliance |
| https://macmini:3007/sdk/industry-templates | Branchenvorlagen |
| https://macmini:3007/sdk/document-crawler | Document Crawler |
| https://macmini:3007/sdk/advisory-board | Advisory Board |
### Admin-Module (Dashboard)
| URL | Modul |
|-----|-------|
| https://macmini:3007/dashboard | Dashboard |
| https://macmini:3007/dashboard/catalog-manager | Katalogverwaltung |
| https://macmini:3007/dashboard/multi-tenant | Mandantenverwaltung |
| https://macmini:3007/dashboard/sso | SSO-Konfiguration |
| https://macmini:3007/dashboard/dsb-portal | DSB Portal |
---
## Abhaengigkeiten zu Core
Compliance-Services nutzen folgende Core-Infrastruktur:
| Core Service | Genutzt von | Zweck |
|-------------|-------------|-------|
| PostgreSQL (46.225.100.82:54321, extern) | Alle | Compliance-Datenbank (Hetzner/meghshakka, TLS) |
| Valkey (6379) | Backend, Admin | Session Cache |
| Vault (8200) | Alle | Secrets Management |
| Qdrant (qdrant-dev.breakpilot.ai) | AI SDK, Document Crawler | Vector-Suche (gehostet, API-Key) |
| Hetzner Object Storage | TTS Service, Document Crawler | Datei-Storage (S3-kompatibel) |
| Embedding (8087) | AI SDK | Text-Embeddings |
| RAG Service (8097) | AI SDK | Retrieval Augmented Generation |
| Nginx | Alle | HTTPS Reverse Proxy |
---
## Services-Dokumentation
- [AI Compliance SDK](services/ai-compliance-sdk/index.md)
- [Architektur](services/ai-compliance-sdk/ARCHITECTURE.md)
- [Developer Guide](services/ai-compliance-sdk/DEVELOPER.md)
- [Auditor-Dokumentation](services/ai-compliance-sdk/AUDITOR_DOCUMENTATION.md)
- [SBOM](services/ai-compliance-sdk/SBOM.md)
- [Document Crawler](services/document-crawler/index.md)
- SDK-Module:
- [Analyse-Module (Paket 2)](services/sdk-modules/analyse-module.md) — Requirements, Controls, Evidence, Risk Matrix, AI Act, Audit Checklist, Audit Report
- [Dokumentations-Module (Paket 3+)](services/sdk-modules/dokumentations-module.md) — VVT, Source Policy, Document Generator, Audit Checklist, Training Engine
- [DSFA (Art. 35 DSGVO)](services/sdk-modules/dsfa.md) — vollständig backend-persistent, Migration 024
- [Rechtliche Texte (Paket 4)](services/sdk-modules/rechtliche-texte.md) — Einwilligungen, Consent, Cookie Banner, Workflow
- [Academy](services/sdk-modules/academy.md)
- [Whistleblower](services/sdk-modules/whistleblower.md)
- [Incidents](services/sdk-modules/incidents.md)
- [Reporting](services/sdk-modules/reporting.md)
- [Vendors](services/sdk-modules/vendors.md)
- [Industry Templates](services/sdk-modules/industry-templates.md)
- [Document Crawler](services/sdk-modules/document-crawler.md)
- [Advisory Board](services/sdk-modules/advisory-board.md)
- [DSB Portal](services/sdk-modules/dsb-portal.md)
## Entwicklung
- [Testing](development/testing.md)
- [Dokumentation](development/documentation.md)
- [CI/CD Pipeline](development/ci-cd-pipeline.md)
| URL | Service |
|-----|---------|
| https://macmini:3007/ | Admin Compliance |
| https://macmini:3006/ | Developer Portal |
| https://macmini:8002/ | Backend API |
| https://macmini:8093/ | AI SDK API |
---
## Deployment
```bash
# Voraussetzung: breakpilot-core muss laufen
# Production (Coolify — Standardweg):
git push origin main && git push gitea main
# Coolify baut und deployt automatisch.
# Alle Compliance-Services starten
# Lokal (Mac Mini — nur Dev/Tests):
docker compose -f breakpilot-compliance/docker-compose.yml up -d
# Einzelnen Service neu bauen
docker compose -f breakpilot-compliance/docker-compose.yml build --no-cache <service>
docker compose -f breakpilot-compliance/docker-compose.yml up -d <service>
```
---
@@ -203,3 +111,17 @@ git push origin main && git push gitea main
# origin: http://macmini:3003/pilotadmin/breakpilot-compliance.git
# gitea: git@gitea.meghsakha.com:Benjamin_Boenisch/breakpilot-compliance.git
```
---
## Services-Dokumentation
- [AI Compliance SDK](services/ai-compliance-sdk/index.md)
- [Document Crawler](services/document-crawler/index.md)
- SDK-Module: siehe Unterverzeichnisse
## Entwicklung
- [Testing](development/testing.md)
- [Dokumentation](development/documentation.md)
- [CI/CD Pipeline](development/ci-cd-pipeline.md)
@@ -0,0 +1,813 @@
# Anti-Fake-Evidence Architektur
**Status:** Phase 3 (aktiv seit 2026-03-23)
**Prefix:** CP-AFE
**Motivation:** Delve-Vorfall (Maerz 2026) — Compliance-Theater verhindern
---
## Warum dieses System existiert
### Das Delve-Problem
Im Maerz 2026 wurde bekannt, wie die Compliance-Plattform Delve ein Compliance-Audit
bestand — ohne dass die Firma tatsaechlich compliant war:
1. **LLM-generierte Nachweise** wurden 1:1 als Evidence akzeptiert. Ein GPT-generierter
Text "Die Organisation hat ein ISMS implementiert" wurde als Nachweis fuer ISO 27001
Kontrolle A.5 eingesetzt — ohne dass ein ISMS existierte.
2. **Controls ohne Evidence** standen auf "pass". Das System erlaubte es, jeden Control-Status
manuell auf "pass" zu setzen, ohne dass ein einziger Nachweis hochgeladen wurde.
3. **100%-Compliance-Dashboards** ohne Validierung. Das Management sah eine gruene 100%-Anzeige
und glaubte, das Audit sei bestanden — bis der externe Auditor nach Dokumenten fragte.
### Haftungsrisiko
Wenn eine Compliance-Plattform falsche Compliance suggeriert, haftet:
- **Die Firma** — Aufsichtsbehoerden (z.B. BfDI, BaFin) akzeptieren "die Software hat gesagt
wir sind compliant" nicht als Entschuldigung
- **Die Geschaeftsfuehrung** — persoenliche Haftung bei DSGVO/NIS2-Verstoessen
- **Der Plattform-Anbieter** — wenn die Software den Eindruck erweckt, Compliance sei
nachgewiesen, obwohl sie nur Platzhalter anzeigt
### Die 6 Guardrails
Die Anti-Fake-Evidence Architektur implementiert 6 Schutzmechanismen:
```mermaid
graph TB
G1["1. Evidence Confidence Levels<br/>(E0-E4)"]
G2["2. Truth-Status Lifecycle<br/>(generated → validated)"]
G3["3. Control Status Machine<br/>(pass erfordert Evidence ≥ E2)"]
G4["4. Four-Eyes-Prinzip<br/>(GOV/PRIV: 2 unabhaengige Reviewer)"]
G5["5. LLM Truth Labels<br/>(may_be_used_as_evidence = false)"]
G6["6. Verbotene Formulierungen<br/>(keine Claims ohne Nachweis)"]
G1 --> G3
G2 --> G3
G4 --> G3
G5 --> G1
G3 --> G6
style G1 fill:#fee2e2,stroke:#dc2626
style G2 fill:#fef3c7,stroke:#d97706
style G3 fill:#dbeafe,stroke:#2563eb
style G4 fill:#d1fae5,stroke:#059669
style G5 fill:#e0e7ff,stroke:#4f46e5
style G6 fill:#fce7f3,stroke:#db2777
```
**Zusammenspiel:** Ein Control kann nur auf "pass" stehen, wenn mindestens ein Evidence
mit Confidence >= E2 vorliegt, dessen Truth-Status validiert ist. Bei GOV/PRIV-Controls
muessen zwei verschiedene Personen den Evidence reviewt haben (Four-Eyes). LLM-generierte
Inhalte koennen nie als Evidence zaehlen.
---
## Zusammenspiel mit evidence_type
Das [evidence_type Feld](evidence-type.md) (code/process/hybrid) bestimmt,
**wie** Evidence gesammelt wird. Das Anti-Fake-Evidence System bestimmt,
**ob** die gesammelte Evidence valide ist:
| evidence_type | Typische Evidence-Quelle | Confidence | Automatisierbar? |
|---|---|---|---|
| `code` | SAST-Report, CI/CD-Pipeline, IaC-Scan | E3 (observed) | Ja — System-beobachtet |
| `process` | Policy-Dokument, Schulungsnachweis, Vertrag | E1 (uploaded) → E2 (reviewed) | Nein — Review noetig |
| `hybrid` | Code-Scan + Prozess-Doku | E1-E3 gemischt | Teilweise |
!!! warning "Code Controls sind nicht automatisch valide"
Auch ein SAST-Report (E3) muss einen validen Truth-Status haben.
Ein veralteter Scan (> 90 Tage) wird als "stale" markiert und reduziert
die Evidence Freshness im Dashboard-Score.
---
## Evidence Confidence Levels (E0E4)
| Level | Bezeichnung | Beschreibung | Beispiel |
|-------|-------------|--------------|----------|
| **E0** | Generated | LLM-Output, Platzhalter | KI-generierter Nachweis-Entwurf |
| **E1** | Uploaded | Manuell hochgeladen, ungeprüft | PDF ohne Reviewer |
| **E2** | Reviewed | Intern geprüft, Hash verifiziert | Dokument von Compliance-Beauftragtem bestätigt |
| **E3** | Observed | System-beobachtet (CI/CD, API) | Automatischer SAST-Report mit SHA-256 |
| **E4** | Auditor-validated | Extern validiert | Wirtschaftsprüfer hat akzeptiert |
### Auto-Klassifikation
| Source | Confidence | Truth Status |
|--------|-----------|--------------|
| `ci_pipeline` | E3 | observed |
| `api` (mit Hash) | E3 | observed |
| `manual` / `upload` | E1 | uploaded |
| `generated` | E0 | generated |
---
## Evidence Truth-Status Lifecycle
```mermaid
stateDiagram-v2
[*] --> generated : LLM erzeugt
[*] --> uploaded : Manuell hochgeladen
[*] --> observed : CI/CD Pipeline
generated --> rejected : Review abgelehnt
uploaded --> validated_internal : Intern geprueft
uploaded --> rejected : Review abgelehnt
observed --> validated_internal : Intern bestaetigt
validated_internal --> provided_to_auditor : An Auditor uebergeben
provided_to_auditor --> accepted_by_auditor : Auditor akzeptiert
provided_to_auditor --> rejected : Auditor lehnt ab
```
---
## Control Status-Transition State Machine
```mermaid
stateDiagram-v2
planned --> in_progress : immer erlaubt
in_progress --> pass : Evidence >= E2 + truth_status valid
in_progress --> partial : min 1 Evidence (beliebig)
in_progress --> fail : immer erlaubt
pass --> fail : Degradation (immer)
partial --> pass : Evidence >= E2 + truth_status valid
note right of pass
Voraussetzung: min 1 Evidence
mit confidence >= E2 UND
truth_status in (uploaded,
observed, validated_internal,
accepted_by_auditor)
end note
```
### Transition-Regeln
| Von | Nach | Voraussetzung |
|-----|------|---------------|
| planned | in_progress | keine |
| in_progress | pass | min 1 Evidence mit confidence >= E2, truth_status valide |
| in_progress | partial | min 1 Evidence (beliebig) |
| in_progress | fail | immer erlaubt |
| pass | fail | immer erlaubt (Degradation) |
| * | n/a | erfordert `status_justification` |
| * | planned | immer erlaubt (Reset) |
Bei Verstoß: **HTTP 409 Conflict** mit Liste der Violations.
---
## LLM Truth-Labels
Jeder LLM-generierte Inhalt wird mit einem Truth-Label versehen:
```json
{
"generation_mode": "draft_assistance",
"truth_status": "generated",
"may_be_used_as_evidence": false,
"generated_by": "system"
}
```
### Audit-Trail
Tabelle `compliance_llm_generation_audit`:
| Feld | Typ | Beschreibung |
|------|-----|--------------|
| entity_type | VARCHAR(50) | 'evidence', 'control', 'document' |
| entity_id | VARCHAR(36) | FK zur generierten Entitaet |
| generation_mode | VARCHAR(100) | 'draft_assistance', 'auto_generation' |
| truth_status | ENUM | generated, uploaded, ... |
| may_be_used_as_evidence | BOOLEAN | Default: FALSE |
| llm_model | VARCHAR(100) | z.B. 'qwen2.5vl:32b' |
| llm_provider | VARCHAR(50) | 'ollama', 'anthropic' |
| prompt_hash | VARCHAR(64) | SHA-256 des Prompts |
---
## Multi-dimensionaler Compliance-Score
Statt einer einzelnen Prozentzahl zeigt der Score 6 Dimensionen:
| Dimension | Gewicht | Beschreibung |
|-----------|---------|--------------|
| requirement_coverage | 20% | % Requirements mit verlinktem Control |
| evidence_strength | 25% | Gewichteter Durchschnitt der Evidence-Confidence |
| validation_quality | 20% | % Evidence mit truth_status >= validated_internal |
| evidence_freshness | 10% | % Evidence nicht expired + reviewed < 90 Tage |
| control_effectiveness | 25% | Bestehende Formel (pass + partial*0.5) |
| **overall_readiness** | — | Gewichteter Composite der 5 Dimensionen |
### Hard Blocks
Zusaetzlich werden **Sperrgründe** angezeigt, die eine Audit-Readiness verhindern:
- Controls auf 'pass' ohne jegliche Evidence
- Controls auf 'pass' mit nur E0/E1-Evidence (keine Validierung)
---
## Verbotene Formulierungen
Der Drafting-Engine Validator prueft auf Formulierungen, die **ohne ausreichenden Nachweis** nicht verwendet werden duerfen:
| Verboten | Sicher stattdessen |
|----------|--------------------|
| "ist compliant" | "soll compliant sein" |
| "erfuellt vollstaendig" | "soll vollstaendig erfuellt werden" |
| "wurde geprueft" | "soll geprueft werden" |
| "wurde umgesetzt" | "ist zur Umsetzung vorgesehen" |
| "ist auditiert" | "soll auditiert werden" |
| "vollstaendig implementiert" | "Implementierung ist vorgesehen" |
| "nachweislich konform" | "Konformitaet ist nachzuweisen" |
**Erlaubt nur wenn:** control_status = pass AND confidence >= E2 AND truth_status in (validated_internal, accepted_by_auditor).
---
## API-Aenderungen
### Neue Endpoints
| Methode | Pfad | Beschreibung |
|---------|------|--------------|
| PATCH | `/evidence/{id}/review` | Evidence reviewen (Confidence upgraden) |
| POST | `/llm-audit` | LLM-Generierungs-Audit erstellen |
| GET | `/llm-audit` | LLM-Audit-Eintraege auflisten |
### Erweiterte Responses
**EvidenceResponse** — 6 neue Felder:
```json
{
"confidence_level": "E3",
"truth_status": "observed",
"generation_mode": null,
"may_be_used_as_evidence": true,
"reviewed_by": null,
"reviewed_at": null
}
```
**DashboardResponse** — neues Feld `multi_score`:
```json
{
"multi_score": {
"requirement_coverage": 85.0,
"evidence_strength": 60.0,
"validation_quality": 40.0,
"evidence_freshness": 90.0,
"control_effectiveness": 70.0,
"overall_readiness": 65.0,
"hard_blocks": ["3 Controls auf 'pass' haben nur E0/E1-Evidence"]
}
}
```
**ControlResponse** — neues Feld `status_justification`.
**ControlUpdate** — neues Feld `status_justification` (Pflicht fuer n/a-Transitions).
### Status-Transition Fehler (409)
```json
{
"detail": {
"error": "Status transition not allowed",
"current_status": "in_progress",
"requested_status": "pass",
"violations": [
"Transition to 'pass' requires at least 1 evidence with confidence >= E2..."
]
}
}
```
---
## Migration
### Phase 1
**Datei:** `backend-compliance/migrations/076_anti_fake_evidence.sql`
- Neue ENUM-Typen: `evidence_confidence_level`, `evidence_truth_status`
- 6 neue Spalten auf `compliance_evidence`
- `in_progress` Wert fuer `controlstatusenum`
- `status_justification` auf `compliance_controls`
- Neue Tabelle `compliance_llm_generation_audit`
- Backfill bestehender Evidence nach Source
- Indizes auf neue Spalten
### Phase 2
**Datei:** `backend-compliance/migrations/077_anti_fake_evidence_phase2.sql`
- Neue Tabelle `compliance_assertions` (Assertion Engine)
- 6 neue Spalten auf `compliance_evidence` (Four-Eyes: approval_status, first_reviewer, etc.)
- Performance-Index auf `compliance_audit_trail (entity_type, action, performed_at)`
---
## Phase 2: UI-Badges
Badges werden auf Evidence-Cards angezeigt und zeigen den Vertrauensstatus auf einen Blick:
| Badge | Farben | Anzeige |
|-------|--------|---------|
| **ConfidenceLevelBadge** | E0=rot, E1=gelb, E2=blau, E3=gruen, E4=emerald | Immer |
| **TruthStatusBadge** | generated=violet, uploaded=grau, observed=blau, validated=gruen, rejected=rot | Immer |
| **GenerationModeBadge** | violet + Sparkles-Icon | Wenn LLM-generiert |
| **ApprovalStatusBadge** | pending=gelb, first_approved=blau, approved=gruen, rejected=rot | Nur bei Four-Eyes |
---
## Phase 2: Assertion Engine
Die Assertion Engine trennt **Behauptungen** von **Fakten** in Compliance-Texten.
```mermaid
flowchart LR
Text[Freitext] --> Split[Satz-Splitting]
Split --> Classify{Normativ?}
Classify -->|Pflicht| A[Assertion pflicht]
Classify -->|Empfehlung| B[Assertion empfehlung]
Classify -->|Kann| C[Assertion kann]
Classify -->|Begruendung| D[Rationale]
Classify -->|Evidence-Keywords| E[Fact tentativ]
E --> Verify[Manuell verifizieren]
Verify --> Fact[Verified Fact]
```
### Assertion-Typen
| Typ | Bedeutung | Beispiel |
|-----|-----------|----------|
| **assertion** | Normative Aussage (unbewiesen) | "Die Organisation muss ein ISMS implementieren" |
| **fact** | Verifizierte Tatsache | "ISO-Zertifikat Nr. 12345 liegt vor" |
| **rationale** | Begruendung | "Dies ist notwendig, weil..." |
### Normative Tiers
| Tier | Signal-Woerter |
|------|---------------|
| **pflicht** | muss, hat sicherzustellen, ist verpflichtet, shall, must, required |
| **empfehlung** | soll, sollte, gewaehrleisten, should, ensure |
| **kann** | kann, darf, may, optional |
---
## Phase 2: Four-Eyes-Prinzip
```mermaid
stateDiagram-v2
[*] --> pending_first : Evidence erstellt (Gov/Priv Domain)
pending_first --> first_approved : 1. Reviewer OK
first_approved --> approved : 2. Reviewer OK (andere Person!)
first_approved --> rejected : 2. Reviewer lehnt ab
pending_first --> rejected : 1. Reviewer lehnt ab
note right of first_approved
Zweiter Reviewer MUSS
eine andere Person sein
als der erste Reviewer
end note
```
### Domains mit Four-Eyes-Pflicht
| Domain | Four-Eyes? | Begruendung |
|--------|-----------|-------------|
| `gov` | Ja | Governance-Controls sind audit-kritisch |
| `priv` | Ja | Datenschutz erfordert unabhaengige Pruefung |
| `ops`, `sdlc`, `ai`, ... | Nein | Operationale Controls mit Single-Review |
---
## Phase 2: Audit-Trail-Erweiterung
Neue Audit-Trail-Eintraege:
| Entity | Action | Wann |
|--------|--------|------|
| evidence | create | Bei Evidence-Erstellung |
| evidence | review | Bei Confidence/Truth-Status-Aenderung |
| evidence | reject | Bei Evidence-Ablehnung |
| control | status_change | Bei Control-Status-Aenderung |
Jeder Eintrag enthaelt `old_value`, `new_value` und einen SHA-256 `checksum`.
Neuer Query-Endpoint: `GET /audit-trail?entity_type=evidence&entity_id={id}`
---
## Phase 2: Neue API-Endpoints
| Methode | Pfad | Beschreibung |
|---------|------|--------------|
| PATCH | `/evidence/{id}/reject` | Evidence ablehnen |
| GET | `/audit-trail` | Audit-Trail abfragen (Filter: entity_type, entity_id, action) |
| POST | `/assertions` | Assertion manuell erstellen |
| GET | `/assertions` | Assertions auflisten (Filter: entity_type, entity_id, assertion_type) |
| GET | `/assertions/{id}` | Assertion Detail |
| PUT | `/assertions/{id}` | Assertion aktualisieren |
| POST | `/assertions/{id}/verify` | Als Fakt markieren |
| POST | `/assertions/extract` | Automatische Extraktion aus Freitext |
| GET | `/assertions/summary` | Stats (total, facts, rationale, unverified) |
### Erweiterte EvidenceResponse (Phase 2)
```json
{
"approval_status": "first_approved",
"first_reviewer": "reviewer1@example.com",
"first_reviewed_at": "2026-03-23T14:00:00Z",
"second_reviewer": null,
"second_reviewed_at": null,
"requires_four_eyes": true
}
```
---
## Phase 3: Durchsetzung (UI + Dashboard)
Phase 3 macht das Anti-Fake-Evidence-System **benutzbar und durchsetzbar** im Frontend.
### Evidence Review/Reject UI
Die Evidence-Seite bietet jetzt direkte Buttons fuer Review und Ablehnung:
- **Reviewen-Button**: Sichtbar wenn `approvalStatus` nicht `approved` oder `rejected`
- **Ablehnen-Button**: Sichtbar bei Four-Eyes-Evidence die noch nicht abgeschlossen ist
**ReviewModal** erlaubt:
- Confidence-Level aendern (E0-E4 Dropdown)
- Truth-Status aendern (Dropdown)
- Reviewer E-Mail angeben
- Four-Eyes-Warnung wenn noch ein weiterer Review noetig ist
**RejectModal** erlaubt:
- Ablehnungsgrund als Freitext
- Reviewer E-Mail angeben
Bei Four-Eyes Same-Person-Fehler (HTTP 400) wird eine Fehlermeldung angezeigt.
### Control Status-Transition Fehlerbehandlung
Die Controls-Seite zeigt jetzt detaillierte Fehler bei blockierten Status-Transitionen:
- **Optimistic Update mit Rollback**: UI aktualisiert sofort, rollt bei Fehler zurueck
- **TransitionErrorBanner**: Zeigt Violations-Liste bei HTTP 409 Conflict
- z.B. "Transition to 'pass' requires at least 1 evidence with confidence >= E2"
- **Link zur Evidence-Seite**: "Evidence hinzufuegen" direkt im Fehler-Banner
### Evidence Audit-Trail Anzeige
Neuer "Historie"-Button auf jeder Evidence-Card zeigt den vollstaendigen Audit-Trail:
- Timeline mit Zeitstempel, Aktion und Akteur
- Details zu Feldaenderungen (old_value → new_value)
- Lazy-Loading: Erst beim Aufklappen wird `GET /audit-trail` abgerufen
### Evidence Confidence-Filter
Neue Filter-Pills auf der Evidence-Seite:
```
[Alle] [Gueltig] [Abgelaufen] [Ausstehend] | [E0] [E1] [E2] [E3] [E4]
```
Farbcodierung: E0=rot, E1=gelb, E2=blau, E3=gruen, E4=emerald (passend zu den Badges)
### Evidence Confidence-Verteilung (Dashboard)
Neuer Endpoint und Dashboard-Bereich:
**Endpoint:** `GET /dashboard/evidence-distribution`
```json
{
"by_confidence": {"E0": 2, "E1": 5, "E2": 3, "E3": 8, "E4": 1},
"four_eyes_pending": 3,
"total": 19
}
```
**Compliance Hub** zeigt:
- Horizontal gestapelter Balken der Confidence-Verteilung (E0 rot → E4 emerald)
- Multi-Score Dimensionen als Fortschrittsbalken (5 Dimensionen + Audit-Readiness)
- Four-Eyes-Warteschlange (Anzahl pending)
- Hard-Blocks-Liste oder "Keine Hard Blocks" Status
### Assertions-Seite
Neue Seite unter `/sdk/assertions` mit 3 Tabs:
| Tab | Inhalt |
|-----|--------|
| **Uebersicht** | Summary-Stats (Assertions, Facts, Rationale, Unverified) |
| **Assertion-Liste** | Filterbarer Tabelle (entity_type, assertion_type) mit AssertionCards |
| **Extraktion** | Textfeld + Button → `POST /assertions/extract` |
**AssertionCard** zeigt:
- Normative-Tier als farbiger Badge (Pflicht=rot, Empfehlung=gelb, Kann=blau)
- Typ-Badge (Assertion/Fact/Rationale)
- "Als Fakt pruefen"-Button → `POST /assertions/{id}/verify`
### Phase 3: Neue API-Endpoints
| Methode | Pfad | Beschreibung |
|---------|------|--------------|
| GET | `/dashboard/evidence-distribution` | Evidence-Verteilung nach Confidence + Four-Eyes-Status |
---
## Sicherheitsarchitektur im Detail
### Warum E0-E4 und nicht einfach "valide/invalide"?
Ein binaeres System ("valide" vs. "invalide") haette ein fundamentales Problem:
Wo zieht man die Grenze? Ein manuell hochgeladenes PDF ist "besser" als ein
LLM-Entwurf, aber "schlechter" als ein automatischer SAST-Report.
Die 5-stufige Skala erlaubt:
1. **Graduelle Verbesserung**: Ein Kunde kann mit E1-Evidence starten und
schrittweise auf E3/E4 aufruesten
2. **Risiko-basierte Entscheidungen**: Ein Auditor sieht sofort, welche
Controls nur auf schwacher Evidence basieren
3. **Automatische Schwellwerte**: Das System blockiert "pass" unterhalb E2,
aber zeigt auch E1-Evidence (mit Warnung)
```mermaid
graph LR
E0["E0<br/>Generated<br/>❌ Kein Nachweis"]
E1["E1<br/>Uploaded<br/>⚠️ Ungeprüft"]
E2["E2<br/>Reviewed<br/>✓ Intern geprüft"]
E3["E3<br/>Observed<br/>✓✓ System-beobachtet"]
E4["E4<br/>Auditor<br/>✓✓✓ Extern validiert"]
E0 --> E1 --> E2 --> E3 --> E4
style E0 fill:#fee2e2,stroke:#dc2626
style E1 fill:#fef3c7,stroke:#d97706
style E2 fill:#dbeafe,stroke:#2563eb
style E3 fill:#d1fae5,stroke:#059669
style E4 fill:#d1fae5,stroke:#047857
```
### Confidence-Gewichtung im Score
| Level | Gewicht | Bedeutung |
|---|---|---|
| E0 | 0.00 | Zaehlt nicht als Evidence |
| E1 | 0.25 | Minimal — ungepruefte Uploads |
| E2 | 0.50 | Schwelle fuer "pass"-Status |
| E3 | 0.75 | Stark — system-verifiziert |
| E4 | 1.00 | Perfekt — extern validiert |
### Warum Four-Eyes nur fuer GOV und PRIV?
Das Four-Eyes-Prinzip erhoert den Aufwand erheblich (jedes Evidence braucht
zwei verschiedene Reviewer). Deshalb wird es gezielt nur fuer Domains eingesetzt,
bei denen Manipulation besonders gefaehrlich ist:
| Domain | Four-Eyes | Begruendung |
|---|---|---|
| **GOV** (Governance) | Ja | Governance-Controls definieren das Compliance-Framework selbst. Wenn hier manipuliert wird, ist alles darunter wertlos. |
| **PRIV** (Datenschutz) | Ja | DSGVO-Nachweise sind rechtlich bindend. Falsche Nachweise koennen zu Bussgeldern fuehren. |
| SEC, AUTH, NET, ... | Nein | Technische Controls sind oft automatisch pruefbar (E3). Der Aufwand von Four-Eyes waere unverhältnismäßig. |
### Same-Person-Schutz
```python
# Der zweite Reviewer MUSS eine andere Person sein:
if review.reviewed_by == evidence.first_reviewer:
raise HTTPException(
status_code=400,
detail="Four-Eyes: second reviewer must be different from first reviewer"
)
```
Dies verhindert, dass eine einzelne Person ein Evidence "durchwinkt". Der Schutz
ist auf DB-Ebene durchgesetzt — nicht nur im Frontend.
---
## Hard Blocks — Audit-Sperren
Hard Blocks sind **absolute Sperren**, die eine Audit-Readiness verhindern.
Sie werden im Dashboard prominent rot angezeigt.
### Block 1: Controls auf "pass" ohne Evidence
```sql
-- Controls die "pass" oder "partial" sind, aber keine Evidence haben
SELECT control_id FROM compliance_controls
WHERE status IN ('pass', 'partial')
AND id NOT IN (SELECT control_id FROM compliance_evidence)
```
**Warum kritisch:** Ein Control auf "pass" ohne jeden Nachweis ist die Definition
von Compliance-Theater. Der Auditor wird sofort fragen: "Wo ist der Nachweis?"
### Block 2: Controls auf "pass" mit nur E0/E1-Evidence
```sql
-- Controls auf "pass" deren beste Evidence nur E0 oder E1 ist
SELECT c.control_id FROM compliance_controls c
JOIN compliance_evidence e ON e.control_id = c.id
WHERE c.status = 'pass'
GROUP BY c.control_id
HAVING MAX(CASE
WHEN e.confidence_level = 'E4' THEN 4
WHEN e.confidence_level = 'E3' THEN 3
WHEN e.confidence_level = 'E2' THEN 2
WHEN e.confidence_level = 'E1' THEN 1
ELSE 0
END) < 2 -- Nur E0 oder E1
```
**Warum kritisch:** Ein LLM-generierter Text (E0) oder ein ungeprüeftes Upload (E1)
reicht nicht aus, um Compliance zu behaupten. Mindestens ein intern geprüeftes
Dokument (E2) ist erforderlich.
---
## Datenbank-Schema (Komplett)
### ENUM-Typen
```sql
CREATE TYPE evidence_confidence_level AS ENUM (
'E0', -- Generated / kein echter Nachweis
'E1', -- Hochgeladen, ungeprüeft
'E2', -- Intern geprüeft, Hash verifiziert
'E3', -- System-beobachtet (CI/CD, API mit Hash)
'E4' -- Extern validiert (Auditor)
);
CREATE TYPE evidence_truth_status AS ENUM (
'generated', -- LLM/System-generiert
'uploaded', -- Manuell hochgeladen
'observed', -- Automatisch beobachtet
'validated_internal', -- Intern geprüeft + bestätigt
'rejected', -- Abgelehnt
'provided_to_auditor', -- An Auditor üebergeben
'accepted_by_auditor' -- Auditor hat akzeptiert
);
```
### compliance_evidence — Erweiterte Spalten
| Spalte | Typ | Default | Beschreibung |
|---|---|---|---|
| confidence_level | ENUM | E1 | Vertrauensstufe (E0-E4) |
| truth_status | ENUM | uploaded | Wahrheitsstatus |
| generation_mode | VARCHAR(100) | NULL | 'draft_assistance', 'auto_generation' |
| may_be_used_as_evidence | BOOLEAN | TRUE | FALSE fuer LLM-Output |
| reviewed_by | VARCHAR(200) | NULL | Reviewer E-Mail |
| reviewed_at | TIMESTAMPTZ | NULL | Zeitpunkt des Reviews |
| approval_status | VARCHAR(30) | 'none' | Four-Eyes Status |
| first_reviewer | VARCHAR(200) | NULL | Erster Reviewer |
| first_reviewed_at | TIMESTAMPTZ | NULL | Zeitpunkt erster Review |
| second_reviewer | VARCHAR(200) | NULL | Zweiter Reviewer (muss anders sein!) |
| second_reviewed_at | TIMESTAMPTZ | NULL | Zeitpunkt zweiter Review |
| requires_four_eyes | BOOLEAN | FALSE | Ob Four-Eyes-Pflicht besteht |
### compliance_llm_generation_audit
Jeder LLM-generierte Inhalt wird in dieser Tabelle protokolliert:
| Spalte | Typ | Beschreibung |
|---|---|---|
| id | VARCHAR(36) | PK |
| tenant_id | VARCHAR(36) | Mandant |
| entity_type | VARCHAR(50) | 'evidence', 'control', 'document' |
| entity_id | VARCHAR(36) | FK zur generierten Entitaet |
| generation_mode | VARCHAR(100) | 'draft_assistance', 'auto_generation' |
| truth_status | ENUM | Default: 'generated' |
| may_be_used_as_evidence | BOOLEAN | Default: FALSE |
| llm_model | VARCHAR(100) | z.B. 'qwen3:30b-a3b' |
| llm_provider | VARCHAR(50) | 'ollama', 'anthropic' |
| prompt_hash | VARCHAR(64) | SHA-256 des Prompts |
| input_summary | TEXT | Zusammenfassung des Inputs |
| output_summary | TEXT | Zusammenfassung des Outputs |
### compliance_assertions
Die Assertion Engine trennt Behauptungen von Fakten:
| Spalte | Typ | Beschreibung |
|---|---|---|
| id | VARCHAR(36) | PK |
| tenant_id | VARCHAR(36) | Mandant |
| entity_type | VARCHAR(50) | 'control', 'evidence', 'document', 'obligation' |
| entity_id | VARCHAR(36) | FK zur Entitaet |
| sentence_text | TEXT | Originalsatz |
| sentence_index | INTEGER | Position im Text |
| assertion_type | VARCHAR(20) | 'assertion', 'fact', 'rationale' |
| evidence_ids | JSONB | Verlinkte Evidence-IDs |
| confidence | FLOAT | 0.0-1.0 Konfidenz |
| normative_tier | VARCHAR(20) | 'pflicht', 'empfehlung', 'kann' |
| verified_by | VARCHAR(200) | Verifizierer |
| verified_at | TIMESTAMPTZ | Zeitpunkt der Verifikation |
---
## Vollstaendige API-Referenz
### Evidence-Endpoints
| Methode | Pfad | Beschreibung | Auth |
|---|---|---|---|
| GET | `/evidence` | Evidence auflisten (mit Filtern) | Tenant |
| POST | `/evidence` | Neues Evidence erstellen | Tenant |
| DELETE | `/evidence/{id}` | Evidence loeschen | Tenant |
| POST | `/evidence/upload` | Evidence-Datei hochladen | Tenant |
| POST | `/evidence/collect` | CI/CD Evidence sammeln (automatisch) | API-Key |
| GET | `/evidence/ci-status` | CI/CD Evidence Statusuebersicht | Tenant |
| **PATCH** | **`/evidence/{id}/review`** | **Evidence reviewen (Four-Eyes)** | Tenant |
| **PATCH** | **`/evidence/{id}/reject`** | **Evidence ablehnen** | Tenant |
### Audit-Trail-Endpoints
| Methode | Pfad | Beschreibung |
|---|---|---|
| GET | `/audit-trail` | Audit-Trail abfragen (entity_type, entity_id, action) |
### Assertion-Endpoints
| Methode | Pfad | Beschreibung |
|---|---|---|
| POST | `/assertions` | Assertion manuell erstellen |
| GET | `/assertions` | Assertions auflisten |
| GET | `/assertions/{id}` | Assertion Detail |
| PUT | `/assertions/{id}` | Assertion aktualisieren |
| POST | `/assertions/{id}/verify` | Als Fakt markieren |
| POST | `/assertions/extract` | Automatische Extraktion aus Freitext |
| GET | `/assertions/summary` | Stats (total, facts, rationale, unverified) |
### LLM-Audit-Endpoints
| Methode | Pfad | Beschreibung |
|---|---|---|
| POST | `/llm-audit` | LLM-Generierungs-Audit erstellen |
| GET | `/llm-audit` | LLM-Audit-Eintraege auflisten |
### Dashboard-Endpoints
| Methode | Pfad | Beschreibung |
|---|---|---|
| GET | `/dashboard/evidence-distribution` | Confidence-Verteilung + Four-Eyes-Status |
---
## Haeufige Fragen
### Kann ich E0-Evidence loeschen?
Ja, aber es bleibt ein Eintrag in `compliance_llm_generation_audit`. Das stellt sicher,
dass die Generierung nachvollziehbar ist, auch wenn der LLM-Output geloescht wurde.
### Was passiert, wenn der erste Reviewer nicht verfuegbar ist?
Das Four-Eyes-System hat keinen Timeout. Der erste Review bleibt als `first_approved`
gespeichert, bis ein zweiter Reviewer die Evidence prueft. Das ist bewusst so —
Compliance-Nachweise sollten nicht durch Zeitdruck kompromittiert werden.
### Kann ein Admin das Four-Eyes-Prinzip umgehen?
Nein. Der Same-Person-Check ist auf Backend-Ebene implementiert (HTTP 400 bei
gleichem Reviewer). Es gibt keine Admin-Bypass-Option. Dies ist ein bewusstes
Design-Prinzip: Wenn selbst der Admin das System umgehen koennte, waere die
gesamte Integritaet gefaehrdet.
### Wie funktioniert die Assertion-Extraktion?
Der Endpoint `POST /assertions/extract` nimmt einen Freitext und:
1. **Satz-Splitting**: Teilt den Text an `.!?` gefolgt von Grossbuchstaben
2. **Klassifikation**: Prueft jeden Satz auf normative Signal-Woerter
3. **Normative Tiers**: "muss/shall/must" → pflicht, "soll/should" → empfehlung, "kann/may" → kann
4. **Evidence-Keywords**: Woerter wie "liegt vor", "wurde geprueft" → als tentative Fakten markiert
5. **Ergebnis**: Liste von Assertions mit Typ und Normative-Tier
### Was ist der Unterschied zwischen Truth-Status und Confidence?
- **Confidence** (E0-E4) sagt: Wie vertrauenswuerdig ist die **Quelle**?
(LLM < Upload < Review < CI/CD < Auditor)
- **Truth-Status** sagt: In welchem **Lifecycle-Zustand** ist der Nachweis?
(generated → uploaded → validated → accepted_by_auditor)
Ein E3-Evidence (CI/CD) kann Truth-Status "observed" haben und ist damit sofort
verwendbar. Ein E1-Evidence (Upload) muss erst "validated_internal" werden.
File diff suppressed because it is too large Load Diff
@@ -0,0 +1,652 @@
# Control Generator Pipeline
Automatische Generierung von Canonical Controls aus dem gesamten RAG-Korpus (~105.000 Chunks aus Gesetzen, Verordnungen und Standards).
**Backend:** `backend-compliance/compliance/services/control_generator.py`
**Routes:** `backend-compliance/compliance/api/control_generator_routes.py`
**API-Prefix:** `/api/compliance/v1/canonical/generate`
---
## Pipeline-Uebersicht
Die Pipeline durchlaeuft 7 Stufen, um aus RAG-Chunks eigenstaendige Security/Compliance Controls zu erzeugen:
```mermaid
flowchart TD
A[1. RAG Scan] -->|Alle Chunks laden| B[2. License Classify]
B -->|Rule 1/2| C[3a. Structure Batch]
B -->|Rule 3| D[3b. Reform Batch]
C --> E[4. Harmonize]
D --> E
E -->|Duplikat| F[Als Duplikat markieren]
E -->|Neu| G[5. Anchor Search]
G --> H[6. Store Control]
H --> I[7. Mark Processed]
```
| Stufe | Name | Beschreibung |
|-------|------|-------------|
| 1 | **RAG Scan** | Laedt unverarbeitete Chunks aus Qdrant (Scroll-API), filtert per SHA-256-Hash |
| 2 | **License Classify** | Bestimmt die Lizenzregel (Rule 1/2/3) anhand `regulation_code` |
| 3a | **Structure (Batch)** | Rule 1+2: Strukturiert Originaltext als Control (Anthropic API) |
| 3b | **Reform (Batch)** | Rule 3: Vollstaendige Reformulierung ohne Originaltext (Anthropic API) |
| 4 | **Harmonize** | Embedding-basierte Duplikaterkennung (bge-m3, Cosine > 0.85) |
| 5 | **Anchor Search** | Findet Open-Source-Referenzen (OWASP, NIST, ENISA) |
| 6 | **Store** | Persistiert Control in `canonical_controls` mit Metadaten |
| 7 | **Mark Processed** | Markiert jeden Chunk als verarbeitet (auch bei Skip/Error/Duplikat) |
---
## Pipeline-Versionen
Die Pipeline hat zwei Versionen. Die Version wird als `pipeline_version` auf `canonical_controls` und `canonical_processed_chunks` gespeichert.
### v1 (Original)
| Eigenschaft | Wert |
|-------------|------|
| **Vorfilter** | Lokales LLM (llama3.2 3B) entscheidet ob Chunk relevant |
| **Anthropic-Prompt** | Alter Prompt ohne null-Skip |
| **Annexe/Anhaenge** | Kein Schutz — wurden haeufig faelschlich als irrelevant uebersprungen |
| **`pipeline_version`** | `1` |
### v2 (Aktuell)
| Eigenschaft | Wert |
|-------------|------|
| **Vorfilter** | Optional (`skip_prefilter`). Wenn aktiviert, entscheidet Anthropic API selbst |
| **Anthropic-Prompt** | Neuer Prompt mit **null-Skip**: API gibt `null` fuer Chunks ohne Anforderung zurueck |
| **Annexe/Anhaenge** | Explizit geschuetzt — Prompt-Anweisung: "Anhaenge/Annexe enthalten oft KONKRETE technische Anforderungen — diese MUESSEN als Control erfasst werden!" |
| **`pipeline_version`** | `2` |
#### Wesentliche Aenderungen v1 → v2
1. **Relevanz-Entscheidung an Anthropic delegiert** — Das lokale LLM (Vorfilter) ist optional. Die Anthropic API entscheidet selbst, welche Chunks Controls enthalten, indem sie `null` fuer irrelevante Chunks zurueckgibt.
2. **null-Skip im JSON-Array** — Das Ergebnis-Array enthaelt `null`-Eintraege fuer Chunks ohne umsetzbare Anforderung. Kein separater Vorfilter-Schritt noetig.
3. **Annexe/Anhaenge geschuetzt** — Explizite Prompt-Anweisung verhindert, dass technische Anforderungen in Anhaengen uebersprungen werden.
#### Datenbank-Feld
```sql
-- Migration 062
ALTER TABLE canonical_controls
ADD COLUMN pipeline_version smallint NOT NULL DEFAULT 1;
ALTER TABLE canonical_processed_chunks
ADD COLUMN pipeline_version smallint NOT NULL DEFAULT 1;
```
Neue Controls erhalten automatisch `pipeline_version = 2`. Bestehende (v1) behalten `1`, damit sie spaeter identifiziert und ggf. reprocessiert werden koennen.
---
## Konfiguration
### Request-Parameter (`GenerateRequest`)
| Parameter | Typ | Default | Beschreibung |
|-----------|-----|---------|-------------|
| `collections` | `List[str]` | Alle 5 Collections | Qdrant-Collections zum Durchsuchen |
| `domain` | `str` | — | Filter auf eine Domain (z.B. `AUTH`, `NET`) |
| `regulation_filter` | `List[str]` | — | Prefix-Matching auf `regulation_code` (z.B. `["eu_2023_1230", "owasp_"]`) |
| `skip_prefilter` | `bool` | `false` | Ueberspringt lokalen LLM-Vorfilter, sendet alle Chunks an die Anthropic API |
| `batch_size` | `int` | `5` | Chunks pro Anthropic-API-Call |
| `max_controls` | `int` | `50` | Maximale Anzahl Controls pro Job (0 = unbegrenzt) |
| `max_chunks` | `int` | `1000` | Maximale Chunks pro Job (0 = unbegrenzt, respektiert Dokumentgrenzen) |
| `skip_web_search` | `bool` | `false` | Ueberspringt Web-Suche in der Anchor-Findung (Stufe 5) |
| `dry_run` | `bool` | `false` | Trockenlauf ohne DB-Schreibzugriffe (synchron, mit Controls im Response) |
!!! info "`regulation_filter` — Prefix-Matching"
Der Filter vergleicht den `regulation_code` jedes Chunks per Prefix.
Beispiel: `["eu_2023_1230"]` erfasst nur Chunks aus der Maschinenverordnung.
`["owasp_"]` erfasst alle OWASP-Dokumente (OWASP ASVS, OWASP SAMM, etc.).
Gross-/Kleinschreibung wird ignoriert.
### Umgebungsvariablen
| Variable | Default | Beschreibung |
|----------|---------|-------------|
| `ANTHROPIC_API_KEY` | — | API-Key fuer Anthropic Claude (Pflicht) |
| `CONTROL_GEN_ANTHROPIC_MODEL` | `claude-sonnet-4-6` | Anthropic-Modell fuer Strukturierung/Reformulierung |
| `OLLAMA_URL` | `http://host.docker.internal:11434` | Lokaler Ollama-Server (Vorfilter + QA) |
| `CONTROL_GEN_OLLAMA_MODEL` | `qwen3.5:35b-a3b` | Lokales LLM-Modell fuer Vorfilter und QA-Arbitrierung |
| `CONTROL_GEN_LLM_TIMEOUT` | `180` | Timeout in Sekunden pro Anthropic-API-Call |
### Pipeline-interne Konstanten
| Konstante | Wert | Beschreibung |
|-----------|------|-------------|
| `PIPELINE_VERSION` | `2` | Aktuelle Pipeline-Version |
| `HARMONIZATION_THRESHOLD` | `0.85` | Cosine-Similarity-Schwelle fuer Duplikaterkennung |
| `max_tokens` | `8192` | Maximale Token-Laenge der LLM-Antwort |
---
## API Endpoints
Alle Endpoints unter `/api/compliance/v1/canonical/`.
### Uebersicht
| Methode | Pfad | Beschreibung |
|---------|------|-------------|
| `POST` | `/generate` | Generierungs-Job starten (laeuft im Hintergrund) |
| `GET` | `/generate/status/{job_id}` | Status eines laufenden Jobs abfragen |
| `GET` | `/generate/jobs` | Alle Jobs auflisten (paginiert) |
| `GET` | `/generate/processed-stats` | Verarbeitungsstatistik pro Collection |
| `GET` | `/generate/review-queue` | Controls zur manuellen Pruefung |
| `POST` | `/generate/review/{control_id}` | Review eines einzelnen Controls abschliessen |
| `POST` | `/generate/bulk-review` | Bulk-Review nach `release_state` |
| `POST` | `/generate/qa-reclassify` | QA-Reklassifizierung bestehender Controls |
| `GET` | `/blocked-sources` | Gesperrte Quellen (Rule 3) auflisten |
| `POST` | `/blocked-sources/cleanup` | Cleanup-Workflow fuer gesperrte Quellen starten |
---
### POST `/v1/canonical/generate` — Job starten
Startet einen Generierungs-Job im Hintergrund. Gibt sofort eine `job_id` zurueck.
**Request:**
```json
{
"collections": ["bp_compliance_gesetze"],
"regulation_filter": ["eu_2023_1230"],
"skip_prefilter": false,
"batch_size": 5,
"max_chunks": 500,
"max_controls": 0,
"skip_web_search": false,
"dry_run": false
}
```
**Response (200):**
```json
{
"job_id": "a1b2c3d4-...",
"status": "running",
"message": "Generation started in background. Poll /generate/status/{job_id} for progress."
}
```
**Beispiel:**
```bash
# Alle Chunks der Maschinenverordnung verarbeiten
curl -X POST https://api-dev.breakpilot.ai/api/compliance/v1/canonical/generate \
-H 'Content-Type: application/json' \
-H 'X-Tenant-ID: 550e8400-e29b-41d4-a716-446655440000' \
-d '{
"collections": ["bp_compliance_ce"],
"regulation_filter": ["eu_2023_1230"],
"max_chunks": 200,
"batch_size": 5
}'
```
```bash
# Dry Run: Keine DB-Aenderungen, Controls im Response
curl -X POST https://api-dev.breakpilot.ai/api/compliance/v1/canonical/generate \
-H 'Content-Type: application/json' \
-H 'X-Tenant-ID: 550e8400-e29b-41d4-a716-446655440000' \
-d '{
"collections": ["bp_compliance_gesetze"],
"max_chunks": 10,
"dry_run": true
}'
```
```bash
# Ohne Vorfilter: Alle Chunks direkt an Anthropic API
curl -X POST https://api-dev.breakpilot.ai/api/compliance/v1/canonical/generate \
-H 'Content-Type: application/json' \
-H 'X-Tenant-ID: 550e8400-e29b-41d4-a716-446655440000' \
-d '{
"collections": ["bp_compliance_gesetze"],
"regulation_filter": ["bdsg"],
"skip_prefilter": true,
"max_chunks": 100
}'
```
!!! warning "Kosten beachten"
Ohne `regulation_filter` und mit `max_chunks: 0` werden **alle** ~105.000 Chunks verarbeitet.
Das verursacht erhebliche Anthropic-API-Kosten (~$700).
---
### GET `/v1/canonical/generate/status/{job_id}` — Job-Status
Gibt den vollstaendigen Status eines Jobs zurueck inkl. Metriken und Fehler.
**Beispiel:**
```bash
curl https://api-dev.breakpilot.ai/api/compliance/v1/canonical/generate/status/a1b2c3d4-... \
-H 'X-Tenant-ID: 550e8400-e29b-41d4-a716-446655440000'
```
**Response:**
```json
{
"id": "a1b2c3d4-...",
"status": "completed",
"total_chunks_scanned": 500,
"controls_generated": 48,
"controls_verified": 45,
"controls_needs_review": 3,
"controls_too_close": 0,
"controls_duplicates_found": 12,
"controls_qa_fixed": 5,
"config": { "..." },
"started_at": "2026-03-17T10:00:00+00:00",
"completed_at": "2026-03-17T10:15:32+00:00"
}
```
---
### GET `/v1/canonical/generate/jobs` — Alle Jobs
Paginierte Liste aller Generierungs-Jobs.
**Query-Parameter:**
| Parameter | Default | Beschreibung |
|-----------|---------|-------------|
| `limit` | `20` | Anzahl Jobs (1-100) |
| `offset` | `0` | Offset fuer Paginierung |
**Beispiel:**
```bash
curl "https://api-dev.breakpilot.ai/api/compliance/v1/canonical/generate/jobs?limit=5" \
-H 'X-Tenant-ID: 550e8400-e29b-41d4-a716-446655440000'
```
---
### GET `/v1/canonical/generate/review-queue` — Review-Queue
Listet Controls auf, die eine manuelle Pruefung benoetigen.
**Query-Parameter:**
| Parameter | Default | Beschreibung |
|-----------|---------|-------------|
| `release_state` | `needs_review` | Filter: `needs_review`, `too_close`, `duplicate` |
| `limit` | `50` | Anzahl (1-200) |
**Beispiel:**
```bash
curl "https://api-dev.breakpilot.ai/api/compliance/v1/canonical/generate/review-queue?release_state=needs_review&limit=10" \
-H 'X-Tenant-ID: 550e8400-e29b-41d4-a716-446655440000'
```
---
### POST `/v1/canonical/generate/review/{control_id}` — Review abschliessen
Schliesst die manuelle Pruefung eines Controls ab.
**Request:**
```json
{
"action": "approve",
"release_state": "draft",
"notes": "Inhaltlich korrekt, Severity passt."
}
```
**Moegliche `action`-Werte:**
| Action | Neuer State | Beschreibung |
|--------|-------------|-------------|
| `approve` | `draft` (oder per `release_state` ueberschreiben) | Control freigeben |
| `reject` | `deprecated` | Control verwerfen |
| `needs_rework` | `needs_review` | Zurueck in die Queue |
**Beispiel:**
```bash
curl -X POST https://api-dev.breakpilot.ai/api/compliance/v1/canonical/generate/review/AUTH-042 \
-H 'Content-Type: application/json' \
-H 'X-Tenant-ID: 550e8400-e29b-41d4-a716-446655440000' \
-d '{"action": "approve", "release_state": "draft"}'
```
---
### POST `/v1/canonical/generate/bulk-review` — Bulk-Review
Aendert den `release_state` aller Controls, die einen bestimmten State haben.
**Request:**
```json
{
"release_state": "needs_review",
"action": "approve",
"new_state": "draft"
}
```
**Beispiel:**
```bash
# Alle needs_review Controls auf draft setzen
curl -X POST https://api-dev.breakpilot.ai/api/compliance/v1/canonical/generate/bulk-review \
-H 'Content-Type: application/json' \
-H 'X-Tenant-ID: 550e8400-e29b-41d4-a716-446655440000' \
-d '{"release_state": "needs_review", "action": "approve", "new_state": "draft"}'
```
---
### GET `/v1/canonical/generate/processed-stats` — Verarbeitungsstatistik
Liefert Statistiken pro RAG-Collection.
**Beispiel:**
```bash
curl https://api-dev.breakpilot.ai/api/compliance/v1/canonical/generate/processed-stats \
-H 'X-Tenant-ID: 550e8400-e29b-41d4-a716-446655440000'
```
**Response:**
```json
{
"stats": [
{
"collection": "bp_compliance_gesetze",
"processed_chunks": 45200,
"direct_adopted": 1850,
"llm_reformed": 120,
"skipped": 43230,
"total_chunks_estimated": 0,
"pending_chunks": 0
}
]
}
```
---
## Kosten und Performance
### Kostenabschaetzung
| Metrik | Wert |
|--------|------|
| **Kosten pro Chunk** | ~$0.0067 (Anthropic API, Batch-Modus) |
| **Yield (Controls/Chunks)** | ~4.5-10% (nur Chunks mit konkreten Anforderungen erzeugen Controls) |
| **Vorfilter-Ersparnis** | ~55% der API-Kosten wenn aktiviert (irrelevante Chunks werden lokal aussortiert) |
### Performance-Kennzahlen
| Metrik | Wert |
|--------|------|
| **Batch-Groesse** | 5 Chunks pro API-Call (Default) |
| **API-Aufrufe Reduktion** | ~80% weniger Aufrufe durch Batching |
| **LLM-Timeout** | 180 Sekunden pro Call |
| **QA-Overhead** | ~2s pro Control (nur bei Disagreement, ~10-15% der Controls) |
### RAG Collections
| Collection | Inhalte | Erwartete Regel |
|-----------|---------|----------------|
| `bp_compliance_gesetze` | Deutsche Gesetze (BDSG, TTDSG, TKG etc.) | Rule 1 |
| `bp_compliance_datenschutz` | Datenschutz-Leitlinien + EU-Verordnungen | Rule 1/2 |
| `bp_compliance_ce` | CE/Sicherheitsstandards | Rule 1/2/3 |
| `bp_dsfa_corpus` | DSFA-Korpus | Rule 1/2 |
| `bp_legal_templates` | Rechtsvorlagen | Rule 1 |
### Aktuelle Groessenordnung
| Metrik | Wert |
|--------|------|
| RAG-Chunks gesamt | ~105.000 (nach Dedup 2026-03-16) |
| Verarbeitete Chunks | ~105.000 |
| Generierte Controls | **~4.738** |
| Konversionsrate | ~4,5% |
---
## Lizenz-Klassifikation (3-Regel-System)
Jeder Chunk wird basierend auf `regulation_code` einer Lizenzregel zugeordnet:
| Regel | Typ | Original erlaubt? | Beispiele |
|-------|-----|-------------------|----------|
| **Rule 1** (free_use) | EU-Gesetze, NIST, DE-Gesetze, Public Domain | Ja | DSGVO, BDSG, NIS2, AI Act |
| **Rule 2** (citation_required) | CC-BY, CC-BY-SA | Ja, mit Zitation | OWASP ASVS, OWASP SAMM |
| **Rule 3** (restricted) | Proprietaer | Nein, volle Reformulierung | BSI TR-03161, ISO 27001 |
### Verarbeitung nach Regel
- **Rule 1+2 → `_structure_batch()`**: Anthropic strukturiert den Originaltext als Control. Ein API-Call fuer den gesamten Batch.
- **Rule 3 → `_reformulate_batch()`**: Anthropic reformuliert vollstaendig — kein Originaltext, keine Quellennamen. Ein API-Call fuer den gesamten Batch.
### Batch Processing
Die Pipeline sammelt Chunks in Batches (Default: 5 Chunks) und sendet sie in einem einzigen Anthropic-API-Call.
1. Relevante Chunks werden mit Lizenz-Info in `pending_batch` gesammelt
2. Bei `batch_size` erreicht → `_flush_batch()`
3. Batch wird nach Lizenzregel getrennt: Rule 1+2 → `_structure_batch()`, Rule 3 → `_reformulate_batch()`
4. Ergebnis: JSON-Array mit genau N Elementen (`null` fuer irrelevante Chunks)
**Fallback:** Bei Batch-Fehler (Timeout, Parsing-Error) wird automatisch auf Einzelverarbeitung zurueckgefallen.
---
## Chunk-Tracking (Processed Chunks)
### Tabelle `canonical_processed_chunks`
| Spalte | Typ | Beschreibung |
|--------|-----|-------------|
| `chunk_hash` | VARCHAR(64) | SHA-256 Hash des Chunk-Textes |
| `collection` | VARCHAR(100) | Qdrant-Collection |
| `regulation_code` | VARCHAR(100) | Quell-Regulation (z.B. `bdsg`, `eu_2016_679`) |
| `license_rule` | INTEGER | 1, 2 oder 3 |
| `processing_path` | VARCHAR(20) | Wie der Chunk verarbeitet wurde |
| `generated_control_ids` | JSONB | UUIDs der generierten Controls |
| `pipeline_version` | SMALLINT | Pipeline-Version (1 oder 2) |
| `job_id` | UUID | Referenz auf den Generierungs-Job |
**UNIQUE Constraint:** `(chunk_hash, collection, document_version)` — verhindert Doppelverarbeitung.
### Processing Paths
| Wert | Stufe | Bedeutung |
|------|-------|-----------|
| `prefilter_skip` | 2 | Lokaler LLM-Vorfilter: Chunk nicht relevant |
| `structured` | 3a | Einzelner Chunk strukturiert (Rule 1/2) |
| `structured_batch` | 3a | Batch-Strukturierung (Rule 1/2) |
| `llm_reform` | 3b | Einzelner Chunk reformuliert (Rule 3) |
| `llm_reform_batch` | 3b | Batch-Reformulierung (Rule 3) |
| `no_control` | 3 | LLM konnte kein Control ableiten (null im Array) |
| `store_failed` | 6 | DB-Speichern fehlgeschlagen |
| `error` | — | Unerwarteter Fehler |
---
## QA Validation (Automatische Qualitaetspruefung)
Die QA-Stufe validiert die Klassifizierung jedes generierten Controls:
1. **LLM-Category:** Anthropic liefert `category` und `domain` im JSON-Response
2. **Keyword-Detection:** `_detect_category(chunk.text)` liefert eine zweite Meinung
3. **Stimmen beide ueberein?** → Schneller Pfad (kein QA noetig)
4. **Bei Disagreement:** Lokales LLM (Ollama) arbitriert
5. **Auto-Fix:** Category/Domain werden automatisch korrigiert
Die QA-Metriken werden in `generation_metadata` gespeichert:
```json
{
"qa_category_fix": {"from": "authentication", "to": "finance", "reason": "IFRS-Thema"},
"qa_domain_fix": {"from": "AUTH", "to": "FIN", "reason": "Finanzregulierung"}
}
```
### Recital-Erkennung (Erwägungsgrund-Detektion)
Die QA-Stufe prueft zusaetzlich, ob der `source_original_text` eines Controls tatsaechlich aus einem Gesetzesartikel stammt — oder aus einem Erwaegungsgrund (Recital). Erwaegungsgruende enthalten keine normativen Pflichten und fuehren zu falsch zugeordneten Controls.
**Erkennungsmethoden:**
| Methode | Pattern | Beispiel |
|---------|---------|----------|
| **Regex** | `\((\d{1,3})\)\s*\n` — Erwaegungsgrund-Nummern | `(126)\nUm den Verwaltungsaufwand...` |
| **Phrasen** | Typische Recital-Formulierungen (≥2 Treffer) | "daher sollte", "in Erwägung nachstehender Gründe" |
**Ergebnis bei Verdacht:**
- `release_state` wird auf `needs_review` gesetzt
- `generation_metadata.recital_suspect = true`
- `generation_metadata.recital_detection` enthaelt Details:
```json
{
"recital_suspect": true,
"recital_detection": {
"recital_suspect": true,
"recital_numbers": ["126", "127"],
"recital_phrases": ["daher sollte"],
"detection_method": "regex+phrases"
}
}
```
**Funktion:** `_detect_recital(text)` in `control_generator.py`
**Hintergrund:** Bei der Analyse von ~5.500 Controls mit Quelltext wurden 1.555 (28%) als Erwaegungsgrund-Verdacht identifiziert. Der Document Crawler unterschied nicht zwischen Artikeltext und Erwaegungsgruenden, was zu falschen `article`/`paragraph`-Zuordnungen fuehrte.
### QA-Reklassifizierung bestehender Controls
```bash
# Dry Run: Welche AUTH-Controls sind falsch klassifiziert?
curl -X POST https://api-dev.breakpilot.ai/api/compliance/v1/canonical/generate/qa-reclassify \
-H 'Content-Type: application/json' \
-H 'X-Tenant-ID: 550e8400-e29b-41d4-a716-446655440000' \
-d '{"limit": 50, "dry_run": true, "filter_domain_prefix": "AUTH"}'
# Korrekturen anwenden:
curl -X POST https://api-dev.breakpilot.ai/api/compliance/v1/canonical/generate/qa-reclassify \
-H 'Content-Type: application/json' \
-H 'X-Tenant-ID: 550e8400-e29b-41d4-a716-446655440000' \
-d '{"limit": 50, "dry_run": false, "filter_domain_prefix": "AUTH"}'
```
---
## Quelldateien
| Datei | Beschreibung |
|-------|-------------|
| `backend-compliance/compliance/services/control_generator.py` | 7-Stufen-Pipeline mit Batch Processing |
| `backend-compliance/compliance/api/control_generator_routes.py` | REST API Endpoints |
| `backend-compliance/compliance/services/license_gate.py` | Lizenz-Gate-Logik |
| `backend-compliance/compliance/services/similarity_detector.py` | Too-Close-Detektor (5 Metriken) |
| `backend-compliance/compliance/services/rag_client.py` | RAG-Client (Qdrant Search + Scroll) |
| `backend-compliance/migrations/046_control_generator.sql` | Job-Tracking, Chunk-Tracking Tabellen |
| `backend-compliance/migrations/048_processing_path_expand.sql` | Erweiterte Processing-Path-Werte |
| `backend-compliance/migrations/062_pipeline_version.sql` | `pipeline_version` Spalte |
| `backend-compliance/tests/test_control_generator.py` | 98+ Tests (Lizenz, Domain, Batch, Pipeline, Recital, Source-Type) |
---
## Pass 0a/0b: Atomare Control-Zerlegung
Die Pipeline v3 erweitert die 7-Stufen-Pipeline um einen Vor-Pass, der Rich Controls in atomare Controls zerlegt.
### Pass 0a: Obligation Extraction
Extrahiert individuelle normative Pflichten aus Rich Controls via LLM.
```mermaid
flowchart LR
A[Rich Control] -->|LLM| B[Obligations]
B --> C{Quality Gate}
C -->|Pass| D[validated]
C -->|Fail| E[rejected]
```
**3-Tier Klassifikation:**
| Typ | Erkennungsmuster | Beispiel |
|-----|-----------------|---------|
| **Pflicht** | muss, ist verpflichtet, hat sicherzustellen | "Der Verantwortliche MUSS ein Verzeichnis fuehren" |
| **Empfehlung** | soll, sollte, wird empfohlen | "Es SOLLTE eine Risikobewertung durchgefuehrt werden" |
| **Kann** | kann, darf, ist berechtigt | "Die Aufsichtsbehoerde KANN Geldbussen verhaengen" |
**Quality Gate (6 Regeln):**
1. Nur normative Aussagen (muss, sicherzustellen, verpflichtet)
2. Ein Hauptverb pro Obligation
3. Test-Obligations separat von operativen
4. Reporting-Obligations separat
5. Nicht auf Evidence-Ebene splitten
6. Parent-Link immer erhalten
### Pass 0b: Atomic Control Composition
Verwandelt jede validierte Obligation in ein eigenstaendiges atomares Control.
```mermaid
flowchart LR
A[Obligation] -->|LLM| B[Atomic Control]
B -->|Dedup Check| C{4-Stage Dedup}
C -->|NEW| D[Insert + Index]
C -->|LINK| E[Parent-Link]
C -->|REVIEW| F[Review-Queue]
```
**Konfiguration:**
| Variable | Default | Beschreibung |
|----------|---------|-------------|
| `DECOMPOSITION_LLM_MODEL` | `claude-sonnet-4-6` | LLM fuer Pass 0a/0b |
| `DECOMPOSITION_BATCH_SIZE` | `5` | Obligations pro LLM-Call |
| `DECOMPOSITION_LLM_TIMEOUT` | `120` | Timeout in Sekunden |
**Ergebnisse (Stand 2026-03-21):**
| Metrik | Wert |
|--------|------|
| Rich Controls (technisch) | ~6.800 |
| Atomare Controls (bisher) | 30 (PoC: 10x CRYP, AUTH, SEC) |
| Ziel nach Full Run | ~18.000 unique Master Controls |
| Obligations pro Rich Control | ~10 |
| Dedup-Reduktion erwartet | ~70% |
### Quelldateien (Pass 0a/0b)
| Datei | Beschreibung |
|-------|-------------|
| `compliance/services/decomposition_pass.py` | Pass 0a + 0b Logik |
| `compliance/services/control_dedup.py` | 4-Stufen Dedup-Engine |
| `migrations/061_obligation_candidates.sql` | Obligation-Tabelle |
| `migrations/074_control_dedup.sql` | Dedup-Tabellen (Parent-Links, Review-Queue) |
| `tests/test_decomposition_pass.py` | 90 Tests |
| `tests/test_control_dedup.py` | 56 Tests |
---
## Verwandte Dokumentation
- [Canonical Control Library (CP-CLIB)](canonical-control-library.md) — Domains, Datenmodell, Too-Close-Detektor, CI/CD Validation
- [Deduplizierungs-Engine](dedup-engine.md) — 4-Stufen Dedup, Multi-Parent-Linking, Review-Queue
- [RAG Pipeline Benchmark](../../development/rag-pipeline-benchmark.md) — State-of-the-Art Vergleich, Optimierungsempfehlungen
- [Multi-Layer Control Architecture](canonical-control-library.md#multi-layer-control-architecture) — 10-Stage Pipeline-Erweiterung mit Obligations, Patterns, Crosswalk
@@ -0,0 +1,463 @@
# Control Provenance Wiki
Dokumentation der rechtlichen und methodischen Grundlage fuer die Control-Erstellung.
**Frontend:** `https://macmini:3007/sdk/control-provenance`
**Production:** `https://admin-dev.breakpilot.ai/sdk/control-provenance`
---
## Methodik der Control-Erstellung
Alle Controls in der Canonical Control Library wurden **eigenstaendig formuliert** und folgen einer
**unabhaengigen Taxonomie**. Es werden keine proprietaeren Bezeichner, Nummern oder Strukturen
aus geschuetzten Quellen uebernommen.
### Dreistufiger Prozess
1. **Offene Recherche** — Identifikation von Security-Anforderungen aus oeffentlichen, frei zugaenglichen
Frameworks (OWASP, NIST, ENISA). Jede Anforderung wird aus mindestens 2 unabhaengigen offenen Quellen belegt.
2. **Eigenstaendige Formulierung** — Jedes Control wird mit eigener Sprache, eigener Struktur und eigener
Taxonomie (z.B. AUTH-001, NET-001) verfasst. Kein Copy-Paste, keine Paraphrase geschuetzter Texte.
3. **Too-Close-Pruefung** — Automatisierte Aehnlichkeitspruefung gegen Quelltexte mit 5 Metriken
(Token Overlap, N-Gram Jaccard, Embedding Cosine, LCS Ratio, Exact-Phrase). Nur Controls mit
Status PASS oder WARN (+ Human Review) werden freigegeben.
### Rechtliche Grundlage
| Gesetz | Bezug |
|--------|-------|
| **UrhG §44b** | Text & Data Mining erlaubt fuer Analyse; Kopien werden danach geloescht |
| **UrhG §23** | Hinreichender Abstand zum Originalwerk durch eigene Formulierung |
| **BSI Nutzungsbedingungen** | Kommerzielle Nutzung nur mit Zustimmung; BSI-Dokumente nur als Analysegrundlage |
---
## Filter in der Control Library
Die Control Library bietet **7 Filter-Dropdowns**, um die ueber 3.000 Controls effizient zu durchsuchen:
### Schweregrad (Severity)
| Stufe | Farbe | Bedeutung |
|-------|-------|-----------|
| **Kritisch** | Rot | Sicherheitskritische Controls — Verstoesse fuehren zu schwerwiegenden Risiken |
| **Hoch** | Orange | Wichtige Controls — sollten zeitnah umgesetzt werden |
| **Mittel** | Gelb | Standardmaessige Controls — empfohlene Umsetzung |
| **Niedrig** | Gruen | Nice-to-have Controls — zusaetzliche Haertung |
### Domain
Das Praefix der Control-ID (z.B. `AUTH-001`, `SEC-042`). Kennzeichnet den thematischen Bereich.
| Domain | Anzahl | Thema |
|--------|--------|-------|
| SEC | ~700 | Allgemeine Sicherheit, Systemhaertung |
| COMP | ~470 | Compliance, Regulierung, Nachweispflichten |
| DATA | ~400 | Datenschutz, Datenklassifizierung, DSGVO |
| AI | ~290 | KI-Regulierung (AI Act, Transparenz, Erklaerbarkeit) |
| LOG | ~230 | Logging, Monitoring, SIEM |
| AUTH | ~200 | Authentifizierung, Zugriffskontrolle |
| NET | ~150 | Netzwerksicherheit, Transport, Firewall |
| CRYP | ~90 | Kryptographie, Schluesselmanagement |
| ACC | ~25 | Zugriffskontrolle (Access Control) |
| INC | ~25 | Incident Response, Vorfallmanagement |
Zusaetzlich existieren spezialisierte Domains wie CRA, ARC, API, PKI, SUP, VUL, BCP, PHY u.v.m.
### Status (Release State)
| Status | Bedeutung |
|--------|-----------|
| **Draft** | Entwurf — noch nicht freigegeben |
| **Approved** | Freigegeben fuer Kunden |
| **Review noetig** | Muss manuell geprueft werden (Pipeline-erzeugt) |
| **Zu aehnlich** | Too-Close-Check hat Warnung ausgeloest |
| **Duplikat** | Wurde als Duplikat eines anderen Controls erkannt |
| **Deprecated** | Veraltet/geloescht |
### Nachweis (Verification Method)
| Methode | Farbe | Beschreibung |
|---------|-------|-------------|
| **Code Review** | Blau | Nachweis durch Quellcode-Inspektion |
| **Dokument** | Amber | Nachweis durch Richtlinien, Prozesse, Schulungen |
| **Tool** | Teal | Nachweis durch automatisierte Scans/Monitoring |
| **Hybrid** | Lila | Kombination aus mehreren Methoden |
### Kategorie
Thematische Einordnung (23 Kategorien). Kategorien sind **thematisch**, Domains **strukturell**.
Ein AUTH-Control kann z.B. die Kategorie "Netzwerksicherheit" haben.
### Zielgruppe (Target Audience)
| Zielgruppe | Bedeutung |
|------------|-----------|
| **Unternehmen** | Fuer Endkunden/Firmen relevant |
| **Behoerden** | Spezifisch fuer oeffentliche Verwaltung |
| **Anbieter** | Fuer SaaS/Plattform-Anbieter |
| **Alle** | Allgemein anwendbar |
| **Entwickler** | Software-Entwickler |
| **DSB** | Datenschutzbeauftragte |
| **GF** | Geschaeftsfuehrung |
| **IT** | IT-Abteilung |
| **Recht** | Rechtsabteilung |
| **Compliance** | Compliance-Officer |
| **Personal** | Personalwesen |
| **Einkauf** | Beschaffung |
| **Produktion** | Fertigung |
| **Vertrieb** | Sales |
| **Gesundheit** | Gesundheitswesen |
| **Finanzen** | Finanzwesen |
| **Oeffentl. Dienst** | Oeffentlicher Dienst |
### Dokumentenursprung (Source)
Filtert nach der Quelldokument-Herkunft des Controls. Die wichtigsten Quellen:
| Quelle | Typ |
|--------|-----|
| KI-Verordnung (EU) 2024/1689 | EU-Recht |
| Cyber Resilience Act (EU) 2024/2847 | EU-Recht |
| DSGVO (EU) 2016/679 | EU-Recht |
| NIS2-Richtlinie (EU) 2022/2555 | EU-Recht |
| NIST SP 800-53, CSF 2.0, SSDF | US-Standards |
| OWASP Top 10, ASVS, SAMM | Open Source |
| ENISA Guidelines | EU-Agentur |
| CISA Secure by Design | US-Behoerde |
| BDSG, TKG, GewO, HGB | Deutsche Gesetze |
| EDPB Leitlinien | EU Datenschutz |
---
## Badges & Lizenzregeln
### Lizenzregel-Badge (Rule 1 / 2 / 3)
Die Lizenzregel bestimmt, wie ein Control erstellt und genutzt werden darf:
| Badge | Farbe | Regel | Bedeutung |
|-------|-------|-------|-----------|
| **Free Use** | Gruen | Rule 1 | Quelle ist Public Domain oder EU-Recht — Originaltext darf gezeigt werden |
| **Zitation** | Blau | Rule 2 | Quelle ist CC-BY oder aehnlich — Zitation + Quellenangabe erforderlich |
| **Reformuliert** | Amber | Rule 3 | Quelle hat eingeschraenkte Lizenz — eigenstaendig reformuliert, kein Originaltext |
### Processing Path
| Pfad | Bedeutung |
|------|-----------|
| `structured` / `structured_batch` | Control direkt aus dem Quelltext strukturiert (Rule 1/2) |
| `llm_reform` / `llm_reform_batch` | Control vollstaendig reformuliert (Rule 3) |
| `no_control` | LLM konnte kein Control ableiten (null im Array) |
### Generation Strategy Badge
| Badge | Farbe | Bedeutung |
|-------|-------|-----------|
| **v1** | Grau | Original-Pipeline (ungrouped) |
| **v2** | Emerald | Document-grouped Pipeline |
### Weitere Badges
| Badge | Bedeutung |
|-------|-----------|
| Score | Risiko-Score (0-10) |
| Severity-Badge | Schweregrad (Kritisch/Hoch/Mittel/Niedrig) |
| State-Badge | Freigabestatus (Draft/Approved/etc.) |
| Kategorie-Badge | Thematische Kategorie |
| Zielgruppe-Badge | Enterprise/Behoerden/Anbieter/Alle/etc. |
---
## Unabhaengige Taxonomie
### Eigenes Klassifikationssystem
Die Canonical Control Library verwendet ein **eigenes Domain-Schema**, das sich bewusst von
proprietaeren Frameworks unterscheidet. Die Domains werden **automatisch** durch den
Control Generator vergeben, basierend auf dem Inhalt der Quelldokumente.
### 16 Standard-Domains
| Domain | Name | Beschreibung |
|--------|------|-------------|
| AUTH | Identity & Access Management | Authentisierung, MFA, Token-Management |
| CRYP | Cryptographic Operations | Key Management, Rotation, HSM |
| NET | Network & Transport Security | TLS, Zertifikate, Netzwerk-Haertung |
| DATA | Data Governance & Classification | Datenklassifikation, Schutzmassnahmen |
| LOG | Security Operations & Logging | Privacy-Aware Logging, SIEM |
| ACC | Access Control | Zugriffskontrolle, Berechtigungen |
| SEC | IT Security | Schwachstellen, Haertung, Konfiguration |
| INC | Incident Management | Vorfallmanagement, Wiederherstellung |
| AI | Artificial Intelligence | KI-Compliance, Bias, Transparenz |
| COMP | Compliance | Konformitaet, Audit, Zertifizierung |
| GOV | Government & Public Administration | Behoerden, Verwaltung, Aufsicht |
| LAB | Labor Law | Arbeitsrecht, Arbeitsschutz |
| FIN | Financial Regulation | Finanzregulierung, BaFin |
| TRD | Trade Regulation | Gewerbe, Handelsrecht |
| ENV | Environmental | Umweltschutz, Nachhaltigkeit |
| HLT | Health | Gesundheit, Medizinprodukte |
### Spezialisierte Domains
Neben den 16 Standard-Domains gibt es ueber 80 weitere Domains fuer spezifische Themen:
CRA, ARC (Architektur), API, PKI, SUP (Supply Chain), VUL, BCP, PHY u.v.m.
### ID-Format
Control-IDs folgen dem Muster `DOMAIN-NNN` (z.B. AUTH-001, SEC-042). Dieses Format ist
**nicht von BSI oder anderen proprietaeren Standards abgeleitet**, sondern folgt einem
allgemein ueblichen Nummerierungsschema.
!!! warning "Keine BSI-Nomenklatur"
Die Domains verwenden bewusst KEINE BSI-Bezeichner (O.Auth_*, O.Netz_*).
---
## Offene Referenzquellen
Alle Controls sind in mindestens einer der folgenden **frei zugaenglichen** Quellen verankert:
### OWASP (CC BY-SA 4.0 — kommerziell erlaubt)
- **ASVS** — Application Security Verification Standard v4.0.3
- **MASVS** — Mobile Application Security Verification Standard v2.1
- **Top 10** — OWASP Top 10 (2021)
- **Cheat Sheets** — OWASP Cheat Sheet Series
- **SAMM** — Software Assurance Maturity Model
### NIST (Public Domain — keine Einschraenkungen)
- **SP 800-53 Rev.5** — Security and Privacy Controls
- **SP 800-63B** — Digital Identity Guidelines (Authentication)
- **SP 800-57** — Key Management Recommendations
- **SP 800-52 Rev.2** — TLS Implementation Guidelines
- **SP 800-92** — Log Management Guide
- **SP 800-218 (SSDF)** — Secure Software Development Framework
### ENISA (CC BY 4.0 — kommerziell erlaubt)
- Good Practices for IoT/Mobile Security
- Data Protection Engineering
- Algorithms, Key Sizes and Parameters Report
### Weitere offene Quellen
- **SLSA** (Supply-chain Levels for Software Artifacts) — Google Open Source
- **CIS Controls v8** (CC BY-NC-ND — nur fuer interne Analyse)
- **CISA Secure by Design** — US-Behoerde (Public Domain)
---
## Geschuetzte Quellen — Nur interne Analyse
Die folgenden Quellen werden **ausschliesslich intern zur Analyse** verwendet.
Kein Text, keine Struktur, keine Bezeichner aus diesen Quellen erscheinen im Produkt.
### BSI (Nutzungsbedingungen — kommerziell eingeschraenkt)
- TR-03161 Teil 1-3 (Mobile, Web, Hintergrunddienste)
- Nutzung: TDM unter UrhG §44b, Kopien werden geloescht
- Kein Shipping von Zitaten, Embeddings oder Strukturen
### ISO/IEC (Kostenpflichtig — kein Shipping)
- ISO 27001, ISO 27002
- Nutzung: Nur als Referenz fuer Mapping, kein Text im Produkt
### ETSI (Restriktiv — kein kommerzieller Gebrauch)
- Nutzung: Nur als Hintergrundwissen, kein direkter Einfluss
### Trennungsprinzip
| Ebene | Geschuetzte Quelle | Offene Quelle |
|-------|--------------------|---------------|
| Analyse | Darf gelesen werden | Darf gelesen werden |
| Inspiration | Darf Ideen liefern | Darf Ideen liefern |
| Formulierung | Keine Uebernahme | Darf zitiert werden |
| Struktur | Keine Uebernahme | Darf verwendet werden |
| Produkttext | Nicht erlaubt | Erlaubt |
---
## Verifikationsmethoden
Jedes Control wird einer von vier Verifikationsmethoden zugeordnet. Dies bestimmt,
**wie** ein Kunde den Nachweis fuer die Einhaltung erbringen kann:
| Methode | Beschreibung | Beispiele |
|---------|-------------|-----------|
| **Code Review** | Quellcode-Inspektion | Input-Validierung, Encryption-Konfiguration, Auth-Logic |
| **Dokument** | Richtlinien, Prozesse, Schulungen | Notfallplaene, Schulungsnachweise, Datenschutzkonzepte |
| **Tool** | Automatisierte Tools/Scans | SIEM-Logs, Vulnerability-Scans, Monitoring-Dashboards |
| **Hybrid** | Kombination mehrerer Methoden | Zugriffskontrollen (Code + Policy + Tool) |
### Bedeutung fuer Kunden
- **Code Review Controls** koennen direkt im SDK-Scan geprueft werden
- **Dokument Controls** erfordern manuelle Uploads (PDFs, Links)
- **Tool Controls** koennen per API-Integration automatisch nachgewiesen werden
- **Hybrid Controls** benoetigen mehrere Nachweisarten
---
## Thematische Kategorien (23)
Controls sind in thematische Kategorien gruppiert:
| Kategorie | Beschreibung |
|-----------|-------------|
| `encryption` | Verschluesselung, Kryptographie, Key Management |
| `authentication` | Authentifizierung, Login, MFA, Session-Management |
| `network` | Netzwerk, Firewall, VPN, Segmentierung |
| `data_protection` | Datenschutz, DSGVO, Anonymisierung |
| `logging` | Protokollierung, Monitoring, SIEM |
| `incident` | Vorfallmanagement, Meldepflichten |
| `continuity` | Business Continuity, Disaster Recovery, Backups |
| `compliance` | Konformitaet, Audit, Zertifizierung |
| `supply_chain` | Lieferkette, Vendor Risk, SBOM |
| `physical` | Physische Sicherheit, Zutritt |
| `personnel` | Schulung, Security Awareness |
| `application` | Software, Code Review, API, SAST/DAST |
| `system` | Haertung, Patch, Konfiguration |
| `risk` | Risikobewertung, -analyse, -management |
| `governance` | ISMS, Richtlinien, Sicherheitsorganisation |
| `hardware` | Hardware, Firmware, TPM, Secure Boot |
| `identity` | IAM, SSO, Federation, Verzeichnisdienste |
| `public_administration` | Behoerden, Verwaltung |
| `labor_law` | Arbeitsrecht, Arbeitsschutz |
| `finance` | Finanzregulierung, Rechnungslegung |
| `trade_regulation` | Gewerbe, Handelsrecht |
| `environmental` | Umweltschutz, Nachhaltigkeit |
| `health` | Gesundheit, Medizinprodukte |
!!! info "Abgrenzung zu Domains"
Kategorien sind **thematisch**, Domains (AUTH, NET, etc.) sind **strukturell**.
Ein Control AUTH-005 (Domain AUTH) hat die Kategorie "authentication",
aber ein Control NET-012 (Domain NET) koennte ebenfalls die Kategorie
"authentication" haben, wenn es um Netzwerk-Authentifizierung geht.
---
## Master Library Strategie
### RAG-First Ansatz
Die Canonical Control Library folgt einer **RAG-First-Strategie** in Wellen:
| Welle | Quellen | Lizenzregel | Vorteil |
|-------|---------|------------|---------|
| 1 | OWASP (ASVS, MASVS, Top10) | Rule 2 (CC-BY-SA, Zitation) | Originaltext + Zitation |
| 2 | NIST (SP 800-53, CSF, SSDF) | Rule 1 (Public Domain) | Voller Text, keine Einschraenkungen |
| 3 | EU-Verordnungen (DSGVO, AI Act, NIS2, CRA) | Rule 1 (EU Law) | Gesetzestext + Erklaerung |
| 4 | Deutsche Gesetze (BDSG, TTDSG, TKG) | Rule 1 (DE Law) | Gesetzestext + Erklaerung |
### Dedup gegen BSI Rule-3 Controls
Die BSI Rule-3 Controls werden gegen die neuen Rule 1+2 Controls abgeglichen:
- Wenn ein BSI-Control ein Duplikat eines OWASP/NIST-Controls ist → **OWASP/NIST bevorzugt**
(weil Originaltext + Zitation erlaubt)
- BSI-Duplikate werden als `deprecated` markiert
- Tags und Anchors werden in den behaltenen Control zusammengefuehrt
---
## Automatisierte Validierung
Jedes Control wird bei jedem Commit automatisch geprueft:
### 1. Schema-Validierung
- Alle Pflichtfelder vorhanden
- Control-ID Format: `^[A-Z]{2,6}-[0-9]{3}$`
- Severity: low, medium, high, critical
- Risk Score: 0-10
### 2. No-Leak Scanner
Regex-Pruefung gegen verbotene Muster in produktfaehigen Feldern:
- `O.[A-Za-z]+_[0-9]+` — BSI Objective-IDs
- `TR-03161` — Direkte BSI-TR-Referenzen
- `BSI-TR-` — BSI-spezifische Locators
- `Anforderung [A-Z].[0-9]+` — BSI-Anforderungsformat
### 3. Open Anchor Check
Jedes freigegebene Control muss mindestens 1 Open-Source-Referenz haben.
### 4. Too-Close Detektor (5 Metriken)
| Metrik | Warn | Fail | Beschreibung |
|--------|------|------|-------------|
| Exact Phrase | ≥8 Tokens | ≥12 Tokens | Laengste identische Token-Sequenz |
| Token Overlap | ≥0.20 | ≥0.30 | Jaccard-Aehnlichkeit der Token-Mengen |
| 3-Gram Jaccard | ≥0.10 | ≥0.18 | Zeichenketten-Aehnlichkeit |
| Embedding Cosine | ≥0.86 | ≥0.92 | Semantische Aehnlichkeit (bge-m3) |
| LCS Ratio | ≥0.35 | ≥0.50 | Longest Common Subsequence |
**Entscheidungslogik:**
- **PASS** — Kein Fail + max 1 Warn
- **WARN** — Max 2 Warn, kein Fail → Human Review erforderlich
- **FAIL** — Irgendein Fail → Blockiert, Umformulierung noetig
---
## Live-Daten im Frontend
### Lizenz-Matrix
Tabelle aller `canonical_control_licenses` mit Berechtigungsbadges:
| Feld | Beschreibung |
|------|-------------|
| `license_id` | Eindeutige Lizenz-ID (z.B. `OWASP_CC_BY_SA`) |
| `name` | Lizenzname |
| `commercial_use` | `allowed` / `restricted` / `prohibited` / `unclear` |
| `ai_training_restriction` | KI-Training-Einschraenkung |
| `tdm_allowed_under_44b` | TDM nach UrhG §44b erlaubt? (`yes` / `no` / `unclear`) |
| `deletion_required` | Loeschpflicht nach Analyse? |
**API:** `GET /v1/canonical/licenses`
### Quellenregister
Karten fuer jede `canonical_control_sources` mit 4 Berechtigungsstufen:
| Feld | Beschreibung |
|------|-------------|
| `source_id` | Eindeutige Quell-ID (z.B. `OWASP_ASVS`) |
| `title` | Quellenname |
| `publisher` | Herausgeber |
| `license_name` | Verknuepfte Lizenz |
| `allowed_analysis` | Analyse erlaubt? |
| `allowed_store_excerpt` | Auszuege speichern erlaubt? |
| `allowed_ship_embeddings` | Embeddings im Produkt erlaubt? |
| `allowed_ship_in_product` | Text im Produkt erlaubt? |
| `vault_retention_days` | Aufbewahrungsfrist in Tagen |
| `vault_access_tier` | `restricted` / `internal` / `public` |
**API:** `GET /v1/canonical/sources`
---
## Quelldateien
| Datei | Beschreibung |
|-------|-------------|
| `admin-compliance/app/sdk/control-provenance/page.tsx` | Frontend (10 Sektionen + 2 Live-Daten-Tabellen) |
| `backend-compliance/migrations/044_canonical_control_library.sql` | DB-Schema (Licenses, Sources, Mappings) |
| `backend-compliance/compliance/api/canonical_control_routes.py` | API: `/v1/canonical/licenses`, `/v1/canonical/sources` |
---
## Verwandte Dokumentation
- [Canonical Control Library (CP-CLIB)](canonical-control-library.md) — Domains, Datenmodell, Pipeline, Tests
- [Control Generator Pipeline](control-generator-pipeline.md) — 7-Stufen-Pipeline, QA, Recital-Erkennung
@@ -0,0 +1,253 @@
# Deduplizierungs-Engine (Control Dedup)
4-stufige Dedup-Pipeline zur Vermeidung doppelter atomarer Controls bei der Pass 0b Komposition. Kern-USP: **"1 Control erfuellt 5 Gesetze"** durch Multi-Parent-Linking.
**Backend:** `backend-compliance/compliance/services/control_dedup.py`
**Migration:** `backend-compliance/migrations/074_control_dedup.sql`
**Tests:** `backend-compliance/tests/test_control_dedup.py` (56 Tests)
---
## Motivation
Aus ~6.800 technischen Controls x ~10 Obligations pro Control entstehen ~68.000 atomare Kandidaten. Ziel: ~18.000 einzigartige Master Controls. Viele Obligations aus verschiedenen Gesetzen fuehren zum gleichen technischen Control (z.B. "MFA implementieren" in DSGVO, NIS2, AI Act).
**Problem:** Embedding-only Deduplizierung ist GEFAEHRLICH fuer Compliance.
!!! danger "False-Positive Beispiel"
- "Admin-Zugriffe muessen MFA nutzen" vs. "Remote-Zugriffe muessen MFA nutzen"
- Embedding sagt >0.9 aehnlich
- Aber es sind **ZWEI verschiedene Controls** (verschiedene Objekte!)
---
## 4-Stufen Entscheidungsbaum
```mermaid
flowchart TD
A[Kandidat-Control] --> B{Pattern-Gate}
B -->|pattern_id verschieden| N1[NEW CONTROL]
B -->|pattern_id gleich| C{Action-Check}
C -->|Action verschieden| N2[NEW CONTROL]
C -->|Action gleich| D{Object-Normalization}
D -->|Objekt verschieden| E{Similarity > 0.95?}
E -->|Ja| L1[LINK]
E -->|Nein| N3[NEW CONTROL]
D -->|Objekt gleich| F{Tiered Thresholds}
F -->|> 0.92| L2[LINK]
F -->|0.85 - 0.92| R[REVIEW QUEUE]
F -->|< 0.85| N4[NEW CONTROL]
```
### Stufe 1: Pattern-Gate (hart)
`pattern_id` muss uebereinstimmen. Verhindert ~80% der False Positives.
```python
if pattern_id != existing.pattern_id:
→ NEW CONTROL # Verschiedene Kontrollmuster = verschiedene Controls
```
### Stufe 2: Action-Check (hart)
Normalisierte Aktionsverben muessen uebereinstimmen. "Implementieren" vs. "Testen" = verschiedene Controls, auch bei gleichem Objekt.
```python
if normalize_action("implementieren") != normalize_action("testen"):
→ NEW CONTROL # "implement" != "test"
```
**Action-Normalisierung (Deutsch → Englisch):**
| Deutsche Verben | Kanonische Form |
|----------------|-----------------|
| implementieren, umsetzen, einrichten, aktivieren | `implement` |
| testen, pruefen, ueberpruefen, verifizieren | `test` |
| ueberwachen, monitoring, beobachten | `monitor` |
| verschluesseln | `encrypt` |
| protokollieren, aufzeichnen, loggen | `log` |
| beschraenken, einschraenken, begrenzen | `restrict` |
### Stufe 3: Object-Normalization (weich)
Compliance-Objekte werden auf kanonische Token normalisiert.
```python
normalize_object("Admin-Konten") → "privileged_access"
normalize_object("Remote-Zugriff") → "remote_access"
normalize_object("MFA") → "multi_factor_auth"
```
Bei verschiedenen Objekten gilt ein hoeherer Schwellenwert (0.95 statt 0.92).
**Objekt-Normalisierung:**
| Eingabe | Kanonischer Token |
|---------|------------------|
| MFA, 2FA, Multi-Faktor-Authentifizierung | `multi_factor_auth` |
| Admin-Konten, privilegierte Zugriffe | `privileged_access` |
| Verschluesselung, Kryptografie | `encryption` |
| Schluessel, Key Management | `key_management` |
| TLS, SSL, HTTPS | `transport_encryption` |
| Firewall | `firewall` |
| Audit-Log, Protokoll, Logging | `audit_logging` |
### Stufe 4: Embedding Similarity (Qdrant)
Tiered Thresholds basierend auf Cosine-Similarity:
| Score | Verdict | Aktion |
|-------|---------|--------|
| > 0.95 | **LINK** | Bei verschiedenen Objekten |
| > 0.92 | **LINK** | Parent-Link hinzufuegen |
| 0.85 - 0.92 | **REVIEW** | In Review-Queue zur manuellen Pruefung |
| < 0.85 | **NEW** | Neues Control anlegen |
---
## Canonicalization Layer
Vor dem Embedding wird der deutsche Compliance-Text in normalisiertes Englisch transformiert:
```
"Administratoren muessen MFA verwenden"
→ "implement multi_factor_auth for administratoren verwenden"
→ Bessere Matches, weniger Embedding-Rauschen
```
Dies reduziert das Rauschen durch synonyme Formulierungen in verschiedenen Gesetzen.
---
## Multi-Parent-Linking (M:N)
Ein atomares Control kann mehrere Eltern-Controls aus verschiedenen Regulierungen haben:
```json
{
"control_id": "AUTH-1072-A01",
"parent_links": [
{"parent_control_id": "AUTH-1001", "source": "NIST IA-02(01)", "link_type": "decomposition"},
{"parent_control_id": "NIS2-045", "source": "NIS2 Art. 21", "link_type": "dedup_merge"}
]
}
```
### Datenbank-Schema
```sql
-- Migration 074: control_parent_links (M:N)
CREATE TABLE control_parent_links (
id UUID PRIMARY KEY DEFAULT gen_random_uuid(),
control_uuid UUID NOT NULL REFERENCES canonical_controls(id),
parent_control_uuid UUID NOT NULL REFERENCES canonical_controls(id),
link_type VARCHAR(30) NOT NULL DEFAULT 'decomposition',
confidence NUMERIC(3,2) DEFAULT 1.0,
source_regulation VARCHAR(100),
source_article VARCHAR(100),
obligation_candidate_id UUID REFERENCES obligation_candidates(id),
created_at TIMESTAMPTZ DEFAULT NOW(),
CONSTRAINT uq_parent_link UNIQUE (control_uuid, parent_control_uuid)
);
```
**Link-Typen:**
| Typ | Bedeutung |
|-----|-----------|
| `decomposition` | Aus Pass 0b Zerlegung |
| `dedup_merge` | Durch Dedup-Engine als Duplikat erkannt |
| `manual` | Manuell durch Reviewer verknuepft |
| `crosswalk` | Aus Crosswalk-Matrix uebernommen |
---
## Review-Queue
Borderline-Matches (Similarity 0.85-0.92) werden in die Review-Queue geschrieben:
```sql
-- Migration 074: control_dedup_reviews
CREATE TABLE control_dedup_reviews (
id UUID PRIMARY KEY DEFAULT gen_random_uuid(),
candidate_control_id VARCHAR(30) NOT NULL,
candidate_title TEXT NOT NULL,
candidate_objective TEXT,
matched_control_uuid UUID REFERENCES canonical_controls(id),
matched_control_id VARCHAR(30),
similarity_score NUMERIC(4,3),
dedup_stage VARCHAR(40) NOT NULL,
review_status VARCHAR(20) DEFAULT 'pending',
-- pending → accepted_link | accepted_new | rejected
created_at TIMESTAMPTZ DEFAULT NOW()
);
```
---
## Qdrant Collection
```
Collection: atomic_controls
Dimension: 1024 (bge-m3)
Distance: COSINE
Payload: pattern_id, action_normalized, object_normalized, control_id, canonical_text
Index: pattern_id (keyword), action_normalized (keyword), object_normalized (keyword)
Query: IMMER mit filter: pattern_id == X (reduziert Suche drastisch)
```
---
## Integration in Pass 0b
Die Dedup-Engine ist optional in `DecompositionPass` integriert:
```python
decomp = DecompositionPass(db=session, dedup_enabled=True)
stats = await decomp.run_pass0b(limit=100, use_anthropic=True)
# Stats enthalten Dedup-Metriken:
# stats["dedup_linked"] = 15 (Duplikate → Parent-Link)
# stats["dedup_review"] = 3 (Borderline → Review-Queue)
# stats["controls_created"] = 82 (Neue Controls)
```
**Ablauf bei Pass 0b mit Dedup:**
1. LLM generiert atomares Control
2. Dedup-Engine prueft 4 Stufen
3. **LINK:** Kein neues Control, Parent-Link zu bestehendem
4. **REVIEW:** Kein neues Control, Eintrag in Review-Queue
5. **NEW:** Control anlegen + in Qdrant indexieren
---
## Konfiguration
| Umgebungsvariable | Default | Beschreibung |
|-------------------|---------|-------------|
| `DEDUP_ENABLED` | `true` | Dedup-Engine ein/ausschalten |
| `DEDUP_LINK_THRESHOLD` | `0.92` | Schwelle fuer automatisches Linking |
| `DEDUP_REVIEW_THRESHOLD` | `0.85` | Schwelle fuer Review-Queue |
| `DEDUP_LINK_THRESHOLD_DIFF_OBJ` | `0.95` | Schwelle bei verschiedenen Objekten |
| `DEDUP_QDRANT_COLLECTION` | `atomic_controls` | Qdrant-Collection fuer Dedup-Index |
| `QDRANT_URL` | `http://host.docker.internal:6333` | Qdrant-URL |
| `EMBEDDING_URL` | `http://embedding-service:8087` | Embedding-Service-URL |
---
## Quelldateien
| Datei | Beschreibung |
|-------|-------------|
| `compliance/services/control_dedup.py` | 4-Stufen Dedup-Engine |
| `compliance/services/decomposition_pass.py` | Pass 0a/0b mit Dedup-Integration |
| `migrations/074_control_dedup.sql` | DB-Schema (parent_links, review_queue) |
| `tests/test_control_dedup.py` | 56 Unit-Tests |
---
## Verwandte Dokumentation
- [Control Generator Pipeline](control-generator-pipeline.md) — 7-Stufen RAG→Control Pipeline
- [Canonical Control Library](canonical-control-library.md) — Datenmodell, Domains, Similarity-Detektor
@@ -80,3 +80,13 @@ Im Company-Profile-Wizard erscheint nach Abschluss (`is_complete = true`) ein CT
- Alle 5 Template-Generatoren mit verschiedenen Kontext-Variationen
- Regulierungs-Flag-Kombinationen
- Route-Registrierung
---
## Policy-Bibliothek
Neben der automatischen Dokumentengenerierung aus Stammdaten stehen **29 deutsche Richtlinien-Templates**
im Dokumentengenerator als Vorlagen bereit (IT-Sicherheit, Datenschutz, Personal, Lieferanten, BCM).
Siehe [Policy-Bibliothek](policy-bibliothek.md) fuer die vollstaendige Liste aller Templates,
Platzhalter und Kategorien.
@@ -0,0 +1,132 @@
# Evidence Type — Code vs. Prozess Controls
## Uebersicht
Nicht jedes Control kann gleich nachgewiesen werden. Ein Verschluesselungs-Control
ist im Quellcode pruefbar, ein Risikomanagement-Control erfordert Dokumente und
Nachweise. Diese Unterscheidung bestimmt, **wie** die Compliance-Plattform den
Nachweis automatisiert oder den Nutzer unterstuetzt.
Das Feld `evidence_type` auf `canonical_controls` klassifiziert jeden Control
in eine von drei Kategorien.
## Die drei Typen
```mermaid
graph LR
subgraph "code"
C1["Source Code"]
C2["IaC / Terraform"]
C3["CI/CD Pipeline"]
C4["Cloud Config"]
end
subgraph "process"
P1["Policies"]
P2["Schulungsnachweise"]
P3["Vertraege"]
P4["Screenshots / Audits"]
end
subgraph "hybrid"
H1["Code + Doku"]
H2["Config + Schulung"]
end
```
### Code Controls
| Eigenschaft | Beschreibung |
|---|---|
| **evidence_type** | `code` |
| **Nachweis** | Automatisiert pruefbar: Source Code, IaC, CI/CD, Cloud-Konfiguration |
| **Automatisierung** | Hoch — SAST, Dependency Scan, Config Audit |
| **Beispiel-Domains** | SEC, AUTH, CRYPT, NET, LOG, ACC, API |
| **Beispiel** | "AES-256 Verschluesselung at rest" → pruefbar via Code Review / IaC Scan |
### Prozess Controls
| Eigenschaft | Beschreibung |
|---|---|
| **evidence_type** | `process` |
| **Nachweis** | Dokumente, Policies, Schulungsnachweise, Vertraege, Screenshots |
| **Automatisierung** | Gering — erfordert manuelle Uploads oder MCP-Dokumenten-Scan |
| **Beispiel-Domains** | GOV, ORG, COMP, LEGAL, HR, FIN, RISK, AUDIT, ENV |
| **Beispiel** | "Reallabor-Zugang fuer KMUs bereitstellen" → Nachweis ueber Programm-Dokumentation |
!!! info "Governance & Regulatorische Controls"
Controls wie "Behoerde muss KMUs Zugang zu Reallaboren geben" sind Prozess-Controls.
Der Nachweis erfolgt ueber Dokumente — nicht im Source Code.
Auch regulatorische Umsetzungspflichten (GOV-Domain) fallen hierunter.
### Hybrid Controls
| Eigenschaft | Beschreibung |
|---|---|
| **evidence_type** | `hybrid` |
| **Nachweis** | Sowohl Code als auch Dokumente erforderlich |
| **Automatisierung** | Teilweise — Code-Teil automatisiert, Prozess-Teil manuell |
| **Beispiel-Domains** | DATA, AI, INC, IAM |
| **Beispiel** | "MFA implementieren" → Config pruefbar (code) + Nutzer-Schulung noetig (process) |
## Backfill-Heuristik
Der Backfill klassifiziert Controls automatisch anhand des Domain-Prefix:
```
POST /api/compliance/v1/canonical/controls/backfill-evidence-type?dry_run=true
```
**Algorithmus:**
1. Domain-Prefix extrahieren (z.B. `SEC` aus `SEC-042`)
2. Gegen vordefinierte Domain-Sets pruefen (code / process / hybrid)
3. Falls Domain unbekannt: Category als Fallback nutzen
4. Falls auch keine Category: `process` (konservativ)
### Domain-Zuordnung
| Typ | Domains |
|---|---|
| **code** | SEC, AUTH, CRYPT, CRYP, NET, LOG, ACC, APP, SYS, API, WEB, DEV, SDL, PKI, HSM, TEE, TPM, VUL, ... |
| **process** | GOV, ORG, COMP, LEGAL, HR, FIN, RISK, AUDIT, ENV, HLT, TRD, LAB, PHYS, PRIV, DPO, ... |
| **hybrid** | DATA, AI, INC, IAM, OPS, MNT, INT, ... |
## Frontend-Anzeige
In der Control-Library werden Controls mit farbcodierten Badges angezeigt:
| evidence_type | Badge | Farbe | Bedeutung |
|---|---|---|---|
| `code` | **Code** | Blau (sky) | Technisch, im Source Code pruefbar |
| `process` | **Prozess** | Amber/Orange | Organisatorisch, Dokument-basiert |
| `hybrid` | **Hybrid** | Violett | Beides erforderlich |
Zusaetzlich steht ein Dropdown-Filter "Nachweisart" zur Verfuegung.
## Zusammenspiel mit anderen Feldern
| Feld | Zweck | Beispiel |
|---|---|---|
| `evidence_type` | **WAS** wird nachgewiesen (Code oder Prozess) | `code` |
| `verification_method` | **WIE** wird verifiziert | `code_review`, `document`, `tool`, `hybrid` |
| `evidence_confidence` | **WIE SICHER** ist der Nachweis (0.0 - 1.0) | `0.92` |
| `normative_strength` | **WIE VERBINDLICH** ist das Control | `must`, `should`, `may` |
!!! warning "evidence_type vs. verification_method"
`evidence_type` sagt, ob ein Control technisch oder organisatorisch ist.
`verification_method` sagt, mit welcher Methode es geprueft wird.
Ein `process`-Control kann trotzdem `verification_method = tool` haben
(z.B. wenn ein MCP-Scan Dokumente automatisch prueft).
## Kuenftige Automatisierung
### Code Controls
- **Git-Repository-Scan**: SAST, Secret Detection, Dependency Check
- **IaC-Analyse**: Terraform/Pulumi/CloudFormation Policies
- **CI/CD-Integration**: Pipeline-Ergebnisse als Evidence sammeln
### Prozess Controls
- **MCP-Dokumenten-Scan**: Kunden-Laufwerk anbinden, Dokumente automatisch pruefen
- **Screenshot-Analyse**: OCR + LLM-Validierung von Screenshots
- **Interview-Protokolle**: Strukturierte Audit-Checklisten
+10 -1
View File
@@ -88,12 +88,21 @@ compliance_evidence (
---
## Anti-Fake-Evidence
Seit Phase 1 (2026-03-23) werden Nachweise automatisch mit **Confidence Levels** (E0E4) und **Truth Status** klassifiziert. Details: [Anti-Fake-Evidence Architektur](anti-fake-evidence.md)
---
## Tests
**Testdatei:** `backend-compliance/tests/test_evidence_routes.py`
**Anzahl Tests:** 11 · **Status:** ✅ alle bestanden (Stand 2026-03-05)
**Anti-Fake-Evidence Tests:** `backend-compliance/tests/test_anti_fake_evidence.py`
**Anzahl Tests:** ~45 · Confidence-Klassifikation, State Machine, Multi-Score, LLM Audit
```bash
cd backend-compliance
python3 -m pytest tests/test_evidence_routes.py -v
python3 -m pytest tests/test_evidence_routes.py tests/test_anti_fake_evidence.py -v
```
File diff suppressed because it is too large Load Diff
+510 -99
View File
@@ -17,84 +17,139 @@ Das IACE-Modul unterstuetzt die vollstaendige CE-Konformitaetsbewertung von Masc
---
## SEPA Risikomodell
## Risikomodell (Dual-Modus)
IACE verwendet das **SEPA-Modell** (Severity × Exposure × Probability × Avoidance):
IACE unterstuetzt zwei Betriebsmodi fuer die Risikobewertung:
### Formel
### Legacy-Modus (S×E×P)
| Avoidance | Formel | Beschreibung |
|-----------|--------|--------------|
| `0` (Standard) | `S × E × P` | Backward-kompatibel, kein Avoidance-Faktor |
| `15` | `S × E × P × (A / 3.0)` | Avoidance-faktor aktiv (3 = neutral) |
| `0` (Standard) | `R = S × E × P` | Backward-kompatibel, kein Avoidance-Faktor |
### Avoidance-Skala
| Wert | Bedeutung |
|------|-----------|
| 1 | Leicht vermeidbar (klare Warnung, langsame Bewegung) |
| 2 | Eher vermeidbar |
| 3 | Neutral (kein Einfluss) |
| 4 | Schwer vermeidbar |
| 5 | Nicht vermeidbar (sofortige Auswirkung) |
### Schwellwerte (Residualrisiko)
**Schwellwerte (Legacy):**
| Schwelle | Level |
|----------|-------|
| 75 | critical |
| 40 | high |
| 15 | medium |
| 5 | low |
| >= 75 | critical |
| >= 40 | high |
| >= 15 | medium |
| >= 5 | low |
| < 5 | negligible |
### ISO-Modus (S×F×P×A) — ab v2.0
Wenn `avoidance >= 1`, wird automatisch der ISO-Modus aktiviert:
| Formel | Beschreibung |
|--------|--------------|
| `R = S × F × P × A` | Direkte 4-Faktor-Multiplikation (KEIN /3.0) |
**Faktoren:**
| Faktor | Skala | Beschreibung |
|--------|-------|--------------|
| **S** (Severity) | 15 | Schwere des moeglichen Schadens |
| **F** (Frequency/Exposure) | 15 | Haeufigkeit/Dauer der Exposition |
| **P** (Probability) | 15 | Wahrscheinlichkeit des Eintretens |
| **A** (Avoidance) | 15 | Moeglichkeit der Vermeidung (1=leicht, 5=nicht vermeidbar) |
**Schwellwerte (ISO-Modus):**
| Schwelle | Level | Farbe |
|----------|-------|-------|
| > 300 | not_acceptable | Dunkelrot |
| 151300 | very_high | Dunkelorange |
| 61150 | high | Rot |
| 2160 | medium | Gelb |
| 120 | low | Gruen |
### ALARP-Akzeptanz
- `residualRisk < 15` → akzeptabel
- `residualRisk < 40` + alle Minderungsschritte verifiziert + Begruendung → akzeptabel (ALARP)
- `residualRisk 40` → nicht akzeptabel (blockiert CE-Export)
- `residualRisk >= 40` → nicht akzeptabel (blockiert CE-Export)
### Schutzmassnahmen-Hierarchie (3-Stufen)
Die Risikobehandlung folgt einer verbindlichen Hierarchie:
| Stufe | Typ | Beschreibung |
|-------|-----|--------------|
| 1 | **Design** | Inhaerent sichere Konstruktion (z.B. Begrenzung von Kraeften, Geschwindigkeiten) |
| 2 | **Schutzeinrichtung** | Technische Schutzmassnahmen (z.B. Schutzgitter, Lichtvorhang, STO) |
| 3 | **Information** | Hinweise, Warnungen, Schulung (z.B. Sicherheitskennzeichnung, Betriebsanleitung) |
!!! warning "Hierarchie-Regel"
Informationsmassnahmen (Stufe 3) duerfen **nicht** als alleinige Primaermassnahme akzeptiert werden, wenn Design- oder Schutzmassnahmen technisch moeglich sind. Das System prueft dies automatisch und gibt eine Warnung aus.
---
## Hazard-Library
Die eingebaute Hazard-Library enthaelt **~140 Eintraege** in 24 Kategorien:
Die eingebaute Hazard-Library enthaelt **150+ Eintraege** in 28 Kategorien. Alle Eintraege verwenden eigene Formulierungen und referenzieren Normen nur als Methodenquelle.
### Urspruengliche Kategorien (12)
### KI/Cyber-Kategorien (12)
| Kategorie | Eintraege | Beschreibung |
|-----------|-----------|--------------|
| `false_classification` | 4 | Falsche KI-Klassifikation |
| `timing_error` | 3 | Echtzeit-Verletzungen |
| `data_poisoning` | 2 | Manipulierte Trainingsdaten |
| `model_drift` | 3 | Modell-Verschlechterung |
| `sensor_spoofing` | 3 | Sensor-Manipulation |
| `communication_failure` | 3 | Kommunikationsausfall |
| `unauthorized_access` | 4 | Unberechtigter Zugriff |
| `firmware_corruption` | 3 | Firmware-Beschaedigung |
| `safety_boundary_violation` | 4 | Sicherheitsgrenzwert-Verletzung |
| `mode_confusion` | 3 | Betriebsart-Verwechslung |
| `unintended_bias` | 2 | Unbeabsichtigte Diskriminierung |
| `update_failure` | 3 | Update-Fehler |
| Kategorie | Beschreibung |
|-----------|--------------|
| `false_classification` | Falsche KI-Klassifikation |
| `timing_error` | Echtzeit-Verletzungen |
| `data_poisoning` | Manipulierte Trainingsdaten |
| `model_drift` | Modell-Verschlechterung |
| `sensor_spoofing` | Sensor-Manipulation |
| `communication_failure` | Kommunikationsausfall |
| `unauthorized_access` | Unberechtigter Zugriff |
| `firmware_corruption` | Firmware-Beschaedigung |
| `safety_boundary_violation` | Sicherheitsgrenzwert-Verletzung |
| `mode_confusion` | Betriebsart-Verwechslung |
| `unintended_bias` | Unbeabsichtigte Diskriminierung |
| `update_failure` | Update-Fehler |
### Neue Kategorien (12, v2.0)
### Software/Hardware-Kategorien (12)
| Kategorie | Eintraege | Beschreibung |
|-----------|-----------|--------------|
| `software_fault` | 10 | Race Condition, Stack Overflow, Integer Overflow, Deadlock... |
| `hmi_error` | 8 | Falsche Einheit, fehlender Alarm, Quittierung ohne Ursache... |
| `mechanical_hazard` | 6 | Unerwarteter Anlauf, Restenergie, Teileauswurf... |
| `electrical_hazard` | 6 | Elektrischer Schlag, Lichtbogen, gespeicherte Energie... |
| `thermal_hazard` | 4 | Ueberhitzung, Brandgefahr, Einfrieren... |
| `emc_hazard` | 5 | EMV-Stoerabstrahlung, ESD, HF-Stoerung... |
| `configuration_error` | 8 | Falscher Safety-Param, Hard-coded Credentials, Debug-Mode... |
| `safety_function_failure` | 8 | Not-Halt, STO, Schutztuer, Zweihand-Taster... |
| `logging_audit_failure` | 5 | Fehlende Protokollierung, Log-Manipulation, Overflow... |
| `integration_error` | 8 | Datentyp-Mismatch, Endianness, Buffer Overflow, Heartbeat... |
| `environmental_hazard` | 5 | Temperatur, Feuchtigkeit, Vibration, Kontamination... |
| `maintenance_hazard` | 6 | LOTO fehlt, Wartung bei laufender Maschine, Wiederanlauf... |
| Kategorie | Beschreibung |
|-----------|--------------|
| `software_fault` | Race Condition, Stack Overflow, Integer Overflow, Deadlock |
| `hmi_error` | Falsche Einheit, fehlender Alarm, Quittierung ohne Ursache |
| `mechanical_hazard` | Quetschen, Scheren, Einziehen, Herabfallende Teile, Instabilitaet |
| `electrical_hazard` | Elektrischer Schlag, Lichtbogen, Ueberstrom, Erdungsfehler |
| `thermal_hazard` | Ueberhitzung, Brandgefahr, Einfrieren, Waermestrahlung |
| `emc_hazard` | EMV-Stoerabstrahlung, ESD, HF-Stoerung |
| `configuration_error` | Falscher Safety-Param, Hard-coded Credentials, Debug-Mode |
| `safety_function_failure` | Not-Halt, STO, Schutztuer, Zweihand-Taster |
| `logging_audit_failure` | Fehlende Protokollierung, Log-Manipulation, Overflow |
| `integration_error` | Datentyp-Mismatch, Endianness, Buffer Overflow, Heartbeat |
| `environmental_hazard` | Temperatur, Feuchtigkeit, Vibration, Kontamination |
| `maintenance_hazard` | LOTO fehlt, Wartung bei laufender Maschine, Wiederanlauf |
**Filter:** `GET /sdk/v1/iace/hazard-library?category=software_fault&componentType=sw`
### Physikalische Kategorien (4, ab v2.0)
| Kategorie | Beschreibung |
|-----------|--------------|
| `pneumatic_hydraulic` | Druckverlust, Druckfreisetzung, Schlauchpeitschen, unerwartete Bewegung |
| `noise_vibration` | Gehoerschaedigung, Hand-Arm-Vibration, Ganzkoerpervibration |
| `ergonomic` | Fehlbedienung, Zwangshaltung, Ueberforderung, Repetitive Belastung |
| `material_environmental` | Staub, Rauch, Daempfe, chemische Exposition, Leckagen |
### Erweiterte Felder (ab v2.0)
Jeder Hazard-Library-Eintrag enthaelt zusaetzlich:
| Feld | Typ | Beschreibung |
|------|-----|--------------|
| `default_exposure` | int (15) | Standard-Expositionswert |
| `default_avoidance` | int (15) | Standard-Vermeidbarkeit |
| `typical_causes` | string[] | Typische Ursachen |
| `typical_harm` | string | Typische Schadensfolge |
| `relevant_lifecycle_phases` | string[] | Relevante Lebensphasen |
| `recommended_measures_design` | string[] | Empfohlene Design-Massnahmen |
| `recommended_measures_technical` | string[] | Empfohlene technische Massnahmen |
| `recommended_measures_information` | string[] | Empfohlene Informationsmassnahmen |
| `suggested_evidence` | string[] | Vorgeschlagene Nachweisdokumente |
| `related_keywords` | string[] | Suchbegriffe |
**Filter:** `GET /sdk/v1/iace/hazard-library?category=mechanical_hazard&componentType=mechanical`
---
@@ -117,14 +172,139 @@ Die Controls-Library enthaelt **200 Eintraege** in 6 Domaenen:
---
## Schutzmassnahmen-Bibliothek (ab v2.0)
Zusaetzlich zur Controls-Library bietet IACE eine **Schutzmassnahmen-Bibliothek** mit **160 Eintraegen**, kategorisiert nach der 3-Stufen-Hierarchie:
| ReductionType | Eintraege | Beispiele |
|---------------|-----------|-----------|
| `design` | ~55 | Kraftbegrenzung, Formschluessige Sicherung, Redundante Sensorik |
| `protective` | ~60 | Schutzgitter, Lichtvorhang, STO, Druckbegrenzungsventil |
| `information` | ~45 | Sicherheitskennzeichnung, Betriebsanleitung, Schulungsprogramm |
**Filter:** `GET /sdk/v1/iace/protective-measures-library?category=mechanical_hazard`
---
## Lebensphasen (25)
Die Risikobeurteilung beruecksichtigt **25 Lebensphasen** einer Maschine:
| Phase | DE | EN |
|-------|----|----|
| `transport` | Transport | Transport |
| `storage` | Lagerung | Storage |
| `assembly` | Montage | Assembly |
| `installation` | Aufstellung | Installation |
| `commissioning` | Inbetriebnahme | Commissioning |
| `parameterization` | Parametrierung | Parameterization |
| `setup` | Einrichten | Setup |
| `normal_operation` | Normalbetrieb | Normal Operation |
| `auto_operation` | Automatikbetrieb | Automatic Operation |
| `manual_operation` | Handbetrieb | Manual Operation |
| `teach_mode` | Teach-Modus | Teach Mode |
| `production_start` | Produktionsstart | Production Start |
| `production_stop` | Produktionsstopp | Production Stop |
| `process_monitoring` | Prozessueberwachung | Process Monitoring |
| `cleaning` | Reinigung | Cleaning |
| `inspection` | Inspektion | Inspection |
| `maintenance` | Wartung | Maintenance |
| `calibration` | Kalibrierung | Calibration |
| `repair` | Reparatur | Repair |
| `software_update` | Software-Update | Software Update |
| `remote_maintenance` | Fernwartung | Remote Maintenance |
| `fault_clearing` | Stoerungsbeseitigung | Fault Clearing |
| `changeover` | Umruestung | Changeover |
| `decommissioning` | Ausserbetriebnahme | Decommissioning |
| `disposal` | Demontage/Entsorgung | Dismantling/Disposal |
**API:** `GET /sdk/v1/iace/lifecycle-phases`
---
## Betroffene Personen (20 Rollen)
Jede Gefaehrdung kann einer oder mehreren betroffenen Personengruppen zugeordnet werden:
| Rolle | DE | EN |
|-------|----|----|
| `operator` | Bediener | Operator |
| `setup_personnel` | Einrichter | Setup Personnel |
| `maintenance_tech` | Wartungstechniker | Maintenance Technician |
| `cleaning_staff` | Reinigungspersonal | Cleaning Staff |
| `supervisor` | Aufsichtsperson | Supervisor |
| `programmer` | Programmierer/Integrator | Programmer/Integrator |
| `trainee` | Auszubildender | Trainee |
| `temp_worker` | Leiharbeiter | Temporary Worker |
| `visitor` | Besucher | Visitor |
| `third_party` | Dritte/Passanten | Third Party/Bystander |
| `transport_personnel` | Transportpersonal | Transport Personnel |
| `commissioning_eng` | Inbetriebnahme-Ingenieur | Commissioning Engineer |
| `quality_inspector` | Qualitaetspruefer | Quality Inspector |
| `safety_officer` | Sicherheitsbeauftragter | Safety Officer |
| `electrical_tech` | Elektrofachkraft | Electrical Technician |
| `it_admin` | IT-Administrator | IT Administrator |
| `remote_operator` | Fernbediener | Remote Operator |
| `emergency_responder` | Ersthelfer/Rettungskraft | Emergency Responder |
| `contractor` | Fremdfirma-Mitarbeiter | Contractor |
| `disabled_person` | Person mit Einschraenkung | Person with Disability |
**API:** `GET /sdk/v1/iace/roles`
---
## Nachweistypen (50 in 7 Kategorien)
Fuer die Verifikation stehen **50 Nachweistypen** zur Auswahl:
| Kategorie | Beispiele |
|-----------|-----------|
| **Konstruktion** | Risikobeurteilung, Sicherheitskonzept, Schaltplan, Pneumatikplan |
| **Berechnung** | Festigkeitsberechnung, Thermische Simulation, FMEA |
| **Pruefung** | Funktionspruefung, Druckpruefung, EMV-Messung, Isolationspruefung |
| **Zertifizierung** | Baumuster-Pruefbescheinigung, SIL/PL-Zertifikat, CE-Konformitaetserklaerung |
| **Software** | Code-Review-Protokoll, Statische Analyse, Unit-Test-Report, Penetrationstest |
| **Betrieb** | Betriebsanleitung, Wartungsplan, Schulungsnachweis, Notfallplan |
| **Ueberwachung** | Inspektionsbericht, Kalibrierprotokoll, Audit-Report, Maengelprotokoll |
**API:** `GET /sdk/v1/iace/evidence-types?category=pruefung`
---
## Verifikationsmethoden (10)
| Methode | Beschreibung |
|---------|--------------|
| `design_review` | Systematische Pruefung von Konstruktionsunterlagen |
| `calculation` | Rechnerischer Nachweis (Festigkeit, Thermik, SIL) |
| `test_report` | Pruefbericht aus Labor- oder Feldversuchen |
| `validation` | Nachweis der Gebrauchstauglichkeit unter realen Bedingungen |
| `electrical_test` | Isolationsmessung, Schutzleiter, Spannungspruefung |
| `software_test` | Unit-Test, Integrationstest, statische Analyse |
| `penetration_test` | Sicherheitstest der IT/OT-Infrastruktur |
| `acceptance_protocol` | Formales Abnahmeprotokoll mit Checkliste |
| `user_test` | Anwendertest unter realistischen Einsatzbedingungen |
| `documentation_release` | Formale Freigabe von Dokumenten und Anleitungen |
---
## API-Endpunkte (30+)
### Libraries (projektunabhaengig)
### Libraries & Referenzdaten (projektunabhaengig)
| Methode | Pfad | Beschreibung |
|---------|------|--------------|
| GET | `/sdk/v1/iace/hazard-library` | Alle Gefaehrdungen (~140) |
| GET | `/sdk/v1/iace/hazard-library` | Alle Gefaehrdungen (150+) |
| GET | `/sdk/v1/iace/controls-library` | Alle Controls (200) |
| GET | `/sdk/v1/iace/protective-measures-library` | Schutzmassnahmen-Bibliothek (160) |
| GET | `/sdk/v1/iace/component-library` | Komponenten-Bibliothek (C001-C120) |
| GET | `/sdk/v1/iace/energy-sources` | Energiequellen (EN01-EN20) |
| GET | `/sdk/v1/iace/hazard-patterns` | Gefaehrdungs-Patterns (102) |
| GET | `/sdk/v1/iace/tags` | Tag-Taxonomie |
| GET | `/sdk/v1/iace/lifecycle-phases` | 25 Lebensphasen (DE/EN) |
| GET | `/sdk/v1/iace/roles` | 20 betroffene Personengruppen (DE/EN) |
| GET | `/sdk/v1/iace/evidence-types` | 50 Nachweistypen in 7 Kategorien |
| POST | `/sdk/v1/iace/library-search` | RAG-Bibliothekssuche |
### Projektmanagement
@@ -136,12 +316,19 @@ Die Controls-Library enthaelt **200 Eintraege** in 6 Domaenen:
| PUT | `/sdk/v1/iace/projects/:id` | Projekt aktualisieren |
| DELETE | `/sdk/v1/iace/projects/:id` | Projekt archivieren |
### Onboarding
### Onboarding & Profil-Import
| Methode | Pfad | Beschreibung |
|---------|------|--------------|
| POST | `/sdk/v1/iace/projects/:id/init-from-profile` | Projekt aus Company-Profile initialisieren |
| POST | `/sdk/v1/iace/projects/:id/completeness-check` | 25-Gates-Pruefung |
| POST | `/sdk/v1/iace/projects/:id/completeness-check` | 22-Gates-Pruefung |
Der `init-from-profile` Endpoint uebernimmt Daten aus dem Company-Profile und Compliance-Scope:
- **company_profile** → Hersteller-Name, Kontaktdaten
- **compliance_scope** → Maschinenname, Typ, Zweckbeschreibung, Software/Firmware/KI-Flags
- Erstellt automatisch initiale Komponenten (Software, Firmware, KI-Modell, Netzwerk)
- Triggert initiale regulatorische Klassifizierungen fuer anwendbare Verordnungen
### Komponenten
@@ -170,7 +357,8 @@ Die Controls-Library enthaelt **200 Eintraege** in 6 Domaenen:
| POST | `/sdk/v1/iace/projects/:id/hazards/suggest` | KI-gestuetzte Vorschlaege |
| POST | `/sdk/v1/iace/projects/:id/hazards/:hid/assess` | Risikobewertung (SEPA) |
| POST | `/sdk/v1/iace/projects/:id/hazards/:hid/reassess` | Neubewertung nach Minderung |
| GET | `/sdk/v1/iace/projects/:id/risk-summary` | Aggregierte Risikoübersicht |
| GET | `/sdk/v1/iace/projects/:id/risk-summary` | Aggregierte Risikouebersicht |
| POST | `/sdk/v1/iace/projects/:id/validate-mitigation-hierarchy` | Hierarchie-Pruefung (3-Stufen) |
### Minderung & Verifikation
@@ -188,9 +376,71 @@ Die Controls-Library enthaelt **200 Eintraege** in 6 Domaenen:
| Methode | Pfad | Beschreibung |
|---------|------|--------------|
| GET | `/sdk/v1/iace/projects/:id/tech-file` | Technische Akte abrufen |
| POST | `/sdk/v1/iace/projects/:id/tech-file/generate` | Akte generieren |
| GET | `/sdk/v1/iace/projects/:id/tech-file/export` | Akte exportieren (PDF/Markdown) |
| PUT | `/sdk/v1/iace/projects/:id/tech-file/sections/:sid` | Abschnitt aktualisieren |
| POST | `/sdk/v1/iace/projects/:id/tech-file/generate` | Alle Sektionen generieren (LLM-basiert) |
| POST | `/sdk/v1/iace/projects/:id/tech-file/:section/generate` | Einzelne Sektion (re-)generieren (LLM) |
| PUT | `/sdk/v1/iace/projects/:id/tech-file/:section` | Abschnitt manuell aktualisieren |
| POST | `/sdk/v1/iace/projects/:id/tech-file/:section/approve` | Abschnitt freigeben |
| POST | `/sdk/v1/iace/projects/:id/tech-file/:section/enrich` | Abschnitt mit RAG-Kontext anreichern |
| GET | `/sdk/v1/iace/projects/:id/tech-file/export?format=` | Akte exportieren (pdf/xlsx/docx/md/json) |
#### Export-Formate
| Format | MIME-Type | Inhalt |
|--------|-----------|--------|
| `pdf` | application/pdf | Vollstaendige CE-Akte mit Deckblatt, Inhaltsverzeichnis, Risikomatrix, Gefaehrdungsprotokoll |
| `xlsx` | application/vnd.openxmlformats-officedocument.spreadsheetml.sheet | 5 Worksheets: Uebersicht, Gefaehrdungsprotokoll, Massnahmen, Risikomatrix, Sektionen |
| `docx` | application/vnd.openxmlformats-officedocument.wordprocessingml.document | Word-Dokument mit allen Sektionen als formatierte Absaetze |
| `md` | text/markdown | Markdown-Dokument mit Projekt-Metadaten und allen Sektionen |
| `json` | application/json | JSON-Export mit Projekt, Sektionen, Klassifizierungen, Risikouebersicht |
#### LLM-basierte Sektionsgenerierung (19 Sektionstypen)
Die Tech-File-Generierung nutzt LLM (Ollama/Anthropic) mit RAG-Kontext aus dem CE-Corpus:
| Sektion | Beschreibung |
|---------|--------------|
| `general_description` | Allgemeine Maschinenbeschreibung |
| `risk_assessment_report` | Zusammenfassung der Risikobeurteilung |
| `hazard_log_combined` | Tabellarisches Gefaehrdungsprotokoll |
| `essential_requirements` | Grundlegende Anforderungen (MVO Anhang III) |
| `design_specifications` | Konstruktionsdaten und Zeichnungen |
| `test_reports` | Pruefberichte und Verifikationsergebnisse |
| `standards_applied` | Angewandte harmonisierte Normen |
| `declaration_of_conformity` | EU-Konformitaetserklaerung (MVO Anhang IV) |
| `component_list` | Komponentenverzeichnis |
| `classification_report` | Regulatorische Klassifikation |
| `mitigation_report` | Massnahmen nach 3-Stufen-Hierarchie |
| `verification_report` | Verifikationsplan und Ergebnisse |
| `evidence_index` | Nachweisdokumenten-Index |
| `instructions_for_use` | Sicherheitshinweise / Betriebsanleitung |
| `monitoring_plan` | Post-Market Surveillance Plan |
| `ai_intended_purpose` | KI: Bestimmungsgemaesser Zweck |
| `ai_model_description` | KI: Modellbeschreibung und Trainingsdaten |
| `ai_risk_management` | KI: Risikomanagementsystem |
| `ai_human_oversight` | KI: Menschliche Aufsicht |
#### TipTap Rich-Text-Editor (Frontend)
Die Tech-File-Sektionen werden im Frontend mit einem TipTap WYSIWYG-Editor bearbeitet (`components/sdk/iace/TechFileEditor.tsx`):
| Feature | Beschreibung |
|---------|--------------|
| Toolbar | Bold, Italic, Headings (H2-H4), Bullet/Ordered Lists, Tabelle, Blockquote, Code, Undo/Redo |
| Auto-Save | Debounced (3 Sekunden nach letzter Aenderung), ruft `PUT /tech-file/:section` auf |
| Read-Only | Fuer freigegebene Sektionen (`status: approved`) |
| Markdown-Import | LLM-generierter Markdown-Content wird automatisch in TipTap-Nodes konvertiert |
| HTML-Speicherung | `editor.getHTML()` → Backend speichert HTML in `iace_tech_file_sections.content` |
**Pakete (alle MIT-Lizenz):**
`@tiptap/react`, `@tiptap/starter-kit`, `@tiptap/extension-table`, `@tiptap/extension-table-row`,
`@tiptap/extension-table-header`, `@tiptap/extension-table-cell`, `@tiptap/extension-image`, `@tiptap/pm`
**Workflow:**
1. Sektion generieren → LLM liefert Markdown
2. TipTap konvertiert Markdown → ProseMirror-Nodes
3. Benutzer bearbeitet im WYSIWYG-Editor
4. Auto-Save speichert HTML im Backend
5. Export rendert HTML → PDF/DOCX/Excel/Markdown
### Post-Market Monitoring
@@ -207,40 +457,59 @@ Die Controls-Library enthaelt **200 Eintraege** in 6 Domaenen:
---
## Completeness Gates (25)
## Completeness Gates (22)
Das Modul prueft 25 Vollstaendigkeitstore vor dem CE-Export:
Das Modul prueft 22 Vollstaendigkeitstore (20 Required, 2 Recommended) vor dem CE-Export:
| Gate | Kategorie | Pflicht |
|------|-----------|---------|
| G01 | Projekt-Grunddaten vollstaendig | ✅ Required |
| G02 | CE-Markierungsziel definiert | ✅ Required |
| G03 | Mind. 1 Komponente erfasst | ✅ Required |
| G04 | Regulatorische Klassifizierung abgeschlossen | ✅ Required |
| G05 | HARA-Dokument vorhanden (Evidence) | ✅ Required |
| G06 | Mind. 1 Gefaehrdung identifiziert | ✅ Required |
| G07 | Alle Gefaehrdungen bewertet | ✅ Required |
| G08 | Kein Restrisiko > critical ohne Akzeptanz | ✅ Required |
| G09 | Mind. 1 Minderungsmassnahme je Gefaehrdung | ✅ Required |
| G10 | Minderungsmassnahmen verifiziert | ✅ Required |
| G11 | Verifikationsplan vorhanden | ✅ Required |
| G12 | SIL/PL-Dokumentation (Evidence) | ✅ Required |
| G13 | Technische Akte generiert | ✅ Required |
| G14 | Konformitaetserklaerung bereit | ✅ Required |
| G15 | Betriebsanleitung vorhanden | ✅ Required |
| G16 | Wartungsanleitung vorhanden | Recommended |
| G17 | Post-Market Monitoring aktiv | Recommended |
| G18 | Cybersecurity-Massnahmen dokumentiert | Recommended |
| G19 | AI-spezifische Anforderungen erfuellt | Recommended (bei AI) |
| G20 | Kalibrierprotokolle vorhanden | Recommended |
| G21 | SBOM generiert | Optional |
| G22 | Penetrationstest durchgefuehrt | Optional |
| G23 | EMV-Pruefung dokumentiert | Optional |
| G24 | Lebenszyklusplan vorhanden | Optional |
| G25 | Monitoring-Ereignisse protokolliert | Optional |
### Onboarding (G01-G09)
| Gate | Label | Pflicht |
|------|-------|---------|
| G01 | Machine identity set | ✅ Required |
| G02 | Intended use described | ✅ Required |
| G03 | Operating limits defined | ✅ Required |
| G04 | Foreseeable misuse documented | ✅ Required |
| G05 | Component tree exists | ✅ Required |
| G06 | AI classification done (if applicable) | ✅ Required |
| G07 | Safety relevance marked | ✅ Required |
| G08 | Manufacturer info present | ✅ Required |
| G09 | Pattern matching performed | Recommended |
### Klassifizierung (G10-G13)
| Gate | Label | Pflicht |
|------|-------|---------|
| G10 | AI Act classification complete | ✅ Required |
| G11 | Machinery Regulation check done | ✅ Required |
| G12 | NIS2 check done | ✅ Required |
| G13 | CRA check done | ✅ Required |
### Gefaehrdungen & Risiko (G20-G24)
| Gate | Label | Pflicht |
|------|-------|---------|
| G20 | Hazards identified | ✅ Required |
| G21 | All hazards assessed | ✅ Required |
| G22 | Critical/High risks mitigated | ✅ Required |
| G23 | **Mitigations verified** | ✅ Required |
| G24 | Residual risk accepted | ✅ Required |
!!! warning "G23 — Strenge Verifikationspflicht"
Alle Mitigations muessen den Status `verified` oder `rejected` haben. Mitigations im Status `planned` oder `implemented` blockieren den Export. Dies stellt sicher, dass keine Massnahme unueberprueft bleibt.
### Evidence & Tech File (G30, G40-G42)
| Gate | Label | Pflicht |
|------|-------|---------|
| G30 | Test evidence linked | Recommended |
| G40 | Risk assessment report generated | ✅ Required |
| G41 | Hazard log generated | ✅ Required |
| G42 | AI documents present (if applicable) | ✅ Required |
**Completeness Score:** `(passed_required/total_required)*80 + (passed_recommended/total_recommended)*15 + (passed_optional/total_optional)*5`
**CanExport** ist nur `true`, wenn alle Required-Gates bestanden sind.
---
## CE RAG-Corpus
@@ -290,19 +559,30 @@ curl -sk https://macmini:8093/sdk/v1/iace/controls-library | python3 -c "import
---
## Beispiel: Risikobewertung mit Avoidance
## Beispiel: Risikobewertung
### Legacy-Modus (A=0)
```bash
curl -sk -X POST https://macmini:8093/sdk/v1/iace/projects/{id}/hazards/{hid}/assess \
-H "Content-Type: application/json" \
-H "X-Tenant-Id: <tenant-uuid>" \
-d '{"severity": 5, "exposure": 3, "probability": 3, "avoidance": 0}'
```
Ergebnis: `R = 5 × 3 × 3 = 45` → **high**
### ISO-Modus (A >= 1)
```bash
# Risikobewertung mit Avoidance-Faktor (A=5: nicht vermeidbar)
curl -sk -X POST https://macmini:8093/sdk/v1/iace/projects/{id}/hazards/{hid}/assess \
-H "Content-Type: application/json" \
-H "X-Tenant-Id: <tenant-uuid>" \
-d '{
"hazard_id": "<hid>",
"severity": 5,
"exposure": 3,
"probability": 3,
"avoidance": 5,
"avoidance": 4,
"control_maturity": 2,
"control_coverage": 0.6,
"test_evidence_strength": 0.5,
@@ -310,9 +590,7 @@ curl -sk -X POST https://macmini:8093/sdk/v1/iace/projects/{id}/hazards/{hid}/as
}'
```
Ohne Avoidance (A=0): `InherentRisk = 5×3×3 = 45`
Mit Avoidance A=5: `InherentRisk = 5×3×3×(5/3) = 75` (kritisch!)
Mit Avoidance A=1: `InherentRisk = 5×3×3×(1/3) = 15` (medium)
Ergebnis: `R = 5 × 3 × 3 × 4 = 180`**very_high** (ISO-Schwellwerte)
---
@@ -330,6 +608,112 @@ curl -sk "https://macmini:8093/sdk/v1/iace/controls-library?category=software_fa
---
## Hazard-Matching-Engine
Die Pattern Engine automatisiert die Ableitung von Gefaehrdungen, Schutzmassnahmen und Nachweisen aus der Maschinenkonfiguration.
### Komponentenbibliothek (120 Eintraege)
```bash
# Alle Komponenten abrufen
curl -sk "https://macmini:8093/sdk/v1/iace/component-library" | python3 -c \
"import sys,json; d=json.load(sys.stdin); print(f'{d[\"total\"]} Komponenten in {len(set(c[\"category\"] for c in d[\"components\"]))} Kategorien')"
# Nach Kategorie filtern
curl -sk "https://macmini:8093/sdk/v1/iace/component-library?category=mechanical"
```
| Kategorie | IDs | Anzahl | Beispiele |
|-----------|-----|--------|-----------|
| mechanical | C001-C020 | 20 | Roboterarm, Greifer, Foerderband |
| structural | C021-C030 | 10 | Maschinenrahmen, Schutzgehaeuse |
| drive | C031-C040 | 10 | Elektromotor, Servomotor |
| hydraulic | C041-C050 | 10 | Hydraulikpumpe, -zylinder |
| pneumatic | C051-C060 | 10 | Pneumatikzylinder, Kompressor |
| electrical | C061-C070 | 10 | Schaltschrank, Stromversorgung |
| control | C071-C080 | 10 | SPS, Sicherheits-SPS, HMI |
| sensor | C081-C090 | 10 | Positionssensor, Kamerasystem |
| actuator | C091-C100 | 10 | Magnetventil, Linearantrieb |
| safety | C101-C110 | 10 | Not-Halt, Lichtgitter |
| it_network | C111-C120 | 10 | Switch, Router, Firewall |
### Energiequellen (20 Eintraege)
```bash
curl -sk "https://macmini:8093/sdk/v1/iace/energy-sources"
```
### Tag-Taxonomie (~85 Tags)
| Domaene | Anzahl | Beispiele |
|---------|--------|-----------|
| component | ~30 | moving_part, rotating_part, high_voltage, networked, has_ai |
| energy | ~15 | kinetic, rotational, electrical_energy, hydraulic_pressure |
| hazard | ~20 | crush_risk, shear_risk, electric_shock_risk, cyber_risk |
| measure | ~10 | guard_measure, interlock_measure, software_safety_measure |
| evidence | ~10 | design_evidence, test_evidence, cyber_evidence |
```bash
# Alle Tags einer Domaene
curl -sk "https://macmini:8093/sdk/v1/iace/tags?domain=component"
```
### Hazard Patterns (102 Regeln: 44 builtin + 58 extended)
Jedes Pattern definiert required_component_tags (AND), required_energy_tags (AND) und excluded_component_tags (NOT). Die Engine prueft alle Patterns gegen die aufgeloesten Tags der Projektkomponenten.
**Builtin (HP001-HP044):** Abstrakte Tag-basierte Patterns fuer 9 Domaenen (mechanisch, elektrisch, thermisch, hydraulik/pneumatik, laerm, ergonomie, software, cyber, KI).
**Extended (HP045-HP102):** 58 zusaetzliche Patterns aus der Rule Library (R051-R1550). Diese ergaenzen die Builtin-Patterns um komponentenspezifische Regeln mit Lebensphase-Einschraenkung.
```bash
# Patterns auflisten
curl -sk "https://macmini:8093/sdk/v1/iace/hazard-patterns" | python3 -c \
"import sys,json; d=json.load(sys.stdin); print(f'{d[\"total\"]} Patterns')"
```
### Pattern-Matching Workflow
```bash
# 1. Pattern-Matching ausfuehren
curl -sk -X POST "https://macmini:8093/sdk/v1/iace/projects/{id}/match-patterns" \
-H "Content-Type: application/json" \
-d '{"component_library_ids": ["C001","C071"], "energy_source_ids": ["EN01","EN07"]}'
# 2. Ergebnisse uebernehmen
curl -sk -X POST "https://macmini:8093/sdk/v1/iace/projects/{id}/apply-patterns" \
-H "Content-Type: application/json" \
-d '{"accepted_hazards": [...], "accepted_measures": [...], "accepted_evidence": [...]}'
# 3. Pro-Hazard Massnahmen vorschlagen
curl -sk -X POST "https://macmini:8093/sdk/v1/iace/projects/{id}/hazards/{hid}/suggest-measures"
# 4. Pro-Massnahme Nachweise vorschlagen
curl -sk -X POST "https://macmini:8093/sdk/v1/iace/projects/{id}/mitigations/{mid}/suggest-evidence"
```
### RAG-Anreicherung (Phase 6)
IACE-Bibliotheken (Hazards, Komponenten, Energiequellen, Massnahmen, Nachweise) sind als RAG-Corpus in Qdrant verfuegbar (`bp_iace_libraries`).
```bash
# Semantische Suche in der IACE-Bibliothek
curl -sk -X POST "https://macmini:8093/sdk/v1/iace/library-search" \
-H "Content-Type: application/json" \
-d '{"query": "Quetschgefahr Roboterarm", "top_k": 5}'
# Tech-File-Abschnitt mit RAG-Kontext anreichern
curl -sk -X POST "https://macmini:8093/sdk/v1/iace/projects/{id}/tech-file/risk_assessment_report/enrich"
```
**Ingestion:**
```bash
# IACE-Bibliotheken in Qdrant ingestieren (auf Mac Mini)
bash ~/Projekte/breakpilot-compliance/scripts/ingest-iace-libraries.sh
```
---
## Datenbank-Tabellen
| Tabelle | Beschreibung |
@@ -338,11 +722,38 @@ curl -sk "https://macmini:8093/sdk/v1/iace/controls-library?category=software_fa
| `iace_components` | System-Komponenten |
| `iace_regulatory_classifications` | Regulierungsklassifizierungen |
| `iace_hazard_library` | Benutzerdefinierte Hazard-Templates |
| `iace_hazards` | Projektspezifische Gefaehrdungen |
| `iace_risk_assessments` | SEPA-Risikobewertungen (inkl. avoidance) |
| `iace_hazards` | Projektspezifische Gefaehrdungen (inkl. lifecycle_phase, affected_person, trigger_event) |
| `iace_risk_assessments` | Risikobewertungen (Legacy S×E×P + ISO S×F×P×A) |
| `iace_mitigations` | Minderungsmassnahmen |
| `iace_verification_plans` | Verifikationsplaene |
| `iace_evidence` | Nachweise (Uploads) |
| `iace_tech_file_sections` | CE-Akte-Abschnitte |
| `iace_monitoring_events` | Post-Market-Ereignisse |
| `iace_audit_trail` | Unveraenderbares Audit-Log |
| `iace_lifecycle_phases` | 25 Lebensphasen (DE/EN) |
| `iace_roles` | 20 betroffene Personengruppen (DE/EN) |
| `iace_evidence_types` | 50 Nachweistypen in 7 Kategorien |
| `iace_component_library` | 120 Maschinenkomponenten (C001-C120) |
| `iace_energy_sources` | 20 Energiequellen (EN01-EN20) |
| `iace_pattern_results` | Audit-Trail fuer Pattern-Matching |
---
## Rechtlicher Hinweis — Normenreferenz
!!! warning "Urheberrecht bei Normen"
Saemtliche Inhalte des IACE-Moduls (Gefaehrdungsbibliothek, Schutzmassnahmen-Katalog,
Risikomodell, Lebensphasen, Rollen) sind **eigenstaendig formuliert**. Normen wie
ISO 12100, DIN EN 62443, IEC 61508 etc. werden ausschliesslich als **Methodenreferenz**
in den Metadaten gefuehrt (z.B. `"methodology_reference": "ISO 12100"`).
Es wird **kein normativer Text** reproduziert — keine Tabellen, Risikoklassifikationen,
Prozesstexte oder Checklisten aus Normen. Dies ist konform mit §51 UrhG (Zitatrecht).
Fuer die Anwendung der vollstaendigen Normen muss die jeweilige Norm separat
ueber DIN Media (beuth.de) oder ISO erworben werden.
**Beispiel fuer konforme Normenreferenz in generierten Dokumenten:**
> Die Risikobeurteilung wurde unter Beruecksichtigung allgemein anerkannter Methoden
> der Maschinensicherheit durchgefuehrt (u.a. angelehnt an ISO 12100).
@@ -0,0 +1,292 @@
# Loeschfristen — Loeschkonzept (Art. 5/17/30 DSGVO)
## Uebersicht
Das Loeschfristen-Modul implementiert ein vollstaendiges, auditfaehiges Loeschkonzept gemaess DSGVO Art. 5 Abs. 1 lit. e (Speicherbegrenzung), Art. 17 (Recht auf Loeschung) und Art. 30 (Dokumentation der Loeschfristen im VVT).
**Kernfunktionen:**
- 3-Level-Loeschlogik (Zweckende → Aufbewahrungspflicht → Legal Hold)
- 25 vordefinierte Baseline-Templates fuer gaengige Datenobjekte
- 4-Schritt-Profiling-Wizard zur automatischen Policy-Generierung
- 11 automatisierte Compliance-Checks
- Druckfertiges Loeschkonzept-Dokument mit 11 Sektionen
- JSON/CSV/Markdown-Export
## 3-Level Loeschlogik
Die Loeschung personenbezogener Daten folgt einer dreistufigen Priorisierung:
```mermaid
graph TD
A[Daten erhoben] --> B{Zweck erfuellt?}
B -->|Ja| C{Aufbewahrungspflicht?}
B -->|Nein| D[Weiter speichern]
C -->|Ja| E{Frist abgelaufen?}
C -->|Nein| F{Legal Hold?}
E -->|Ja| F
E -->|Nein| G[Aufbewahren bis Fristende]
F -->|Ja| H[Speichern bis Legal Hold endet]
F -->|Nein| I[Loeschung durchfuehren]
```
| Level | Trigger | Beschreibung |
|-------|---------|--------------|
| 1 | **Zweckende** | Daten werden geloescht, wenn der Verarbeitungszweck entfaellt |
| 2 | **Aufbewahrungspflicht** | Gesetzliche Aufbewahrungsfristen verlaengern die Speicherung |
| 3 | **Legal Hold** | Aktive Legal Holds setzen die Loeschung aus |
## Frontend — 5-Tab-Aufbau
### Tab 1: Uebersicht
Statistik-Dashboard mit Filterung und Suche:
- Gesamtanzahl Policies, Status-Verteilung, ueberfaellige Pruefungen
- Suche nach Datenobjekt, Tags und Status
- Schnellaktionen: Bearbeiten, Klonen, Archivieren
### Tab 2: Editor
Vollstaendiges Bearbeitungsformular mit 35+ Feldern:
- Stammdaten (Datenobjekt, Beschreibung, Betroffenengruppen, Datenkategorien)
- 3-Level-Loeschlogik (Trigger, Aufbewahrungstreiber, Frist, Startereignis)
- Loeschmethode und -details
- Speicherorte (Typ, Provider, Backup-Kennzeichnung)
- Legal Hold Management (Hinzufuegen, Aktivieren, Aufheben)
- Verantwortlichkeiten und VVT-Verknuepfung
- Status-Workflow (Entwurf → Aktiv → Pruefung erforderlich → Archiviert)
### Tab 3: Generator
4-Schritt-Profiling-Wizard mit 16 Fragen:
1. **Organisation** (4 Fragen): Branche, Mitarbeiterzahl, Geschaeftsmodell, Website
2. **Datenkategorien** (5 Fragen): HR, Buchhaltung, Vertraege, Marketing, Video
3. **Systeme** (4 Fragen): Cloud, Backup, ERP/CRM, Zutrittskontrolle
4. **Spezielle Anforderungen** (3 Fragen): Legal Hold, Langzeitarchivierung, Gesundheitsdaten
Der Wizard generiert automatisch passende Policies aus dem Baseline-Katalog.
### Tab 4: Export & Compliance
- **JSON-Export**: Vollstaendiger Policy-Export als JSON
- **CSV-Export**: Excel-kompatibel mit BOM und Semikolon-Trennung
- **Compliance-Bericht**: Markdown-formatierter Bericht mit Score und Empfehlungen
- **11 Compliance-Checks**: Automatisierte Pruefung aller Policies
### Tab 5: Loeschkonzept-Dokument
Druckfertiges Loeschkonzept mit 11 Sektionen:
| # | Sektion | Inhalt |
|---|---------|--------|
| 0 | Deckblatt | Organisation, DSB, Version, Datum |
| — | Inhaltsverzeichnis | Auto-generiert |
| 1 | Ziel und Zweck | DSGVO Art. 5/17/30 Bezug |
| 2 | Geltungsbereich | Systeme, Speicherorte |
| 3 | Grundprinzipien | 5 Kernprinzipien |
| 4 | Loeschregeln-Uebersicht | Tabelle aller Policies |
| 5 | Detaillierte Loeschregeln | Pro Policy: Alle Felder |
| 6 | VVT-Verknuepfung | Cross-Referenz-Tabelle |
| 7 | Legal Hold Verfahren | Prozedur + aktive Holds |
| 8 | Verantwortlichkeiten | Rollenmatrix |
| 9 | Pruef-/Revisionszyklus | Review-Zeitplan |
| 10 | Compliance-Status | Score, Issues |
| 11 | Aenderungshistorie | Versionstabelle |
**Ausgabe:** HTML-Download oder PDF-Druck via Browser.
## Backend API (7 Endpoints)
| Methode | Pfad | Beschreibung |
|---------|------|--------------|
| `GET` | `/api/v1/compliance/loeschfristen` | Alle Policies abrufen (mit Pagination) |
| `POST` | `/api/v1/compliance/loeschfristen` | Neue Policy erstellen |
| `GET` | `/api/v1/compliance/loeschfristen/{id}` | Einzelne Policy abrufen |
| `PUT` | `/api/v1/compliance/loeschfristen/{id}` | Policy aktualisieren |
| `DELETE` | `/api/v1/compliance/loeschfristen/{id}` | Policy loeschen |
| `GET` | `/api/v1/compliance/loeschfristen/stats` | Statistik-Uebersicht |
| `PATCH` | `/api/v1/compliance/loeschfristen/{id}/status` | Status aendern |
## Datenbank-Schema
Tabelle: `compliance_loeschfristen`
| Spalte | Typ | Beschreibung |
|--------|-----|--------------|
| `id` | UUID (PK) | Datenbank-ID |
| `tenant_id` | UUID | Mandant |
| `project_id` | UUID | Projekt |
| `policy_id` | VARCHAR | Display-ID (LF-2026-001) |
| `data_object_name` | VARCHAR | Datenobjekt |
| `description` | TEXT | Beschreibung |
| `affected_groups` | JSONB | Betroffenengruppen |
| `data_categories` | JSONB | Datenkategorien |
| `primary_purpose` | TEXT | Verarbeitungszweck |
| `deletion_trigger` | VARCHAR | Loeschtrigger |
| `retention_driver` | VARCHAR | Aufbewahrungstreiber |
| `retention_driver_detail` | TEXT | Detail zum Treiber |
| `retention_duration` | INTEGER | Aufbewahrungsdauer |
| `retention_unit` | VARCHAR | Einheit (DAYS/MONTHS/YEARS) |
| `retention_description` | TEXT | Beschreibung der Frist |
| `start_event` | VARCHAR | Startereignis |
| `has_active_legal_hold` | BOOLEAN | Legal Hold aktiv? |
| `legal_holds` | JSONB | Legal Holds (Array) |
| `storage_locations` | JSONB | Speicherorte (Array) |
| `deletion_method` | VARCHAR | Loeschmethode |
| `deletion_method_detail` | TEXT | Detail zur Methode |
| `responsible_role` | VARCHAR | Verantwortliche Rolle |
| `responsible_person` | VARCHAR | Verantwortliche Person |
| `release_process` | TEXT | Freigabeprozess |
| `linked_vvt_activity_ids` | JSONB | VVT-Verknuepfungen |
| `status` | VARCHAR | Status |
| `last_review_date` | TIMESTAMP | Letzte Pruefung |
| `next_review_date` | TIMESTAMP | Naechste Pruefung |
| `review_interval` | VARCHAR | Pruefintervall |
| `tags` | JSONB | Tags |
| `created_at` | TIMESTAMP | Erstellt am |
| `updated_at` | TIMESTAMP | Geaendert am |
Migration: `backend-compliance/migrations/017_loeschfristen.sql`
## Baseline-Katalog (25 Templates)
| # | Template-ID | Datenobjekt | Treiber | Frist | Trigger |
|---|-------------|-------------|---------|-------|---------|
| 1 | `personal-akten` | Personalakten | AO 147 | 10 Jahre | Aufbewahrungspflicht |
| 2 | `buchhaltungsbelege` | Buchhaltungsbelege | HGB 257 | 10 Jahre | Aufbewahrungspflicht |
| 3 | `rechnungen` | Rechnungen | UStG 14b | 10 Jahre | Aufbewahrungspflicht |
| 4 | `geschaeftsbriefe` | Geschaeftsbriefe | HGB 257 | 6 Jahre | Aufbewahrungspflicht |
| 5 | `bewerbungsunterlagen` | Bewerbungsunterlagen | AGG 15 | 6 Monate | Aufbewahrungspflicht |
| 6 | `kundenstammdaten` | Kundenstammdaten | BGB 195 | 3 Jahre | Aufbewahrungspflicht |
| 7 | `newsletter-einwilligungen` | Newsletter-Einwilligungen | — | Bis Widerruf | Zweckende |
| 8 | `webserver-logs` | Webserver-Logs | BSIG | 7 Tage | Aufbewahrungspflicht |
| 9 | `videoueberwachung` | Videoueberwachung | BDSG 35 | 2 Tage | Aufbewahrungspflicht |
| 10 | `gehaltsabrechnungen` | Gehaltsabrechnungen | AO 147 | 10 Jahre | Aufbewahrungspflicht |
| 11 | `vertraege` | Vertraege | HGB 257 | 10 Jahre | Aufbewahrungspflicht |
| 12 | `zeiterfassung` | Zeiterfassungsdaten | ArbZG 16 | 2 Jahre | Aufbewahrungspflicht |
| 13 | `krankmeldungen` | Krankmeldungen | BGB 195 | 3 Jahre | Aufbewahrungspflicht |
| 14 | `steuererklaerungen` | Steuererklaerungen | AO 147 | 10 Jahre | Aufbewahrungspflicht |
| 15 | `protokolle-gesellschafter` | Gesellschafterprotokolle | HGB 257 | 10 Jahre | Aufbewahrungspflicht |
| 16 | `crm-kontakthistorie` | CRM-Kontakthistorie | BGB 195 | 3 Jahre | Aufbewahrungspflicht |
| 17 | `backup-daten` | Backup-Daten | BSIG | 90 Tage | Aufbewahrungspflicht |
| 18 | `cookie-consent-logs` | Cookie-Consent-Nachweise | BGB 195 | 3 Jahre | Aufbewahrungspflicht |
| 19 | `email-archivierung` | E-Mail-Archivierung | HGB 257 | 6 Jahre | Aufbewahrungspflicht |
| 20 | `zutrittsprotokolle` | Zutrittsprotokolle | BSIG | 90 Tage | Aufbewahrungspflicht |
| 21 | `schulungsnachweise` | Schulungsnachweise | Individuell | 3 Jahre | Aufbewahrungspflicht |
| 22 | `betriebsarzt-doku` | Betriebsarzt-Dokumentation | Individuell | 40 Jahre | Aufbewahrungspflicht |
| 23 | `kundenreklamationen` | Kundenreklamationen | BGB 195 | 3 Jahre | Aufbewahrungspflicht |
| 24 | `lieferantenbewertungen` | Lieferantenbewertungen | HGB 257 | 6 Jahre | Aufbewahrungspflicht |
| 25 | `social-media-daten` | Social-Media-Marketingdaten | — | Bis Zweckende | Zweckende |
## 9 Aufbewahrungstreiber
| Treiber | Gesetz | Standard-Frist | Beschreibung |
|---------|--------|----------------|--------------|
| `AO_147` | 147 AO | 10 Jahre | Steuerrelevante Unterlagen |
| `HGB_257` | 257 HGB | 10/6 Jahre | Handelsbuecher, -briefe |
| `USTG_14B` | 14b UStG | 10 Jahre | Rechnungen |
| `BGB_195` | 195 BGB | 3 Jahre | Regelmaessige Verjaehrung |
| `ARBZG_16` | 16 Abs. 2 ArbZG | 2 Jahre | Arbeitszeitaufzeichnungen |
| `AGG_15` | 15 Abs. 4 AGG | 6 Monate | Entschaedigungsansprueche |
| `BDSG_35` | 35 BDSG / Art. 17 DSGVO | Unverzueglich | Zweckwegfall |
| `BSIG` | BSIG / IT-SiG 2.0 | 90 Tage | Sicherheitslogs |
| `CUSTOM` | Individuell | — | Benutzerdefiniert |
## 6 Loeschmethoden
| Methode | Beschreibung |
|---------|--------------|
| `AUTO_DELETE` | Automatische Loeschung durch System-Job |
| `MANUAL_REVIEW_DELETE` | Manuelle Pruefung vor Loeschung |
| `ANONYMIZATION` | Anonymisierung (Statistik bleibt erhalten) |
| `AGGREGATION` | Statistische Verdichtung |
| `CRYPTO_ERASE` | Kryptographische Loeschung (Key Destruction) |
| `PHYSICAL_DESTROY` | Physische Vernichtung (DIN 66399) |
## Profiling Wizard (4 Schritte, 16 Fragen)
Der Profiling-Wizard generiert automatisch passende Loeschrichtlinien basierend auf dem Unternehmensprofil.
| Schritt | Titel | Fragen | Inhalt |
|---------|-------|--------|--------|
| 1 | Organisation | 4 | Branche, Groesse, Geschaeftsmodell, Website |
| 2 | Datenkategorien | 5 | HR, Buchhaltung, Vertraege, Marketing, Video |
| 3 | Systeme & Infrastruktur | 4 | Cloud, Backup, ERP/CRM, Zutrittskontrolle |
| 4 | Spezielle Anforderungen | 3 | Legal Hold, Archivierung, Gesundheitsdaten |
**Regelbeispiele:**
- `data-hr = true` → Personalakten, Gehaltsabrechnungen, Zeiterfassung, Bewerbungen, Krankmeldungen, Schulungsnachweise
- `data-buchhaltung = true` → Buchhaltungsbelege, Rechnungen, Steuererklaerungen
- `data-vertraege = true` → Vertraege, Geschaeftsbriefe, Kundenstammdaten, Kundenreklamationen, Lieferantenbewertungen
- `data-marketing = true` → Newsletter, CRM-Kontakthistorie, Cookie-Consent, Social-Media-Daten
- `sys-zutritt = true` → Zutrittsprotokolle
- `sys-cloud = true` → E-Mail-Archivierung
- `special-gesundheit = true` → Krankmeldungen, Betriebsarzt-Dokumentation
## Compliance Checker (11 Pruefungen)
| # | Check-Typ | Schweregrad | Ausloeser |
|---|-----------|-------------|-----------|
| 1 | `MISSING_TRIGGER` | HIGH | Policy ohne Loeschtrigger |
| 2 | `MISSING_LEGAL_BASIS` | HIGH | Aufbewahrungspflicht ohne Rechtsgrundlage |
| 3 | `OVERDUE_REVIEW` | MEDIUM | Ueberfaellige Pruefung |
| 4 | `NO_RESPONSIBLE` | MEDIUM | Keine Verantwortliche Person/Rolle |
| 5 | `LEGAL_HOLD_CONFLICT` | CRITICAL | Legal Hold + Auto-Delete aktiv |
| 6 | `STALE_DRAFT` | LOW | Entwurf aelter als 90 Tage |
| 7 | `UNCOVERED_VVT_CATEGORY` | MEDIUM | VVT-Datenkategorie ohne Loeschfrist |
| 8 | `MISSING_DELETION_METHOD` | MEDIUM | Aktive Policy ohne Loeschmethoden-Detail |
| 9 | `MISSING_STORAGE_LOCATIONS` | MEDIUM | Aktive Policy ohne Speicherorte |
| 10 | `EXCESSIVE_RETENTION` | HIGH | Frist > 2x gesetzliches Maximum |
| 11 | `MISSING_DATA_CATEGORIES` | LOW | Nicht-Entwurf ohne Datenkategorien |
**Score-Berechnung:** `100 - (CRITICAL*15 + HIGH*10 + MEDIUM*5 + LOW*2)`
## Cross-Modul-Integration
### VVT-Verknuepfung
Jede Loeschregel kann mit Verarbeitungstaetigkeiten aus dem VVT verknuepft werden (`linked_vvt_activity_ids`). Das Loeschkonzept-Dokument generiert automatisch eine Cross-Referenz-Tabelle (Sektion 6).
### Scope Engine Prefill
Der Profiling-Wizard kann Antworten aus der Compliance Scope Engine uebernehmen. 12 Fragen werden automatisch vorausgefuellt:
- `org-branche`, `org-mitarbeiter`, `org-geschaeftsmodell`, `org-website`
- `data-hr`, `data-buchhaltung`, `data-vertraege`, `data-marketing`, `data-video`
- `sys-cloud`, `sys-erp`
### Document Generator Template
Das Loeschkonzept kann als eigenstaendiges Template im Document Generator genutzt werden (Template-Typ: `loeschkonzept`).
## Audit-Faehigkeit
Das Loeschkonzept erfuellt folgende Audit-Kriterien:
1. **Vollstaendigkeit:** Alle Datenobjekte mit Loeschfristen, Rechtsgrundlagen und Methoden dokumentiert
2. **Nachvollziehbarkeit:** Aenderungshistorie mit Versionsnummern und Autoren
3. **Aktualitaet:** Definiertes Pruefintervall mit automatischer Ueberfaelligkeits-Erkennung
4. **Verantwortlichkeit:** Rollenmatrix mit klaren Zustaendigkeiten
5. **Cross-Referenz:** Verknuepfung mit VVT (Art. 30 DSGVO)
6. **Compliance-Nachweis:** Automatisierte 11-Punkt-Pruefung mit Score und Befundprotokoll
7. **Druckfertigkeit:** PDF-taugliches Dokument mit Deckblatt, Inhaltsverzeichnis und rechtlichen Verweisen
## Datei-Uebersicht
| Datei | Beschreibung |
|-------|--------------|
| `admin-compliance/app/sdk/loeschfristen/page.tsx` | Frontend-Seite (5 Tabs) |
| `admin-compliance/lib/sdk/loeschfristen-types.ts` | TypeScript-Typen und Konstanten |
| `admin-compliance/lib/sdk/loeschfristen-baseline-catalog.ts` | 25 Baseline-Templates |
| `admin-compliance/lib/sdk/loeschfristen-profiling.ts` | 4-Schritt-Profiling-Wizard |
| `admin-compliance/lib/sdk/loeschfristen-compliance.ts` | 11 Compliance-Checks |
| `admin-compliance/lib/sdk/loeschfristen-export.ts` | JSON/CSV/Markdown-Export |
| `admin-compliance/lib/sdk/loeschfristen-document.ts` | Loeschkonzept-Dokument-Generator |
| `backend-compliance/compliance/api/loeschfristen_routes.py` | Backend API-Routen |
| `backend-compliance/compliance/db/loeschfristen_models.py` | SQLAlchemy-Modelle |
| `backend-compliance/migrations/017_loeschfristen.sql` | Datenbank-Migration |
| `backend-compliance/tests/test_loeschfristen_routes.py` | Backend-Tests (58+) |
@@ -0,0 +1,201 @@
# Normative Verbindlichkeit — Dreistufenmodell
## Uebersicht
Nicht jede Quelle, aus der Controls abgeleitet werden, hat die gleiche rechtliche
Verbindlichkeit. Ein Control, das aus einem EU-Gesetz stammt, hat ein anderes
Gewicht als eines aus einem freiwilligen Framework.
Das Dreistufenmodell klassifiziert jede Quell-Regulierung und leitet daraus die
**effektive normative Staerke** der daraus erzeugten Obligations ab.
## Die drei Stufen
```mermaid
graph TB
subgraph "Stufe 1 — GESETZ (law)"
direction LR
A1["DSGVO, NIS2, AI Act, CRA..."]
A2["Rechtlich bindend"]
A3["Bussgeld bei Verstoss"]
A4["normative_strength: must/should/may"]
end
subgraph "Stufe 2 — LEITLINIE (guideline)"
direction LR
B1["EDPB-Leitlinien, BSI-TR, WP29"]
B2["Offizielle Auslegungshilfe"]
B3["Beweislastumkehr"]
B4["max normative_strength: should"]
end
subgraph "Stufe 3 — FRAMEWORK (framework)"
direction LR
C1["ENISA, NIST, OWASP, OECD"]
C2["Freiwillige Best Practice"]
C3["Stand der Technik"]
C4["max normative_strength: can"]
end
A1 --> A2 --> A3 --> A4
B1 --> B2 --> B3 --> B4
C1 --> C2 --> C3 --> C4
```
### Stufe 1: Gesetz (law)
| Eigenschaft | Beschreibung |
|---|---|
| **Verbindlichkeit** | Rechtlich bindend, Bussgeld bei Verstoss |
| **normative_strength** | Bleibt wie im Gesetzestext: `must`, `should` oder `may` |
| **Beispiele** | DSGVO (EU) 2016/679, NIS2-Richtlinie, KI-Verordnung, CRA, BDSG |
| **Warum relevant** | "Sie MUESSEN angemessene technische Massnahmen ergreifen" (Art. 32 DSGVO) |
!!! warning "Wichtig"
Gesetze formulieren Pflichten **abstrakt**. Art. 32 DSGVO sagt:
"dem Stand der Technik entsprechende Massnahmen" — aber NICHT
"verwende AES-256". Das WAS ist Pflicht, das WIE bleibt offen.
### Stufe 2: Leitlinie (guideline)
| Eigenschaft | Beschreibung |
|---|---|
| **Verbindlichkeit** | Nicht direkt bindend, aber Beweislastumkehr |
| **normative_strength** | Maximal `should` — auch wenn die Leitlinie intern "must" schreibt |
| **Beispiele** | EDPB-Leitlinien, BSI Technische Richtlinien, WP29-Dokumente |
| **Warum relevant** | "Daten at rest muessen verschluesselt werden" (BSI-TR) → `should` |
!!! info "Beweislastumkehr"
Wenn eine Aufsichtsbehoerde fragt "Warum verschluesselt ihr nicht?",
muss die Firma begruenden, warum sie von der Leitlinie abweicht.
Die Firma muss aber nicht genau so verschluesseln wie die BSI vorschlaegt.
### Stufe 3: Framework (framework)
| Eigenschaft | Beschreibung |
|---|---|
| **Verbindlichkeit** | Freiwillig, nicht rechtsverbindlich |
| **normative_strength** | Maximal `can` — unabhaengig von interner Sprache |
| **Beispiele** | ENISA CCM, NIST CSF, OWASP Top 10, OECD KI-Empfehlung |
| **Warum relevant** | "Organizations SHALL implement..." (ENISA) → `can` fuer den Anwender |
!!! tip "Stand der Technik"
NIS2 Art. 21 verweist auf ENISA-Leitlinien als Referenz fuer den
"Stand der Technik". Das hebt ENISA-Controls faktisch auf Stufe 2 (`should`)
— aber nur im Kontext von NIS2-pflichtigen Unternehmen, nicht generell.
## Ableitungskette
Die vollstaendige Kette von der Rechtsquelle zum atomaren Control:
```mermaid
graph LR
R["Regulierung<br/>(DSGVO Art. 32)"] -->|"MUSS"| O["Obligation<br/>(Daten schuetzen)"]
O -->|decomposition| RC["Rich Control<br/>(Verschluesselung)"]
RC -->|pass0b| AC["Atomares Control<br/>(AES-256 at rest)"]
R2["Framework<br/>(ENISA CCM)"] -->|"KANN"| AC
style R fill:#fee2e2,stroke:#dc2626
style R2 fill:#dbeafe,stroke:#2563eb
style O fill:#fef3c7,stroke:#d97706
style RC fill:#e0e7ff,stroke:#4f46e5
style AC fill:#d1fae5,stroke:#059669
```
**Beispiel**: Das atomare Control "AES-256 Verschluesselung at rest"
- Aus DSGVO Art. 32 abgeleitet → Obligation "must secure data" → **MUSS** (die Pflicht zu schuetzen)
- Aus ENISA CCM konkretisiert → **KANN** (AES-256 ist *eine* moegliche Umsetzung)
- Resultat: Die Firma MUSS verschluesseln, KANN aber waehlen wie
## Multi-Parent-Links
Ein atomares Control kann aus mehreren Quellen stammen:
| Control | Parent 1 | Parent 2 | Parent 3 | Effektive Staerke |
|---|---|---|---|---|
| SEC-042 (Encrypt at rest) | DSGVO Art. 32 (law) | NIS2 Art. 21 (law) | ENISA CCM (framework) | **must** (Gesetz uebertrumpft) |
| NET-015 (Zero Trust) | NIST SP 800-207 (framework) | CISA (framework) | — | **can** (nur Frameworks) |
| AUTH-003 (MFA) | DSGVO Art. 32 (law) | BSI-TR (guideline) | OWASP ASVS (framework) | **must** (Gesetz vorhanden) |
**Regel**: Der hoechste source_type bestimmt, ob die normative_strength begrenzt wird.
Wenn mindestens ein Parent-Link ein Gesetz ist, bleibt die Staerke wie extrahiert.
## Technische Umsetzung
### Klassifikations-Map
Datei: `backend-compliance/compliance/data/source_type_classification.py`
Jeder `source_regulation`-Wert aus `control_parent_links` wird klassifiziert:
```python
SOURCE_REGULATION_CLASSIFICATION = {
"DSGVO (EU) 2016/679": "law",
"EDPB Leitlinien 01/2020 (Datentransfers)": "guideline",
"NIST Cybersecurity Framework 2.0": "framework",
# ... 55+ Eintraege
}
```
### Backfill-Endpoint
```
POST /api/compliance/v1/canonical/controls/backfill-normative-strength?dry_run=true
```
Ablauf:
1. Alle aktiven `obligation_candidates` laden
2. Fuer jede Obligation den Parent-Control finden
3. Ueber `control_parent_links` die source_regulations ermitteln
4. Hoechsten source_type bestimmen
5. `normative_strength` begrenzen falls noetig
6. Bei `dry_run=false`: Aenderungen in die DB schreiben
### Cap-Funktion
```python
def cap_normative_strength(original: str, source_type: str) -> str:
"""
cap_normative_strength("must", "framework") → "may"
cap_normative_strength("should", "law") → "should"
cap_normative_strength("must", "guideline") → "should"
"""
```
## Frontend-Anzeige
In der Control-Detail-Ansicht werden Obligations mit farbcodierten Badges angezeigt:
| normative_strength | Badge | Farbe | Bedeutung |
|---|---|---|---|
| `must` | **MUSS** | Rot | Gesetzliche Pflicht |
| `should` | **SOLL** | Gelb/Amber | Empfohlen, Begruendungspflicht bei Abweichung |
| `may` | **KANN** | Gruen | Freiwillige Best Practice |
## Haeufige Fragen
### Warum steht bei einem ENISA-Control "MUSS"?
**Vor dem Backfill**: Das System uebernahm die Sprache des Quelldokuments 1:1.
ENISA schreibt intern "shall/must" weil es innerhalb seines Frameworks
verbindlich formuliert. Fuer den Anwender ist das ENISA-Dokument aber nicht
rechtsverbindlich.
**Nach dem Backfill**: ENISA-Controls zeigen maximal "KANN", es sei denn
ein Gesetz (z.B. NIS2) referenziert dasselbe Control — dann gilt die
gesetzliche Verbindlichkeit.
### Was bedeutet "Stand der Technik"?
NIS2 und DSGVO verweisen auf den "Stand der Technik", ohne ihn zu definieren.
In der Praxis werden ENISA- und BSI-Dokumente als Referenz herangezogen.
Das macht ihre Empfehlungen relevant ("SOLL"), aber nicht zu Gesetzen ("MUSS").
### Wie gehe ich mit unbekannten Quellen um?
Neue Regulierungen muessen in der `SOURCE_REGULATION_CLASSIFICATION` Map
eingetragen werden. Der Fallback fuer unbekannte Quellen ist `framework`
(konservativstes Ergebnis — geringste Verbindlichkeit zugewiesen).
+92 -7
View File
@@ -291,17 +291,60 @@ POST /sdk/v1/ucca/obligations/gap-analysis
---
## Frontend
## Frontend — 5-Tab-Aufbau
**URL:** `https://macmini:3007/sdk/obligations`
Die Obligations-Seite zeigt:
Die Obligations-Seite ist in 5 Tabs gegliedert:
- **Überblick-Kacheln:** Gesamtanzahl, nach Priorität, nach Regulierung
- **Regulierungs-Tabs:** Pflichten gefiltert nach DSGVO, AI Act, NIS2, etc.
- **Gap-Analyse-View:** Fehlende TOM-Controls visualisiert als Heatmap
- **TOM-Control-Panel:** Mapping von Pflichten → Controls mit Status
- **Export:** C-Level-Memo (Markdown) direkt aus dem Frontend
| Tab | Inhalt |
|-----|--------|
| **Uebersicht** | Statistik-Kacheln, Compliance-Score, Regulierungs-Filter, Pflichten-Liste (Cards), Compliance-Befunde |
| **Detail-Editor** | Pflichtenliste mit Bearbeitungsfunktion, Status-/Prioritaets-Badges |
| **Profiling** | Auto-Profiling aus CompanyProfile + Compliance-Scope, anwendbare Regulierungen |
| **Gap-Analyse** | GapAnalysisView + TOMControlPanel (UCCA-Integration) |
| **Pflichtenregister** | Druckbares HTML-Dokument (12 Sektionen), Org-Header, Revisionen |
### 12 Compliance-Checks
Der Compliance-Checker (`obligations-compliance.ts`) prueft automatisch:
| # | Check | Severity | Ausloeser |
|---|-------|----------|-----------|
| 1 | `MISSING_RESPONSIBLE` | MEDIUM | Pflicht ohne Verantwortlichen |
| 2 | `OVERDUE_DEADLINE` | HIGH | Frist ueberschritten, Status != completed |
| 3 | `MISSING_EVIDENCE` | HIGH | Abgeschlossene Pflicht ohne Nachweis |
| 4 | `MISSING_DESCRIPTION` | MEDIUM | Pflicht ohne Beschreibung |
| 5 | `NO_LEGAL_REFERENCE` | HIGH | Pflicht ohne Artikel-Referenz |
| 6 | `INCOMPLETE_REGULATION` | HIGH | Regulierung mit allen Pflichten pending/overdue |
| 7 | `HIGH_PRIORITY_NOT_STARTED` | CRITICAL | Critical/High-Pflicht seit >30d pending |
| 8 | `STALE_PENDING` | LOW | Pflicht seit >90d pending |
| 9 | `MISSING_LINKED_SYSTEMS` | MEDIUM | Pflicht ohne Systemzuordnung |
| 10 | `NO_REVIEW_PROCESS` | MEDIUM | Keine Pflicht hat review_date |
| 11 | `CRITICAL_WITHOUT_EVIDENCE` | CRITICAL | Kritische Pflicht ohne Nachweis |
| 12 | `MISSING_VENDOR_LINK` | MEDIUM | Art.-28-Pflicht ohne verknuepften Auftragsverarbeiter |
**Score:** `100 - (CRITICAL*15 + HIGH*10 + MEDIUM*5 + LOW*2)`, min 0.
### Pflichtenregister-Dokument (12 Sektionen)
Das druckbare HTML-Dokument (`obligations-document.ts`) umfasst:
| # | Sektion | Datenquelle |
|---|---------|-------------|
| 0 | Deckblatt | orgHeader |
| — | Inhaltsverzeichnis | statisch |
| 1 | Ziel und Zweck | statisch |
| 2 | Geltungsbereich | orgHeader, obligations (distinct sources) |
| 3 | Methodik | statisch |
| 4 | Regulatorische Grundlagen | obligations gruppiert nach source |
| 5 | Pflichtenuebersicht | obligations nach Status |
| 6 | Detaillierte Pflichten | Pro Regulierung: Detail-Karten |
| 7 | Verantwortlichkeiten | Rollenmatrix |
| 8 | Fristen und Termine | Ueberfaellige + anstehende Deadlines |
| 9 | Nachweisverzeichnis | Evidence pro Pflicht |
| 10 | Compliance-Status | Score + Issues |
| 11 | Aenderungshistorie | Revisionstabelle |
---
@@ -333,3 +376,45 @@ cd ai-compliance-sdk && go test ./internal/ucca/... -v -run TestObligationCondit
**Weitere Tests:**
- `tom_mapper_test.go` — TOM-Mapping Tests
- `v2_loader_test.go` — JSON-Loader für Regulierungs-Dateien
- `backend-compliance/tests/test_obligation_routes.py` — 39 Backend-API-Tests
---
## Cross-Modul-Integration
| Modul | Integration |
|-------|------------|
| **VVT** | Pflichten referenzieren Verarbeitungstaetigkeiten ueber `linked_systems` |
| **TOM** | TOM-Control-Mapping (UCCA) zeigt erforderliche Massnahmen pro Pflicht |
| **Loeschfristen** | Loeschpflichten (Art. 17 DSGVO) im Pflichtenregister referenziert |
| **Vendor Compliance** | Art.-28-Pflichten verknuepfbar mit Auftragsverarbeitern ueber `linked_vendor_ids` (DB: JSONB). Compliance-Check #12 (`MISSING_VENDOR_LINK`) prueft fehlende Verknuepfung. |
| **UCCA** | Condition Engine bewertet Pflichten gegen UnifiedFacts |
| **Compliance-Scope** | Auto-Profiling nutzt Scope-Antworten fuer Regulierungs-Ableitung |
---
## Audit-Faehigkeit
Das Pflichtenregister ist auditfaehig durch:
1. **Druckbares HTML-Dokument** mit 12 Sektionen, A4-Layout, `@media print`
2. **11 automatische Compliance-Checks** mit Score (0-100) und Befunden nach Schweregrad
3. **Nachweisverzeichnis** (Sektion 9) dokumentiert Evidence pro Pflicht
4. **Aenderungshistorie** (Sektion 11) mit Version, Datum, Autor, Beschreibung
5. **Fristen-Tracking** (Sektion 8) mit ueberfaelligen und anstehenden Terminen
---
## Datei-Uebersicht
| Datei | Beschreibung |
|-------|-------------|
| `admin-compliance/app/sdk/obligations/page.tsx` | Haupt-Seite (5-Tab-Layout) |
| `admin-compliance/lib/sdk/obligations-compliance.ts` | 11 Compliance-Checks + Obligation-Type |
| `admin-compliance/lib/sdk/obligations-document.ts` | HTML-Dokument-Generator (12 Sektionen) |
| `admin-compliance/components/sdk/obligations/ObligationDocumentTab.tsx` | Pflichtenregister-Tab-Komponente |
| `admin-compliance/components/sdk/obligations/GapAnalysisView.tsx` | Gap-Analyse-Komponente |
| `admin-compliance/components/sdk/obligations/TOMControlPanel.tsx` | TOM-Control-Panel |
| `backend-compliance/compliance/api/obligation_routes.py` | 7 Backend-API-Endpoints |
| `backend-compliance/migrations/013_obligations.sql` | DB-Schema |
| `ai-compliance-sdk/policies/obligations/v2/` | 325 Pflichten, 9 Regulierungen |
@@ -0,0 +1,224 @@
# Policy-Bibliothek (Migration 054)
Die Policy-Bibliothek stellt **29 deutsche Richtlinien-Templates** bereit, die ueber den Dokumentengenerator
als Vorlagen genutzt werden koennen. Alle Templates sind nach deutschen Compliance-Standards strukturiert
und enthalten Platzhalter fuer unternehmensspezifische Anpassung.
---
## Uebersicht
| Kategorie | Anzahl | UI-Pill | Beschreibung |
|-----------|--------|---------|--------------|
| [IT-Sicherheit](#it-sicherheit-policies) | 14 | `IT-Sicherheit Policies` | Informationssicherheit, Zugriffskontrollen, Verschluesselung, Patch-Mgmt. |
| [Daten-Policies](#daten-policies) | 5 | `Daten-Policies` | Datenschutz, Klassifizierung, Aufbewahrung, Transfer |
| [Personal-Policies](#personal-policies) | 4 | `Personal-Policies` | Mitarbeitersicherheit, Awareness, Remote Work, Offboarding |
| [Lieferanten-Policies](#lieferanten-policies) | 3 | `Lieferanten-Policies` | Vendor Risk, Drittanbieter, Lieferanten-Sicherheit |
| [BCM/Notfall](#bcmnotfall) | 3 | `BCM/Notfall` | Business Continuity, Disaster Recovery, Krisenmanagement |
**Gesamt:** 29 Policy-Templates + 7 Sicherheitskonzepte (Migration 051) + 16 Basis-Dokumenttypen = **52 Dokumenttypen**
---
## Template-Struktur
Alle 29 Policy-Templates folgen einer einheitlichen **9-Abschnitte-Struktur:**
1. **Zweck** — Zielsetzung der Richtlinie
2. **Geltungsbereich** — Fuer wen gilt die Richtlinie
3. **Begriffe** — Definitionen
4. **Verantwortlichkeiten** — Rollen und Zustaendigkeiten
5. **Richtlinie** (Kern) — Die eigentlichen Regelungen
6. **Massnahmen** — Konkrete Umsetzungsschritte
7. **Ueberwachung & Audit** — Pruef- und Kontrollmechanismen
8. **Schulung** — Anforderungen an Mitarbeiterschulung
9. **Inkrafttreten** — Gueltigkeitsdatum und Freigabe
### Gemeinsame Platzhalter
| Platzhalter | Beschreibung |
|-------------|--------------|
| `{{COMPANY_NAME}}` | Firmenname |
| `{{SECURITY_OFFICER}}` / `{{ISB_NAME}}` | Informationssicherheitsbeauftragter |
| `{{GF_NAME}}` | Geschaeftsfuehrung (Freigabe) |
| `{{VERSION}}` | Dokumentversion |
| `{{DATE}}` | Erstellungsdatum |
| `{{SCOPE_DESCRIPTION}}` | Geltungsbereich |
| `{{NEXT_REVIEW_DATE}}` | Naechster Prueftermin |
---
## IT-Sicherheit Policies
14 Templates fuer die IT-Sicherheitsorganisation:
| Typ | Titel | Spezifische Platzhalter |
|-----|-------|------------------------|
| `information_security_policy` | Informationssicherheits-Richtlinie | `SCOPE_DESCRIPTION` |
| `access_control_policy` | Zugriffskontrollen-Richtlinie | `REVIEW_INTERVAL_DAYS` |
| `password_policy` | Passwort-Richtlinie | `MIN_PASSWORD_LENGTH`, `MAX_AGE_DAYS`, `HISTORY_COUNT` |
| `encryption_policy` | Verschluesselungs-Richtlinie | `MIN_KEY_LENGTH` |
| `logging_policy` | Logging-Richtlinie | `LOG_RETENTION_DAYS` |
| `backup_policy` | Backup-Richtlinie | `RPO_HOURS`, `RTO_HOURS`, `BACKUP_RETENTION_DAYS` |
| `incident_response_policy` | Incident-Response-Richtlinie | `INCIDENT_HOTLINE`, `NOTIFICATION_HOURS` |
| `change_management_policy` | Change-Management-Richtlinie | `CAB_SCHEDULE` |
| `patch_management_policy` | Patch-Management-Richtlinie | `CRITICAL_PATCH_HOURS`, `PATCH_WINDOW` |
| `asset_management_policy` | Asset-Management-Richtlinie | `INVENTORY_TOOL` |
| `cloud_security_policy` | Cloud-Sicherheits-Richtlinie | `APPROVED_PROVIDERS` |
| `devsecops_policy` | DevSecOps-Richtlinie | `CI_TOOL`, `SAST_TOOL` |
| `secrets_management_policy` | Secrets-Management-Richtlinie | `VAULT_URL`, `ROTATION_DAYS` |
| `vulnerability_management_policy` | Schwachstellenmanagement-Richtlinie | `SCAN_FREQUENCY`, `SCANNER_TOOL` |
---
## Daten-Policies
5 Templates fuer Datenschutz und Datenmanagement:
| Typ | Titel | Spezifische Platzhalter |
|-----|-------|------------------------|
| `data_protection_policy` | Datenschutz-Richtlinie | `DSB_NAME`, `DSB_EMAIL`, `SUPERVISORY_AUTHORITY` |
| `data_classification_policy` | Datenklassifizierungs-Richtlinie | `CLASSIFICATION_TOOL` |
| `data_retention_policy` | Datenaufbewahrungs-Richtlinie | `DEFAULT_RETENTION_YEARS`, `DELETION_TOOL` |
| `data_transfer_policy` | Datentransfer-Richtlinie | `DPO_EMAIL` |
| `privacy_incident_policy` | Datenschutzvorfall-Richtlinie | `DPO_EMAIL`, `NOTIFICATION_HOURS` |
---
## Personal-Policies
4 Templates fuer Mitarbeitersicherheit:
| Typ | Titel | Spezifische Platzhalter |
|-----|-------|------------------------|
| `employee_security_policy` | Mitarbeiter-Sicherheitsrichtlinie | `HR_CONTACT` |
| `security_awareness_policy` | Security-Awareness-Richtlinie | `TRAINING_FREQUENCY`, `LMS_URL` |
| `remote_work_policy` | Remote-Work-Richtlinie | `VPN_TOOL`, `MDM_TOOL` |
| `offboarding_policy` | Offboarding-Richtlinie | `HR_CONTACT`, `IT_CONTACT` |
---
## Lieferanten-Policies
3 Templates fuer die Lieferkette:
| Typ | Titel | Spezifische Platzhalter |
|-----|-------|------------------------|
| `vendor_risk_management_policy` | Lieferanten-Risikomanagement-Richtlinie | `PROCUREMENT_CONTACT`, `REVIEW_FREQUENCY` |
| `third_party_security_policy` | Drittanbieter-Sicherheitsrichtlinie | `SECURITY_CONTACT` |
| `supplier_security_policy` | Lieferanten-Sicherheitsrichtlinie | `PROCUREMENT_CONTACT` |
---
## BCM/Notfall
3 Templates fuer Business Continuity:
| Typ | Titel | Spezifische Platzhalter |
|-----|-------|------------------------|
| `business_continuity_policy` | Business-Continuity-Richtlinie | `RTO_HOURS`, `RPO_HOURS`, `BC_COORDINATOR` |
| `disaster_recovery_policy` | Disaster-Recovery-Richtlinie | `DR_SITE`, `RTO_HOURS`, `RPO_HOURS` |
| `crisis_management_policy` | Krisenmanagement-Richtlinie | `CRISIS_HOTLINE`, `CRISIS_TEAM_LEAD` |
---
## API
Die Policy-Templates werden ueber die bestehende Legal-Templates-API verwaltet:
| Methode | Pfad | Beschreibung |
|---------|------|--------------|
| `GET` | `/api/compliance/legal-templates` | Templates listen (Filter: `document_type`, `status`, `language`) |
| `GET` | `/api/compliance/legal-templates/status` | Anzahl nach Typ und Status |
| `GET` | `/api/compliance/legal-templates/{id}` | Einzelnes Template laden |
| `POST` | `/api/compliance/legal-templates` | Neues Template erstellen |
| `PUT` | `/api/compliance/legal-templates/{id}` | Template aktualisieren |
| `DELETE` | `/api/compliance/legal-templates/{id}` | Template loeschen |
### Beispiel: Policy-Templates nach Kategorie filtern
```bash
# Alle IT-Sicherheit Policies
curl "https://api-dev.breakpilot.ai/api/compliance/legal-templates?document_type=information_security_policy"
# Alle Policy-Templates (mehrere Typen)
curl "https://api-dev.breakpilot.ai/api/compliance/legal-templates/status"
```
### Beispiel: Template erstellen
```bash
curl -X POST "https://api-dev.breakpilot.ai/api/compliance/legal-templates" \
-H "Content-Type: application/json" \
-H "X-Tenant-Id: <tenant-id>" \
-d '{
"document_type": "password_policy",
"title": "Passwort-Richtlinie",
"content": "# Passwort-Richtlinie\n\n...",
"placeholders": ["{{COMPANY_NAME}}", "{{MIN_PASSWORD_LENGTH}}"],
"language": "de",
"jurisdiction": "DE"
}'
```
---
## Frontend
Die Policy-Templates sind im **Dokumentengenerator** (`/sdk/document-generator`) unter 5 neuen Kategorie-Pills erreichbar:
| UI-Pill | Enthaltene Typen |
|---------|-----------------|
| IT-Sicherheit Policies | 14 Typen (information_security_policy bis vulnerability_management_policy) |
| Daten-Policies | 5 Typen (data_protection_policy bis privacy_incident_policy) |
| Personal-Policies | 5 Typen (employee_security_policy, security_awareness_policy, acceptable_use, remote_work_policy, offboarding_policy) |
| Lieferanten-Policies | 3 Typen (vendor_risk_management_policy bis supplier_security_policy) |
| BCM/Notfall | 3 Typen (business_continuity_policy bis crisis_management_policy) |
---
## Seeding
Das Seed-Script `backend-compliance/scripts/seed_policy_templates.py` fuegt alle 29 Templates ueber die API ein:
```bash
python3 backend-compliance/scripts/seed_policy_templates.py
```
Das Script nutzt die Production-API (`https://api-dev.breakpilot.ai`) und benoetigt einen gueltigen
`X-Tenant-Id` Header. Bereits existierende Templates werden nicht dupliziert (Upsert ueber `document_type`).
---
## Tests
- **48 Tests** in `test_policy_templates.py`
- Alle 29 Dokumenttypen gegen `VALID_DOCUMENT_TYPES` validiert
- API-Akzeptanz (POST 201) fuer jeden Typ (parametrized)
- Filterung nach Kategorie (GET 200)
- Platzhalter-Validierung
- Seed-Script-Struktur (29 Templates, Pflichtfelder, deutsche Inhalte)
- Ablehnung ungeltiger Typen (400)
---
## Zusammenspiel mit anderen Modulen
```mermaid
graph LR
A[Company Profile] --> B[Compliance Engine]
B --> C[Policy-Bibliothek]
C --> D[Dokumentengenerator]
D --> E[Change-Requests]
E --> F[Document Workflow]
C --> G[Controls / Mapping-Matrix]
G --> H[Process Manager Tasks]
G --> I[Evidence Checks]
```
Die Policy-Bibliothek bildet die **Vorlage-Ebene** der geplanten Compliance Engine:
1. **CompanyProfile + Scope** → bestimmt welche Regulations/Controls relevant sind
2. **Controls** → verweisen auf relevante **Policies** aus der Bibliothek
3. **Policies** → werden ueber den Dokumentengenerator als Entwuerfe erstellt
4. **Entwuerfe** → durchlaufen den Document Workflow (Review → Freigabe → Veroeffentlichung)
@@ -412,3 +412,8 @@ Die **Einwilligungen** legen fest, welche Datenpunkte einer Einwilligung beduerf
Die **Rechtlichen Vorlagen** erstellen die zugehoerigen Dokumente (DSE, AGB, etc.).
Der **Cookie Banner** konfiguriert das Frontend-Consent-Widget.
Der **Document Workflow** fuhrt alle Dokumente durch den Freigabeprozess vor der Veroeffentlichung.
!!! info "Policy-Bibliothek (Migration 054)"
Zusaetzlich zu den rechtlichen Texten stehen **29 deutsche Richtlinien-Templates** zur Verfuegung
(IT-Sicherheit, Datenschutz, Personal, Lieferanten, BCM). Siehe
[Policy-Bibliothek](policy-bibliothek.md) fuer Details.
+271
View File
@@ -0,0 +1,271 @@
# TOM — Technische und Organisatorische Massnahmen (Art. 32 DSGVO)
## Uebersicht
Das TOM-Modul implementiert die systematische Ableitung, Dokumentation und Ueberpruefung technischer und organisatorischer Massnahmen gemaess Art. 32 DSGVO. Es bietet einen 6-Schritt-Generator-Wizard, eine regelbasierte Kontrollbibliothek mit 88 Massnahmen, Gap-Analyse, SDM-Mapping, auditfaehige Dokumentengenerierung und 11 Compliance-Checks.
**Route:** `/sdk/tom` | **Backend:** `backend-compliance:8002` | **Checkpoint:** `CP-TOM`
---
## Art. 32 DSGVO Anforderungen
| Absatz | Anforderung | TOM-Modul Umsetzung |
|--------|-------------|---------------------|
| Art. 32 Abs. 1 lit. a | Pseudonymisierung und Verschluesselung | Kategorien ENCRYPTION (5 Controls) und PSEUDONYMIZATION (4 Controls) |
| Art. 32 Abs. 1 lit. b | Vertraulichkeit, Integritaet, Verfuegbarkeit, Belastbarkeit | 8 Kategorien: ACCESS_CONTROL, ADMISSION_CONTROL, ACCESS_AUTHORIZATION, TRANSFER_CONTROL, RESILIENCE, AVAILABILITY, SEPARATION, INPUT_CONTROL |
| Art. 32 Abs. 1 lit. c | Rasche Wiederherstellung nach Zwischenfall | Kategorie RECOVERY (5 Controls) |
| Art. 32 Abs. 1 lit. d | Regelmaessige Ueberpruefung und Bewertung | Kategorie REVIEW (11 Controls) + Compliance-Check NO_REVIEW_PROCESS |
---
## TOM-Ableitung — Zwei Quellen
TOMs werden aus zwei unabhaengigen Quellen abgeleitet:
### 1. Scope/Profil-Module (Embedded Controls)
Der 6-Schritt-Wizard erfasst:
- **CompanyProfile**: Branche, Groesse, Rolle (Controller/Processor)
- **DataProfile**: Datenkategorien, besondere Kategorien (Art. 9), Betroffene
- **ArchitectureProfile**: Hosting, Cloud-Provider, Mandantenfaehigkeit
- **SecurityProfile**: Auth, Backup, Logging, DR-Plan
- **RiskProfile**: CIA-Bewertung, Schutzniveau
Die **Rules Engine** wertet 88 Embedded Controls gegen die Profile-Daten aus. Jeder Control hat `applicabilityConditions` mit Operatoren (EQUALS, IN, GREATER_THAN, CONTAINS) und Prioritaeten.
### 2. Canonical Control Library (CP-CLIB)
Die dynamisch generierte **Canonical Control Library** (`/sdk/control-library`) enthaelt unternehmensrelevante Security-Controls aus OWASP, NIST, ENISA und weiteren Frameworks. Diese werden durch den Control Generator Pipeline erzeugt und haben einen eigenen Review-Workflow.
!!! info "Herkunftsdokumentation"
Im TOM-Dokument (Sektion 2 und 6) wird die **Herkunft** jeder Massnahme dokumentiert —
ob sie aus der Embedded Control Library oder der Canonical Control Library stammt.
---
## Frontend — 5-Tab-Aufbau
| Tab | Beschreibung |
|-----|-------------|
| **Uebersicht** | Alle TOMs mit Filter (Kategorie, Typ, Status, Applicability), SDM-Abdeckung, Statistiken |
| **Detail-Editor** | Einzelne TOM bearbeiten: Status, Verantwortlich, Evidence, Review-Datum |
| **Generator** | 6-Schritt-Wizard starten, Quick-Stats |
| **Gap-Analyse & Export** | Gap-Analyse-Ergebnisse, SDM/Modul-Abdeckung, JSON/DOCX Export |
| **TOM-Dokument** | Auditfaehiges HTML-Dokument (12 Sektionen), Org-Header, Revisionsmanager, PDF-Druck |
---
## Kontrollbibliothek (88 Massnahmen)
| Kategorie | Code-Prefix | Anzahl | DSGVO-Referenz |
|-----------|-------------|--------|----------------|
| Zutrittskontrolle | TOM-AC | 6 | Art. 32 Abs. 1 lit. b |
| Zugangskontrolle | TOM-ADM | 6 | Art. 32 Abs. 1 lit. b |
| Zugriffskontrolle | TOM-AZ | 7 | Art. 32 Abs. 1 lit. b |
| Weitergabekontrolle | TOM-TR | 7 | Art. 32 Abs. 1 lit. b |
| Eingabekontrolle | TOM-IN | 5 | Art. 32 Abs. 1 lit. b |
| Auftragskontrolle | TOM-OR | 6 | Art. 28 |
| Verfuegbarkeit | TOM-AV | 7 | Art. 32 Abs. 1 lit. b, c |
| Trennbarkeit | TOM-SE | 6 | Art. 32 Abs. 1 lit. b |
| Verschluesselung | TOM-ENC | 5 | Art. 32 Abs. 1 lit. a |
| Pseudonymisierung | TOM-PS | 4 | Art. 32 Abs. 1 lit. a |
| Belastbarkeit | TOM-RE | 5 | Art. 32 Abs. 1 lit. b |
| Wiederherstellbarkeit | TOM-RC | 5 | Art. 32 Abs. 1 lit. c |
| Ueberpruefung & Bewertung | TOM-RV / TOM-DL / TOM-TR | 11 | Art. 32 Abs. 1 lit. d |
---
## SDM Gewaehrleistungsziele
Das [Standard-Datenschutzmodell](https://www.datenschutz-wiki.de/SDM) definiert 7 Gewaehrleistungsziele:
| Ziel | Relevante Kategorien |
|------|---------------------|
| Verfuegbarkeit | AVAILABILITY, RESILIENCE, RECOVERY |
| Integritaet | ADMISSION_CONTROL, TRANSFER_CONTROL, INPUT_CONTROL, ENCRYPTION, RECOVERY |
| Vertraulichkeit | ACCESS_CONTROL, ADMISSION_CONTROL, ACCESS_AUTHORIZATION, TRANSFER_CONTROL, ENCRYPTION |
| Nichtverkettung | ACCESS_AUTHORIZATION, SEPARATION, PSEUDONYMIZATION |
| Intervenierbarkeit | ORDER_CONTROL, REVIEW |
| Transparenz | INPUT_CONTROL, ORDER_CONTROL, REVIEW |
| Datenminimierung | SEPARATION, PSEUDONYMIZATION |
!!! tip "SDM-Abdeckung"
Die Gap-Analyse (Tab 4) zeigt pro SDM-Gewaehrleistungsziel den Abdeckungsgrad
in Prozent. Ziele mit 0% Abdeckung loesen den Compliance-Check `UNCOVERED_SDM_GOAL`
(Schweregrad HIGH) aus.
---
## 11 Compliance-Checks
| # | Check | Schweregrad | Ausloeser |
|---|-------|-------------|-----------|
| 1 | `MISSING_RESPONSIBLE` | MEDIUM | REQUIRED-TOM ohne verantwortliche Person/Abteilung |
| 2 | `OVERDUE_REVIEW` | MEDIUM | TOM mit reviewDate in der Vergangenheit |
| 3 | `MISSING_EVIDENCE` | HIGH | IMPLEMENTED-TOM ohne Evidence (obwohl evidenceRequirements > 0) |
| 4 | `INCOMPLETE_CATEGORY` | HIGH | Kategorie, in der alle REQUIRED-Controls NOT_IMPLEMENTED sind |
| 5 | `NO_ENCRYPTION_MEASURES` | CRITICAL | Kein ENCRYPTION-Control implementiert |
| 6 | `NO_PSEUDONYMIZATION` | MEDIUM | Besondere Datenkategorien (Art. 9) ohne PSEUDONYMIZATION |
| 7 | `MISSING_AVAILABILITY` | HIGH | Kein AVAILABILITY/RECOVERY implementiert + kein DR-Plan |
| 8 | `NO_REVIEW_PROCESS` | MEDIUM | Kein REVIEW-Control implementiert |
| 9 | `UNCOVERED_SDM_GOAL` | HIGH | SDM-Gewaehrleistungsziel mit 0% Abdeckung |
| 10 | `HIGH_RISK_WITHOUT_MEASURES` | CRITICAL | Schutzniveau VERY_HIGH aber < 50% implementiert |
| 11 | `STALE_NOT_IMPLEMENTED` | LOW | REQUIRED-TOM seit > 90 Tagen NOT_IMPLEMENTED |
**Score-Berechnung:** `100 - (CRITICAL*15 + HIGH*10 + MEDIUM*5 + LOW*2)`, Minimum 0.
---
## Backend API (9+ Endpoints)
| Methode | Pfad | Beschreibung |
|---------|------|--------------|
| `GET` | `/api/v1/tom/state` | TOM-Generator-State laden |
| `POST` | `/api/v1/tom/state` | State speichern |
| `POST` | `/api/v1/tom/evaluate` | Controls evaluieren (Rules Engine) |
| `POST` | `/api/v1/tom/gap-analysis` | Gap-Analyse durchfuehren |
| `POST` | `/api/v1/tom/evidence/upload` | Evidence-Dokument hochladen |
| `POST` | `/api/v1/tom/evidence/analyze` | KI-Analyse eines Evidence-Dokuments |
| `POST` | `/api/v1/tom/export` | Export (JSON, DOCX, PDF, ZIP) |
| `GET` | `/api/v1/tom/controls` | Kontrollbibliothek abrufen |
| `GET` | `/api/v1/tom/controls/:id` | Einzelnen Control abrufen |
### TOM ↔ Canonical Control Mapping API
| Methode | Pfad | Beschreibung |
|---------|------|--------------|
| `POST` | `/api/compliance/tom-mappings/sync` | Controls synchronisieren (Profil-basiert) |
| `GET` | `/api/compliance/tom-mappings` | Alle Mappings auflisten |
| `GET` | `/api/compliance/tom-mappings/by-tom/{code}` | Mappings pro TOM-Kategorie |
| `GET` | `/api/compliance/tom-mappings/stats` | Coverage-Statistiken |
| `POST` | `/api/compliance/tom-mappings/manual` | Manuelle Zuordnung |
| `DELETE` | `/api/compliance/tom-mappings/{id}` | Zuordnung entfernen |
!!! info "Proxy-Route (Frontend)"
Das Admin-Frontend ruft die Endpoints ueber den Next.js-Proxy auf:
`/api/sdk/v1/tom/**``backend-compliance:8002/api/v1/tom/**`
`/api/sdk/v1/compliance/tom-mappings/**``backend-compliance:8002/api/compliance/tom-mappings/**`
---
## TOM-Dokument (12 Sektionen)
| # | Sektion | Inhalt |
|---|---------|--------|
| 0 | Deckblatt | Organisation, DSB, IT-Sicherheit, Version |
| — | Inhaltsverzeichnis | Automatisch generiert |
| 1 | Ziel und Zweck | Art. 32 DSGVO Rechtsrahmen |
| 2 | Geltungsbereich | Unternehmen, Hosting, Systeme, Control-Quellen |
| 3 | Grundprinzipien Art. 32 | Vertraulichkeit, Integritaet, Verfuegbarkeit, Belastbarkeit, Wirksamkeitspruefung |
| 4 | Schutzbedarf und Risikoanalyse | CIA-Bewertung, Schutzniveau, DSFA-Pflicht |
| 5 | Massnahmen-Uebersicht | Tabelle: Kategorie, Anzahl, Status-Verteilung |
| 6 | Detaillierte Massnahmen | Pro Kategorie: Detail-Karten mit Code, Status, Evidence, Mappings |
| 7 | SDM Gewaehrleistungsziele | Abdeckungstabelle (7 Ziele x Prozent) |
| 8 | Verantwortlichkeiten | Rollenmatrix |
| 9 | Pruef- und Revisionszyklus | Review-Zeitplan |
| 10 | Compliance-Status | Score, Issues nach Schweregrad |
| 11 | Aenderungshistorie | Versionstabelle |
**Ausgabe:** HTML-Download oder PDF-Druck via Browser (`window.print()`).
---
## Drei-Schichten-Architektur (TOM ↔ Canonical Controls)
Die Audit-faehige Dokumentation nutzt eine **Drei-Schichten-Architektur**:
```mermaid
graph TD
TOM["TOM-Massnahmen (~88, Audit-Level)"]
MAP["tom_control_mappings (Bridge-Tabelle)"]
CC["Canonical Controls (10.000+, Implementation-Level)"]
TOM --> MAP --> CC
```
| Schicht | Beschreibung | Beispiel |
|---------|-------------|---------|
| **TOM-Massnahmen** | 88 abstrakte, auditfaehige Massnahmen in 13 Kategorien | TOM-ENC-01: Transportverschluesselung |
| **Mapping-Bridge** | Verknuepfung TOM-Kategorie → Canonical Controls per Profil | ENCRYPTION → encryption-Kategorie, Industry-Filter |
| **Canonical Controls** | 10.000+ konkrete Security-Controls aus OWASP, NIST, ENISA | CRYP-001: Cryptographic Key Lifecycle |
### Kategorie-Zuordnung
| TOM-Kategorie | Canonical Kategorien |
|---------------|---------------------|
| ACCESS_CONTROL | authentication, identity, physical |
| ADMISSION_CONTROL | authentication, identity, system |
| ACCESS_AUTHORIZATION | authentication, identity |
| TRANSFER_CONTROL | network, data_protection, encryption |
| INPUT_CONTROL | application, data_protection |
| ORDER_CONTROL | supply_chain, compliance |
| AVAILABILITY | continuity, system |
| SEPARATION | network, data_protection |
| ENCRYPTION | encryption |
| PSEUDONYMIZATION | data_protection, encryption |
| RESILIENCE | continuity, system |
| RECOVERY | continuity |
| REVIEW | compliance, governance, risk |
### Sync-Algorithmus
1. CompanyProfile (Branche, Groesse) wird gehasht
2. Aenderung erkannt → alte auto-Mappings loeschen
3. Pro TOM-Kategorie: Canonical Controls mit passender `category`, `applicable_industries`, `applicable_company_size` und `release_state = 'approved'` suchen
4. Neue Mappings inserieren (ON CONFLICT DO NOTHING)
5. Sync-State aktualisieren
---
## Cross-Modul-Integration
| Modul | Integration |
|-------|------------|
| **DSFA** | TOM-Controls als Massnahmen in Datenschutz-Folgenabschaetzung |
| **VVT** | Verknuepfung von TOMs mit Verarbeitungstaetigkeiten |
| **Loeschfristen** | Loeschkontrollen (TOM-DL) referenzieren Loeschfristen-Policies |
| **Control Library** | Canonical Controls als belegende Security-Controls pro TOM-Kategorie |
| **Risk Assessment** | RiskProfile steuert Applicability der Controls |
```mermaid
graph LR
Scope["Scope Engine"] -->|Profile| TOM["TOM (Art. 32)"]
CLIB["Control Library"] -->|Canonical Controls| TOM
TOM --> DSFA["DSFA (Art. 35)"]
TOM --> VVT["VVT (Art. 30)"]
TOM --> Loeschfristen["Loeschfristen"]
Risk["Risk Assessment"] -->|RiskProfile| TOM
```
---
## Audit-Faehigkeit
Das TOM-Modul erfuellt 7 Audit-Kriterien:
1. **Vollstaendigkeit**: 88 Controls decken alle Art. 32 Anforderungen ab
2. **Nachvollziehbarkeit**: Rules Engine dokumentiert Applicability-Gruende
3. **Aktualitaet**: Review-Zyklen + Compliance-Check OVERDUE_REVIEW
4. **Verantwortlichkeit**: Rollenmatrix im TOM-Dokument
5. **Evidence**: Evidence-Verknuepfung + Gap-Analyse
6. **Druckfaehigkeit**: Auditfaehiges HTML-Dokument mit 12 Sektionen
7. **Wirksamkeitspruefung**: 11 Compliance-Checks + Score
---
## Datei-Uebersicht
| Datei | Beschreibung |
|-------|--------------|
| `admin-compliance/app/sdk/tom/page.tsx` | Haupt-Seite mit 5 Tabs |
| `admin-compliance/components/sdk/tom-dashboard/` | Tab-Komponenten (Overview, Editor, GapExport, Document) |
| `admin-compliance/lib/sdk/tom-generator/types.ts` | Alle TypeScript-Typen |
| `admin-compliance/lib/sdk/tom-generator/controls/loader.ts` | 88 Embedded Controls |
| `admin-compliance/lib/sdk/tom-generator/rules-engine.ts` | Applicability-Auswertung |
| `admin-compliance/lib/sdk/tom-generator/context.tsx` | State Management (Reducer) |
| `admin-compliance/lib/sdk/tom-generator/sdm-mapping.ts` | SDM-Gewaehrleistungsziel-Mapping |
| `admin-compliance/lib/sdk/tom-compliance.ts` | 11 Compliance-Checks |
| `admin-compliance/lib/sdk/tom-document.ts` | HTML-Dokument-Generator |
| `backend-compliance/compliance/api/tom_mapping_routes.py` | TOM ↔ Canonical Control Mapping API (6 Endpoints) |
| `backend-compliance/migrations/068_tom_control_mappings.sql` | DB-Schema fuer Mapping-Bridge |
+157 -45
View File
@@ -1,22 +1,27 @@
# Training Engine (CP-TRAIN)
KI-generierte Schulungsinhalte, Rollenmatrix, Quiz-Engine und Zertifikatsverwaltung für Compliance-Schulungen.
KI-generierte Schulungsinhalte, Rollenmatrix, Quiz-Engine, Zertifikate und Training Blocks fuer Compliance-Schulungen.
**Prefix:** `CP-TRAIN` · **seq:** 4800 · **Frontend:** `https://macmini:3007/sdk/training`
**Learner-Portal:** `https://macmini:3007/sdk/training/learner`
**Service:** `ai-compliance-sdk` (Go/Gin, Port 8093)
**Proxy:** `/api/sdk/v1/training/[[...path]]``ai-compliance-sdk:8090/sdk/v1/training/...`
**Developer Portal:** `https://macmini:3006/api/training`
---
## Features
- Rollenbasierte Schulungsmatrix (Wer muss was absolvieren?)
- Rollenbasierte Schulungsmatrix (CTM) — 10 Rollen (R1R10)
- KI-generierte Schulungsinhalte (Text, Audio, Video via TTS-Service)
- Quiz-Engine mit automatischer Auswertung
- Deadline-Tracking und Eskalation bei Überziehung
- Quiz-Engine mit automatischer Auswertung und Bestehensgrenze
- Deadline-Tracking und 4-stufige Eskalation (7/14/30/45 Tage)
- Aufgabenzuweisung (Assignments) mit Fortschrittstracking
- Unveränderliches Audit-Log für Compliance-Nachweise
- Bulk-Content-Generierung für alle Module auf einmal
- PDF-Zertifikate nach erfolgreichem Abschluss
- Training Blocks — automatische Modul-Erstellung aus Canonical Controls
- Learner-Portal fuer Mitarbeiter (Schulung absolvieren, Quiz, Zertifikat)
- Unveraenderliches Audit-Log fuer Compliance-Nachweise
- Bulk-Content-Generierung fuer alle Module auf einmal
---
@@ -25,13 +30,15 @@ KI-generierte Schulungsinhalte, Rollenmatrix, Quiz-Engine und Zertifikatsverwalt
| Artikel | Bezug |
|---------|-------|
| Art. 39 Abs. 1b DSGVO | DSB-Aufgabe: Sensibilisierung und Schulung |
| Art. 5 AI Act | Schulungspflicht für verbotene KI-Praktiken |
| Art. 4 Abs. 2 AI Act | Schulung für KI-Alphabetisierung |
| Art. 5 AI Act | Schulungspflicht fuer verbotene KI-Praktiken |
| Art. 4 Abs. 2 AI Act | Schulung fuer KI-Alphabetisierung |
---
## Tabs / Ansichten
### Admin-Frontend (`/sdk/training`)
| Tab | Inhalt |
|-----|--------|
| `overview` | Statistiken, Deadline-Warnung, Eskalation-Check |
@@ -39,7 +46,23 @@ KI-generierte Schulungsinhalte, Rollenmatrix, Quiz-Engine und Zertifikatsverwalt
| `matrix` | Rollen-Modul-Matrix — wer muss welche Schulung absolvieren |
| `assignments` | Zugewiesene Schulungen mit Fortschritt und Deadline |
| `content` | KI-generierter Inhalt pro Modul + Audio/Video-Player |
| `audit` | Unveränderliches Audit-Log aller Schulungsaktivitäten |
| `audit` | Unveraenderliches Audit-Log aller Schulungsaktivitaeten |
### Learner-Portal (`/sdk/training/learner`)
| Tab | Inhalt |
|-----|--------|
| Meine Schulungen | Zuweisungsliste mit Status-Badges, Fortschrittsbalken, Deadline |
| Schulungsinhalt | Modul-Content (Markdown), AudioPlayer, VideoPlayer |
| Quiz | Fragen mit Antwortauswahl, Timer, Ergebnis-Anzeige |
| Zertifikate | Grid mit abgeschlossenen Schulungen, PDF-Download |
**Learner-Workflow:**
1. Mitarbeiter sieht seine Zuweisungen
2. Klickt "Schulung starten" → Content lesen, Audio/Video anhoeren
3. "Quiz starten" → Fragen beantworten
4. Bei Bestehen: "Zertifikat generieren" → PDF-Download
---
@@ -49,65 +72,122 @@ KI-generierte Schulungsinhalte, Rollenmatrix, Quiz-Engine und Zertifikatsverwalt
| Methode | Pfad | Beschreibung |
|---------|------|--------------|
| `GET` | `/sdk/v1/training/modules` | Alle Module (`status`, `regulation` Filter) |
| `GET` | `/sdk/v1/training/modules/:id` | Modul-Detail |
| `GET` | `/sdk/v1/training/modules` | Alle Module (`regulation_area`, `frequency_type`, `search` Filter) |
| `GET` | `/sdk/v1/training/modules/:id` | Modul-Detail mit Content und Quiz-Fragen |
| `POST` | `/sdk/v1/training/modules` | Modul erstellen |
| `PUT` | `/sdk/v1/training/modules/:id` | Modul aktualisieren |
| `DELETE` | `/sdk/v1/training/modules/:id` | Modul löschen |
| `DELETE` | `/sdk/v1/training/modules/:id` | Modul loeschen |
### Rollenmatrix
### Rollenmatrix (CTM)
| Methode | Pfad | Beschreibung |
|---------|------|--------------|
| `GET` | `/sdk/v1/training/matrix` | Vollständige Rollenmatrix |
| `GET` | `/sdk/v1/training/matrix/role/:role` | Matrix für eine Rolle |
| `POST` | `/sdk/v1/training/matrix` | Eintrag hinzufügen |
| `GET` | `/sdk/v1/training/matrix` | Vollstaendige Rollenmatrix |
| `GET` | `/sdk/v1/training/matrix/:role` | Matrix fuer eine Rolle |
| `POST` | `/sdk/v1/training/matrix` | Eintrag hinzufuegen |
| `DELETE` | `/sdk/v1/training/matrix/:role/:moduleId` | Eintrag entfernen |
**Rollen:** R1 Geschaeftsfuehrung, R2 IT-Leitung, R3 DSB, R4 ISB, R5 HR, R6 Einkauf, R7 Fachabteilung, R8 IT-Admin, R9 Alle Mitarbeiter, R10 Behoerden
### Assignments
| Methode | Pfad | Beschreibung |
|---------|------|--------------|
| `GET` | `/sdk/v1/training/assignments` | Alle Zuweisungen (Filter: `status`, `role`, `moduleId`) |
| `GET` | `/sdk/v1/training/assignments` | Alle Zuweisungen (Filter: `user_id`, `module_id`, `role`, `status`) |
| `GET` | `/sdk/v1/training/assignments/:id` | Zuweisung-Detail |
| `POST` | `/sdk/v1/training/assignments/compute` | Zuweisungen aus Matrix berechnen |
| `POST` | `/sdk/v1/training/assignments/:id/start` | Schulung starten |
| `POST` | `/sdk/v1/training/assignments/:id/progress` | Fortschritt aktualisieren |
| `POST` | `/sdk/v1/training/assignments/:id/complete` | Schulung abschliessen |
| `PUT` | `/sdk/v1/training/assignments/:id` | Deadline aktualisieren |
| `POST` | `/sdk/v1/training/assignments/:id/complete` | Schulung abschließen |
### KI-Inhalt
### KI-Content-Generierung
| Methode | Pfad | Beschreibung |
|---------|------|--------------|
| `GET` | `/sdk/v1/training/modules/:id/content` | Aktueller Inhalt |
| `POST` | `/sdk/v1/training/modules/:id/generate` | Inhalt KI-generieren (Skript, Audio, Video) |
| `POST` | `/sdk/v1/training/content/generate` | Inhalt KI-generieren (Markdown) |
| `POST` | `/sdk/v1/training/content/generate-quiz` | Quiz-Fragen KI-generieren |
| `GET` | `/sdk/v1/training/content/:moduleId` | Veroeffentlichten Content laden |
| `POST` | `/sdk/v1/training/content/:contentId/publish` | Inhalt freigeben |
| `POST` | `/sdk/v1/training/content/generate-all` | Alle Module bulk-generieren |
| `POST` | `/sdk/v1/training/content/:id/publish` | Inhalt freigeben |
| `POST` | `/sdk/v1/training/content/generate-all-quiz` | Alle Quizzes bulk-generieren |
### Quiz
| Methode | Pfad | Beschreibung |
|---------|------|--------------|
| `GET` | `/sdk/v1/training/modules/:id/quiz` | Quiz-Fragen |
| `POST` | `/sdk/v1/training/modules/:id/quiz/generate` | Quiz KI-generieren |
| `POST` | `/sdk/v1/training/modules/:id/quiz/generate-all` | Alle Quizzes bulk-generieren |
| `POST` | `/sdk/v1/training/modules/:id/quiz/submit` | Antworten einreichen |
| `GET` | `/sdk/v1/training/assignments/:id/attempts` | Quiz-Versuche |
| `GET` | `/sdk/v1/training/quiz/:moduleId` | Quiz-Fragen fuer ein Modul |
| `POST` | `/sdk/v1/training/quiz/:moduleId/submit` | Antworten einreichen |
| `GET` | `/sdk/v1/training/quiz/attempts/:assignmentId` | Quiz-Versuche anzeigen |
### Media (Audio/Video)
| Methode | Pfad | Beschreibung |
|---------|------|--------------|
| `POST` | `/sdk/v1/training/content/:moduleId/generate-audio` | Audio generieren (Piper TTS) |
| `POST` | `/sdk/v1/training/content/:moduleId/generate-video` | Video generieren (TTS + Folien) |
| `POST` | `/sdk/v1/training/content/:moduleId/preview-script` | Video-Script Vorschau (JSON) |
| `GET` | `/sdk/v1/training/media/module/:moduleId` | Alle Medien eines Moduls |
| `GET` | `/sdk/v1/training/media/:mediaId/url` | Metadaten (Bucket, Object Key) |
| `POST` | `/sdk/v1/training/media/:mediaId/publish` | Media veroeffentlichen |
| `GET` | `/sdk/v1/training/media/:mediaId/stream` | **Media streamen** (307 → Presigned URL) |
**Media-Streaming:** Der `/stream`-Endpoint liefert einen `307 Temporary Redirect` zu einer zeitlich begrenzten Presigned URL (MinIO/S3). Browser und Player folgen dem Redirect automatisch. Der Next.js-Proxy leitet den Redirect transparent weiter.
### Deadlines & Eskalation
| Methode | Pfad | Beschreibung |
|---------|------|--------------|
| `GET` | `/sdk/v1/training/deadlines` | Bevorstehende Deadlines |
| `GET` | `/sdk/v1/training/deadlines/overdue` | Überfällige Deadlines |
| `POST` | `/sdk/v1/training/escalations/check` | Eskalation auslösen |
| `GET` | `/sdk/v1/training/deadlines/overdue` | Ueberfaellige Deadlines |
| `POST` | `/sdk/v1/training/escalation/check` | Eskalation ausfuehren |
**Eskalationsstufen:**
| Stufe | Tage ueberfaellig | Aktion |
|-------|-------------------|--------|
| 1 | 7 Tage | Erinnerung an Mitarbeiter |
| 2 | 14 Tage | Benachrichtigung Teamleitung |
| 3 | 30 Tage | Benachrichtigung Management |
| 4 | 45 Tage | Benachrichtigung Compliance Officer |
### Zertifikate
| Methode | Pfad | Beschreibung |
|---------|------|--------------|
| `POST` | `/sdk/v1/training/certificates/generate/:assignmentId` | Zertifikat generieren |
| `GET` | `/sdk/v1/training/certificates` | Alle Zertifikate des Tenants |
| `GET` | `/sdk/v1/training/certificates/:id/pdf` | Zertifikat als PDF herunterladen |
| `GET` | `/sdk/v1/training/certificates/:id/verify` | Zertifikat verifizieren |
**Voraussetzungen:** Status `completed` UND `quiz_passed = true`. Das PDF wird im Querformat (A4 Landscape) generiert und enthaelt Modul-Titel, Benutzer-Name, Datum und eine eindeutige Zertifikats-ID.
### Training Blocks (Controls → Module)
| Methode | Pfad | Beschreibung |
|---------|------|--------------|
| `GET` | `/sdk/v1/training/blocks` | Alle Block-Konfigurationen |
| `POST` | `/sdk/v1/training/blocks` | Block-Konfiguration erstellen |
| `GET` | `/sdk/v1/training/blocks/:id` | Block-Konfiguration laden |
| `PUT` | `/sdk/v1/training/blocks/:id` | Block-Konfiguration aktualisieren |
| `DELETE` | `/sdk/v1/training/blocks/:id` | Block-Konfiguration loeschen |
| `POST` | `/sdk/v1/training/blocks/:id/preview` | Vorschau: Welche Controls/Module? |
| `POST` | `/sdk/v1/training/blocks/:id/generate` | Module generieren (Content + CTM) |
| `GET` | `/sdk/v1/training/blocks/:id/controls` | Verlinkte Controls anzeigen |
### Canonical Controls
| Methode | Pfad | Beschreibung |
|---------|------|--------------|
| `GET` | `/sdk/v1/training/canonical/controls` | Controls auflisten (Filter: domain, category, severity, target_audience) |
| `GET` | `/sdk/v1/training/canonical/meta` | Metadaten (Domains, Kategorien, Audiences mit Counts) |
### Statistiken & Audit
| Methode | Pfad | Beschreibung |
|---------|------|--------------|
| `GET` | `/sdk/v1/training/stats` | Überblick-Statistiken |
| `GET` | `/sdk/v1/training/audit` | Audit-Log (Filter: `action`, `moduleId`, `userId`) |
| `GET` | `/sdk/v1/training/stats` | Ueberblick-Statistiken |
| `GET` | `/sdk/v1/training/audit-log` | Audit-Log (Filter: `action`, `entity_type`, `limit`, `offset`) |
---
@@ -118,7 +198,7 @@ seq 4700: Academy (Compliance Academy — manuelle Schulungen)
seq 4800: Training Engine (KI-generierte Schulungen, Matrix, Quiz)
```
Das Training-Modul erweitert die Academy um KI-generierte Inhalte. Während die Academy einfache Schulungseinheiten verwaltet, bietet die Training Engine automatische Inhaltsgenerierung, eine Rollenmatrix und eine vollständige Quiz-Engine.
Das Training-Modul erweitert die Academy um KI-generierte Inhalte. Waehrend die Academy einfache Schulungseinheiten verwaltet, bietet die Training Engine automatische Inhaltsgenerierung, eine Rollenmatrix und eine vollstaendige Quiz-Engine.
---
@@ -128,25 +208,39 @@ KI-generierte Inhalte werden via `compliance-tts-service` (Port 8095) in Audio u
- **Audio:** Piper TTS → MP3 (Modell: `de_DE-thorsten-high.onnx`)
- **Video:** FFmpeg → MP4 (Skript + Stimme + Untertitel)
- **Storage:** Hetzner Object Storage (`nbg1.your-objectstorage.com`, S3-kompatibel)
- **Storage:** S3-kompatibles Object Storage (Hetzner, TLS)
- **Streaming:** `/media/:id/stream` → 307 Redirect zu MinIO Presigned URL
```
AudioPlayer → /sdk/v1/training/modules/:id/media (audio)
VideoPlayer → /sdk/v1/training/modules/:id/media (video)
AudioPlayer → /sdk/v1/training/media/:mediaId/stream
VideoPlayer → /sdk/v1/training/media/:mediaId/stream
TTS Service → POST /presigned-url (returns pre-signed MinIO URL)
```
---
## Frontend
### Admin-Frontend
**URL:** `https://macmini:3007/sdk/training`
6-Tab-Oberfläche mit:
6-Tab-Oberflaeche mit:
- Statistik-Dashboard (Abschlussquote, offene Schulungen, Deadlines)
- Modul-CRUD mit Regulierungs-Badges
- Modul-CRUD mit Regulierungs-Badges und Loeschfunktion
- Interaktive Rollenmatrix (Checkboxen)
- Fortschritts-Balken pro Assignment
- Eingebetteter Audio/Video-Player für KI-generierte Inhalte
- Eingebetteter Audio/Video-Player fuer KI-generierte Inhalte
### Learner-Portal
**URL:** `https://macmini:3007/sdk/training/learner`
4-Tab-Oberflaeche fuer Mitarbeiter:
- Meine Schulungen: Zuweisungsliste mit Status, Fortschritt, Deadline
- Schulungsinhalt: Markdown-Rendering, Audio-Player, Video-Player
- Quiz: Multiple-Choice mit Timer, Ergebnis-Anzeige, Bestehens-Logik
- Zertifikate: Uebersicht abgeschlossener Schulungen, PDF-Download
---
@@ -155,11 +249,29 @@ VideoPlayer → /sdk/v1/training/modules/:id/media (video)
Die Training Engine verwendet eigene Tabellen im `compliance` Schema:
```sql
training_modules -- Schulungsmodule (title, regulation, frequency, ...)
training_matrix -- Rollen-Modul-Zuordnungen
training_assignments -- Zuweisungen (user, module, status, progress, deadline)
training_content -- KI-generierter Inhalt (script, audio_url, video_url, ...)
training_quiz -- Quiz-Fragen pro Modul
training_quiz_attempts -- Eingereichter Antworten + Score
training_audit_log -- Unveränderliches Audit-Log
training_modules -- Schulungsmodule (title, regulation, frequency, ...)
training_matrix -- Rollen-Modul-Zuordnungen (CTM)
training_assignments -- Zuweisungen (user, module, status, progress, deadline, certificate_id)
training_content -- KI-generierter Inhalt (markdown, summary, llm_model)
training_quiz_questions -- Quiz-Fragen pro Modul (options JSONB, correct_index)
training_quiz_attempts -- Eingereichte Antworten + Score
training_media -- Audio/Video-Dateien (bucket, object_key, status)
training_audit_log -- Unveraenderliches Audit-Log
training_block_configs -- Block-Konfigurationen (Filter, Prefix, Frequenz)
training_block_controls -- Verlinkte Canonical Controls pro Block
```
---
## Tests
```bash
# Handler-Tests (47 Tests)
cd ai-compliance-sdk && go test -v ./internal/api/handlers/ -run "TestGet|TestCreate|TestUpdate|TestDelete|..."
# Escalation + Content Generator Tests (43 Tests)
cd ai-compliance-sdk && go test -v ./internal/training/ -run "TestEscalation|TestBuildContent|TestParseQuiz|..."
# Block Generator Tests (14 Tests)
cd ai-compliance-sdk && go test -v ./internal/training/ -run "TestBlock"
```
+25
View File
@@ -32,3 +32,28 @@ Seite unter `/sdk/vendor-compliance` mit Vendor-Tabelle, Risiko-Matrix und Vertr
## Datenbank
Migration in der AI Compliance SDK erstellt Tabellen fuer Vendors, Risikobewertungen, Vertraege und AVV-Klauseln.
- `vendor_vendors` — Stammdaten, Rolle, Risiko-Scores, Kontakte
- `vendor_contracts` — AVV-Dokumente, Pruefstatus
- `vendor_findings` — Findings aus Pruefungen
- `vendor_control_instances` — Control-Instanzen pro Vendor (inkl. 6 TOM-Controls VND-TOM-01..06)
- `compliance_templates` — Shared Templates
## Cross-Modul-Integration
Seit der Vendor-Compliance Cross-Modul-Integration (2026-03-19) ist das Modul mit vier DSGVO-Modulen verknuepft:
| Modul | Integration | Richtung |
|-------|------------|----------|
| **VVT** | Processor-Tab (Art. 30 Abs. 2) liest Vendors mit `role=PROCESSOR/SUB_PROCESSOR` aus Vendor-API. Kein eigener State mehr — Single Source of Truth. | Read |
| **Obligations** | Art.-28-Pflichten verknuepfbar via `linked_vendor_ids` (JSONB). Compliance-Check `MISSING_VENDOR_LINK` prueft fehlende Verknuepfung. | Read/Write |
| **TOM** | Uebersicht-Tab zeigt Vendor-TOM-Controls (VND-TOM-01..06) als Querverweis-Tabelle. | Read |
| **Loeschfristen** | Loeschfrist-Policies verknuepfbar via `linked_vendor_ids` (JSONB). Loeschkonzept-Dokument listet verknuepfte Auftragsverarbeiter. | Read/Write |
### Sidebar-Position
Das Vendor-Compliance-Modul steht in der SDK-Sidebar bei **seq 2500** (Paket "dokumentation"), direkt nach VVT (seq 2400):
```
obligations (2000) → dsfa (2100) → tom (2200) → loeschfristen (2300) → vvt (2400) → vendor-compliance (2500)
```
+759
View File
@@ -0,0 +1,759 @@
# VVT — Verzeichnis von Verarbeitungstaetigkeiten (Art. 30 DSGVO)
Das VVT-Modul implementiert das Verarbeitungsverzeichnis gemaess Art. 30 DSGVO mit einer
3-Schichten-Architektur: **Master-Libraries** (globale Stammdaten) + **Prozess-Templates**
(vorgefertigte Verarbeitungsvorlagen) + **Tenant-Instanzen** (individuelle Verarbeitungstaetigkeiten).
**Route:** `/sdk/vvt` | **Backend:** `backend-compliance:8002` | **Migrationen:** `006`, `033`, `035`, `064`-`067`
---
## Uebersicht
| Checkpoint | Reviewer | Rechtsgrundlage | Status |
|-----------|----------|-----------------|--------|
| CP-VVT (REQUIRED) | DSB | Art. 30 DSGVO | Phase 1 abgeschlossen |
**Wann ist ein VVT Pflicht?**
Jeder Verantwortliche und jeder Auftragsverarbeiter muss ein Verzeichnis aller
Verarbeitungstaetigkeiten fuehren (Art. 30 Abs. 1 und Abs. 2 DSGVO). Ausnahmen gelten
nur fuer Unternehmen mit weniger als 250 Beschaeftigten — und auch nur dann, wenn die
Verarbeitung kein Risiko birgt, nur gelegentlich erfolgt und keine besonderen Datenkategorien
(Art. 9/10 DSGVO) betroffen sind. In der Praxis entfaellt die Ausnahme fast nie.
---
## 3-Schichten-Architektur
Das VVT-Modul arbeitet mit drei Abstraktionsebenen:
```mermaid
graph TD
A[Ebene A: Master-Libraries] -->|IDs referenzieren| B[Ebene B: Prozess-Templates]
B -->|Instanziierung| C[Ebene C: Tenant-Aktivitaeten]
A -->|Direkte Auswahl| C
```
### Ebene A — Master-Libraries (Global)
8 globale Referenztabellen, die **ohne `tenant_id`** arbeiten und allen Mandanten zur Verfuegung stehen:
| Library | Tabelle | Eintraege | Beschreibung |
|---------|---------|-----------|-------------|
| Betroffenenkategorien | `vvt_lib_data_subjects` | 15 | Mitarbeiter, Kunden, Bewerber, ... |
| Datenkategorien | `vvt_lib_data_categories` | 35 | Hierarchisch mit Parent/Child (9 Oberkategorien + 26 Unterkategorien) |
| Empfaenger | `vvt_lib_recipients` | 15 | Intern, Auftragsverarbeiter, Behoerden |
| Rechtsgrundlagen | `vvt_lib_legal_bases` | 12 | Art. 6, Art. 9, BDSG, UWG |
| Loeschfristen | `vvt_lib_retention_rules` | 12 | HGB 10J, AO 6J/10J, AGG 6M, ... |
| Transfermechanismen | `vvt_lib_transfer_mechanisms` | 8 | Angemessenheit, SCC, BCR, DPF, ... |
| Verarbeitungszwecke | `vvt_lib_purposes` | 20 | Personalverwaltung, CRM, Analytics, ... |
| TOMs | `vvt_lib_toms` | 20 | RBAC, MFA, Verschluesselung, Backup, ... |
#### Datenkategorien-Hierarchie
Die Datenkategorien sind zweistufig organisiert:
| Oberkategorie | Unterkategorien | Art. 9 |
|--------------|----------------|--------|
| Identifikationsdaten | Name, Geburtsdatum, Ausweisnummer, SV-Nummer | Nein |
| Kontaktdaten | Anschrift, Kontaktinformationen | Nein |
| Finanzdaten | Steuer-ID, Bankverbindung, Zahlungsdaten, Gehaltsdaten | Nein |
| Beschaeftigungsdaten | Arbeitsvertragsdaten, Ausbildungsdaten | Nein |
| Digitale Identitaet | IP-Adresse, Geraete-ID, Zugangsdaten, Nutzungsdaten | Nein |
| Kommunikationsdaten | Korrespondenz, Vertragsdaten | Nein |
| Medien- und Standortdaten | Bild/Video, Standortdaten | Nein |
| Besondere Kategorien (Art. 9) | Gesundheit, Genetik, Biometrie, Ethnische Herkunft, Politische Meinungen, Religion, Gewerkschaft, Sexualleben | **Ja** |
| Strafrechtliche Daten (Art. 10) | Verurteilungen, Straftaten | Art. 10 |
### Ebene B — Prozess-Templates (System + Tenant)
18 vorgefertigte Prozess-Templates, die Library-IDs referenzieren und mit einem Klick
in eine VVT-Aktivitaet instanziiert werden koennen:
| Template-ID | Name | Business Function | Loeschfrist |
|-------------|------|-------------------|-------------|
| `hr-mitarbeiterverwaltung` | Mitarbeiterverwaltung | Personal | 10 Jahre (HGB) |
| `hr-gehaltsabrechnung` | Gehaltsabrechnung | Personal | 10 Jahre (AO) |
| `hr-bewerbermanagement` | Bewerbermanagement | Personal | 6 Monate (AGG) |
| `hr-zeiterfassung` | Zeiterfassung | Personal | 2 Jahre (ArbZG) |
| `finance-buchhaltung` | Buchhaltung | Finanzen | 10 Jahre (HGB) |
| `finance-zahlungsverkehr` | Zahlungsverkehr | Finanzen | 10 Jahre (HGB) |
| `sales-kundenverwaltung` | Kundenverwaltung | Vertrieb | 3 Jahre (BGB) |
| `sales-vertriebssteuerung` | Vertriebssteuerung | Vertrieb | 3 Jahre (BGB) |
| `marketing-newsletter` | Newsletter-Versand | Marketing | Bis Widerruf |
| `marketing-website-analytics` | Website-Analyse | Marketing | 14 Monate |
| `marketing-social-media` | Social-Media-Marketing | Marketing | Bis Zweckerfuellung |
| `support-ticketsystem` | Ticketsystem | Support | 3 Jahre (BGB) |
| `it-systemadministration` | IT-Systemadministration | IT | 90 Tage |
| `it-backup` | Datensicherung | IT | 90 Tage |
| `it-logging` | Logging und Ueberwachung | IT | 90 Tage |
| `it-iam` | Identitaetsmanagement | IT | 6 Monate (AGG) |
| `other-videokonferenz` | Videokonferenz | Sonstiges | Bis Zweckerfuellung |
| `other-besuchermanagement` | Besuchermanagement | Sonstiges | 30 Tage |
### Ebene C — Tenant-Aktivitaeten
Individuelle Verarbeitungstaetigkeiten pro Mandant. Jede Aktivitaet kann sowohl
**Freitext-Felder** (bestehendes Schema) als auch **Library-Referenzen** (neue `*_refs`-Felder)
enthalten. Beide existieren parallel — die Library-Referenzen ergaenzen die Freitext-Felder
fuer strukturierte Auswertungen und Cross-Modul-Verknuepfungen.
---
## Funktionen
- **CRUD-Operationen:** Anlegen, Lesen, Aktualisieren, Loeschen von VVT-Aktivitaeten
- **Organisations-Header:** DSB-Kontakt, VVT-Version, Pruefintervall
- **Template-Instanziierung:** Neue Aktivitaet aus Prozess-Template erstellen (inkl. automatischer Freitext-Befuellung)
- **Library-Referenzen:** Strukturierte Auswahl aus 8 Master-Libraries (parallel zu Freitext)
- **Art. 30 Completeness-Check:** Automatische Bewertung der Pflichtfelder-Vollstaendigkeit
- **Scope-basierte Generierung:** Automatische Erstellung von Aktivitaeten aus Compliance-Scope-Antworten
- **Status-Workflow:** `DRAFT` -> `REVIEW` -> `APPROVED` / `ARCHIVED`
- **Export:** JSON und CSV (Excel-kompatibel mit BOM, Semikolon-getrennt)
- **Audit-Log:** Protokollierung aller Aktionen (CREATE / UPDATE / DELETE / EXPORT)
- **Statistiken:** Zaehler nach Status, Geschaeftsbereich, DSFA-Pflicht, Drittlandtransfers
- **Cross-Modul-Links:** Verknuepfung zu Loeschfristen und TOM-Massnahmen (Phase 2)
---
## API-Endpoints
### Aktivitaeten (CRUD)
| Methode | Pfad | Beschreibung |
|---------|------|--------------|
| `GET` | `/vvt/activities` | Liste (Filter: status, business_function, search, review_overdue) |
| `POST` | `/vvt/activities` | Neue Aktivitaet anlegen -> HTTP 201 |
| `GET` | `/vvt/activities/{id}` | Einzelne Aktivitaet abrufen |
| `PUT` | `/vvt/activities/{id}` | Aktivitaet aktualisieren |
| `DELETE` | `/vvt/activities/{id}` | Aktivitaet loeschen |
| `GET` | `/vvt/activities/{id}/completeness` | Art. 30 Vollstaendigkeits-Check |
| `GET` | `/vvt/activities/{id}/versions` | Versionshistorie |
### Organisation
| Methode | Pfad | Beschreibung |
|---------|------|--------------|
| `GET` | `/vvt/organization` | Organisations-Header laden |
| `PUT` | `/vvt/organization` | Organisations-Header speichern (Upsert) |
### Export & Statistik
| Methode | Pfad | Beschreibung |
|---------|------|--------------|
| `GET` | `/vvt/export?format=json` | JSON-Export aller Aktivitaeten |
| `GET` | `/vvt/export?format=csv` | CSV-Export (Semikolon, UTF-8 BOM) |
| `GET` | `/vvt/stats` | Statistik-Zusammenfassung |
| `GET` | `/vvt/audit-log` | Audit-Trail (limit, offset) |
### Master-Libraries (read-only, global)
| Methode | Pfad | Beschreibung |
|---------|------|--------------|
| `GET` | `/vvt/libraries` | Uebersicht: alle 8 Library-Typen mit Anzahl |
| `GET` | `/vvt/libraries/data-subjects` | Betroffenenkategorien (Filter: `typical_for`) |
| `GET` | `/vvt/libraries/data-categories` | Datenkategorien — hierarchisch oder `?flat=true` (Filter: `parent_id`, `is_art9`) |
| `GET` | `/vvt/libraries/recipients` | Empfaenger (Filter: `type`) |
| `GET` | `/vvt/libraries/legal-bases` | Rechtsgrundlagen (Filter: `is_art9`, `type`) |
| `GET` | `/vvt/libraries/retention-rules` | Loeschfristen mit Dauer, Einheit, Rechtsgrundlage |
| `GET` | `/vvt/libraries/transfer-mechanisms` | Uebermittlungsmechanismen |
| `GET` | `/vvt/libraries/purposes` | Verarbeitungszwecke (Filter: `typical_for`) |
| `GET` | `/vvt/libraries/toms` | Technisch-Organisatorische Massnahmen (Filter: `category`) |
### Prozess-Templates
| Methode | Pfad | Beschreibung |
|---------|------|--------------|
| `GET` | `/vvt/templates` | Alle Templates (Filter: `business_function`, `search`) |
| `GET` | `/vvt/templates/{id}` | Einzelnes Template mit aufgeloesten Library-Labels |
| `POST` | `/vvt/templates/{id}/instantiate` | VVT-Aktivitaet aus Template erstellen -> HTTP 201 |
!!! info "Proxy-Route (Frontend)"
Das Admin-Frontend ruft die Endpoints ueber den Next.js-Proxy auf:
`/api/sdk/v1/compliance/vvt/**` -> `backend-compliance:8002/api/compliance/vvt/**`
---
## Datenfluss: Template-Instanziierung
```mermaid
sequenceDiagram
participant F as Frontend
participant B as Backend
participant DB as PostgreSQL
F->>B: POST /vvt/templates/hr-mitarbeiterverwaltung/instantiate
B->>DB: SELECT FROM vvt_process_templates WHERE id = 'hr-mitarbeiterverwaltung'
DB-->>B: Template mit Library-Referenzen
Note over B: Fuer jeden ref-Typ:<br/>Library-IDs -> Labels aufloesen
B->>DB: SELECT FROM vvt_lib_purposes WHERE id IN ('EMPLOYMENT_ADMIN', 'PAYROLL')
DB-->>B: Labels: "Personalverwaltung", "Gehaltsabrechnung"
B->>DB: SELECT FROM vvt_lib_retention_rules WHERE id = 'HGB_257_10Y'
DB-->>B: "10 Jahre (HGB § 257)"
Note over B: Neue VVT-Aktivitaet erstellen:<br/>- Freitext-Felder mit Labels befuellt<br/>- *_refs-Felder mit Library-IDs
B->>DB: INSERT INTO compliance_vvt_activities (...)
B->>DB: INSERT INTO compliance_vvt_audit_log (action='CREATE', ...)
DB-->>B: Neue Aktivitaet mit UUID
B-->>F: 201 Created + VVTActivityResponse
F->>F: Wechsel zu Editor-Tab
```
---
## Datenmodell
### VVT-Aktivitaet (Response) — vollstaendig
```json
{
"id": "uuid",
"vvt_id": "VVT-0001",
"name": "Mitarbeiterverwaltung",
"description": "Verwaltung des Beschaeftigungsverhaeltnisses",
"status": "DRAFT",
"business_function": "hr",
"purposes": ["Personalverwaltung", "Gehaltsabrechnung"],
"legal_bases": [{"type": "BDSG_26", "description": "Beschaeftigtenverhaeltnis"}],
"data_subject_categories": ["Beschaeftigte"],
"personal_data_categories": ["Name", "Geburtsdatum", "Bankverbindung"],
"recipient_categories": [{"type": "INTERNAL", "name": "Personalabteilung"}],
"third_country_transfers": [],
"retention_period": {
"description": "10 Jahre (HGB § 257)",
"legalBasis": "HGB § 257",
"deletionProcedure": "Vernichtung",
"duration": 10,
"durationUnit": "YEARS"
},
"tom_description": "Rollenbasierte Zugriffskontrolle, Verschluesselung",
"structured_toms": {
"accessControl": ["RBAC", "Need-to-Know"],
"confidentiality": ["Verschluesselung ruhender Daten"],
"integrity": ["Audit-Logging"],
"availability": [],
"separation": ["Mandantentrennung"]
},
"systems": [{"systemId": "HR-Software", "name": "HR-Software"}],
"deployment_model": "cloud",
"protection_level": "HIGH",
"dpia_required": true,
"responsible": "Max Mustermann",
"owner": "Personalabteilung",
"purpose_refs": ["EMPLOYMENT_ADMIN", "PAYROLL"],
"legal_basis_refs": ["BDSG_26", "ART6_1B"],
"data_subject_refs": ["EMPLOYEES"],
"data_category_refs": ["NAME", "DOB", "ADDRESS", "BANK_ACCOUNT", "EMPLOYMENT_DATA"],
"recipient_refs": ["INTERNAL_HR", "INTERNAL_FINANCE", "PROCESSOR_PAYROLL"],
"retention_rule_ref": "HGB_257_10Y",
"transfer_mechanism_refs": null,
"tom_refs": ["AC_RBAC", "AC_NEED_TO_KNOW", "CONF_ENCRYPTION_REST", "INT_AUDIT_LOG"],
"source_template_id": "hr-mitarbeiterverwaltung",
"risk_score": 3,
"linked_loeschfristen_ids": null,
"linked_tom_measure_ids": null,
"art30_completeness": {
"score": 90,
"missing": ["responsible"],
"warnings": [],
"passed": 9,
"total": 10
},
"created_at": "2026-03-19T10:00:00Z",
"updated_at": "2026-03-19T12:30:00Z"
}
```
!!! warning "Dual-Schema: Freitext + Library-Referenzen"
Jede Aktivitaet hat **zwei parallele Repraesentationen** fuer Datenkategorien,
Betroffene, Zwecke etc.: Die bestehenden Freitext-Felder (`purposes`, `legal_bases`, ...)
und die neuen Library-Referenz-Felder (`purpose_refs`, `legal_basis_refs`, ...).
Beide existieren parallel. Bei Template-Instanziierung werden beide automatisch befuellt.
Bestehende Aktivitaeten ohne `*_refs` bleiben voll funktionsfaehig.
### Art. 30 Completeness-Check
Der Completeness-Endpoint prueft 10 Pflichtfelder nach Art. 30 Abs. 1 DSGVO:
| Nr. | Pruefung | Quelle |
|-----|---------|--------|
| 1 | Name der Verarbeitung | `name` |
| 2 | Verarbeitungszweck(e) | `purposes` ODER `purpose_refs` |
| 3 | Rechtsgrundlage | `legal_bases` ODER `legal_basis_refs` |
| 4 | Betroffenenkategorien | `data_subject_categories` ODER `data_subject_refs` |
| 5 | Datenkategorien | `personal_data_categories` ODER `data_category_refs` |
| 6 | Empfaenger | `recipient_categories` ODER `recipient_refs` |
| 7 | Drittland-Uebermittlung | Immer bestanden (kein Transfer ist valide) |
| 8 | Loeschfristen | `retention_period.description` ODER `retention_rule_ref` |
| 9 | TOM-Beschreibung | `tom_description` ODER `tom_refs` ODER `structured_toms` |
| 10 | Verantwortlicher | `responsible` |
**Warnings** (nicht im Score, aber angezeigt):
- `dpia_required_but_no_dsfa_linked` — DSFA erforderlich, aber keine DSFA verknuepft
- `third_country_transfer_without_mechanism` — Drittlandtransfer ohne Transfermechanismus
```json
{
"score": 80,
"missing": ["retention_period", "responsible"],
"warnings": ["dpia_required_but_no_dsfa_linked"],
"passed": 8,
"total": 10
}
```
---
## Library-Datenmodell
### Master-Library-Eintrag (allgemein)
```json
{
"id": "EMPLOYEES",
"label_de": "Beschaeftigte",
"description_de": "Aktuelle Mitarbeiterinnen und Mitarbeiter",
"sort_order": 1
}
```
### Datenkategorie (hierarchisch)
```json
{
"id": "IDENTIFICATION",
"label_de": "Identifikationsdaten",
"children": [
{
"id": "NAME",
"parent_id": "IDENTIFICATION",
"label_de": "Name",
"is_art9": false,
"risk_weight": 1
},
{
"id": "DOB",
"parent_id": "IDENTIFICATION",
"label_de": "Geburtsdatum",
"is_art9": false,
"risk_weight": 2
}
]
}
```
### Loeschfrist (Retention Rule)
```json
{
"id": "HGB_257_10Y",
"label_de": "10 Jahre (HGB § 257)",
"legal_basis": "HGB § 257",
"duration": 10,
"duration_unit": "YEARS",
"start_event": "Ende des Kalenderjahres",
"deletion_procedure": "Vernichtung nach Ablauf der Aufbewahrungsfrist"
}
```
### Prozess-Template
```json
{
"id": "hr-mitarbeiterverwaltung",
"name": "Mitarbeiterverwaltung",
"business_function": "hr",
"purpose_refs": ["EMPLOYMENT_ADMIN", "PAYROLL"],
"legal_basis_refs": ["BDSG_26", "ART6_1B"],
"data_subject_refs": ["EMPLOYEES"],
"data_category_refs": ["NAME", "DOB", "ADDRESS", "CONTACT", "SOCIAL_SECURITY", "BANK_ACCOUNT", "EMPLOYMENT_DATA", "HEALTH_DATA"],
"recipient_refs": ["INTERNAL_HR", "INTERNAL_FINANCE", "PROCESSOR_PAYROLL"],
"tom_refs": ["AC_RBAC", "AC_NEED_TO_KNOW", "CONF_ENCRYPTION_REST", "INT_AUDIT_LOG"],
"retention_rule_ref": "HGB_257_10Y",
"typical_systems": ["HR-Software", "Personalakte (digital)"],
"protection_level": "HIGH",
"dpia_required": true,
"risk_score": 3,
"tags": ["personal", "pflicht"]
}
```
---
## Status-Workflow
```mermaid
stateDiagram-v2
[*] --> DRAFT : Neue Aktivitaet
DRAFT --> REVIEW : Zur Pruefung
REVIEW --> APPROVED : Genehmigt
REVIEW --> DRAFT : Zurueck zu Entwurf
APPROVED --> REVIEW : Erneute Pruefung
APPROVED --> ARCHIVED : Archivieren
ARCHIVED --> DRAFT : Reaktivieren
```
---
## DB-Tabellen
### Migrationshistorie
| Migration | Datei | Inhalt |
|-----------|-------|--------|
| 006 | `006_vvt.sql` | Initiale VVT-Tabellen (organization, activities, audit_log) |
| 033 | `033_vvt_consolidation.sql` | Schema-Konsolidierung |
| 035 | `035_vvt_tenant_isolation.sql` | Tenant-Isolation |
| **064** | `064_vvt_master_libraries.sql` | 8 Library-Tabellen (global) |
| **065** | `065_vvt_library_seed.sql` | Seed-Daten (~150 Eintraege) |
| **066** | `066_vvt_process_templates.sql` | Template-Tabelle + 13 neue Spalten auf `compliance_vvt_activities` |
| **067** | `067_vvt_process_templates_seed.sql` | 18 Prozess-Templates |
### Tabellen-Uebersicht
| Tabelle | Typ | Tenant-scoped | Eintraege |
|---------|-----|--------------|-----------|
| `compliance_vvt_organization` | Daten | Ja | 1 pro Tenant |
| `compliance_vvt_activities` | Daten | Ja | n pro Tenant |
| `compliance_vvt_audit_log` | Audit | Ja | Unbegrenzt |
| `vvt_lib_data_subjects` | Library | **Nein** (global) | 15 |
| `vvt_lib_data_categories` | Library | **Nein** (global) | 35 |
| `vvt_lib_recipients` | Library | **Nein** (global) | 15 |
| `vvt_lib_legal_bases` | Library | **Nein** (global) | 12 |
| `vvt_lib_retention_rules` | Library | **Nein** (global) | 12 |
| `vvt_lib_transfer_mechanisms` | Library | **Nein** (global) | 8 |
| `vvt_lib_purposes` | Library | **Nein** (global) | 20 |
| `vvt_lib_toms` | Library | **Nein** (global) | 20 |
| `vvt_process_templates` | Hybrid | System + Tenant | 18 (System) |
---
## Datei-Uebersicht
### Backend
| Datei | Beschreibung |
|-------|-------------|
| `compliance/db/vvt_models.py` | SQLAlchemy Models: Organization, Activity, AuditLog |
| `compliance/db/vvt_library_models.py` | SQLAlchemy Models: 8 Libraries + ProcessTemplate |
| `compliance/api/vvt_routes.py` | Activity CRUD, Export, Stats, Completeness |
| `compliance/api/vvt_library_routes.py` | Library GET-Endpoints, Template CRUD + Instantiate |
| `compliance/api/schemas.py` | Pydantic Schemas (VVTActivityCreate/Update/Response) |
### Frontend
| Datei | Beschreibung |
|-------|-------------|
| `admin-compliance/app/sdk/vvt/page.tsx` | VVT-Seite (3 Tabs: Verzeichnis, Editor, Export) |
| `admin-compliance/lib/sdk/vvt-types.ts` | TypeScript-Typen, Library-Interfaces, Helper |
| `admin-compliance/lib/sdk/vvt-profiling.ts` | Scope-basierte Generierung |
### Migrationen
| Datei | Beschreibung |
|-------|-------------|
| `migrations/064_vvt_master_libraries.sql` | 8 Library-Tabellen |
| `migrations/065_vvt_library_seed.sql` | Seed: ~150 Eintraege |
| `migrations/066_vvt_process_templates.sql` | Template-Tabelle + 13 Spalten auf Activities |
| `migrations/067_vvt_process_templates_seed.sql` | Seed: 18 Prozess-Templates |
---
## Tests
```bash
# Backend: Alle VVT-Tests (Library + Routes)
cd backend-compliance && python3 -m pytest tests/test_vvt_library_routes.py tests/test_vvt_routes.py -v
# Backend: Nur Library-Tests (54 Tests)
python3 -m pytest tests/test_vvt_library_routes.py -v
# Backend: Nur bestehende VVT-Tests (49 Tests)
python3 -m pytest tests/test_vvt_routes.py -v
# Frontend: Scope → VVT Integration (35 Tests)
cd admin-compliance && npx vitest run lib/sdk/__tests__/vvt-scope-integration.test.ts
```
### Testabdeckung
| Testdatei | Tests | Abdeckung |
|-----------|-------|-----------|
| `test_vvt_library_routes.py` | 54 | Models, Helpers, Endpoints, Completeness, Schema-Compat |
| `test_vvt_routes.py` | 49 | CRUD, Export, Stats, Audit, Organization |
| `vvt-scope-integration.test.ts` | 35 | Profile→Scope Prefill, Scope→VVT Export, Generator, Full Pipeline, Dept. Data Categories, Block 9 Mapping |
| **Gesamt** | **138** | |
---
## Frontend: 5-Tab-Aufbau
### Tab 1: Verzeichnis
- **Statistik-Kacheln:** Gesamt, Genehmigt, Entwurf, Drittland, Art. 9
- **Filter:** Status, Drittland, Art. 9
- **Suche:** VVT-ID, Name, Beschreibung
- **Sortierung:** Name, Datum, Status
- **"Aus Vorlage erstellen":** Template-Picker-Modal mit 18 Templates, filterbar nach Geschaeftsbereich
- **"Neue Verarbeitung":** Leere Aktivitaet erstellen
- **"Aus Scope generieren":** Automatische Generierung aus Compliance-Scope-Antworten
### Tab 2: Editor
- **Formular-Sections:** Grunddaten, Zwecke, Rechtsgrundlagen, Betroffene, Datenkategorien, Empfaenger, Drittlandtransfers, Loeschfristen, TOMs, Systeme, Datenquellen, Datenfluesse
- **Library-Unterstuetzung:** Dropdown-Auswahl aus Master-Libraries fuer alle strukturierten Felder
- **Freitext-Fallback:** Manuelle Eingabe bleibt immer moeglich
### Tab 3: Export & Compliance
- **Compliance-Check:** Pruefung aller Pflichtfelder nach Art. 30 DSGVO
- **Art. 30 Vollstaendigkeit:** Pro-Aktivitaet-Fortschrittsbalken
- **Organisations-Header:** DSB-Kontakt, Version, Pruefintervall
- **JSON-Export:** Vollstaendiger Export aller Aktivitaeten + Metadaten
- **CSV-Export:** Excel-kompatibel (Semikolon, UTF-8 BOM)
- **Statistik:** Zaehler nach Geschaeftsbereichen und Datenkategorien
### Tab 4: VVT-Dokument (Druckansicht)
Generiert ein vollstaendiges, druckbares VVT-Dokument gemaess Art. 30 Abs. 1 DSGVO:
- **Deckblatt:** Organisation, DSB-Kontakt, Versionierung, Pruefintervall, Erstellungsdatum
- **Inhaltsverzeichnis:** Automatisch nummerierte Eintraege aller Verarbeitungstaetigkeiten
- **Aktivitaeten-Tabellen:** Pro Aktivitaet eine zweispaltige Tabelle mit allen Pflichtfeldern:
- Zweck der Verarbeitung, Rechtsgrundlagen, Betroffene Personen
- Datenkategorien (mit Art. 9/10 Kennzeichnung), Empfaengerkategorien
- Drittlandtransfers mit Transfermechanismus
- Loeschfristen, TOMs, Systeme, Schutzbedarfsstufe
- **Library-Aufloesung:** IDs werden automatisch zu deutschen Labels aufgeloest (DATA_SUBJECT_CATEGORY_META, PERSONAL_DATA_CATEGORY_META, LEGAL_BASIS_META, TRANSFER_MECHANISM_META)
- **PDF-Druck:** Via `window.open()` + `window.print()` — eigenstaendiges HTML mit Inline-CSS und `@media print`-Regeln fuer Seitenumbrueche
- **HTML-Download:** Vollstaendiges Dokument als HTML-Datei speicherbar
### Tab 5: Auftragsverarbeiter (Art. 30 Abs. 2)
Eigenstaendiges Verzeichnis fuer Auftragsverarbeiter-Taetigkeiten gemaess Art. 30 Abs. 2 DSGVO:
- **Pflichtfelder (Art. 30 Abs. 2):**
- Name und Kontakt des Auftragsverarbeiters
- Kategorien der Verarbeitungen (fuer jeden Verantwortlichen)
- Unterauftragsverarbeiter-Kette (Name, Zweck, Land, Drittland-Kennzeichnung)
- Drittlandtransfers mit Transfermechanismen
- Technisch-Organisatorische Massnahmen (TOMs)
- **Editor:** Vollstaendiges Formular mit FormSection/FormField-Komponenten
- **Listenansicht:** Karten mit Auftraggeber, Anzahl Kategorien, Unterauftragnehmer, Status-Badge
- **Status-Workflow:** DRAFT → REVIEW → APPROVED → ARCHIVED
- **PDF-Druck:** Eigene Druckfunktion fuer das Auftragsverarbeiter-Verzeichnis
- **Rechtshinweis:** Infobox mit Erlaeuterung der Art. 30 Abs. 2 Anforderungen
!!! note "Datenhaltung"
Auftragsverarbeiter-Eintraege werden aktuell im Frontend-State verwaltet.
Backend-Persistenz (eigene DB-Tabelle + API-Endpoints) ist fuer Phase 2 geplant.
---
## Compliance-Kontext
| Verknuepftes Modul | Beziehung |
|-------------------|-----------|
| **Company Profile** | Stammdaten (DSB, Branche, Mitarbeiter, Angebote) fliessen via Scope in VVT |
| **Compliance Scope** | Scope-Antworten (Block 8+9) generieren VVT-Aktivitaeten per Knopfdruck |
| **DSFA** (Art. 35) | VVT-Aktivitaet referenziert DSFA ueber `dsfa_id` |
| **Loeschfristen** | Cross-Modul-Link ueber `linked_loeschfristen_ids` (Phase 2) |
| **TOM** (Art. 32) | Cross-Modul-Link ueber `linked_tom_measure_ids` (Phase 2) |
---
## Datenfluss: Company Profile → Compliance Scope → VVT Generator
Das VVT-Modul bezieht seine Daten aus einer **3-stufigen Pipeline**, in der keine Daten doppelt
abgefragt werden. Das Company Profile (`/sdk/company-profile`) dient als Single Source of Truth
fuer Stammdaten. Der Compliance Scope (`/sdk/compliance-scope`) fungiert als impliziter
**Daten-Verteilungs-Agent** — jede Scope-Frage deklariert per `mapsToVVTQuestion`-Eigenschaft,
welche VVT-Frage sie befuellt.
### Gesamtablauf
```mermaid
sequenceDiagram
participant CP as Company Profile
participant SE as Compliance Scope<br/>(Block 1-9)
participant VG as VVT Generator
participant DB as PostgreSQL
Note over CP: Stammdaten:<br/>DSB, Branche, Mitarbeiter,<br/>Angebote, Geschaeftsmodell
CP->>SE: prefillFromCompanyProfile(profile)<br/>+ getAutoFilledScoringAnswers(profile)
Note over SE: Auto-Prefill:<br/>dpoName → org_has_dsb<br/>offerings → prod_type<br/>employeeCount → org_employee_count
SE->>SE: Block 8: Abteilungswahl<br/>(personal, finanzen, marketing, ...)
SE->>SE: Block 9: Datenkategorien pro Abteilung<br/>(dk_dept_hr → NAME, SALARY_DATA, ...)
SE->>VG: exportToVVTAnswers(scopeAnswers)<br/>→ mapsToVVTQuestion-Mapping
Note over VG: prefillFromScopeAnswers():<br/>Scope-Antworten → ProfilingAnswers
VG->>VG: generateActivities(profilingAnswers)<br/>→ Template-Triggering + Enrichment
VG->>DB: POST /vvt/activities (je Aktivitaet)
Note over DB: VVT-Aktivitaeten gespeichert<br/>mit Library-Refs + Freitext
```
### Stufe 1: Company Profile → Scope (automatisches Prefill)
Beim Oeffnen des Compliance-Scope-Moduls werden Stammdaten aus dem Company Profile automatisch
in Scope-Antworten ueberfuehrt — der Nutzer muss diese Daten nicht erneut eingeben.
**Funktion:** `prefillFromCompanyProfile()` (`compliance-scope-profiling.ts:764`)
| Company Profile Feld | Scope-Frage | Mapping |
|----------------------|-------------|---------|
| `dpoName` (nicht leer) | `org_has_dsb` | `true` |
| `offerings` (WebApp) | `prod_type` | `['webapp']` |
| `offerings` (SaaS) | `prod_type` | `['saas']` |
| `offerings` (Webshop) | `prod_webshop` | `true` |
**Funktion:** `getAutoFilledScoringAnswers()` (`compliance-scope-profiling.ts:844`)
| Company Profile Feld | Scope-Frage | Zweck |
|----------------------|-------------|-------|
| `employeeCount` | `org_employee_count` | Scoring + Art. 30 Abs. 5 Pruefung |
| `annualRevenue` | `org_annual_revenue` | Scoring |
| `industry` | `org_industry` | Scoring + Branchenkontext |
| `businessModel` | `org_business_model` | Scoring |
### Stufe 2: Compliance Scope — Block 8 + Block 9
#### Block 8: Verarbeitungstaetigkeiten (Abteilungswahl)
Die Frage `vvt_departments` (Multi-Choice) bestimmt, welche Abteilungen personenbezogene Daten verarbeiten:
| Auswahl-Wert | Department-Key(s) | Beschreibung |
|--------------|-------------------|-------------|
| `personal` | `dept_hr`, `dept_recruiting` | Personal + Bewerbermanagement |
| `finanzen` | `dept_finance` | Finanzen & Buchhaltung |
| `vertrieb` | `dept_sales` | Vertrieb & CRM |
| `marketing` | `dept_marketing` | Marketing |
| `it` | `dept_it` | IT / Administration |
| `recht` | `dept_recht` | Recht / Compliance |
| `kundenservice` | `dept_support` | Kundenservice / Support |
| `produktion` | `dept_produktion` | Produktion / Fertigung |
| `logistik` | `dept_logistik` | Logistik / Versand |
| `einkauf` | `dept_einkauf` | Einkauf / Beschaffung |
| `facility` | `dept_facility` | Facility Management |
Das Mapping erfolgt in `ScopeWizardTab.tsx` ueber `DEPT_VALUE_TO_KEY`.
#### Block 9: Datenkategorien pro Abteilung
Fuer jede in Block 8 gewaehlte Abteilung wird eine eigene Frage mit spezifischen Datenkategorien angezeigt.
Die Datenkategorien stammen aus `DEPARTMENT_DATA_CATEGORIES` (`vvt-profiling.ts:306`).
**12 Abteilungen mit insgesamt ~80 Datenkategorien:**
| Abteilung | Scope-Frage | VVT-Mapping | Kategorien (Auswahl) | Art. 9 |
|-----------|-------------|-------------|---------------------|--------|
| Personal (HR) | `dk_dept_hr` | `dept_hr_categories` | Stammdaten, Gehalt, SV-Nr., Bankverbindung, Gesundheit, Religion | Gesundheit, Religion |
| Recruiting | `dk_dept_recruiting` | `dept_recruiting_categories` | Bewerberstammdaten, Bewerbungsunterlagen, Qualifikationen | Gesundheit |
| Finanzen | `dk_dept_finance` | `dept_finance_categories` | Kunden-/Lieferantendaten, Bankverbindungen, Steuer-IDs, Rechnungen | — |
| Vertrieb | `dk_dept_sales` | `dept_sales_categories` | Kontaktdaten, CRM-Daten, Kommunikation, Vertragsdaten | — |
| Marketing | `dk_dept_marketing` | `dept_marketing_categories` | E-Mail, Tracking, Consent, Social-Media, Interessenprofil | — |
| Support | `dk_dept_support` | `dept_support_categories` | Kundenstammdaten, Tickets, Kommunikation, Vertragsdaten | — |
| IT | `dk_dept_it` | `dept_it_categories` | Benutzerkonten, Logs, Geraete, Netzwerk, E-Mail, Backups | — |
| Recht | `dk_dept_recht` | `dept_recht_categories` | Vertraege, Compliance-Daten, Vorfaelle, Strafrechtliche Daten | Strafrechtlich |
| Produktion | `dk_dept_produktion` | `dept_produktion_categories` | Schichtplaene, Mitarbeiterdaten, Arbeitsschutz, Zugang | Gesundheit |
| Logistik | `dk_dept_logistik` | `dept_logistik_categories` | Empfaenger, Versandadressen, Sendungsverfolgung, Fahrer | — |
| Einkauf | `dk_dept_einkauf` | `dept_einkauf_categories` | Lieferantenkontakte, Vertraege, Bankverbindungen | — |
| Facility | `dk_dept_facility` | `dept_facility_categories` | Zutrittsdaten, Dienstleister, Videoueberwachung, Besucher | Gesundheit |
**Smart Auto-Prefill:** Beim erstmaligen Aufklappen einer Abteilungskarte werden automatisch
alle Kategorien mit `isTypical: true` vorausgewaehlt. Art.-9-Kategorien werden orange hervorgehoben.
### Stufe 3: Scope → VVT Generator
**Funktion:** `exportToVVTAnswers()` (`compliance-scope-profiling.ts:987`)
Jede Scope-Frage, die ein `mapsToVVTQuestion`-Attribut traegt, wird in das VVT-Antwort-Format
ueberfuehrt. Das Mapping ist **deklarativ** — kein imperativer Verteilungscode.
**Funktion:** `generateActivities()` (`vvt-profiling.ts:459`)
1. **Template-Triggering:** Jede VVT-Profiling-Frage hat ein `triggersTemplates`-Array. Wird eine Boolean-Frage mit `true` beantwortet, werden alle referenzierten Templates aktiviert.
2. **IT-Baseline:** Die 4 IT-Templates (Systemadministration, Backup, Logging, IAM) werden **immer** generiert.
3. **Enrichment:** `enrichActivityFromAnswers()` reichert Aktivitaeten an:
- `transfer_cloud_us = true` → US-Drittlandtransfer mit SCC + TIA auf jede Aktivitaet
- `data_health = true``HEALTH_DATA` + Art. 9 Rechtsgrundlage auf HR-Aktivitaeten
- `data_minors = true``MINORS` als Betroffenenkategorie auf Support/Engineering
- `special_ai / special_video_surveillance``dpiaRequired = true`
4. **Art. 30 Abs. 5 Pruefung:** `< 250 Mitarbeiter UND keine besonderen Kategorien → Ausnahme moeglich`
### 16 vorbefuellte Fragen (SCOPE_PREFILLED_VVT_QUESTIONS)
Diese VVT-Profiling-Fragen werden automatisch aus Scope-Antworten befuellt,
sodass der Nutzer sie nicht doppelt beantworten muss:
| VVT-Frage | Quelle (Scope-Block) |
|-----------|---------------------|
| `org_industry` | Block 1 (Organisation) |
| `org_employees` | Company Profile |
| `org_b2b_b2c` | Block 1 |
| `dept_hr` | Block 2/8 (Abteilungen) |
| `dept_finance` | Block 2/8 |
| `dept_marketing` | Block 2/8 |
| `data_health` | Block 2/4 (Datenkategorien) |
| `data_minors` | Block 2/4 |
| `data_biometric` | Block 2/4 |
| `data_criminal` | Block 2/4 |
| `special_ai` | Block 3/7 (Besondere Verarbeitungen) |
| `special_video_surveillance` | Block 3/4 |
| `special_tracking` | Block 3/4 |
| `transfer_cloud_us` | Block 4 (Drittland) |
| `transfer_subprocessor` | Block 4 |
| `transfer_support_non_eu` | Block 4 |
### Cross-Modul-Datenverteilung
Dasselbe deklarative Muster wird auch fuer andere Module verwendet:
| Modul | Export-Funktion | Mapping-Attribut |
|-------|----------------|-----------------|
| VVT | `exportToVVTAnswers()` | `mapsToVVTQuestion` |
| Loeschfristen | `exportToLoeschfristenAnswers()` | `mapsToLFQuestion` |
| TOM Generator | `exportToTOMProfile()` | (direkte Ableitung) |
**Bidirektionale Mappings:** `prefillFromVVTAnswers()` und `prefillFromLoeschfristenAnswers()`
ermoeglichen auch den Rueckfluss: Wenn ein Nutzer zuerst das VVT-Modul verwendet, koennen
diese Antworten in den Scope uebernommen werden.
---
## Datei-Uebersicht: Scope-Integration
| Datei | Beschreibung |
|-------|-------------|
| `lib/sdk/compliance-scope-profiling.ts` | Scope Engine: 9 Bloecke, Export-Funktionen, Company-Profile-Prefill |
| `lib/sdk/vvt-profiling.ts` | VVT-Profiling: 25 Fragen, 12 Abteilungs-Datenkategorien, Generator |
| `lib/sdk/vvt-baseline-catalog.ts` | 18 Baseline-Templates mit Freitext-Feldern |
| `components/sdk/compliance-scope/ScopeWizardTab.tsx` | Block-9-UI: Accordion, Auto-Prefill, Art.-9-Badges |
| `lib/sdk/__tests__/vvt-scope-integration.test.ts` | 35 Integrationstests fuer die gesamte Pipeline |
---
## Phase 2 — Geplante Erweiterungen
| Feature | Beschreibung |
|---------|-------------|
| Processor Records Backend | DB-Tabelle + API-Endpoints fuer Art. 30 Abs. 2 Auftragsverarbeiter |
| Link-Tabellen | M:N-Verknuepfungen VVT <-> Loeschfristen und VVT <-> TOM |
| Bidirektionaler Sync | Link-Operation aktualisiert auch Ziel-Modul |
| VVT Generator Service | Backend-basierte Auto-Fill Engine mit Company Profile + Templates |
| LibraryAutocomplete-Komponente | Wiederverwendbare Frontend-Komponente fuer alle Library-Felder |
| Word/DOCX-Export | Ergaenzung des PDF-Drucks um nativen Word-Export |
+235 -15
View File
@@ -1,33 +1,253 @@
# Whistleblower — Hinweisgebersystem
HinSchG-konformes Hinweisgebersystem fuer anonyme Meldungen und sichere Fallbearbeitung.
HinSchG-konformes Hinweisgebersystem fuer anonyme und namentliche Meldungen, sichere Fallbearbeitung und automatische Fristenueberwachung.
## Gesetzliche Grundlage
### Hinweisgeberschutzgesetz (HinSchG)
Das **Hinweisgeberschutzgesetz (HinSchG)** setzt die EU-Whistleblowing-Richtlinie (EU) 2019/1937 in deutsches Recht um. Es ist seit dem **2. Juli 2023** in Kraft.
| Datum | Pflicht |
|-------|---------|
| 02.07.2023 | Inkrafttreten fuer Unternehmen ab 250 Beschaeftigten |
| 17.12.2023 | Erweiterung auf Unternehmen ab 50 Beschaeftigten (ss 12 HinSchG) |
### Sachlicher Anwendungsbereich (ss 2 HinSchG)
Das Gesetz schuetzt Hinweisgeber, die Informationen ueber **Verstoesse** melden, die unter anderem folgende Bereiche betreffen:
- **Strafrecht** — Straftaten nach StGB und Nebenstrafrecht
- **Datenschutz** — Verstoesse gegen DSGVO und BDSG
- **Geldwaesche** — Verstoesse gegen das Geldwaeschegesetz (GwG)
- **Produktsicherheit** — Verstoesse gegen Produktsicherheitsvorschriften
- **Umweltschutz** — Verstoesse gegen Umweltauflagen und -gesetze
- **Arbeitsschutz** — Verstoesse gegen Arbeitnehmerrechte und Arbeitsschutzvorschriften
- **Lebensmittelsicherheit** — Verstoesse gegen lebensmittelrechtliche Vorgaben
- **Wettbewerbs- und Kartellrecht** — Unlauterer Wettbewerb, Marktmanipulation
- **Verbraucherschutz** — Verstoesse gegen Verbraucherschutzvorschriften
- **Steuerrecht** — Steuerverstoesse bei Unternehmen
### Geschuetzte Personengruppen (ss 1 HinSchG)
- Arbeitnehmerinnen und Arbeitnehmer
- Beamtinnen und Beamte
- Auszubildende und Praktikanten
- Freiwillige und ehrenamtlich Taetige
- Selbststaendige und Anteilseigner
- Mitglieder von Leitungs- und Aufsichtsorganen
- Personen, die im Rahmen einer Bewerbung Informationen erlangt haben
### Fristen und Pflichten
| Pflicht | Frist | Rechtsgrundlage |
|---------|-------|-----------------|
| Eingangsbestaetigung | **7 Tage** nach Meldungseingang | ss 17 Abs. 1 S. 2 HinSchG |
| Rueckmeldung ueber Folgemaßnahmen | **3 Monate** nach Eingangsbestaetigung | ss 17 Abs. 2 HinSchG |
| Aufbewahrung der Dokumentation | **3 Jahre** nach Abschluss des Verfahrens | ss 11 Abs. 5 HinSchG |
### Schutz des Hinweisgebers
| Schutzmechanismus | Rechtsgrundlage | Beschreibung |
|-------------------|-----------------|--------------|
| **Repressalienverbot** | ss 36 HinSchG | Jede Benachteiligung wegen einer Meldung ist verboten |
| **Beweislastumkehr** | ss 36 Abs. 2 HinSchG | Arbeitgeber muss beweisen, dass Maßnahmen nicht mit Meldung zusammenhaengen |
| **Schadensersatz** | ss 37 HinSchG | Hinweisgeber hat Anspruch auf Ersatz des erlittenen Schadens |
| **Vertraulichkeit** | ss 8 HinSchG | Identitaet darf nur mit Einwilligung oder bei gesetzlicher Pflicht offengelegt werden |
### Sanktionen (ss 40 HinSchG)
| Verstoß | Bussgeld |
|---------|----------|
| Keine interne Meldestelle eingerichtet | Bis zu **20.000 EUR** |
| Behinderung einer Meldung | Bis zu **50.000 EUR** |
| Verstoß gegen Vertraulichkeitsgebot | Bis zu **50.000 EUR** |
| Repressalien gegen Hinweisgeber | Bis zu **50.000 EUR** |
---
## Features
- **Anonyme Meldungen** — Sichere, anonyme Eingabe von Hinweisen
- **Fallbearbeitung** — Workflow fuer Sichtung, Untersuchung und Abschluss
- **Fristen-Management** Automatische Ueberwachung der gesetzlichen Bearbeitungsfristen (7 Tage Eingangsbestaetigung, 3 Monate Rueckmeldung)
- **Kommunikationskanal**Anonymer Austausch zwischen Hinweisgeber und Ombudsperson
- **Audit-Trail** — Lueckenlose Dokumentation aller Bearbeitungsschritte
- **Anonyme und namentliche Meldungen** — Sichere Eingabe von Hinweisen, wahlweise anonym oder mit Kontaktdaten
- **Mehrstufiger Fallbearbeitungs-Workflow** — Neu → Bestaetigt → In Pruefung Untersuchung → Massnahmen → Abgeschlossen
- **Automatisches Fristen-Management** — Ueberwachung der 7-Tage- und 3-Monate-Fristen gemaess ss 17 HinSchG mit Warnungen bei drohender Ueberschreitung
- **Anonymer Kommunikationskanal**Sicherer Austausch zwischen Hinweisgeber und Ombudsperson ohne Identitaetspreisgabe
- **Massnahmen-Tracking** — Dokumentation und Nachverfolgung von Folgemaßnahmen
- **Prioritaetsstufen** — Klassifizierung nach Niedrig, Normal, Hoch, Kritisch
- **Audit-Trail** — Lueckenlose, revisionssichere Dokumentation aller Bearbeitungsschritte
- **Kategorisierung** — Vordefinierte Meldekategorien (Korruption, Betrug, Datenschutz, Diskriminierung, Umwelt, Wettbewerb, Produktsicherheit, Steuerhinterziehung)
- **Statistik-Dashboard** — Ueberblick ueber Meldungsaufkommen, Bearbeitungsstand und Fristeneinhaltung
---
## Architektur
### Bearbeitungs-Workflow
```mermaid
stateDiagram-v2
[*] --> Neu: Meldung eingereicht
Neu --> Bestaetigt: Eingangsbestaetigung (≤ 7 Tage)
Bestaetigt --> InPruefung: Inhaltliche Pruefung
InPruefung --> Untersuchung: Formelle Untersuchung
Untersuchung --> Massnahmen: Folgemaßnahmen eingeleitet
Massnahmen --> Abgeschlossen: Rueckmeldung (≤ 3 Monate)
InPruefung --> Abgelehnt: Unbegruendet / nicht zustaendig
Abgeschlossen --> [*]
Abgelehnt --> [*]
```
### Komponenten
| Komponente | Technologie | Beschreibung |
|------------|-------------|--------------|
| Frontend (Admin) | Next.js / React | SDK-Seite unter `/sdk/whistleblower` mit Tabs: Uebersicht, Neue Meldungen, In Untersuchung, Abgeschlossen, Einstellungen |
| API-Proxy | Next.js API Route | `/api/sdk/v1/whistleblower/[[...path]]/route.ts` — Proxy zum Backend |
| Backend-Handlers | Go / Gin | `whistleblower_handlers.go` — REST API fuer Meldungen, Nachrichten, Statistiken |
| Datenschicht | Go | `store.go` — PostgreSQL-Operationen, prepared statements |
| Datenmodell | Go | `models.go` — Structs fuer Report, Message, Measure, AuditEntry |
| TypeScript Types | TypeScript | `lib/sdk/whistleblower/types.ts` — Frontend-Typen, Deadline-Utilities |
| API Client | TypeScript | `lib/sdk/whistleblower/api.ts` — SDK-API-Aufrufe |
| DB-Schema | SQL | `migrations/009_whistleblower_schema.sql` |
---
## API Endpoints
Alle unter `/api/v1/whistleblower/`, benoetigen `X-Tenant-ID` Header.
### Admin-Endpoints
| Method | Endpoint | Beschreibung |
|--------|----------|-------------|
| GET | `/reports` | Meldungen auflisten |
| POST | `/reports` | Neue Meldung erstellen |
| GET | `/reports/{id}` | Meldungsdetails |
| PUT | `/reports/{id}/status` | Status aktualisieren |
| POST | `/reports/{id}/messages` | Nachricht hinzufuegen |
| GET | `/reports/{id}/messages` | Nachrichten abrufen |
| GET | `/statistics` | Statistiken |
| GET | `/reports` | Meldungen auflisten (mit Filter und Paginierung) |
| POST | `/reports` | Neue Meldung erfassen |
| GET | `/reports/{id}` | Meldungsdetails inkl. Nachrichten, Massnahmen, Audit-Trail |
| PUT | `/reports/{id}` | Meldung aktualisieren (Status, Prioritaet, Zuweisung) |
| DELETE | `/reports/{id}` | Meldung loeschen |
| POST | `/reports/{id}/messages` | Nachricht an Hinweisgeber senden (Ombudsperson-Rolle) |
| GET | `/reports/{id}/messages` | Nachrichten-Verlauf abrufen |
| GET | `/statistics` | Statistiken (Gesamt, nach Kategorie, nach Status, ueberfaellige) |
### Oeffentliche Endpoints (fuer Hinweisgeber)
| Method | Endpoint | Beschreibung |
|--------|----------|-------------|
| POST | `/public/reports` | Anonyme/namentliche Meldung einreichen |
| GET | `/public/reports/{accessKey}` | Meldungsstatus mit Zugangscode abfragen |
| POST | `/public/reports/{accessKey}/messages` | Nachricht als Hinweisgeber senden |
---
## Frontend
Seite unter `/sdk/whistleblower` mit Meldungsuebersicht, Falldetails und Statistik-Dashboard.
### SDK Admin-Seite (`/sdk/whistleblower`)
Die Seite bietet fuenf Tabs:
| Tab | Inhalt |
|-----|--------|
| **Uebersicht** | Statistik-Cards, HinSchG-Info-Box mit Fristen und Anwendungsbereich, Fristenwarnungen, alle Meldungen |
| **Neue Meldungen** | Gefilterte Ansicht: nur Status "Neu" — Eingangsbestaetigung steht aus |
| **In Untersuchung** | Gefilterte Ansicht: Status "Bestaetigt", "In Pruefung", "Untersuchung", "Massnahmen" |
| **Abgeschlossen** | Gefilterte Ansicht: Status "Abgeschlossen" und "Abgelehnt" |
| **Einstellungen** | Konfiguration (in spaeteren Versionen) |
### Funktionen
- **Meldung erfassen**: Modal-Dialog fuer Titel, Beschreibung, Kategorie, Prioritaet, anonym/namentlich
- **Falldetail-Drawer**: Seitenleiste mit Beschreibung, Badges, Status-Transitions, Zuweisungen, Kommentare, Nachrichten-Verlauf
- **Filter**: Kategorie, Status, Prioritaet — kombinierbar
- **Sortierung**: Ueberfaellige Meldungen zuerst, dann nach Prioritaet, dann nach Datum
- **Fristenwarnungen**: Rote Alerts bei ueberschrittenen 7-Tage- oder 3-Monate-Fristen
---
## Datenbank
Migration `009_whistleblower_schema.sql` erstellt Tabellen fuer Meldungen, Nachrichten und Bearbeitungsschritte.
### Schema (Migration `009_whistleblower_schema.sql`)
#### Tabelle: `whistleblower_reports`
| Spalte | Typ | Beschreibung |
|--------|-----|--------------|
| `id` | UUID | Primaerschluessel |
| `tenant_id` | UUID | Mandanten-Zuordnung |
| `reference_number` | VARCHAR | Referenznummer (z.B. "WB-2026-000042") |
| `access_key` | VARCHAR | Anonymer Zugangscode (XXXX-XXXX-XXXX) |
| `category` | VARCHAR | Meldekategorie |
| `status` | VARCHAR | Bearbeitungsstatus |
| `priority` | VARCHAR | Prioritaetsstufe |
| `title` | VARCHAR | Meldungstitel |
| `description` | TEXT | Detailbeschreibung |
| `is_anonymous` | BOOLEAN | Anonyme Meldung |
| `reporter_name` | VARCHAR | Name (optional) |
| `reporter_email` | VARCHAR | E-Mail (optional) |
| `assigned_to` | VARCHAR | Zustaendige Person |
| `received_at` | TIMESTAMP | Eingangszeitpunkt |
| `acknowledged_at` | TIMESTAMP | Eingangsbestaetigung |
| `deadline_acknowledgment` | TIMESTAMP | 7-Tage-Frist (automatisch berechnet) |
| `deadline_feedback` | TIMESTAMP | 3-Monate-Frist (automatisch berechnet) |
| `closed_at` | TIMESTAMP | Abschlusszeitpunkt |
#### Tabelle: `whistleblower_messages`
Anonymer Kommunikationskanal zwischen Hinweisgeber und Ombudsperson.
#### Tabelle: `whistleblower_measures`
Dokumentation von Folgemaßnahmen mit Status-Tracking (geplant, in Bearbeitung, abgeschlossen).
#### Tabelle: `whistleblower_audit_trail`
Lueckenlose, revisionssichere Protokollierung aller Bearbeitungsschritte.
---
## Meldekategorien
| Kategorie | Beschreibung | Beispiele |
|-----------|--------------|-----------|
| Korruption | Bestechung, Vorteilsnahme | Schmiergeldzahlungen, Kickback-Vereinbarungen |
| Betrug | Vermoegensdelikte | Urkundenfaelschung, Bilanzbetrug |
| Datenschutz | DSGVO/BDSG-Verstoesse | Unerlaubte Datenweitergabe, fehlende Einwilligung |
| Diskriminierung | Benachteiligung | Mobbing, sexuelle Belaestigung, AGG-Verstoesse |
| Umwelt | Umweltvergehen | Illegale Entsorgung, Emissionsverstoesse |
| Wettbewerb | Kartellrecht | Preisabsprachen, Marktmanipulation |
| Produktsicherheit | Sicherheitsmaengel | Mangelhafte Produkte, fehlende Warnhinweise |
| Steuerhinterziehung | Steuerverstoesse | Steuerhinterziehung, illegale Steuergestaltung |
| Sonstiges | Weitere Verstoesse | Interne Richtlinienverstoesse |
---
## Fristen-Tracking
Das System berechnet Fristen automatisch und warnt bei drohender Ueberschreitung:
| Frist | Berechnung | Warnstufe |
|-------|------------|-----------|
| 7-Tage-Eingangsbestaetigung | `received_at + 7 Tage` | Orange ab 2 Tage vorher, Rot bei Ueberschreitung |
| 3-Monate-Rueckmeldung | `acknowledged_at + 3 Monate` | Orange ab 14 Tage vorher, Rot bei Ueberschreitung |
Utility-Funktionen in `types.ts`:
- `getDaysUntilAcknowledgment(report)` — Verbleibende Tage bis Eingangsbestaetigung
- `getDaysUntilFeedback(report)` — Verbleibende Tage bis Rueckmeldungsfrist
- `isAcknowledgmentOverdue(report)` — Prueft 7-Tage-Frist
- `isFeedbackOverdue(report)` — Prueft 3-Monate-Frist
- `generateAccessKey()` — Erzeugt Zugangscode im Format XXXX-XXXX-XXXX
---
## Datei-Referenz
| Datei | Beschreibung |
|-------|--------------|
| `admin-compliance/app/sdk/whistleblower/page.tsx` | Frontend-Seite (Tabs, Filter, Modals, Detail-Drawer) |
| `admin-compliance/app/api/sdk/v1/whistleblower/[[...path]]/route.ts` | API-Proxy zum Backend |
| `admin-compliance/lib/sdk/whistleblower/types.ts` | TypeScript-Typen, Enums, Deadline-Utilities |
| `admin-compliance/lib/sdk/whistleblower/api.ts` | API-Client fuer SDK-Backend |
| `ai-compliance-sdk/internal/whistleblower/models.go` | Go-Datenmodelle |
| `ai-compliance-sdk/internal/whistleblower/store.go` | PostgreSQL-Store (CRUD, Queries) |
| `ai-compliance-sdk/internal/api/handlers/whistleblower_handlers.go` | REST-API-Handler |
| `ai-compliance-sdk/migrations/009_whistleblower_schema.sql` | Datenbankschema |