From 7594039fd07db2bfd050fba3fbc503a20ec2d1a0 Mon Sep 17 00:00:00 2001 From: agent-bot Date: Mon, 17 Aug 2026 16:55:03 +0000 Subject: [PATCH] WIP checkpoint: Scaffold FastAPI backend project structure --- backend/__init__.py | 0 backend/app/__init__.py | 0 backend/app/config.py | 32 ++++++++++++++++++++++++++++++++ backend/app/database.py | 38 ++++++++++++++++++++++++++++++++++++++ backend/app/main.py | 36 ++++++++++++++++++++++++++++++++++++ 5 files changed, 106 insertions(+) create mode 100644 backend/__init__.py create mode 100644 backend/app/__init__.py create mode 100644 backend/app/config.py create mode 100644 backend/app/database.py create mode 100644 backend/app/main.py diff --git a/backend/__init__.py b/backend/__init__.py new file mode 100644 index 0000000..e69de29 diff --git a/backend/app/__init__.py b/backend/app/__init__.py new file mode 100644 index 0000000..e69de29 diff --git a/backend/app/config.py b/backend/app/config.py new file mode 100644 index 0000000..35109a7 --- /dev/null +++ b/backend/app/config.py @@ -0,0 +1,32 @@ +from pydantic_settings import BaseSettings +from functools import lru_cache + + +class Settings(BaseSettings): + # Database + DATABASE_URL: str = "postgresql+asyncpg://agp_user:agp_password@localhost:5432/agp_db" + + # Redis + REDIS_URL: str = "redis://localhost:6379/0" + + # JWT + SECRET_KEY: str = "change-me-to-a-secure-random-string" + ALGORITHM: str = "HS256" + ACCESS_TOKEN_EXPIRE_MINUTES: int = 30 + + # App + DEBUG: bool = True + CORS_ORIGINS: str = "http://localhost:8080,http://localhost:3000" + + @property + def cors_origins_list(self) -> list[str]: + return [origin.strip() for origin in self.CORS_ORIGINS.split(",")] + + class Config: + env_file = ".env" + case_sensitive = True + + +@lru_cache() +def get_settings() -> Settings: + return Settings() diff --git a/backend/app/database.py b/backend/app/database.py new file mode 100644 index 0000000..1002c8d --- /dev/null +++ b/backend/app/database.py @@ -0,0 +1,38 @@ +"""Async database engine and session factory.""" + +from sqlalchemy.ext.asyncio import ( + AsyncSession, + async_sessionmaker, + create_async_engine, +) +from sqlalchemy.orm import DeclarativeBase + +from app.config import settings + +engine = create_async_engine( + settings.database_url, + echo=settings.DEBUG, + pool_size=10, + max_overflow=20, +) + +async_session_factory = async_sessionmaker( + engine, + class_=AsyncSession, + expire_on_commit=False, +) + + +class Base(DeclarativeBase): + pass + + +async def get_db() -> AsyncSession: + """Dependency that yields an async database session.""" + async with async_session_factory() as session: + try: + yield session + await session.commit() + except Exception: + await session.rollback() + raise diff --git a/backend/app/main.py b/backend/app/main.py new file mode 100644 index 0000000..e3210e0 --- /dev/null +++ b/backend/app/main.py @@ -0,0 +1,36 @@ +"""FastAPI application entry point.""" + +from contextlib import asynccontextmanager + +from fastapi import FastAPI + +from app.config import settings +from app.routers import auth, users, worlds, assets + + +@asynccontextmanager +async def lifespan(app: FastAPI): + """Application lifespan: startup and shutdown events.""" + # Startup: initialize database, connect to Redis, etc. + yield + # Shutdown: close connections, cleanup + + +app = FastAPI( + title=settings.app_name, + version=settings.app_version, + description="Agentic Game Platform - Backend API", + lifespan=lifespan, +) + +# Include routers +app.include_router(auth.router, prefix="/api/auth", tags=["auth"]) +app.include_router(users.router, prefix="/api/users", tags=["users"]) +app.include_router(worlds.router, prefix="/api/worlds", tags=["worlds"]) +app.include_router(assets.router, prefix="/api/assets", tags=["assets"]) + + +@app.get("/api/health") +async def health_check(): + """Simple health check endpoint.""" + return {"status": "ok", "app": settings.app_name}