Giter Club home page Giter Club logo

szilvia-csernus / book-cycle Goto Github PK

View Code? Open in Web Editor NEW
1.0 1.0 0.0 80.93 MB

BookCYCLE is an all-condition textbook store for secondary schools and their students. Built with Python & Django, PostgreSQL, HTML, CSS, JavaScript and the STRIPE API. Hosted on Heroku.

Home Page: https://book-cycle-f6aff45df7ba.herokuapp.com/

Python 22.22% HTML 68.43% CSS 6.23% JavaScript 3.11% Procfile 0.01%
django full-stack javascript python stripe-api webshop progressive-web-app pwa e-commerce

book-cycle's Introduction

Book-CYCLE

DeepScan grade

Book-CYCLE is a Full Stack Webshop Application designed to be used by secondary schools in the UK.

The project is written in Django, a full-stack Python framework, alongside HTML, CSS, JavaScript and the Stripe API for payments. It is a Progressive Web App (PWA), allowing the user to install the app on both mobile and desktop devices.

The purpose of the application is to promote the re-use of textbooks by students while generating income for the school. The webshop allows the school to list all the textbooks they recommend their students to buy in both new and used conditions, possibly asking students to donate their used books back to the school.

Users can purchase listed textbooks using the STRIPE payment system and will receive confirmation emails about orders and shipping. School staff members can manage the book inventory and incoming orders.

The webshop has not been customized for a specific school, but it can be done by including the school's logo, contact details, and possibly some additional design elements. Customizations would allow the webshop to be utilized by multiple schools.


View the live project here


Landing Page Landing Page

This project was created for Code Institute's Web Development Course as the 4th Milestone Project (MS4) - Full Stack E-Commerce Web Application.

Not for public use.

© 2023 Szilvia Csernusne Berczes.


Features

Installation

Book-CYCLE is a Progressive Web App (PWA), allowing the user to install the app to the computer or mobile as a standalone app, providing a native-app-like experience.

Install - MacOS Chrome Install - Windows Edge
Install MacOS Chrome Install Windows Edge
Install - Android Installed App - iPhone
Install Android Install Windows Edge

Cache-first strategy is implemented in the Service Worker, where all the static and image files are pre-cached and served from the cache whenever possible. This implementation greatly improves the loading speed of the application.


Landing Page

The Landing page is minimalist with only a few options at the top. The side menu opens from the left-hand side, where users can search for textbooks in the store.

Landing Page - light mode Side Menu Landing Page on mobile
Landing Page light mode Browse light mode Browse light mode
Landing Page - dark mode
Landing Page dark mode Browse dark mode Browse dark mode

Bookstore

Filtering for books

Users have filtering and searching options from the side menu and additional options on the main bookstore page. Clicking the shop button or one of the filtering options from the menu will take us to the bookstore:

Book store - light mode Book store - dark mode
Books light mode Books - dark  mode

Under the More Options button, complex searching, filtering and sorting can be carried out.

Books search light mode Books search dark mode

Book details

The lowest price of the book, its condition (new, good or fair), if it is out of stock or 'in your bag' are all listed among the details of the book.

Book details Book details Book out of stock Book out of stock Book in your bag

In order to speed up loading, pagination is used to avoid unnecessary data load.


Shopping Process

You can start shopping right away, without the need for signing up. You can add products directly from the bookstore's page or by visiting the individual book's page. The number of books in your shopping bag will be shown in the top right corner.

shopping bag

Stock management allows displaying the available stock to the user and prevents purchasing out-of-stock items.

Book Detail Page - light mode Book Detail Page - dark mode
Book detail light mode Book detail dark mode

The shopping bag is available by clicking the shopping bag icon in the top right corner of the page.

Shopping bag from side - light mode Shopping bag from side - dark mode
Side bag light mode Side bag dark mode

If you would like to edit your shopping bag, you can do so by clicking the Edit Bag button. You can also select your shipping preference.

