fix: runtime deployment fixes for Docker Compose stack
- Add .gitignore for __pycache__, node_modules, .playwright-mcp - Add CLAUDE.md project instructions - docker-compose: remove host port exposure for internal services, remove Ollama container (use host), add CORS origin, bake NEXT_PUBLIC_API_URL at build time, run alembic migrations on gateway startup, add CPU-only torch pre-install - gateway: add CORS middleware, graceful Slack degradation without bot token, fix None guard on slack_handler - gateway pyproject: add aiohttp dependency for slack-bolt async - llm-pool pyproject: install litellm from GitHub (removed from PyPI), enable hatch direct references - portal: enable standalone output in next.config.ts - Remove orphaned migration 003_phase2_audit_kb.py (renamed to 004) Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
This commit is contained in:
@@ -62,16 +62,38 @@ app = FastAPI(
|
||||
version="0.1.0",
|
||||
)
|
||||
|
||||
# ---------------------------------------------------------------------------
|
||||
# CORS — allow portal origin to call gateway API
|
||||
# ---------------------------------------------------------------------------
|
||||
from fastapi.middleware.cors import CORSMiddleware
|
||||
|
||||
app.add_middleware(
|
||||
CORSMiddleware,
|
||||
allow_origins=[
|
||||
"http://localhost:3000",
|
||||
"http://127.0.0.1:3000",
|
||||
"http://100.64.0.10:3000",
|
||||
],
|
||||
allow_credentials=True,
|
||||
allow_methods=["*"],
|
||||
allow_headers=["*"],
|
||||
)
|
||||
|
||||
# ---------------------------------------------------------------------------
|
||||
# Slack bolt app — initialized at module import time.
|
||||
# signing_secret="" is safe for local dev/testing; set via env in production.
|
||||
# ---------------------------------------------------------------------------
|
||||
slack_app = AsyncApp(
|
||||
token=settings.slack_bot_token or None,
|
||||
signing_secret=settings.slack_signing_secret or None,
|
||||
# In HTTP mode (Events API), token_verification_enabled must be True
|
||||
# slack-bolt validates signing_secret on every inbound request
|
||||
)
|
||||
slack_app: AsyncApp | None = None
|
||||
if settings.slack_bot_token and settings.slack_signing_secret:
|
||||
slack_app = AsyncApp(
|
||||
token=settings.slack_bot_token,
|
||||
signing_secret=settings.slack_signing_secret,
|
||||
)
|
||||
else:
|
||||
import logging
|
||||
logging.getLogger(__name__).warning(
|
||||
"SLACK_BOT_TOKEN or SLACK_SIGNING_SECRET not set — Slack adapter disabled"
|
||||
)
|
||||
|
||||
# Async Redis client — shared across all request handlers
|
||||
_redis: Redis | None = None # type: ignore[type-arg]
|
||||
@@ -88,16 +110,14 @@ def _get_redis() -> Redis: # type: ignore[type-arg]
|
||||
# ---------------------------------------------------------------------------
|
||||
# Register Slack event handlers
|
||||
# ---------------------------------------------------------------------------
|
||||
register_slack_handlers(
|
||||
slack_app=slack_app,
|
||||
redis=_get_redis(),
|
||||
get_session=async_session_factory,
|
||||
)
|
||||
|
||||
# ---------------------------------------------------------------------------
|
||||
# Slack request handler — adapts slack-bolt AsyncApp to FastAPI
|
||||
# ---------------------------------------------------------------------------
|
||||
slack_handler = AsyncSlackRequestHandler(slack_app)
|
||||
slack_handler: AsyncSlackRequestHandler | None = None
|
||||
if slack_app is not None:
|
||||
register_slack_handlers(
|
||||
slack_app=slack_app,
|
||||
redis=_get_redis(),
|
||||
get_session=async_session_factory,
|
||||
)
|
||||
slack_handler = AsyncSlackRequestHandler(slack_app)
|
||||
|
||||
# ---------------------------------------------------------------------------
|
||||
# Register channel routers
|
||||
@@ -133,6 +153,8 @@ async def slack_events(request: Request) -> Response:
|
||||
CRITICAL: This endpoint MUST return HTTP 200 within 3 seconds.
|
||||
All LLM/heavy work is dispatched to Celery inside the event handlers.
|
||||
"""
|
||||
if slack_handler is None:
|
||||
return Response(content='{"error":"Slack not configured"}', status_code=503, media_type="application/json")
|
||||
return await slack_handler.handle(request)
|
||||
|
||||
|
||||
|
||||
@@ -13,6 +13,7 @@ dependencies = [
|
||||
"konstruct-orchestrator",
|
||||
"fastapi[standard]>=0.115.0",
|
||||
"slack-bolt>=1.22.0",
|
||||
"aiohttp>=3.9.0",
|
||||
"python-telegram-bot>=21.0",
|
||||
"httpx>=0.28.0",
|
||||
"redis>=5.0.0",
|
||||
|
||||
Reference in New Issue
Block a user