Skip to content

Repository files navigation

FastAPI movie theater

FastAPI Movie Theater is a RESTful API for managing a movie theater platform, built with Python and FastAPI. The service supports movie management, user interactions (comments, ratings, reactions, favourites) and an authentication system with role-based access control.

Features

  • JWT-based authentication
    • Access & refresh tokens
    • Role separation: users, moderators, admins
  • Custom user model
    • User registration
    • Account activation
    • Password change:
      • old password
      • refresh token
  • Movie management
    • Create, update, delete movies (staff/admin)
    • Pagination & filtering
  • User interactions
    • Post comments on movies
    • Add ratings (toggle / update)
    • React to movies
    • Add movies to favourites
  • Swagger & ReDoc
    • Auto-generated API documentation
  • Production-ready architecture
    • Async SQLAlchemy
    • Alembic migrations
    • Docker & Docker Compose support

Tech stack

Backend

  • Python 3.12+
  • FastAPI
  • Pydantic v2
  • SQLAlchemy (async)
  • Alembic

Database

  • SQLite (local / development)
  • PostgreSQL (production)

Infrastructure & DevOps

  • Docker & Docker Compose
  • Nginx (reverse proxy)
  • AWS EC2
  • GitHub Actions (CI)

API Documentation

Once the application is running, interactive documentation is available at:

  • Swagger UI:
    http://localhost:8000/docs
  • ReDoc:
    http://localhost:8000/redoc

Directory Tree

.
├── Dockerfile
├── README.MD
├── alembic.ini
├── commands
│   ├── run_migration.sh
│   ├── run_web_server_dev.sh
│   ├── run_web_server_prod.sh
│   ├── set_nginx_basic_auth.sh
│   ├── setup_mailhog_auth.sh
│   └── setup_minio.sh
├── configs
│   └── nginx
│       └── nginx.conf
├── docker
│   ├── mailhog
│   │   └── Dockerfile
│   ├── minio_mc
│   │   └── Dockerfile
│   ├── nginx
│   │   └── Dockerfile
│   └── tests
│       └── Dockerfile
├── docker-compose-dev.yml
├── docker-compose-prod.yml
├── docker-compose-tests.yml
├── init.sql
├── poetry.lock
├── pyproject.toml
├── pytest.ini
└── cinema
    ├── config
    │   ├── __init__.py
    │   ├── dependencies.py
    │   └── settings.py
    ├── database
    │   ├── __init__.py
    │   ├── migrations
    │   │   ├── README
    │   │   ├── env.py
    │   │   ├── script.py.mako
    │   │   └── versions
    │   │       ├── 2da0dc469be8_temp_migration.py
    │   │       ├── 32b1054a69e3_initial_migration.py
    │   │       └── 41cdafa531cf_temp_migration.py
    │   ├── models
    │   │   ├── __init__.py
    │   │   ├── accounts.py
    │   │   ├── base.py
    │   │   └── movies.py
    │   ├── populate.py
    │   ├── seed_data
    │   │   └── test_data.csv
    │   ├── session_postgresql.py
    │   ├── session_sqlite.py
    │   └── validators
    │       ├── __init__.py
    │       └── accounts.py
    ├── exceptions
    │   ├── __init__.py
    │   ├── email.py
    │   ├── security.py
    │   └── storage.py
    ├── main.py
    ├── notifications
    │   ├── __init__.py
    │   ├── emails.py
    │   ├── interfaces.py
    │   └── templates
    │       ├── activation_complete.html
    │       ├── activation_request.html
    │       ├── password_reset_complete.html
    │       └── password_reset_request.html
    ├── routes
    │   ├── __init__.py
    │   ├── accounts.py
    │   ├── genres.py
    │   ├── movies
    │   │   ├── movies.py
    │   │   ├── movies_comments.py
    │   │   ├── movies_favourites.py
    │   │   ├── movies_ratings.py
    │   │   ├── movies_reactions.py
    │   └── profiles.py
    ├── schemas
    │   ├── __init__.py
    │   ├── accounts.py
    │   ├── movies.py
    │   └── profiles.py
    ├── security
    │   ├── __init__.py
    │   ├── http.py
    │   ├── interfaces.py
    │   ├── passwords.py
    │   ├── token_manager.py
    │   └── utils.py
    ├── storages
    │   ├── __init__.py
    │   ├── interfaces.py
    │   └── s3.py
    ├── tests
    │   ├── __init__.py
    │   ├── conftest.py
    │   ├── doubles
    │   │   ├── __init__.py
    │   │   ├── fakes
    │   │   │   ├── __init__.py
    │   │   │   └── storage.py
    │   │   └── stubs
    │   │       ├── __init__.py
    │   │       └── emails.py
    │   ├── test_e2e
    │   │   ├── __init__.py
    │   │   ├── test_email_notification.py
    │   │   └── test_storage.py
    │   └── test_integration
    │       ├── __init__.py
    │       ├── test_accounts.py
    │       ├── test_movies.py
    │       ├── test_movies_comments.py
    │       ├── test_movies_favourites.py
    │       ├── test_movies_ratings.py
    │       ├── test_movies_reactions.py
    │       └── test_profiles.py
    └── validation
        ├── __init__.py
        └── profile.py

