refactor(backend/api): extract Notfallplan schemas + services (Step 4)
Split notfallplan_routes.py (1018 LOC) into clean architecture layers: - compliance/schemas/notfallplan.py (146 LOC): all Pydantic models - compliance/services/notfallplan_service.py (500 LOC): contacts, scenarios, checklists, exercises, stats - compliance/services/notfallplan_workflow_service.py (309 LOC): incidents, templates - compliance/api/notfallplan_routes.py (361 LOC): thin handlers with domain error translation All 250 tests pass. Schemas re-exported via __all__ for legacy test imports. Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
This commit is contained in:
146
backend-compliance/compliance/schemas/notfallplan.py
Normal file
146
backend-compliance/compliance/schemas/notfallplan.py
Normal file
@@ -0,0 +1,146 @@
|
||||
"""
|
||||
Notfallplan (Emergency Plan) schemas -- Art. 33/34 DSGVO.
|
||||
|
||||
Phase 1 Step 4: extracted from ``compliance.api.notfallplan_routes``.
|
||||
"""
|
||||
|
||||
from typing import Any, List, Optional
|
||||
|
||||
from pydantic import BaseModel
|
||||
|
||||
|
||||
# ============================================================================
|
||||
# Contacts
|
||||
# ============================================================================
|
||||
|
||||
|
||||
class ContactCreate(BaseModel):
|
||||
name: str
|
||||
role: Optional[str] = None
|
||||
email: Optional[str] = None
|
||||
phone: Optional[str] = None
|
||||
is_primary: bool = False
|
||||
available_24h: bool = False
|
||||
|
||||
|
||||
class ContactUpdate(BaseModel):
|
||||
name: Optional[str] = None
|
||||
role: Optional[str] = None
|
||||
email: Optional[str] = None
|
||||
phone: Optional[str] = None
|
||||
is_primary: Optional[bool] = None
|
||||
available_24h: Optional[bool] = None
|
||||
|
||||
|
||||
# ============================================================================
|
||||
# Scenarios
|
||||
# ============================================================================
|
||||
|
||||
|
||||
class ScenarioCreate(BaseModel):
|
||||
title: str
|
||||
category: Optional[str] = None
|
||||
severity: str = "medium"
|
||||
description: Optional[str] = None
|
||||
response_steps: List[Any] = []
|
||||
estimated_recovery_time: Optional[int] = None
|
||||
is_active: bool = True
|
||||
|
||||
|
||||
class ScenarioUpdate(BaseModel):
|
||||
title: Optional[str] = None
|
||||
category: Optional[str] = None
|
||||
severity: Optional[str] = None
|
||||
description: Optional[str] = None
|
||||
response_steps: Optional[List[Any]] = None
|
||||
estimated_recovery_time: Optional[int] = None
|
||||
last_tested: Optional[str] = None
|
||||
is_active: Optional[bool] = None
|
||||
|
||||
|
||||
# ============================================================================
|
||||
# Checklists
|
||||
# ============================================================================
|
||||
|
||||
|
||||
class ChecklistCreate(BaseModel):
|
||||
title: str
|
||||
scenario_id: Optional[str] = None
|
||||
description: Optional[str] = None
|
||||
order_index: int = 0
|
||||
is_required: bool = True
|
||||
|
||||
|
||||
class ChecklistUpdate(BaseModel):
|
||||
title: Optional[str] = None
|
||||
description: Optional[str] = None
|
||||
order_index: Optional[int] = None
|
||||
is_required: Optional[bool] = None
|
||||
|
||||
|
||||
# ============================================================================
|
||||
# Exercises
|
||||
# ============================================================================
|
||||
|
||||
|
||||
class ExerciseCreate(BaseModel):
|
||||
title: str
|
||||
scenario_id: Optional[str] = None
|
||||
exercise_type: str = "tabletop"
|
||||
exercise_date: Optional[str] = None
|
||||
participants: List[Any] = []
|
||||
outcome: Optional[str] = None
|
||||
notes: Optional[str] = None
|
||||
|
||||
|
||||
# ============================================================================
|
||||
# Incidents
|
||||
# ============================================================================
|
||||
|
||||
|
||||
class IncidentCreate(BaseModel):
|
||||
title: str
|
||||
description: Optional[str] = None
|
||||
detected_by: Optional[str] = None
|
||||
status: str = "detected"
|
||||
severity: str = "medium"
|
||||
affected_data_categories: List[Any] = []
|
||||
estimated_affected_persons: int = 0
|
||||
measures: List[Any] = []
|
||||
art34_required: bool = False
|
||||
art34_justification: Optional[str] = None
|
||||
|
||||
|
||||
class IncidentUpdate(BaseModel):
|
||||
title: Optional[str] = None
|
||||
description: Optional[str] = None
|
||||
detected_by: Optional[str] = None
|
||||
status: Optional[str] = None
|
||||
severity: Optional[str] = None
|
||||
affected_data_categories: Optional[List[Any]] = None
|
||||
estimated_affected_persons: Optional[int] = None
|
||||
measures: Optional[List[Any]] = None
|
||||
art34_required: Optional[bool] = None
|
||||
art34_justification: Optional[str] = None
|
||||
reported_to_authority_at: Optional[str] = None
|
||||
notified_affected_at: Optional[str] = None
|
||||
closed_at: Optional[str] = None
|
||||
closed_by: Optional[str] = None
|
||||
lessons_learned: Optional[str] = None
|
||||
|
||||
|
||||
# ============================================================================
|
||||
# Templates
|
||||
# ============================================================================
|
||||
|
||||
|
||||
class TemplateCreate(BaseModel):
|
||||
type: str = "art33"
|
||||
title: str
|
||||
content: str
|
||||
|
||||
|
||||
class TemplateUpdate(BaseModel):
|
||||
type: Optional[str] = None
|
||||
title: Optional[str] = None
|
||||
content: Optional[str] = None
|
||||
Reference in New Issue
Block a user