cuatrolabs-spa-ms / DASHBOARD_INTEGRATION_EXAMPLE.md
MukeshKapoor25's picture
feat(dashboard): implement 3-tier caching architecture for mobile performance
fd7ec1d

Dashboard Integration Examples

Quick Integration Guide

This document shows exactly how to integrate dashboard updates in your existing code.

1. Order Service Integration

Update app/orders/services/service.py

# Add import at the top
from app.dashboard.utils import update_on_order_created, update_on_order_status_changed

# In create_order method, after order is created:
@staticmethod
async def create_order(partner_id: str, order_data: OrderCreateRequest):
    try:
        # ... existing order creation code ...
        
        # After successful order creation
        order = SpaPartnerOrder(...)
        session.add(order)
        await session.commit()
        
        # βœ… ADD THIS: Update dashboard
        await update_on_order_created(partner_id)
        
        return {
            "success": True,
            "message": "Order created successfully",
            "order": OrderResponse.model_validate(order_with_items)
        }
    except Exception as e:
        logger.error("Error creating order", exc_info=e)
        return {"success": False, "message": str(e)}

Update Order Status

# In update_order_status method:
@staticmethod
async def update_order_status(order_id: UUID, new_status: str):
    try:
        # ... existing status update code ...
        
        order.order_status = new_status
        await session.commit()
        
        # βœ… ADD THIS: Update dashboard
        await update_on_order_status_changed(order.partner_id)
        
        return {"success": True, "order": order}
    except Exception as e:
        logger.error("Error updating order status", exc_info=e)
        return {"success": False}

2. Wallet Service Integration

Update app/wallet/services/service.py

# Add import at the top
from app.dashboard.utils import update_on_wallet_transaction, update_on_payment_received

# In create_transaction method:
@staticmethod
async def create_transaction(
    partner_id: str,
    amount: Decimal,
    transaction_type: str,
    reference_type: Optional[str] = None,
    reference_id: Optional[str] = None,
    description: Optional[str] = None
):
    try:
        # ... existing transaction creation code ...
        
        transaction = SpaWalletTransaction(...)
        session.add(transaction)
        await session.commit()
        
        # βœ… ADD THIS: Update dashboard
        await update_on_wallet_transaction(partner_id)
        
        return {"success": True, "transaction": transaction}
    except Exception as e:
        logger.error("Error creating transaction", exc_info=e)
        return {"success": False}

Payment Processing

# In process_payment method:
@staticmethod
async def process_payment(order_id: UUID, payment_data: dict):
    try:
        # ... existing payment processing code ...
        
        # Update order payment status
        order.payment_status = "paid"
        await session.commit()
        
        # βœ… ADD THIS: Update dashboard
        await update_on_payment_received(order.partner_id)
        
        return {"success": True, "payment": payment}
    except Exception as e:
        logger.error("Error processing payment", exc_info=e)
        return {"success": False}

3. Leave/Booking Service Integration

Update app/leave/services/service.py

# Add import at the top
from app.dashboard.utils import update_dashboard_on_transaction

# In create_leave method:
@staticmethod
async def create_leave(partner_id: str, leave_data: dict):
    try:
        # ... existing leave creation code ...
        
        leave = SpaPartnerLeave(...)
        session.add(leave)
        await session.commit()
        
        # βœ… ADD THIS: Update dashboard
        await update_dashboard_on_transaction(partner_id, "booking_created")
        
        return {"success": True, "leave": leave}
    except Exception as e:
        logger.error("Error creating leave", exc_info=e)
        return {"success": False}

Update Leave Status

# In update_leave_status method:
@staticmethod
async def update_leave_status(leave_id: UUID, new_status: str):
    try:
        # ... existing status update code ...
        
        leave.status = new_status
        await session.commit()
        
        # βœ… ADD THIS: Update dashboard
        await update_dashboard_on_transaction(leave.partner_id, "booking_updated")
        
        return {"success": True, "leave": leave}
    except Exception as e:
        logger.error("Error updating leave status", exc_info=e)
        return {"success": False}

4. Rating Service Integration (Future)

When rating tables are created:

# In app/ratings/services/service.py

from app.dashboard.utils import update_on_rating_submitted

@staticmethod
async def submit_rating(partner_id: str, rating_data: dict):
    try:
        # ... rating creation code ...
        
        rating = PartnerRating(...)
        session.add(rating)
        await session.commit()
        
        # βœ… ADD THIS: Update dashboard
        await update_on_rating_submitted(partner_id)
        
        return {"success": True, "rating": rating}
    except Exception as e:
        logger.error("Error submitting rating", exc_info=e)
        return {"success": False}

5. Background Job for Bulk Refresh

Create app/jobs/dashboard_refresh.py

"""
Background job to refresh stale dashboard summaries.
Run this periodically (e.g., every 10 minutes).
"""
import asyncio
from insightfy_utils.logging import get_logger
from app.dashboard.services.mongo_persistence import dashboard_mongo
from app.dashboard.utils import bulk_update_dashboards

logger = get_logger(__name__)


