feat(phase2): add Flow Builder UI and internal flow routes

- Add FlowBuilder.tsx with React Flow visual editor
- Add FlowList.tsx for flow management
- Add /internal/flow/send endpoint for flow-engine messaging
- Add reactflow dependency to frontend

Co-Authored-By: Claude Opus 4.5 <noreply@anthropic.com>
This commit is contained in:
Claude AI
2026-01-29 10:23:02 +00:00
parent 14a579d5ca
commit c97d380635
4 changed files with 457 additions and 1 deletions

View File

@@ -3,6 +3,7 @@ from sqlalchemy.orm import Session
from typing import List
from uuid import UUID
import httpx
from pydantic import BaseModel
from app.core.database import get_db
from app.core.config import get_settings
from app.core.security import get_current_user
@@ -273,3 +274,59 @@ async def handle_whatsapp_event(
db.commit()
return {"status": "ok"}
class FlowSendRequest(BaseModel):
conversation_id: str
content: str
type: str = "text"
@router.post("/internal/flow/send")
async def flow_send_message(
request: FlowSendRequest,
db: Session = Depends(get_db),
):
"""Internal endpoint for flow engine to send messages"""
conversation = db.query(Conversation).filter(
Conversation.id == request.conversation_id
).first()
if not conversation:
raise HTTPException(status_code=404, detail="Conversation not found")
# Create message in DB
message = Message(
conversation_id=conversation.id,
direction=MessageDirection.OUTBOUND,
type=MessageType.TEXT,
content=request.content,
status=MessageStatus.PENDING,
)
db.add(message)
db.commit()
db.refresh(message)
# Send via WhatsApp Core
async with httpx.AsyncClient() as client:
try:
response = await client.post(
f"{settings.WHATSAPP_CORE_URL}/api/sessions/{conversation.whatsapp_account_id}/messages",
json={
"to": conversation.contact.phone_number,
"type": "text",
"content": {"text": request.content},
},
timeout=30,
)
if response.status_code == 200:
data = response.json()
message.whatsapp_message_id = data.get("messageId")
message.status = MessageStatus.SENT
else:
message.status = MessageStatus.FAILED
except Exception:
message.status = MessageStatus.FAILED
db.commit()
return {"success": True, "message_id": str(message.id)}