File size: 3,163 Bytes
7ac6163
 
 
 
 
 
 
 
 
 
 
 
 
 
 
3203a8c
a76c4ac
7ac6163
 
 
 
 
 
 
 
cbff5e0
7ac6163
dd0b28c
 
 
 
7ac6163
 
dd0b28c
 
 
 
7ac6163
 
 
 
 
 
 
2e3db11
 
 
 
 
 
 
 
 
 
 
 
7ac6163
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
cbff5e0
7ac6163
 
cbff5e0
 
 
7ac6163
 
 
 
 
 
 
3203a8c
54df631
7ac6163
 
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
"""
CrownCode backend entrypoint with enhanced error handling.
"""

from __future__ import annotations

import os

from fastapi import FastAPI, Request
from fastapi.middleware.cors import CORSMiddleware
from fastapi.responses import JSONResponse

from .routes.health import router as health_router
from .routes.youtube import router as youtube_router
from .routes.data_processing import router as data_processing_router
from .routes.analyze import router as analyze_router
from .routes.commend import router as commend_router
from .services.logging_config import setup_logging, get_logger


setup_logging(level=os.getenv("LOG_LEVEL", "INFO"))
logger = get_logger(__name__)


def _load_origins() -> list[str]:
    raw = os.getenv("CROWNCODE_CORS_ORIGINS") or os.getenv("CORS_ORIGIN") or "http://localhost:3000"
    if raw.strip() == "*":
        logger.warning(
            "CORS wildcard '*' is not recommended for production. "
            "Set CROWNCODE_CORS_ORIGINS to an explicit origin list."
        )
        return ["*"]
    origins = [origin.strip() for origin in raw.split(",") if origin.strip()]
    if not origins:
        # No origins configured — default to localhost for development
        origins = ["http://localhost:3000"]
        logger.warning("No CORS origins configured, defaulting to localhost")
    logger.info(f"CORS configured for origins: {origins}")
    return origins


app = FastAPI(title="CrownCode Backend API", version="0.1.0")


@app.get("/")
async def root():
    """Root endpoint for health check and API info."""
    return {
        "name": "CrownCode Backend API",
        "version": "0.1.0",
        "status": "running",
        "docs": "/docs",
        "health": "/api/health"
    }


@app.exception_handler(ValueError)
async def value_error_handler(request: Request, exc: ValueError) -> JSONResponse:
    logger.warning(f"Validation error: {exc}")
    return JSONResponse(
        status_code=400,
        content={"detail": str(exc), "type": "validation_error"}
    )


@app.exception_handler(FileNotFoundError)
async def file_not_found_handler(request: Request, exc: FileNotFoundError) -> JSONResponse:
    logger.error(f"File not found: {exc}")
    return JSONResponse(
        status_code=404,
        content={"detail": "Resource not found", "type": "not_found"}
    )


@app.exception_handler(Exception)
async def general_exception_handler(request: Request, exc: Exception) -> JSONResponse:
    logger.error(f"Unhandled exception: {type(exc).__name__}: {exc}", exc_info=True)
    return JSONResponse(
        status_code=500,
        content={"detail": "Internal server error", "type": "server_error"}
    )


_origins = _load_origins()
app.add_middleware(
    CORSMiddleware,
    allow_origins=_origins,
    # credentials=True is only safe with an explicit origin list, not wildcard
    allow_credentials="*" not in _origins,
    allow_methods=["*"],
    allow_headers=["*"],
)

app.include_router(health_router)
app.include_router(youtube_router)
app.include_router(data_processing_router)
app.include_router(analyze_router)
app.include_router(commend_router)

logger.info("CrownCode backend API initialized")