package models import ( "time" "github.com/google/uuid" ) // ======================================== // DSGVO Betroffenenanfragen (DSR) // Data Subject Request Management // Art. 15, 16, 17, 18, 20 DSGVO // ======================================== // DSRRequestType defines the GDPR article for the request type DSRRequestType string const ( DSRTypeAccess DSRRequestType = "access" // Art. 15 - Auskunftsrecht DSRTypeRectification DSRRequestType = "rectification" // Art. 16 - Berichtigungsrecht DSRTypeErasure DSRRequestType = "erasure" // Art. 17 - Löschungsrecht DSRTypeRestriction DSRRequestType = "restriction" // Art. 18 - Einschränkungsrecht DSRTypePortability DSRRequestType = "portability" // Art. 20 - Datenübertragbarkeit ) // DSRStatus defines the workflow state of a DSR type DSRStatus string const ( DSRStatusIntake DSRStatus = "intake" // Eingegangen DSRStatusIdentityVerification DSRStatus = "identity_verification" // Identitätsprüfung DSRStatusProcessing DSRStatus = "processing" // In Bearbeitung DSRStatusCompleted DSRStatus = "completed" // Abgeschlossen DSRStatusRejected DSRStatus = "rejected" // Abgelehnt DSRStatusCancelled DSRStatus = "cancelled" // Storniert ) // DSRPriority defines the priority level of a DSR type DSRPriority string const ( DSRPriorityNormal DSRPriority = "normal" DSRPriorityExpedited DSRPriority = "expedited" // Art. 16, 17, 18 - beschleunigt DSRPriorityUrgent DSRPriority = "urgent" ) // DSRSource defines where the request came from type DSRSource string const ( DSRSourceAPI DSRSource = "api" // Über API/Self-Service DSRSourceAdminPanel DSRSource = "admin_panel" // Manuell im Admin DSRSourceEmail DSRSource = "email" // Per E-Mail DSRSourcePostal DSRSource = "postal" // Per Post ) // Art. 17(3) Exception Types const ( DSRExceptionFreedomExpression = "freedom_expression" // Art. 17(3)(a) DSRExceptionLegalObligation = "legal_obligation" // Art. 17(3)(b) DSRExceptionPublicInterest = "public_interest" // Art. 17(3)(c) DSRExceptionPublicHealth = "public_health" // Art. 17(3)(c) DSRExceptionArchiving = "archiving" // Art. 17(3)(d) DSRExceptionLegalClaims = "legal_claims" // Art. 17(3)(e) ) // DataSubjectRequest represents a GDPR data subject request type DataSubjectRequest struct { ID uuid.UUID `json:"id" db:"id"` UserID *uuid.UUID `json:"user_id,omitempty" db:"user_id"` RequestNumber string `json:"request_number" db:"request_number"` RequestType DSRRequestType `json:"request_type" db:"request_type"` Status DSRStatus `json:"status" db:"status"` Priority DSRPriority `json:"priority" db:"priority"` Source DSRSource `json:"source" db:"source"` RequesterEmail string `json:"requester_email" db:"requester_email"` RequesterName *string `json:"requester_name,omitempty" db:"requester_name"` RequesterPhone *string `json:"requester_phone,omitempty" db:"requester_phone"` IdentityVerified bool `json:"identity_verified" db:"identity_verified"` IdentityVerifiedAt *time.Time `json:"identity_verified_at,omitempty" db:"identity_verified_at"` IdentityVerifiedBy *uuid.UUID `json:"identity_verified_by,omitempty" db:"identity_verified_by"` IdentityVerificationMethod *string `json:"identity_verification_method,omitempty" db:"identity_verification_method"` RequestDetails map[string]interface{} `json:"request_details" db:"request_details"` DeadlineAt time.Time `json:"deadline_at" db:"deadline_at"` LegalDeadlineDays int `json:"legal_deadline_days" db:"legal_deadline_days"` ExtendedDeadlineAt *time.Time `json:"extended_deadline_at,omitempty" db:"extended_deadline_at"` ExtensionReason *string `json:"extension_reason,omitempty" db:"extension_reason"` AssignedTo *uuid.UUID `json:"assigned_to,omitempty" db:"assigned_to"` ProcessingNotes *string `json:"processing_notes,omitempty" db:"processing_notes"` CompletedAt *time.Time `json:"completed_at,omitempty" db:"completed_at"` CompletedBy *uuid.UUID `json:"completed_by,omitempty" db:"completed_by"` ResultSummary *string `json:"result_summary,omitempty" db:"result_summary"` ResultData map[string]interface{} `json:"result_data,omitempty" db:"result_data"` RejectedAt *time.Time `json:"rejected_at,omitempty" db:"rejected_at"` RejectedBy *uuid.UUID `json:"rejected_by,omitempty" db:"rejected_by"` RejectionReason *string `json:"rejection_reason,omitempty" db:"rejection_reason"` RejectionLegalBasis *string `json:"rejection_legal_basis,omitempty" db:"rejection_legal_basis"` CreatedAt time.Time `json:"created_at" db:"created_at"` UpdatedAt time.Time `json:"updated_at" db:"updated_at"` CreatedBy *uuid.UUID `json:"created_by,omitempty" db:"created_by"` } // DSRStatusHistory tracks status changes for audit trail type DSRStatusHistory struct { ID uuid.UUID `json:"id" db:"id"` RequestID uuid.UUID `json:"request_id" db:"request_id"` FromStatus *DSRStatus `json:"from_status,omitempty" db:"from_status"` ToStatus DSRStatus `json:"to_status" db:"to_status"` ChangedBy *uuid.UUID `json:"changed_by,omitempty" db:"changed_by"` Comment *string `json:"comment,omitempty" db:"comment"` Metadata map[string]interface{} `json:"metadata,omitempty" db:"metadata"` CreatedAt time.Time `json:"created_at" db:"created_at"` } // DSRCommunication tracks all communications related to a DSR type DSRCommunication struct { ID uuid.UUID `json:"id" db:"id"` RequestID uuid.UUID `json:"request_id" db:"request_id"` Direction string `json:"direction" db:"direction"` Channel string `json:"channel" db:"channel"` CommunicationType string `json:"communication_type" db:"communication_type"` TemplateVersionID *uuid.UUID `json:"template_version_id,omitempty" db:"template_version_id"` Subject *string `json:"subject,omitempty" db:"subject"` BodyHTML *string `json:"body_html,omitempty" db:"body_html"` BodyText *string `json:"body_text,omitempty" db:"body_text"` RecipientEmail *string `json:"recipient_email,omitempty" db:"recipient_email"` SentAt *time.Time `json:"sent_at,omitempty" db:"sent_at"` ErrorMessage *string `json:"error_message,omitempty" db:"error_message"` Attachments []map[string]interface{} `json:"attachments,omitempty" db:"attachments"` CreatedAt time.Time `json:"created_at" db:"created_at"` CreatedBy *uuid.UUID `json:"created_by,omitempty" db:"created_by"` } // DSRTemplate represents a template type for DSR communications type DSRTemplate struct { ID uuid.UUID `json:"id" db:"id"` TemplateType string `json:"template_type" db:"template_type"` Name string `json:"name" db:"name"` Description *string `json:"description,omitempty" db:"description"` RequestTypes []string `json:"request_types" db:"request_types"` IsActive bool `json:"is_active" db:"is_active"` SortOrder int `json:"sort_order" db:"sort_order"` CreatedAt time.Time `json:"created_at" db:"created_at"` UpdatedAt time.Time `json:"updated_at" db:"updated_at"` } // DSRTemplateVersion represents a versioned template for DSR communications type DSRTemplateVersion struct { ID uuid.UUID `json:"id" db:"id"` TemplateID uuid.UUID `json:"template_id" db:"template_id"` Version string `json:"version" db:"version"` Language string `json:"language" db:"language"` Subject string `json:"subject" db:"subject"` BodyHTML string `json:"body_html" db:"body_html"` BodyText string `json:"body_text" db:"body_text"` Status string `json:"status" db:"status"` PublishedAt *time.Time `json:"published_at,omitempty" db:"published_at"` CreatedBy *uuid.UUID `json:"created_by,omitempty" db:"created_by"` ApprovedBy *uuid.UUID `json:"approved_by,omitempty" db:"approved_by"` ApprovedAt *time.Time `json:"approved_at,omitempty" db:"approved_at"` CreatedAt time.Time `json:"created_at" db:"created_at"` UpdatedAt time.Time `json:"updated_at" db:"updated_at"` } // DSRExceptionCheck tracks Art. 17(3) exception evaluations for erasure requests type DSRExceptionCheck struct { ID uuid.UUID `json:"id" db:"id"` RequestID uuid.UUID `json:"request_id" db:"request_id"` ExceptionType string `json:"exception_type" db:"exception_type"` Description string `json:"description" db:"description"` Applies *bool `json:"applies,omitempty" db:"applies"` CheckedBy *uuid.UUID `json:"checked_by,omitempty" db:"checked_by"` CheckedAt *time.Time `json:"checked_at,omitempty" db:"checked_at"` Notes *string `json:"notes,omitempty" db:"notes"` CreatedAt time.Time `json:"created_at" db:"created_at"` } // ======================================== // DSR DTOs // ======================================== // CreateDSRRequest for creating a new data subject request type CreateDSRRequest struct { RequestType string `json:"request_type" binding:"required"` RequesterEmail string `json:"requester_email" binding:"required,email"` RequesterName *string `json:"requester_name"` RequesterPhone *string `json:"requester_phone"` Source string `json:"source"` RequestDetails map[string]interface{} `json:"request_details"` Priority string `json:"priority"` } // UpdateDSRRequest for updating a DSR type UpdateDSRRequest struct { Status *string `json:"status"` AssignedTo *string `json:"assigned_to"` ProcessingNotes *string `json:"processing_notes"` ExtendDeadline *bool `json:"extend_deadline"` ExtensionReason *string `json:"extension_reason"` RequestDetails map[string]interface{} `json:"request_details"` Priority *string `json:"priority"` } // VerifyDSRIdentityRequest for verifying identity of requester type VerifyDSRIdentityRequest struct { Method string `json:"method" binding:"required"` Comment *string `json:"comment"` } // CompleteDSRRequest for completing a DSR type CompleteDSRRequest struct { ResultSummary string `json:"result_summary" binding:"required"` ResultData map[string]interface{} `json:"result_data"` } // RejectDSRRequest for rejecting a DSR type RejectDSRRequest struct { Reason string `json:"reason" binding:"required"` LegalBasis string `json:"legal_basis" binding:"required"` } // ExtendDSRDeadlineRequest for extending a DSR deadline type ExtendDSRDeadlineRequest struct { Reason string `json:"reason" binding:"required"` Days int `json:"days"` } // AssignDSRRequest for assigning a DSR to a handler type AssignDSRRequest struct { AssigneeID string `json:"assignee_id" binding:"required"` Comment *string `json:"comment"` } // SendDSRCommunicationRequest for sending a communication type SendDSRCommunicationRequest struct { CommunicationType string `json:"communication_type" binding:"required"` TemplateVersionID *string `json:"template_version_id"` CustomSubject *string `json:"custom_subject"` CustomBody *string `json:"custom_body"` Variables map[string]string `json:"variables"` } // UpdateDSRExceptionCheckRequest for updating an exception check type UpdateDSRExceptionCheckRequest struct { Applies bool `json:"applies"` Notes *string `json:"notes"` } // DSRListFilters for filtering DSR list type DSRListFilters struct { Status *string `form:"status"` RequestType *string `form:"request_type"` AssignedTo *string `form:"assigned_to"` Priority *string `form:"priority"` OverdueOnly bool `form:"overdue_only"` FromDate *time.Time `form:"from_date"` ToDate *time.Time `form:"to_date"` Search *string `form:"search"` } // DSRDashboardStats for the admin dashboard type DSRDashboardStats struct { TotalRequests int `json:"total_requests"` PendingRequests int `json:"pending_requests"` OverdueRequests int `json:"overdue_requests"` CompletedThisMonth int `json:"completed_this_month"` AverageProcessingDays float64 `json:"average_processing_days"` ByType map[string]int `json:"by_type"` ByStatus map[string]int `json:"by_status"` UpcomingDeadlines []DataSubjectRequest `json:"upcoming_deadlines"` } // DSRWithDetails combines DSR with related data type DSRWithDetails struct { Request DataSubjectRequest `json:"request"` StatusHistory []DSRStatusHistory `json:"status_history"` Communications []DSRCommunication `json:"communications"` ExceptionChecks []DSRExceptionCheck `json:"exception_checks,omitempty"` AssigneeName *string `json:"assignee_name,omitempty"` CreatorName *string `json:"creator_name,omitempty"` } // DSRTemplateWithVersions combines template with versions type DSRTemplateWithVersions struct { Template DSRTemplate `json:"template"` LatestVersion *DSRTemplateVersion `json:"latest_version,omitempty"` Versions []DSRTemplateVersion `json:"versions,omitempty"` } // CreateDSRTemplateVersionRequest for creating a template version type CreateDSRTemplateVersionRequest struct { TemplateID string `json:"template_id" binding:"required"` Version string `json:"version" binding:"required"` Language string `json:"language" binding:"required"` Subject string `json:"subject" binding:"required"` BodyHTML string `json:"body_html" binding:"required"` BodyText string `json:"body_text" binding:"required"` } // UpdateDSRTemplateVersionRequest for updating a template version type UpdateDSRTemplateVersionRequest struct { Subject *string `json:"subject"` BodyHTML *string `json:"body_html"` BodyText *string `json:"body_text"` Status *string `json:"status"` } // PreviewDSRTemplateRequest for previewing a template with variables type PreviewDSRTemplateRequest struct { Variables map[string]string `json:"variables"` } // DSRTemplatePreviewResponse for template preview type DSRTemplatePreviewResponse struct { Subject string `json:"subject"` BodyHTML string `json:"body_html"` BodyText string `json:"body_text"` } // ======================================== // DSR Helper Methods // ======================================== // Label returns German label for request type func (rt DSRRequestType) Label() string { switch rt { case DSRTypeAccess: return "Auskunftsanfrage (Art. 15)" case DSRTypeRectification: return "Berichtigungsanfrage (Art. 16)" case DSRTypeErasure: return "Löschanfrage (Art. 17)" case DSRTypeRestriction: return "Einschränkungsanfrage (Art. 18)" case DSRTypePortability: return "Datenübertragung (Art. 20)" default: return string(rt) } } // DeadlineDays returns the legal deadline in days for request type func (rt DSRRequestType) DeadlineDays() int { switch rt { case DSRTypeAccess, DSRTypePortability: return 30 // 1 month case DSRTypeRectification, DSRTypeErasure, DSRTypeRestriction: return 14 // 2 weeks (expedited per BDSG) default: return 30 } } // IsExpedited returns whether this request type should be processed expeditiously func (rt DSRRequestType) IsExpedited() bool { switch rt { case DSRTypeRectification, DSRTypeErasure, DSRTypeRestriction: return true default: return false } } // Label returns German label for status func (s DSRStatus) Label() string { switch s { case DSRStatusIntake: return "Eingang" case DSRStatusIdentityVerification: return "Identitätsprüfung" case DSRStatusProcessing: return "In Bearbeitung" case DSRStatusCompleted: return "Abgeschlossen" case DSRStatusRejected: return "Abgelehnt" case DSRStatusCancelled: return "Storniert" default: return string(s) } } // IsValidDSRRequestType checks if a string is a valid DSR request type func IsValidDSRRequestType(reqType string) bool { switch DSRRequestType(reqType) { case DSRTypeAccess, DSRTypeRectification, DSRTypeErasure, DSRTypeRestriction, DSRTypePortability: return true default: return false } } // IsValidDSRStatus checks if a string is a valid DSR status func IsValidDSRStatus(status string) bool { switch DSRStatus(status) { case DSRStatusIntake, DSRStatusIdentityVerification, DSRStatusProcessing, DSRStatusCompleted, DSRStatusRejected, DSRStatusCancelled: return true default: return false } }