diff --git a/app/__init__.py b/app/__init__.py new file mode 100644 index 0000000..e69de29 diff --git a/app/db/__init__.py b/app/db/__init__.py new file mode 100644 index 0000000..e69de29 diff --git a/app/db/base.py b/app/db/base.py new file mode 100644 index 0000000..9d46b7b --- /dev/null +++ b/app/db/base.py @@ -0,0 +1,19 @@ +from sqlalchemy import create_engine +from sqlalchemy.ext.declarative import declarative_base +from sqlalchemy.orm import sessionmaker +from pathlib import Path + +# Database setup +DB_DIR = Path("/app/storage/db") +DB_DIR.mkdir(parents=True, exist_ok=True) + +SQLALCHEMY_DATABASE_URL = f"sqlite:///{DB_DIR}/db.sqlite" + +engine = create_engine( + SQLALCHEMY_DATABASE_URL, + connect_args={"check_same_thread": False} +) + +SessionLocal = sessionmaker(autocommit=False, autoflush=False, bind=engine) + +Base = declarative_base() \ No newline at end of file diff --git a/app/db/session.py b/app/db/session.py new file mode 100644 index 0000000..5ac3870 --- /dev/null +++ b/app/db/session.py @@ -0,0 +1,13 @@ +from sqlalchemy.orm import Session +from app.db.base import SessionLocal + + +def get_db() -> Session: + """ + Dependency to get database session. + """ + db = SessionLocal() + try: + yield db + finally: + db.close() \ No newline at end of file diff --git a/app/models/__init__.py b/app/models/__init__.py new file mode 100644 index 0000000..e69de29 diff --git a/app/models/todo.py b/app/models/todo.py new file mode 100644 index 0000000..2bb7ef1 --- /dev/null +++ b/app/models/todo.py @@ -0,0 +1,15 @@ +from datetime import datetime +from sqlalchemy import Column, Integer, String, Text, Boolean, DateTime + +from app.db.base import Base + + +class Todo(Base): + __tablename__ = "todos" + + id = Column(Integer, primary_key=True, index=True) + title = Column(String(255), nullable=False) + description = Column(Text, nullable=True) + completed = Column(Boolean, default=False, nullable=False) + created_at = Column(DateTime, default=datetime.utcnow, nullable=False) + updated_at = Column(DateTime, default=datetime.utcnow, onupdate=datetime.utcnow, nullable=False) \ No newline at end of file diff --git a/main.py b/main.py new file mode 100644 index 0000000..9965fd3 --- /dev/null +++ b/main.py @@ -0,0 +1,65 @@ +from fastapi import FastAPI +from fastapi.middleware.cors import CORSMiddleware +from fastapi.responses import JSONResponse +from app.api.v1.api import api_router +from app.core.config import settings + +# Create FastAPI app instance +app = FastAPI( + title=settings.PROJECT_NAME, + description="A simple Todo API built with FastAPI", + version="1.0.0", + openapi_url="/openapi.json", +) + +# Add CORS middleware to allow all origins +app.add_middleware( + CORSMiddleware, + allow_origins=["*"], # Allow all origins + allow_credentials=True, + allow_methods=["*"], + allow_headers=["*"], +) + +# Include API router +app.include_router(api_router, prefix="/api/v1") + + +@app.get("/") +async def root(): + """ + Root endpoint that returns basic app information. + """ + return JSONResponse( + content={ + "title": settings.PROJECT_NAME, + "description": "A simple Todo API built with FastAPI", + "version": "1.0.0", + "documentation": "/docs", + "health_check": "/health" + } + ) + + +@app.get("/health") +async def health_check(): + """ + Health check endpoint to report application status. + """ + return JSONResponse( + content={ + "status": "healthy", + "service": settings.PROJECT_NAME, + "version": "1.0.0" + } + ) + + +if __name__ == "__main__": + import uvicorn + uvicorn.run( + "main:app", + host="0.0.0.0", + port=8000, + reload=True + ) \ No newline at end of file diff --git a/requirements.txt b/requirements.txt new file mode 100644 index 0000000..dfd48ca --- /dev/null +++ b/requirements.txt @@ -0,0 +1,10 @@ +fastapi==0.104.1 +uvicorn[standard]==0.24.0 +sqlalchemy==2.0.23 +alembic==1.12.1 +pydantic==2.5.0 +pydantic-settings==2.1.0 +python-multipart==0.0.6 +passlib[bcrypt]==1.7.4 +python-jose[cryptography]==3.3.0 +ruff==0.1.6 \ No newline at end of file