""" Minimal event schemas for services to emit events. Services send minimal event data with only event_type and metadata. All enrichment, i18n generation, and priority calculation happens in the alert_processor service. """ from pydantic import BaseModel, Field from typing import Dict, Any, Literal, Optional from datetime import datetime from uuid import UUID class MinimalEvent(BaseModel): """ Minimal event structure sent by services. Services only need to provide: - tenant_id: Who this event belongs to - event_class: alert, notification, or recommendation - event_domain: Business domain (inventory, production, supply_chain, etc.) - event_type: Specific event identifier (critical_stock_shortage, production_delay, etc.) - service: Source service name - metadata: Dictionary with event-specific data The alert_processor service enriches this with: - i18n keys and parameters - Priority score and level - Orchestrator context (AI actions) - Business impact analysis - Urgency assessment - User agency determination - Smart actions """ tenant_id: str = Field(..., description="Tenant UUID as string") event_class: Literal["alert", "notification", "recommendation"] = Field( ..., description="Event classification - alert requires action, notification is FYI, recommendation is suggestion" ) event_domain: str = Field( ..., description="Business domain: inventory, production, supply_chain, demand, operations, distribution" ) event_type: str = Field( ..., description="Specific event type identifier, e.g., critical_stock_shortage, production_delay, po_approval_needed" ) service: str = Field(..., description="Source service name, e.g., inventory, production, procurement") metadata: Dict[str, Any] = Field( default_factory=dict, description="Event-specific data - structure varies by event_type" ) timestamp: Optional[datetime] = Field( default=None, description="Event timestamp, set automatically if not provided" ) class Config: from_attributes = True json_schema_extra = { "examples": [ { "tenant_id": "550e8400-e29b-41d4-a716-446655440000", "event_class": "alert", "event_domain": "inventory", "event_type": "critical_stock_shortage", "service": "inventory", "metadata": { "ingredient_id": "123e4567-e89b-12d3-a456-426614174000", "ingredient_name": "Flour", "current_stock": 5.2, "required_stock": 10.0, "shortage_amount": 4.8, "supplier_name": "Flour Supplier Co.", "lead_time_days": 3, "po_id": "PO-12345", "po_amount": 2500.00, "po_status": "pending_approval", "delivery_date": "2025-12-10" } }, { "tenant_id": "550e8400-e29b-41d4-a716-446655440000", "event_class": "alert", "event_domain": "production", "event_type": "production_delay", "service": "production", "metadata": { "batch_id": "987fbc97-4bed-5078-9f07-9141ba07c9f3", "product_name": "Croissant", "batch_number": "B-2025-001", "delay_minutes": 45, "affected_orders": 3, "customer_names": ["Customer A", "Customer B"] } }, { "tenant_id": "550e8400-e29b-41d4-a716-446655440000", "event_class": "notification", "event_domain": "supply_chain", "event_type": "po_approved", "service": "procurement", "metadata": { "po_id": "PO-12345", "po_number": "PO-2025-001", "supplier_name": "Flour Supplier Co.", "total_amount": 2500.00, "currency": "EUR", "approved_at": "2025-12-05T10:30:00Z", "approved_by": "user@example.com" } } ] } # Event Domain Constants class EventDomain: """Standard event domains""" INVENTORY = "inventory" PRODUCTION = "production" SUPPLY_CHAIN = "supply_chain" DEMAND = "demand" OPERATIONS = "operations" DISTRIBUTION = "distribution" FINANCE = "finance" # Event Class Constants class EventClass: """Event classifications""" ALERT = "alert" # Requires user decision/action NOTIFICATION = "notification" # Informational, no action needed RECOMMENDATION = "recommendation" # Optimization suggestion # Severity Levels (for routing) class Severity: """Alert severity levels for routing""" URGENT = "urgent" # Immediate attention required HIGH = "high" # Important, address soon MEDIUM = "medium" # Standard priority LOW = "low" # Minor, can wait INFO = "info" # Informational only