Directory and File Descriptions

Below is a detailed description of each directory and its contents to help you navigate and understand the project's structure.

Root Directory (.)

  • Dockerfile: Defines the Docker image configuration for the application, including base image, dependencies, and startup commands.
  • README.MD: The main documentation file providing an overview, setup instructions, and usage guidelines for the project.
  • alembic.ini: Configuration file for Alembic, a database migration tool used with SQLAlchemy.
  • init.sql: SQL script for initializing the database with necessary tables and data.

commands/

Contains shell scripts that automate various tasks related to the project.

  • run_migration.sh: Executes database migrations using Alembic to update the database schema.
  • run_web_server_dev.sh: Starts the web server in development mode, typically with debugging enabled.
  • run_web_server_prod.sh: Starts the web server in production mode, optimized for performance and security.
  • set_nginx_basic_auth.sh: Configures Nginx with Basic Authentication to secure specific endpoints.
  • setup_mailhog_auth.sh: Sets up authentication for MailHog, an email testing tool.
  • setup_minio.sh: Configures MinIO, an object storage server compatible with Amazon S3 APIs.

configs/nginx/

Holds configuration files for Nginx, the web server used to serve the application.

  • nginx.conf: The main Nginx configuration file that sets up server blocks, proxy settings, and security configurations like Basic Authentication.

docker/

Contains Dockerfiles for various services used in the project, facilitating containerization and orchestration.

  • mailhog/Dockerfile: Dockerfile for setting up the MailHog email testing tool.
  • minio_mc/Dockerfile: Dockerfile for configuring MinIO client tools.
  • nginx/Dockerfile: Dockerfile for building the custom Nginx image with necessary configurations and scripts.
  • tests/Dockerfile: Dockerfile for setting up the testing environment, ensuring consistency across different environments.

Docker Compose Files

Manage multi-container Docker applications, defining services, networks, and volumes.

  • docker-compose-dev.yml: Configuration for the development environment, including services, volumes, and ports tailored for development workflows.
  • docker-compose-prod.yml: Configuration for the production environment, optimized for performance, security, and scalability.
  • docker-compose-tests.yml: Configuration for running tests within Docker containers, ensuring isolation and consistency during testing.

cinema/

The core source code of the application, organized into various modules and components for maintainability and scalability.

cinema/config/

Handles application configurations and dependencies.

  • __init__.py: Initializes the config module.
  • dependencies.py: Defines dependencies for the application, often used with FastAPI for dependency injection.
  • settings.py: Manages application settings, possibly using environment variables for configuration.
cinema/database/

Manages database interactions, migrations, and models.

  • __init__.py: Initializes the database module.
  • models/: Defines the database models using SQLAlchemy.
    • __init__.py: Initializes the models module.
    • accounts.py: Defines the Account model and related database structures.
    • base.py: Base model definitions and common configurations.
    • movies.py: Defines the Movie model and related database structures.
  • populate.py: Script to populate the database with initial data.
  • seed_data/: Contains CSV files used for seeding the database.
    • test_data.csv: Additional seed data for testing purposes.
  • session_postgresql.py: Manages PostgreSQL database sessions.
  • session_sqlite.py: Manages SQLite database sessions for development or testing.
  • validators/: Contains data validation logic.
    • __init__.py: Initializes the validators module.
    • accounts.py: Validation functions and classes for account-related data.
cinema/exceptions/

Defines custom exception classes to handle various error scenarios within the application.

  • __init__.py: Initializes the exceptions module.
  • email.py: Exceptions related to email operations.
  • security.py: Exceptions related to security and authentication.
  • storage.py: Exceptions related to storage and file handling.
cinema/main.py

The main entry point of the application, typically initializing the FastAPI app, including middleware, routers, and other configurations.

cinema/notifications/

Handles email notifications and related functionalities.

  • __init__.py: Initializes the notifications module.
  • emails.py: Functions and classes for sending emails.
  • interfaces.py: Defines interfaces or abstract classes for notification services.
  • templates/: HTML templates used for email notifications.
    • activation_complete.html: Template for activation completion emails.
    • activation_request.html: Template for activation request emails.
    • password_reset_complete.html: Template for password reset completion emails.
    • password_reset_request.html: Template for password reset request emails.
