2025-11-27 15:52:40 +01:00
#!/usr/bin/env python3
"""
Comprehensive Dashboard Demo Seed Script
Seeds ALL dashboard scenarios to showcase the complete JTBD - aligned dashboard :
1. Health Status ( green / yellow / red with tri - state checklist )
2. Unified Action Queue ( URGENT / TODAY / WEEK time - based grouping )
3. Execution Progress ( production / deliveries / approvals tracking )
4. Orchestration Summary ( AI automated vs user needed )
5. Stock Receipt Modal scenarios
6. AI Prevented Issues showcase
7. Alert Hub with all alert types
This creates a realistic dashboard state with :
- Actions in all time groups ( urgent < 6 h , today < 24 h , week < 7 d )
- Execution progress with on_track / at_risk states
- AI prevented issues with savings
- Deliveries ready for stock receipt
- Production batches in various states
- Purchase orders needing approval
Usage :
python services / demo_session / scripts / seed_dashboard_comprehensive . py
Environment Variables :
RABBITMQ_URL : RabbitMQ connection URL ( default : amqp : / / guest : guest @localhost : 5672 / )
DEMO_TENANT_ID : Tenant ID to seed data for ( default : demo - tenant - bakery - ia )
"""
import asyncio
import os
import sys
import uuid
from datetime import datetime , timedelta , timezone
from pathlib import Path
from typing import List , Dict , Any
# Add project root to path
sys . path . insert ( 0 , str ( Path ( __file__ ) . parent . parent . parent . parent ) )
2025-12-09 10:21:41 +01:00
from shared . messaging import RabbitMQClient , AlertTypeConstants
2025-11-27 15:52:40 +01:00
import structlog
logger = structlog . get_logger ( )
# Configuration
DEMO_TENANT_ID = os . getenv ( ' DEMO_TENANT_ID ' , ' demo-tenant-bakery-ia ' )
# Build RabbitMQ URL from individual components or use direct URL
RABBITMQ_URL = os . getenv ( ' RABBITMQ_URL ' )
if not RABBITMQ_URL :
rabbitmq_host = os . getenv ( ' RABBITMQ_HOST ' , ' localhost ' )
rabbitmq_port = os . getenv ( ' RABBITMQ_PORT ' , ' 5672 ' )
rabbitmq_user = os . getenv ( ' RABBITMQ_USER ' , ' guest ' )
rabbitmq_password = os . getenv ( ' RABBITMQ_PASSWORD ' , ' guest ' )
RABBITMQ_URL = f ' amqp:// { rabbitmq_user } : { rabbitmq_password } @ { rabbitmq_host } : { rabbitmq_port } / '
# Demo entity IDs
FLOUR_ID = " flour-tipo-55 "
YEAST_ID = " yeast-fresh "
BUTTER_ID = " butter-french "
SUGAR_ID = " sugar-white "
CHOCOLATE_ID = " chocolate-dark "
CROISSANT_PRODUCT = " croissant-mantequilla "
BAGUETTE_PRODUCT = " baguette-traditional "
CHOCOLATE_CAKE_PRODUCT = " chocolate-cake "
SUPPLIER_FLOUR = " supplier-harinera "
SUPPLIER_YEAST = " supplier-levadura "
SUPPLIER_DAIRY = " supplier-lacteos "
def utc_now ( ) - > datetime :
""" Get current UTC time """
return datetime . now ( timezone . utc )
# ============================================================
# 1. UNIFIED ACTION QUEUE - Time-Based Grouping
# ============================================================
def create_urgent_actions ( ) - > List [ Dict [ str , Any ] ] :
"""
Create URGENT actions ( < 6 hours deadline )
These appear in the 🔴 URGENT section
"""
now = utc_now ( )
return [
# PO Approval Escalation - 2h deadline
{
' id ' : str ( uuid . uuid4 ( ) ) ,
' tenant_id ' : DEMO_TENANT_ID ,
' item_type ' : ' alert ' ,
' service ' : ' procurement ' ,
' alert_type ' : AlertTypeConstants . PO_APPROVAL_ESCALATION ,
' title ' : ' URGENT: PO Approval Needed - Yeast Supplier ' ,
' message ' : ' Purchase order #PO-2024-089 has been pending for 72 hours. Production batch depends on this delivery tomorrow morning. ' ,
' alert_metadata ' : {
' po_id ' : ' po-2024-089 ' ,
' po_number ' : ' PO-2024-089 ' ,
' supplier_id ' : SUPPLIER_YEAST ,
' supplier_name ' : ' Levadura Fresh S.L. ' ,
' supplier_phone ' : ' +34-555-1234 ' ,
' total_amount ' : 450.00 ,
' currency ' : ' EUR ' ,
' item_categories ' : [ ' Yeast ' , ' Leavening Agents ' ] ,
' delivery_date ' : ( now + timedelta ( hours = 10 ) ) . isoformat ( ) ,
' batch_id ' : ' batch-croissants-tomorrow ' ,
' batch_name ' : ' Croissants Butter - Morning Batch ' ,
' financial_impact_eur ' : 1200 ,
' orders_affected ' : 8 ,
' escalation ' : {
' aged_hours ' : 72 ,
' priority_boost ' : 20 ,
' reason ' : ' pending_over_72h '
} ,
' urgency_context ' : {
' deadline ' : ( now + timedelta ( hours = 2 ) ) . isoformat ( ) ,
' time_until_consequence_hours ' : 2 ,
' auto_action_countdown_seconds ' : 7200 , # 2h countdown
' can_wait_until_tomorrow ' : False
}
} ,
' timestamp ' : ( now - timedelta ( hours = 72 ) ) . isoformat ( )
} ,
# Delivery Overdue - Needs immediate action
{
' id ' : str ( uuid . uuid4 ( ) ) ,
' tenant_id ' : DEMO_TENANT_ID ,
' item_type ' : ' alert ' ,
' service ' : ' procurement ' ,
' alert_type ' : AlertTypeConstants . DELIVERY_OVERDUE ,
' title ' : ' Delivery Overdue: Flour Delivery ' ,
' message ' : ' Expected delivery from Harinera San José is 4 hours overdue. Contact supplier immediately. ' ,
' alert_metadata ' : {
' po_id ' : ' po-2024-085 ' ,
' po_number ' : ' PO-2024-085 ' ,
' supplier_id ' : SUPPLIER_FLOUR ,
' supplier_name ' : ' Harinera San José ' ,
' supplier_phone ' : ' +34-555-5678 ' ,
' supplier_email ' : ' pedidos@harinerasj.es ' ,
' ingredient_id ' : FLOUR_ID ,
' ingredient_name ' : ' Harina Tipo 55 ' ,
' quantity_expected ' : 500 ,
' unit ' : ' kg ' ,
' expected_delivery ' : ( now - timedelta ( hours = 4 ) ) . isoformat ( ) ,
' hours_overdue ' : 4 ,
' stock_runout_hours ' : 18 ,
' batches_at_risk ' : [ ' batch-baguettes-001 ' , ' batch-croissants-002 ' ] ,
' urgency_context ' : {
' deadline ' : ( now + timedelta ( hours = 3 ) ) . isoformat ( ) ,
' time_until_consequence_hours ' : 3 ,
' can_wait_until_tomorrow ' : False
}
} ,
' timestamp ' : ( now - timedelta ( hours = 4 ) ) . isoformat ( )
} ,
# Production Batch At Risk - 5h window
{
' id ' : str ( uuid . uuid4 ( ) ) ,
' tenant_id ' : DEMO_TENANT_ID ,
' item_type ' : ' alert ' ,
' service ' : ' production ' ,
' alert_type ' : AlertTypeConstants . BATCH_AT_RISK ,
' title ' : ' Batch At Risk: Missing Ingredients ' ,
' message ' : ' Batch " Chocolate Cakes Evening " scheduled in 5 hours but missing 3kg dark chocolate. ' ,
' alert_metadata ' : {
' batch_id ' : ' batch-chocolate-cake-evening ' ,
' batch_name ' : ' Chocolate Cakes Evening ' ,
' product_id ' : CHOCOLATE_CAKE_PRODUCT ,
' product_name ' : ' Chocolate Cake Premium ' ,
' planned_start ' : ( now + timedelta ( hours = 5 ) ) . isoformat ( ) ,
' missing_ingredients ' : [
{ ' ingredient_id ' : CHOCOLATE_ID , ' name ' : ' Dark Chocolate 70 % ' , ' needed ' : 3 , ' available ' : 0 , ' unit ' : ' kg ' }
] ,
' orders_dependent ' : 5 ,
' financial_impact_eur ' : 380 ,
' urgency_context ' : {
' deadline ' : ( now + timedelta ( hours = 5 ) ) . isoformat ( ) ,
' time_until_consequence_hours ' : 5 ,
' can_wait_until_tomorrow ' : False
}
} ,
' timestamp ' : now . isoformat ( )
}
]
def create_today_actions ( ) - > List [ Dict [ str , Any ] ] :
"""
Create TODAY actions ( < 24 hours deadline )
These appear in the 🟡 TODAY section
"""
now = utc_now ( )
return [
# PO Approval Needed - Standard priority
{
' id ' : str ( uuid . uuid4 ( ) ) ,
' tenant_id ' : DEMO_TENANT_ID ,
' item_type ' : ' alert ' ,
' service ' : ' procurement ' ,
' alert_type ' : AlertTypeConstants . PO_APPROVAL_NEEDED ,
' title ' : ' PO Approval: Butter & Dairy Products ' ,
' message ' : ' Purchase order for weekly dairy delivery needs your approval. Delivery scheduled for Friday. ' ,
' alert_metadata ' : {
' po_id ' : ' po-2024-090 ' ,
' po_number ' : ' PO-2024-090 ' ,
' supplier_id ' : SUPPLIER_DAIRY ,
' supplier_name ' : ' Lácteos Frescos Madrid ' ,
' supplier_phone ' : ' +34-555-9012 ' ,
' total_amount ' : 890.50 ,
' currency ' : ' EUR ' ,
' item_categories ' : [ ' Butter ' , ' Cream ' , ' Milk ' ] ,
' delivery_date ' : ( now + timedelta ( days = 2 ) ) . isoformat ( ) ,
' line_items ' : [
{ ' ingredient ' : ' French Butter ' , ' quantity ' : 20 , ' unit ' : ' kg ' , ' price ' : 12.50 } ,
{ ' ingredient ' : ' Heavy Cream ' , ' quantity ' : 15 , ' unit ' : ' L ' , ' price ' : 4.20 } ,
{ ' ingredient ' : ' Whole Milk ' , ' quantity ' : 30 , ' unit ' : ' L ' , ' price ' : 1.80 }
] ,
' urgency_context ' : {
' deadline ' : ( now + timedelta ( hours = 20 ) ) . isoformat ( ) ,
' time_until_consequence_hours ' : 20 ,
' can_wait_until_tomorrow ' : True
}
} ,
' timestamp ' : ( now - timedelta ( hours = 6 ) ) . isoformat ( )
} ,
# Delivery Arriving Soon - Needs preparation
{
' id ' : str ( uuid . uuid4 ( ) ) ,
' tenant_id ' : DEMO_TENANT_ID ,
' item_type ' : ' alert ' ,
' service ' : ' procurement ' ,
' alert_type ' : AlertTypeConstants . DELIVERY_ARRIVING_SOON ,
' title ' : ' Delivery Arriving in 8 Hours: Sugar & Ingredients ' ,
' message ' : ' Prepare for incoming delivery. Stock receipt will be required. ' ,
' alert_metadata ' : {
' po_id ' : ' po-2024-088 ' ,
' po_number ' : ' PO-2024-088 ' ,
' supplier_id ' : ' supplier-ingredients ' ,
' supplier_name ' : ' Ingredientes Premium ' ,
' supplier_phone ' : ' +34-555-3456 ' ,
' delivery_id ' : ' delivery-2024-088 ' ,
' expected_arrival ' : ( now + timedelta ( hours = 8 ) ) . isoformat ( ) ,
' item_count ' : 5 ,
' total_weight_kg ' : 250 ,
' requires_stock_receipt ' : True ,
' warehouse_location ' : ' Warehouse A - Section 3 ' ,
' line_items ' : [
{ ' ingredient ' : ' White Sugar ' , ' quantity ' : 100 , ' unit ' : ' kg ' } ,
{ ' ingredient ' : ' Brown Sugar ' , ' quantity ' : 50 , ' unit ' : ' kg ' } ,
{ ' ingredient ' : ' Vanilla Extract ' , ' quantity ' : 2 , ' unit ' : ' L ' }
] ,
' urgency_context ' : {
' deadline ' : ( now + timedelta ( hours = 8 ) ) . isoformat ( ) ,
' time_until_consequence_hours ' : 8 ,
' can_wait_until_tomorrow ' : False
}
} ,
' timestamp ' : now . isoformat ( )
} ,
# Low Stock Warning - Today action recommended
{
' id ' : str ( uuid . uuid4 ( ) ) ,
' tenant_id ' : DEMO_TENANT_ID ,
' item_type ' : ' alert ' ,
' service ' : ' inventory ' ,
' alert_type ' : AlertTypeConstants . LOW_STOCK_WARNING ,
' title ' : ' Low Stock: Fresh Yeast ' ,
' message ' : ' Fresh yeast stock is low. Current: 2.5kg, Minimum: 10kg. Recommend ordering today. ' ,
' alert_metadata ' : {
' ingredient_id ' : YEAST_ID ,
' ingredient_name ' : ' Fresh Yeast ' ,
' current_stock ' : 2.5 ,
' minimum_stock ' : 10 ,
' maximum_stock ' : 25 ,
' unit ' : ' kg ' ,
' daily_consumption_avg ' : 3.5 ,
' days_remaining ' : 0.7 ,
' supplier_name ' : ' Levadura Fresh S.L. ' ,
' last_order_date ' : ( now - timedelta ( days = 8 ) ) . isoformat ( ) ,
' recommended_order_quantity ' : 20 ,
' urgency_context ' : {
' stockout_risk_hours ' : 17 ,
' can_wait_until_tomorrow ' : True
}
} ,
' timestamp ' : ( now - timedelta ( hours = 3 ) ) . isoformat ( )
}
]
def create_week_actions ( ) - > List [ Dict [ str , Any ] ] :
"""
Create WEEK actions ( < 7 days deadline )
These appear in the 🟢 THIS WEEK section
"""
now = utc_now ( )
return [
# Demand Surge Predicted - Plan ahead
{
' id ' : str ( uuid . uuid4 ( ) ) ,
' tenant_id ' : DEMO_TENANT_ID ,
' item_type ' : ' alert ' ,
' service ' : ' forecasting ' ,
' alert_type ' : AlertTypeConstants . DEMAND_SURGE_PREDICTED ,
' title ' : ' Weekend Demand Surge Predicted ' ,
' message ' : ' Sunny weather forecast for Saturday-Sunday. Expect 25 % d emand increase for croissants and pastries. ' ,
' alert_metadata ' : {
' forecast_type ' : ' weather_based ' ,
' weather_condition ' : ' sunny ' ,
' days_affected ' : [
( now + timedelta ( days = 3 ) ) . date ( ) . isoformat ( ) ,
( now + timedelta ( days = 4 ) ) . date ( ) . isoformat ( )
] ,
' expected_demand_increase_pct ' : 25 ,
' products_affected ' : [
{ ' product_id ' : CROISSANT_PRODUCT , ' product_name ' : ' Croissant Butter ' , ' increase_pct ' : 30 } ,
{ ' product_id ' : BAGUETTE_PRODUCT , ' product_name ' : ' Baguette Traditional ' , ' increase_pct ' : 20 }
] ,
' confidence ' : 0.85 ,
' recommended_action ' : ' Increase production by 25 % a nd ensure adequate stock ' ,
' estimated_revenue_opportunity_eur ' : 450 ,
' urgency_context ' : {
' deadline ' : ( now + timedelta ( days = 2 ) ) . isoformat ( ) ,
' can_wait_until_tomorrow ' : True
}
} ,
' timestamp ' : now . isoformat ( )
} ,
# Stock Receipt Incomplete - Can wait
{
' id ' : str ( uuid . uuid4 ( ) ) ,
' tenant_id ' : DEMO_TENANT_ID ,
' item_type ' : ' alert ' ,
' service ' : ' inventory ' ,
' alert_type ' : AlertTypeConstants . STOCK_RECEIPT_INCOMPLETE ,
' title ' : ' Stock Receipt Pending: Flour Delivery ' ,
' message ' : ' Delivery received 2 days ago but stock receipt not completed. Please confirm lot details and expiration dates. ' ,
' alert_metadata ' : {
' receipt_id ' : ' receipt-2024-012 ' ,
' po_id ' : ' po-2024-083 ' ,
' po_number ' : ' PO-2024-083 ' ,
' supplier_name ' : ' Harinera San José ' ,
' delivery_date ' : ( now - timedelta ( days = 2 ) ) . isoformat ( ) ,
' days_since_delivery ' : 2 ,
' line_items_pending ' : 3 ,
' total_items ' : 3 ,
' requires_lot_tracking ' : True ,
' requires_expiration ' : True ,
' urgency_context ' : {
' deadline ' : ( now + timedelta ( days = 5 ) ) . isoformat ( ) ,
' can_wait_until_tomorrow ' : True
}
} ,
' timestamp ' : ( now - timedelta ( days = 2 ) ) . isoformat ( )
}
]
# ============================================================
# 2. AI PREVENTED ISSUES - Showcase AI Value
# ============================================================
def create_prevented_issues ( ) - > List [ Dict [ str , Any ] ] :
"""
Create alerts showing AI prevented issues ( type_class : prevented_issue )
These show in the Health Status Card and Prevented Issues Card
"""
now = utc_now ( )
return [
# Prevented Stockout - PO created automatically
{
' id ' : str ( uuid . uuid4 ( ) ) ,
' tenant_id ' : DEMO_TENANT_ID ,
' item_type ' : ' alert ' ,
' service ' : ' inventory ' ,
' alert_type ' : ' ai_prevented_stockout ' ,
' title ' : ' ✅ AI Prevented Stockout: Flour ' ,
' message ' : ' AI detected upcoming stockout and created purchase order automatically. Delivery arriving Friday. ' ,
' alert_metadata ' : {
' type_class ' : ' prevented_issue ' ,
' priority_level ' : ' info ' ,
' ingredient_id ' : FLOUR_ID ,
' ingredient_name ' : ' Harina Tipo 55 ' ,
' prevented_risk ' : ' stockout ' ,
' ai_action_taken ' : ' purchase_order_created ' ,
' po_id ' : ' po-2024-091 ' ,
' po_number ' : ' PO-2024-091 ' ,
' quantity_ordered ' : 500 ,
' unit ' : ' kg ' ,
' supplier_name ' : ' Harinera San José ' ,
' delivery_date ' : ( now + timedelta ( days = 2 ) ) . isoformat ( ) ,
' estimated_savings_eur ' : 250 ,
' orchestrator_context ' : {
' already_addressed ' : True ,
' action_type ' : ' purchase_order ' ,
' action_id ' : ' po-2024-091 ' ,
' action_status ' : ' pending_approval ' ,
' reasoning ' : ' Detected stock would run out in 1.8 days based on historical consumption patterns '
} ,
' business_impact ' : {
' prevented_stockout_hours ' : 43 ,
' affected_orders_prevented ' : 12 ,
' production_batches_secured ' : 4
} ,
' ai_reasoning_summary ' : ' Analyzed consumption patterns and detected stockout in 43 hours. Created PO for 500kg to arrive Friday, preventing disruption to 4 production batches. '
} ,
' timestamp ' : ( now - timedelta ( hours = 12 ) ) . isoformat ( )
} ,
# Prevented Waste - Production adjusted
{
' id ' : str ( uuid . uuid4 ( ) ) ,
' tenant_id ' : DEMO_TENANT_ID ,
' item_type ' : ' alert ' ,
' service ' : ' production ' ,
' alert_type ' : ' ai_prevented_waste ' ,
' title ' : ' ✅ AI Prevented Waste: Reduced Monday Production ' ,
' message ' : ' AI detected post-weekend demand pattern and reduced Monday production by 15 % , preventing €120 in waste. ' ,
' alert_metadata ' : {
' type_class ' : ' prevented_issue ' ,
' priority_level ' : ' info ' ,
' product_id ' : BAGUETTE_PRODUCT ,
' product_name ' : ' Baguette Traditional ' ,
' prevented_risk ' : ' waste ' ,
' ai_action_taken ' : ' production_adjusted ' ,
' reduction_pct ' : 15 ,
' units_reduced ' : 45 ,
' day_of_week ' : ' Monday ' ,
' historical_pattern ' : ' post_weekend_low_demand ' ,
' estimated_savings_eur ' : 120 ,
' orchestrator_context ' : {
' already_addressed ' : True ,
' action_type ' : ' production_batch ' ,
' action_id ' : ' batch-baguettes-monday-adjusted ' ,
' action_status ' : ' completed ' ,
' reasoning ' : ' Historical data shows 18 % d emand drop on Mondays following sunny weekends '
} ,
' business_impact ' : {
' waste_prevented_kg ' : 12 ,
' waste_reduction_pct ' : 15
} ,
' ai_reasoning_summary ' : ' Detected consistent Monday demand drop (18 % a vg) in post-weekend data. Adjusted production to prevent overproduction and waste. '
} ,
' timestamp ' : ( now - timedelta ( days = 1 ) ) . isoformat ( )
} ,
# Prevented Production Delay - Batch rescheduled
{
' id ' : str ( uuid . uuid4 ( ) ) ,
' tenant_id ' : DEMO_TENANT_ID ,
' item_type ' : ' alert ' ,
' service ' : ' production ' ,
' alert_type ' : ' ai_prevented_delay ' ,
' title ' : ' ✅ AI Prevented Delay: Rescheduled Conflicting Batches ' ,
' message ' : ' AI detected oven capacity conflict and rescheduled batches to optimize throughput. ' ,
' alert_metadata ' : {
' type_class ' : ' prevented_issue ' ,
' priority_level ' : ' info ' ,
' prevented_risk ' : ' production_delay ' ,
' ai_action_taken ' : ' batch_rescheduled ' ,
' batches_affected ' : 3 ,
' equipment_id ' : ' oven-001 ' ,
' equipment_name ' : ' Industrial Oven #1 ' ,
' capacity_utilization_before ' : 110 ,
' capacity_utilization_after ' : 95 ,
' time_saved_minutes ' : 45 ,
' estimated_savings_eur ' : 85 ,
' orchestrator_context ' : {
' already_addressed ' : True ,
' action_type ' : ' batch_optimization ' ,
' action_status ' : ' completed ' ,
' reasoning ' : ' Detected overlapping batch schedules would exceed oven capacity by 10 % '
} ,
' business_impact ' : {
' orders_on_time ' : 8 ,
' customer_satisfaction_impact ' : ' high '
} ,
' ai_reasoning_summary ' : ' Identified capacity conflict in oven schedule. Rescheduled 3 batches to maintain on-time delivery for 8 orders. '
} ,
' timestamp ' : ( now - timedelta ( hours = 18 ) ) . isoformat ( )
}
]
# ============================================================
# 3. EXECUTION PROGRESS - Production/Deliveries/Approvals
# ============================================================
def create_production_batches ( ) - > List [ Dict [ str , Any ] ] :
"""
Create production batch data for execution progress tracking
"""
now = utc_now ( )
return [
# Completed batch
{
' batch_id ' : ' batch-morning-croissants ' ,
' product_name ' : ' Croissant Butter ' ,
' quantity ' : 120 ,
' status ' : ' completed ' ,
' planned_start ' : ( now - timedelta ( hours = 4 ) ) . isoformat ( ) ,
' actual_start ' : ( now - timedelta ( hours = 4 , minutes = 5 ) ) . isoformat ( ) ,
' actual_end ' : ( now - timedelta ( hours = 1 ) ) . isoformat ( )
} ,
# In progress batch
{
' batch_id ' : ' batch-baguettes-lunch ' ,
' product_name ' : ' Baguette Traditional ' ,
' quantity ' : 80 ,
' status ' : ' in_progress ' ,
' planned_start ' : ( now - timedelta ( hours = 2 ) ) . isoformat ( ) ,
' actual_start ' : ( now - timedelta ( hours = 2 , minutes = 10 ) ) . isoformat ( ) ,
' progress_pct ' : 65
} ,
# Pending batches
{
' batch_id ' : ' batch-afternoon-pastries ' ,
' product_name ' : ' Mixed Pastries ' ,
' quantity ' : 50 ,
' status ' : ' pending ' ,
' planned_start ' : ( now + timedelta ( hours = 1 ) ) . isoformat ( )
} ,
{
' batch_id ' : ' batch-evening-bread ' ,
' product_name ' : ' Artisan Bread Assortment ' ,
' quantity ' : 40 ,
' status ' : ' pending ' ,
' planned_start ' : ( now + timedelta ( hours = 3 ) ) . isoformat ( )
}
]
# ============================================================
# MAIN SEEDING FUNCTION
# ============================================================
async def seed_comprehensive_dashboard ( ) :
"""
Seed comprehensive dashboard demo data
Creates realistic dashboard state showcasing :
- All time - based action groups ( urgent / today / week )
- AI prevented issues with savings
- Execution progress tracking
- Stock receipt scenarios
- Full alert type coverage
"""
print ( " \n " + " = " * 80 )
print ( " 🚀 SEEDING COMPREHENSIVE DASHBOARD DEMO DATA " )
print ( " = " * 80 + " \n " )
print ( f " 📋 Configuration: " )
print ( f " Tenant ID: { DEMO_TENANT_ID } " )
print ( f " RabbitMQ: { RABBITMQ_URL } " )
print ( )
try :
# Initialize RabbitMQ
logger . info ( " Connecting to RabbitMQ " , url = RABBITMQ_URL )
rabbitmq_client = RabbitMQClient ( RABBITMQ_URL , ' dashboard-demo-seeder ' )
await rabbitmq_client . connect ( )
# Collect all alerts
all_alerts = [ ]
all_alerts . extend ( create_urgent_actions ( ) )
all_alerts . extend ( create_today_actions ( ) )
all_alerts . extend ( create_week_actions ( ) )
all_alerts . extend ( create_prevented_issues ( ) )
print ( f " 📊 Dashboard Scenarios to Seed: " )
print ( f " 🔴 URGENT actions (<6h): { len ( create_urgent_actions ( ) ) } " )
print ( f " 🟡 TODAY actions (<24h): { len ( create_today_actions ( ) ) } " )
print ( f " 🟢 WEEK actions (<7d): { len ( create_week_actions ( ) ) } " )
print ( f " ✅ AI Prevented Issues: { len ( create_prevented_issues ( ) ) } " )
print ( f " 📦 Total Alerts: { len ( all_alerts ) } " )
print ( )
# Publish alerts
print ( " 📤 Publishing Alerts: " )
print ( " - " * 80 )
success_count = 0
for i , alert in enumerate ( all_alerts , 1 ) :
routing_key = f " { alert [ ' item_type ' ] } . { alert [ ' service ' ] } . { alert [ ' alert_type ' ] } "
success = await rabbitmq_client . publish_event (
exchange_name = ' alerts.exchange ' ,
routing_key = routing_key ,
event_data = alert ,
persistent = True
)
if success :
success_count + = 1
status = " ✅ "
else :
status = " ❌ "
logger . warning ( " Failed to publish alert " , alert_id = alert [ ' id ' ] )
# Determine time group emoji
if ' escalation ' in alert . get ( ' alert_metadata ' , { } ) or \
alert . get ( ' alert_metadata ' , { } ) . get ( ' urgency_context ' , { } ) . get ( ' time_until_consequence_hours ' , 999 ) < 6 :
group = " 🔴 URGENT "
elif alert . get ( ' alert_metadata ' , { } ) . get ( ' urgency_context ' , { } ) . get ( ' time_until_consequence_hours ' , 999 ) < 24 :
group = " 🟡 TODAY "
elif alert . get ( ' alert_metadata ' , { } ) . get ( ' type_class ' ) == ' prevented_issue ' :
group = " ✅ PREVENTED "
else :
group = " 🟢 WEEK "
print ( f " { i : 2d } . { status } [ { group } ] { alert [ ' title ' ] } " )
print ( )
print ( f " ✅ Published { success_count } / { len ( all_alerts ) } alerts successfully " )
print ( )
await rabbitmq_client . disconnect ( )
# Print dashboard preview
print ( " = " * 80 )
print ( " 📊 EXPECTED DASHBOARD STATE " )
print ( " = " * 80 )
print ( )
print ( " 🏥 HEALTH STATUS: " )
print ( " Status: YELLOW (actions needed) " )
print ( " Checklist: " )
print ( " ⚡ AI Handled: 3 issues prevented (€455 saved) " )
print ( " ⚠️ Needs You: 3 urgent actions, 3 today actions " )
print ( )
print ( " 📋 ACTION QUEUE: " )
print ( " 🔴 URGENT (<6h): 3 actions " )
print ( " - PO Approval Escalation (2h deadline) " )
print ( " - Delivery Overdue (4h late) " )
print ( " - Batch At Risk (5h until start) " )
print ( )
print ( " 🟡 TODAY (<24h): 3 actions " )
print ( " - PO Approval: Dairy Products " )
print ( " - Delivery Arriving Soon (8h) " )
print ( " - Low Stock: Fresh Yeast " )
print ( )
print ( " 🟢 THIS WEEK (<7d): 2 actions " )
print ( " - Weekend Demand Surge " )
print ( " - Stock Receipt Incomplete " )
print ( )
print ( " 📊 EXECUTION PROGRESS: " )
print ( " Production: 2/4 batches (on_track) " )
print ( " ✅ Completed: 1 " )
print ( " 🔄 In Progress: 1 " )
print ( " ⏳ Pending: 2 " )
print ( )
print ( " Deliveries: Status depends on real PO data " )
print ( " Approvals: 2 pending " )
print ( )
print ( " ✅ AI PREVENTED ISSUES: " )
print ( " Total Prevented: 3 issues " )
print ( " Total Savings: €455 " )
print ( " Details: " )
print ( " - Prevented stockout (€250 saved) " )
print ( " - Prevented waste (€120 saved) " )
print ( " - Prevented delay (€85 saved) " )
print ( )
print ( " = " * 80 )
print ( " 🎉 DASHBOARD DEMO SEEDED SUCCESSFULLY! " )
print ( " = " * 80 )
print ( )
print ( " Next Steps: " )
print ( " 1. Verify alert-processor is running: " )
print ( " kubectl get pods -l app.kubernetes.io/name=alert-processor-service " )
print ( )
print ( " 2. Check alert enrichment logs: " )
print ( " kubectl logs -f deployment/alert-processor-service | grep ' enriched_alert ' " )
print ( )
print ( " 3. View dashboard: " )
print ( " http://localhost:3000/dashboard " )
print ( )
print ( " 4. Test smart actions: " )
print ( " - Approve/Reject PO from action queue " )
print ( " - Mark delivery as received (opens stock receipt modal) " )
print ( " - Call supplier (initiates phone call) " )
print ( " - Adjust production (navigates to production page) " )
print ( )
except Exception as e :
logger . error ( " Failed to seed dashboard demo " , error = str ( e ) , exc_info = True )
print ( f " \n ❌ ERROR: { str ( e ) } " )
print ( " \n Troubleshooting: " )
print ( " • Verify RabbitMQ is running: kubectl get pods | grep rabbitmq " )
print ( " • Check RABBITMQ_URL environment variable " )
print ( " • Ensure alerts.exchange exists " )
print ( " • Check alert-processor service logs for errors " )
raise
if __name__ == " __main__ " :
# Load environment variables
from dotenv import load_dotenv
load_dotenv ( )
# Run seeder
asyncio . run ( seed_comprehensive_dashboard ( ) )