Phase 1: Project Setup & Architecture

The Stack: Why FastAPI + PostgreSQL + Docker

3 min read

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

HTTP layer
Validation boundary
Data access
Storage
Runtime

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 every pip install, so a bad constraint fails loudly.
  • The Dockerfile and docker-compose.yml image 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

our choice

FastAPI

Concurrency modelasync-native
API docsgenerated from type hints
Batteries includedfew, by design
Pros
  • 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
Cons
  • 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

Concurrency modelsync-first
API docsadd-on schema generation
Batteries includedmany
Pros
  • 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
Cons
  • 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 utilities
  • api/ — Route handlers organized by version
  • models/ — SQLAlchemy ORM models (database tables)
  • schemas/ — Pydantic models (request/response validation)
  • tests/ — pytest test suite

What You'll Have After This Module

  1. A running Docker Compose stack with FastAPI, PostgreSQL, and Redis
  2. A health check endpoint at GET /health that confirms all services are connected
  3. A clean project structure ready for the database models, auth system, and API routes we'll build in the next modules
  4. 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 :::

Quiz

Module 1 Quiz: Project Setup & Architecture

Take Quiz
Was this lesson helpful?

Sign in to rate