async def refresh_stale_dashboards():
    """Refresh dashboards that haven't been updated in 10 minutes"""
    try:
        # Get stale partner IDs
        stale_ids = await dashboard_mongo.get_stale_summaries(minutes=10)
        
        if not stale_ids:
            logger.info("No stale dashboards found")
            return
        
        logger.info(f"Found {len(stale_ids)} stale dashboards, refreshing...")
        
        # Bulk update
        results = await bulk_update_dashboards(stale_ids, "scheduled_refresh")
        
        logger.info(
            "Dashboard refresh completed",
            extra={
                "total": results["total"],
                "success": results["success"],
                "failed": results["failed"]
            }
        )
        
    except Exception as e:
        logger.error("Error in dashboard refresh job", exc_info=e)


if __name__ == "__main__":
    # For testing
    asyncio.run(refresh_stale_dashboards())

Schedule with Cron

# Add to crontab
# Refresh stale dashboards every 10 minutes
*/10 * * * * cd /path/to/app && python -m app.jobs.dashboard_refresh

Or use APScheduler

# In app/main.py

from apscheduler.schedulers.asyncio import AsyncIOScheduler
from app.jobs.dashboard_refresh import refresh_stale_dashboards

scheduler = AsyncIOScheduler()

@app.on_event("startup")
async def startup_event():
    # ... existing startup code ...
    
    # Schedule dashboard refresh every 10 minutes
    scheduler.add_job(
        refresh_stale_dashboards,
        'interval',
        minutes=10,
        id='dashboard_refresh'
    )
    scheduler.start()
    
    logger.info("Dashboard refresh job scheduled")

@app.on_event("shutdown")
async def shutdown_event():
    # ... existing shutdown code ...
    
    scheduler.shutdown()

6. Testing Integration

Test Dashboard Update

# test_dashboard_integration.py

import asyncio
from app.dashboard.utils import update_on_order_created
from app.dashboard.services.mongo_persistence import dashboard_mongo
from app.sql import connect_to_database
from app.nosql import connect_to_mongo

async def test_integration():
    # Initialize connections
    await connect_to_database()
    await connect_to_mongo()
    
    test_partner_id = "PARTNER001"
    
    # Simulate order creation
    print(f"Updating dashboard for {test_partner_id}...")
    success = await update_on_order_created(test_partner_id)
    
    if success:
        print("βœ… Dashboard updated successfully")
        
        # Verify in MongoDB
        doc = await dashboard_mongo.get_summary(test_partner_id)
        if doc:
            print(f"βœ… Found in MongoDB: {doc['summary']['bookings']['total_bookings']} bookings")
        else:
            print("❌ Not found in MongoDB")
    else:
        print("❌ Dashboard update failed")

if __name__ == "__main__":
    asyncio.run(test_integration())

7. Error Handling Best Practices

Always Wrap Dashboard Updates

# βœ… Good - Dashboard update failure doesn't break main operation
async def create_order(partner_id: str, order_data: dict):
    try:
        # Create order
        order = await _create_order_logic(partner_id, order_data)
        
        # Update dashboard (non-blocking)
        try:
            await update_on_order_created(partner_id)
        except Exception as e:
            logger.error("Dashboard update failed", exc_info=e)
            # Continue - order was created successfully
        
        return {"success": True, "order": order}
    except Exception as e:
        logger.error("Order creation failed", exc_info=e)
        return {"success": False, "message": str(e)}

Use Fire-and-Forget for Non-Critical Updates

# For non-critical updates, use background task
from fastapi import BackgroundTasks

@router.post("/orders")
async def create_order(
    order_data: OrderCreateRequest,
    background_tasks: BackgroundTasks,
    token_data: dict = Depends(verify_token)
):
    partner_id = token_data["partner_id"]
    
    # Create order
    result = await order_service.create_order(partner_id, order_data)
    
    # Update dashboard in background
    background_tasks.add_task(update_on_order_created, partner_id)
    
    return result

8. Monitoring Integration

Add Metrics

# In app/dashboard/utils.py

from prometheus_client import Counter, Histogram

dashboard_updates = Counter(
    'dashboard_updates_total',
    'Total dashboard updates',
    ['transaction_type', 'status']
)

dashboard_update_duration = Histogram(
    'dashboard_update_duration_seconds',
    'Dashboard update duration',
    ['transaction_type']
)

async def update_dashboard_on_transaction(
    partner_id: str,
    transaction_type: str = "transaction"
) -> bool:
    with dashboard_update_duration.labels(transaction_type).time():
        try:
            # ... existing code ...
            
            dashboard_updates.labels(
                transaction_type=transaction_type,
                status='success'
            ).inc()
            
            return True
        except Exception as e:
            dashboard_updates.labels(
                transaction_type=transaction_type,
                status='failed'
            ).inc()
            raise

Summary

Integration Checklist

  • Add dashboard update to order creation
  • Add dashboard update to order status changes
  • Add dashboard update to wallet transactions
  • Add dashboard update to payment processing
  • Add dashboard update to booking/leave operations
  • Set up background job for stale refresh
  • Add error handling around updates
  • Add monitoring/metrics
  • Test integration with sample data
  • Deploy and monitor

Key Points

  1. Always call update functions after transactions
  2. Use specific functions (update_on_order_created, etc.)
  3. Handle errors gracefully - don't break main operations
  4. Use background tasks for non-critical updates
  5. Monitor update success rate with metrics
  6. Schedule bulk refresh for stale data

Performance Impact

  • Dashboard update: ~50-100ms
  • Non-blocking: Use background tasks
  • Minimal overhead: Only updates MongoDB
  • Redis populated on next API request