package ucca // ============================================================================ // DSGVO Module // ============================================================================ // // This module implements the GDPR (DSGVO - Datenschutz-Grundverordnung) obligations. // // Split into: // - dsgvo_module.go — struct, constants, classification, derive methods, decision tree // - dsgvo_yaml.go — YAML loading and conversion helpers // - dsgvo_obligations.go — hardcoded fallback obligations/controls/deadlines // // ============================================================================ // DSGVOModule implements the RegulationModule interface for DSGVO type DSGVOModule struct { obligations []Obligation controls []ObligationControl incidentDeadlines []IncidentDeadline decisionTree *DecisionTree loaded bool } var ( // DSGVOSpecialCategories contains Article 9 special categories of personal data DSGVOSpecialCategories = map[string]bool{ "racial_ethnic_origin": true, "political_opinions": true, "religious_beliefs": true, "trade_union_membership": true, "genetic_data": true, "biometric_data": true, "health_data": true, "sexual_orientation": true, } // DSGVOHighRiskProcessing contains high risk processing activities (Art. 35) DSGVOHighRiskProcessing = map[string]bool{ "systematic_monitoring": true, "automated_decisions": true, "large_scale_special": true, "public_area_monitoring": true, "profiling": true, "vulnerable_persons": true, } ) // NewDSGVOModule creates a new DSGVO module, loading obligations from YAML func NewDSGVOModule() (*DSGVOModule, error) { m := &DSGVOModule{ obligations: []Obligation{}, controls: []ObligationControl{}, incidentDeadlines: []IncidentDeadline{}, } if err := m.loadFromYAML(); err != nil { m.loadHardcodedObligations() } m.buildDecisionTree() m.loaded = true return m, nil } // ID returns the module identifier func (m *DSGVOModule) ID() string { return "dsgvo" } // Name returns the human-readable name func (m *DSGVOModule) Name() string { return "DSGVO (Datenschutz-Grundverordnung)" } // Description returns a brief description func (m *DSGVOModule) Description() string { return "EU-Datenschutz-Grundverordnung (Verordnung (EU) 2016/679) - Schutz personenbezogener Daten" } // IsApplicable checks if DSGVO applies to the organization func (m *DSGVOModule) IsApplicable(facts *UnifiedFacts) bool { if !facts.DataProtection.ProcessesPersonalData { return false } if facts.Organization.EUMember || facts.DataProtection.OffersToEU || facts.DataProtection.MonitorsEUIndividuals { return true } return facts.DataProtection.ProcessesPersonalData } // GetClassification returns the DSGVO classification as string func (m *DSGVOModule) GetClassification(facts *UnifiedFacts) string { if !m.IsApplicable(facts) { return "nicht_anwendbar" } if m.hasHighRiskProcessing(facts) { if facts.DataProtection.IsController { return "verantwortlicher_hohes_risiko" } return "auftragsverarbeiter_hohes_risiko" } if facts.DataProtection.IsController { return "verantwortlicher" } return "auftragsverarbeiter" } func (m *DSGVOModule) hasHighRiskProcessing(facts *UnifiedFacts) bool { for _, cat := range facts.DataProtection.SpecialCategories { if DSGVOSpecialCategories[cat] { return true } } for _, activity := range facts.DataProtection.HighRiskActivities { if DSGVOHighRiskProcessing[activity] { return true } } if facts.DataProtection.DataSubjectCount > 10000 { return true } if facts.DataProtection.SystematicMonitoring { return true } if facts.DataProtection.AutomatedDecisions && facts.DataProtection.LegalEffects { return true } return false } func (m *DSGVOModule) requiresDPO(facts *UnifiedFacts) bool { if facts.Organization.IsPublicAuthority { return true } if facts.DataProtection.SystematicMonitoring && facts.DataProtection.DataSubjectCount > 10000 { return true } if len(facts.DataProtection.SpecialCategories) > 0 && facts.DataProtection.DataSubjectCount > 10000 { return true } if facts.Organization.Country == "DE" && facts.Organization.EmployeeCount >= 20 { return true } return false } // DeriveObligations derives all applicable DSGVO obligations func (m *DSGVOModule) DeriveObligations(facts *UnifiedFacts) []Obligation { if !m.IsApplicable(facts) { return []Obligation{} } var result []Obligation isHighRisk := m.hasHighRiskProcessing(facts) needsDPO := m.requiresDPO(facts) isController := facts.DataProtection.IsController usesProcessors := facts.DataProtection.UsesExternalProcessor for _, obl := range m.obligations { if m.obligationApplies(obl, isController, isHighRisk, needsDPO, usesProcessors, facts) { customized := obl customized.RegulationID = m.ID() result = append(result, customized) } } return result } func (m *DSGVOModule) obligationApplies(obl Obligation, isController, isHighRisk, needsDPO, usesProcessors bool, facts *UnifiedFacts) bool { switch obl.AppliesWhen { case "always": return true case "controller": return isController case "processor": return !isController case "high_risk": return isHighRisk case "needs_dpo": return needsDPO case "uses_processors": return usesProcessors case "controller_or_processor": return true case "special_categories": return len(facts.DataProtection.SpecialCategories) > 0 case "cross_border": return facts.DataProtection.CrossBorderProcessing case "": return true default: return true } } // DeriveControls derives all applicable DSGVO controls func (m *DSGVOModule) DeriveControls(facts *UnifiedFacts) []ObligationControl { if !m.IsApplicable(facts) { return []ObligationControl{} } var result []ObligationControl for _, ctrl := range m.controls { ctrl.RegulationID = m.ID() result = append(result, ctrl) } return result } // GetDecisionTree returns the DSGVO applicability decision tree func (m *DSGVOModule) GetDecisionTree() *DecisionTree { return m.decisionTree } // GetIncidentDeadlines returns DSGVO breach notification deadlines func (m *DSGVOModule) GetIncidentDeadlines(facts *UnifiedFacts) []IncidentDeadline { if !m.IsApplicable(facts) { return []IncidentDeadline{} } return m.incidentDeadlines } func (m *DSGVOModule) buildDecisionTree() { m.decisionTree = &DecisionTree{ ID: "dsgvo_applicability", Name: "DSGVO Anwendbarkeits-Entscheidungsbaum", RootNode: &DecisionNode{ ID: "root", Question: "Verarbeitet Ihre Organisation personenbezogene Daten?", YesNode: &DecisionNode{ ID: "eu_check", Question: "Ist Ihre Organisation in der EU/EWR ansässig?", YesNode: &DecisionNode{ ID: "eu_established", Result: "DSGVO anwendbar", Explanation: "Die DSGVO gilt für alle in der EU ansässigen Organisationen, die personenbezogene Daten verarbeiten.", }, NoNode: &DecisionNode{ ID: "offering_check", Question: "Bieten Sie Waren oder Dienstleistungen an Personen in der EU an?", YesNode: &DecisionNode{ ID: "offering_to_eu", Result: "DSGVO anwendbar", Explanation: "Die DSGVO gilt für Organisationen außerhalb der EU, die Waren/Dienstleistungen an EU-Bürger anbieten.", }, NoNode: &DecisionNode{ ID: "monitoring_check", Question: "Beobachten Sie das Verhalten von Personen in der EU?", YesNode: &DecisionNode{ ID: "monitoring_eu", Result: "DSGVO anwendbar", Explanation: "Die DSGVO gilt für Organisationen, die das Verhalten von Personen in der EU beobachten (z.B. Tracking, Profiling).", }, NoNode: &DecisionNode{ ID: "not_applicable", Result: "DSGVO nicht anwendbar", Explanation: "Die DSGVO ist nicht anwendbar, da keine der Anknüpfungskriterien erfüllt ist.", }, }, }, }, NoNode: &DecisionNode{ ID: "no_personal_data", Result: "DSGVO nicht anwendbar", Explanation: "Die DSGVO gilt nur für die Verarbeitung personenbezogener Daten.", }, }, } }