Phase 1: Project Setup & Architecture
The Stack: Why FastAPI + PostgreSQL + Docker
What We're Building
Welcome to TaskFlow — a production-grade task management REST API. By the end of this course, you'll have built a fully functional API that handles:
- User management — Registration, login, JWT authentication
- Projects — Create and manage project workspaces
- Tasks — Full CRUD with status tracking, priorities, and assignments
- Role-based access — Owners, admins, and members with different permissions
This isn't a toy project. TaskFlow uses the same architecture patterns you'll find at companies shipping real software.
What Each Piece Is Responsible For
A stack is easier to reason about as a stack of responsibilities than as a list of package names. Every request that enters TaskFlow crosses these boundaries in order, and each boundary is where a specific class of bug gets caught:
One TaskFlow request, top to bottom
The payoff of this arrangement is narrow blame. When a request fails, the layer that rejected it tells you which kind of mistake you made — a 422 is a contract problem, a pool timeout is a capacity problem, a constraint violation is a modelling problem. Stacks that blur these boundaries make every bug feel the same.
Where the version numbers live
This course does not quote version numbers in prose, and that is deliberate. Prose pins go stale silently: nothing throws an error, the text just quietly becomes wrong. Pins belong in two places where the machine reads them and a mismatch actually surfaces:
requirements.txt— resolved on everypip install, so a bad constraint fails loudly.- The
Dockerfileanddocker-compose.ymlimage tags — resolved on every build.
For current releases, go to the source: FastAPI, SQLAlchemy, Alembic, Pydantic, PostgreSQL, Redis, Python and Docker Compose.
One habit worth forming now: read the support policy, not just the latest number. PostgreSQL's versioning page tells you how long each major is supported, and Python's version page tells you when a release stops getting security fixes. Those dates are what should drive an upgrade, not novelty.
Why Not Django REST Framework?
Presenting a framework without its cost reads as marketing, so here is the honest comparison. Both of these ship real APIs; they are optimised for different bets.
FastAPI vs Django REST Framework for TaskFlow
FastAPI
- Async all the way down, so a slow query parks a coroutine instead of a worker
- OpenAPI comes from the same type hints that do the validation, so docs cannot drift from behaviour
- You assemble only the layers you need — no admin, no templates, no ORM opinion
- You assemble the layers yourself: auth, migrations, admin tooling and project structure are all decisions you have to make and defend
- Async correctness is on you — one blocking call inside an async handler stalls the whole event loop, and nothing warns you
- Smaller set of drop-in third-party apps, so 'is there a package for this' is answered 'no' more often
Django REST Framework
- Auth, permissions, admin, migrations and the ORM arrive already wired together and already argued about
- The built-in admin is genuinely hard to beat for internal CRUD and support tooling
- A very deep ecosystem — for most common requirements a maintained package already exists
- Async support is partial rather than end-to-end, so an async-heavy workload fights the framework
- You carry the parts you do not use, in image size, startup time and cognitive load
- Serializers are a second modelling language to learn on top of the ORM models
The short version: pick DRF when the product is a Django application that also has an API. Pick FastAPI when the product is the API and you expect to be I/O-bound — which is exactly TaskFlow.
Project Structure
Here's the directory layout we'll build throughout this course:
taskflow/
├── docker-compose.yml # Services: app, postgres, redis
├── Dockerfile # Multi-stage build for the API
├── requirements.txt # Pinned dependencies
├── .env # Environment variables (never commit)
├── alembic.ini # Alembic configuration
├── alembic/ # Migration scripts
│ └── versions/
├── app/
│ ├── __init__.py
│ ├── main.py # FastAPI application entry point
│ ├── core/
│ │ ├── __init__.py
│ │ ├── config.py # Settings via Pydantic
│ │ ├── database.py # SQLAlchemy engine & session
│ │ ├── security.py # JWT & password hashing
│ │ └── redis.py # Redis connection
│ ├── api/
│ │ ├── __init__.py
│ │ ├── deps.py # Dependency injection
│ │ └── v1/
│ │ ├── __init__.py
│ │ ├── auth.py # Login & registration
│ │ ├── users.py # User endpoints
│ │ ├── projects.py # Project endpoints
│ │ └── tasks.py # Task endpoints
│ ├── models/
│ │ ├── __init__.py
│ │ ├── user.py # User SQLAlchemy model
│ │ ├── project.py # Project model
│ │ └── task.py # Task model
│ ├── schemas/
│ │ ├── __init__.py
│ │ ├── user.py # User Pydantic schemas
│ │ ├── project.py # Project schemas
│ │ └── task.py # Task schemas
│ └── tests/
│ ├── __init__.py
│ ├── conftest.py # Fixtures & test database
│ ├── test_auth.py
│ ├── test_users.py
│ ├── test_projects.py
│ └── test_tasks.py
Each directory has a clear responsibility:
core/— Configuration, database connections, security utilitiesapi/— Route handlers organized by versionmodels/— SQLAlchemy ORM models (database tables)schemas/— Pydantic models (request/response validation)tests/— pytest test suite
What You'll Have After This Module
- A running Docker Compose stack with FastAPI, PostgreSQL, and Redis
- A health check endpoint at
GET /healththat confirms all services are connected - A clean project structure ready for the database models, auth system, and API routes we'll build in the next modules
- Pinned dependencies so your environment is reproducible anywhere
One thing to watch for in the lab: a dependency file can be internally contradictory even when every single line in it names a real, current package. pip install is the only thing that finds that out. Run it before you write a line of application code.
Next: Hands-on lab — Initialize the TaskFlow project :::
Sign in to rate