add saas files
This commit is contained in:
+10
-5
@@ -6,6 +6,9 @@ HOST=0.0.0.0
|
||||
PORT=8000
|
||||
LOG_LEVEL=info
|
||||
|
||||
# Authentication Configuration
|
||||
ENABLE_AUTH=false # Set to true in production for JWT validation
|
||||
|
||||
# CORS Configuration
|
||||
# Comma-separated list of allowed origins
|
||||
# Use * to allow all origins (not recommended for production)
|
||||
@@ -42,12 +45,14 @@ EMSAL_TIMEOUT=60
|
||||
# Sentry DSN for error tracking
|
||||
# SENTRY_DSN=https://your-sentry-dsn@sentry.io/project-id
|
||||
|
||||
# Clerk Configuration
|
||||
CLERK_SECRET_KEY=sk_test_YourClerkSecretKey
|
||||
# ------ Clerk ------
|
||||
CLERK_PUBLISHABLE_KEY=pk_test_xxx
|
||||
CLERK_SECRET_KEY=sk_test_xxx
|
||||
CLERK_ISSUER=https://your-app.clerk.accounts.dev # issuer & JWKS root
|
||||
|
||||
# Stripe Configuration
|
||||
STRIPE_SECRET_KEY=sk_test_YourStripeSecretKey
|
||||
STRIPE_WEBHOOK_SECRET=whsec_YourStripeWebhookSecret
|
||||
# ------ Stripe ------
|
||||
STRIPE_SECRET=sk_live_xxx
|
||||
STRIPE_WEBHOOK_SECRET=whsec_xxx
|
||||
|
||||
# Application Configuration
|
||||
APP_URL=http://localhost:8000
|
||||
|
||||
@@ -0,0 +1,18 @@
|
||||
# See https://fly.io/docs/app-guides/continuous-deployment-with-github-actions/
|
||||
|
||||
name: Fly Deploy
|
||||
on:
|
||||
push:
|
||||
branches:
|
||||
- main
|
||||
jobs:
|
||||
deploy:
|
||||
name: Deploy app
|
||||
runs-on: ubuntu-latest
|
||||
concurrency: deploy-group # optional: ensure only one action runs at a time
|
||||
steps:
|
||||
- uses: actions/checkout@v4
|
||||
- uses: superfly/flyctl-actions/setup-flyctl@master
|
||||
- run: flyctl deploy --remote-only
|
||||
env:
|
||||
FLY_API_TOKEN: ${{ secrets.FLY_API_TOKEN }}
|
||||
+6
-5
@@ -180,9 +180,10 @@ redis-data/
|
||||
|
||||
# Production logs
|
||||
logs/*.log.*
|
||||
Dockerfile
|
||||
Dockerfile
|
||||
fly.toml
|
||||
.github/workflows/fly-deploy.yml
|
||||
Dockerfile
|
||||
|
||||
# Remove these lines - we need deployment files in git:
|
||||
# Dockerfile - NEEDED for SaaS deployment
|
||||
# fly.toml - NEEDED for Fly.io deployment
|
||||
# .github/workflows/fly-deploy.yml - NEEDED for GitHub Actions
|
||||
|
||||
GEMINI.md
|
||||
|
||||
+24
-22
@@ -1,31 +1,33 @@
|
||||
# ---------- temel imaj ----------
|
||||
FROM python:3.12-slim
|
||||
|
||||
# Playwright’in istediği kitaplıklar
|
||||
RUN apt-get update && apt-get install -y \
|
||||
libnss3 libnspr4 libatk1.0-0 libatk-bridge2.0-0 libcups2 \
|
||||
libdrm2 libdbus-1-3 libatspi2.0-0 libx11-6 libxcomposite1 \
|
||||
libxdamage1 libxext6 libxfixes3 libxrandr2 libgbm1 libxcb1 \
|
||||
libxkbcommon0 libpango-1.0-0 libcairo2 libasound2 \
|
||||
&& rm -rf /var/lib/apt/lists/*
|
||||
# -------- BASE IMAGE (includes Chromium & deps) ----------------------------
|
||||
FROM mcr.microsoft.com/playwright/python:v1.52.0-jammy # Playwright docs
|
||||
|
||||
# -------- Runtime setup ----------------------------------------------------
|
||||
WORKDIR /app
|
||||
|
||||
# Gereksinimler
|
||||
COPY requirements.txt .
|
||||
RUN pip install --no-cache-dir --upgrade pip
|
||||
RUN pip install --no-cache-dir -r requirements.txt
|
||||
# Copy dependency manifests first for layer-cache
|
||||
COPY pyproject.toml poetry.lock* requirements*.txt* ./
|
||||
|
||||
# Uygulama dosyaları
|
||||
# Fast, deterministic install with `uv`
|
||||
RUN pip install --no-cache-dir uv && \
|
||||
uv pip install --system --no-cache-dir .[asgi] # installs FastMCP, FastAPI
|
||||
|
||||
# Copy application source
|
||||
COPY . .
|
||||
|
||||
# Python path ayarı (import sorunlarını önler)
|
||||
ENV PYTHONPATH=/app
|
||||
|
||||
# Playwright tarayıcılarını kur
|
||||
RUN playwright install chromium
|
||||
|
||||
# -------- Environment ------------------------------------------------------
|
||||
ENV PYTHONUNBUFFERED=1
|
||||
ENV ENABLE_AUTH=true # Clerk JWT validation ON by default
|
||||
ENV PORT=8000
|
||||
|
||||
# -------- Health check -----------------------------------------------------
|
||||
HEALTHCHECK --interval=30s --timeout=10s --start-period=10s --retries=3 \
|
||||
CMD python - <<'PY'
|
||||
import httpx, os, sys; \
|
||||
r=httpx.get(f"http://localhost:{os.getenv('PORT','8000')}/health"); \
|
||||
sys.exit(0 if r.status_code==200 else 1)
|
||||
PY
|
||||
|
||||
EXPOSE 8000
|
||||
|
||||
CMD ["uvicorn", "fastapi_app:app", "--host", "0.0.0.0", "--port", "8000", "--proxy-headers"]
|
||||
# -------- Entrypoint -------------------------------------------------------
|
||||
CMD ["uvicorn", "asgi_app:app", "--host", "0.0.0.0", "--port", "8000", "--proxy-headers"]
|
||||
+9
-1
@@ -18,7 +18,9 @@ from starlette.requests import Request
|
||||
from starlette.responses import JSONResponse, PlainTextResponse
|
||||
|
||||
# Import the main MCP app
|
||||
from mcp_server_main import app as mcp_server
|
||||
from mcp_factory import create_app
|
||||
|
||||
mcp_server = create_app()
|
||||
|
||||
# Add a health check endpoint
|
||||
@mcp_server.custom_route("/health", methods=["GET"])
|
||||
@@ -83,6 +85,9 @@ custom_middleware = [
|
||||
),
|
||||
]
|
||||
|
||||
# Import Stripe webhook router
|
||||
from stripe_webhook import router as stripe_router
|
||||
|
||||
# Create ASGI apps with different transports
|
||||
|
||||
# Recommended: Streamable HTTP transport
|
||||
@@ -91,6 +96,9 @@ app = mcp_server.http_app(
|
||||
middleware=custom_middleware
|
||||
)
|
||||
|
||||
# Add Stripe webhook router
|
||||
app.include_router(stripe_router, prefix="/api")
|
||||
|
||||
# Alternative: SSE transport (for compatibility)
|
||||
sse_app = mcp_server.http_app(
|
||||
path="/sse",
|
||||
|
||||
@@ -0,0 +1,32 @@
|
||||
# fly.toml app configuration file generated for yargi-mcp on 2025-06-29T00:23:47+03:00
|
||||
#
|
||||
# See https://fly.io/docs/reference/configuration/ for information about how to use this file.
|
||||
#
|
||||
|
||||
app = 'yargi-mcp'
|
||||
primary_region = 'fra'
|
||||
|
||||
[env]
|
||||
ENABLE_AUTH = "true"
|
||||
PORT = "8000"
|
||||
|
||||
[build]
|
||||
|
||||
[http_service]
|
||||
internal_port = 8000
|
||||
force_https = true
|
||||
auto_stop_machines = 'stop'
|
||||
auto_start_machines = true
|
||||
min_machines_running = 0
|
||||
processes = ['app']
|
||||
|
||||
[[vm]]
|
||||
memory = '1gb'
|
||||
cpu_kind = 'shared'
|
||||
cpus = 1
|
||||
|
||||
[checks.http_health] # keep MCP /health live
|
||||
type = "http"
|
||||
interval = "30s"
|
||||
timeout = "10s"
|
||||
path = "/health"
|
||||
@@ -0,0 +1,28 @@
|
||||
import os
|
||||
from functools import lru_cache
|
||||
from fastmcp import FastMCP
|
||||
from fastmcp.server.auth import BearerAuthProvider
|
||||
|
||||
@lru_cache
|
||||
def create_app() -> FastMCP:
|
||||
"""Return a FastMCP instance; Clerk JWT validation when ENABLE_AUTH=true."""
|
||||
if os.getenv("ENABLE_AUTH", "false").lower() != "true":
|
||||
return FastMCP(
|
||||
name="Yargı MCP – DEV",
|
||||
instructions="MCP server for TR legal databases (Yargitay, Danistay, Emsal, Uyusmazlik, Anayasa-Norm, Anayasa-Bireysel, KIK, Sayistay, Rekabet).",
|
||||
dependencies=["httpx", "beautifulsoup4", "markitdown", "pydantic", "aiohttp", "playwright"]
|
||||
)
|
||||
|
||||
issuer = os.environ["CLERK_ISSUER"] # e.g. https://cool-app.clerk.accounts.dev
|
||||
auth = BearerAuthProvider(
|
||||
jwks_uri=f"{issuer}/.well-known/jwks.json", # Clerk JWKS pattern
|
||||
issuer=issuer,
|
||||
audience=os.environ["CLERK_PUBLISHABLE_KEY"], # PK appears in aud claim
|
||||
required_scopes=["yargi.read"],
|
||||
)
|
||||
return FastMCP(
|
||||
name="Yargı MCP – PROD",
|
||||
auth=auth,
|
||||
instructions="MCP server for TR legal databases (Yargitay, Danistay, Emsal, Uyusmazlik, Anayasa-Norm, Anayasa-Bireysel, KIK, Sayistay, Rekabet) with JWT authentication.",
|
||||
dependencies=["httpx", "beautifulsoup4", "markitdown", "pydantic", "aiohttp", "playwright"]
|
||||
)
|
||||
+2
-6
@@ -31,7 +31,7 @@ root_logger.addHandler(console_handler)
|
||||
logger = logging.getLogger(__name__)
|
||||
# --- Logging Configuration End ---
|
||||
|
||||
from fastmcp import FastMCP
|
||||
from mcp_factory import create_app
|
||||
|
||||
# --- Module Imports ---
|
||||
from yargitay_mcp_module.client import YargitayOfficialApiClient
|
||||
@@ -97,11 +97,7 @@ from sayistay_mcp_module.models import (
|
||||
from sayistay_mcp_module.enums import DaireEnum, KamuIdaresiTuruEnum, WebKararKonusuEnum
|
||||
|
||||
|
||||
app = FastMCP(
|
||||
name="YargiMCP",
|
||||
instructions="MCP server for TR legal databases (Yargitay, Danistay, Emsal, Uyusmazlik, Anayasa-Norm, Anayasa-Bireysel, KIK, Sayistay).",
|
||||
dependencies=["httpx", "beautifulsoup4", "markitdown", "pydantic", "aiohttp", "playwright"]
|
||||
)
|
||||
app = create_app()
|
||||
|
||||
# --- API Client Instances ---
|
||||
yargitay_client_instance = YargitayOfficialApiClient()
|
||||
|
||||
@@ -0,0 +1,24 @@
|
||||
import os, stripe
|
||||
from clerk import ClerkClient # Clerk backend SDK
|
||||
from fastapi import APIRouter, Request, HTTPException
|
||||
|
||||
router = APIRouter()
|
||||
stripe.api_key = os.getenv("STRIPE_SECRET")
|
||||
clerk = ClerkClient(secret_key=os.getenv("CLERK_SECRET_KEY"))
|
||||
|
||||
@router.post("/stripe/webhook")
|
||||
async def stripe_hook(req: Request):
|
||||
payload, sig = await req.body(), req.headers["stripe-signature"]
|
||||
try:
|
||||
event = stripe.Webhook.construct_event( # Stripe-recommended verify
|
||||
payload, sig, os.getenv("STRIPE_WEBHOOK_SECRET"))
|
||||
except stripe.error.SignatureVerificationError:
|
||||
raise HTTPException(400, "Bad sig")
|
||||
|
||||
if event["type"] == "customer.subscription.updated":
|
||||
item = event["data"]["object"]["items"]["data"][0]
|
||||
plan = item["price"]["nickname"] # "Pro", "Enterprise"…
|
||||
userID = event["data"]["object"]["metadata"]["clerk_user_id"]
|
||||
clerk.users.update_user_metadata( # merge into unsafe_metadata
|
||||
userID, unsafe_metadata={"plan": plan})
|
||||
return {"ok": True}
|
||||
Reference in New Issue
Block a user