Files
docs/integration-problem-analysis.md
-Puter e6685203fe feat: initial docs repo with project inventory and all documentation
- Added REPO_INVENTORY.md with all repos, branches, remotes, and staging info
- Added .gitignore
- Synced all existing docs from local workspace
- Centralized documentation hub for GrowQR team
2026-06-22 15:04:27 +05:30

404 lines
12 KiB
Markdown

# GrowQR Integration Problem Analysis
## Current Pain Points
### 1. Hardcoded Routing Maps
The orchestrator has hardcoded `PAGE_TO_AGENT` and `ACTION_TO_AGENT` dictionaries in `session.py`. When new services are added or actions renamed, these maps must be updated, requiring:
- Code changes to orchestrator
- Redeployment of orchestrator
- Coordination between your team (service changes) and original team (orchestrator updates)
### 2. Redis Streams Complexity
Current event-driven architecture uses Redis Streams with specific naming conventions:
- Stream naming: `tasks:{agent_name}`
- Response channels: `responses:{task_id}`
- Message format with specific JSON schema
- Pub/sub completion sentinels (`__task_complete__`)
Contributors must understand this protocol, implement consumers, handle backpressure, etc.
### 3. Dual Transport Maintenance
Services must implement both:
- Redis Stream worker (for streaming/async)
- HTTP A2A endpoints (for synchronous fallback)
This doubles the integration surface area.
### 4. Contract Breaking on Changes
When you modify microservices:
- Action names change
- Message formats evolve
- New parameters added
- Response structures modified
The original team must update all consumers (orchestrator, other services) to match.
### 5. No Runtime Tool Registration
Agent cards (`/.well-known/agent-card.json`) are static JSON files. To add/modify skills:
- Change JSON
- Redeploy service
- Orchestrator must rediscover
There's no dynamic "tool marketplace" where contributors can register capabilities at runtime.
## Goals for Improvement
1. **Minimize breaking changes** - Changes to services shouldn't require orchestrator updates
2. **Simplify contributor integration** - New developers should add tools without deep Redis/protocol knowledge
3. **Dynamic tool management** - Frontend-visible tools should be registrable at runtime
4. **Pluggable interface** - SDK-like experience without building a full SDK
5. **Preserve architecture** - Keep the 4-lane model, orchestrator pattern, Q-Score signals
## Potential Solution Paths
### Path A: Dynamic Tool Registry (Database-Driven)
Replace hardcoded maps with a database table that stores:
- Tool ID, name, description
- Target agent/service URL
- Input schema (JSON Schema)
- Output schema (JSON Schema)
- Routing rules (page patterns, action patterns)
- Version info
**Pros:**
- Runtime tool registration
- Versioning support
- Frontend can show available tools dynamically
- No orchestrator redeploy for new tools
**Cons:**
- Still need to define schemas
- Database migration required
- Some complexity in registry UI/management
### Path B: HTTP-Only Standardization (Simplify Transport)
Standardize on HTTP A2A for ALL service communication. Remove Redis Streams complexity.
**Changes:**
- All services implement `/a2a/tasks` endpoint
- Standardized request/response format
- Streaming via SSE (Server-Sent Events) instead of Redis pub/sub
- Orchestrator routes all traffic via HTTP
**Pros:**
- Single transport to understand
- HTTP is familiar to all developers
- Easy to test/debug with curl/Postman
- Load balancing built-in
- No Redis consumer complexity
**Cons:**
- Loses Redis persistence/replay capability
- Slightly higher latency (acceptable?)
- WebSocket to HTTP bridging needed
### Path C: Schema Registry + Code Generation
Maintain a central schema registry (like Confluent Schema Registry or simple JSON Schema store):
- Services register their message schemas
- Orchestrator validates messages against schemas
- Code generation for type-safe clients
- Schema evolution rules (backward/forward compatibility)
**Pros:**
- Strong typing
- Schema evolution managed
- Clear contracts
**Cons:**
- Complex to implement
- Still requires coordination
- Overhead for simple services
### Path D: GraphQL Federation
Replace REST/A2A with GraphQL:
- Single GraphQL gateway (orchestrator becomes gateway)
- Services expose GraphQL schemas
- Frontend queries exactly what it needs
- Natural stitching of services
**Pros:**
- Single query for multi-service data
- Strong typing
- Introspection = automatic discovery
- Frontend-driven queries
**Cons:**
- Major architectural shift
- Learning curve for team
- Q-Score signals need separate path
- Breaking change to entire system
### Path E: Plugin Architecture with Self-Registration
Services self-register at startup via a "Plugin Registry" API:
```python
# In service startup
await plugin_registry.register({
"service_name": "interview-service",
"version": "2.0.0",
"tools": [
{
"tool_id": "configure_interview",
"name": "Configure Interview",
"endpoint": "/a2a/tasks",
"input_schema": {...},
"triggers": ["page:interview", "action:configure_interview"],
"outputs": ["interview_configured", "qscore_signals"]
}
]
})
```
**Pros:**
- Services describe themselves
- No hardcoded maps
- Runtime discovery
- Can include health checks
**Cons:**
- Services must implement registration logic
- Registration order matters
- Need deregistration/cleanup
### Path F: OpenAPI-Based Dynamic Client Generation
Services expose OpenAPI specs at `/.well-known/openapi.json`:
- Orchestrator fetches specs
- Generates client code dynamically (or uses generic client)
- Routes based on operationIds
- Validates requests/responses
**Pros:**
- Industry standard
- Auto-generated docs
- Code generation tools exist
- Language agnostic
**Cons:**
- Still need routing logic
- OpenAPI can be verbose
- Doesn't solve the action/page routing problem
### Path G: gRPC with Reflection
Replace HTTP A2A with gRPC:
- Services define .proto files
- gRPC reflection for discovery
- Strongly typed, efficient
- Streaming support built-in
**Pros:**
- Type safety
- Performance
- Streaming
- Reflection = discovery
**Cons:**
- Major architectural change
- Frontend needs gRPC-web or gateway
- Learning curve
- Overkill for simple CRUD
## Recommended Hybrid Approach
Based on the constraints (minimal breaking changes, contributor-friendly, pluggable), I recommend a **hybrid approach combining Path A + Path B + Path E**:
### Phase 1: Dynamic Tool Registry (Immediate Win)
**Create a Tool Registry Service (or add to orchestrator):**
```python
# Tool Registry Schema
tool_registry = {
"tool_id": "resume_analyze",
"name": "AI Resume Analysis",
"description": "Analyzes resume for ATS compatibility",
"service_name": "resume-builder", # Maps to agent name
"service_url": "http://resume-builder:8000",
"triggers": {
"pages": ["resume-hub", "resume-editor"],
"actions": ["ai_analyze", "analyze_resume"],
"skills": ["resume.analysis"]
},
"input_schema": {
"type": "object",
"properties": {
"resume_id": {"type": "string"},
"deep_analysis": {"type": "boolean"}
},
"required": ["resume_id"]
},
"output_schema": {
"type": "object",
"properties": {
"score": {"type": "number"},
"suggestions": {"type": "array"}
}
},
"qscore_signals": ["resume.ats_score", "resume.completeness"],
"version": "2.1.0",
"enabled": True,
"created_by": "contributor-xyz",
"created_at": "2024-01-15"
}
```
**Changes to Orchestrator:**
1. Replace hardcoded `PAGE_TO_AGENT` and `ACTION_TO_AGENT` with registry lookups
2. Cache registry in memory with periodic refresh
3. New admin endpoints for tool CRUD
4. Frontend can query available tools for a page
### Phase 2: HTTP-First with Optional Redis (Simplify Transport)
**Standardize on HTTP A2A as primary transport:**
1. Make HTTP A2A the default (already implemented)
2. Deprecate Redis Streams for new services (keep for existing)
3. Add SSE streaming support for real-time updates
4. Contributors only need to implement: `POST /a2a/tasks`
**Service Template for Contributors:**
```python
# Minimal service template
from fastapi import FastAPI
from pydantic import BaseModel
app = FastAPI()
class TaskRequest(BaseModel):
task_id: str
action: str
params: dict
user_id: str
user_context: dict | None = None
@app.post("/a2a/tasks")
async def handle_task(request: TaskRequest):
# Route to appropriate handler
if request.action == "my_tool_action":
result = await my_tool.execute(request.params, request.user_context)
return {
"task_id": request.task_id,
"status": "completed",
"messages": [{
"type": "agent_data",
"action": "my_tool_complete",
"data": result
}]
}
```
### Phase 3: Self-Registration with Health Checks (Plugin Architecture)
**Services self-register on startup:**
```python
# Service startup
async def register_tools():
async with httpx.AsyncClient() as client:
await client.post(
"http://orchestrator:8000/api/v1/tools/register",
json={
"service_name": "my-new-service",
"tools": [
{
"tool_id": "my_tool",
"triggers": {
"pages": ["my-page"],
"actions": ["my_action"]
},
"endpoint": "/a2a/tasks",
"health_check": "/health"
}
]
},
headers={"Authorization": f"Bearer {REGISTRATION_TOKEN}"}
)
```
**Orchestrator enhancements:**
- Accept dynamic registrations
- Health check polling
- Automatic deregistration on unhealthy services
- Tool versioning (multiple versions of same tool)
### Phase 4: Frontend Tool Marketplace
**Allow dynamic tool enabling from frontend:**
```typescript
// Admin interface
interface ToolConfig {
toolId: string;
enabled: boolean;
visibleToUsers: boolean;
requirePlan: 'free' | 'pro' | 'enterprise';
customParams: Record<string, any>;
}
// Users see tools based on registry + their plan
const availableTools = await fetch('/api/v1/tools/available?page=resume-hub');
```
## Implementation Roadmap (Minimal Breaking Changes)
### Week 1-2: Registry Foundation
1. Create `ToolRegistry` class in orchestrator (in-memory first)
2. Add `/api/v1/tools` CRUD endpoints
3. Load hardcoded maps into registry at startup
4. Switch routing to use registry lookups
**Breaking change:** None - just refactoring
### Week 3-4: Service Self-Registration
1. Add registration endpoint to orchestrator
2. Create simple registration helper library
3. Update one service (e.g., interview-service) to self-register
4. Test end-to-end
**Breaking change:** None for existing services
### Week 5-6: Frontend Integration
1. Add tool discovery API: `/api/v1/tools?page={page}`
2. Frontend fetches available tools per page
3. Dynamic UI rendering based on tool registry
4. Admin interface for tool management
**Breaking change:** None - additive feature
### Week 7-8: HTTP-First Migration
1. Ensure all services have HTTP A2A endpoints
2. Switch orchestrator default to HTTP
3. Add SSE streaming for real-time updates
4. Document contributor template
**Breaking change:** Redis becomes optional (not default)
### Week 9-10: Contributor SDK (Lightweight)
1. Python decorator library:
```python
from growqr_sdk import tool, register_service
@tool(
tool_id="analyze_resume",
triggers=["page:resume-hub", "action:analyze"]
)
async def analyze_resume(params, user_context):
# Implementation
return {"score": 85}
register_service(
name="my-service",
orchestrator_url="http://orchestrator:8000",
tools=[analyze_resume]
)
```
2. JavaScript/TypeScript equivalent for Node services
## Summary: Why This Works
1. **Minimal breaking changes**: Existing services keep working, Redis optional
2. **Contributor-friendly**: Single HTTP endpoint to implement, decorator SDK optional
3. **Pluggable**: Runtime registration, dynamic UI, no orchestrator redeploy
4 **Preserves architecture**: Still 4-lane, still orchestrated, still Q-Score signals
5 **Your team benefits**: You change services independently, original team gets stability
6 **Original team benefits**: Less integration code, dynamic capabilities, easier debugging
The key insight: **The orchestrator should ask "what tools are available?" not "is this action in my hardcoded map?"**