Backend API for the AttendEase attendance management system, built with FastAPI and PostgreSQL.
- Framework: FastAPI
- Database: PostgreSQL 16
- ORM: SQLAlchemy 2.0
- Migrations: Alembic
- Validation: Pydantic v2
app/
├── main.py # FastAPI application entry point
├── core/
│ └── config.py # Settings and environment variables
├── db/
│ ├── base.py # Imports all models for Alembic discovery
│ ├── base_class.py # SQLAlchemy declarative Base class
│ └── session.py # Database engine and session factory
├── models/ # SQLAlchemy ORM models (one file per entity)
│ ├── item.py
│ └── user.py
├── schemas/ # Pydantic request/response schemas
│ ├── item.py
│ └── user.py
├── crud/ # Database CRUD operations
│ ├── base.py # Generic CRUDBase class
│ ├── crud_item.py
│ └── crud_user.py
└── api/
├── deps.py # Shared dependencies (e.g. get_db)
└── v1/
├── api.py # v1 router aggregator
└── endpoints/ # Route handlers (one file per entity)
├── items.py
└── users.py
- Python 3.10+
- Docker (for PostgreSQL)
- Git
git clone <repository-url>
cd AttendEase/Backend# Create
python -m venv venv
# Activate (Linux/macOS/Git Bash)
source venv/Scripts/activate # Windows Git Bash
source venv/bin/activate # Linux/macOS
# Activate (PowerShell)
.\venv\Scripts\Activate.ps1pip install -r requirements.txtcp .env.example .envEdit .env with your database credentials:
DATABASE_URL=postgresql://user:password@localhost/dbnamedocker-compose up -duvicorn app.main:app --reloadThe API will be available at:
| URL | Description |
|---|---|
| http://127.0.0.1:8000 | Root health check |
| http://127.0.0.1:8000/docs | Swagger UI (interactive) |
| http://127.0.0.1:8000/redoc | ReDoc (read-only docs) |
Follow these steps to add a new entity (e.g. Attendance):
Create app/models/attendance.py:
from sqlalchemy import Column, Integer, String, DateTime
from app.db.base_class import Base
class Attendance(Base):
id = Column(Integer, primary_key=True, index=True)
student_id = Column(Integer, nullable=False)
timestamp = Column(DateTime, nullable=False)Then register it in app/models/__init__.py:
from .attendance import AttendanceAnd in app/db/base.py:
from app.models.attendance import AttendanceCreate app/schemas/attendance.py:
from datetime import datetime
from typing import Optional
from pydantic import BaseModel
class AttendanceBase(BaseModel):
student_id: int
timestamp: datetime
class AttendanceCreate(AttendanceBase):
pass
class AttendanceUpdate(AttendanceBase):
student_id: Optional[int] = None
timestamp: Optional[datetime] = None
class Attendance(AttendanceBase):
id: int
model_config = {"from_attributes": True}Then register it in app/schemas/__init__.py:
from .attendance import Attendance, AttendanceCreate, AttendanceUpdateCreate app/crud/crud_attendance.py:
from app.crud.base import CRUDBase
from app.models.attendance import Attendance
from app.schemas.attendance import AttendanceCreate, AttendanceUpdate
class CRUDAttendance(CRUDBase[Attendance, AttendanceCreate, AttendanceUpdate]):
pass
attendance = CRUDAttendance(Attendance)Then register it in app/crud/__init__.py:
from .crud_attendance import attendanceCreate app/api/v1/endpoints/attendance.py:
from typing import Any, List
from fastapi import APIRouter, Depends, HTTPException
from sqlalchemy.orm import Session
from app import crud, schemas
from app.api import deps
router = APIRouter()
@router.get("/", response_model=List[schemas.Attendance])
def read_attendances(
db: Session = Depends(deps.get_db),
skip: int = 0,
limit: int = 100,
) -> Any:
"""Retrieve attendance records."""
return crud.attendance.get_multi(db, skip=skip, limit=limit)
@router.post("/", response_model=schemas.Attendance)
def create_attendance(
*,
db: Session = Depends(deps.get_db),
obj_in: schemas.AttendanceCreate,
) -> Any:
"""Create new attendance record."""
return crud.attendance.create(db=db, obj_in=obj_in)In app/api/v1/api.py:
from app.api.v1.endpoints import attendance
api_router.include_router(attendance.router, prefix="/attendance", tags=["attendance"])In app/main.py, add the tag to openapi_tags:
{"name": "attendance", "description": "Attendance tracking operations."},- Follow PEP 8 formatting
- Use 2 blank lines before top-level classes and functions
- Comments should explain why, not what
- Run
flake8 app/before committing
# Start dev server
uvicorn app.main:app --reload
# Start database
docker-compose up -d
# Stop database
docker-compose down
# Lint code
flake8 app/
# Freeze dependencies
pip freeze > requirements.txt