""" SQLAlchemy models for DSR — Data Subject Requests (Betroffenenanfragen nach DSGVO Art. 15-21). Tables: - compliance_dsr_requests: Haupttabelle fuer Betroffenenanfragen - compliance_dsr_status_history: Status-Audit-Trail - compliance_dsr_communications: Kommunikation mit Betroffenen - compliance_dsr_templates: Kommunikationsvorlagen - compliance_dsr_template_versions: Versionierte Template-Inhalte - compliance_dsr_exception_checks: Art. 17(3) Ausnahmepruefungen """ import uuid from datetime import datetime from sqlalchemy import ( Column, Text, Boolean, DateTime, JSON, Index ) from sqlalchemy.dialects.postgresql import UUID from classroom_engine.database import Base class DSRRequestDB(Base): """DSR request — Betroffenenanfrage nach DSGVO Art. 15-21.""" __tablename__ = 'compliance_dsr_requests' id = Column(UUID(as_uuid=True), primary_key=True, default=uuid.uuid4) tenant_id = Column(UUID(as_uuid=True), nullable=False) request_number = Column(Text, nullable=False) request_type = Column(Text, nullable=False, default='access') status = Column(Text, nullable=False, default='intake') priority = Column(Text, nullable=False, default='normal') # Antragsteller requester_name = Column(Text, nullable=False) requester_email = Column(Text, nullable=False) requester_phone = Column(Text) requester_address = Column(Text) requester_customer_id = Column(Text) # Anfrage-Details source = Column(Text, nullable=False, default='email') source_details = Column(Text) request_text = Column(Text) notes = Column(Text) internal_notes = Column(Text) # Fristen received_at = Column(DateTime, nullable=False, default=datetime.utcnow) deadline_at = Column(DateTime, nullable=False) extended_deadline_at = Column(DateTime) extension_reason = Column(Text) extension_approved_by = Column(Text) extension_approved_at = Column(DateTime) # Identitaetspruefung identity_verified = Column(Boolean, nullable=False, default=False) verification_method = Column(Text) verified_at = Column(DateTime) verified_by = Column(Text) verification_notes = Column(Text) verification_document_ref = Column(Text) # Zuweisung assigned_to = Column(Text) assigned_at = Column(DateTime) assigned_by = Column(Text) # Abschluss completed_at = Column(DateTime) completion_notes = Column(Text) rejection_reason = Column(Text) rejection_legal_basis = Column(Text) # Typ-spezifische Daten erasure_checklist = Column(JSON, default=list) data_export = Column(JSON, default=dict) rectification_details = Column(JSON, default=dict) objection_details = Column(JSON, default=dict) affected_systems = Column(JSON, default=list) created_at = Column(DateTime, default=datetime.utcnow, nullable=False) updated_at = Column(DateTime, default=datetime.utcnow, onupdate=datetime.utcnow) created_by = Column(Text, default='system') updated_by = Column(Text) __table_args__ = ( Index('idx_dsr_requests_tenant', 'tenant_id'), Index('idx_dsr_requests_status', 'status'), Index('idx_dsr_requests_type', 'request_type'), Index('idx_dsr_requests_priority', 'priority'), Index('idx_dsr_requests_assigned', 'assigned_to'), Index('idx_dsr_requests_deadline', 'deadline_at'), Index('idx_dsr_requests_received', 'received_at'), ) class DSRStatusHistoryDB(Base): """Status-Audit-Trail fuer DSR Requests.""" __tablename__ = 'compliance_dsr_status_history' id = Column(UUID(as_uuid=True), primary_key=True, default=uuid.uuid4) tenant_id = Column(UUID(as_uuid=True), nullable=False) dsr_id = Column(UUID(as_uuid=True), nullable=False) previous_status = Column(Text) new_status = Column(Text, nullable=False) changed_by = Column(Text) comment = Column(Text) created_at = Column(DateTime, default=datetime.utcnow, nullable=False) __table_args__ = ( Index('idx_dsr_history_dsr', 'dsr_id'), Index('idx_dsr_history_created', 'created_at'), ) class DSRCommunicationDB(Base): """Kommunikation mit Betroffenen (E-Mail, Portal, intern).""" __tablename__ = 'compliance_dsr_communications' id = Column(UUID(as_uuid=True), primary_key=True, default=uuid.uuid4) tenant_id = Column(UUID(as_uuid=True), nullable=False) dsr_id = Column(UUID(as_uuid=True), nullable=False) communication_type = Column(Text, nullable=False, default='outgoing') channel = Column(Text, nullable=False, default='email') subject = Column(Text) content = Column(Text, nullable=False) template_used = Column(Text) attachments = Column(JSON, default=list) sent_at = Column(DateTime) sent_by = Column(Text) received_at = Column(DateTime) created_at = Column(DateTime, default=datetime.utcnow, nullable=False) created_by = Column(Text, default='system') __table_args__ = ( Index('idx_dsr_comms_dsr', 'dsr_id'), ) class DSRTemplateDB(Base): """Kommunikationsvorlagen fuer DSR.""" __tablename__ = 'compliance_dsr_templates' id = Column(UUID(as_uuid=True), primary_key=True, default=uuid.uuid4) tenant_id = Column(UUID(as_uuid=True), nullable=False) name = Column(Text, nullable=False) template_type = Column(Text, nullable=False) request_type = Column(Text) language = Column(Text, nullable=False, default='de') is_active = Column(Boolean, nullable=False, default=True) created_at = Column(DateTime, default=datetime.utcnow, nullable=False) updated_at = Column(DateTime, default=datetime.utcnow, onupdate=datetime.utcnow) __table_args__ = ( Index('idx_dsr_templates_tenant', 'tenant_id'), Index('idx_dsr_templates_type', 'template_type'), ) class DSRTemplateVersionDB(Base): """Versionierte Template-Inhalte.""" __tablename__ = 'compliance_dsr_template_versions' id = Column(UUID(as_uuid=True), primary_key=True, default=uuid.uuid4) template_id = Column(UUID(as_uuid=True), nullable=False) version = Column(Text, nullable=False, default='1.0') subject = Column(Text, nullable=False) body_html = Column(Text, nullable=False) body_text = Column(Text) status = Column(Text, nullable=False, default='draft') published_at = Column(DateTime) published_by = Column(Text) created_at = Column(DateTime, default=datetime.utcnow, nullable=False) created_by = Column(Text, default='system') __table_args__ = ( Index('idx_dsr_tpl_versions_template', 'template_id'), Index('idx_dsr_tpl_versions_status', 'status'), ) class DSRExceptionCheckDB(Base): """Art. 17(3) Ausnahmepruefungen fuer Loeschanfragen.""" __tablename__ = 'compliance_dsr_exception_checks' id = Column(UUID(as_uuid=True), primary_key=True, default=uuid.uuid4) tenant_id = Column(UUID(as_uuid=True), nullable=False) dsr_id = Column(UUID(as_uuid=True), nullable=False) check_code = Column(Text, nullable=False) article = Column(Text, nullable=False) label = Column(Text, nullable=False) description = Column(Text) applies = Column(Boolean) notes = Column(Text) checked_by = Column(Text) checked_at = Column(DateTime) created_at = Column(DateTime, default=datetime.utcnow, nullable=False) __table_args__ = ( Index('idx_dsr_exception_dsr', 'dsr_id'), )