Files
bakery-ia/CALENDAR_DEPLOYMENT_GUIDE.md
2025-11-02 20:24:44 +01:00

8.4 KiB

Hyperlocal School Calendar - Deployment Guide

🎯 Overview

This guide provides step-by-step instructions to deploy the hyperlocal school calendar feature for Prophet forecasting enhancement.


Prerequisites

  • External service database access
  • Redis instance running
  • Access to deploy to external, training, and forecasting services

📦 Deployment Steps

Step 1: Run Database Migration

cd services/external
python -m alembic upgrade head

Expected Output:

INFO [alembic.runtime.migration] Running upgrade b97bab14ac47 -> 693e0d98eaf9, add_school_calendars_and_location_context

Verify Tables Created:

-- Connect to external service database
SELECT table_name FROM information_schema.tables
WHERE table_schema = 'public'
AND table_name IN ('school_calendars', 'tenant_location_contexts');

Step 2: Seed Calendar Data

cd services/external
python scripts/seed_school_calendars.py

Expected Output:

INFO Starting school calendar seeding...
INFO Found 2 calendars in registry
INFO Processing calendar calendar_id=madrid_primary_2024_2025 city=madrid type=primary
INFO Calendar seeded successfully calendar_id=<uuid> city=madrid type=primary
INFO Processing calendar calendar_id=madrid_secondary_2024_2025 city=madrid type=secondary
INFO Calendar seeded successfully calendar_id=<uuid> city=madrid type=secondary
INFO Calendar seeding completed seeded=2 skipped=0 total=2

Verify Calendars Loaded:

SELECT calendar_name, city_id, school_type, academic_year
FROM school_calendars;

Expected: 2 rows (Madrid Primary and Secondary 2024-2025)

Step 3: Restart External Service

# Via Tilt or kubectl
kubectl rollout restart deployment external-service -n bakery-ia
kubectl wait --for=condition=ready pod -l app=external-service -n bakery-ia --timeout=60s

Verify Service Health:

curl -k https://localhost/api/v1/external/health

Step 4: Test Calendar API

List Calendars for Madrid:

curl -k -H "X-Tenant-ID: <tenant-id>" \
  https://localhost/api/v1/external/operations/cities/madrid/school-calendars

Expected Response:

{
  "city_id": "madrid",
  "calendars": [
    {
      "calendar_id": "<uuid>",
      "calendar_name": "Madrid Primary School Calendar 2024-2025",
      "city_id": "madrid",
      "school_type": "primary",
      "academic_year": "2024-2025",
      "holiday_periods": [...],
      "school_hours": {...},
      "enabled": true
    },
    ...
  ],
  "total": 2
}

Step 5: Assign Calendar to Test Tenant

# Get a calendar ID from previous step
CALENDAR_ID="<uuid-from-previous-step>"
TENANT_ID="<your-test-tenant-id>"

curl -k -X POST \
  -H "X-Tenant-ID: $TENANT_ID" \
  -H "Content-Type: application/json" \
  -d '{
    "city_id": "madrid",
    "school_calendar_id": "'$CALENDAR_ID'",
    "neighborhood": "Chamberí",
    "notes": "Test bakery near primary school"
  }' \
  https://localhost/api/v1/external/tenants/$TENANT_ID/location-context

Verify Assignment:

curl -k -H "X-Tenant-ID: $TENANT_ID" \
  https://localhost/api/v1/external/tenants/$TENANT_ID/location-context

Step 6: Test Holiday Check

# Check if Christmas is a holiday
curl -k -H "X-Tenant-ID: $TENANT_ID" \
  "https://localhost/api/v1/external/operations/school-calendars/$CALENDAR_ID/is-holiday?check_date=2024-12-25"

Expected Response:

{
  "date": "2024-12-25",
  "is_holiday": true,
  "holiday_name": "Christmas Holiday",
  "calendar_id": "<uuid>",
  "calendar_name": "Madrid Primary School Calendar 2024-2025"
}

Step 7: Verify Redis Caching

First Request (Cache Miss):

time curl -k -H "X-Tenant-ID: $TENANT_ID" \
  https://localhost/api/v1/external/tenants/$TENANT_ID/location-context

Expected: ~50-100ms

Second Request (Cache Hit):

