Files
breakpilot-compliance/backend-compliance/compliance/schemas/notfallplan.py
Sharang Parnerkar 1a2ae896fb 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>
2026-04-09 20:10:43 +02:00

147 lines
4.1 KiB
Python

"""
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