cinema/routes/

Defines the API endpoints and their respective handlers.

  • __init__.py: Initializes the routes module.
  • accounts.py: Routes related to user accounts (e.g., registration, login).
  • movies/: Routes related to movies (e.g., registration, login).
    • __init__.py: Initializes the movies package.
    • movies.py: Routes related to movie data (e.g., listing, details).
    • movies_comments.py: Routes related to movie comments (e.g., listing, details).
    • movies_favourites.py: Routes related to movie comments (e.g., listing, details).
    • movies_ratings.py: Routes related to movie ratings.
    • movies_reactions.py: Routes related to movie reactions.
  • profiles.py: Routes related to user profiles.
cinema/schemas/

Defines the data schemas using Pydantic for request validation and response models.

  • __init__.py: Initializes the schemas module.
  • accounts.py: Schemas for account-related operations.
  • movies.py: Schemas for movie-related operations.
  • profiles.py: Schemas for profile-related operations.
cinema/security/

Manages authentication, authorization, and security-related functionalities.

  • __init__.py: Initializes the security module.
  • http.py: Handles HTTP security configurations, possibly OAuth or JWT setups.
  • interfaces.py: Defines interfaces for security components.
  • passwords.py: Functions for hashing and verifying passwords.
  • token_manager.py: Manages token creation, validation, and refreshing.
  • utils.py: Utility functions related to security.
cinema/storages/

Handles file storage, interfacing with storage services like Amazon S3.

  • __init__.py: Initializes the storages module.
  • interfaces.py: Defines interfaces for storage services.
  • s3.py: Implements storage functionalities using Amazon S3 APIs.
cinema/tests/

Contains all test cases to ensure the application's reliability and correctness.

  • __init__.py: Initializes the tests module.
  • conftest.py: Configuration file for pytest, defining fixtures and plugins.
  • doubles/: Contains test doubles like fakes and stubs for mocking dependencies.
    • __init__.py: Initializes the doubles module.
    • fakes/: Implements fake objects for testing.
      • __init__.py: Initializes the fakes module.
      • storage.py: Fake storage implementations for tests.
    • stubs/: Implements stubs for testing.
      • __init__.py: Initializes the stubs module.
      • emails.py: Stub implementations for email functionalities.
  • test_e2e/: End-to-End test cases.
    • __init__.py: Initializes the test_e2e module.
    • test_email_notification.py: Tests for email notification flows.
    • test_storage.py: Tests for storage functionalities.
  • test_integration/: Integration test cases.
    • __init__.py: Initializes the test_integration module.
    • test_accounts.py: Integration tests for account-related operations.
    • test_movies.py: Integration tests for movie-related operations.
    • test_movies_comments.py: Integration tests for movie comments operations.
    • test_movies_favourites.py: Integration tests for movie favourites operations.
    • test_movies_ratings.py: Integration tests for movie ratings operations.
    • test_movies_reactions.py: Integration tests for movie reactions operations.
    • test_profiles.py: Integration tests for profile-related operations.
cinema/validation/

Contains validation logic to ensure data integrity and correctness.

  • __init__.py: Initializes the validation module.
  • profile.py: Validation functions and classes for profile data.

This directory structure is thoughtfully organized to promote maintainability, scalability, and clarity. Here's a quick overview:

  • Configuration and Commands:

    • commands/: Automates routine tasks like migrations and server setup.
    • configs/nginx/: Houses Nginx configuration files.
  • Docker Setup:

    • docker/: Contains Dockerfiles for various services ensuring consistent containerization.
    • docker-compose-*.yml: Manages multi-container Docker applications for different environments (development, production, testing).
  • Source Code (cinema/):

    • Organized into submodules like config, database, routes, schemas, security, storages, notifications, exceptions, and validation to separate concerns and enhance code readability.
  • Testing:

    • cinema/tests/: Structured to support both End-to-End and Integration testing, utilizing test doubles for isolated testing scenarios.
  • Dependencies and Setup:

    • poetry.lock & pyproject.toml: Manage Python dependencies using Poetry.
    • alembic.ini: Configure database migrations with Alembic.
  • Miscellaneous:

    • init.sql: Initial SQL setup script.
    • README.MD: Project documentation.

