diff --git a/.github/workflows/backend-linter-and-tester.yml b/.github/workflows/backend-linter-and-tester.yml new file mode 100644 index 0000000..cf9d0b4 --- /dev/null +++ b/.github/workflows/backend-linter-and-tester.yml @@ -0,0 +1,26 @@ +name: Pylint +on: [push] +jobs: + Backend-Linter-and-Test: + runs-on: ubuntu-latest + env: + PYTHON_VERSION: "3.10.12" + defaults: + run: + working-directory: ./backend + steps: + - uses: actions/checkout@v4 + - name: Set up Python $PYTHON_VERSION + uses: actions/setup-python@v3 + with: + python-version: ${{ env.PYTHON_VERSION }} + - name: Install dependencies + run: | + python -m pip install --upgrade pip + pip install -r requirements.txt + - name: Analysing the code with pylint + run: | + pylint $(git ls-files '*.py') + - name: Run tests + run: | + pytest diff --git a/.github/workflows/backend-linter.yml b/.github/workflows/backend-linter.yml deleted file mode 100644 index 5f011da..0000000 --- a/.github/workflows/backend-linter.yml +++ /dev/null @@ -1,29 +0,0 @@ -name: Pylint -on: [push] -jobs: - Backend-Linter: - runs-on: ubuntu-latest - env: - PYTHON_VERSION: "3.10.12" - defaults: - run: - working-directory: ./backend - steps: - - uses: actions/checkout@v4 - - name: Set up Python $PYTHON_VERSION - uses: actions/setup-python@v3 - with: - python-version: ${{ env.PYTHON_VERSION }} - - name: Install dependencies - run: | - python -m pip install --upgrade pip - pip install -r requirements.txt - - name: Analysing the code with pylint - run: | - pylint $(git ls-files '*.py') - - - - - - diff --git a/Makefile b/Makefile new file mode 100644 index 0000000..04cbeb6 --- /dev/null +++ b/Makefile @@ -0,0 +1,30 @@ +BACKEND_CONTAINER_NAME=python_backend + +.PHONY: docker/start docker/start-build docker/clean backend/test backend/migrate backend/upgrade + +# Docker commands: + +docker/start: + docker compose up + +docker/start-build: + docker compose up --build + +docker/clean: + docker compose down --volumes --rmi all + +# Backend commands: + +backend/migrate: + @if [ "$(message)" = "" ]; then \ + echo "Please provide a migration message. Usage: make migrate message='Your migration message'"; \ + exit 1; \ + else \ + docker compose exec $(BACKEND_CONTAINER_NAME) python3 -m flask --app main db migrate -m "$(message)"; \ + fi + +backend/upgrade: + docker compose exec $(BACKEND_CONTAINER_NAME) python3 -m flask --app main db upgrade + +backend/test: + docker compose exec $(BACKEND_CONTAINER_NAME) pytest \ No newline at end of file diff --git a/README.md b/README.md index ad044b6..127be54 100644 --- a/README.md +++ b/README.md @@ -1,45 +1,76 @@ # Bookstore Management System -The Bookstore Management System is designed to showcase the integration of various technologies for building a web application -![Concept Map](assets/concept-map.png) +The Bookstore Management System is a web application designed to demonstrate the integration of various modern technologies and best practices in software development. This project serves as a showcase of how to effectively combine multiple tools and frameworks to create a robust, maintainable, and scalable application. -## Overview -It consists of the following components: +## Key Features + +### Deployment and CI/CD + +- _Docker and Docker Compose_: Containerization of the application for consistent and isolated environments, enabling easy deployment and scaling. +- _GitHub Actions_: Automated pipeline for continuous integration and continuous deployment (CI/CD), ensuring code quality and rapid delivery of updates. -Backend API (Python Flask + Postgres): Implements CRUD (Create, Read, Update, Delete) operations for managing books. Utilizes PostgresSQL for data storage, demonstrating the integration of Flask with a NoSQL database. +### Backend -Frontend Application (React): Provides a user-friendly interface for browsing and managing books. Interacts with the Flask backend via RESTful API to fetch and update data. +- _MVCS Architecture_: Implementation of Model-View-Controller-Service architecture for a well-structured and modular backend. +- _Flask_: A lightweight and flexible web framework for building the server-side application. +- _PostgreSQL with Flask-SQLAlchemy_: Powerful ORM for database management and seamless interaction with a PostgreSQL database. +- _Marshmallow_: Schema validation and serialization/deserialization library for managing input/output data integrity. +- _Pytest_: Unit testing framework to ensure the reliability and correctness of the backend code. -This POC was developed do demonstrate the CI/CD Github actions working together with the following AWS Services: -1. AWS Elastic Beanstalk for Flask -2. AWS RDS for Postgress -3. AWS Amplify for the React web app -4. Docker was used for AWS local development +### Frontend +- _React with TypeScript_: Modern frontend library combined with TypeScript for type safety and robust application development. +- _Reusable Components_: Building blocks for creating maintainable and scalable UI. +- _ESLint and Prettier_: Tools for code linting and formatting, ensuring consistent and clean codebase. +## Project Structure + +It consists of the following components: + +Backend API (Python Flask + Postgres): Implements CRUD (Create, Read, Update, Delete) operations for managing books. Utilizes PostgresSQL for data storage, demonstrating the integration of Flask with a SQL database. + +Frontend Application (React): Provides a user-friendly interface for browsing and managing books. Interacts with the Flask backend via RESTful API to fetch and create data. ## Installation -1. Install and set up the backend, follow the instructions in the [`backend/README.md`](./backend/README.md) file. +1. Docker is being used to run the backend, frontend, database and even the database manager (PgAdmin). In order to install it make sure to have both docker and docker-compose installed. + +2. To start the services run `make docker/start` + +### Makefile Commands -2. Docker is being used to run the backend, frontend, database and even the database manager (PgAdmin). In order to install it make sure to have both docker and docker-compose installed. +This Makefile provides convenient targets to automate common development tasks. -3. To start the services run `docker compose up` +- **docker/start**: Starts Docker containers. +- **docker/start-build**: Starts Docker containers and rebuilds images. + +- **docker/clean**: Remove volumes and delete all images associated with the containers defined in the `docker-compose.yml` file. + +- **backend/migrate**: Runs Flask migration with a specified message. + +- **backend/upgrade**: Upgrades the database schema using Flask. + +- **backend/test**: Runs pytest for testing. ### PgAdmin + +PgAdmin is a popular open-source administration and development platform for PostgreSQL, a relational database management system. It provides a graphical interface for users to manage their PostgreSQL databases, execute SQL queries, monitor database activity, and perform various administrative tasks. + If you want to see your database on PgAdmin, you'll need to follow a few steps: 1. Access to PgAdmin: - - **URL:** http://localhost:5050 - - **Username:** pgadmin4@pgadmin.org - - **Password:** admin + + - **URL:** http://localhost:5050 + - **Username:** pgadmin4@pgadmin.org + - **Password:** admin 2. Add a new server in PgAdmin: - - **Host:** name/address postgres - - **Port:** 5432 - - **Username:** postgres - - **Password:** changeme + - **Host:** name/address postgres + - **Port:** 5432 + - **Username:** postgres + - **Password:** changeme + +## References -# References -1. The database docker configuration was retrieved from [khezen/compose-postgres](https://github.com/khezen/compose-postgres/tree/master) \ No newline at end of file +1. The database docker configuration was retrieved from [khezen/compose-postgres](https://github.com/khezen/compose-postgres/tree/master) diff --git a/assets/concept-map.png b/assets/concept-map.png deleted file mode 100644 index 37951f3..0000000 Binary files a/assets/concept-map.png and /dev/null differ diff --git a/backend/.pylintrc b/backend/.pylintrc index 27d068f..8204753 100644 --- a/backend/.pylintrc +++ b/backend/.pylintrc @@ -1,4 +1,4 @@ [MASTER] disable= - C0114, C0115, R0903, C0413, C0116, C0415 + C0114, C0115, R0903, C0413, C0116, C0415, F0001 ignore-paths=migrations/ diff --git a/backend/Makefile b/backend/Makefile deleted file mode 100644 index 00cdd57..0000000 --- a/backend/Makefile +++ /dev/null @@ -1,24 +0,0 @@ -.PHONY: migrate upgrade start start-build clean test lint - -migrate: - @if [ "$(message)" = "" ]; then \ - echo "Please provide a migration message. Usage: make migrate message='Your migration message'"; \ - exit 1; \ - else \ - python3 -m flask --app main db migrate -m "$(message)"; \ - fi - -upgrade: - python3 -m flask --app main db upgrade - -start: - docker compose up - -start-build: - docker compose up --build - -clean: - docker compose down --volumes --rmi all - -test: - pytest diff --git a/backend/README.md b/backend/README.md deleted file mode 100644 index 89bdbf5..0000000 --- a/backend/README.md +++ /dev/null @@ -1,49 +0,0 @@ -# Flask Backend Rest API -this is the back-end of the project. - -## Installation - -1. Copy the .env-example to a .env file inside of the backend folder and replace its variables with yours - -2. Create a Python Virtual Environment: - `python3 -m venv venv` - -3. Activate the Virtual Environment: - - On macOS and Linux: - `source venv/bin/activate` - - - On Windows (using Command Prompt): - `venv\Scripts\activate.bat` - - - On Windows (using PowerShell): - `.\venv\Scripts\Activate.ps1` - -4. Install Dependencies from requirements.txt: - `pip install -r requirements.txt` - -Now, your virtual environment is activated, and all the dependencies listed in requirements.txt have been installed. You can proceed with running the provided commands in the Makefile for development. - -### Makefile Commands - -This Makefile provides convenient targets to automate common development tasks. - - -- **migrate**: Runs Flask migration with a specified message. - -- **upgrade**: Upgrades the database schema using Flask. - -- **start**: Starts Docker containers. - -- **start-build**: Starts Docker containers and rebuilds images. - -- **clean**: Remove volumes and delete all images associated with the containers defined in the `docker-compose.yml` file. - -- **test**: Runs pytest for testing. - -- **lint**: Runs pylint on all Python files in the repository. - -## Note - -- **migrate**: When running the migrate command, ensure to provide a migration message as an argument like the example above. If no message is provided, the command will prompt you to provide one. - -- If you try to run the migration commands outside of the docker network, remember to change the `.env` **DATABASE_URI** host address(probably to `localhost`). \ No newline at end of file diff --git a/backend/migrations/versions/17eb199d7416_initial_commit.py b/backend/migrations/versions/17eb199d7416_initial_commit.py deleted file mode 100644 index 2bf7998..0000000 --- a/backend/migrations/versions/17eb199d7416_initial_commit.py +++ /dev/null @@ -1,51 +0,0 @@ -"""Initial commit - -Revision ID: 17eb199d7416 -Revises: -Create Date: 2024-05-16 16:58:03.648098 - -""" -from alembic import op -import sqlalchemy as sa - - -# revision identifiers, used by Alembic. -revision = '17eb199d7416' -down_revision = None -branch_labels = None -depends_on = None - - -def upgrade(): - # ### commands auto generated by Alembic - please adjust! ### - op.create_table('Author', - sa.Column('id', sa.Integer(), nullable=False), - sa.Column('name', sa.String(length=300), nullable=False), - sa.Column('email', sa.String(length=320), nullable=True), - sa.Column('nationality', sa.String(length=100), nullable=False), - sa.Column('birthDate', sa.Date(), nullable=False), - sa.PrimaryKeyConstraint('id') - ) - op.create_table('Book', - sa.Column('id', sa.Integer(), nullable=False), - sa.Column('title', sa.String(length=300), nullable=False), - sa.Column('pages', sa.Integer(), nullable=False), - sa.PrimaryKeyConstraint('id') - ) - op.create_table('BookAuthor', - sa.Column('id', sa.Integer(), nullable=False), - sa.Column('bookId', sa.Integer(), nullable=True), - sa.Column('authorId', sa.Integer(), nullable=True), - sa.ForeignKeyConstraint(['authorId'], ['Author.id'], ), - sa.ForeignKeyConstraint(['bookId'], ['Book.id'], ), - sa.PrimaryKeyConstraint('id') - ) - # ### end Alembic commands ### - - -def downgrade(): - # ### commands auto generated by Alembic - please adjust! ### - op.drop_table('BookAuthor') - op.drop_table('Book') - op.drop_table('Author') - # ### end Alembic commands ### diff --git a/docker-compose.yaml b/docker-compose.yaml index 27ba508..087e521 100644 --- a/docker-compose.yaml +++ b/docker-compose.yaml @@ -8,6 +8,7 @@ volumes: services: python_backend: + container_name: python_backend build: ./backend ports: - "5000:5000" @@ -40,13 +41,13 @@ services: POSTGRES_PASSWORD: ${POSTGRES_PASSWORD:-changeme} PGDATA: /data/postgres volumes: - - postgres:/data/postgres + - postgres:/data/postgres ports: - "5432:5432" networks: - my_network restart: unless-stopped - + pgadmin: container_name: pgadmin_container logging: @@ -55,13 +56,12 @@ services: environment: PGADMIN_DEFAULT_EMAIL: ${PGADMIN_DEFAULT_EMAIL:-pgadmin4@pgadmin.org} PGADMIN_DEFAULT_PASSWORD: ${PGADMIN_DEFAULT_PASSWORD:-admin} - PGADMIN_CONFIG_SERVER_MODE: 'False' + PGADMIN_CONFIG_SERVER_MODE: "False" volumes: - - pgadmin:/var/lib/pgadmin + - pgadmin:/var/lib/pgadmin ports: - "${PGADMIN_PORT:-5050}:80" networks: - my_network restart: unless-stopped - diff --git a/frontend/.env.example b/frontend/.env.example deleted file mode 100644 index babc50e..0000000 --- a/frontend/.env.example +++ /dev/null @@ -1 +0,0 @@ -REACT_APP_API_URL=http://localhost:5000 \ No newline at end of file diff --git a/frontend/src/pages/Books/BookForm.tsx b/frontend/src/pages/Books/BookForm.tsx index 8e45d42..f3e25b7 100644 --- a/frontend/src/pages/Books/BookForm.tsx +++ b/frontend/src/pages/Books/BookForm.tsx @@ -104,6 +104,8 @@ const BookForm: React.FC = () => { return (
+

Book's Authors

+
);