diff --git a/backend/__init__.py b/backend/__init__.py new file mode 100644 index 0000000..e70cddd --- /dev/null +++ b/backend/__init__.py @@ -0,0 +1 @@ +# Debate Backend Package diff --git a/backend/app/__init__.py b/backend/app/__init__.py new file mode 100644 index 0000000..cc1422d --- /dev/null +++ b/backend/app/__init__.py @@ -0,0 +1 @@ +# Debate Backend Application diff --git a/backend/app/api/__init__.py b/backend/app/api/__init__.py new file mode 100644 index 0000000..28b07ef --- /dev/null +++ b/backend/app/api/__init__.py @@ -0,0 +1 @@ +# API package diff --git a/backend/app/api/v1/__init__.py b/backend/app/api/v1/__init__.py new file mode 100644 index 0000000..6c2f33c --- /dev/null +++ b/backend/app/api/v1/__init__.py @@ -0,0 +1 @@ +# API v1 package diff --git a/backend/app/api/v1/endpoints/__init__.py b/backend/app/api/v1/endpoints/__init__.py new file mode 100644 index 0000000..f7e1d0d --- /dev/null +++ b/backend/app/api/v1/endpoints/__init__.py @@ -0,0 +1 @@ +# API v1 endpoints package diff --git a/backend/app/api/v1/endpoints/health.py b/backend/app/api/v1/endpoints/health.py new file mode 100644 index 0000000..a2b2fab --- /dev/null +++ b/backend/app/api/v1/endpoints/health.py @@ -0,0 +1,17 @@ +"""Health check endpoints.""" + +from fastapi import APIRouter + +router = APIRouter() + + +@router.get("") +async def health_check() -> dict[str, str]: + """Basic health check endpoint.""" + return {"status": "healthy"} + + +@router.get("/ready") +async def readiness_check() -> dict[str, str]: + """Readiness check endpoint (DB check added in plan 01-02).""" + return {"status": "ready"} diff --git a/backend/app/api/v1/router.py b/backend/app/api/v1/router.py new file mode 100644 index 0000000..959b459 --- /dev/null +++ b/backend/app/api/v1/router.py @@ -0,0 +1,9 @@ +"""API v1 router configuration.""" + +from fastapi import APIRouter + +from backend.app.api.v1.endpoints import health + +api_router = APIRouter() + +api_router.include_router(health.router, prefix="/health", tags=["health"]) diff --git a/backend/app/core/__init__.py b/backend/app/core/__init__.py new file mode 100644 index 0000000..ab0bf36 --- /dev/null +++ b/backend/app/core/__init__.py @@ -0,0 +1 @@ +# Core application components diff --git a/backend/app/core/config.py b/backend/app/core/config.py new file mode 100644 index 0000000..9a4adec --- /dev/null +++ b/backend/app/core/config.py @@ -0,0 +1,51 @@ +"""Application configuration via pydantic-settings.""" + +from pydantic_settings import BaseSettings + + +class Settings(BaseSettings): + """Application settings loaded from environment variables.""" + + # Database + database_url: str = "postgresql+asyncpg://debate:debate_dev@localhost:5433/debate" + + # Security + secret_key: str = "change-me-in-production" + csrf_secret_key: str = "change-me-in-production" + + # Environment + environment: str = "development" + debug: bool = True + + # CORS and trusted hosts + allowed_hosts: str = "localhost,127.0.0.1" + allowed_origins: str = "http://localhost:3000,http://127.0.0.1:3000" + + # Cookie settings + cookie_domain: str = "localhost" + + @property + def allowed_hosts_list(self) -> list[str]: + """Parse allowed hosts as a list.""" + return [h.strip() for h in self.allowed_hosts.split(",") if h.strip()] + + @property + def allowed_origins_list(self) -> list[str]: + """Parse allowed origins as a list.""" + return [o.strip() for o in self.allowed_origins.split(",") if o.strip()] + + @property + def is_production(self) -> bool: + """Check if running in production environment.""" + return self.environment == "production" + + class Config: + """Pydantic settings configuration.""" + + env_file = ".env" + env_file_encoding = "utf-8" + extra = "ignore" + + +# Global settings instance +settings = Settings() diff --git a/backend/app/main.py b/backend/app/main.py new file mode 100644 index 0000000..54488ab --- /dev/null +++ b/backend/app/main.py @@ -0,0 +1,24 @@ +"""FastAPI application entry point.""" + +from fastapi import FastAPI + +from backend.app.api.v1.router import api_router +from backend.app.core.config import settings + +app = FastAPI( + title="Debate API", + version="1.0.0", + description="Backend API for Debate - Linux distribution customization platform", + docs_url="/docs" if not settings.is_production else None, + redoc_url="/redoc" if not settings.is_production else None, + debug=settings.debug, +) + +# Include API routers +app.include_router(api_router, prefix="/api/v1") + + +@app.get("/health") +async def root_health() -> dict[str, str]: + """Root health check endpoint.""" + return {"status": "healthy"}