ppt-tool/backend/api/main.py
Vadym Samoilenko c431d4ab45 Implement critical security fixes and modern design system (Pre-launch P0 tasks)
Security Improvements (P0.0-P0.4):
- P0.0: Migrate to Gemini-only AI stack (simplified, single billing)
- P0.1: Fix CORS to restrict allowed origins from env (was *)
- P0.2: Remove hardcoded dev password, require env var
- P0.3: Add rate limiting (slowapi) - 3-10 req/min on sensitive endpoints
- P0.4: Add request size limits (100MB default via middleware)

New Features:
- Unified LLM service with Google Gemini priority
- OXML geometry extractor for layout parsing
- TSX validator for generated React components
- Client ID support in presentation requests with access control
- Configurable LLM/image timeouts via env vars

Modern Design System (P0.9 - partial):
- Enhanced CSS design tokens (primary, semantic colors, shadows)
- Typography scale (h1-h4, body variants, caption)
- Modern animations (fadeIn, slideIn, scaleIn)
- Updated Button component with better variants and hover effects
- Created unified Card and StatusBadge components
- Applied design system to Dashboard and Settings pages

Backend Improvements:
- Master deck parser simplification
- Slide-to-HTML endpoint cleanup (325 lines removed)
- Better error handling in prompts endpoint

Frontend Improvements:
- Settings UI simplified to show only Google/Gemini
- Dashboard uses CSS variables instead of hardcoded colors
- Improved button transitions and hover states

Co-Authored-By: Claude Sonnet 4.5 (1M context) <noreply@anthropic.com>
2026-02-27 18:28:24 +00:00

93 lines
3.8 KiB
Python

import os
from fastapi import APIRouter, FastAPI
from fastapi.middleware.cors import CORSMiddleware
from fastapi.staticfiles import StaticFiles
from slowapi import _rate_limit_exceeded_handler
from slowapi.errors import RateLimitExceeded
from api.lifespan import app_lifespan
from api.middlewares import UserConfigEnvUpdateMiddleware
from api.middlewares.auth_middleware import AuthMiddleware
from api.middlewares.rate_limit_middleware import limiter
from api.middlewares.request_size_middleware import RequestSizeLimitMiddleware
from api.v1.ppt.router import API_V1_PPT_ROUTER
from api.v1.webhook.router import API_V1_WEBHOOK_ROUTER
from api.v1.mock.router import API_V1_MOCK_ROUTER
from api.v1.auth.router import AUTH_ROUTER
from api.v1.admin.users_router import USERS_ROUTER
from api.v1.admin.teams_router import TEAMS_ROUTER
from api.v1.admin.clients_router import CLIENTS_ROUTER
from api.v1.admin.audit_router import AUDIT_ROUTER
from api.v1.admin.brand_config_router import BRAND_CONFIG_ROUTER
from api.v1.admin.master_decks_router import MASTER_DECKS_ROUTER
from api.v1.admin.analytics_router import ANALYTICS_ROUTER
from api.v1.admin.storage_router import STORAGE_ROUTER
from api.v1.admin.settings_router import SETTINGS_ROUTER
from api.v1.ppt.endpoints.jobs import JOBS_ROUTER
from api.v1.ppt.endpoints.review import REVIEW_ROUTER
from api.v1.ppt.endpoints.export import EXPORT_ROUTER
from api.middlewares.audit_middleware import AuditMiddleware
app = FastAPI(lifespan=app_lifespan)
# Configure rate limiting
app.state.limiter = limiter
app.add_exception_handler(RateLimitExceeded, _rate_limit_exceeded_handler)
# Admin router aggregator
ADMIN_ROUTER = APIRouter(prefix="/api/v1/admin")
ADMIN_ROUTER.include_router(USERS_ROUTER)
ADMIN_ROUTER.include_router(TEAMS_ROUTER)
ADMIN_ROUTER.include_router(CLIENTS_ROUTER)
ADMIN_ROUTER.include_router(AUDIT_ROUTER)
ADMIN_ROUTER.include_router(BRAND_CONFIG_ROUTER)
ADMIN_ROUTER.include_router(MASTER_DECKS_ROUTER)
ADMIN_ROUTER.include_router(ANALYTICS_ROUTER)
ADMIN_ROUTER.include_router(STORAGE_ROUTER)
ADMIN_ROUTER.include_router(SETTINGS_ROUTER)
# Routers
app.include_router(AUTH_ROUTER)
app.include_router(ADMIN_ROUTER)
app.include_router(API_V1_PPT_ROUTER)
app.include_router(JOBS_ROUTER)
app.include_router(REVIEW_ROUTER)
app.include_router(EXPORT_ROUTER)
app.include_router(API_V1_WEBHOOK_ROUTER)
app.include_router(API_V1_MOCK_ROUTER)
# Serve static assets (placeholder images, etc.)
_static_dir = os.path.join(os.path.dirname(__file__), "..", "static")
if os.path.isdir(_static_dir):
app.mount("/static", StaticFiles(directory=_static_dir), name="static")
# Serve data directory (images, exports, uploads) for local dev
# In Docker, nginx serves these directly; this is a fallback for dev mode
_data_dir = os.environ.get("APP_DATA_DIRECTORY", os.path.join(os.path.dirname(__file__), "..", "data"))
os.makedirs(_data_dir, exist_ok=True)
app.mount("/app_data", StaticFiles(directory=_data_dir), name="app_data")
# Middlewares (executed in reverse order: last added = first executed)
# 1. CORS must run first (handles preflight OPTIONS)
origins = os.getenv("ALLOWED_ORIGINS", "http://localhost:3000").split(",")
app.add_middleware(
CORSMiddleware,
allow_origins=origins,
allow_credentials=True,
allow_methods=["GET", "POST", "PUT", "PATCH", "DELETE", "OPTIONS"],
allow_headers=["Authorization", "Content-Type", "Accept"],
)
# 2. Request size limit (reject large requests early)
max_request_size = int(os.getenv("MAX_REQUEST_SIZE", str(100 * 1024 * 1024))) # 100MB
app.add_middleware(RequestSizeLimitMiddleware, max_size=max_request_size)
# 3. Auth middleware (validates JWT, attaches user to request.state)
app.add_middleware(AuthMiddleware)
# 4. Audit middleware (fire-and-forget logging for mutations)
app.add_middleware(AuditMiddleware)
# 5. User config middleware
app.add_middleware(UserConfigEnvUpdateMiddleware)