services:
  db:
    image: 'postgres:latest'
    container_name: postgres_theater
    env_file:
      - .env
    ports:
      - "5432:5432"
    volumes:
      - ./init.sql:/docker-entrypoint-initdb.d/init.sql
      - postgres_theater_data:/var/lib/postgresql
    networks:
      - theater_network
    healthcheck:
      test: [ "CMD-SHELL", "pg_isready -U $POSTGRES_USER -d $POSTGRES_DB -h 127.0.0.1 || exit 1" ]
      interval: 10s
      timeout: 5s
      retries: 5
      start_period: 20s

  pgadmin:
    image: dpage/pgadmin4
    container_name: pgadmin_theater
    ports:
      - "3333:80"
    env_file:
      - .env
    depends_on:
      db:
        condition: service_healthy
    volumes:
      - pgadmin_theater_data:/var/lib/pgadmin
    networks:
      - theater_network

  web:
    restart: always
    build: .
    container_name: backend_theater
    command: [ "/bin/bash", "/commands/run_web_server_prod.sh" ]
    env_file:
      - .env
    environment:
      - LOG_LEVEL=debug
      - PYTHONPATH=/usr/src/fastapi
      - WATCHFILES_FORCE_POLLING=true
    ports:
      - "8000:8000"
    depends_on:
      db:
        condition: service_healthy
      minio:
        condition: service_healthy
    volumes:
      - ./src:/usr/src/fastapi
    networks:
      - theater_network

  migrator:
    build: .
    container_name: alembic_migrator_theater
    command: ["/bin/bash", "/commands/run_migration.sh"]
    depends_on:
      db:
        condition: service_healthy
    volumes:
      - ./src:/usr/src/fastapi
    env_file:
      - .env
    environment:
      - PYTHONPATH=/usr/src/fastapi
    networks:
      - theater_network

  mailhog:
    restart: always
    build:
      context: .
      dockerfile: ./docker/mailhog/Dockerfile
    container_name: mailhog_theater
    command: [ "/bin/bash", "-c", "/commands/setup_mailhog_auth.sh && MailHog" ]
    ports:
      - "8025:8025"
      - "1025:1025"
    env_file:
      - .env
    environment:
      MH_AUTH_FILE: /mailhog.auth
    networks:
      - theater_network

  minio:
    image: minio/minio:latest
    container_name: minio-theater
    command: server --console-address ":9001" /data
    ports:
      - "9000:9000"
      - "9001:9001"
    env_file:
      - .env
    volumes:
      - minio_data:/data
    healthcheck:
      test: [ "CMD", "curl", "-f", "http://localhost:9000/minio/health/live" ]
      interval: 10s
      timeout: 5s
      retries: 5
    networks:
      - theater_network

  minio_mc:
    build:
      context: .
      dockerfile: docker/minio_mc/Dockerfile
    container_name: minio_mc_theater
    command: ["/bin/sh", "-c", "/commands/setup_minio.sh"]
    depends_on:
      minio:
        condition: service_healthy
    env_file:
      - .env
    networks:
      - theater_network

  nginx:
    build:
      context: .
      dockerfile: docker/nginx/Dockerfile
    container_name: nginx
    restart: always
    ports:
      - "80:80"
    volumes:
      - ./configs/nginx/nginx.conf:/etc/nginx/nginx.conf:ro
    depends_on:
      - web
    env_file:
      - ./docker/nginx/.env
    networks:
      - theater_network

volumes:
  postgres_theater_data:
    driver: local
  pgadmin_theater_data:
    driver: local
  minio_data:
    driver: local

networks:
  theater_network:
    driver: bridge

Docker Compose Description

This docker-compose.yml defines a production-ready FastAPI movie theater stack with database, migrations, object storage, email testing, and reverse proxy, all connected through a single isolated Docker network.

Services Overview

  • db (PostgreSQL) Primary relational database for the application.

    • Initialized using init.sql
    • Persistent storage via Docker volume
    • Healthcheck ensures dependent services start only when DB is ready
  • pgadmin Web-based PostgreSQL administration tool.

    • Accessible on http://localhost:3333
    • Starts only after the database becomes healthy
  • web (FastAPI backend) Main application container.

    • Built from the project Dockerfile
    • Runs the production startup script
    • Mounts source code for flexibility
    • Depends on PostgreSQL and MinIO healthchecks
  • migrator (Alembic) Dedicated container for database migrations.

    • Runs Alembic migrations automatically
    • Ensures schema is up to date before app usage
    • Depends on healthy PostgreSQL service
  • mailhog Local SMTP testing service for email flows.

    • Web UI on http://localhost:8025
    • SMTP server on port 1025
    • Includes basic authentication setup
  • minio S3-compatible object storage (used for media/files).

    • API on port 9000
    • Admin console on port 9001
    • Persistent data stored in a Docker volume
    • Healthcheck ensures readiness before setup
  • minio_mc MinIO client container.

    • Automatically configures buckets and policies
    • Runs only after MinIO is healthy
  • nginx Reverse proxy for the FastAPI backend.

    • Exposes application on port 80
    • Uses a custom Nginx configuration
    • Routes traffic to the web service