time curl -k -H "X-Tenant-ID: $TENANT_ID" \
  https://localhost/api/v1/external/tenants/$TENANT_ID/location-context

Expected: ~5-10ms (much faster!)

Check Redis:

redis-cli
> KEYS tenant_context:*
> GET tenant_context:<tenant-id>
> TTL tenant_context:<tenant-id>  # Should show ~86400 seconds (24 hours)

🔧 Optional: Integrate with Training/Forecasting Services

The helper classes are ready to use:

In Training Service:

# services/training/app/ml/data_processor.py
from app.ml.calendar_features import CalendarFeatureEngine
from shared.clients.external_client import ExternalServiceClient

# In __init__:
self.external_client = ExternalServiceClient(config=settings, calling_service_name="training")
self.calendar_engine = CalendarFeatureEngine(self.external_client)

# In _engineer_features():
if tenant_id:
    df = await self.calendar_engine.add_calendar_features(df, tenant_id)

In Forecasting Service:

# services/forecasting/app/services/forecasting_service.py or prediction_service.py
from app.ml.calendar_features import forecast_calendar_features

# When preparing future features:
future_df = await forecast_calendar_features.add_calendar_features(
    future_df,
    tenant_id=tenant_id,
    date_column="ds"
)

Option B: Gradual Rollout

  1. Phase 1: Deploy infrastructure (Steps 1-6 above)
  2. Phase 2: Test with 1-2 bakeries near schools
  3. Phase 3: Integrate into training service
  4. Phase 4: Retrain models for test bakeries
  5. Phase 5: Integrate into forecasting service
  6. Phase 6: Compare forecast accuracy
  7. Phase 7: Full rollout to all tenants

📊 Monitoring & Validation

Database Metrics

-- Check calendar usage
SELECT COUNT(*) FROM tenant_location_contexts
WHERE school_calendar_id IS NOT NULL;

-- Check which calendars are most used
SELECT c.calendar_name, COUNT(t.tenant_id) as tenant_count
FROM school_calendars c
LEFT JOIN tenant_location_contexts t ON c.id = t.school_calendar_id
GROUP BY c.calendar_name;

Redis Cache Metrics

redis-cli
> INFO stats  # Check hit/miss rates
> KEYS calendar:*  # List cached calendars
> KEYS tenant_context:*  # List cached tenant contexts

API Performance

Check external service logs for:

  • Calendar API response times
  • Cache hit rates
  • Any errors
kubectl logs -n bakery-ia -l app=external-service --tail=100 | grep calendar

🔍 Troubleshooting

Problem: Migration Fails

Error: alembic.util.exc.CommandError: Can't locate revision...

Solution:

# Check current migration version
cd services/external
python -m alembic current

# Force to specific version if needed
python -m alembic stamp head

Problem: Seed Script Fails

Error: No module named 'app'

Solution:

# Ensure you're in the right directory
cd services/external
# Set PYTHONPATH
export PYTHONPATH=$(pwd):$PYTHONPATH
python scripts/seed_school_calendars.py

Problem: Calendar API Returns 404

Check:

  1. External service deployed with new router?
    kubectl logs -n bakery-ia -l app=external-service | grep "calendar_operations"
    
  2. Migration completed?
    SELECT * FROM alembic_version;
    
  3. Calendars seeded?
    SELECT COUNT(*) FROM school_calendars;
    

Problem: Cache Not Working

Check Redis Connection:

# From external service pod
kubectl exec -it <external-pod> -n bakery-ia -- redis-cli -h <redis-host> PING

Check Logs:

kubectl logs -n bakery-ia -l app=external-service | grep "cache"

📝 Rollback Procedure

If you need to rollback:

# 1. Rollback migration
cd services/external
python -m alembic downgrade -1

# 2. Restart external service
kubectl rollout restart deployment external-service -n bakery-ia

# 3. Clear Redis cache
redis-cli
> FLUSHDB

🎉 Success Criteria

  • Migration completed successfully
  • 2 calendars seeded (Madrid Primary & Secondary)
  • Calendar API returns valid responses
  • Tenant can be assigned to calendar
  • Holiday check works correctly
  • Redis cache reduces response time by >80%
  • No errors in external service logs

📞 Support

For issues or questions:


Deployment Completed: [Date] Deployed By: [Name] Version: 1.0.0