feat(sdk): VVT master libraries, process templates, Loeschfristen profiling + document
VVT: Master library tables (7 catalogs), 500+ seed entries, process templates with instantiation, library API endpoints + 18 tests. Loeschfristen: Baseline catalog, compliance checks, profiling engine, HTML document generator, MkDocs documentation. Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
This commit is contained in:
@@ -1755,6 +1755,20 @@ class VVTActivityCreate(BaseModel):
|
||||
next_review_at: Optional[datetime] = None
|
||||
created_by: Optional[str] = None
|
||||
dsfa_id: Optional[str] = None
|
||||
# Library refs (optional, parallel to freetext)
|
||||
purpose_refs: Optional[List[str]] = None
|
||||
legal_basis_refs: Optional[List[str]] = None
|
||||
data_subject_refs: Optional[List[str]] = None
|
||||
data_category_refs: Optional[List[str]] = None
|
||||
recipient_refs: Optional[List[str]] = None
|
||||
retention_rule_ref: Optional[str] = None
|
||||
transfer_mechanism_refs: Optional[List[str]] = None
|
||||
tom_refs: Optional[List[str]] = None
|
||||
source_template_id: Optional[str] = None
|
||||
risk_score: Optional[int] = None
|
||||
linked_loeschfristen_ids: Optional[List[str]] = None
|
||||
linked_tom_measure_ids: Optional[List[str]] = None
|
||||
art30_completeness: Optional[Dict[str, Any]] = None
|
||||
|
||||
|
||||
class VVTActivityUpdate(BaseModel):
|
||||
@@ -1783,6 +1797,20 @@ class VVTActivityUpdate(BaseModel):
|
||||
next_review_at: Optional[datetime] = None
|
||||
created_by: Optional[str] = None
|
||||
dsfa_id: Optional[str] = None
|
||||
# Library refs
|
||||
purpose_refs: Optional[List[str]] = None
|
||||
legal_basis_refs: Optional[List[str]] = None
|
||||
data_subject_refs: Optional[List[str]] = None
|
||||
data_category_refs: Optional[List[str]] = None
|
||||
recipient_refs: Optional[List[str]] = None
|
||||
retention_rule_ref: Optional[str] = None
|
||||
transfer_mechanism_refs: Optional[List[str]] = None
|
||||
tom_refs: Optional[List[str]] = None
|
||||
source_template_id: Optional[str] = None
|
||||
risk_score: Optional[int] = None
|
||||
linked_loeschfristen_ids: Optional[List[str]] = None
|
||||
linked_tom_measure_ids: Optional[List[str]] = None
|
||||
art30_completeness: Optional[Dict[str, Any]] = None
|
||||
|
||||
|
||||
class VVTActivityResponse(BaseModel):
|
||||
@@ -1813,6 +1841,20 @@ class VVTActivityResponse(BaseModel):
|
||||
next_review_at: Optional[datetime] = None
|
||||
created_by: Optional[str] = None
|
||||
dsfa_id: Optional[str] = None
|
||||
# Library refs
|
||||
purpose_refs: Optional[List[str]] = None
|
||||
legal_basis_refs: Optional[List[str]] = None
|
||||
data_subject_refs: Optional[List[str]] = None
|
||||
data_category_refs: Optional[List[str]] = None
|
||||
recipient_refs: Optional[List[str]] = None
|
||||
retention_rule_ref: Optional[str] = None
|
||||
transfer_mechanism_refs: Optional[List[str]] = None
|
||||
tom_refs: Optional[List[str]] = None
|
||||
source_template_id: Optional[str] = None
|
||||
risk_score: Optional[int] = None
|
||||
linked_loeschfristen_ids: Optional[List[str]] = None
|
||||
linked_tom_measure_ids: Optional[List[str]] = None
|
||||
art30_completeness: Optional[Dict[str, Any]] = None
|
||||
created_at: datetime
|
||||
updated_at: Optional[datetime] = None
|
||||
|
||||
|
||||
427
backend-compliance/compliance/api/vvt_library_routes.py
Normal file
427
backend-compliance/compliance/api/vvt_library_routes.py
Normal file
@@ -0,0 +1,427 @@
|
||||
"""
|
||||
FastAPI routes for VVT Master Libraries + Process Templates.
|
||||
|
||||
Library endpoints (read-only, global):
|
||||
GET /vvt/libraries — Overview: all library types + counts
|
||||
GET /vvt/libraries/data-subjects — Data subjects (filter: typical_for)
|
||||
GET /vvt/libraries/data-categories — Hierarchical (filter: parent_id, is_art9, flat)
|
||||
GET /vvt/libraries/recipients — Recipients (filter: type)
|
||||
GET /vvt/libraries/legal-bases — Legal bases (filter: is_art9, type)
|
||||
GET /vvt/libraries/retention-rules — Retention rules
|
||||
GET /vvt/libraries/transfer-mechanisms — Transfer mechanisms
|
||||
GET /vvt/libraries/purposes — Purposes (filter: typical_for)
|
||||
GET /vvt/libraries/toms — TOMs (filter: category)
|
||||
|
||||
Template endpoints:
|
||||
GET /vvt/templates — List templates (filter: business_function, search)
|
||||
GET /vvt/templates/{id} — Single template with resolved labels
|
||||
POST /vvt/templates/{id}/instantiate — Create VVT activity from template
|
||||
"""
|
||||
|
||||
import logging
|
||||
import uuid
|
||||
from datetime import datetime
|
||||
from typing import Optional
|
||||
|
||||
from fastapi import APIRouter, Depends, HTTPException, Query, Request
|
||||
from sqlalchemy.orm import Session
|
||||
|
||||
from classroom_engine.database import get_db
|
||||
|
||||
from ..db.vvt_library_models import (
|
||||
VVTLibDataSubjectDB,
|
||||
VVTLibDataCategoryDB,
|
||||
VVTLibRecipientDB,
|
||||
VVTLibLegalBasisDB,
|
||||
VVTLibRetentionRuleDB,
|
||||
VVTLibTransferMechanismDB,
|
||||
VVTLibPurposeDB,
|
||||
VVTLibTomDB,
|
||||
VVTProcessTemplateDB,
|
||||
)
|
||||
from ..db.vvt_models import VVTActivityDB, VVTAuditLogDB
|
||||
from .tenant_utils import get_tenant_id
|
||||
|
||||
logger = logging.getLogger(__name__)
|
||||
router = APIRouter(prefix="/vvt", tags=["compliance-vvt-libraries"])
|
||||
|
||||
|
||||
# ============================================================================
|
||||
# Helper: row → dict
|
||||
# ============================================================================
|
||||
|
||||
def _row_to_dict(row, extra_fields=None):
|
||||
"""Generic row → dict for library items."""
|
||||
d = {
|
||||
"id": row.id,
|
||||
"label_de": row.label_de,
|
||||
}
|
||||
if hasattr(row, 'description_de') and row.description_de:
|
||||
d["description_de"] = row.description_de
|
||||
if hasattr(row, 'sort_order'):
|
||||
d["sort_order"] = row.sort_order
|
||||
if extra_fields:
|
||||
for f in extra_fields:
|
||||
if hasattr(row, f):
|
||||
val = getattr(row, f)
|
||||
if val is not None:
|
||||
d[f] = val
|
||||
return d
|
||||
|
||||
|
||||
# ============================================================================
|
||||
# Library Overview
|
||||
# ============================================================================
|
||||
|
||||
@router.get("/libraries")
|
||||
async def get_libraries_overview(db: Session = Depends(get_db)):
|
||||
"""Overview of all library types with item counts."""
|
||||
return {
|
||||
"libraries": [
|
||||
{"type": "data-subjects", "count": db.query(VVTLibDataSubjectDB).count()},
|
||||
{"type": "data-categories", "count": db.query(VVTLibDataCategoryDB).count()},
|
||||
{"type": "recipients", "count": db.query(VVTLibRecipientDB).count()},
|
||||
{"type": "legal-bases", "count": db.query(VVTLibLegalBasisDB).count()},
|
||||
{"type": "retention-rules", "count": db.query(VVTLibRetentionRuleDB).count()},
|
||||
{"type": "transfer-mechanisms", "count": db.query(VVTLibTransferMechanismDB).count()},
|
||||
{"type": "purposes", "count": db.query(VVTLibPurposeDB).count()},
|
||||
{"type": "toms", "count": db.query(VVTLibTomDB).count()},
|
||||
]
|
||||
}
|
||||
|
||||
|
||||
# ============================================================================
|
||||
# Data Subjects
|
||||
# ============================================================================
|
||||
|
||||
@router.get("/libraries/data-subjects")
|
||||
async def list_data_subjects(
|
||||
typical_for: Optional[str] = Query(None, description="Filter by business function"),
|
||||
db: Session = Depends(get_db),
|
||||
):
|
||||
query = db.query(VVTLibDataSubjectDB).order_by(VVTLibDataSubjectDB.sort_order)
|
||||
rows = query.all()
|
||||
items = [_row_to_dict(r, ["art9_relevant", "typical_for"]) for r in rows]
|
||||
if typical_for:
|
||||
items = [i for i in items if typical_for in (i.get("typical_for") or [])]
|
||||
return items
|
||||
|
||||
|
||||
# ============================================================================
|
||||
# Data Categories (hierarchical)
|
||||
# ============================================================================
|
||||
|
||||
@router.get("/libraries/data-categories")
|
||||
async def list_data_categories(
|
||||
flat: Optional[bool] = Query(False, description="Return flat list instead of tree"),
|
||||
parent_id: Optional[str] = Query(None),
|
||||
is_art9: Optional[bool] = Query(None),
|
||||
db: Session = Depends(get_db),
|
||||
):
|
||||
query = db.query(VVTLibDataCategoryDB).order_by(VVTLibDataCategoryDB.sort_order)
|
||||
if parent_id is not None:
|
||||
query = query.filter(VVTLibDataCategoryDB.parent_id == parent_id)
|
||||
if is_art9 is not None:
|
||||
query = query.filter(VVTLibDataCategoryDB.is_art9 == is_art9)
|
||||
rows = query.all()
|
||||
|
||||
extra = ["parent_id", "is_art9", "is_art10", "risk_weight", "default_retention_rule", "default_legal_basis"]
|
||||
items = [_row_to_dict(r, extra) for r in rows]
|
||||
|
||||
if flat or parent_id is not None or is_art9 is not None:
|
||||
return items
|
||||
|
||||
# Build tree
|
||||
by_parent: dict = {}
|
||||
for item in items:
|
||||
pid = item.get("parent_id")
|
||||
by_parent.setdefault(pid, []).append(item)
|
||||
|
||||
tree = []
|
||||
for item in by_parent.get(None, []):
|
||||
children = by_parent.get(item["id"], [])
|
||||
if children:
|
||||
item["children"] = children
|
||||
tree.append(item)
|
||||
return tree
|
||||
|
||||
|
||||
# ============================================================================
|
||||
# Recipients
|
||||
# ============================================================================
|
||||
|
||||
@router.get("/libraries/recipients")
|
||||
async def list_recipients(
|
||||
type: Optional[str] = Query(None, description="INTERNAL, PROCESSOR, CONTROLLER, AUTHORITY"),
|
||||
db: Session = Depends(get_db),
|
||||
):
|
||||
query = db.query(VVTLibRecipientDB).order_by(VVTLibRecipientDB.sort_order)
|
||||
if type:
|
||||
query = query.filter(VVTLibRecipientDB.type == type)
|
||||
rows = query.all()
|
||||
return [_row_to_dict(r, ["type", "is_third_country", "country"]) for r in rows]
|
||||
|
||||
|
||||
# ============================================================================
|
||||
# Legal Bases
|
||||
# ============================================================================
|
||||
|
||||
@router.get("/libraries/legal-bases")
|
||||
async def list_legal_bases(
|
||||
is_art9: Optional[bool] = Query(None),
|
||||
type: Optional[str] = Query(None),
|
||||
db: Session = Depends(get_db),
|
||||
):
|
||||
query = db.query(VVTLibLegalBasisDB).order_by(VVTLibLegalBasisDB.sort_order)
|
||||
if is_art9 is not None:
|
||||
query = query.filter(VVTLibLegalBasisDB.is_art9 == is_art9)
|
||||
if type:
|
||||
query = query.filter(VVTLibLegalBasisDB.type == type)
|
||||
rows = query.all()
|
||||
return [_row_to_dict(r, ["article", "type", "is_art9", "typical_national_law"]) for r in rows]
|
||||
|
||||
|
||||
# ============================================================================
|
||||
# Retention Rules
|
||||
# ============================================================================
|
||||
|
||||
@router.get("/libraries/retention-rules")
|
||||
async def list_retention_rules(db: Session = Depends(get_db)):
|
||||
rows = db.query(VVTLibRetentionRuleDB).order_by(VVTLibRetentionRuleDB.sort_order).all()
|
||||
return [_row_to_dict(r, ["legal_basis", "duration", "duration_unit", "start_event", "deletion_procedure"]) for r in rows]
|
||||
|
||||
|
||||
# ============================================================================
|
||||
# Transfer Mechanisms
|
||||
# ============================================================================
|
||||
|
||||
@router.get("/libraries/transfer-mechanisms")
|
||||
async def list_transfer_mechanisms(db: Session = Depends(get_db)):
|
||||
rows = db.query(VVTLibTransferMechanismDB).order_by(VVTLibTransferMechanismDB.sort_order).all()
|
||||
return [_row_to_dict(r, ["article", "requires_tia"]) for r in rows]
|
||||
|
||||
|
||||
# ============================================================================
|
||||
# Purposes
|
||||
# ============================================================================
|
||||
|
||||
@router.get("/libraries/purposes")
|
||||
async def list_purposes(
|
||||
typical_for: Optional[str] = Query(None),
|
||||
db: Session = Depends(get_db),
|
||||
):
|
||||
rows = db.query(VVTLibPurposeDB).order_by(VVTLibPurposeDB.sort_order).all()
|
||||
items = [_row_to_dict(r, ["typical_legal_basis", "typical_for"]) for r in rows]
|
||||
if typical_for:
|
||||
items = [i for i in items if typical_for in (i.get("typical_for") or [])]
|
||||
return items
|
||||
|
||||
|
||||
# ============================================================================
|
||||
# TOMs
|
||||
# ============================================================================
|
||||
|
||||
@router.get("/libraries/toms")
|
||||
async def list_toms(
|
||||
category: Optional[str] = Query(None),
|
||||
db: Session = Depends(get_db),
|
||||
):
|
||||
query = db.query(VVTLibTomDB).order_by(VVTLibTomDB.sort_order)
|
||||
if category:
|
||||
query = query.filter(VVTLibTomDB.category == category)
|
||||
rows = query.all()
|
||||
return [_row_to_dict(r, ["category", "art32_reference"]) for r in rows]
|
||||
|
||||
|
||||
# ============================================================================
|
||||
# Process Templates
|
||||
# ============================================================================
|
||||
|
||||
def _template_to_dict(t: VVTProcessTemplateDB) -> dict:
|
||||
return {
|
||||
"id": t.id,
|
||||
"name": t.name,
|
||||
"description": t.description,
|
||||
"business_function": t.business_function,
|
||||
"purpose_refs": t.purpose_refs or [],
|
||||
"legal_basis_refs": t.legal_basis_refs or [],
|
||||
"data_subject_refs": t.data_subject_refs or [],
|
||||
"data_category_refs": t.data_category_refs or [],
|
||||
"recipient_refs": t.recipient_refs or [],
|
||||
"tom_refs": t.tom_refs or [],
|
||||
"transfer_mechanism_refs": t.transfer_mechanism_refs or [],
|
||||
"retention_rule_ref": t.retention_rule_ref,
|
||||
"typical_systems": t.typical_systems or [],
|
||||
"protection_level": t.protection_level or "MEDIUM",
|
||||
"dpia_required": t.dpia_required or False,
|
||||
"risk_score": t.risk_score,
|
||||
"tags": t.tags or [],
|
||||
"is_system": t.is_system,
|
||||
"sort_order": t.sort_order,
|
||||
}
|
||||
|
||||
|
||||
def _resolve_labels(template_dict: dict, db: Session) -> dict:
|
||||
"""Resolve library IDs to labels within the template dict."""
|
||||
resolvers = {
|
||||
"purpose_refs": (VVTLibPurposeDB, "purpose_labels"),
|
||||
"legal_basis_refs": (VVTLibLegalBasisDB, "legal_basis_labels"),
|
||||
"data_subject_refs": (VVTLibDataSubjectDB, "data_subject_labels"),
|
||||
"data_category_refs": (VVTLibDataCategoryDB, "data_category_labels"),
|
||||
"recipient_refs": (VVTLibRecipientDB, "recipient_labels"),
|
||||
"tom_refs": (VVTLibTomDB, "tom_labels"),
|
||||
"transfer_mechanism_refs": (VVTLibTransferMechanismDB, "transfer_mechanism_labels"),
|
||||
}
|
||||
for refs_key, (model, labels_key) in resolvers.items():
|
||||
ids = template_dict.get(refs_key) or []
|
||||
if ids:
|
||||
rows = db.query(model).filter(model.id.in_(ids)).all()
|
||||
label_map = {r.id: r.label_de for r in rows}
|
||||
template_dict[labels_key] = {rid: label_map.get(rid, rid) for rid in ids}
|
||||
|
||||
# Resolve single retention rule
|
||||
rr = template_dict.get("retention_rule_ref")
|
||||
if rr:
|
||||
row = db.query(VVTLibRetentionRuleDB).filter(VVTLibRetentionRuleDB.id == rr).first()
|
||||
if row:
|
||||
template_dict["retention_rule_label"] = row.label_de
|
||||
|
||||
return template_dict
|
||||
|
||||
|
||||
@router.get("/templates")
|
||||
async def list_templates(
|
||||
business_function: Optional[str] = Query(None),
|
||||
search: Optional[str] = Query(None),
|
||||
db: Session = Depends(get_db),
|
||||
):
|
||||
"""List process templates (system + tenant)."""
|
||||
query = db.query(VVTProcessTemplateDB).order_by(VVTProcessTemplateDB.sort_order)
|
||||
if business_function:
|
||||
query = query.filter(VVTProcessTemplateDB.business_function == business_function)
|
||||
if search:
|
||||
term = f"%{search}%"
|
||||
query = query.filter(
|
||||
(VVTProcessTemplateDB.name.ilike(term)) |
|
||||
(VVTProcessTemplateDB.description.ilike(term))
|
||||
)
|
||||
templates = query.all()
|
||||
return [_template_to_dict(t) for t in templates]
|
||||
|
||||
|
||||
@router.get("/templates/{template_id}")
|
||||
async def get_template(
|
||||
template_id: str,
|
||||
db: Session = Depends(get_db),
|
||||
):
|
||||
"""Get a single template with resolved library labels."""
|
||||
t = db.query(VVTProcessTemplateDB).filter(VVTProcessTemplateDB.id == template_id).first()
|
||||
if not t:
|
||||
raise HTTPException(status_code=404, detail=f"Template '{template_id}' not found")
|
||||
result = _template_to_dict(t)
|
||||
return _resolve_labels(result, db)
|
||||
|
||||
|
||||
@router.post("/templates/{template_id}/instantiate", status_code=201)
|
||||
async def instantiate_template(
|
||||
template_id: str,
|
||||
http_request: Request,
|
||||
tid: str = Depends(get_tenant_id),
|
||||
db: Session = Depends(get_db),
|
||||
):
|
||||
"""Create a new VVT activity from a process template."""
|
||||
t = db.query(VVTProcessTemplateDB).filter(VVTProcessTemplateDB.id == template_id).first()
|
||||
if not t:
|
||||
raise HTTPException(status_code=404, detail=f"Template '{template_id}' not found")
|
||||
|
||||
# Generate unique VVT-ID
|
||||
count = db.query(VVTActivityDB).filter(VVTActivityDB.tenant_id == tid).count()
|
||||
vvt_id = f"VVT-{count + 1:04d}"
|
||||
|
||||
# Resolve library IDs to freetext labels for backward-compat fields
|
||||
purpose_labels = _resolve_ids(db, VVTLibPurposeDB, t.purpose_refs or [])
|
||||
legal_labels = _resolve_ids(db, VVTLibLegalBasisDB, t.legal_basis_refs or [])
|
||||
subject_labels = _resolve_ids(db, VVTLibDataSubjectDB, t.data_subject_refs or [])
|
||||
category_labels = _resolve_ids(db, VVTLibDataCategoryDB, t.data_category_refs or [])
|
||||
recipient_labels = _resolve_ids(db, VVTLibRecipientDB, t.recipient_refs or [])
|
||||
|
||||
# Resolve retention rule
|
||||
retention_period = {}
|
||||
if t.retention_rule_ref:
|
||||
rr = db.query(VVTLibRetentionRuleDB).filter(VVTLibRetentionRuleDB.id == t.retention_rule_ref).first()
|
||||
if rr:
|
||||
retention_period = {
|
||||
"description": rr.label_de,
|
||||
"legalBasis": rr.legal_basis or "",
|
||||
"deletionProcedure": rr.deletion_procedure or "",
|
||||
"duration": rr.duration,
|
||||
"durationUnit": rr.duration_unit,
|
||||
}
|
||||
|
||||
# Build structured TOMs from tom_refs
|
||||
structured_toms = {"accessControl": [], "confidentiality": [], "integrity": [], "availability": [], "separation": []}
|
||||
if t.tom_refs:
|
||||
tom_rows = db.query(VVTLibTomDB).filter(VVTLibTomDB.id.in_(t.tom_refs)).all()
|
||||
for tr in tom_rows:
|
||||
cat = tr.category
|
||||
if cat in structured_toms:
|
||||
structured_toms[cat].append(tr.label_de)
|
||||
|
||||
act = VVTActivityDB(
|
||||
tenant_id=tid,
|
||||
vvt_id=vvt_id,
|
||||
name=t.name,
|
||||
description=t.description or "",
|
||||
purposes=purpose_labels,
|
||||
legal_bases=[{"type": lid, "description": lbl} for lid, lbl in zip(t.legal_basis_refs or [], legal_labels)],
|
||||
data_subject_categories=subject_labels,
|
||||
personal_data_categories=category_labels,
|
||||
recipient_categories=[{"type": "unknown", "name": lbl} for lbl in recipient_labels],
|
||||
retention_period=retention_period,
|
||||
business_function=t.business_function,
|
||||
systems=[{"systemId": s, "name": s} for s in (t.typical_systems or [])],
|
||||
protection_level=t.protection_level or "MEDIUM",
|
||||
dpia_required=t.dpia_required or False,
|
||||
structured_toms=structured_toms,
|
||||
status="DRAFT",
|
||||
created_by=http_request.headers.get("X-User-ID", "system"),
|
||||
# Library refs
|
||||
purpose_refs=t.purpose_refs,
|
||||
legal_basis_refs=t.legal_basis_refs,
|
||||
data_subject_refs=t.data_subject_refs,
|
||||
data_category_refs=t.data_category_refs,
|
||||
recipient_refs=t.recipient_refs,
|
||||
retention_rule_ref=t.retention_rule_ref,
|
||||
transfer_mechanism_refs=t.transfer_mechanism_refs,
|
||||
tom_refs=t.tom_refs,
|
||||
source_template_id=t.id,
|
||||
risk_score=t.risk_score,
|
||||
)
|
||||
db.add(act)
|
||||
db.flush()
|
||||
|
||||
# Audit log
|
||||
audit = VVTAuditLogDB(
|
||||
tenant_id=tid,
|
||||
action="CREATE",
|
||||
entity_type="activity",
|
||||
entity_id=act.id,
|
||||
changed_by=http_request.headers.get("X-User-ID", "system"),
|
||||
new_values={"vvt_id": vvt_id, "source_template_id": t.id, "name": t.name},
|
||||
)
|
||||
db.add(audit)
|
||||
db.commit()
|
||||
db.refresh(act)
|
||||
|
||||
# Return full response
|
||||
from .vvt_routes import _activity_to_response
|
||||
return _activity_to_response(act)
|
||||
|
||||
|
||||
def _resolve_ids(db: Session, model, ids: list) -> list:
|
||||
"""Resolve list of library IDs to list of label_de strings."""
|
||||
if not ids:
|
||||
return []
|
||||
rows = db.query(model).filter(model.id.in_(ids)).all()
|
||||
label_map = {r.id: r.label_de for r in rows}
|
||||
return [label_map.get(i, i) for i in ids]
|
||||
@@ -174,6 +174,20 @@ def _activity_to_response(act: VVTActivityDB) -> VVTActivityResponse:
|
||||
next_review_at=act.next_review_at,
|
||||
created_by=act.created_by,
|
||||
dsfa_id=str(act.dsfa_id) if act.dsfa_id else None,
|
||||
# Library refs
|
||||
purpose_refs=act.purpose_refs,
|
||||
legal_basis_refs=act.legal_basis_refs,
|
||||
data_subject_refs=act.data_subject_refs,
|
||||
data_category_refs=act.data_category_refs,
|
||||
recipient_refs=act.recipient_refs,
|
||||
retention_rule_ref=act.retention_rule_ref,
|
||||
transfer_mechanism_refs=act.transfer_mechanism_refs,
|
||||
tom_refs=act.tom_refs,
|
||||
source_template_id=act.source_template_id,
|
||||
risk_score=act.risk_score,
|
||||
linked_loeschfristen_ids=act.linked_loeschfristen_ids,
|
||||
linked_tom_measure_ids=act.linked_tom_measure_ids,
|
||||
art30_completeness=act.art30_completeness,
|
||||
created_at=act.created_at,
|
||||
updated_at=act.updated_at,
|
||||
)
|
||||
@@ -336,6 +350,107 @@ async def delete_activity(
|
||||
return {"success": True, "message": f"Activity {activity_id} deleted"}
|
||||
|
||||
|
||||
# ============================================================================
|
||||
# Art. 30 Completeness Check
|
||||
# ============================================================================
|
||||
|
||||
@router.get("/activities/{activity_id}/completeness")
|
||||
async def get_activity_completeness(
|
||||
activity_id: str,
|
||||
tid: str = Depends(get_tenant_id),
|
||||
db: Session = Depends(get_db),
|
||||
):
|
||||
"""Calculate Art. 30 completeness score for a VVT activity."""
|
||||
act = db.query(VVTActivityDB).filter(
|
||||
VVTActivityDB.id == activity_id,
|
||||
VVTActivityDB.tenant_id == tid,
|
||||
).first()
|
||||
if not act:
|
||||
raise HTTPException(status_code=404, detail=f"Activity {activity_id} not found")
|
||||
return _calculate_completeness(act)
|
||||
|
||||
|
||||
def _calculate_completeness(act: VVTActivityDB) -> dict:
|
||||
"""Calculate Art. 30 completeness — required fields per DSGVO Art. 30 Abs. 1."""
|
||||
missing = []
|
||||
warnings = []
|
||||
total_checks = 10
|
||||
passed = 0
|
||||
|
||||
# 1. Name/Zweck
|
||||
if act.name:
|
||||
passed += 1
|
||||
else:
|
||||
missing.append("name")
|
||||
|
||||
# 2. Verarbeitungszwecke
|
||||
has_purposes = bool(act.purposes) or bool(act.purpose_refs)
|
||||
if has_purposes:
|
||||
passed += 1
|
||||
else:
|
||||
missing.append("purposes")
|
||||
|
||||
# 3. Rechtsgrundlage
|
||||
has_legal = bool(act.legal_bases) or bool(act.legal_basis_refs)
|
||||
if has_legal:
|
||||
passed += 1
|
||||
else:
|
||||
missing.append("legal_bases")
|
||||
|
||||
# 4. Betroffenenkategorien
|
||||
has_subjects = bool(act.data_subject_categories) or bool(act.data_subject_refs)
|
||||
if has_subjects:
|
||||
passed += 1
|
||||
else:
|
||||
missing.append("data_subjects")
|
||||
|
||||
# 5. Datenkategorien
|
||||
has_categories = bool(act.personal_data_categories) or bool(act.data_category_refs)
|
||||
if has_categories:
|
||||
passed += 1
|
||||
else:
|
||||
missing.append("data_categories")
|
||||
|
||||
# 6. Empfaenger
|
||||
has_recipients = bool(act.recipient_categories) or bool(act.recipient_refs)
|
||||
if has_recipients:
|
||||
passed += 1
|
||||
else:
|
||||
missing.append("recipients")
|
||||
|
||||
# 7. Drittland-Uebermittlung (checked but not strictly required)
|
||||
passed += 1 # always passes — no transfer is valid state
|
||||
|
||||
# 8. Loeschfristen
|
||||
has_retention = bool(act.retention_period and act.retention_period.get('description')) or bool(act.retention_rule_ref)
|
||||
if has_retention:
|
||||
passed += 1
|
||||
else:
|
||||
missing.append("retention_period")
|
||||
|
||||
# 9. TOM-Beschreibung
|
||||
has_tom = bool(act.tom_description) or bool(act.tom_refs) or bool(act.structured_toms)
|
||||
if has_tom:
|
||||
passed += 1
|
||||
else:
|
||||
missing.append("tom_description")
|
||||
|
||||
# 10. Verantwortlicher
|
||||
if act.responsible:
|
||||
passed += 1
|
||||
else:
|
||||
missing.append("responsible")
|
||||
|
||||
# Warnings
|
||||
if act.dpia_required and not act.dsfa_id:
|
||||
warnings.append("dpia_required_but_no_dsfa_linked")
|
||||
if act.third_country_transfers and not act.transfer_mechanism_refs:
|
||||
warnings.append("third_country_transfer_without_mechanism")
|
||||
|
||||
score = int((passed / total_checks) * 100)
|
||||
return {"score": score, "missing": missing, "warnings": warnings, "passed": passed, "total": total_checks}
|
||||
|
||||
|
||||
# ============================================================================
|
||||
# Audit Log
|
||||
# ============================================================================
|
||||
|
||||
164
backend-compliance/compliance/db/vvt_library_models.py
Normal file
164
backend-compliance/compliance/db/vvt_library_models.py
Normal file
@@ -0,0 +1,164 @@
|
||||
"""
|
||||
SQLAlchemy models for VVT Master Libraries + Process Templates.
|
||||
|
||||
Tables (global, no tenant_id):
|
||||
- vvt_lib_data_subjects
|
||||
- vvt_lib_data_categories (hierarchical, self-referencing)
|
||||
- vvt_lib_recipients
|
||||
- vvt_lib_legal_bases
|
||||
- vvt_lib_retention_rules
|
||||
- vvt_lib_transfer_mechanisms
|
||||
- vvt_lib_purposes
|
||||
- vvt_lib_toms
|
||||
|
||||
Tenant-scoped:
|
||||
- vvt_process_templates (system + tenant-specific)
|
||||
"""
|
||||
|
||||
from datetime import datetime
|
||||
|
||||
from sqlalchemy import (
|
||||
Column, String, Text, Boolean, Integer, DateTime, JSON, Index,
|
||||
ForeignKey,
|
||||
)
|
||||
from sqlalchemy.dialects.postgresql import UUID
|
||||
|
||||
from classroom_engine.database import Base
|
||||
|
||||
|
||||
class VVTLibDataSubjectDB(Base):
|
||||
__tablename__ = 'vvt_lib_data_subjects'
|
||||
|
||||
id = Column(String(50), primary_key=True)
|
||||
label_de = Column(String(200), nullable=False)
|
||||
description_de = Column(Text)
|
||||
art9_relevant = Column(Boolean, default=False)
|
||||
typical_for = Column(JSON, default=list)
|
||||
sort_order = Column(Integer, default=0)
|
||||
created_at = Column(DateTime(timezone=True), default=datetime.utcnow)
|
||||
|
||||
|
||||
class VVTLibDataCategoryDB(Base):
|
||||
__tablename__ = 'vvt_lib_data_categories'
|
||||
|
||||
id = Column(String(50), primary_key=True)
|
||||
parent_id = Column(String(50), ForeignKey('vvt_lib_data_categories.id', ondelete='SET NULL'), nullable=True)
|
||||
label_de = Column(String(200), nullable=False)
|
||||
description_de = Column(Text)
|
||||
is_art9 = Column(Boolean, default=False)
|
||||
is_art10 = Column(Boolean, default=False)
|
||||
risk_weight = Column(Integer, default=1)
|
||||
default_retention_rule = Column(String(50))
|
||||
default_legal_basis = Column(String(50))
|
||||
sort_order = Column(Integer, default=0)
|
||||
created_at = Column(DateTime(timezone=True), default=datetime.utcnow)
|
||||
|
||||
|
||||
class VVTLibRecipientDB(Base):
|
||||
__tablename__ = 'vvt_lib_recipients'
|
||||
|
||||
id = Column(String(50), primary_key=True)
|
||||
type = Column(String(20), nullable=False)
|
||||
label_de = Column(String(200), nullable=False)
|
||||
description_de = Column(Text)
|
||||
is_third_country = Column(Boolean, default=False)
|
||||
country = Column(String(5))
|
||||
sort_order = Column(Integer, default=0)
|
||||
created_at = Column(DateTime(timezone=True), default=datetime.utcnow)
|
||||
|
||||
|
||||
class VVTLibLegalBasisDB(Base):
|
||||
__tablename__ = 'vvt_lib_legal_bases'
|
||||
|
||||
id = Column(String(50), primary_key=True)
|
||||
article = Column(String(50), nullable=False)
|
||||
type = Column(String(30), nullable=False)
|
||||
label_de = Column(String(300), nullable=False)
|
||||
description_de = Column(Text)
|
||||
is_art9 = Column(Boolean, default=False)
|
||||
typical_national_law = Column(String(100))
|
||||
sort_order = Column(Integer, default=0)
|
||||
created_at = Column(DateTime(timezone=True), default=datetime.utcnow)
|
||||
|
||||
|
||||
class VVTLibRetentionRuleDB(Base):
|
||||
__tablename__ = 'vvt_lib_retention_rules'
|
||||
|
||||
id = Column(String(50), primary_key=True)
|
||||
label_de = Column(String(300), nullable=False)
|
||||
description_de = Column(Text)
|
||||
legal_basis = Column(String(200))
|
||||
duration = Column(Integer, nullable=False)
|
||||
duration_unit = Column(String(10), nullable=False)
|
||||
start_event = Column(String(200))
|
||||
deletion_procedure = Column(String(500))
|
||||
sort_order = Column(Integer, default=0)
|
||||
created_at = Column(DateTime(timezone=True), default=datetime.utcnow)
|
||||
|
||||
|
||||
class VVTLibTransferMechanismDB(Base):
|
||||
__tablename__ = 'vvt_lib_transfer_mechanisms'
|
||||
|
||||
id = Column(String(50), primary_key=True)
|
||||
label_de = Column(String(300), nullable=False)
|
||||
description_de = Column(Text)
|
||||
article = Column(String(50))
|
||||
requires_tia = Column(Boolean, default=False)
|
||||
sort_order = Column(Integer, default=0)
|
||||
created_at = Column(DateTime(timezone=True), default=datetime.utcnow)
|
||||
|
||||
|
||||
class VVTLibPurposeDB(Base):
|
||||
__tablename__ = 'vvt_lib_purposes'
|
||||
|
||||
id = Column(String(50), primary_key=True)
|
||||
label_de = Column(String(300), nullable=False)
|
||||
description_de = Column(Text)
|
||||
typical_legal_basis = Column(String(50))
|
||||
typical_for = Column(JSON, default=list)
|
||||
sort_order = Column(Integer, default=0)
|
||||
created_at = Column(DateTime(timezone=True), default=datetime.utcnow)
|
||||
|
||||
|
||||
class VVTLibTomDB(Base):
|
||||
__tablename__ = 'vvt_lib_toms'
|
||||
|
||||
id = Column(String(50), primary_key=True)
|
||||
category = Column(String(30), nullable=False)
|
||||
label_de = Column(String(300), nullable=False)
|
||||
description_de = Column(Text)
|
||||
art32_reference = Column(String(100))
|
||||
sort_order = Column(Integer, default=0)
|
||||
created_at = Column(DateTime(timezone=True), default=datetime.utcnow)
|
||||
|
||||
|
||||
class VVTProcessTemplateDB(Base):
|
||||
__tablename__ = 'vvt_process_templates'
|
||||
|
||||
id = Column(String(80), primary_key=True)
|
||||
name = Column(String(300), nullable=False)
|
||||
description = Column(Text)
|
||||
business_function = Column(String(50))
|
||||
purpose_refs = Column(JSON, default=list)
|
||||
legal_basis_refs = Column(JSON, default=list)
|
||||
data_subject_refs = Column(JSON, default=list)
|
||||
data_category_refs = Column(JSON, default=list)
|
||||
recipient_refs = Column(JSON, default=list)
|
||||
tom_refs = Column(JSON, default=list)
|
||||
transfer_mechanism_refs = Column(JSON, default=list)
|
||||
retention_rule_ref = Column(String(50))
|
||||
typical_systems = Column(JSON, default=list)
|
||||
protection_level = Column(String(10), default='MEDIUM')
|
||||
dpia_required = Column(Boolean, default=False)
|
||||
risk_score = Column(Integer)
|
||||
tags = Column(JSON, default=list)
|
||||
is_system = Column(Boolean, default=True)
|
||||
tenant_id = Column(UUID(as_uuid=True), nullable=True)
|
||||
sort_order = Column(Integer, default=0)
|
||||
created_at = Column(DateTime(timezone=True), default=datetime.utcnow)
|
||||
updated_at = Column(DateTime(timezone=True), default=datetime.utcnow, onupdate=datetime.utcnow)
|
||||
|
||||
__table_args__ = (
|
||||
Index('idx_vvt_process_templates_bf', 'business_function'),
|
||||
Index('idx_vvt_process_templates_system', 'is_system'),
|
||||
)
|
||||
@@ -79,6 +79,26 @@ class VVTActivityDB(Base):
|
||||
next_review_at = Column(DateTime(timezone=True), nullable=True)
|
||||
created_by = Column(String(200), default='system')
|
||||
dsfa_id = Column(UUID(as_uuid=True), nullable=True)
|
||||
|
||||
# Library refs (Phase 1 — parallel to freetext fields)
|
||||
purpose_refs = Column(JSON, nullable=True)
|
||||
legal_basis_refs = Column(JSON, nullable=True)
|
||||
data_subject_refs = Column(JSON, nullable=True)
|
||||
data_category_refs = Column(JSON, nullable=True)
|
||||
recipient_refs = Column(JSON, nullable=True)
|
||||
retention_rule_ref = Column(String(50), nullable=True)
|
||||
transfer_mechanism_refs = Column(JSON, nullable=True)
|
||||
tom_refs = Column(JSON, nullable=True)
|
||||
|
||||
# Cross-module links
|
||||
linked_loeschfristen_ids = Column(JSON, nullable=True)
|
||||
linked_tom_measure_ids = Column(JSON, nullable=True)
|
||||
|
||||
# Template + risk
|
||||
source_template_id = Column(String(80), nullable=True)
|
||||
risk_score = Column(Integer, nullable=True)
|
||||
art30_completeness = Column(JSON, nullable=True)
|
||||
|
||||
created_at = Column(DateTime, default=datetime.utcnow, nullable=False)
|
||||
updated_at = Column(DateTime, default=datetime.utcnow, onupdate=datetime.utcnow)
|
||||
|
||||
|
||||
105
backend-compliance/migrations/064_vvt_master_libraries.sql
Normal file
105
backend-compliance/migrations/064_vvt_master_libraries.sql
Normal file
@@ -0,0 +1,105 @@
|
||||
-- Migration 064: VVT Master Libraries — 8 global reference tables
|
||||
-- These are shared across all tenants (no tenant_id).
|
||||
|
||||
BEGIN;
|
||||
|
||||
-- 1. Data Subjects (Betroffenenkategorien)
|
||||
CREATE TABLE IF NOT EXISTS vvt_lib_data_subjects (
|
||||
id VARCHAR(50) PRIMARY KEY,
|
||||
label_de VARCHAR(200) NOT NULL,
|
||||
description_de TEXT,
|
||||
art9_relevant BOOLEAN DEFAULT FALSE,
|
||||
typical_for JSONB DEFAULT '[]'::jsonb,
|
||||
sort_order INTEGER DEFAULT 0,
|
||||
created_at TIMESTAMPTZ DEFAULT NOW()
|
||||
);
|
||||
|
||||
-- 2. Data Categories (Datenkategorien — hierarchisch)
|
||||
CREATE TABLE IF NOT EXISTS vvt_lib_data_categories (
|
||||
id VARCHAR(50) PRIMARY KEY,
|
||||
parent_id VARCHAR(50) REFERENCES vvt_lib_data_categories(id) ON DELETE SET NULL,
|
||||
label_de VARCHAR(200) NOT NULL,
|
||||
description_de TEXT,
|
||||
is_art9 BOOLEAN DEFAULT FALSE,
|
||||
is_art10 BOOLEAN DEFAULT FALSE,
|
||||
risk_weight INTEGER DEFAULT 1 CHECK (risk_weight BETWEEN 1 AND 5),
|
||||
default_retention_rule VARCHAR(50),
|
||||
default_legal_basis VARCHAR(50),
|
||||
sort_order INTEGER DEFAULT 0,
|
||||
created_at TIMESTAMPTZ DEFAULT NOW()
|
||||
);
|
||||
CREATE INDEX IF NOT EXISTS idx_vvt_lib_data_categories_parent ON vvt_lib_data_categories(parent_id);
|
||||
|
||||
-- 3. Recipients (Empfaengerkategorien)
|
||||
CREATE TABLE IF NOT EXISTS vvt_lib_recipients (
|
||||
id VARCHAR(50) PRIMARY KEY,
|
||||
type VARCHAR(20) NOT NULL CHECK (type IN ('INTERNAL', 'PROCESSOR', 'CONTROLLER', 'AUTHORITY')),
|
||||
label_de VARCHAR(200) NOT NULL,
|
||||
description_de TEXT,
|
||||
is_third_country BOOLEAN DEFAULT FALSE,
|
||||
country VARCHAR(5),
|
||||
sort_order INTEGER DEFAULT 0,
|
||||
created_at TIMESTAMPTZ DEFAULT NOW()
|
||||
);
|
||||
|
||||
-- 4. Legal Bases (Rechtsgrundlagen)
|
||||
CREATE TABLE IF NOT EXISTS vvt_lib_legal_bases (
|
||||
id VARCHAR(50) PRIMARY KEY,
|
||||
article VARCHAR(50) NOT NULL,
|
||||
type VARCHAR(30) NOT NULL CHECK (type IN ('CONSENT', 'CONTRACT', 'LEGAL_OBLIGATION', 'VITAL_INTEREST', 'PUBLIC_TASK', 'LEGITIMATE_INTEREST', 'ART9', 'NATIONAL')),
|
||||
label_de VARCHAR(300) NOT NULL,
|
||||
description_de TEXT,
|
||||
is_art9 BOOLEAN DEFAULT FALSE,
|
||||
typical_national_law VARCHAR(100),
|
||||
sort_order INTEGER DEFAULT 0,
|
||||
created_at TIMESTAMPTZ DEFAULT NOW()
|
||||
);
|
||||
|
||||
-- 5. Retention Rules (Aufbewahrungsfristen)
|
||||
CREATE TABLE IF NOT EXISTS vvt_lib_retention_rules (
|
||||
id VARCHAR(50) PRIMARY KEY,
|
||||
label_de VARCHAR(300) NOT NULL,
|
||||
description_de TEXT,
|
||||
legal_basis VARCHAR(200),
|
||||
duration INTEGER NOT NULL,
|
||||
duration_unit VARCHAR(10) NOT NULL CHECK (duration_unit IN ('DAYS', 'MONTHS', 'YEARS')),
|
||||
start_event VARCHAR(200),
|
||||
deletion_procedure VARCHAR(500),
|
||||
sort_order INTEGER DEFAULT 0,
|
||||
created_at TIMESTAMPTZ DEFAULT NOW()
|
||||
);
|
||||
|
||||
-- 6. Transfer Mechanisms (Uebermittlungsmechanismen)
|
||||
CREATE TABLE IF NOT EXISTS vvt_lib_transfer_mechanisms (
|
||||
id VARCHAR(50) PRIMARY KEY,
|
||||
label_de VARCHAR(300) NOT NULL,
|
||||
description_de TEXT,
|
||||
article VARCHAR(50),
|
||||
requires_tia BOOLEAN DEFAULT FALSE,
|
||||
sort_order INTEGER DEFAULT 0,
|
||||
created_at TIMESTAMPTZ DEFAULT NOW()
|
||||
);
|
||||
|
||||
-- 7. Purposes (Verarbeitungszwecke)
|
||||
CREATE TABLE IF NOT EXISTS vvt_lib_purposes (
|
||||
id VARCHAR(50) PRIMARY KEY,
|
||||
label_de VARCHAR(300) NOT NULL,
|
||||
description_de TEXT,
|
||||
typical_legal_basis VARCHAR(50),
|
||||
typical_for JSONB DEFAULT '[]'::jsonb,
|
||||
sort_order INTEGER DEFAULT 0,
|
||||
created_at TIMESTAMPTZ DEFAULT NOW()
|
||||
);
|
||||
|
||||
-- 8. TOMs (Technisch-Organisatorische Massnahmen)
|
||||
CREATE TABLE IF NOT EXISTS vvt_lib_toms (
|
||||
id VARCHAR(50) PRIMARY KEY,
|
||||
category VARCHAR(30) NOT NULL CHECK (category IN ('accessControl', 'confidentiality', 'integrity', 'availability', 'separation')),
|
||||
label_de VARCHAR(300) NOT NULL,
|
||||
description_de TEXT,
|
||||
art32_reference VARCHAR(100),
|
||||
sort_order INTEGER DEFAULT 0,
|
||||
created_at TIMESTAMPTZ DEFAULT NOW()
|
||||
);
|
||||
|
||||
COMMIT;
|
||||
200
backend-compliance/migrations/065_vvt_library_seed.sql
Normal file
200
backend-compliance/migrations/065_vvt_library_seed.sql
Normal file
@@ -0,0 +1,200 @@
|
||||
-- Migration 065: VVT Library Seed Data (~150 entries)
|
||||
-- All content self-authored, MIT-compatible.
|
||||
|
||||
BEGIN;
|
||||
|
||||
-- =============================================================================
|
||||
-- Data Subjects (15)
|
||||
-- =============================================================================
|
||||
INSERT INTO vvt_lib_data_subjects (id, label_de, description_de, art9_relevant, typical_for, sort_order) VALUES
|
||||
('EMPLOYEES', 'Beschaeftigte', 'Aktuelle Mitarbeiterinnen und Mitarbeiter', FALSE, '["hr","it_operations"]', 1),
|
||||
('APPLICANTS', 'Bewerber', 'Stellenbewerberinnen und -bewerber', FALSE, '["hr"]', 2),
|
||||
('CUSTOMERS', 'Kunden', 'Aktive Kundinnen und Kunden', FALSE, '["sales_crm","support","finance"]', 3),
|
||||
('PROSPECTIVE_CUSTOMERS', 'Interessenten', 'Potenzielle Kundinnen und Kunden', FALSE, '["marketing","sales_crm"]', 4),
|
||||
('SUPPLIERS', 'Lieferanten', 'Geschaeftspartner als Lieferanten', FALSE, '["finance"]', 5),
|
||||
('BUSINESS_PARTNERS', 'Geschaeftspartner', 'Kooperationspartner, Berater, Dienstleister', FALSE, '["management","finance"]', 6),
|
||||
('VISITORS', 'Besucher', 'Betriebsbesucher und Gaeste', FALSE, '["management"]', 7),
|
||||
('WEBSITE_USERS', 'Website-Nutzer', 'Besucher der Unternehmenswebsite', FALSE, '["marketing","it_operations"]', 8),
|
||||
('APP_USERS', 'App-Nutzer', 'Nutzer mobiler Anwendungen', FALSE, '["product_engineering"]', 9),
|
||||
('NEWSLETTER_SUBSCRIBERS', 'Newsletter-Abonnenten', 'Empfaenger von Newslettern', FALSE, '["marketing"]', 10),
|
||||
('MEMBERS', 'Mitglieder', 'Vereins- oder Verbandsmitglieder', FALSE, '["management"]', 11),
|
||||
('PATIENTS', 'Patienten', 'Patientinnen und Patienten', TRUE, '["other"]', 12),
|
||||
('STUDENTS', 'Schueler/Studierende', 'Lernende in Bildungseinrichtungen', FALSE, '["other"]', 13),
|
||||
('MINORS', 'Minderjaehrige', 'Personen unter 16 Jahren (Art. 8 DSGVO)', FALSE, '["other"]', 14),
|
||||
('OTHER', 'Sonstige', 'Andere Betroffenenkategorien', FALSE, '[]', 15)
|
||||
ON CONFLICT (id) DO NOTHING;
|
||||
|
||||
-- =============================================================================
|
||||
-- Data Categories — Parent categories (9)
|
||||
-- =============================================================================
|
||||
INSERT INTO vvt_lib_data_categories (id, parent_id, label_de, description_de, is_art9, is_art10, risk_weight, sort_order) VALUES
|
||||
('IDENTIFICATION', NULL, 'Identifikationsdaten', 'Daten zur Identifizierung natuerlicher Personen', FALSE, FALSE, 2, 1),
|
||||
('CONTACT_DATA', NULL, 'Kontaktdaten', 'Kommunikationsdaten und Adressen', FALSE, FALSE, 1, 2),
|
||||
('FINANCIAL', NULL, 'Finanzdaten', 'Bank-, Gehalts- und Zahlungsdaten', FALSE, FALSE, 3, 3),
|
||||
('EMPLOYMENT', NULL, 'Beschaeftigungsdaten', 'Arbeitsverhaeltnis und Qualifikation', FALSE, FALSE, 2, 4),
|
||||
('DIGITAL_IDENTITY', NULL, 'Digitale Identitaet', 'Online-Kennungen und Zugangsdaten', FALSE, FALSE, 2, 5),
|
||||
('COMMUNICATION', NULL, 'Kommunikationsdaten', 'Nachrichten und Vertragsdaten', FALSE, FALSE, 2, 6),
|
||||
('MEDIA', NULL, 'Medien- und Standortdaten', 'Bild, Video, Standort', FALSE, FALSE, 3, 7),
|
||||
('ART9_SPECIAL', NULL, 'Besondere Kategorien (Art. 9)', 'Besonders schuetzenswerte Daten', TRUE, FALSE, 5, 8),
|
||||
('ART10', NULL, 'Strafrechtliche Daten (Art. 10)', 'Daten ueber strafrechtliche Verurteilungen', FALSE, TRUE, 5, 9)
|
||||
ON CONFLICT (id) DO NOTHING;
|
||||
|
||||
-- =============================================================================
|
||||
-- Data Categories — Child categories (26)
|
||||
-- =============================================================================
|
||||
INSERT INTO vvt_lib_data_categories (id, parent_id, label_de, description_de, is_art9, is_art10, risk_weight, default_retention_rule, default_legal_basis, sort_order) VALUES
|
||||
('NAME', 'IDENTIFICATION', 'Name', 'Vor- und Nachname, Geburtsname', FALSE, FALSE, 1, NULL, NULL, 10),
|
||||
('DOB', 'IDENTIFICATION', 'Geburtsdatum', 'Geburtstag und -ort', FALSE, FALSE, 2, NULL, NULL, 11),
|
||||
('ADDRESS', 'CONTACT_DATA', 'Anschrift', 'Wohn- und Postadresse', FALSE, FALSE, 1, NULL, NULL, 20),
|
||||
('CONTACT', 'CONTACT_DATA', 'Kontaktinformationen', 'Telefon, E-Mail, Fax', FALSE, FALSE, 1, NULL, NULL, 21),
|
||||
('ID_NUMBER', 'IDENTIFICATION', 'Ausweisnummer', 'Personalausweis-, Reisepassnummer', FALSE, FALSE, 3, NULL, NULL, 12),
|
||||
('SOCIAL_SECURITY', 'IDENTIFICATION', 'Sozialversicherungsnummer', 'SV-Nummer', FALSE, FALSE, 4, 'BDSG_35_DELETE', 'ART6_1C', 13),
|
||||
('TAX_ID', 'FINANCIAL', 'Steuer-ID', 'Steueridentifikationsnummer', FALSE, FALSE, 3, 'AO_147_10Y', 'ART6_1C', 30),
|
||||
('BANK_ACCOUNT', 'FINANCIAL', 'Bankverbindung', 'IBAN, BIC, Kontonummer', FALSE, FALSE, 3, 'HGB_257_10Y', 'ART6_1B', 31),
|
||||
('PAYMENT_DATA', 'FINANCIAL', 'Zahlungsdaten', 'Kreditkartendaten, Zahlungshistorie', FALSE, FALSE, 4, 'HGB_257_10Y', 'ART6_1B', 32),
|
||||
('SALARY_DATA', 'FINANCIAL', 'Gehaltsdaten', 'Brutto/Netto, Zulagen, Abzuege', FALSE, FALSE, 4, 'AO_147_10Y', 'BDSG_26', 33),
|
||||
('EMPLOYMENT_DATA', 'EMPLOYMENT', 'Arbeitsvertragsdaten', 'Vertragsdetails, Position, Abteilung', FALSE, FALSE, 2, 'HGB_257_10Y', 'BDSG_26', 40),
|
||||
('EDUCATION_DATA', 'EMPLOYMENT', 'Ausbildungsdaten', 'Zeugnisse, Qualifikationen, Zertifikate', FALSE, FALSE, 2, 'AGG_15_6M', 'BDSG_26', 41),
|
||||
('IP_ADDRESS', 'DIGITAL_IDENTITY', 'IP-Adresse', 'IPv4/IPv6 Adressen', FALSE, FALSE, 2, 'CUSTOM_90D', 'ART6_1F', 50),
|
||||
('DEVICE_ID', 'DIGITAL_IDENTITY', 'Geraete-ID', 'Browser-Fingerprint, Device-ID', FALSE, FALSE, 2, 'CUSTOM_14M', 'ART6_1A', 51),
|
||||
('LOGIN_DATA', 'DIGITAL_IDENTITY', 'Zugangsdaten', 'Benutzername, Passwort-Hash', FALSE, FALSE, 3, NULL, 'ART6_1B', 52),
|
||||
('USAGE_DATA', 'DIGITAL_IDENTITY', 'Nutzungsdaten', 'Klickverhalten, Seitenaufrufe, Sessions', FALSE, FALSE, 2, 'CUSTOM_14M', 'ART6_1A', 53),
|
||||
('COMMUNICATION_DATA', 'COMMUNICATION', 'Korrespondenz', 'E-Mails, Chat-Nachrichten, Briefe', FALSE, FALSE, 2, 'BGB_195_3Y', NULL, 60),
|
||||
('CONTRACT_DATA', 'COMMUNICATION', 'Vertragsdaten', 'Vertragsdetails, Bestellungen', FALSE, FALSE, 2, 'HGB_257_10Y', 'ART6_1B', 61),
|
||||
('PHOTO_VIDEO', 'MEDIA', 'Bild-/Videodaten', 'Fotos, Videos von Personen', FALSE, FALSE, 3, 'CONSENT_REVOKE', 'ART6_1A', 70),
|
||||
('LOCATION_DATA', 'MEDIA', 'Standortdaten', 'GPS-Koordinaten, Aufenthaltsorte', FALSE, FALSE, 3, 'CUSTOM_90D', 'ART6_1A', 71),
|
||||
('HEALTH_DATA', 'ART9_SPECIAL', 'Gesundheitsdaten', 'Krankheitsdaten, Atteste, Behinderung', TRUE, FALSE, 5, 'BDSG_35_DELETE', 'ART9_2H', 80),
|
||||
('GENETIC_DATA', 'ART9_SPECIAL', 'Genetische Daten', 'DNA-Analysen, genetische Merkmale', TRUE, FALSE, 5, 'BDSG_35_DELETE', 'ART9_2A', 81),
|
||||
('BIOMETRIC_DATA', 'ART9_SPECIAL', 'Biometrische Daten', 'Fingerabdruck, Gesichtserkennung', TRUE, FALSE, 5, 'BDSG_35_DELETE', 'ART9_2A', 82),
|
||||
('RACIAL_ETHNIC', 'ART9_SPECIAL', 'Rassische/ethnische Herkunft', 'Ethnische Zugehoerigkeit', TRUE, FALSE, 5, NULL, 'ART9_2A', 83),
|
||||
('POLITICAL_OPINIONS', 'ART9_SPECIAL', 'Politische Meinungen', 'Parteizugehoerigkeit, politische Haltung', TRUE, FALSE, 5, NULL, 'ART9_2A', 84),
|
||||
('RELIGIOUS_BELIEFS', 'ART9_SPECIAL', 'Religioese Ueberzeugungen', 'Konfession, religioese Praktiken', TRUE, FALSE, 5, NULL, 'ART9_2A', 85),
|
||||
('TRADE_UNION', 'ART9_SPECIAL', 'Gewerkschaftszugehoerigkeit', 'Mitgliedschaft in Gewerkschaften', TRUE, FALSE, 5, NULL, 'ART9_2A', 86),
|
||||
('SEX_LIFE', 'ART9_SPECIAL', 'Sexualleben/Orientierung', 'Sexuelle Orientierung', TRUE, FALSE, 5, NULL, 'ART9_2A', 87),
|
||||
('CRIMINAL_DATA', 'ART10', 'Strafrechtliche Daten', 'Verurteilungen, Straftaten, Fuehrungszeugnis', FALSE, TRUE, 5, 'BDSG_35_DELETE', 'BDSG_24', 90)
|
||||
ON CONFLICT (id) DO NOTHING;
|
||||
|
||||
-- =============================================================================
|
||||
-- Legal Bases (12)
|
||||
-- =============================================================================
|
||||
INSERT INTO vvt_lib_legal_bases (id, article, type, label_de, description_de, is_art9, typical_national_law, sort_order) VALUES
|
||||
('ART6_1A', 'Art. 6 Abs. 1 lit. a', 'CONSENT', 'Einwilligung', 'Die betroffene Person hat ihre Einwilligung gegeben', FALSE, NULL, 1),
|
||||
('ART6_1B', 'Art. 6 Abs. 1 lit. b', 'CONTRACT', 'Vertragserfullung', 'Erforderlich fuer die Erfuellung eines Vertrags', FALSE, NULL, 2),
|
||||
('ART6_1C', 'Art. 6 Abs. 1 lit. c', 'LEGAL_OBLIGATION', 'Rechtliche Verpflichtung', 'Erforderlich zur Erfuellung einer rechtlichen Verpflichtung', FALSE, NULL, 3),
|
||||
('ART6_1D', 'Art. 6 Abs. 1 lit. d', 'VITAL_INTEREST', 'Lebenswichtige Interessen', 'Schutz lebenswichtiger Interessen', FALSE, NULL, 4),
|
||||
('ART6_1E', 'Art. 6 Abs. 1 lit. e', 'PUBLIC_TASK', 'Oeffentliches Interesse', 'Wahrnehmung einer Aufgabe im oeffentlichen Interesse', FALSE, NULL, 5),
|
||||
('ART6_1F', 'Art. 6 Abs. 1 lit. f', 'LEGITIMATE_INTEREST', 'Berechtigtes Interesse', 'Wahrung berechtigter Interessen des Verantwortlichen', FALSE, NULL, 6),
|
||||
('ART9_2A', 'Art. 9 Abs. 2 lit. a', 'ART9', 'Ausdrueckliche Einwilligung (Art. 9)', 'Ausdrueckliche Einwilligung fuer besondere Kategorien', TRUE, NULL, 7),
|
||||
('ART9_2B', 'Art. 9 Abs. 2 lit. b', 'ART9', 'Arbeitsrecht (Art. 9)', 'Erforderlich im Arbeitsrecht', TRUE, 'BDSG § 26', 8),
|
||||
('ART9_2H', 'Art. 9 Abs. 2 lit. h', 'ART9', 'Gesundheitsvorsorge (Art. 9)', 'Gesundheitsvorsorge oder Arbeitsmedizin', TRUE, NULL, 9),
|
||||
('BDSG_26', '§ 26 BDSG', 'NATIONAL', 'Beschaeftigtenverhaeltnis', 'Datenverarbeitung fuer Zwecke des Beschaeftigungsverhaeltnisses', FALSE, 'BDSG § 26', 10),
|
||||
('BDSG_24', '§ 24 BDSG', 'NATIONAL', 'Strafrechtliche Daten', 'Verarbeitung strafrechtlicher Daten (Art. 10 DSGVO)', FALSE, 'BDSG § 24', 11),
|
||||
('UWG_7', '§ 7 UWG', 'NATIONAL', 'Werbung mit Einwilligung', 'Werbliche Ansprache nach UWG', FALSE, 'UWG § 7', 12)
|
||||
ON CONFLICT (id) DO NOTHING;
|
||||
|
||||
-- =============================================================================
|
||||
-- Retention Rules (12)
|
||||
-- =============================================================================
|
||||
INSERT INTO vvt_lib_retention_rules (id, label_de, description_de, legal_basis, duration, duration_unit, start_event, deletion_procedure, sort_order) VALUES
|
||||
('HGB_257_10Y', '10 Jahre (HGB § 257)', 'Handelsrechtliche Aufbewahrungspflicht fuer Handelsbuecher, Jahresabschluesse, Buchungsbelege', 'HGB § 257', 10, 'YEARS', 'Ende des Kalenderjahres', 'Vernichtung nach Ablauf der Aufbewahrungsfrist', 1),
|
||||
('AO_147_10Y', '10 Jahre (AO § 147)', 'Steuerrechtliche Aufbewahrungspflicht fuer Buchungsbelege', 'AO § 147', 10, 'YEARS', 'Ende des Kalenderjahres', 'Vernichtung nach Ablauf der Aufbewahrungsfrist', 2),
|
||||
('AO_147_6Y', '6 Jahre (AO § 147)', 'Steuerrechtliche Aufbewahrungspflicht fuer Geschaeftsbriefe', 'AO § 147', 6, 'YEARS', 'Ende des Kalenderjahres', 'Vernichtung nach Ablauf der Aufbewahrungsfrist', 3),
|
||||
('AGG_15_6M', '6 Monate (AGG § 15)', 'Frist fuer Schadensersatzansprueche nach AGG', 'AGG § 15', 6, 'MONTHS', 'Ablehnung / Ende des Verfahrens', 'Loeschung personenbezogener Bewerbungsdaten', 4),
|
||||
('ARBZG_16_2Y', '2 Jahre (ArbZG § 16)', 'Aufzeichnungspflicht der Arbeitszeiten', 'ArbZG § 16', 2, 'YEARS', 'Ende des Aufzeichnungszeitraums', 'Vernichtung der Arbeitszeitaufzeichnungen', 5),
|
||||
('BGB_195_3Y', '3 Jahre (BGB § 195)', 'Regelverjaehrungsfrist fuer vertragliche Ansprueche', 'BGB § 195', 3, 'YEARS', 'Ende des Jahres der Anspruchsentstehung', 'Loeschung nach Ablauf der Verjaehrungsfrist', 6),
|
||||
('CONSENT_REVOKE', 'Bis Widerruf', 'Speicherung bis zum Widerruf der Einwilligung', 'Art. 7 Abs. 3 DSGVO', 0, 'DAYS', 'Widerruf der Einwilligung', 'Unverzuegliche Loeschung nach Widerruf', 7),
|
||||
('PURPOSE_END', 'Bis Zweckerfuellung', 'Speicherung bis der Verarbeitungszweck erreicht ist', 'Art. 5 Abs. 1 lit. e DSGVO', 0, 'DAYS', 'Zweckerfuellung', 'Loeschung nach Zweckerfuellung', 8),
|
||||
('BDSG_35_DELETE', 'Unverzuegliche Loeschung', 'Loeschung sobald Speicherung nicht mehr erforderlich', 'BDSG § 35', 0, 'DAYS', 'Wegfall der Erforderlichkeit', 'Unverzuegliche Loeschung', 9),
|
||||
('CUSTOM_90D', '90 Tage', 'Benutzerdefinierte Aufbewahrungsfrist von 90 Tagen', NULL, 90, 'DAYS', 'Erstellung des Datensatzes', 'Automatische Loeschung nach 90 Tagen', 10),
|
||||
('CUSTOM_14M', '14 Monate', 'Benutzerdefinierte Aufbewahrungsfrist von 14 Monaten (z.B. Analytics)', NULL, 14, 'MONTHS', 'Erstellung des Datensatzes', 'Automatische Loeschung nach 14 Monaten', 11),
|
||||
('CUSTOM_30D', '30 Tage', 'Benutzerdefinierte Aufbewahrungsfrist von 30 Tagen', NULL, 30, 'DAYS', 'Erstellung des Datensatzes', 'Automatische Loeschung nach 30 Tagen', 12)
|
||||
ON CONFLICT (id) DO NOTHING;
|
||||
|
||||
-- =============================================================================
|
||||
-- Recipients (15)
|
||||
-- =============================================================================
|
||||
INSERT INTO vvt_lib_recipients (id, type, label_de, description_de, is_third_country, country, sort_order) VALUES
|
||||
('INTERNAL_HR', 'INTERNAL', 'Personalabteilung', 'Interne HR-Abteilung', FALSE, 'DE', 1),
|
||||
('INTERNAL_FINANCE', 'INTERNAL', 'Finanzabteilung', 'Interne Buchhaltung und Finanzen', FALSE, 'DE', 2),
|
||||
('INTERNAL_IT', 'INTERNAL', 'IT-Abteilung', 'Interne IT-Administration', FALSE, 'DE', 3),
|
||||
('INTERNAL_MANAGEMENT', 'INTERNAL', 'Geschaeftsfuehrung', 'Geschaeftsfuehrung und Vorstand', FALSE, 'DE', 4),
|
||||
('INTERNAL_MARKETING', 'INTERNAL', 'Marketingabteilung', 'Internes Marketing-Team', FALSE, 'DE', 5),
|
||||
('INTERNAL_SUPPORT', 'INTERNAL', 'Kundenservice', 'Interner Support und Service', FALSE, 'DE', 6),
|
||||
('PROCESSOR_PAYROLL', 'PROCESSOR', 'Lohnabrechnungsdienstleister', 'Externer Gehaltsabrechnungs-Dienstleister', FALSE, 'DE', 7),
|
||||
('PROCESSOR_HOSTING', 'PROCESSOR', 'Hosting-Provider', 'Cloud- oder Server-Hosting-Anbieter', FALSE, NULL, 8),
|
||||
('PROCESSOR_ANALYTICS', 'PROCESSOR', 'Analytics-Anbieter', 'Web-Analytics und Tracking-Dienstleister', FALSE, NULL, 9),
|
||||
('PROCESSOR_EMAIL', 'PROCESSOR', 'E-Mail-Dienstleister', 'Newsletter- und E-Mail-Versand-Anbieter', FALSE, NULL, 10),
|
||||
('PROCESSOR_HELPDESK', 'PROCESSOR', 'Helpdesk-Anbieter', 'Ticketsystem- und Support-Plattform', FALSE, NULL, 11),
|
||||
('AUTHORITY_FINANZAMT', 'AUTHORITY', 'Finanzamt', 'Zustaendiges Finanzamt', FALSE, 'DE', 12),
|
||||
('AUTHORITY_SOZIALVERSICHERUNG', 'AUTHORITY', 'Sozialversicherungstraeger', 'Renten-, Kranken-, Arbeitslosen-, Pflegeversicherung', FALSE, 'DE', 13),
|
||||
('AUTHORITY_KRANKENKASSE', 'AUTHORITY', 'Krankenkasse', 'Gesetzliche oder private Krankenkasse', FALSE, 'DE', 14),
|
||||
('AUTHORITY_DATENSCHUTZ', 'AUTHORITY', 'Datenschutzbehoerde', 'Zustaendige Datenschutz-Aufsichtsbehoerde', FALSE, 'DE', 15)
|
||||
ON CONFLICT (id) DO NOTHING;
|
||||
|
||||
-- =============================================================================
|
||||
-- Transfer Mechanisms (8)
|
||||
-- =============================================================================
|
||||
INSERT INTO vvt_lib_transfer_mechanisms (id, label_de, description_de, article, requires_tia, sort_order) VALUES
|
||||
('ADEQUACY_DECISION', 'Angemessenheitsbeschluss', 'EU-Angemessenheitsbeschluss gemaess Art. 45 DSGVO', 'Art. 45 DSGVO', FALSE, 1),
|
||||
('SCC_CONTROLLER', 'Standardvertragsklauseln (C2C)', 'Standardvertragsklauseln Controller-zu-Controller', 'Art. 46 Abs. 2 lit. c DSGVO', TRUE, 2),
|
||||
('SCC_PROCESSOR', 'Standardvertragsklauseln (C2P)', 'Standardvertragsklauseln Controller-zu-Processor', 'Art. 46 Abs. 2 lit. c DSGVO', TRUE, 3),
|
||||
('BCR', 'Binding Corporate Rules', 'Verbindliche interne Datenschutzvorschriften', 'Art. 47 DSGVO', FALSE, 4),
|
||||
('CONSENT_49A', 'Einwilligung (Art. 49)', 'Ausdrueckliche Einwilligung der betroffenen Person', 'Art. 49 Abs. 1 lit. a DSGVO', FALSE, 5),
|
||||
('DEROGATION_49', 'Ausnahme (Art. 49)', 'Ausnahme fuer bestimmte Faelle gemaess Art. 49', 'Art. 49 DSGVO', FALSE, 6),
|
||||
('DPF', 'EU-US Data Privacy Framework', 'Zertifizierung unter dem EU-US Data Privacy Framework', 'Art. 45 DSGVO (DPF)', FALSE, 7),
|
||||
('TIA', 'Transfer Impact Assessment', 'Einzelfallbezogene Risikobewertung fuer Drittlandtransfers', 'Art. 46 DSGVO + Schrems II', TRUE, 8)
|
||||
ON CONFLICT (id) DO NOTHING;
|
||||
|
||||
-- =============================================================================
|
||||
-- Purposes (20)
|
||||
-- =============================================================================
|
||||
INSERT INTO vvt_lib_purposes (id, label_de, description_de, typical_legal_basis, typical_for, sort_order) VALUES
|
||||
('EMPLOYMENT_ADMIN', 'Personalverwaltung', 'Verwaltung des Beschaeftigungsverhaeltnisses', 'BDSG_26', '["hr"]', 1),
|
||||
('PAYROLL', 'Gehaltsabrechnung', 'Durchfuehrung der Lohn- und Gehaltsabrechnung', 'BDSG_26', '["hr","finance"]', 2),
|
||||
('RECRUITING', 'Bewerbermanagement', 'Durchfuehrung von Bewerbungsverfahren', 'BDSG_26', '["hr"]', 3),
|
||||
('TIME_TRACKING', 'Zeiterfassung', 'Erfassung und Verwaltung von Arbeitszeiten', 'ART6_1C', '["hr"]', 4),
|
||||
('ACCOUNTING', 'Buchhaltung', 'Fuehrung der Handelsbuecher und Finanzberichterstattung', 'ART6_1C', '["finance"]', 5),
|
||||
('INVOICING', 'Rechnungsstellung', 'Erstellung und Verwaltung von Rechnungen', 'ART6_1B', '["finance"]', 6),
|
||||
('CRM', 'Kundenbeziehungsmanagement', 'Verwaltung und Pflege von Kundenbeziehungen', 'ART6_1B', '["sales_crm"]', 7),
|
||||
('DIRECT_MARKETING', 'Direktmarketing', 'Newsletter-Versand und Werbemassnahmen', 'ART6_1A', '["marketing"]', 8),
|
||||
('WEBSITE_ANALYTICS', 'Web-Analyse', 'Analyse des Nutzerverhaltens auf der Website', 'ART6_1A', '["marketing","it_operations"]', 9),
|
||||
('CUSTOMER_SUPPORT', 'Kundenbetreuung', 'Bearbeitung von Kundenanfragen und Support-Tickets', 'ART6_1B', '["support"]', 10),
|
||||
('IT_ADMIN', 'IT-Administration', 'Verwaltung der IT-Infrastruktur und Benutzerkonten', 'ART6_1F', '["it_operations"]', 11),
|
||||
('BACKUP_RECOVERY', 'Datensicherung', 'Backup-Erstellung und Wiederherstellung', 'ART6_1F', '["it_operations"]', 12),
|
||||
('SECURITY_MONITORING', 'Sicherheitsueberwachung', 'Log-Analyse und Intrusion Detection', 'ART6_1F', '["it_operations"]', 13),
|
||||
('IAM', 'Identitaets- und Zugriffsmanagement', 'Verwaltung von Benutzeridentitaeten und Berechtigungen', 'ART6_1F', '["it_operations"]', 14),
|
||||
('VIDEO_CONFERENCING', 'Videokonferenz', 'Durchfuehrung von Online-Meetings und Videokonferenzen', 'ART6_1B', '["other"]', 15),
|
||||
('VISITOR_MANAGEMENT', 'Besucherverwaltung', 'Erfassung und Verwaltung von Betriebsbesuchern', 'ART6_1F', '["management"]', 16),
|
||||
('PAYMENT_PROCESSING', 'Zahlungsabwicklung', 'Verarbeitung und Abwicklung von Zahlungen', 'ART6_1B', '["finance"]', 17),
|
||||
('SOCIAL_MEDIA', 'Social-Media-Marketing', 'Betrieb von Social-Media-Praesenzen', 'ART6_1A', '["marketing"]', 18),
|
||||
('SALES_REPORTING', 'Vertriebssteuerung', 'Vertriebsanalysen und Berichterstattung', 'ART6_1F', '["sales_crm"]', 19),
|
||||
('COMPLIANCE_DOCS', 'Compliance-Dokumentation', 'Erstellung und Pflege von Compliance-Dokumenten', 'ART6_1C', '["legal","management"]', 20)
|
||||
ON CONFLICT (id) DO NOTHING;
|
||||
|
||||
-- =============================================================================
|
||||
-- TOMs (20)
|
||||
-- =============================================================================
|
||||
INSERT INTO vvt_lib_toms (id, category, label_de, description_de, art32_reference, sort_order) VALUES
|
||||
('AC_RBAC', 'accessControl', 'Rollenbasierte Zugriffskontrolle (RBAC)', 'Zugriff nur nach Rolle und Berechtigung', 'Art. 32 Abs. 1 lit. b', 1),
|
||||
('AC_MFA', 'accessControl', 'Multi-Faktor-Authentifizierung', 'Zwei- oder mehrstufige Anmeldung', 'Art. 32 Abs. 1 lit. b', 2),
|
||||
('AC_NEED_TO_KNOW', 'accessControl', 'Need-to-Know-Prinzip', 'Zugriff nur auf fuer die Aufgabe erforderliche Daten', 'Art. 32 Abs. 1 lit. b', 3),
|
||||
('AC_PAM', 'accessControl', 'Privileged Access Management', 'Verwaltung und Ueberwachung privilegierter Zugaenge', 'Art. 32 Abs. 1 lit. b', 4),
|
||||
('CONF_ENCRYPTION_REST', 'confidentiality', 'Verschluesselung ruhender Daten', 'AES-256 Verschluesselung fuer gespeicherte Daten', 'Art. 32 Abs. 1 lit. a', 5),
|
||||
('CONF_ENCRYPTION_TRANSIT', 'confidentiality', 'Transportverschluesselung', 'TLS 1.3 fuer alle Datenuebertragungen', 'Art. 32 Abs. 1 lit. a', 6),
|
||||
('CONF_PSEUDONYMIZATION', 'confidentiality', 'Pseudonymisierung', 'Verarbeitung ohne direkten Personenbezug', 'Art. 32 Abs. 1 lit. a', 7),
|
||||
('CONF_NDA', 'confidentiality', 'Vertraulichkeitsvereinbarungen', 'NDAs fuer Mitarbeiter und Auftragnehmer', 'Art. 32 Abs. 1 lit. b', 8),
|
||||
('INT_AUDIT_LOG', 'integrity', 'Audit-Logging', 'Lueckenlose Protokollierung aller Datenzugriffe', 'Art. 32 Abs. 1 lit. b', 9),
|
||||
('INT_FOUR_EYES', 'integrity', 'Vier-Augen-Prinzip', 'Kritische Aenderungen nur mit Freigabe durch zweite Person', 'Art. 32 Abs. 1 lit. b', 10),
|
||||
('INT_CHECKSUMS', 'integrity', 'Pruefsummen und Hashing', 'Integritaetspruefung durch kryptographische Hashes', 'Art. 32 Abs. 1 lit. b', 11),
|
||||
('INT_CHANGE_MGMT', 'integrity', 'Change Management', 'Dokumentierter Aenderungsprozess fuer IT-Systeme', 'Art. 32 Abs. 1 lit. b', 12),
|
||||
('AVAIL_BACKUP', 'availability', 'Regelmaessige Backups', 'Taegliche und woechentliche Datensicherungen', 'Art. 32 Abs. 1 lit. c', 13),
|
||||
('AVAIL_REDUNDANCY', 'availability', 'Redundante Systeme', 'Hochverfuegbarkeit durch Systemredundanz', 'Art. 32 Abs. 1 lit. c', 14),
|
||||
('AVAIL_321_RULE', 'availability', '3-2-1 Backup-Regel', 'Drei Kopien, zwei Medien, ein externer Standort', 'Art. 32 Abs. 1 lit. c', 15),
|
||||
('AVAIL_MONITORING', 'availability', 'System-Monitoring', 'Kontinuierliche Ueberwachung der Systemverfuegbarkeit', 'Art. 32 Abs. 1 lit. c', 16),
|
||||
('SEP_TENANT_ISOLATION', 'separation', 'Mandantentrennung', 'Logische Trennung der Daten verschiedener Mandanten', 'Art. 32 Abs. 1 lit. b', 17),
|
||||
('SEP_NETWORK_SEG', 'separation', 'Netzwerksegmentierung', 'Trennung von Netzwerkbereichen (VLANs, Firewalls)', 'Art. 32 Abs. 1 lit. b', 18),
|
||||
('SEP_DATA_SEPARATION', 'separation', 'Datentrennung', 'Separate Datenbanken oder Schemas pro Zweck', 'Art. 32 Abs. 1 lit. b', 19),
|
||||
('SEP_ENV_SEPARATION', 'separation', 'Umgebungstrennung', 'Getrennte Entwicklungs-, Test- und Produktionsumgebungen', 'Art. 32 Abs. 1 lit. b', 20)
|
||||
ON CONFLICT (id) DO NOTHING;
|
||||
|
||||
COMMIT;
|
||||
54
backend-compliance/migrations/066_vvt_process_templates.sql
Normal file
54
backend-compliance/migrations/066_vvt_process_templates.sql
Normal file
@@ -0,0 +1,54 @@
|
||||
-- Migration 066: VVT Process Templates + Activity extensions
|
||||
-- Template table + new ref columns on compliance_vvt_activities
|
||||
|
||||
BEGIN;
|
||||
|
||||
-- =============================================================================
|
||||
-- Process Templates
|
||||
-- =============================================================================
|
||||
CREATE TABLE IF NOT EXISTS vvt_process_templates (
|
||||
id VARCHAR(80) PRIMARY KEY,
|
||||
name VARCHAR(300) NOT NULL,
|
||||
description TEXT,
|
||||
business_function VARCHAR(50),
|
||||
purpose_refs JSONB DEFAULT '[]'::jsonb,
|
||||
legal_basis_refs JSONB DEFAULT '[]'::jsonb,
|
||||
data_subject_refs JSONB DEFAULT '[]'::jsonb,
|
||||
data_category_refs JSONB DEFAULT '[]'::jsonb,
|
||||
recipient_refs JSONB DEFAULT '[]'::jsonb,
|
||||
tom_refs JSONB DEFAULT '[]'::jsonb,
|
||||
transfer_mechanism_refs JSONB DEFAULT '[]'::jsonb,
|
||||
retention_rule_ref VARCHAR(50),
|
||||
typical_systems JSONB DEFAULT '[]'::jsonb,
|
||||
protection_level VARCHAR(10) DEFAULT 'MEDIUM',
|
||||
dpia_required BOOLEAN DEFAULT FALSE,
|
||||
risk_score INTEGER,
|
||||
tags JSONB DEFAULT '[]'::jsonb,
|
||||
is_system BOOLEAN DEFAULT TRUE,
|
||||
tenant_id UUID,
|
||||
sort_order INTEGER DEFAULT 0,
|
||||
created_at TIMESTAMPTZ DEFAULT NOW(),
|
||||
updated_at TIMESTAMPTZ DEFAULT NOW()
|
||||
);
|
||||
|
||||
CREATE INDEX IF NOT EXISTS idx_vvt_process_templates_bf ON vvt_process_templates(business_function);
|
||||
CREATE INDEX IF NOT EXISTS idx_vvt_process_templates_system ON vvt_process_templates(is_system);
|
||||
|
||||
-- =============================================================================
|
||||
-- New columns on compliance_vvt_activities (all DEFAULT NULL for backward compat)
|
||||
-- =============================================================================
|
||||
ALTER TABLE compliance_vvt_activities ADD COLUMN IF NOT EXISTS purpose_refs JSONB DEFAULT NULL;
|
||||
ALTER TABLE compliance_vvt_activities ADD COLUMN IF NOT EXISTS legal_basis_refs JSONB DEFAULT NULL;
|
||||
ALTER TABLE compliance_vvt_activities ADD COLUMN IF NOT EXISTS data_subject_refs JSONB DEFAULT NULL;
|
||||
ALTER TABLE compliance_vvt_activities ADD COLUMN IF NOT EXISTS data_category_refs JSONB DEFAULT NULL;
|
||||
ALTER TABLE compliance_vvt_activities ADD COLUMN IF NOT EXISTS recipient_refs JSONB DEFAULT NULL;
|
||||
ALTER TABLE compliance_vvt_activities ADD COLUMN IF NOT EXISTS retention_rule_ref VARCHAR(50) DEFAULT NULL;
|
||||
ALTER TABLE compliance_vvt_activities ADD COLUMN IF NOT EXISTS transfer_mechanism_refs JSONB DEFAULT NULL;
|
||||
ALTER TABLE compliance_vvt_activities ADD COLUMN IF NOT EXISTS tom_refs JSONB DEFAULT NULL;
|
||||
ALTER TABLE compliance_vvt_activities ADD COLUMN IF NOT EXISTS linked_loeschfristen_ids JSONB DEFAULT NULL;
|
||||
ALTER TABLE compliance_vvt_activities ADD COLUMN IF NOT EXISTS linked_tom_measure_ids JSONB DEFAULT NULL;
|
||||
ALTER TABLE compliance_vvt_activities ADD COLUMN IF NOT EXISTS source_template_id VARCHAR(80) DEFAULT NULL;
|
||||
ALTER TABLE compliance_vvt_activities ADD COLUMN IF NOT EXISTS risk_score INTEGER DEFAULT NULL;
|
||||
ALTER TABLE compliance_vvt_activities ADD COLUMN IF NOT EXISTS art30_completeness JSONB DEFAULT NULL;
|
||||
|
||||
COMMIT;
|
||||
305
backend-compliance/migrations/067_vvt_process_templates_seed.sql
Normal file
305
backend-compliance/migrations/067_vvt_process_templates_seed.sql
Normal file
@@ -0,0 +1,305 @@
|
||||
-- Migration 067: VVT Process Templates Seed — 18 templates from vvt-baseline-catalog
|
||||
-- All content self-authored, MIT-compatible.
|
||||
|
||||
BEGIN;
|
||||
|
||||
INSERT INTO vvt_process_templates (id, name, description, business_function, purpose_refs, legal_basis_refs, data_subject_refs, data_category_refs, recipient_refs, tom_refs, retention_rule_ref, typical_systems, protection_level, dpia_required, risk_score, tags, sort_order) VALUES
|
||||
|
||||
-- HR Templates
|
||||
('hr-mitarbeiterverwaltung',
|
||||
'Mitarbeiterverwaltung',
|
||||
'Verwaltung des Beschaeftigungsverhaeltnisses inkl. Personalakte, Urlaub, Krankmeldungen',
|
||||
'hr',
|
||||
'["EMPLOYMENT_ADMIN", "PAYROLL"]',
|
||||
'["BDSG_26", "ART6_1B"]',
|
||||
'["EMPLOYEES"]',
|
||||
'["NAME", "DOB", "ADDRESS", "CONTACT", "SOCIAL_SECURITY", "BANK_ACCOUNT", "EMPLOYMENT_DATA", "HEALTH_DATA"]',
|
||||
'["INTERNAL_HR", "INTERNAL_FINANCE", "PROCESSOR_PAYROLL", "AUTHORITY_SOZIALVERSICHERUNG", "AUTHORITY_KRANKENKASSE"]',
|
||||
'["AC_RBAC", "AC_NEED_TO_KNOW", "CONF_ENCRYPTION_REST", "CONF_ENCRYPTION_TRANSIT", "INT_AUDIT_LOG", "SEP_TENANT_ISOLATION"]',
|
||||
'HGB_257_10Y',
|
||||
'["HR-Software", "Personalakte (digital)"]',
|
||||
'HIGH', TRUE, 3,
|
||||
'["personal", "pflicht"]',
|
||||
1),
|
||||
|
||||
('hr-gehaltsabrechnung',
|
||||
'Gehaltsabrechnung',
|
||||
'Monatliche Lohn- und Gehaltsabrechnung inkl. Steuer- und Sozialversicherungsmeldungen',
|
||||
'hr',
|
||||
'["PAYROLL"]',
|
||||
'["BDSG_26", "ART6_1C"]',
|
||||
'["EMPLOYEES"]',
|
||||
'["NAME", "ADDRESS", "SOCIAL_SECURITY", "TAX_ID", "BANK_ACCOUNT", "SALARY_DATA"]',
|
||||
'["INTERNAL_HR", "INTERNAL_FINANCE", "PROCESSOR_PAYROLL", "AUTHORITY_FINANZAMT", "AUTHORITY_SOZIALVERSICHERUNG"]',
|
||||
'["AC_RBAC", "AC_NEED_TO_KNOW", "CONF_ENCRYPTION_REST", "CONF_ENCRYPTION_TRANSIT", "INT_AUDIT_LOG", "INT_FOUR_EYES"]',
|
||||
'AO_147_10Y',
|
||||
'["Lohnabrechnungssoftware", "DATEV"]',
|
||||
'HIGH', FALSE, 3,
|
||||
'["personal", "finanzen", "pflicht"]',
|
||||
2),
|
||||
|
||||
('hr-bewerbermanagement',
|
||||
'Bewerbermanagement',
|
||||
'Durchfuehrung von Bewerbungsverfahren vom Eingang bis zur Zu-/Absage',
|
||||
'hr',
|
||||
'["RECRUITING"]',
|
||||
'["BDSG_26", "ART6_1B"]',
|
||||
'["APPLICANTS"]',
|
||||
'["NAME", "DOB", "ADDRESS", "CONTACT", "EDUCATION_DATA", "PHOTO_VIDEO"]',
|
||||
'["INTERNAL_HR", "INTERNAL_MANAGEMENT"]',
|
||||
'["AC_RBAC", "AC_NEED_TO_KNOW", "CONF_ENCRYPTION_REST", "CONF_NDA"]',
|
||||
'AGG_15_6M',
|
||||
'["Bewerbermanagement-Software", "E-Mail"]',
|
||||
'MEDIUM', FALSE, 2,
|
||||
'["personal", "recruiting"]',
|
||||
3),
|
||||
|
||||
('hr-zeiterfassung',
|
||||
'Zeiterfassung',
|
||||
'Erfassung und Verwaltung von Arbeitszeiten gemaess ArbZG',
|
||||
'hr',
|
||||
'["TIME_TRACKING"]',
|
||||
'["ART6_1C", "BDSG_26"]',
|
||||
'["EMPLOYEES"]',
|
||||
'["NAME", "EMPLOYMENT_DATA"]',
|
||||
'["INTERNAL_HR", "INTERNAL_MANAGEMENT"]',
|
||||
'["AC_RBAC", "INT_AUDIT_LOG", "CONF_ENCRYPTION_TRANSIT"]',
|
||||
'ARBZG_16_2Y',
|
||||
'["Zeiterfassungssystem", "Stempeluhr"]',
|
||||
'LOW', FALSE, 1,
|
||||
'["personal", "pflicht"]',
|
||||
4),
|
||||
|
||||
-- Finance Templates
|
||||
('finance-buchhaltung',
|
||||
'Buchhaltung',
|
||||
'Fuehrung der Handelsbuecher und steuerrechtliche Dokumentation',
|
||||
'finance',
|
||||
'["ACCOUNTING", "INVOICING"]',
|
||||
'["ART6_1C", "ART6_1B"]',
|
||||
'["CUSTOMERS", "SUPPLIERS", "EMPLOYEES"]',
|
||||
'["NAME", "ADDRESS", "CONTACT", "BANK_ACCOUNT", "PAYMENT_DATA", "CONTRACT_DATA", "TAX_ID"]',
|
||||
'["INTERNAL_FINANCE", "AUTHORITY_FINANZAMT", "PROCESSOR_HOSTING"]',
|
||||
'["AC_RBAC", "INT_AUDIT_LOG", "INT_FOUR_EYES", "CONF_ENCRYPTION_REST", "AVAIL_BACKUP"]',
|
||||
'HGB_257_10Y',
|
||||
'["Buchhaltungssoftware", "DATEV", "ERP-System"]',
|
||||
'HIGH', FALSE, 2,
|
||||
'["finanzen", "pflicht"]',
|
||||
5),
|
||||
|
||||
('finance-zahlungsverkehr',
|
||||
'Zahlungsverkehr',
|
||||
'Verarbeitung und Abwicklung von ein- und ausgehenden Zahlungen',
|
||||
'finance',
|
||||
'["PAYMENT_PROCESSING"]',
|
||||
'["ART6_1B", "ART6_1C"]',
|
||||
'["CUSTOMERS", "SUPPLIERS"]',
|
||||
'["NAME", "BANK_ACCOUNT", "PAYMENT_DATA", "CONTRACT_DATA"]',
|
||||
'["INTERNAL_FINANCE", "PROCESSOR_HOSTING"]',
|
||||
'["AC_RBAC", "AC_MFA", "CONF_ENCRYPTION_REST", "CONF_ENCRYPTION_TRANSIT", "INT_AUDIT_LOG"]',
|
||||
'HGB_257_10Y',
|
||||
'["Online-Banking", "Payment-Gateway"]',
|
||||
'HIGH', FALSE, 3,
|
||||
'["finanzen"]',
|
||||
6),
|
||||
|
||||
-- Sales/CRM Templates
|
||||
('sales-kundenverwaltung',
|
||||
'Kundenverwaltung',
|
||||
'Verwaltung und Pflege der Kundenbeziehungen im CRM-System',
|
||||
'sales_crm',
|
||||
'["CRM"]',
|
||||
'["ART6_1B", "ART6_1F"]',
|
||||
'["CUSTOMERS", "PROSPECTIVE_CUSTOMERS"]',
|
||||
'["NAME", "ADDRESS", "CONTACT", "CONTRACT_DATA", "COMMUNICATION_DATA"]',
|
||||
'["INTERNAL_MARKETING", "INTERNAL_SUPPORT", "PROCESSOR_HOSTING"]',
|
||||
'["AC_RBAC", "CONF_ENCRYPTION_REST", "CONF_ENCRYPTION_TRANSIT", "INT_AUDIT_LOG", "SEP_TENANT_ISOLATION"]',
|
||||
'BGB_195_3Y',
|
||||
'["CRM-System", "E-Mail-Client"]',
|
||||
'MEDIUM', FALSE, 2,
|
||||
'["vertrieb", "kunden"]',
|
||||
7),
|
||||
|
||||
('sales-vertriebssteuerung',
|
||||
'Vertriebssteuerung',
|
||||
'Vertriebsanalysen, Forecasting und Berichterstattung',
|
||||
'sales_crm',
|
||||
'["SALES_REPORTING"]',
|
||||
'["ART6_1F"]',
|
||||
'["CUSTOMERS", "PROSPECTIVE_CUSTOMERS"]',
|
||||
'["NAME", "CONTACT", "CONTRACT_DATA"]',
|
||||
'["INTERNAL_MANAGEMENT", "INTERNAL_MARKETING"]',
|
||||
'["AC_RBAC", "AC_NEED_TO_KNOW", "CONF_PSEUDONYMIZATION"]',
|
||||
'BGB_195_3Y',
|
||||
'["CRM-System", "BI-Tool"]',
|
||||
'LOW', FALSE, 1,
|
||||
'["vertrieb", "reporting"]',
|
||||
8),
|
||||
|
||||
-- Marketing Templates
|
||||
('marketing-newsletter',
|
||||
'Newsletter-Versand',
|
||||
'Versand von Newslettern und Werbemails an Abonnenten',
|
||||
'marketing',
|
||||
'["DIRECT_MARKETING"]',
|
||||
'["ART6_1A", "UWG_7"]',
|
||||
'["NEWSLETTER_SUBSCRIBERS", "CUSTOMERS"]',
|
||||
'["NAME", "CONTACT", "USAGE_DATA"]',
|
||||
'["INTERNAL_MARKETING", "PROCESSOR_EMAIL"]',
|
||||
'["AC_RBAC", "CONF_ENCRYPTION_TRANSIT", "SEP_DATA_SEPARATION"]',
|
||||
'CONSENT_REVOKE',
|
||||
'["Newsletter-Tool", "E-Mail-Marketing-Plattform"]',
|
||||
'LOW', FALSE, 1,
|
||||
'["marketing", "einwilligung"]',
|
||||
9),
|
||||
|
||||
('marketing-website-analytics',
|
||||
'Website-Analyse',
|
||||
'Analyse des Nutzerverhaltens auf der Unternehmenswebsite',
|
||||
'marketing',
|
||||
'["WEBSITE_ANALYTICS"]',
|
||||
'["ART6_1A"]',
|
||||
'["WEBSITE_USERS"]',
|
||||
'["IP_ADDRESS", "DEVICE_ID", "USAGE_DATA"]',
|
||||
'["INTERNAL_MARKETING", "PROCESSOR_ANALYTICS"]',
|
||||
'["CONF_PSEUDONYMIZATION", "CONF_ENCRYPTION_TRANSIT", "SEP_DATA_SEPARATION"]',
|
||||
'CUSTOM_14M',
|
||||
'["Web-Analytics-Tool", "Tag-Manager"]',
|
||||
'LOW', FALSE, 1,
|
||||
'["marketing", "einwilligung", "tracking"]',
|
||||
10),
|
||||
|
||||
('marketing-social-media',
|
||||
'Social-Media-Marketing',
|
||||
'Betrieb und Verwaltung von Social-Media-Praesenzen',
|
||||
'marketing',
|
||||
'["SOCIAL_MEDIA"]',
|
||||
'["ART6_1A", "ART6_1F"]',
|
||||
'["WEBSITE_USERS", "CUSTOMERS"]',
|
||||
'["NAME", "CONTACT", "USAGE_DATA", "PHOTO_VIDEO"]',
|
||||
'["INTERNAL_MARKETING", "PROCESSOR_ANALYTICS"]',
|
||||
'["AC_RBAC", "CONF_ENCRYPTION_TRANSIT"]',
|
||||
'PURPOSE_END',
|
||||
'["Social-Media-Plattformen", "Social-Media-Management-Tool"]',
|
||||
'LOW', FALSE, 1,
|
||||
'["marketing", "social-media"]',
|
||||
11),
|
||||
|
||||
-- Support Templates
|
||||
('support-ticketsystem',
|
||||
'Ticketsystem / Kundenservice',
|
||||
'Bearbeitung von Kundenanfragen ueber das Ticketsystem',
|
||||
'support',
|
||||
'["CUSTOMER_SUPPORT"]',
|
||||
'["ART6_1B"]',
|
||||
'["CUSTOMERS"]',
|
||||
'["NAME", "CONTACT", "COMMUNICATION_DATA", "CONTRACT_DATA"]',
|
||||
'["INTERNAL_SUPPORT", "PROCESSOR_HELPDESK"]',
|
||||
'["AC_RBAC", "CONF_ENCRYPTION_TRANSIT", "INT_AUDIT_LOG"]',
|
||||
'BGB_195_3Y',
|
||||
'["Ticketsystem", "Help-Desk-Software"]',
|
||||
'MEDIUM', FALSE, 1,
|
||||
'["support", "kunden"]',
|
||||
12),
|
||||
|
||||
-- IT Templates
|
||||
('it-systemadministration',
|
||||
'IT-Systemadministration',
|
||||
'Verwaltung der IT-Infrastruktur, Benutzerkonten und Berechtigungen',
|
||||
'it_operations',
|
||||
'["IT_ADMIN"]',
|
||||
'["ART6_1F", "ART6_1B"]',
|
||||
'["EMPLOYEES"]',
|
||||
'["NAME", "LOGIN_DATA", "IP_ADDRESS", "DEVICE_ID"]',
|
||||
'["INTERNAL_IT", "PROCESSOR_HOSTING"]',
|
||||
'["AC_RBAC", "AC_MFA", "AC_PAM", "CONF_ENCRYPTION_REST", "CONF_ENCRYPTION_TRANSIT", "INT_AUDIT_LOG", "SEP_NETWORK_SEG", "SEP_ENV_SEPARATION"]',
|
||||
'CUSTOM_90D',
|
||||
'["Active Directory", "LDAP", "IT-Management-Tool"]',
|
||||
'HIGH', FALSE, 2,
|
||||
'["it", "infrastruktur"]',
|
||||
13),
|
||||
|
||||
('it-backup',
|
||||
'Datensicherung und Recovery',
|
||||
'Regelmaessige Backups und Wiederherstellungsverfahren',
|
||||
'it_operations',
|
||||
'["BACKUP_RECOVERY"]',
|
||||
'["ART6_1F"]',
|
||||
'["EMPLOYEES", "CUSTOMERS"]',
|
||||
'["NAME", "ADDRESS", "CONTACT", "CONTRACT_DATA", "LOGIN_DATA"]',
|
||||
'["INTERNAL_IT", "PROCESSOR_HOSTING"]',
|
||||
'["AVAIL_BACKUP", "AVAIL_321_RULE", "AVAIL_REDUNDANCY", "CONF_ENCRYPTION_REST", "INT_CHECKSUMS"]',
|
||||
'CUSTOM_90D',
|
||||
'["Backup-Software", "Cloud-Backup", "NAS"]',
|
||||
'HIGH', FALSE, 2,
|
||||
'["it", "verfuegbarkeit"]',
|
||||
14),
|
||||
|
||||
('it-logging',
|
||||
'Logging und Sicherheitsueberwachung',
|
||||
'Protokollierung von System- und Sicherheitsereignissen',
|
||||
'it_operations',
|
||||
'["SECURITY_MONITORING"]',
|
||||
'["ART6_1F"]',
|
||||
'["EMPLOYEES", "CUSTOMERS", "WEBSITE_USERS"]',
|
||||
'["IP_ADDRESS", "LOGIN_DATA", "USAGE_DATA", "DEVICE_ID"]',
|
||||
'["INTERNAL_IT"]',
|
||||
'["CONF_ENCRYPTION_REST", "INT_AUDIT_LOG", "INT_CHECKSUMS", "AVAIL_MONITORING", "SEP_DATA_SEPARATION"]',
|
||||
'CUSTOM_90D',
|
||||
'["SIEM-System", "Log-Management", "Monitoring-Tool"]',
|
||||
'MEDIUM', FALSE, 2,
|
||||
'["it", "sicherheit"]',
|
||||
15),
|
||||
|
||||
('it-iam',
|
||||
'Identitaets- und Zugriffsmanagement',
|
||||
'Verwaltung von Benutzeridentitaeten, Rollen und Berechtigungen',
|
||||
'it_operations',
|
||||
'["IAM"]',
|
||||
'["ART6_1F", "BDSG_26"]',
|
||||
'["EMPLOYEES"]',
|
||||
'["NAME", "LOGIN_DATA", "EMPLOYMENT_DATA"]',
|
||||
'["INTERNAL_IT", "INTERNAL_HR"]',
|
||||
'["AC_RBAC", "AC_MFA", "AC_PAM", "AC_NEED_TO_KNOW", "INT_AUDIT_LOG", "CONF_ENCRYPTION_REST"]',
|
||||
'AGG_15_6M',
|
||||
'["IAM-System", "SSO-Provider", "Active Directory"]',
|
||||
'HIGH', FALSE, 2,
|
||||
'["it", "sicherheit", "zugriffskontrolle"]',
|
||||
16),
|
||||
|
||||
-- Other Templates
|
||||
('other-videokonferenz',
|
||||
'Videokonferenz',
|
||||
'Durchfuehrung von Online-Meetings und Videokonferenzen',
|
||||
'other',
|
||||
'["VIDEO_CONFERENCING"]',
|
||||
'["ART6_1B", "ART6_1F"]',
|
||||
'["EMPLOYEES", "CUSTOMERS", "BUSINESS_PARTNERS"]',
|
||||
'["NAME", "CONTACT", "PHOTO_VIDEO", "IP_ADDRESS"]',
|
||||
'["INTERNAL_IT", "PROCESSOR_HOSTING"]',
|
||||
'["CONF_ENCRYPTION_TRANSIT", "AC_RBAC"]',
|
||||
'PURPOSE_END',
|
||||
'["Videokonferenz-Tool", "Webinar-Plattform"]',
|
||||
'LOW', FALSE, 1,
|
||||
'["kommunikation"]',
|
||||
17),
|
||||
|
||||
('other-besuchermanagement',
|
||||
'Besuchermanagement',
|
||||
'Erfassung und Verwaltung von Betriebsbesuchern',
|
||||
'other',
|
||||
'["VISITOR_MANAGEMENT"]',
|
||||
'["ART6_1F"]',
|
||||
'["VISITORS"]',
|
||||
'["NAME", "CONTACT", "PHOTO_VIDEO"]',
|
||||
'["INTERNAL_MANAGEMENT"]',
|
||||
'["AC_RBAC", "CONF_ENCRYPTION_REST"]',
|
||||
'CUSTOM_30D',
|
||||
'["Besuchermanagement-System", "Empfangsterminal"]',
|
||||
'LOW', FALSE, 1,
|
||||
'["sonstiges", "besucher"]',
|
||||
18)
|
||||
|
||||
ON CONFLICT (id) DO NOTHING;
|
||||
|
||||
COMMIT;
|
||||
1099
backend-compliance/tests/test_vvt_library_routes.py
Normal file
1099
backend-compliance/tests/test_vvt_library_routes.py
Normal file
File diff suppressed because it is too large
Load Diff
Reference in New Issue
Block a user