Volumes

  • postgres_theater_data – PostgreSQL persistent storage
  • pgadmin_theater_data – pgAdmin configuration and state
  • minio_data – MinIO object storage data

Network

  • theater_network Custom bridge network that allows all services to communicate internally while keeping them isolated from other Docker stacks.

Nginx Dockerfile (docker/nginx/Dockerfile)

The Nginx Dockerfile customizes the Nginx image to include necessary packages and scripts for setting up Basic Authentication and other configurations.

# Use the official Nginx image as the base
FROM nginx:latest

# Install the necessary packages
RUN apt-get update && \
    apt-get install -y --no-install-recommends \
        apache2-utils \
        dos2unix \
        bash && \
    rm -rf /var/lib/apt/lists/*

# Copy command scripts into the container
COPY ./commands/set_nginx_basic_auth.sh /commands/set_nginx_basic_auth.sh

# Ensure Unix-style line endings for scripts
RUN dos2unix /commands/*.sh

# Make the scripts executable
RUN chmod +x /commands/*.sh

# Set the entry point to the Basic Auth setup script
ENTRYPOINT ["/commands/set_nginx_basic_auth.sh"]

# Run Nginx in the foreground to keep the container running
CMD ["nginx", "-g", "daemon off;"]
  • Key Steps:
    1. Base Image:

      • FROM nginx:latest: Starts with the latest official Nginx image.
    2. Install Necessary Packages:

      • apache2-utils: Provides utilities like htpasswd for managing Basic Authentication.
      • dos2unix: Converts DOS-style line endings to Unix-style, ensuring scripts run correctly.
      • bash: Provides the Bash shell for executing scripts.
    3. Copy Command Scripts:

      • COPY ./commands/set_nginx_basic_auth.sh /commands/set_nginx_basic_auth.sh: Adds the set_nginx_basic_auth.sh script to the container.
    4. Convert Line Endings:

      • RUN dos2unix /commands/*.sh: Ensures all shell scripts have Unix-style line endings.
    5. Make Scripts Executable:

      • RUN chmod +x /commands/*.sh: Grants execute permissions to the scripts.
    6. Set Entry Point:

      • ENTRYPOINT ["/commands/set_nginx_basic_auth.sh"]: Defines the script to run when the container starts, setting up Basic Authentication.
    7. Run Nginx in Foreground:

      • CMD ["nginx", "-g", "daemon off;"]: Starts Nginx in the foreground, ensuring the container remains active.

Nginx Configuration (configs/nginx/nginx.conf)

The Nginx configuration file sets up the server to handle HTTP requests, proxy them to the backend service, and secure specific endpoints with Basic Authentication.

events {}

http {
    upstream backend_theater {
        server web:8000;
    }

    server {
        listen 80 default_server;
        listen [::]:80 default_server;
        server_name _;

        location / {
            proxy_pass http://web:8000;
            proxy_set_header Host $host;
            proxy_set_header X-Real-IP $remote_addr;
            proxy_set_header X-Forwarded-For $proxy_add_x_forwarded_for;
            proxy_set_header X-Forwarded-Proto $scheme;
        }

        location /docs {
            include /etc/nginx/conf.d/auth.conf;

            proxy_pass http://web:8000/docs;
            proxy_set_header Host $host;
            proxy_set_header X-Real-IP $remote_addr;
            proxy_set_header X-Forwarded-For $proxy_add_x_forwarded_for;
            proxy_set_header X-Forwarded-Proto $scheme;
        }

        location /redoc {
            include /etc/nginx/conf.d/auth.conf;

            proxy_pass http://web:8000/redoc;
            proxy_set_header Host $host;
            proxy_set_header X-Real-IP $remote_addr;
            proxy_set_header X-Forwarded-For $proxy_add_x_forwarded_for;
            proxy_set_header X-Forwarded-Proto $scheme;
        }

        location /openapi.json {
            include /etc/nginx/conf.d/auth.conf;

            proxy_pass http://web:8000/openapi.json;
            proxy_set_header Host $host;
            proxy_set_header X-Real-IP $remote_addr;
            proxy_set_header X-Forwarded-For $proxy_add_x_forwarded_for;
            proxy_set_header X-Forwarded-Proto $scheme;
        }
    }
}
  • Key Configurations:
    1. Upstream Definition:

      • upstream backend_theater { server web:8000; }: Defines a group of backend servers. In this case, it points to the web service on port 8000.
    2. Server Block:

      • Listening Ports:
        • listen 80 default_server;: Listens on port 80 for IPv4.
        • listen [::]:80 default_server;: Listens on port 80 for IPv6.
      • Server Name:
        • server_name _;: Catches all server names not explicitly defined elsewhere.
    3. Location Blocks:

      • Root Location (/):

        • Purpose:
          Proxies all incoming traffic to the web service.
        • Configurations:
          • proxy_pass http://web:8000;: Forwards requests to the backend.
          • Header Settings:
            Ensures that the original request headers are preserved and forwarded to the backend.
      • Secure Locations (/docs, /redoc, /openapi.json):

        • Purpose:
          Protects API documentation and specification endpoints with Basic Authentication.
        • Configurations:
          • include /etc/nginx/conf.d/auth.conf;: Includes authentication configurations.
          • proxy_pass and Header Settings:
            Similar to the root location, proxies requests to the respective backend endpoints while preserving headers.

Summary of Docker Compose and Nginx Configuration

The docker-compose-prod.yml orchestrates a multi-container Docker application with the following key components:

  • Database Layer:

    • PostgreSQL (db): Stores application data.
    • PgAdmin (pgadmin): Provides a GUI for managing the PostgreSQL database.
  • Application Layer:

    • Web Server (web): Hosts the backend application, built from the project's source code.
    • Migrator (migrator): Manages database schema migrations to keep the database in sync with the application.
  • Auxiliary Services:

    • MailHog (mailhog): Captures outgoing emails for testing purposes without sending them to real recipients.
    • MinIO (minio): Offers object storage capabilities, serving as an alternative to AWS S3.
    • MinIO Client (minio_mc): Provides command-line tools to interact with the MinIO server.
  • Reverse Proxy and Security:

    • Nginx (nginx): Acts as a reverse proxy, directing traffic to the appropriate backend services and securing specific endpoints with Basic Authentication.
  • Data Persistence:

    • Volumes: Ensure data persistence for PostgreSQL, PgAdmin, and MinIO across container restarts.
  • Networking:

    • theater_network: A dedicated Docker network that isolates and facilitates communication between all services within the application stack.

GitHub Actions

GitHub Actions automates your software workflows, enabling continuous integration (CI) and continuous deployment (CD). This project utilizes GitHub Actions to ensure code quality through automated testing and to deploy the application seamlessly to AWS EC2.

CI (Continuous Integration)

The Continuous Integration (CI) pipeline is designed to automatically test your code whenever a pull request is made to the main branch. This ensures that new changes do not break existing functionality and adhere to code quality standards.

CI Pipeline Overview

The CI pipeline performs the following tasks:

  1. Checkout Code: Retrieves the latest code from the repository.
  2. Set Up Python: Configures the Python environment.
  3. Install Dependencies: Installs project dependencies using Poetry.
  4. Run flake8: Checks the code for style and syntax errors.
  5. Run Tests: Executes integration tests for different components of the application.
name: CI

on:
  push:
    branches: ["**"]
  pull_request:

concurrency:
  group: ${{ github.workflow }}-${{ github.ref }}
  cancel-in-progress: true

jobs:
  lint:
    runs-on: ubuntu-latest
    timeout-minutes: 10

    steps:
      - name: Checkout
        uses: actions/checkout@v4

      - name: Set up Python
        uses: actions/setup-python@v5
        with:
          python-version: "3.13"

      - name: Install flake8
        run: |
          python -m pip install --upgrade pip
          pip install flake8

      - name: Run flake8
        run: |
          flake8 .

  tests:
    runs-on: ubuntu-latest
    timeout-minutes: 30
    needs: lint

    steps:
      - name: Checkout
        uses: actions/checkout@v4

      - name: Set up Docker Buildx
        uses: docker/setup-buildx-action@v3

      - name: Run tests via docker compose
        run: |
          docker compose -f docker-compose-tests.yml down -v --remove-orphans || true
          docker compose -f docker-compose-tests.yml up --build --abort-on-container-exit --exit-code-from web

      - name: Cleanup
        if: always()
        run: |
          docker compose -f docker-compose-tests.yml down -v --remove-orphans || true
          docker system prune -af || true

CI: Lint + Tests (GitHub Actions)

This GitHub Actions workflow runs automatic code quality checks and end-to-end/integration tests for the project on every push and pull request. It helps catch style issues early and ensures the application works correctly inside Docker (same way you run it locally).


Trigger conditions

The workflow runs when:

  • Any push happens to any branch
  • Any pull request is opened/updated
on:
  push:
    branches: ["**"]
  pull_request:

Concurrency control

To avoid wasting CI minutes when multiple commits are pushed quickly, the workflow cancels older runs for the same branch/workflow:

concurrency:
  group: ${{ github.workflow }}-${{ github.ref }}
  cancel-in-progress: true
  • Groups runs by workflow name + branch reference
  • Cancels in-progress runs if a newer one starts

Jobs overview

This workflow has two jobs:

  1. lint — runs flake8 (fast code style / lint checks)
  2. tests — runs test suite using Docker Compose (only after lint passes)

Job 1: lint (flake8)

Runs on ubuntu-latest with a 10 minute timeout:

runs-on: ubuntu-latest
timeout-minutes: 10

Steps breakdown

1) Checkout repository

Downloads the repo to the runner:

- uses: actions/checkout@v4

2) Set up Python 3.13

Uses Python 3.13 for linting to match your project version:

- uses: actions/setup-python@v5
  with:
    python-version: "3.13"

3) Install flake8

Upgrades pip and installs flake8:

python -m pip install --upgrade pip
pip install flake8

4) Run flake8

Checks the whole project:

flake8 .

If flake8 fails, CI stops and the tests job will not run.


Job 2: tests (Docker Compose)

Runs only if lint succeeds:

needs: lint

Runs on ubuntu-latest with a 30 minute timeout:

timeout-minutes: 30

Steps breakdown

1) Checkout repository

Downloads the repo again for the test job:

- uses: actions/checkout@v4

2) Set up Docker Buildx

Enables Docker Buildx for building images efficiently:

      - name: Set up Docker Buildx
        uses: docker/setup-buildx-action@v3

3) Run tests using docker-compose

This job executes your test environment defined in docker-compose-tests.yml.

docker compose -f docker-compose-tests.yml down -v --remove-orphans || true
docker compose -f docker-compose-tests.yml up --build --abort-on-container-exit --exit-code-from web

What this does:

  • Cleans up any leftover containers/volumes first (safe because of || true)
  • Builds images (--build)
  • Starts all services needed for tests (DB, Mailhog, MinIO, web, etc.)
  • Stops everything when the test container finishes (--abort-on-container-exit)
  • Uses the web container exit code as the final CI result (--exit-code-from web)

So CI passes/fails exactly based on the test run inside the web container.


Cleanup step (always runs)

Even if tests fail, the workflow ensures containers/volumes are removed and Docker cache is cleaned:

      - name: Cleanup
        if: always()
        run: |
          docker compose -f docker-compose-tests.yml down -v --remove-orphans || true
          docker system prune -af || true

This keeps GitHub runners from running out of disk space and prevents cross-run interference.


Summary

This CI workflow enforces two quality gates:

  • Code style must pass (flake8)
  • Tests must pass in Docker Compose environment

That gives you confidence that every PR and every push stays clean and deployable.

Adding the CI Pipeline to Your Repository

  1. Create Workflow Directory:

    Ensure that the .github/workflows/ directory exists in the root of your repository. If not, create it:

    mkdir -p .github/workflows
  2. Add the CI Workflow File:

    Create a file named ci.yml inside .github/workflows/ and paste the CI pipeline YAML configuration provided above.

    touch .github/workflows/ci.yml
  3. Commit and Push:

    Commit the new workflow file and push it to the main branch.

    git add .github/workflows/ci-pipeline.yml
    git commit -m "Add CI Pipeline for automated testing"
    git push origin main
  4. Triggering the CI Pipeline:

    The CI pipeline will automatically run whenever a pull request is opened or updated against the main branch. You can monitor the progress and results in the Actions tab of your GitHub repository.


CD (Continuous Deployment)

The Continuous Deployment (CD) pipeline automates the deployment of your application to AWS EC2 instances after successful tests. This ensures that your latest changes are reflected in the production environment without manual intervention.

CD Pipeline Overview

The CD pipeline performs the following tasks:

  1. Checkout Code: Retrieves the latest code from the repository.
  2. Set Up SSH Agent: Configures SSH for secure access to the EC2 instance.
  3. Add EC2 Host to known_hosts: Adds the EC2 host to known SSH hosts to prevent authenticity prompts.
  4. Execute Deployment Script on EC2: Connects to the EC2 instance and runs the deploy.sh script to update the application.

CD Pipeline Configuration

This GitHub Actions workflow automates deployment of the FastAPI Movie Theater application to an AWS EC2 instance whenever changes are merged into the main branch.

Trigger conditions

name: Deploy to AWS EC2

on:
  push:
    branches: [main]
  pull_request:
    types: [closed]
    branches: [main]

concurrency:
  group: deploy-${{ github.ref }}
  cancel-in-progress: true

jobs:
  deploy:
    if: github.event_name == 'push' || github.event.pull_request.merged == true
    runs-on: ubuntu-latest
    timeout-minutes: 30

    steps:
      - name: Checkout
        uses: actions/checkout@v4

      - name: Add EC2 SSH key
        uses: webfactory/ssh-agent@v0.9.0
        with:
          ssh-private-key: ${{ secrets.EC2_SSH_KEY }}

      - name: Add EC2 host to known_hosts
        run: |
          mkdir -p ~/.ssh
          ssh-keyscan -H "${{ secrets.EC2_HOST }}" >> ~/.ssh/known_hosts

      - name: Deploy (run deploy script on EC2)
        run: |
          ssh "${{ secrets.EC2_USER }}@${{ secrets.EC2_HOST }}" "bash /home/ubuntu/src/FastAPI_movie_theater/commands/deploy.sh"

The workflow runs when:

  • A push is made directly to the main branch
  • A pull request is merged into the main branch
on:
  push:
    branches: [main]
  pull_request:
    types: [closed]
    branches: [main]

An additional condition ensures deployment only happens if:

  • The event is a push, or
  • The pull request was successfully merged
if: github.event_name == 'push' || github.event.pull_request.merged == true

Concurrency control

To prevent multiple deployments from running at the same time, the workflow uses concurrency locking:

concurrency:
  group: deploy-${{ github.ref }}
  cancel-in-progress: true
  • Only one deployment per branch can run at a time
  • Any in-progress deployment is canceled if a new one starts

Deployment job overview

The workflow runs a single job named deploy on the latest Ubuntu runner:

runs-on: ubuntu-latest
timeout-minutes: 30

Steps breakdown

1. Checkout repository

Fetches the latest version of the repository so the workflow has access to the code and configuration files.

- name: Checkout
  uses: actions/checkout@v4

2. Add EC2 SSH key

Loads the EC2 private SSH key from GitHub Secrets using an SSH agent, enabling secure remote access.

- name: Add EC2 SSH key
  uses: webfactory/ssh-agent@v0.9.0
  with:
    ssh-private-key: ${{ secrets.EC2_SSH_KEY }}

Required secret:

  • EC2_SSH_KEY – private SSH key for the EC2 instance

3. Add EC2 host to known_hosts

Adds the EC2 server to known_hosts to avoid SSH authenticity prompts during deployment.

- name: Add EC2 host to known_hosts
  run: |
    mkdir -p ~/.ssh
    ssh-keyscan -H "${{ secrets.EC2_HOST }}" >> ~/.ssh/known_hosts

Required secret:

  • EC2_HOST – public IP or domain of the EC2 instance

4. Run deploy script on EC2

Connects to the EC2 instance via SSH and executes the deployment script located on the server.

- name: Deploy (run deploy script on EC2)
  run: |
    ssh "${{ secrets.EC2_USER }}@${{ secrets.EC2_HOST }}" \
    "bash /home/ubuntu/src/FastAPI_movie_theater/commands/deploy.sh"

Required secrets:

  • EC2_USER – SSH username (e.g. ubuntu)
  • EC2_HOST – EC2 public IP or hostname

The deploy.sh script typically:

  • Pulls the latest code from GitHub
  • Resets the local repository to origin/main
  • Builds Docker images
  • Starts or restarts services using docker compose
  • Runs Alembic migrations (if configured)

Setting Up the CD Pipeline

To set up the CD pipeline, follow these steps:

  1. Create Workflow Directory:

    Ensure that the .github/workflows/ directory exists in the root of your repository. If not, create it:

    mkdir -p .github/workflows
  2. Add the CD Workflow File:

    Create a file named cd-pipeline.yml inside .github/workflows/ and paste the CD pipeline YAML configuration provided above.

    touch .github/workflows/cd-pipeline.yml
  3. Configure GitHub Secrets:

    For the CD pipeline to securely access your EC2 instance, you need to add the following secrets to your GitHub repository:

    • EC2_SSH_KEY: Your private SSH key for accessing the EC2 instance.
    • EC2_HOST: The public DNS or IP address of your EC2 instance.
    • EC2_USER: The SSH username for your EC2 instance (e.g., ubuntu).

    How to Add Secrets:

    • Navigate to your GitHub repository.
    • Click on Settings > Secrets and variables > Actions.
    • Click on New repository secret.
    • Add each secret with its respective name and value.
  4. Commit and Push:

    Commit the new workflow file and push it to the main branch.

    git add .github/workflows/cd-pipeline.yml
    git commit -m "Add CD Pipeline for automated deployment"
    git push origin main
  5. Triggering the CD Pipeline:

    The CD pipeline will automatically run under the following conditions:

    • Push to main branch: When changes are pushed directly to the main branch.
    • Merged Pull Request: When a pull request is merged into the main branch.

    Additionally, you can manually trigger the deployment:

    • Navigate to the Actions tab in your GitHub repository.
    • Select the Deploy to AWS EC2 workflow.
    • Click on the Run workflow button.

About

FastAPI_movie_theater

Resources

Stars

0 stars

Watchers

0 watching

Forks

Releases

Packages

Contributors

Languages