Shopping bag - light mode Shopping bag - dark mode
Bag light mode Bag dark mode

If you choose to go back to the bookstore's page, you will see if you have a particular book in your shopping bag:

In your bag!


After clicking the Checkout button, you will be taken to the Checkout Page. If you chose to have the books delivered, you need to provide detailed shipping information. Otherwise, only the Country and the Postcode are needed for the card payment.

Checkout - light mode Checkout - dark mode
Checkout light mode Checkout dark mode

Stripe provides a number of test cards that you can use for successful or failed payments. After a successful payment, you will receive a confirmation email about your order.

Payment Checkout Success Page & Email Confirmation
Payment light mode Insufficient FundsCard Declined Checkout success light modeEmail confirmation

Authentication

I used the django-allauth package to implement authentication. The user can sign up with email address & password, as well as with their Google account.

Register with email

Signing up with an email and password is straightforward. After the user clicks the link in the verification email, they will be signed in straight away.

Register Verify Email Page Verify Email Message
Register Verify Email Sign Up Email

Sign in

For signing in at a later time, the user's email and password are required.

Sign In Page Sign In Success
Sign In Sign In Success

Registering/Signing in with a Google account

If a user signs in with their Google account, there is no need to verify the email address, so the process is significantly faster. In the admin views below, I demonstrate how my user account and social account were created when I signed up with my Google account. In this case, no password has been set.

Google Sign In User's account in Admin view
Google Sign InSign In Success User Admin ViewSocial Account Admin View

If a user already has an account and later decides to use their social account, their social account will be linked to their original account if the email address is the same.


User Account

After successful registration, the user has access to their order history and contact details.

User Account Page - Light Mode User Account Page - Dark Mode
User Account Light User Account Dark

The user can change their password if they have one or set a new password if they don't.

Change Password User with Social Account Only Set Password
Change Password Account Set Password Set Password

All users can use the Forgot password? function.

Password Reset Password Reset Notification
Forgot password Password Reset Notification

Deleting a User Account

The user can delete their account from the database, including their social account. Their order history will not be erased from the database, but no profile info will be attached to them and will be inaccessible for the user. I demonstrate how a user account is being deleted by deleting my social account I created earlier.

Confirm Notification Account Deleted Message Accound Deleted Admin View
Change Password Account deleted message Admin View

Error pages

In case of an error, custom error pages would be shown to the user:

  • 404 (not found) page in case of an invalid URL was typed in.
  • 403 (access denied) page if there is an authentication issue.
  • 400 (bad request) if a request to the server was sent with incorrect data/structure.
  • 500 (internal server error) in case there is a problem with code execution or with the connection to the server.
404 - Not Found 403 - Access Denied 500 - Server Error
Not found page Access denied Error page

Admin Functions

If the user's account is a Staff Account, they are taken to a different home page after signing in.

Admin Home - Light Mode Side Menu
Landing Page light mode Browse light mode
Admin Home - Dark Mode Side Menu
Browse light mode Browse light mode

Inventory Management

Staff members can Add/Edit/Delete Books as well as manage the books' stock.

Add New Book Add New Book Success
Add New Book Add New Book Success
Manage Stock
Manage Stock
Edit Book Edit Book Success
Edit Book Edit Book Success
Delete Book Delete Book Success
Delete Book Delete Book Success

Order Management

Staff members can monitor if there are new orders in the system. The orders that require shipping are listed separately from the ones that need to be collected.

Orders require shipping Orders for Collection
Orders for Shipping Orders for Collection

On the individual order's page, the staff member can use the shipping details for postage and register the tracking number.

Order to Post - Light Mode Successful Shipping
Order to PostManage shipping Order Post SuccessOrder Post Email

Similarly to the shipping, the staff member can register if an order has been collected.

Order for Collection - Dark Mode Successful Collection
Order for Collection Order Collection SuccessOrder Collection Email

