# 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 ```bash 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:** ```sql -- 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 ```bash 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= city=madrid type=primary INFO Processing calendar calendar_id=madrid_secondary_2024_2025 city=madrid type=secondary INFO Calendar seeded successfully calendar_id= city=madrid type=secondary INFO Calendar seeding completed seeded=2 skipped=0 total=2 ``` **Verify Calendars Loaded:** ```sql 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 ```bash # 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:** ```bash curl -k https://localhost/api/v1/external/health ``` ### Step 4: Test Calendar API **List Calendars for Madrid:** ```bash curl -k -H "X-Tenant-ID: " \ https://localhost/api/v1/external/operations/cities/madrid/school-calendars ``` **Expected Response:** ```json { "city_id": "madrid", "calendars": [ { "calendar_id": "", "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 ```bash # Get a calendar ID from previous step CALENDAR_ID="" 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:** ```bash curl -k -H "X-Tenant-ID: $TENANT_ID" \ https://localhost/api/v1/external/tenants/$TENANT_ID/location-context ``` ### Step 6: Test Holiday Check ```bash # 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:** ```json { "date": "2024-12-25", "is_holiday": true, "holiday_name": "Christmas Holiday", "calendar_id": "", "calendar_name": "Madrid Primary School Calendar 2024-2025" } ``` ### Step 7: Verify Redis Caching **First Request (Cache Miss):** ```bash 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):** ```bash 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:** ```bash redis-cli > KEYS tenant_context:* > GET tenant_context: > TTL tenant_context: # 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:** ```python # 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:** ```python # 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 ```sql -- 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 ```bash 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 ```bash 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:** ```bash # 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:** ```bash # 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? ```bash kubectl logs -n bakery-ia -l app=external-service | grep "calendar_operations" ``` 2. Migration completed? ```sql SELECT * FROM alembic_version; ``` 3. Calendars seeded? ```sql SELECT COUNT(*) FROM school_calendars; ``` ### Problem: Cache Not Working **Check Redis Connection:** ```bash # From external service pod kubectl exec -it -n bakery-ia -- redis-cli -h PING ``` **Check Logs:** ```bash kubectl logs -n bakery-ia -l app=external-service | grep "cache" ``` --- ## πŸ“ Rollback Procedure If you need to rollback: ```bash # 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](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