NutriForce is a B2C online shop for sports and health nutrition in Ireland. The main purpose of the site is to enable the developer's friend to set up shop, as has been planned over a longer period of time. The reason for this is so that customers in Ireland can have a small, local business to support when it comes to their nutritional needs. High quality products will be sourced to build a loyal customer-base that trusts in the shop. A long-standing dream will come to fruition with the launch of this online shop, and we hope to provide customers with all the sports and health nutrition they need, as well as personalised, and excellent customer service. This can be become the one-stop-shop for anyone regularly purchasing such products, as requests will also be accepted, where we will aim to source the products, wherever possible. Welcome to the NutriForce family! Thank you for helping to make this dream possible!
The target audience is any adult interested in sports, and/or their health within Ireland. Whether they are just starting out, or experienced with their nutrition, NutriForce can help with suggestions, recommendations, or even sourcing a customer's favourite products, if not already in stock on the site.
The shop only has an online presence, but ensures to let customers know that it's a small, local business, using the keywords on the site, as well as the information on the About Us page. With shopping local becoming increasingly important worldwide, it's imperative the target audience is made aware of who they are buying their nutritional products from. Due to the planned scale of the business, the shop only allows addresses in Ireland for orders.
Pricing for products on the site will be competitive, as there are many large companies selling such products. While a slight increase to big box store prices is typically acceptable for customers interested in shopping locally, if the prices are too high, the benefits of using a small business will not be enough to attract and keep customers.
A newsletter signup link is available on every page of the site. The prominent but unobtrusive display of this feature makes it easy for customers to make use of it, without being bothered by it. When a customer signs up, a confirmation email is sent out to the email address used. This helps to ensure no one's email is used or stored for this, without their consent (in case someone uses an email address that does not belong to them). The confirmation email includes a link to unsubscribe from the mailing list that can be used at any time. If the email address used is linked to a registered account, the customer can also unsubscribe from their Profile at any time as well.
Privacy and customer experience concerns aside, the newsletter is used to promote special deals and new products, which should help entice some customers to make additional purchases.
See details and screenshots in the Feature Details section. Newsletter and Automated Emails > Customer Newsletter.
A social media presence is critical for any business in current times. A mock-up Facebook page was created for the business that can be viewed below. An actual business page already exists, created by the business owner, but has not been used for this project. It is also not yet complete.
For search engine optimisation, the following keywords are used in the site's metadata, and where reasonable, on various pages throughout the site:
These were identified based on the products being sold, typical search terms, our target audience, and typical business profile (small/local business based in Cork selling specifically in Ireland).
robots.txt and sitemap.xml files were created to ensure search engines know which pages should be accessed on the site. This helps improve site ratings, and hopefully the site's presence in search engine search results.
Additional pages - all in the site footer - were created to ensure customers have all the necessary information about the company, their data and it's usage, and orders. Everything below in this section will help show customers that this is a trusted site they can make purchases from, as we are transparent, and all information is readily available. The Shipping, Returns, Privacy, and Support pages additionally include details on how to get in touch with the support team, should the customers need this.
See details and an example screenshot in the Feature Details > Information Pages section.
This page gives an introduction about the company and what is important to us. It should help customers feel more connected to us, and hopefully instill some confidence, as our values greatly relate to quality and integrity, as stated on the page.
The Shipping detail page is currently rather generic, but will be updated once the shop officially goes live. For now, basic information is available to customers on the free shipping limit, shipping methods and times, and delayed orders.
This page details information on returns and refunds, again so customers don't have to search for this and have it readily available. The page ensures customers have the information necessary for them to know according to their rights, when a refund or return is required.
Details regarding what data is collected from customers and how it is used is fully outlined on this page. This is critical, particularly with the site being not only available in the EU, but specifically selling in Ireland (EU).
A page outlining the full T&C for the site is available.
A page specifically for customers to access support details was created, in case of users with strict security settings, who may not get the JavaScript modal pop-ups used in various areas on the site. While there is a "Support" link at the top of the page already, this is for the aforementioned JavaScript modal. The Support page and footer link were added as a backup. This way, any customer should be able to access support details, no matter what.
Screenshots and more details on the features implemented to achieve the visitor goals are available in the Feature Details section.
* Save for Later and Watchlist features are not yet implemented. This is planned for release 1.1.
All completed EPICs and related user stories are listed in the repository Issues here.
The Montserrat Google font is used throughout the site.
Bing AI was used to create the logo, default product, and favicon images on the site. It was also used for the banner and "liked by" profile images in the Facebook page mockup.
Wireframes were used to plan out the pages for the site. Minor adjustments were made throughout, as the pages were being created. The navigation menu was reorganised in the final site iteration, and differs from the wireframes below as follows:
Login: _Social media signup options have not yet been implemented. This is planned for release 1.1. See user story here._
Create Account: _Social media signup options have not yet been implemented. This is planned for release 1.1. See user story here._
Account Details:
Addresses: The Add New Address (now Add Address) button was moved, but otherwise the style has stayed the same.
Orders:
Order Details:
Saved Items: _Saved Items have not yet been implemented. Therefore, the menu item (on the left) and the page itself is not yet available. This is planned for release 1.1. See user story here._
Watchlist: _The Watchlist has not yet been implemented. Therefore, the menu item (on the left) and the page itself is not yet available. This is planned for release 1.1. See user story here._
Homepage (Featured Products):
Product Browser:
Product Page: _Save for Later/Add to Watchlist is not yet available. This is planned for release 1.1. See user story here._
Cart: _Save for Later is not currently available. This is planned for release 1.1. See user story here._
Login / Guest Checkout: _This view was slightly updated. Social media login options are not available (planned for 1.1), Forgot Password was added to the login section, and Create Account was added below Login as an option._
Addresses: A "Back to Cart" button was added at the bottom left of this page.
Payment Options: _This page was completely removed. Also, only stripe payment is currently available. Additional payment options (GooglePay, Apple Pay, and PayPal) are planned for release 1.1._
Confirmation: Show/Hide Cart and Edit Address links were added to this page. A Note to Seller is now also available at checkout. Text indicating that the customer will be charged once they confirm the purchase is now present. Finally, a "Back to Cart" button was added at the bottom left of this page.
All user stories, features, and bugs are listed in the repository's projects. For release 1.0, the kanban board can be found here. Completed and postponed (Cancelled) features are outlined in the board.
Some additional unplanned minor features have been implemented, not outlined in user stories/features, to promote customer satisfaction and loyalty, such as mailto links with predefined email subjects and bodies, where customers can request products be stocked, that are not in the database. These features are still outlined below as well.
When a user scrolls down on any page on the site, a "Back to top" link will appear on the right side of the footer. When a customer clicks this, it will bring them to the top of the page again. This should make for easier site navigation, particularly on pages with a lot of content (e.g. the All Products page).
JavaScript modals are implemented throughout the site to provide support details to customers. As mailto links opening are dependent on a user's browser and system settings, relying solely on these would cause problems for some customers. Therefore, modals were implemented to display the mailto link, as well as the plain-text support email address. Huge thanks to my mentor for identifying this issue and providing the suggestion.
The related user story is here. The site has a newsletter signup button, that sends an email confirmation to the address entered. This way, if someone's email is used without their knowledge, or if they just no longer want to be subscribed, they can directly unsubscribe using the link in that same email. Customers can be kept up-to-date on new promotions and products via the newsletter.
Customers can create an account, so they can save and view their addresses, cart contents, and orders (user story).
The profile page offers various features for customers. They can change the email and/or password associated with their account. They can completely delete their account from the database. Addresses can be saved to the account, and those can be edited or deleted. Lastly, customers can view all their orders and the order details for each, such as order status and tracking links.
User stories for these features are below:
Main categories (Sports, Health) are available for customers to browse products specific to their needs via the navigation bar. Dropdowns are available for sizes, and if applicable, flavours, for each product. The price displayed for the product immediately updates, depending on the size/flavour selected. Customers can then set a quantity for how much of the product they want, and add it to their cart (user story). Product pages include links to expand the description and ingredients for the products. This way, space on the page is saved. The user story for product details is here. Lastly, product pages also include a list of similar items, if available. These are determined by matching sub-categories for the products. The user story for linked products is here.
All navigation bar product view options (All Products, Sports, Health, What's New) offer a button to sort/filter the products on the page by Brand, Product (name), Price, and On Sale products. This should make it easier for customers to find what they're looking for, while browsing.
A search bar is available at the top of the site, so customers can search for products. This function looks for partial matches to brand names, product names, or flavours. If a flavour is searched, the relevant dropdown is pre-selected, if the flavour is in-stock.
If a customer is logged in, products added to cart will be added to both the session cart, and the SavedItems Django model for their account cart. The contents of the account cart are always available and saved until the customer empties it, or checks out. If not logged in, contents are just added to the session cart. Various features are available in the cart view:
When logging in on any page except during checkout, if the customer has products in their session cart that they don't already have saved to their account cart, the session cart products will be added to the account cart.
The user story for checkouts is here. Customers can check out as a guest, or while logged in. Doing so while logged in provides some useful features, such as being able to used saved addresses, and having their order saved to their account for later viewing.
A "Same as Shipping" feature is available for all customers during checkout, to match their billing with their entered shipping address. When logged in, if addresses are saved to the account, the address form is autofilled with the default address, if available, and otherwise the most recently saved address. A dropdown is available to select any address saved to the account, which will autofill the form with the newly selected address details. The dropdown also includes a "New Address" option to clear the form, so the customer can enter new details without having to manually delete the autofilled address first.
At the last checkout page to confirm the purchase, a "Show/Hide Cart" feature is available. By default, the cart contents are not displayed, only the cart totals, to save space and show a cleaner, less-busy overview.
While not exactly a feature, the informational pages on the site, linked in the footer, serve to provide customers with details they may need to common questions or problems. They help promote trust in the site, and ensure that customers can receive the support they need, for any possible issue.
Verification and confirmation emails are automatically sent by the system for various features. These are sent to customers to ensure they have all the necessary information for various actions. There are also some that are sent to the admin of the site, where action may be required of them.
Some example screenshots have been added below.
The user story for mobile views is here. Based on the customer's screen width, various parts of the website are adjusted to better utilise the available space. The main changes between larger and smaller screens are that text is updated to icons or shorter text, and lesser-important information is removed from tables. Specifically:
Show/hide the box with links via clicking "Menu".
An admin panel is available for the site owner to view, edit, create, and delete any contents in/from the database. The Django Admin Panel is fully sufficient for this purpose, so no custom views or functionality were included, beyond special sorting for products. The admin panel cannot be accessed by standard user accounts. Related user stories are:
For release 1.1, the kanban board is here. Postponed User Stories from 1.0 are planned for release 1.1, as well as enhancements and minor bugs identified during initial project release. They can also be found in the repository's Issues. Enhancements are labelled with "enhancement" and the postponed user stories are labelled with "user-story".
All "Inspector" tests were conducted in Chrome on macOS.
Function __ |
Expectation ___ |
MacOS Safari __ |
iOS Safari __ |
iPadOS Chrome __ |
Windows 11 Edge __ |
Windows 11 Chrome __ |
AndroidOS Chrome _____ |
Inspector > 1100px _____ |
Inspector < 1100px _____ |
Inspector < 800px _____ |
Inspector < 500px _____ |
Inspector < 320px _____ |
---|---|---|---|---|---|---|---|---|---|---|---|---|
JavaScript mailto modals | These are used on various pages throughout the site. "click here" in the modal text is a mailto link. It should open a draft email to the support contact email in the local mail client. Depending on the scenario, the draft email will also have an auto-filled email subject and email body. Clicking the email address in the modal text should copy it to clipboard and show a "Copied!" message below the text. The modal itself and/or the mailto link may not work, depending on user's browser and system settings, e.g. blocked pop-ups. | ✓ | ✓ | ✓ | ✓ | ✓ | ✓ | ✓ | ✓ | ✓ | ✓ | ✓ |
csrf errors - view | Any csrf errors on the site should direct to the custom view. | ✓ | ✓ | ✓ | ✓ | ✓ | ✓ | ✓ | ✓ | ✓ | ✓ | ✓ |
csrf errors - email to admin | csrf errors should send an email to the admin. | ✓ | ✓ | ✓ | ✓ | ✓ | ✓ | ✓ | ✓ | ✓ | ✓ | ✓ |
csrf errors - modal | The custom csrf error text should have a link in the text that opens a mailto modal. | ✓ | ✓ | ✓ | ✓ | ✓ | ✓ | ✓ | ✓ | ✓ | ✓ | ✓ |
404 errors - view | Any 404 errors on the site should direct to the custom view. | ✓ | ✓ | ✓ | ✓ | ✓ | ✓ | ✓ | ✓ | ✓ | ✓ | ✓ |
404 errors - modal | The custom 404 error text should have a link in the text that opens a mailto modal. | ✓ | ✓ | ✓ | ✓ | ✓ | ✓ | ✓ | ✓ | ✓ | ✓ | ✓ |
500 server errors - view | Server errors (500) should direct to the custom view. | ✓ | ✓ | ✓ | ✓ | ✓ | ✓ | ✓ | ✓ | ✓ | ✓ | ✓ |
500 server errors - email to admin | Server errors (500) should send an email to the admin. | ✓ | ✓ | ✓ | ✓ | ✓ | ✓ | ✓ | ✓ | ✓ | ✓ | ✓ |
500 server errors - modal | Th custom 500 error text should have a link in the text that opens a mailto modal. | ✓ | ✓ | ✓ | ✓ | ✓ | ✓ | ✓ | ✓ | ✓ | ✓ | ✓ |
Footer - Back to top function | Button should be hidden until user scrolls down. Button should then appear. Onclick, user should be brought to the top of the page. | ✓ | ✓ | ✓ | ✓ | ✓ | ✓ | ✓ | ✓ | ✓ | ✓ | ✓ |
Footer - Support | Support link in the footer should bring the user to the Support view. This is a backup for user systems/settings that can't display the JavaScript modal and mailto links. | ✓ | ✓ | ✓ | ✓ | ✓ | ✓ | ✓ | ✓ | ✓ | ✓ | ✓ |
Footer - About page | About link in footer should bring the user to the About Us view. | ✓ | ✓ | ✓ | ✓ | ✓ | ✓ | ✓ | ✓ | ✓ | ✓ | ✓ |
Footer - Privacy page | Privacy link in footer should bring the user to the Privacy Policy view. | ✓ | ✓ | ✓ | ✓ | ✓ | ✓ | ✓ | ✓ | ✓ | ✓ | ✓ |
Footer - Returns page | Returns link in footer should bring the user to the Returns and Refunds view. | ✓ | ✓ | ✓ | ✓ | ✓ | ✓ | ✓ | ✓ | ✓ | ✓ | ✓ |
Footer - Shipping page | Shipping link in footer should bring the user to the Shipping Information view. | ✓ | ✓ | ✓ | ✓ | ✓ | ✓ | ✓ | ✓ | ✓ | ✓ | ✓ |
Footer - T&C page | Terms & Conditions link in footer should bring the user to the T&C view. | ✓ | ✓ | ✓ | ✓ | ✓ | ✓ | ✓ | ✓ | ✓ | ✓ | ✓ |
Footer - Facebook link | Facebook (Follow Us) link in footer should bring the user to the external Facebook page for the business. | ✓ | ✓ | ✓ | ✓ | ✓ | ✓ | ✓ | ✓ | ✓ | ✓ | ✓ |
Navigation bar - desktop sizing | Nav bar for widths > 1100px should display with both text and icons for the nav-left, and larger center nav buttons. | ✓ | N/A | N/A | ✓ | ✓ | N/A | ✓ | ✓ | ✓ | ✓ | ✓ |
Navigation bar - larger screen sizing | Widths < 1100px should reduce the center nav button padding. | ✓ | N/A | ✓ | ✓ | ✓ | N/A | ✓ | ✓ | ✓ | ✓ | ✓ |
Navigation bar - mid-screen sizing | Widths < 800px should remove text from the nav-left to leave only icons, and change center nav button text to shortened versions. | ✓ | N/A | N/A | ✓ | ✓ | N/A | ✓ | ✓ | ✓ | ✓ | ✓ |
Navigation bar - small-screen sizing | Widths < 500px should reduce center button padding further and reduce overall font size. | ✓ | ✓ | N/A | ✓ | ✓ | ✓ | ✓ | ✓ | ✓ | ✓ | ✓ |
Navigation bar - smallest screen sizing | Widths < 320px change the top middle links (newsletter and support) to colum flex-direction and reduce paddings and margins. | ✓ | N/A | N/A | ✓ | ✓ | N/A | ✓ | ✓ | ✓ | ✓ | ✓ |
Support - link and modal | When clicking the link, a mailto modal should open with support contact details. | ✓ | ✓ | ✓ | ✓ | ✓ | ✓ | ✓ | ✓ | ✓ | ✓ | ✓ |
Newsletter signup - modal | Clicking the Newsletter Signup link should open a modal asking the user to enter their email address and provide a "Subscribe" button. | ✓ | ✓ | ✓ | ✓ | ✓ | ✓ | ✓ | ✓ | ✓ | ✓ | ✓ |
Newsletter signup - empty input | Empty inputs should show an error to the user (on the current page, not in the modal). | ✓ | ✓ | ✓ | ✓ | ✓ | ✓ | ✓ | ✓ | ✓ | ✓ | ✓ |
Newsletter signup - invalid input | Inputs without "@" should show an error from the input field, that the email address is missing an "@". Inputs with an "@" but without the top-level domain should show an error to the user (on the current page, not in the modal). | ✓ | ✓ | ✓ | ✓ | ✓ | ✓ | ✓ | ✓ | ✓ | ✓ | ✓ |
Newsletter signup - successful | Entering a valid email address should add the email to the Django Newsletter model and show a message to the user confirming successful sign-up. | ✓ | ✓ | ✓ | ✓ | ✓ | ✓ | ✓ | ✓ | ✓ | ✓ | ✓ |
Newsletter signup - already subscribed | If the user tries to subscribe with an email address already in the Django Newsletter model, they should receive a message that they're already subscribed. | ✓ | ✓ | ✓ | ✓ | ✓ | ✓ | ✓ | ✓ | ✓ | ✓ | ✓ |
Newsletter signup - confirmation email to user | After successfully signing up to the newsletter, the user should receive a confirmation email that includes an unsubscribe link. | ✓ | ✓ | ✓ | ✓ | ✓ | ✓ | ✓ | ✓ | ✓ | ✓ | ✓ |
Newsletter signup - unsubscribe from confirmation email link | Clicking the unsubscribe link in newsletter confirmation or other emails should remove the email address from the Django Newsletter model and display a success message to the user on a specific unsubscribe page. | ✓ | ✓ | ✓ | ✓ | ✓ | ✓ | ✓ | ✓ | ✓ | ✓ | ✓ |
Newsletter signup - unsubscribe errors and modal | There are custom error messages for various scenarios. 1) User already unsubscribed previously (with mailto modal to contact support, if needed). 2) Link formatted incorrectly. 3) Link accessed manually (no POST request). | ✓ | ✓ | ✓ | ✓ | ✓ | ✓ | ✓ | ✓ | ✓ | ✓ | ✓ |
Login - account doesn't exist | Trying to log in with an email address that is not registered, should display an error that the email/password is incorrect. | ✓ | ✓ | ✓ | ✓ | ✓ | ✓ | ✓ | ✓ | ✓ | ✓ | ✓ |
Login - invalid credentials | Logging in with the incorrect password should display an error that the email/password is incorrect. | ✓ | ✓ | ✓ | ✓ | ✓ | ✓ | ✓ | ✓ | ✓ | ✓ | ✓ |
Login - successful | A successful login should display a success message for the user and redirect to the homepage. | ✓ | ✓ | ✓ | ✓ | ✓ | ✓ | ✓ | ✓ | ✓ | ✓ | ✓ |
Login page - logged in | Accessing the login page when already logged in should immediately redirect to the homepage. | ✓ | ✓ | ✓ | ✓ | ✓ | ✓ | ✓ | ✓ | ✓ | ✓ | ✓ |
Logout | Logging out should display a success message for the user and redirect to the homepage. | ✓ | ✓ | ✓ | ✓ | ✓ | ✓ | ✓ | ✓ | ✓ | ✓ | ✓ |
Logo link | Clicking in the logo, which is wrapped in an anchor link, should load the homepage. | ✓ | ✓ | ✓ | ✓ | ✓ | ✓ | ✓ | ✓ | ✓ | ✓ | ✓ |
Password reset - errors | Email validation is in place for the password reset view. Errors should appear from the input for empty inputs or inputs without an "@". An error should appear on the page for invalid email addresses (top-level domain missing). | ✓ | ✓ | ✓ | ✓ | ✓ | ✓ | ✓ | ✓ | ✓ | ✓ | ✓ |
Password reset - link requested - success | A message should display for the user to confirm they were sent an email. | ✓ | ✓ | ✓ | ✓ | ✓ | ✓ | ✓ | ✓ | ✓ | ✓ | ✓ |
Password reset - link requested - error | If the user accesses the page following any link except for the /password/reset, an error should be displayed with links to the Forgot Password page on the site. A mailto modal should also be included in the text to contact support, if needed. | ✓ | ✓ | ✓ | ✓ | ✓ | ✓ | ✓ | ✓ | ✓ | ✓ | ✓ |
Password reset - email - account exists | The user should receive an email with a custom password reset link after successfully requesting a password reset for an existing account. | ✓ | ✓ | ✓ | ✓ | ✓ | ✓ | ✓ | ✓ | ✓ | ✓ | ✓ |
Password reset - email - account does not exist | Trying to reset the password using an email address that is not yet registered should result in an email to that address stating that the account does not exist, and include the account signup link. | ✓ | ✓ | ✓ | ✓ | ✓ | ✓ | ✓ | ✓ | ✓ | ✓ | ✓ |
Password reset - link error | If the user accesses an invalid link (e.g. expired/already used), they should receive a corresponding error message that includes a link to the forgot password form. | ✓ | ✓ | ✓ | ✓ | ✓ | ✓ | ✓ | ✓ | ✓ | ✓ | ✓ |
Password reset - link valid | When the user clicks a valid password reset link from their email, they should encounter a page to change the password for their account. | ✓ | ✓ | ✓ | ✓ | ✓ | ✓ | ✓ | ✓ | ✓ | ✓ | ✓ |
Password reset - password change invalid | If the user enters a password that does not the meet the minimum requirements, they should receive an error message. | ✓ | ✓ | ✓ | ✓ | ✓ | ✓ | ✓ | ✓ | ✓ | ✓ | ✓ |
Password reset - password change successful | If the user enters a password that meets minimum password requirements, they should be automatically logged in, receive a success message for the changed password and login, and be redirected to the homepage. | ✓ | ✓ | ✓ | ✓ | ✓ | ✓ | ✓ | ✓ | ✓ | ✓ | ✓ |
Password reset pages - logged in | When accessing any password reset pages while logged in, the user should receive a message that they're already logged in and can change their password from their Profile instead. | ✓ | ✓ | ✓ | ✓ | ✓ | ✓ | ✓ | ✓ | ✓ | ✓ | ✓ |
Account creation - email invalid | Input errors should appear for empty email address inputs or emails entered without "@". An error will appear on the page for otherwise invalid email addresses (e.g. missing top-level domain). | ✓ | ✓ | ✓ | ✓ | ✓ | ✓ | ✓ | ✓ | ✓ | ✓ | ✓ |
Account creation - email exists | When trying to sign up using an email address that is already registered, the user should see a message to verify their email address. The email sent should indicate that an account already exists, and provide a password reset link. | ✓ | ✓ | ✓ | ✓ | ✓ | ✓ | ✓ | ✓ | ✓ | ✓ | ✓ |
Account creation - password invalid | The user should receive an error when using a password that does not meet the minimum requirements. | ✓ | ✓ | ✓ | ✓ | ✓ | ✓ | ✓ | ✓ | ✓ | ✓ | ✓ |
Account creation - successful | After successfully entering an email and password for account creation, the user should receive a message to verify their email address. | ✓ | ✓ | ✓ | ✓ | ✓ | ✓ | ✓ | ✓ | ✓ | ✓ | ✓ |
Account creation - email verification valid link | When a user clicks a valid email verification link for creating an account, they should be brought to the login page with a message that their email address is confirmed. | ✓ | ✓ | ✓ | ✓ | ✓ | ✓ | ✓ | ✓ | ✓ | ✓ | ✓ |
Account creation - email verification invalid link | When a user clicks an invalid link, they should receive a message that the link is expired and to issue a new one, if needed. | ✓ | ✓ | ✓ | ✓ | ✓ | ✓ | ✓ | ✓ | ✓ | ✓ | ✓ |
Account creation -logged in | Accessing the signup page when logged in should redirect to the homepage. | ✓ | ✓ | ✓ | ✓ | ✓ | ✓ | ✓ | ✓ | ✓ | ✓ | ✓ |
Profile - menu - larger screens | Screen widths > 800px should display text links on the left side of each profile page to navigate between the profile pages. | ✓ | N/A | ✓ | ✓ | ✓ | N/A | ✓ | ✓ | ✓ | ✓ | ✓ |
Profile - menu - smaller screens | Screen widths < 800px should display just a "Menu" link at the top of each profile page, that expands to show the links to the different profile pages for navigation. | ✓ | ✓ | N/A | ✓ | ✓ | ✓ | ✓ | ✓ | ✓ | ✓ | ✓ |
Profile - account details | Accessing the main profile page should display account details - the user's email address, and buttons to change their email/password, unsubscribe from the newsletter (if subscribed), and delete their account. | ✓ | ✓ | ✓ | ✓ | ✓ | ✓ | ✓ | ✓ | ✓ | ✓ | ✓ |
Profile - unsubscribe from newsletter via profile | Clicking the button to unsubscribe should immediately remove the user's email address from the Django Newsletters model, and confirm to the user that they are unsubscribed. | ✓ | ✓ | ✓ | ✓ | ✓ | ✓ | ✓ | ✓ | ✓ | ✓ | ✓ |
Profile - delete account with modal | Clicking the delete account button should open a modal, asking the user to confirm account deletion, as this cannot be undone. Once confirmed, the user should be deleted from the Django Users model. | ✓ | ✓ | ✓ | ✓ | ✓ | ✓ | ✓ | ✓ | ✓ | ✓ | ✓ |
Profile - email change - email invalid | An error message should appear when entering an empty/invalid email address. | ✓ | ✓ | ✓ | ✓ | ✓ | ✓ | ✓ | ✓ | ✓ | ✓ | ✓ |
Profile - email change - email exists | An error should appear that the email is already registered to another account (or "this" account, if it's the same email address as the logged in user), when trying to use an email address linked to another user. | ✓ | ✓ | ✓ | ✓ | ✓ | ✓ | ✓ | ✓ | ✓ | ✓ | ✓ |
Profile - email change - pending verification | After submitting a valid email address, the user should receive a message that a verification email has been sent. Accessing the email change view while an email change is pending should display both email addresses (current and changing to), a message for the pending verification, and a button to re-send the verification email. | ✓ | ✓ | ✓ | ✓ | ✓ | ✓ | ✓ | ✓ | ✓ | ✓ | ✓ |
Profile - email change - re-send verification | Using the re-send verification button on the email change page during a pending change, should result in a new verification email being sent out, along with a confirmation message to the user. | ✓ | ✓ | ✓ | ✓ | ✓ | ✓ | ✓ | ✓ | ✓ | ✓ | ✓ |
Profile - email change - email verification valid | Clicking a valid email verification link should display a message for the user to confirm the email address was verified. | ✓ | ✓ | ✓ | ✓ | ✓ | ✓ | ✓ | ✓ | ✓ | ✓ | ✓ |
Profile - email change - email verification invalid | Using an invalid (e.g already used) email verification link should provide an error that it's invalid/expired, and advise to issue a new email confirmation request. | ✓ | ✓ | ✓ | ✓ | ✓ | ✓ | ✓ | ✓ | ✓ | ✓ | ✓ |
Profile - email change - successful | After clicking a valid email verification link, the email address for the account in the Django Users model should be updated, and the user should be able to log in with the new email address and same password. | ✓ | ✓ | ✓ | ✓ | ✓ | ✓ | ✓ | ✓ | ✓ | ✓ | ✓ |
Profile - email change - cancel pending change | Canceling an email change should remove the email address pending verification from the user's email change profile view and enable them to start a new email change process. | ✓ | ✓ | ✓ | ✓ | ✓ | ✓ | ✓ | ✓ | ✓ | ✓ | ✓ |
Profile - password change - current password invalid | An error should appear asking the user to type their current password, if they enter an incorrect one. | ✓ | ✓ | ✓ | ✓ | ✓ | ✓ | ✓ | ✓ | ✓ | ✓ | ✓ |
Profile - password change - new password invalid | If the user enters a new password that does not meet the minimum requirements, they should receive an error message accordingly. | ✓ | ✓ | ✓ | ✓ | ✓ | ✓ | ✓ | ✓ | ✓ | ✓ | ✓ |
Profile - password change - successful | If the user enters a valid current and new password, they should receive a message that their password was successfully changed, and only be able to log in with their new password. | ✓ | ✓ | ✓ | ✓ | ✓ | ✓ | ✓ | ✓ | ✓ | ✓ | ✓ |
Profile - addresses - no addresses | For user accounts with no saved addresses, the Default and Other Address(es) columns should be displayed, with only an Add Address button under Default Address. | ✓ | ✓ | ✓ | ✓ | ✓ | ✓ | ✓ | ✓ | ✓ | ✓ | ✓ |
Profile - addresses - only non-default address | For user accounts with only Other Addresses, and no default, the list of Other Addresses should be displayed, with Make Default, Edit Address, and Delete Address buttons for each. The Add Address button should be displayed under the Default Address header. | ✓ | ✓ | ✓ | ✓ | ✓ | ✓ | ✓ | ✓ | ✓ | ✓ | ✓ |
Profile - addresses - only default address | For user accounts with only a default address, the Other Addresses column should be empty of addresses. The default address should be displayed under the Default Address header, along with an Edit Address button. An Add Address button should be displayed under the Other Addresses header. | ✓ | ✓ | ✓ | ✓ | ✓ | ✓ | ✓ | ✓ | ✓ | ✓ | ✓ |
Profile - addresses - default and other addresses | If the user account has both default and other addresses, the default address should be displayed with an Edit Address button. Add Address should be displayed right under the Other Addresses header, and below that button, the non-default saved addresses should be displayed, with the Make Default, Edit Address, and Delete Address buttons. | ✓ | ✓ | ✓ | ✓ | ✓ | ✓ | ✓ | ✓ | ✓ | ✓ | ✓ |
Profile - addresses - make default | Make Default should move the current default address (if applicable) to Other Addresses, and the address above the Make Default button to the Default Address. The user should receive a success message. | ✓ | ✓ | ✓ | ✓ | ✓ | ✓ | ✓ | ✓ | ✓ | ✓ | ✓ |
Profile - addresses - delete address | Delete Address should delete the address above the clicked button from the account. The user should receive a success message. The message will either indicate that the address was completely deleted (backend: from the user account and the Django Addresses model). Or that the address was only deleted from their account, but still exists in the system, as an order is associated with it. In this case, the user is just deleted from that column in the Django Addresses model. | ✓ | ✓ | ✓ | ✓ | ✓ | ✓ | ✓ | ✓ | ✓ | ✓ | ✓ |
Profile - addresses - add address - missing required field | An input error should indicate a missing required field, if applicable. | ✓ | ✓ | ✓ | ✓ | ✓ | ✓ | ✓ | ✓ | ✓ | ✓ | ✓ |
Profile - addresses - add address - successful non-default | Adding a non-default address to the account should redirect the user to the main profile addresses page, provide a success message, and display the new address in the Other Addresses list, along with the others (if applicable). | ✓ | ✓ | ✓ | ✓ | ✓ | ✓ | ✓ | ✓ | ✓ | ✓ | ✓ |
Profile - addresses - add address - successful default | Adding a default address to the account should remove the default flag from the previous default address (if applicable), redirect the user to the main profile addresses page, provide a success message, display the new address under Default Address, and display the previous default under Other Addresses (if applicable). | ✓ | ✓ | ✓ | ✓ | ✓ | ✓ | ✓ | ✓ | ✓ | ✓ | ✓ |
Profile - addresses - edit address - invalid address ID | If the address ID in the URL is invalid for addresses for the logged-in user, a custom error should appear. | ✓ | ✓ | ✓ | ✓ | ✓ | ✓ | ✓ | ✓ | ✓ | ✓ | ✓ |
Profile - addresses - edit address - missing required field | An input error should indicate a missing required field, if applicable. | ✓ | ✓ | ✓ | ✓ | ✓ | ✓ | ✓ | ✓ | ✓ | ✓ | ✓ |
Profile - addresses - edit address - successful non-default | Editing an address as non-default should redirect the user to the main profile addresses page, provide a success message, and display the updated address in the Other Addresses list, along with the others (if applicable). | ✓ | ✓ | ✓ | ✓ | ✓ | ✓ | ✓ | ✓ | ✓ | ✓ | ✓ |
Profile - addresses - edit address - successful default | Editing an address as default should remove the default flag from the previous default address (if applicable), redirect the user to the main profile addresses page, provide a success message, display the updated address under Default Address, and display the previous default under Other Addresses (if applicable). | ✓ | ✓ | ✓ | ✓ | ✓ | ✓ | ✓ | ✓ | ✓ | ✓ | ✓ |
Profile - orders - no orders | A message advising that there are no orders to display should be shown. | ✓ | ✓ | ✓ | ✓ | ✓ | ✓ | ✓ | ✓ | ✓ | ✓ | ✓ |
Profile - orders - with order(s) | A list of (limited) order information should be displayed for each order linked to the account. Each order should also have a button to view the details for that order. | ✓ | ✓ | ✓ | ✓ | ✓ | ✓ | ✓ | ✓ | ✓ | ✓ | ✓ |
Profile - orders - with orders(s) - larger screens | Screen widths > 1100px should display text headers for the list of order information. | ✓ | N/A | N/A | ✓ | ✓ | ✓ | ✓ | ✓ | ✓ | ✓ | ✓ |
Profile - orders - with order(s) - smaller screens | Screen widths < 1100px should display icons instead of text headers. Widths < 500px should additional update the "View Order" button text to "View". | ✓ | ✓ | ✓ | ✓ | ✓ | ✓ | ✓ | ✓ | ✓ | ✓ | ✓ |
Profile - orders - order details | The basic order information should be displayed, as well as a table below that to display details for the products purchased, and prices for the order. | ✓ | ✓ | ✓ | ✓ | ✓ | ✓ | ✓ | ✓ | ✓ | ✓ | ✓ |
Profile - orders - order details - invalid ID | If the order ID in the URL is invalid for orders for the logged-in user, a custom error should appear. | ✓ | ✓ | ✓ | ✓ | ✓ | ✓ | ✓ | ✓ | ✓ | ✓ | ✓ |
Profile - orders - order details - larger screens | Screen widths > 1100px should display text headers for the list of order information. | ✓ | N/A | N/A | ✓ | ✓ | N/A | ✓ | ✓ | ✓ | ✓ | ✓ |
Profile - orders - order details - smaller screens | Screen widths < 1100px should display icons instead of text headers. Screen widths < 800px should additionally completely remove the product image, and the "Individual Price" column from the purchased product details. | ✓ | ✓ | ✓ | ✓ | ✓ | ✓ | ✓ | ✓ | ✓ | ✓ | ✓ |
Profile - orders - order details - status pending/processing/ready | Orders with pending, processing, or ready to ship status should display a Request Cancellation button in the order information. This button displays a mailto modal, that includes custom email subject/body content. | ✓ | ✓ | ✓ | ✓ | ✓ | ✓ | ✓ | ✓ | ✓ | ✓ | ✓ |
Profile - orders - order details - status shipped/delivered | Orders with shipped or delivered status should display a Request Refund button in the order information. This button displays a mailto modal, that includes custom email subject/body content. | ✓ | ✓ | ✓ | ✓ | ✓ | ✓ | ✓ | ✓ | ✓ | ✓ | ✓ |
Profile - orders - order details - without tracking | Orders without a tracking link in the database should display "N/A" in the tracking column. | ✓ | ✓ | ✓ | ✓ | ✓ | ✓ | ✓ | ✓ | ✓ | ✓ | ✓ |
Profile - orders - order details - with tracking | Orders with a tracking link should display linked "Track" text that, when clicked, opens the shipping provider's page to display tracking information. | ✓ | ✓ | ✓ | ✓ | ✓ | ✓ | ✓ | ✓ | ✓ | ✓ | ✓ |
Profile pages - logged out | Trying to access any profile pages while logged out should display a message that the user needs to log in to view the page. | ✓ | ✓ | ✓ | ✓ | ✓ | ✓ | ✓ | ✓ | ✓ | ✓ | ✓ |
Homepage - featured products | The homepage should display 1 new featured product, 1 featured sports product, and 1 featured health product. All 3 should be different products (no overlap with new and sports/health). All should have in-stock options. Where no featured product is available for a certain category, a message should be displayed to that effect. | ✓ | ✓ | ✓ | ✓ | ✓ | ✓ | ✓ | ✓ | ✓ | ✓ | ✓ |
Homepage - out of stock flavours/sizes | Out of stock options should be greyed out. | ✓ | ✓ | ✓ | ✓ | ✓ | ✓ | ✓ | ✓ | ✓ | ✓ | ✓ |
Homepage - product link | Clicking the product image/name should open the individual product page. | ✓ | ✓ | ✓ | ✓ | ✓ | ✓ | ✓ | ✓ | ✓ | ✓ | ✓ |
Homepage - add to cart | Adding a product to cart should display a Django message with a link to View Cart. | ✓ | ✓ | ✓ | ✓ | ✓ | ✓ | ✓ | ✓ | ✓ | ✓ | ✓ |
All products - view | Accessing the All Products view should display all active products. By default, they are sorted by descending stock count. Where no active products are available, a message should be displayed to that effect. | ✓ | ✓ | ✓ | ✓ | ✓ | ✓ | ✓ | ✓ | ✓ | ✓ | ✓ |
All products - out of stock flavours/sizes | Out of stock options should be greyed out. | ✓ | ✓ | ✓ | ✓ | ✓ | ✓ | ✓ | ✓ | ✓ | ✓ | ✓ |
All products - fully out of stock | Products where all flavours and sizes are out of stock should hide the select dropdowns and add to cart feature, and only display "Out Of Stock" text below the product image and name. | ✓ | ✓ | ✓ | ✓ | ✓ | ✓ | ✓ | ✓ | ✓ | ✓ | ✓ |
All products - product link | Clicking on the product image/name should open the individual product page. | ✓ | ✓ | ✓ | ✓ | ✓ | ✓ | ✓ | ✓ | ✓ | ✓ | ✓ |
All products - add to cart | Adding a product to cart should display a Django message with a link to View Cart. | ✓ | ✓ | ✓ | ✓ | ✓ | ✓ | ✓ | ✓ | ✓ | ✓ | ✓ |
All products - sorting | Using the sort menu should sort and display the products according to the option selected. All products should still be displayed (except for the On Sale sort option). | ✓ | ✓ | ✓ | ✓ | ✓ | ✓ | ✓ | ✓ | ✓ | ✓ | ✓ |
Sports products - view | Accessing the Sports Products view should display all active products with the main category "sports. By default, they are sorted by descending stock count. Where no sports products are available, a message should be displayed to that effect. | ✓ | ✓ | ✓ | ✓ | ✓ | ✓ | ✓ | ✓ | ✓ | ✓ | ✓ |
Sports products - out of stock flavours/sizes | Out of stock options should be greyed out. | ✓ | ✓ | ✓ | ✓ | ✓ | ✓ | ✓ | ✓ | ✓ | ✓ | ✓ |
Sports products - fully out of stock | Products where all flavours and sizes are out of stock should hide the select dropdowns and add to cart feature, and only display "Out Of Stock" text below the product image and name. | ✓ | ✓ | ✓ | ✓ | ✓ | ✓ | ✓ | ✓ | ✓ | ✓ | ✓ |
Sports products - product link | Clicking on the product image/name should open the individual product page. | ✓ | ✓ | ✓ | ✓ | ✓ | ✓ | ✓ | ✓ | ✓ | ✓ | ✓ |
Sports products - add to cart | Adding a product to cart should display a Django message with a link to View Cart. | ✓ | ✓ | ✓ | ✓ | ✓ | ✓ | ✓ | ✓ | ✓ | ✓ | ✓ |
Sports products - sorting | Using the sort menu should sort and display the products according to the option selected. All sports products should still be displayed (except for the On Sale sort option). | ✓ | ✓ | ✓ | ✓ | ✓ | ✓ | ✓ | ✓ | ✓ | ✓ | ✓ |
Health products - view | Accessing the Health Products view should display all active products with the main category "health". By default, they are sorted by descending stock count. Where no health products are available, a message should be displayed to that effect. | ✓ | ✓ | ✓ | ✓ | ✓ | ✓ | ✓ | ✓ | ✓ | ✓ | ✓ |
Health products - out of stock flavours/sizes | Out of stock options should be greyed out.Using the sort menu should sort and display the products according to the option selected. All products should still be displayed (except for the On Sale option). | ✓ | ✓ | ✓ | ✓ | ✓ | ✓ | ✓ | ✓ | ✓ | ✓ | ✓ |
Health products - fully out of stock | Products where all flavours and sizes are out of stock should hide the select dropdowns and add to cart feature, and only display "Out Of Stock" text below the product image and name. | ✓ | ✓ | ✓ | ✓ | ✓ | ✓ | ✓ | ✓ | ✓ | ✓ | ✓ |
Health products - product link | Clicking on the product image/name should open the individual product page. | ✓ | ✓ | ✓ | ✓ | ✓ | ✓ | ✓ | ✓ | ✓ | ✓ | ✓ |
Health products - add to cart | Adding a product to cart should display a Django message with a link to View Cart. | ✓ | ✓ | ✓ | ✓ | ✓ | ✓ | ✓ | ✓ | ✓ | ✓ | ✓ |
Health products - sorting | Using the sort menu should sort and display the products according to the option selected. All health products should still be displayed (except for the On Sale sort option). | ✓ | ✓ | ✓ | ✓ | ✓ | ✓ | ✓ | ✓ | ✓ | ✓ | ✓ |
New products - view | Accessing the What's New view should display all active products that were added to the database in the last 30 days. By default, they are sorted by descending stock count. Where no new products are available, a message should be displayed to that effect. | ✓ | ✓ | ✓ | ✓ | ✓ | ✓ | ✓ | ✓ | ✓ | ✓ | ✓ |
New products - out of stock flavours/sizes | Out of stock options should be greyed out. | ✓ | ✓ | ✓ | ✓ | ✓ | ✓ | ✓ | ✓ | ✓ | ✓ | ✓ |
New products - product link | Clicking on the product image/name should open the individual product page. | ✓ | ✓ | ✓ | ✓ | ✓ | ✓ | ✓ | ✓ | ✓ | ✓ | ✓ |
New products - add to cart | Adding a product to cart should display a Django message with a link to View Cart. | ✓ | ✓ | ✓ | ✓ | ✓ | ✓ | ✓ | ✓ | ✓ | ✓ | ✓ |
New products - sorting | Using the sort menu should sort and display the products according to the option selected. All new products should still be displayed (except for the On Sale sort option). | ✓ | ✓ | ✓ | ✓ | ✓ | ✓ | ✓ | ✓ | ✓ | ✓ | ✓ |
Sorting - Brand A-Z | Using the Brand A-Z sort should ascending sort all products on the page by the product brand name. | ✓ | ✓ | ✓ | ✓ | ✓ | ✓ | ✓ | ✓ | ✓ | ✓ | ✓ |
Sorting - Brand Z-A | Using the Brand Z-A sort should descending sort all products on the page by the product brand name. | ✓ | ✓ | ✓ | ✓ | ✓ | ✓ | ✓ | ✓ | ✓ | ✓ | ✓ |
Sorting - Product A-Z | Using the Product A-Z sort should ascending sort all products on the page by the product name. | ✓ | ✓ | ✓ | ✓ | ✓ | ✓ | ✓ | ✓ | ✓ | ✓ | ✓ |
Sorting - Product Z-A | Using the Product Z-A sort should descending sort all products on the page by the product name. | ✓ | ✓ | ✓ | ✓ | ✓ | ✓ | ✓ | ✓ | ✓ | ✓ | ✓ |
Sorting - Price Low to High | Using the Price Low-High sort should ascending sort all products on the page by the product price. It should sort any in-stock option, not just the auto- or user-selected ones. Fully out of stock products will no longer be visible, as they don't have a price. | ✓ | ✓ | ✓ | ✓ | ✓ | ✓ | ✓ | ✓ | ✓ | ✓ | ✓ |
Sorting - Price High to Low | Using the Price High-Low sort should descending sort all products on the page by the product price. It should sort any in-stock option, not just the auto- or user-selected ones. Fully out of stock products will no longer be visible, as they don't have a price. | ✓ | ✓ | ✓ | ✓ | ✓ | ✓ | ✓ | ✓ | ✓ | ✓ | ✓ |
Sorting - On Sale | Using the On Sale sort option is actually filter and should only display products with the sale boolean set to true in the database. Where no products are on sale, a message should be displayed to that effect. | ✓ | ✓ | ✓ | ✓ | ✓ | ✓ | ✓ | ✓ | ✓ | ✓ | ✓ |
Sorting - add to cart | After adding a product to the cart from a sorted view, the sorting should persist until they load a new page (or refresh the current one). | ✓ | ✓ | ✓ | ✓ | ✓ | ✓ | ✓ | ✓ | ✓ | ✓ | ✓ |
Product search - empty input | If the user submits an empty search, they should receive a message that an empty search term was used. | ✓ | ✓ | ✓ | ✓ | ✓ | ✓ | ✓ | ✓ | ✓ | ✓ | ✓ |
Product search - no results | If no product brands, names, or flavours in the database match the search term, the user should receive a message to that effect. | ✓ | ✓ | ✓ | ✓ | ✓ | ✓ | ✓ | ✓ | ✓ | ✓ | ✓ |
Product search - no results - modal functions | The message for no results following a product search includes a mailto modal link. The mailto for this scenario includes a pre-filled email subject and body. | ✓ | ✓ | ✓ | ✓ | ✓ | ✓ | ✓ | ✓ | ✓ | ✓ | ✓ |
Product search - brand/name results | A successful search for a product brand or name should display the results in a list similar to the existing product pages, along with a message displaying the searched term. | ✓ | ✓ | ✓ | ✓ | ✓ | ✓ | ✓ | ✓ | ✓ | ✓ | ✓ |
Product search - flavour results | In addition to the functionality used for brand/name search results, a successful flavour search should automatically select the searched flavour in the displayed results (if in stock). | ✓ | ✓ | ✓ | ✓ | ✓ | ✓ | ✓ | ✓ | ✓ | ✓ | ✓ |
Product search - add to cart | After adding a product to the cart from a search results view, the results list should persist until they load a new page or make a new search. | ✓ | ✓ | ✓ | ✓ | ✓ | ✓ | ✓ | ✓ | ✓ | ✓ | ✓ |
Product search - sorting | Using the sort menu should sort and display the products according to the option selected. All new products should still be displayed (except for the On Sale sort option). | ✓ | ✓ | ✓ | ✓ | ✓ | ✓ | ✓ | ✓ | ✓ | ✓ | ✓ |
Product page - view | The individual product page should display the relevant product, detailed product information, and a list of linked products, if applicable. | ✓ | ✓ | ✓ | ✓ | ✓ | ✓ | ✓ | ✓ | ✓ | ✓ | ✓ |
Product page - out of stock flavours/sizes | Out of stock options should be greyed out. | ✓ | ✓ | ✓ | ✓ | ✓ | ✓ | ✓ | ✓ | ✓ | ✓ | ✓ |
Product page - fully out of stock | The product flavour (if applicable), size, price, quantity, and add to cart should all be hidden, if nothing is in stock. The "Availability" text should update to include "Out Of Stock". | ✓ | ✓ | ✓ | ✓ | ✓ | ✓ | ✓ | ✓ | ✓ | ✓ | ✓ |
Product page - add to cart | Adding a product to cart should display a Django message with a link to View Cart. | ✓ | ✓ | ✓ | ✓ | ✓ | ✓ | ✓ | ✓ | ✓ | ✓ | ✓ |
Product page - show/hide description | Clicking the Show/Hide description button should display or hide the description for the product. | ✓ | ✓ | ✓ | ✓ | ✓ | ✓ | ✓ | ✓ | ✓ | ✓ | ✓ |
Product page - show/hide ingredients | Clicking the Show/Hide ingredients button should display or hide the ingredients for the product. | ✓ | ✓ | ✓ | ✓ | ✓ | ✓ | ✓ | ✓ | ✓ | ✓ | ✓ |
Product page - no linked products | The entire linked product section, with the "you may also like..." text should be hidden, if there are none. | ✓ | ✓ | ✓ | ✓ | ✓ | ✓ | ✓ | ✓ | ✓ | ✓ | ✓ |
Product page - linked products | In-stock products that share categories with the individual product page product should be listed in the linked products section at the bottom of the page. Product details and add to cart options should be visible and functional for each linked product. | ✓ | ✓ | ✓ | ✓ | ✓ | ✓ | ✓ | ✓ | ✓ | ✓ | ✓ |
Product page - linked products - out of stock flavours/sizes | Out of stock options should not be displayed at all. | ✓ | ✓ | ✓ | ✓ | ✓ | ✓ | ✓ | ✓ | ✓ | ✓ | ✓ |
Product page - linked products - add to cart | Adding a product to cart should display a Django message with a link to View Cart. | ✓ | ✓ | ✓ | ✓ | ✓ | ✓ | ✓ | ✓ | ✓ | ✓ | ✓ |
Add to cart - single product | When successfully adding a single product to the cart, a success message should appear for the user, using the singular "product". | ✓ | ✓ | ✓ | ✓ | ✓ | ✓ | ✓ | ✓ | ✓ | ✓ | ✓ |
Add to cart - multiple products | When successfully adding a multiple products to the cart at a time, a success message should appear for the user, using the plural "products". | ✓ | ✓ | ✓ | ✓ | ✓ | ✓ | ✓ | ✓ | ✓ | ✓ | ✓ |
Add to cart - stock exceeded - nothing added | When adding a product to the cart where the user already has the maximum available stock of that same product in their cart, a Django message should appear that the product could not be added, and why. | ✓ | ✓ | ✓ | ✓ | ✓ | ✓ | ✓ | ✓ | ✓ | ✓ | ✓ |
Add to cart - stock exceeded - maximum added (multiple) | If the total quantity for a product in the user's cart plus the quantity they want to add for the same product, exceeds the stock, the maximum possible amount will be added, with a message explaining this to the user (using plural terminology). | ✓ | ✓ | ✓ | ✓ | ✓ | ✓ | ✓ | ✓ | ✓ | ✓ | ✓ |
Add to cart - stock exceeded - maximum added (single) | If the total quantity for a product in the user's cart plus the quantity they want to add for the same product, exceeds the stock, the maximum possible amount will be added, with a message explaining this to the user (using singular terminology). | ✓ | ✓ | ✓ | ✓ | ✓ | ✓ | ✓ | ✓ | ✓ | ✓ | ✓ |
Add to cart - view cart link | After trying to add a product to the cart, the Django message should include a link for the user to click to view their cart. | ✓ | ✓ | ✓ | ✓ | ✓ | ✓ | ✓ | ✓ | ✓ | ✓ | ✓ |
Guest and account carts | If not logged in, the user's cart contents should be added to their Django session. Once cookies are cleared, for any reason, the cart contents will be gone. If logged in, the user's cart contents should be saved to the Django SavedItems model. This data persists until the user deletes it, or completes the purchase. | ✓ | ✓ | ✓ | ✓ | ✓ | ✓ | ✓ | ✓ | ✓ | ✓ | ✓ |
Cart merge function - non-checkout | When a user adds products to their cart when not logged in, and then logs in after, the cart contents from their Django session storage is merged with their SavedItems cart contents. | ✓ | ✓ | ✓ | ✓ | ✓ | ✓ | ✓ | ✓ | ✓ | ✓ | ✓ |
Cart merge function - checkout | When a user logs in during the checkout process, carts should not be merged. The Django session cart should be used, and should overwrite the SavedItems cart. | ✓ | ✓ | ✓ | ✓ | ✓ | ✓ | ✓ | ✓ | ✓ | ✓ | ✓ |
Cart - with products | The cart view should display product information and overall cart pricing. Below 800px screen width, the text headers are replaced by icons, and the product image and Individual Price column are removed. | ✓ | ✓ | ✓ | ✓ | ✓ | ✓ | ✓ | ✓ | ✓ | ✓ | ✓ |
Cart - product removed | If a product is removed from the user's cart, due to stock changes, they should see a message to that effect when next accessing the cart. | ✓ | ✓ | ✓ | ✓ | ✓ | ✓ | ✓ | ✓ | ✓ | ✓ | ✓ |
Cart - stock changed for product | If the quantity for a product in the user's cart is reduced, due to stock changes, they should see a message to that effect when next accessing the cart. | ✓ | ✓ | ✓ | ✓ | ✓ | ✓ | ✓ | ✓ | ✓ | ✓ | ✓ |
Cart - remove product from cart | When the user removes a product from their cart (red X beside the quantity input), they should receive a message confirming the product was removed. | ✓ | ✓ | ✓ | ✓ | ✓ | ✓ | ✓ | ✓ | ✓ | ✓ | ✓ |
Cart - update cart (add/remove quantity) | When a user clicks the "Update Cart" button, the current quantity for products should be updated in their session cart, and if logged in, their SavedItems cart. They should also receive a confirmation message that their cart was updated. | ✓ | ✓ | ✓ | ✓ | ✓ | ✓ | ✓ | ✓ | ✓ | ✓ | ✓ |
Cart - empty cart function and modal | Clicking the Empty Cart button should display a modal for the user to confirm, as the action cannot be undone. Once confirmed, the full cart contents should be deleted from the Django session, and if logged in, also from the SavedItems model. | ✓ | ✓ | ✓ | ✓ | ✓ | ✓ | ✓ | ✓ | ✓ | ✓ | ✓ |
Checkout pages - back to cart | All checkout pages (signin, addresses, confirm) should have a button that leaves the checkout process and loads the cart view on-click. | ✓ | ✓ | ✓ | ✓ | ✓ | ✓ | ✓ | ✓ | ✓ | ✓ | ✓ |
Checkout - signin - create account | If not logged in, the first checkout page should display a button for the user to create an account, which takes them through the standard account signup flow and pages. | ✓ | ✓ | ✓ | ✓ | ✓ | ✓ | ✓ | ✓ | ✓ | ✓ | ✓ |
Checkout - signin - forgot password | The initial checkout page when not logged in should include a forgot password password, that takes the user through the normal forgot password flow and pages. | ✓ | ✓ | ✓ | ✓ | ✓ | ✓ | ✓ | ✓ | ✓ | ✓ | ✓ |
Checkout - signin - login | The initial checkout page when not logged in should display login fields. This login should include the standard checks for correct emails/passwords. Upon successful login, the user should be directed to the next checkout page (addresses). | ✓ | ✓ | ✓ | ✓ | ✓ | ✓ | ✓ | ✓ | ✓ | ✓ | ✓ |
Checkout - signin - guest checkout | The initial checkout page when not logged in should display a guest checkout button, that lets the user access the second checkout page (addresses) without logging in. | ✓ | ✓ | ✓ | ✓ | ✓ | ✓ | ✓ | ✓ | ✓ | ✓ | ✓ |
Checkout - addresses - logged out | The addresses checkout, when not logged in, should display 2 address forms - one for shipping, and oen for billing. Above the billing address form, a button for the same as shipping function should be displayed. | ✓ | ✓ | ✓ | ✓ | ✓ | ✓ | ✓ | ✓ | ✓ | ✓ | ✓ |
Checkout - addresses - logged in - saved addresses | When logged in, the address checkout should show a dropdown for saved addresses linked to the user's account. If the account has no saved addresses linked, the view should be the same as when logged out. | ✓ | ✓ | ✓ | ✓ | ✓ | ✓ | ✓ | ✓ | ✓ | ✓ | ✓ |
Checkout - addresses - logged in - select saved address | When selecting a saved address from the dropdown, the form data should auto-fill, based on the selected address. | ✓ | ✓ | ✓ | ✓ | ✓ | ✓ | ✓ | ✓ | ✓ | ✓ | ✓ |
Checkout - addresses - logged in - default saved address | If the user has a saved address marked as default in their account, the form should have that address auto-filled when accessing the page. | ✓ | ✓ | ✓ | ✓ | ✓ | ✓ | ✓ | ✓ | ✓ | ✓ | ✓ |
Checkout - addresses - logged in - no default saved address | If the user has saved addresses, but none are marked as default, the latest address added to the account should be auto-filled in the form. | ✓ | ✓ | ✓ | ✓ | ✓ | ✓ | ✓ | ✓ | ✓ | ✓ | ✓ |
Checkout - addresses - logged in - change autofilled input | When a user edits an input with auto-filled content, the saved address dropdown should change from the originally selected address, to "Select Saved Address". | ✓ | ✓ | ✓ | ✓ | ✓ | ✓ | ✓ | ✓ | ✓ | ✓ | ✓ |
Checkout - addresses - logged in - new address function | When the user selects "New Address" from the dropdown, it should empty all form input fields. | ✓ | ✓ | ✓ | ✓ | ✓ | ✓ | ✓ | ✓ | ✓ | ✓ | ✓ |
Checkout - addresses - same as shipping function | Clicking the "Same as Shipping" button should copy all input values from the Shipping Address, to the Billing Address. | ✓ | ✓ | ✓ | ✓ | ✓ | ✓ | ✓ | ✓ | ✓ | ✓ | ✓ |
Checkout - addresses - missing required fields | An input error should appear if the user does not fill in all required address fields. | ✓ | ✓ | ✓ | ✓ | ✓ | ✓ | ✓ | ✓ | ✓ | ✓ | ✓ |
Checkout - addresses - successful | Successfully entering a shipping and billing address and clicking Next should bring the user to the last checkout page (confirm and purchase). | ✓ | ✓ | ✓ | ✓ | ✓ | ✓ | ✓ | ✓ | ✓ | ✓ | ✓ |
Checkout - confirm - show/hide cart function | Clicking the Show/Hide Cart button should display and hide the product details in the cart. Totals (sub, shipping, grand) should always be visible. | ✓ | ✓ | ✓ | ✓ | ✓ | ✓ | ✓ | ✓ | ✓ | ✓ | ✓ |
Checkout - confirm - stock changes | The user's cart contents should be checked against the product stock when accessing the confirm checkout page, and when clicking confirm purchase. Any cart changes should then be displayed in the cart section of the confirm checkout page. | ✓ | ✓ | ✓ | ✓ | ✓ | ✓ | ✓ | ✓ | ✓ | ✓ | ✓ |
Checkout - confirm - emptied cart | If the user's cart is completely emptied during checkout, due to stock changes, they should be redirected back to the cart page, and see a message listing the issue and removed products. | ✓ | ✓ | ✓ | ✓ | ✓ | ✓ | ✓ | ✓ | ✓ | ✓ | ✓ |
Checkout - confirm - edit address function | Using the Edit Address button on the confirm checkout page, should bring the user back to the address checkout page. However, the previously entered addresses should be autofilled in the form instead. | ✓ | ✓ | ✓ | ✓ | ✓ | ✓ | ✓ | ✓ | ✓ | ✓ | ✓ |
Checkout - confirm - note to seller | Users can add a note to seller on teh confirm checkout page, that should be saved to the user's order, and PaymentIntent. When using the Edit Address function, the order note should be saved, and be autofilled when confirming the edited address and going back to the confirm checkout page. | ✓ | ✓ | ✓ | ✓ | ✓ | ✓ | ✓ | ✓ | ✓ | ✓ | ✓ |
Checkout - confirm - invalid card number | Entering an invalid card number in the stripe input field should display an error. | ✓ | ✓ | ✓ | ✓ | ✓ | ✓ | ✓ | ✓ | ✓ | ✓ | ✓ |
Checkout - confirm - invalid expiry date | Entering an invalid expiry date in the stripe input field should display an error. | ✓ | ✓ | ✓ | ✓ | ✓ | ✓ | ✓ | ✓ | ✓ | ✓ | ✓ |
Checkout - confirm - invalid post code format | Entering an invalid post code format into the stripe input field should display an error. | ✓ | ✓ | ✓ | ✓ | ✓ | ✓ | ✓ | ✓ | ✓ | ✓ | ✓ |
Checkout - confirm - server error 500 (e.g. hosted endpoint off) | If the hosted endpoint is offline, the user's payment should go through, but the webhook handler is unlikely to complete the other necessary actions to create the order in the database and send the user the confirmation email. In this case, they should receive a custom error to not make another purchase and that the support will be in touch. | ✓ | ✓ | ✓ | ✓ | ✓ | ✓ | ✓ | ✓ | ✓ | ✓ | ✓ |
Checkout - confirm - server error 500 - email to admin | The admin should receive an email that the error occurred, so they can review it and, if necessary, re-send the webhook attempt to create the order and send the confirmation emails. | ✓ | ✓ | ✓ | ✓ | ✓ | ✓ | ✓ | ✓ | ✓ | ✓ | ✓ |
Checkout - confirm - successful | For a successful checkout, the order details should be added to the Django OrderHistory model, and the individual products purchased to the Django Purchases model. | ✓ | ✓ | ✓ | ✓ | ✓ | ✓ | ✓ | ✓ | ✓ | ✓ | ✓ |
Checkout - success view | The user should be directed a purchase confirmation page upon successful checkout. This page should display their purchased products, the totals for the order, their shipping and billing address, and their note to seller (if applicable). | ✓ | ✓ | ✓ | ✓ | ✓ | ✓ | ✓ | ✓ | ✓ | ✓ | ✓ |
Checkout - confirmation email to user | After a successful purchase, the user should receive a confirmation email. | ✓ | ✓ | ✓ | ✓ | ✓ | ✓ | ✓ | ✓ | ✓ | ✓ | ✓ |
Checkout - confirmation email to admin | After a successful purchase, the admin should receive a confirmation email, so they know to prepare the order. | ✓ | ✓ | ✓ | ✓ | ✓ | ✓ | ✓ | ✓ | ✓ | ✓ | ✓ |
Checkout - error view | For any errors during checkout, or when trying to access the checkout/success page outside of the checkout flow, the user should see a custom error (for checkout issue, page refreshes, or accessing the link manually). For errors and refreshes, a mailto modal to contact support, if needed, should be linked in the text. | ✓ | ✓ | ✓ | ✓ | ✓ | ✓ | ✓ | ✓ | ✓ | ✓ | ✓ |
Automated testing has not yet been implemented. This has been postponed to the 1.1 release.
All pages were checked with Nu HTML Checker. Minor issues identified were resolved, and no errors or other warnings remain.
Contents of every CSS file validate using Jigsaw without errors.
All JavaScript files were checked using JSHint.
The below warnings from JSHint remain, but are not relevant, as per the provided comments:
All other (syntax) issues were resolved.
All python files were checked using PEP8. The only errors are from Django default "AUTH_PASSWORD_VALIDATORS" in the settings.py file (lines too long).
WAVE was used on each page of the site. The majority of issues were contrast errors. Styling on the site was updated to alleviate this for better accessibility.
All pages were checked using Lighthouse. Several minor performance issues (most notably on pages with a lot of scripts and/or images, such as All Products) are due to HTTP/1.1 requests, unused JavaScript (stripe), and render-blocking resources, that are all necessary. Amazon S3 does not support HTTP/2, so an enhancement was raised to potentially switch over to Amazon CloudFront, which additionally seems more cost-effective.
Profile pages have an SEO score of only 91, due to the mobile menu being an uncrawlable link (javascript:void(0);
).
All checkout pages share the same link, so Lighthouse could not evaluate them separately (always loads the checkout address page while Lighthouse is running).
JavaScript product functionality is dependent on the select option dropdowns being sorted the same as the JavaScript JSON. A specific product flavour/size/stock combination helped identify an issue with inconsistent sorting, that led to incorrect/unexpected results being displayed on the page. This, and hopefully any other issues, were resolved by implementing/updating 2 sort functions. Near the start of the product scripts, the product select options on the page are sorted to match the JSON. Near the end, the product select options are sorted for aesthetics (alphabetically/ascending).
The main focus of fixes during testing were due to unique Safari browser behaviours, as the same features worked without issue in Chrome during development and testing.
Android keyboards fire a window resize event, which caused some issues with JavaScript modals. All resize event listeners were updated to check for screen width* resizes instead (Android keyboards resize height only).
While not a bug, of particular note is that the JavaScript modals and mailto links throughout the site are dependent on the user's system and browser settings. This means that the mailto link may not open, and the entire modal may not even appear, for certain users. To help with this, an extra support page was added to the footer, with the support contact email. A link to that page was added to the texts that open the mailto modal, where possible. There are a few areas on the site, where users with strict security settings will still encounter issues, e.g. the Newsletter Signup, and any mailto modals linked specifically to buttons (e.g. order cancellation/refund requests). These users can, of course, still access the support page via the footer, and reach out manually.
Additional minor updates were made throughout testing, when it was determined that better styling or functionality would improve the user experience.
Remaining unfixed bugs can be found in the kanban board for release 1.1 (prepended with [BUG]). Alternatively, in the repository's Issues using the "bug" label.
The site was deployed on Heroku. ElephantSQL was used for the database, as end of life is only in January 2025. PyCharm and GitHub Desktop were used for local development.
pip3 install django==4.2.1
django-admin startproject XX_PROJECT_NAME_XX .
touch .gitignore
python3 manage.py migrate
for the initial migrationHeroku re-uploads the entirety of the static files to AWS with every commit, which causes the free tier limit to be reached within days. To avoid this, DISABLE_COLLECTSTATIC = 1 was added to Config Vars on Heroku. It is then necessary to manually run env USE_AWS='True' bash -c 'python3 manage.py collectstatic'
locally to push the static file changes to production (used by Heroku).
This project additionally uses fixtures to populate initial data into some of the Django models. As these use a primary key of 0, the following needed to be run in Terminal before fixtures could be loaded:
ALTER SEQUENCE XX_TABLE_PKFIELD_SEQ_XX MINVALUE 0 START 1 RESTART 0
Then: python3 manage.py loaddata XX_FIXTURESFILE.yaml_XX
as in Django docs
The base template was cloned from the Code Institute GitHub repository. Various other resources were used for different features. They are all listed below, categorised accordingly.
*These will be replaced with actual in-stock products and details, once these are sourced