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
Option A: Manual Integration (Recommended First)
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
- Phase 1: Deploy infrastructure (Steps 1-6 above) ✅
- Phase 2: Test with 1-2 bakeries near schools
- Phase 3: Integrate into training service
- Phase 4: Retrain models for test bakeries
- Phase 5: Integrate into forecasting service
- Phase 6: Compare forecast accuracy
- 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:
- External service deployed with new router?
kubectl logs -n bakery-ia -l app=external-service | grep "calendar_operations" - Migration completed?
SELECT * FROM alembic_version; - 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:
- Check HYPERLOCAL_CALENDAR_IMPLEMENTATION.md for full technical details
- Review API endpoint documentation in calendar_operations.py
- Check logs for specific error messages
Deployment Completed: [Date] Deployed By: [Name] Version: 1.0.0