solventum-image-metadata/backend/app/main.py
SamoilenkoVadym 77494488d5 feat(deploy): add auto git pull and cleanup to deployment script
- Auto pull latest code before deployment
- Clean old Docker images before building new ones
- Add comprehensive cleanup commands documentation
- Add production deployment guide
- Fix frontend serving from /var/www/html for production
- Preserve build cache for faster deployments

Co-Authored-By: Claude Sonnet 4.5 (1M context) <noreply@anthropic.com>
2026-02-09 15:40:11 +00:00

136 lines
3.9 KiB
Python

"""
Oliver Metadata Tool - FastAPI Backend
Main application entry point with CORS, middleware, and routers.
"""
from fastapi import FastAPI
from fastapi.middleware.cors import CORSMiddleware
from fastapi.responses import JSONResponse, FileResponse
from fastapi.staticfiles import StaticFiles
from contextlib import asynccontextmanager
import os
from pathlib import Path
from app.api import auth, files, metadata, templates
from app.api import import_api
from app.core.redis_client import RedisSessionStore
from app.core.database import init_db
# Lifespan context manager for startup/shutdown events
@asynccontextmanager
async def lifespan(app: FastAPI):
"""Application lifespan: startup and shutdown logic"""
# Startup
print("🚀 Starting Oliver Metadata Tool API...")
# Initialize database
await init_db()
print("✅ Database initialized")
# Initialize Redis
redis_url = os.getenv("REDIS_URL", "redis://localhost:6379/0")
app.state.redis = RedisSessionStore(redis_url)
print(f"✅ Redis connected: {redis_url}")
yield
# Shutdown
print("👋 Shutting down Oliver Metadata Tool API...")
await app.state.redis.close()
# Create FastAPI app
app = FastAPI(
title="Oliver Metadata Tool API",
description="Universal metadata creation and management API for files",
version="4.0.0",
lifespan=lifespan
)
# CORS Configuration
# Allow React frontend to make requests from different origin
origins = [
"http://localhost:3000", # React dev server
"http://localhost:5173", # Vite dev server
"http://localhost:80", # Production frontend
os.getenv("FRONTEND_URL", ""), # Custom frontend URL from env
]
app.add_middleware(
CORSMiddleware,
allow_origins=origins,
allow_credentials=True,
allow_methods=["*"],
allow_headers=["*"],
)
# Include routers
app.include_router(auth.router, prefix="/auth", tags=["auth"])
app.include_router(files.router, prefix="/files", tags=["files"])
app.include_router(metadata.router, prefix="/metadata", tags=["metadata"])
app.include_router(templates.router, prefix="/templates", tags=["templates"])
app.include_router(import_api.router, prefix="/import", tags=["import"])
# Serve React frontend
# Try production path first, fallback to local frontend/dist
FRONTEND_DIR = os.getenv("FRONTEND_DIR", "/var/www/html/solventum-image-metadata")
STATIC_DIR = Path(FRONTEND_DIR) if Path(FRONTEND_DIR).exists() else Path(__file__).parent.parent.parent / "frontend" / "dist"
@app.get("/")
async def root():
"""Serve React index.html or API info"""
if STATIC_DIR.exists() and (STATIC_DIR / "index.html").exists():
return FileResponse(str(STATIC_DIR / "index.html"))
else:
return {
"name": "Oliver Metadata Tool API",
"version": "4.0.0",
"status": "running",
"docs": "/docs",
"redoc": "/redoc"
}
# Mount static files for React assets
if STATIC_DIR.exists():
app.mount("/assets", StaticFiles(directory=str(STATIC_DIR / "assets")), name="assets")
# Health check endpoint
@app.get("/health")
async def health_check():
"""Health check endpoint for Docker/K8s"""
return {
"status": "healthy",
"database": "connected", # Will check actual DB later
"redis": "connected" # Will check actual Redis later
}
# Global exception handler
@app.exception_handler(Exception)
async def global_exception_handler(request, exc):
"""Handle all uncaught exceptions"""
return JSONResponse(
status_code=500,
content={
"error": "Internal server error",
"detail": str(exc) if os.getenv("DEBUG") == "true" else "An error occurred"
}
)
if __name__ == "__main__":
import uvicorn
# Run with: python -m app.main
uvicorn.run(
"app.main:app",
host="0.0.0.0",
port=8000,
reload=True, # Auto-reload on code changes
log_level="info"
)