User Experience (UX)

User Stories

User Stories


Wireframes

Wireframes were created in Balsamiq.

Home Page
All Books
Book Detail


Colour Scheme

I personally chose the colors for this project, and the colour palette was created using Figma.

Light and dark modes are implemented for both customer and staff member pages, automatically adjusting to the computer's light/dark mode settings.

Book store - light mode Book store - dark mode
Main Colour Palette light mode Main Colour Palette dark mode
Admin Console - light mode Admin Console - dark mode
Admin console light mode Admin console dark mode

Typography

I used two fonts, Koulen and KoHo from the Google Fonts library. I selected these fonts because I felt that they complement each other, and their styles are fitting for the theme.


Imagery

The main image on the home page is credited to Jessica Ruscello and distributed by Unsplash.

The logo and icons used in the project are my own drawings, with the exception of the Google icon, which was downloaded from SVG Repo.


Data

Database Schema

The diagram illustrates a layout of the tables represented by my models in the database. The tables that were created by django by default are omitted, as well as the django-allauth tables, with the exeption of the User table which is directly connected to my User Profile and Order tables.

The Book model contains most of the product details. To enable filtering by both Year Group and Subject, I chose to create separate models for each category. For each book instance, three Stock instances are created, representing different conditions: New, Good, and Fair. This one-to-many relationship allows me to manage prices, quantities, and reserved quantities based on the book's condition rather than the book itself. This structure also facilitates inventory management functions, such as adjusting stock levels, reserving stock while it's in a user's shopping bag, and reducing stock when a purchase is made.

When a user makes a purchase, the stock item is represented as an Orderline Item within the Order instance, which establishes a many-to-one relationship. The Order model contains all the necessary order details, including delivery, contact, and payment information. A User Profile is only attached to an order if the user has created an account and is signed in.

Upon user registration on the site and the creation of a User instance, a corresponding User Profile instance is created to store the user's default shipping and contact information. This feature enhances the checkout process for subsequent purchases.

Shopping bag is stored in django's built in Session model as a text field as was suggested in Code Institute's reference project (Boutique Ado) - not included in the diagram below.

I used Lucid Charts to visualize the database schema.

database-schema

Schema Link (accessible for LucidChart users)

Product data

I compiled a custom textbook list, converted it to JSON, and wrote custom scripts to create stock data, generating prices and stock amounts randomly. Finally, I used these files as fixtures to populate the database.

The book pictures and details were taken from the publishers' websites, and a link pointing to the original site is provided for all books.


Accessibility

  • Semantic HTML was used.
  • Images have alt labels.
  • Icons with inferred meanings are marked with aria labels.
  • All colours were tested for contrast in Chrome's Dev Tools.
  • For detailed Lighthouse scores for Accessibility, please refer to the Testing document.

SEO

  • Lighthouse scores for Search Engine Optimization are 100% throughout all pages.
  • robots.txt and sitemap.xml files are provided for use by search engines.
  • I created a slug for each book, based on their titles, making the books discoverable by search engines when someone is searching for the book's title. This approach increases site traffic and potential revenue.

Performance

The app is currently hosted in the most budget-friendly package of Heroku, with expected high-latency. To mitigate this, I used the Cache First Strategy as part of the Progressive Web App (PWA) implementation, which greatly improved serving the static and image files of the application. The lower performance in production is due to unavoidable elements, like Stripe's script needed for Fraud detection and the slow response time from the hosting providers. Purchasing more expensive hosting packages would greatly improve performance in production.

For the project's detailed Lighthouse scores, please refer to the Testing document.


Future Implementations

  • Further functions for staff members: searching/filtering orders, handling returns and refunds.
  • Adding further functionality to stock management, i.e. reports, analytics.
  • Re-structure the database and functions to replace the Session-based shopping bag with a Shopping Bag model in order to have greater control over managing the user's shopping bag items.
  • Implementing an API to calculate postage data and integrate package tracking.
  • Re-creating the project in a Django REST + ReactJS architecture to improve UX.

