feat: add appointments, campaigns, admin, storage, tests and various updates

- Add new routers: admin, appointments, campaigns
- Add storage service and logging config
- Add migrations directory and test suite with pytest config
- Add supabase_migration_features.sql
- Update models, dependencies, config, and existing routers
- Remove whatsapp_service (deleted)
- Update pyproject.toml and uv.lock dependencies

Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
This commit is contained in:
belviskhoremk
2026-04-03 09:11:58 +00:00
parent 9dccc83293
commit 92d4c2fc5e
51 changed files with 7076 additions and 515 deletions

View File

@@ -5,6 +5,7 @@ from app.models import (
from app.database import get_supabase
from app.dependencies import get_current_user, get_user_subscription
from app.services.vector_store import vector_store
from app.services.storage import delete_from_storage
from app.config import PLAN_LIMITS
from typing import List
import uuid
@@ -83,8 +84,20 @@ async def create_chatbot(data: ChatbotCreate, user=Depends(get_current_user)):
"handoff_keywords": data.handoff_keywords,
}
result = supabase.table("chatbots").insert(chatbot_data).execute()
if not result.data:
try:
result = supabase.table("chatbots").insert(chatbot_data).execute()
if not result.data:
raise HTTPException(status_code=500, detail="Failed to create chatbot")
except HTTPException:
raise
except Exception as e:
# Cleanup orphaned Qdrant collection if DB insert failed
if collection_name:
try:
vector_store.delete_collection(collection_name)
logger.warning(f"Cleaned up orphaned Qdrant collection {collection_name} after DB failure")
except Exception:
pass
raise HTTPException(status_code=500, detail="Failed to create chatbot")
return _format_chatbot(result.data[0], supabase)
@@ -139,7 +152,11 @@ async def delete_chatbot(chatbot_id: str, user=Depends(get_current_user)):
try:
vector_store.delete_collection(chatbot["qdrant_collection_name"])
except Exception as e:
logger.warning(f"Failed to delete collection: {e}")
logger.warning(f"Failed to delete Qdrant collection: {e}")
# Delete logo from Supabase Storage
if chatbot.get("logo_url"):
delete_from_storage(supabase, "logos", chatbot["logo_url"])
supabase.table("chatbots").delete().eq("id", chatbot_id).execute()
return SuccessResponse(success=True, message="Chatbot deleted")
@@ -303,4 +320,5 @@ def _format_chatbot(chatbot: dict, supabase) -> ChatbotResponse:
handoff_message=chatbot.get("handoff_message", "I'll connect you with our team. Please wait."),
handoff_email=chatbot.get("handoff_email"),
handoff_keywords=chatbot.get("handoff_keywords") or ["human", "agent", "speak to someone", "talk to a person", "real person"],
booking_enabled=bool(chatbot.get("booking_enabled")),
)