2025-12-05 20:07:01 +01:00
|
|
|
"""
|
|
|
|
|
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.
|
2025-12-09 10:21:41 +01:00
|
|
|
|
|
|
|
|
This is the unified messaging layer - the single source of truth for
|
|
|
|
|
event schemas used in the messaging system.
|
2025-12-05 20:07:01 +01:00
|
|
|
"""
|
|
|
|
|
|
|
|
|
|
from pydantic import BaseModel, Field
|
|
|
|
|
from typing import Dict, Any, Literal, Optional
|
|
|
|
|
from datetime import datetime
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
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"
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
]
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
2025-12-09 10:21:41 +01:00
|
|
|
# ============================================================
|
2025-12-05 20:07:01 +01:00
|
|
|
# Event Domain Constants
|
2025-12-09 10:21:41 +01:00
|
|
|
# ============================================================
|
|
|
|
|
|
2025-12-05 20:07:01 +01:00
|
|
|
class EventDomain:
|
|
|
|
|
"""Standard event domains"""
|
|
|
|
|
INVENTORY = "inventory"
|
|
|
|
|
PRODUCTION = "production"
|
|
|
|
|
SUPPLY_CHAIN = "supply_chain"
|
|
|
|
|
DEMAND = "demand"
|
|
|
|
|
OPERATIONS = "operations"
|
|
|
|
|
DISTRIBUTION = "distribution"
|
|
|
|
|
FINANCE = "finance"
|
|
|
|
|
|
|
|
|
|
|
2025-12-09 10:21:41 +01:00
|
|
|
# ============================================================
|
2025-12-05 20:07:01 +01:00
|
|
|
# Event Class Constants
|
2025-12-09 10:21:41 +01:00
|
|
|
# ============================================================
|
|
|
|
|
|
2025-12-05 20:07:01 +01:00
|
|
|
class EventClass:
|
|
|
|
|
"""Event classifications"""
|
|
|
|
|
ALERT = "alert" # Requires user decision/action
|
|
|
|
|
NOTIFICATION = "notification" # Informational, no action needed
|
|
|
|
|
RECOMMENDATION = "recommendation" # Optimization suggestion
|
|
|
|
|
|
|
|
|
|
|
2025-12-09 10:21:41 +01:00
|
|
|
# ============================================================
|
2025-12-05 20:07:01 +01:00
|
|
|
# Severity Levels (for routing)
|
2025-12-09 10:21:41 +01:00
|
|
|
# ============================================================
|
|
|
|
|
|
2025-12-05 20:07:01 +01:00
|
|
|
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
|
2025-12-09 10:21:41 +01:00
|
|
|
|
|
|
|
|
|
|
|
|
|
# ============================================================
|
|
|
|
|
# Alert Type Constants (for demo/testing purposes)
|
|
|
|
|
# ============================================================
|
|
|
|
|
|
|
|
|
|
class AlertTypeConstants:
|
|
|
|
|
"""Standard alert type string constants"""
|
|
|
|
|
|
|
|
|
|
# Inventory alerts
|
|
|
|
|
LOW_STOCK_WARNING = "low_stock_warning"
|
|
|
|
|
CRITICAL_STOCK_SHORTAGE = "critical_stock_shortage"
|
|
|
|
|
EXPIRING_SOON = "expiring_soon"
|
|
|
|
|
EXPIRED_STOCK = "expired_stock"
|
|
|
|
|
|
|
|
|
|
# Production alerts
|
|
|
|
|
PRODUCTION_DELAY = "production_delay"
|
|
|
|
|
PRODUCTION_STALLED = "production_stalled"
|
|
|
|
|
BATCH_AT_RISK = "batch_at_risk"
|
|
|
|
|
PRODUCTION_BATCH_START = "production_batch_start"
|
|
|
|
|
|
|
|
|
|
# Purchase Order alerts
|
|
|
|
|
PO_APPROVAL_NEEDED = "po_approval_needed"
|
|
|
|
|
PO_APPROVAL_ESCALATION = "po_approval_escalation"
|
|
|
|
|
|
|
|
|
|
# Delivery lifecycle alerts
|
|
|
|
|
DELIVERY_SCHEDULED = "delivery_scheduled"
|
|
|
|
|
DELIVERY_ARRIVING_SOON = "delivery_arriving_soon"
|
|
|
|
|
DELIVERY_OVERDUE = "delivery_overdue"
|
|
|
|
|
STOCK_RECEIPT_INCOMPLETE = "stock_receipt_incomplete"
|
|
|
|
|
|
|
|
|
|
# Forecasting alerts
|
|
|
|
|
DEMAND_SURGE_PREDICTED = "demand_surge_predicted"
|
|
|
|
|
DEMAND_DROP_PREDICTED = "demand_drop_predicted"
|