Technologies Used

Languages Used

  • Python: Using the Django framework and other plugins to develop the app.
  • HTML: For page structure.
  • CSS: For styling.
  • JavaScript: Interactive frontend components and AJAX.

Frameworks, Libraries and Packages

  • Django: Full-stack python framework.
  • Stripe: Used for processing payments securely.
  • django-allauth: A Django package for authentication.
  • crispy-forms: A Django package for form management.
  • Pillow: A Python imaging library for processing images.
  • Google Fonts: For decorative text fonts.
  • boto3: Used for configuration and Management of AWS.
  • coverage: Measures lines of code tested.
  • dj-database-url: Parses database URLs for Django.
  • django-countries: Provides model fields for up-to-date country selection.
  • django-storages: Creates custom storages for use with AWS.
  • gunicorn: Web server to run on Heroku.
  • psycopg2: Adapter for use with a PostgreSQL Database.

Hosting platforms

  • Heroku: For hosting the main codebase.
  • ElephantSQL: For database hosting.
  • Amazon AWS S3: For static/media file hosting.

Other Tools


Testing

Please refer to TESTING.md for detailed testing documentation.


Local Development and Deployment

Local Development

To develop this project locally in VSCode, the following steps are needed.

  1. Prerequisites: make sure python and psql are installed.

  2. Set up a free account with STRIPE.

  3. Clone this project into a new repository.

  4. Create a new virtual environment in the project's parent folder with python3 -m venv venv.

  5. While in the project's parent folder, activate the virtual environment with source venv/bin/activate.

  6. Reload VSCode window. If the virtual environment creation and activation was successful, (venv) will appear in front of the prompt.

  7. Install the required packages with pip install -r requirements.txt.

  8. Create a .gitignore file, and place in the lines below.

    .vscode
    venv
    *.sqlite3
    *.pyc
    __pycache__
    .env
    
  9. Create the .env file.

    SECRET_KEY=<your-secret-key>
    DEVELOPMENT=development
    STRIPE_PUBLIC_KEY=<your-stripe-public-key>
    STRIPE_SECRET_KEY=<your-stripe-secret-key>
    STRIPE_WH_SECRET=<your-stripe-webhook-secret>
    GOOGLE_CLIENT_ID=<your-google-client-id>
    GOOGLE_SECRET=<your-google-secret>
    DEBUG=anything
    
  10. Run migrations with python manage.py migrate

  11. Create a superuser for your database with python manage.py createsuperuser

  12. Populate the database with data (in this order):

    1. python manage.py loaddata yeargroup
    2. python manage.py loaddata subject
    3. python manage.py loaddata book
    4. python manage.py loaddata stock
  13. To back up data:

    1. python manage.py dumpdata inventory.YearGroup > backup-yeargroup.json
    2. python manage.py dumpdata inventory.Subject > backup-subject.json
    3. python manage.py dumpdata inventory.Book > backup-book.json
    4. python manage.py dumpdata inventory.Stock > backup-stock.json

    Alternatively, you can create just one backup file with python manage.py dumpdata > backup.json, these will include all data inc. user login history.


Deployment

The project is deployed on Heroku, the database on ElephantSQL and the static/media files on Amazon AWS S3.

