diff --git a/app/__init__.py b/app/__init__.py new file mode 100644 index 0000000..539ac85 --- /dev/null +++ b/app/__init__.py @@ -0,0 +1 @@ +# This makes app a package \ No newline at end of file diff --git a/app/api/__init__.py b/app/api/__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..8cc3bc6 --- /dev/null +++ b/app/db/__init__.py @@ -0,0 +1 @@ +# Database package \ No newline at end of file diff --git a/app/db/base.py b/app/db/base.py new file mode 100644 index 0000000..7c2377a --- /dev/null +++ b/app/db/base.py @@ -0,0 +1,3 @@ +from sqlalchemy.ext.declarative import declarative_base + +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..dc6a1af --- /dev/null +++ b/app/db/session.py @@ -0,0 +1,29 @@ +from pathlib import Path +from sqlalchemy import create_engine +from sqlalchemy.orm import sessionmaker + +from .base import Base + +# Database setup with absolute path as specified in guidelines +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) + +# Create tables +Base.metadata.create_all(bind=engine) + +# Dependency to get database session +def get_db(): + 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..d8cfe8a --- /dev/null +++ b/app/models/__init__.py @@ -0,0 +1 @@ +# Models package \ No newline at end of file diff --git a/app/models/todo.py b/app/models/todo.py new file mode 100644 index 0000000..054e045 --- /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/app/schemas/__init__.py b/app/schemas/__init__.py new file mode 100644 index 0000000..40587b8 --- /dev/null +++ b/app/schemas/__init__.py @@ -0,0 +1 @@ +# Schemas package \ No newline at end of file diff --git a/app/schemas/todo.py b/app/schemas/todo.py new file mode 100644 index 0000000..3065b8f --- /dev/null +++ b/app/schemas/todo.py @@ -0,0 +1,26 @@ +from datetime import datetime +from typing import Optional +from pydantic import BaseModel + + +class TodoCreate(BaseModel): + title: str + description: Optional[str] = None + + +class TodoUpdate(BaseModel): + title: Optional[str] = None + description: Optional[str] = None + completed: Optional[bool] = None + + +class TodoResponse(BaseModel): + id: int + title: str + description: Optional[str] = None + completed: bool + created_at: datetime + updated_at: datetime + + class Config: + from_attributes = True \ No newline at end of file diff --git a/main.py b/main.py new file mode 100644 index 0000000..7c19cdf --- /dev/null +++ b/main.py @@ -0,0 +1,43 @@ +from fastapi import FastAPI +from fastapi.middleware.cors import CORSMiddleware + +app = FastAPI( + title="Todo App API", + description="A simple Todo application API built with FastAPI", + version="1.0.0", + openapi_url="/openapi.json", + docs_url="/docs", + redoc_url="/redoc" +) + +# Configure CORS +app.add_middleware( + CORSMiddleware, + allow_origins=["*"], + allow_credentials=True, + allow_methods=["*"], + allow_headers=["*"], +) + + +@app.get("/") +async def root(): + """Base endpoint that returns app information""" + return { + "title": "Todo App API", + "description": "A simple Todo application API built with FastAPI", + "version": "1.0.0", + "documentation": "/docs", + "health_check": "/health" + } + + +@app.get("/health") +async def health_check(): + """Health check endpoint""" + return {"status": "healthy", "message": "Todo App API is running"} + + +if __name__ == "__main__": + import uvicorn + uvicorn.run(app, host="0.0.0.0", port=8000) \ No newline at end of file diff --git a/requirements.txt b/requirements.txt new file mode 100644 index 0000000..ea8e47b --- /dev/null +++ b/requirements.txt @@ -0,0 +1,7 @@ +fastapi==0.104.1 +uvicorn==0.24.0 +sqlalchemy==2.0.23 +alembic==1.13.1 +pydantic==2.5.0 +python-multipart==0.0.6 +ruff==0.1.7 \ No newline at end of file