Purpose: Step-by-step guide for migrating services from direct adapter imports to router pattern Status: Active (CORE-QUERY-1 Phase 6) Last Updated: 2025-09-29
# ❌ OLD: Direct Import
from services.mcp.consumer.google_calendar_adapter import GoogleCalendarMCPAdapter
calendar = GoogleCalendarMCPAdapter()
events = await calendar.get_events()
# ✅ NEW: Router Pattern
from services.integrations.calendar.calendar_integration_router import CalendarIntegrationRouter
calendar = CalendarIntegrationRouter()
events = await calendar.get_events() # Same method call
Feature Flags:
USE_SPATIAL_CALENDAR - Enable spatial intelligence (default: true)ALLOW_LEGACY_CALENDAR - Allow legacy fallback (default: false)# ❌ OLD: Direct Import
from services.integrations.mcp.notion_adapter import NotionMCPAdapter
notion = NotionMCPAdapter()
database = await notion.get_database(db_id)
# ✅ NEW: Router Pattern
from services.integrations.notion.notion_integration_router import NotionIntegrationRouter
notion = NotionIntegrationRouter()
database = await notion.get_database(db_id) # Same method call
Feature Flags:
USE_SPATIAL_NOTION - Enable spatial intelligence (default: true)ALLOW_LEGACY_NOTION - Allow legacy fallback (default: false)# ❌ OLD: Direct Import (Dual Component)
from services.integrations.slack.spatial_adapter import SlackSpatialAdapter
from services.integrations.slack.slack_client import SlackClient
spatial = SlackSpatialAdapter()
client = SlackClient(config_service)
# Spatial operations
spatial_event = await spatial.create_spatial_event_from_slack(...)
# Client operations
await client.send_message(channel, text)
# ✅ NEW: Router Pattern (Unified Access)
from services.integrations.slack.slack_integration_router import SlackIntegrationRouter
slack = SlackIntegrationRouter(config_service)
# Spatial adapter access
spatial = slack.get_spatial_adapter()
spatial_event = await spatial.create_spatial_event_from_slack(...)
# Client methods available directly on router
await slack.send_message(channel, text)
Feature Flags:
USE_SPATIAL_SLACK - Enable spatial intelligence (default: true)ALLOW_LEGACY_SLACK - Allow legacy fallback (default: false)Note: Slack router requires config_service parameter for client initialization.
Identify all direct adapter imports in your service:
# Find Calendar direct imports
grep -r "GoogleCalendarMCPAdapter" services/your_service/
# Find Notion direct imports
grep -r "NotionMCPAdapter" services/your_service/
# Find Slack direct imports
grep -r "SlackSpatialAdapter\|SlackClient" services/your_service/
Always create a backup before migration:
cp services/your_service/your_file.py services/your_service/your_file.py.backup
Replace direct adapter imports with router imports:
Calendar:
# Replace this:
from services.mcp.consumer.google_calendar_adapter import GoogleCalendarMCPAdapter
# With this:
from services.integrations.calendar.calendar_integration_router import CalendarIntegrationRouter
Notion:
# Replace this:
from services.integrations.mcp.notion_adapter import NotionMCPAdapter
# With this:
from services.integrations.notion.notion_integration_router import NotionIntegrationRouter
Slack:
# Replace this:
from services.integrations.slack.spatial_adapter import SlackSpatialAdapter
from services.integrations.slack.slack_client import SlackClient
# With this:
from services.integrations.slack.slack_integration_router import SlackIntegrationRouter
Replace adapter instantiation with router instantiation:
Calendar:
# Replace this:
self.calendar = GoogleCalendarMCPAdapter()
# With this:
self.calendar = CalendarIntegrationRouter()
Notion:
# Replace this:
self.notion = NotionMCPAdapter()
# With this:
self.notion = NotionIntegrationRouter()
Slack (requires config_service):
# Replace this:
self.spatial = SlackSpatialAdapter()
self.client = SlackClient(config_service)
# With this:
self.slack = SlackIntegrationRouter(config_service)
# Access spatial: self.slack.get_spatial_adapter()
# Client methods: self.slack.send_message(), etc.
In most cases, method calls remain identical due to transparent delegation:
# Calendar - No changes needed
events = await self.calendar.get_events()
summary = await self.calendar.get_temporal_summary()
# Notion - No changes needed
database = await self.notion.get_database(db_id)
page = await self.notion.create_page(parent_id, properties)
# Slack - Client methods unchanged
await self.slack.send_message(channel, text)
channels = await self.slack.list_channels()
# Slack - Spatial adapter requires accessor
spatial = self.slack.get_spatial_adapter()
event = await spatial.create_spatial_event_from_slack(...)
Verify the migrated service works correctly:
# Import test
PYTHONPATH=. python3 -c "from services.your_service.your_file import YourClass"
# Instantiation test
PYTHONPATH=. python3 -c "
from services.your_service.your_file import YourClass
obj = YourClass()
print('✅ Service instantiates correctly')
"
# Run relevant unit tests
pytest tests/your_service/test_your_file.py -v
Use the automated checker:
python scripts/check_direct_imports.py services/your_service/your_file.py
Expected output:
✅ No direct adapter imports detected (1 files checked)
Commit with evidence of successful migration:
git add services/your_service/your_file.py
git commit -m "Migrate your_service to [Integration]Router pattern
- Import: [OldAdapter] → [NewRouter]
- Instantiation updated
- Method calls preserved (transparent delegation)
- Testing: Service imports successfully
- Verification: No direct imports remain
CORE-QUERY-1 service migration"
services/intent_service/canonical_handlers.pyservices/features/morning_standup.pyservices/domain/notion_domain_service.pyservices/publishing/publisher.pyservices/intelligence/spatial/notion_spatial.pyservices/integrations/slack/webhook_router.pyclass MyService:
def __init__(self):
# OLD
self.calendar = GoogleCalendarMCPAdapter()
# NEW
self.calendar = CalendarIntegrationRouter()
class MyService:
def __init__(self, use_calendar: bool = True):
# OLD
if use_calendar:
self.calendar = GoogleCalendarMCPAdapter()
# NEW
if use_calendar:
self.calendar = CalendarIntegrationRouter()
class MyService:
def __init__(self):
self._calendar = None
async def get_calendar_data(self):
# OLD
if not self._calendar:
from services.mcp.consumer.google_calendar_adapter import GoogleCalendarMCPAdapter
self._calendar = GoogleCalendarMCPAdapter()
# NEW
if not self._calendar:
from services.integrations.calendar.calendar_integration_router import CalendarIntegrationRouter
self._calendar = CalendarIntegrationRouter()
return await self._calendar.get_events()
class MyService:
# OLD
def __init__(self, calendar: GoogleCalendarMCPAdapter = None):
self.calendar = calendar or GoogleCalendarMCPAdapter()
# NEW
def __init__(self, calendar: CalendarIntegrationRouter = None):
self.calendar = calendar or CalendarIntegrationRouter()
class MySlackService:
def __init__(self, config_service):
# OLD
self.spatial = SlackSpatialAdapter()
self.client = SlackClient(config_service)
# Spatial operations
await self.spatial.create_spatial_event_from_slack(...)
# Client operations
await self.client.send_message(channel, text)
# NEW
def __init__(self, config_service):
self.slack = SlackIntegrationRouter(config_service)
# Spatial operations via accessor
spatial = self.slack.get_spatial_adapter()
await spatial.create_spatial_event_from_slack(...)
# Client operations directly on router
await self.slack.send_message(channel, text)
Symptom:
ImportError: cannot import name 'CalendarIntegrationRouter' from 'services.integrations.calendar'
Solution: Verify the router file exists and is in the correct location:
ls -la services/integrations/calendar/calendar_integration_router.py
Symptom:
AttributeError: 'CalendarIntegrationRouter' object has no attribute 'some_method'
Solution: The router might be missing a method. Verify router completeness:
from services.integrations.calendar.calendar_integration_router import CalendarIntegrationRouter
from services.mcp.consumer.google_calendar_adapter import GoogleCalendarMCPAdapter
router = CalendarIntegrationRouter()
adapter = GoogleCalendarMCPAdapter()
router_methods = set(m for m in dir(router) if not m.startswith('_'))
adapter_methods = set(m for m in dir(adapter) if not m.startswith('_'))
missing = adapter_methods - router_methods
if missing:
print(f"Missing methods: {missing}")
Symptom:
RuntimeError: No calendar integration available for get_events
Solution: Feature flags are disabling all integration modes. Enable at least one:
export USE_SPATIAL_CALENDAR=true
Symptom:
❌ ARCHITECTURAL VIOLATIONS DETECTED
services/your_service/your_file.py:42: Prohibited direct adapter import
Solution: Complete the migration by replacing the direct import with the router import.
After migration, verify:
If you encounter issues during migration:
python scripts/check_direct_imports.pydocs/architecture/router-patterns.mddev/2025/09/29/2025-09-29-1022-prog-code-log.mdVersion: 1.0 Last Updated: 2025-09-29 Maintained By: Architecture Team