For deployment, the following steps were taken:

  1. Prerequisites: An account with Heroku, ElephantSQL, Amazon AWS, Stripe, and an email server provider, such as Google.

  2. Create a new ElephantSQL instance

  3. Migrate the database

    • install dj_database_url and psycopg2,
    • in settings.py, add
    import dj_database_url
    
    if 'DATABASE_URL' in os.environ:
        DATABASES = {
            'default': dj_database_url.parse(os.environ.get('DATABASE_URL', ''))
        }
        else:
            DATABASES = {
                'default': {
                    'ENGINE': 'django.db.backends.sqlite3',
                    'NAME': BASE_DIR / 'db.sqlite3',
                }
            }
    • temporarily, add DATABASE_URL=<the-elephant-sql-database-url to the .env file,
    • run python manage.py showmigrations, this will show if we are connected to the external database. No checks should show!
    • run python manage.py migrate
    • create a superuser for the database with python manage.py createsuperuser
    • populate the database with data (in this order):
      1. python manage.py loaddata yeargroup
      2. python manage.py loaddata subject
      3. python manage.py loaddata book
      4. python manage.py loaddata stock
    • confirm that the data is in the external database by running a table query in the ElephantSQL/Browser console.
    • remove the temporarily added DATABASE_URL from the .env file
    • to prevent 500 error on the deployed sign-in, edit the line temporary in the settings.py: ACCOUNT_EMAIL_VERIFICATION='none'
  4. Create a new Heroku App.

    • In Settings/Config Vars add:

      DATABASE_URL
      SECRET_KEY
      STRIPE_PUBLIC_KEY
      STRIPE_SECRET_KEY
      STRIPE_WH_SECRET
      GOOGLE_CLIENT_ID
      GOOGLE_SECRET 
      EMAIL_HOST_PASS
      EMAIL_HOST_USER
      USE_AWS
      AWS_ACCESS_KEY_ID
      AWS_SECRET_ACCESS_KEY
      
    • install gunicorn

    • create the Procfile

    • to stop Heroku to collect static files, set DISABLE_COLLECTSATIC in the config file:

    heroku login
    heroku config:set DISABLE_COLLECTSTATIC=1 --app <heroku-app-name>
    
    • add the new Heroku app url to ALLOWED_HOSTS in settings.py
    • commit and push changes to Github.
    • set up heroku as a remote heroku repo for the project: heroku git:remote -a <github-repo-name>
    • deploy the project: git push heroku main
    • set up automatic deployment on Heroku: Deploy/GitHub, search for <github-repo-name>, Connect then Enable Automatic Deploys
  5. Create a new S3 bucket on Amazon AWS to serve static and media files

    • Create a new bucket
    • Enable static website hosting in Properties, this will give access point to be used from the internet. Select Use this bucket to host a website, keep the default values (they won't be used) and Save Changes.
    • Set up permissions by generating a CORS policy with the Policy Generator.
  6. Set up a user group in AWS IAM in order to set up user permissions for the new bucket.

    • Create a user group: create a policy by importing Amazon S3 Full Access, set it up with the bucket's ARN, attach the policy to the group.
    • Create a user to go in the new group and create access key for this user
    • Add all AWS keys to the Heroku Config Vars.
  7. Connect the django project to the new bucket

    • install boto3 and django-storages, add storages to INSTALLED_APPS in settings.py
    • update the settings to use AWS:
    if 'USE_AWS' in os.environ:
        # Cache control
        AWS_S3_OBJECT_PARAMETERS = {
            'Expires': 'Thu, 31 Dec 2099 20:00:00 GMT',
            'CacheControl': 'max-age=94608000',
            }
    
        AWS_STORAGE_BUCKET_NAME = 'book-cycle'
        AWS_S3_REGION_NAME = 'eu-west-2'
        AWS_ACCESS_KEY_ID = os.environ.get('AWS_ACCESS_KEY_ID')
        AWS_SECRET_ACCESS_KEY = os.environ.get('AWS_SECRET_ACCESS_KEY')
        AWS_S3_CUSTOM_DOMAIN = f'{AWS_STORAGE_BUCKET_NAME}.s3.amazonaws.com'
    
        # Static and media files
        STATICFILES_STORAGE = 'custom_storages.StaticStorage'
        STATICFILES_LOCATION = 'static'
        DEFAULT_FILE_STORAGE = 'custom_storages.MediaStorage'
        MEDIAFILES_LOCATION = 'media'
    
        # Override static and media URLs in production
        STATIC_URL = f'https://{AWS_S3_CUSTOM_DOMAIN}/{STATICFILES_LOCATION}/'
        MEDIA_URL = f'https://{AWS_S3_CUSTOM_DOMAIN}/{MEDIAFILES_LOCATION}/'
    • Remove DISABLE_COLLECTSTATIC=1 variable from the Heroku config vars, because this time, we want django to collect the static files.
    • Create the custom_storages.py file to tell django to use AWS S3 whenever someone runs collectstatic, and when any product image upload occurs.
    • Add and commit all changes to GitHub, which will trigger the automatic deployment to Heroku. Go to Heroku's Activity tab and view the build log to see if it was successful.
    • Go to AWS S3, the new bucket has a static folder in it.
    • For media files, add a new folder called media next to static. Click Upload and select all images to upload. Click Upload again.
  8. Create/confirm the email address for the superuser.

    • Log in to the admin panel, go to Email addresses. Add a new email address if there is none.
    • Go to Users, select the only user, add the only email address then mark it as verified and primary.
    • In settings.py, change the ACCOUNT_EMAIL_VERIFIED back to mandatory.
    • Commit and push to GitHub.
  9. Set up STRIPE for the deployed site.

    • Go to STRIPE Developers tag, grap the API Keys and add them to Heroku Config.
    • Create a new webhook endpoint with the deployed url, /checkout/wh/ at the end. Select all events and Add them. Scroll down and Add endppoint.
    • Reveal the Signing secret and add it to the Heroku config vars.
    • Test that the webhook listeners are working by sending test webhook events from the CLI.

Credits

Learning Resources


Programs used


Other helpful ideas/resources

Images

  • Background image: Unsplash - Photo by Jessica Ruscello on Unsplash.
  • Google logo: Vectors and icons by Google Design in Logo License via SVG Repo.
  • The book images were taken from the publishers' websites. As this project was created for educational purposes only, it is exempt from copyright law. Nevertheless, I credited all products by providing a link to the original website. For further information, please refer to the UK government's website: Exceptions to Copyright.

Acknowledgements

I would like to thank the following contributors:

Disclaimer

This project was created for Code Institute's web application development course as the 4th Milestone Project for educational purposes.

Not for public use.

© 2023 Szilvia Csernusne Berczes. All rights reserved.

book-cycle's People

Contributors

szilvia-csernus avatar dependabot[bot] avatar

Stargazers

 avatar

Watchers

 avatar

Recommend Projects

  • React photo React

    A declarative, efficient, and flexible JavaScript library for building user interfaces.

  • Vue.js photo Vue.js

    🖖 Vue.js is a progressive, incrementally-adoptable JavaScript framework for building UI on the web.

  • Typescript photo Typescript

    TypeScript is a superset of JavaScript that compiles to clean JavaScript output.

  • TensorFlow photo TensorFlow

    An Open Source Machine Learning Framework for Everyone

  • Django photo Django

    The Web framework for perfectionists with deadlines.

  • D3 photo D3

    Bring data to life with SVG, Canvas and HTML. 📊📈🎉

Recommend Topics

  • javascript

    JavaScript (JS) is a lightweight interpreted programming language with first-class functions.

  • web

    Some thing interesting about web. New door for the world.

  • server

    A server is a program made to process requests and deliver data to clients.

  • Machine learning

    Machine learning is a way of modeling and interpreting data that allows a piece of software to respond intelligently.

  • Game

    Some thing interesting about game, make everyone happy.

Recommend Org

  • Facebook photo Facebook

    We are working to build community through open source technology. NB: members must have two-factor auth.

  • Microsoft photo Microsoft

    Open source projects and samples from Microsoft.

  • Google photo Google

    Google ❤️ Open Source for everyone.

  • D3 photo D3

    Data-Driven Documents codes.