Fix and UI imporvements

This commit is contained in:
Urtzi Alfaro
2025-12-09 10:21:41 +01:00
parent 667e6e0404
commit 508f4569b9
22 changed files with 833 additions and 953 deletions

191
shared/messaging/schemas.py Normal file
View File

@@ -0,0 +1,191 @@
"""
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.
This is the unified messaging layer - the single source of truth for
event schemas used in the messaging system.
"""
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"
}
}
]
}
# ============================================================
# 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
# ============================================================
# 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"