diff --git a/backend/.env.example b/backend/.env.example new file mode 100644 index 0000000..bf81915 --- /dev/null +++ b/backend/.env.example @@ -0,0 +1,3 @@ +DATABASE_URL=postgresql+asyncpg://codetutor:codetutor@localhost:5432/codetutor +DEBUG=false +CORS_ORIGINS=["http://localhost:3000"] diff --git a/backend/pyproject.toml b/backend/pyproject.toml new file mode 100644 index 0000000..7f4e62f --- /dev/null +++ b/backend/pyproject.toml @@ -0,0 +1,86 @@ +[project] +name = "codetutor-backend" +version = "0.1.0" +description = "CodeTutor API - Coding interview preparation backend" +readme = "readme.md" +requires-python = ">=3.12" +dependencies = [ + "fastapi>=0.115.0", + "uvicorn[standard]>=0.32.0", + "sqlalchemy>=2.0.36", + "asyncpg>=0.30.0", + "pydantic>=2.10.0", + "pydantic-settings>=2.6.0", + "alembic>=1.14.0", + "python-slugify>=8.0.0", + "pyyaml>=6.0.0", +] + +[project.optional-dependencies] +dev = [ + "pytest>=8.3.0", + "pytest-asyncio>=0.24.0", + "pytest-cov>=6.0.0", + "httpx>=0.28.0", + "ruff>=0.8.0", + "mypy>=1.13.0", + "types-pyyaml>=6.0.0", +] + +[build-system] +requires = ["hatchling"] +build-backend = "hatchling.build" + +[tool.hatch.build.targets.wheel] +packages = ["src"] + +[tool.ruff] +line-length = 100 +target-version = "py312" +src = ["src"] + +[tool.ruff.lint] +select = [ + "E", # pycodestyle errors + "W", # pycodestyle warnings + "F", # pyflakes + "I", # isort + "B", # flake8-bugbear + "C4", # flake8-comprehensions + "UP", # pyupgrade + "ARG", # flake8-unused-arguments + "SIM", # flake8-simplify +] +ignore = [ + "E501", # line too long (handled by formatter) +] + +[tool.ruff.lint.isort] +known-first-party = ["src"] + +[tool.mypy] +python_version = "3.12" +strict = true +warn_return_any = true +warn_unused_ignores = true +plugins = ["pydantic.mypy"] + +[[tool.mypy.overrides]] +module = ["asyncpg.*"] +ignore_missing_imports = true + +[tool.pytest.ini_options] +asyncio_mode = "auto" +asyncio_default_fixture_loop_scope = "function" +testpaths = ["tests"] +addopts = "-v --cov=src --cov-report=term-missing" + +[tool.coverage.run] +source = ["src"] +branch = true + +[tool.coverage.report] +exclude_lines = [ + "pragma: no cover", + "if TYPE_CHECKING:", +] diff --git a/backend/readme.md b/backend/readme.md new file mode 100644 index 0000000..453a2c9 --- /dev/null +++ b/backend/readme.md @@ -0,0 +1,43 @@ +# CodeTutor Backend + +FastAPI backend for the CodeTutor coding interview preparation application. + +## Setup + +```bash +# Install dependencies +pip install -e ".[dev]" + +# Run migrations +alembic upgrade head + +# Load content data +python scripts/load_data.py + +# Start development server +uvicorn src.main:app --reload +``` + +## API Endpoints + +- `GET /api/questions` - List questions with filters +- `GET /api/questions/{slug}` - Question detail +- `GET /api/categories` - List categories +- `GET /api/patterns` - List patterns +- `GET /api/patterns/{slug}` - Pattern detail +- `GET /api/stats` - Aggregate statistics +- `GET /api/health` - Health check + +## Testing + +```bash +pytest +``` + +## Code Quality + +```bash +ruff check . +ruff format --check . +mypy src/ +```