BopStop is a full stack partial clone of the e-commerce website Bandcamp. This platform serves as a hub for music creators and fans, enabling artists to share and sell their music while fostering a community of listeners who can explore, purchase, and support their favorite sounds and merchandise.
Feature List | Database Schema | User Stories
-
Clone this repository (only this branch).
-
Install dependencies.
pipenv install -r requirements.txt
-
Create a .env file based on the example with proper settings for your development environment.
-
Make sure the SQLite3 database connection URL is in the .env file.
-
This starter organizes all tables inside the
flask_schema
schema, defined by theSCHEMA
environment variable. Replace the value forSCHEMA
with a unique name, making sure you use the snake_case convention. -
Get into your pipenv, migrate your database, seed your database, and run your Flask app:
pipenv shell
flask db upgrade
flask seed all
flask run
-
To run the React frontend in development,
cd
into the react-vite directory and runnpm i
to install dependencies. Next, runnpm run build
to create thedist
folder. The starter has modified thenpm run build
command to include the--watch
flag. This flag will rebuild the dist folder whenever you change your code, keeping the production version up to date.
- Users
- Products
- Reviews
- Cart
- Wishlist
- Users can search for products or sellers using keywords and view relevant search results.
- Users can preview music tracks before deciding whether to purchase.
- Add preview image when editing or adding a new product.
- Create fan users that have different permission than artist users.
- Allowing the ability to pay with credit card information, linking product purchases with banking information
Users can log in using their email or username.
-
Require authentication: False
-
Request
- Method: POST
- Route path: /api/auth/login
- Body:
{ "email_or_username": "user@example.com or username", "password": "your_password" }
-
Successful Response
- Status Code: 200
- Body:
{ "id": 1, "artistName": "exampleArtist", "username": "username", "email": "user@example.com", "bio": "example bio here", "profileImageUrl": "exampleprofile.url", "bannerImageUrl": "examplebanner.url", "createdAt": "2024-10-30 23:51:27", "updatedAt": "2024-10-30 23:51:27", "products": [productsList with their info], }
-
Error Response: Couldn't find user with given credentials
- Status Code: 404
- Body:
{
"message": "Login failed. Please check your credentials and try again."
}
Users should be able to logout if they are currently logged in
-
Require authentication: True
-
Request
- Method: GET
- Route path: /api/auth/logout
- Body: None
-
Successful Response
- Status Code: 200
- Body:
{ "message": "User logged out" }
Users can create a new account by signing up.
-
Require authentication: False
-
Request
- Method: POST
- Route path: /api/auth/signup
- Body:
{ "artistname": "desired_artistName", "username": "desired_username", "email": "user@example.com", "password": "your_password", "confirm_password": "your_password" }
-
Successful Response
- Status Code: 201
- Body:
{ "id": 21, "artistName": "desired_artistName", "username": "desired_username", "email": "user@example.com", "bio": "", "profileImageUrl": "", "bannerImageUrl": "", "createdAt": "2024-11-01 02:12:32", "updatedAt": "2024-11-01 02:12:32", "products": [] }
-
Error Response: User already exists
- Status Code: 409
- Body:
{ "message": "Username or email already exists." }
Users can delete their account.
-
Require authentication: True
-
Request
- Method: DELETE
- Route path: /api/users/session
- Body: None
-
Successful Response
- Status Code: 204
- Body:
{ "message": "User deleted successfully." }
-
Error Response: User is not authenticated
- Status Code: 401
- Body:
{ "message": "Unauthorized" }
Users can retrieve their own user information.
-
Require authentication: True
-
Request
- Method: GET
- Route path: /api/users/session
- Body: None
-
Successful Response
- Status Code: 200
- Body:
{ "id": 1, "username": "current_username", "email": "current_user@example.com", "bio": "Current user's bio", "profileImageUrl": "currentprofile.url", "bannerImageUrl": "currentbanner.url", "createdAt": "2024-10-30 23:51:27", "updatedAt": "2024-10-30 23:51:27", "products": [products list here] }
-
Error Response: User is not logged in
- Status Code: 401
- Body:
{ "message": "Unauthorized" }
Users should be able to view all Products.
-
Require authentication: false
-
Request
- Method: GET
- Route path: /api/products
- Body: none
-
Successful Response
-
Status Code: 200
-
Body:
{ "products": [ { "productId": 1, "name": "ProductName", "userId": 1, "type": "CD", "genre": "Rock", "price": 3, "description": "Description Here", "imageUrl": "image.url" } // more products... ] }
-
Return details of a product specified by its id.
-
Require Authentication: False
-
Request
- Method: GET
- Route path: /api/products/:productId
- Body: None
-
Successful Response
- Status Code: 200
- Body:
{ "productId": 1, "name": "ProductName", "userId": 1, "type": "CD", "genre": "Rock", "price": 3, "description": "Description Here", "imageUrl": "image.url", "createdAt": "2024-10-29 18:38:09.043894", "updatedAt": "2024-10-29 18:38:09.043894" }
-
Error Response
- Status Code: 404
- Body:
{ "message": "Product not found!" }
Return details of a product specified by its id.
-
Require Authentication: True
-
Request
- Method: GET
- Route path: /api/products/current
- Body: None
-
Successful Response
- Status Code: 200
- Body:
[ { "productId": 1, "name": "Adele - 30", "userId": 1, "type": "CD", "genre": "", "price": "14.99", "description": "Adele's highly anticipated album showcasing her powerful vocals and emotional lyrics.", "imageUrl": ".../seed-images/products/Adele-30(CD).jpg", "createdAt": "2024-10-30 23:51:27", "updatedAt": "2024-10-30 23:51:27" }, { // more listed products } ]
-
Error Response
- Status Code: 401
- Body:
{ "message": "Unauthorized" }
Return all products by specified user's id.
-
Require Authentication: False
-
Request
- Method: GET
- Route path: /api/products/:userId
- Body: None
-
Successful Response
- Status Code: 200
- Body:
[ { "productId": 1, "name": "Adele - 30", "userId": 1, "type": "CD", "genre": "", "price": "14.99", "description": "Adele's highly anticipated album showcasing her powerful vocals and emotional lyrics.", "imageUrl": ".../seed-images/products/Adele-30(CD).jpg", "createdAt": "2024-10-30 23:51:27", "updatedAt": "2024-10-30 23:51:27" }, { // more listed products } ]
-
Error Response - User not found
- Status Code: 404
- Body:
{ "message": "Artist not found" }
Users should be able to create a Product.
-
Require authentication: True
-
Request
- Method: POST
- Route path: /api/products
- Body:
{ "name": "ProductName2", "userId": 2, "type": "CD", "genre": "Rock", "price": 4, "description": "Description here too", "imageUrl": "image.url" }
-
Successful Response
- Status Code: 201
- Body:
{ "product": { "productId": 2, "name": "ProductName2", "userId": 2, "type": "CD", "genre": "Rock", "price": 4, "description": "Description here too", "imageUrl": "image.url" } }
-
Error Response: Body Validation Errors
- Status Code: 400
- Body:
{ "message": "Bad Request", "errors": { "name": "Name is required", "userId": "User is required", "type": "Type is required", "price": "Price must be a positive number", "description": "Description is required", "imageUrl": "Image is required" } }
Users should be able to update their Product(s).
-
Require authentication: True
-
Require proper Authentication: Product must belong to the user
-
Request
- Method: Put
- Route path: /api/products/:productId
- Body:
{ "name": "ProductName", "userId": 1, "type": "CD", "genre": "Rock", "price": 2, "description": "Updated description here", "imageUrl": "image.url" }
-
Successful Response
- Status Code: 200
- Body:
{ "product": { "productId": 1, "name": "ProductName", "userId": 1, "type": "CD", "genre": "Rock", "price": 2, "description": "Updated description here", "imageUrl": "image.url" } }
-
Error Response: Body Validation Errors
- Status Code: 400
- Body:
{ "message": "Bad Request", "errors": { "name": "Name is required", "userId": "User is required", "type": "type is required", "price": "Price must be a positive number", "description": "Description is required", "imageUrl": "Image is required" } }
-
Error Response: Couldn't find a product by specified id
- Status Code: 404
- Body:
{ "message": "Product could not be found!" }
Users should be able to delete their Product(s).
-
Require authentication: True
-
Require proper Authentication: Product must belong to the user
-
Request
- Method: DELETE
- Route path: /api/products/:productId
- Body: None
-
Successful Response
- Status Code: 200
- Body:
{ "message": "Product successfully deleted" }
-
Error Response: Couldn't find a product by specified id
- Status Code: 404
- Body:
{ "message": "Product not be found!" }
Users should be able to view all reviews on a Product.
-
Require authentication: False
-
Request
- Method: GET
- Route path: /api/products/:productId/reviews
- Body: None
-
Successful Response
- Status Code: 200
- Body:
{ "reviews": [ { "id": 1, "productId": 1, "userId": 1, "review": "Random comment" } // more reviews... ] }
-
Error Response: Couldn't find a product by specified id
- Status Code: 404
- Body:
{ "message": "Product could not be found!" }
Users should be able to create a review for a Product.
-
Require authentication: True
-
Request
- Method: POST
- Route path: /api/products/:productId/reviews
- Body:
{ "review": "Random comment" }
-
Successful Response
- Status Code: 201
- Body:
{ "review": { "id": 2, "productId": 1, "userId": 2, "review": "Random comment" } }
-
Error Response: Body Validation Errors
- Status Code: 400
- Body:
{ "message": "Bad **Request**", "errors": { "review": "Review is required" } }
-
Error Response: Couldn't find a product by specified id
- Status Code: 404
- Body:
{ "message": "Product could not be found" }
-
Error Response: Review from the current user already Exists for the Product
- Status Code: 500
- Body:
{ "message": "User already has a review for this product" }
Users should be able to update their review for a Product.
-
Require authentication: True
-
Request
- Method: Put
- Route path: /api/reviews/:reviewId
- Body:
{ "review": "Random updated comment" }
-
Successful Response
- Status Code: 200
- Body:
{
"review": {
"id": 2,
"productId": 1,
"userId": 2,
"review": "Random updated comment"
}
}
-
Error Response: Body Validation Errors
- Status Code: 400
- Body:
{ "message": "Bad **Request**", "errors": { "review": "Review is required" } }
-
Error Response: Couldn't find a product by specified id
-
Status Code: 404
-
Body:
{ "message": "Product could not be found!" }
-
Error Response: Couldn't find a product by specified id
-
Status Code: 403
-
Body:
{ "message": "Requires proper authorization" }
-
Users should be able to delete their review from a Product.
-
Require authentication: True
-
Request
- Method: DELETE
- Route path: /api/reviews/:reviewId
- Body: None
-
Successful Response
- Status Code: 200
- Body:
{ "message": "Review successfully deleted" }
-
Error Response: Couldn't find a review by specified id
- Status Code: 404
- Body:
{ "message": "Review couldn't be found" }
Users should be able to view all products added to their cart.
-
Require authentication: True
-
Request
- Method: GET
- Route path: /api/cart
- Body: None
-
Successful Response
- Status Code: 200
- Body:
{ "cart": { "id": 1, "products": [ { "productId": 1, "name": "ProductName", "quantity": 2, "price": 2 } // more products in cart ] } }
-
Error Response: User not logged in
- Status Code: 401
- Body:
{ "message": "Unauthorized" }
Users should be able to add products to their shopping cart.
-
Require authentication: True
-
Request
- Method: POST
- Route path: /api/cart
- Body:
{ "productId": 1, "quantity": 2 }
-
Successful Response
- Status Code: 200
- Body:
{ "message": "Product has been added to cart", "cart": { "id": 1 "products": [ { "productId": 1, "name": "ProductName", "quantity": 2, "price": 2 } ] } }
-
Error Response: Body Validation Errors
- Status Code: 400
- Body:
{ "message": "Product not found" }
Users should be able to remove products from their shopping cart.
-
Require authentication: True
-
Request
- Method: DELETE
- Route path: /api/cart/:productId
- Body: None
-
Successful Response
- Status Code: 200
- Body:
{ "message": "Product removed from Cart" }
-
Error Response: Can't find product
- Status Code: 404
- Body:
{ "message": "Can't find product in Cart" }
Users should be able to perform a "transaction" to complete their purchase.
-
Require authentication: True
-
Request
- Method: POST
- Route path: /api/cart/checkout
- Body: None
-
Successful Response
- Status Code: 200
- Body:
{ "message": "Your transaction of 19.98 was successful" }
-
Error Response
- Status Code: 404
- Body:
{ "message": "Your cart is empty" }
Users should be able to view all of their wishlisted products.
- Require authentication: True
- Request
- Method: GET
- Route path: /api/wishlist
- Body: None
- Successful Response
- Status Code: 200
- Body:
{
"wishlist": [
{
"productId": 1,
"productName": "ProductName",
"userId": 1,
"price": 2
},
{
"productId": 2,
"name": "ProductName2",
"userId": 1,
"price": 4
}
]
}
Users should be able to wishlisted products.
-
Require authentication: True
-
Request
- Method: POST
- Route path: /api/wishlist
- Body:
{ "productId": 1 }
-
Successful Response
- Status Code: 200
- Body:
{ "message": "Product added to the wishlist" "wishlist": [ { "productId": 1, "productName": "ProductName", "userId": 2, "price": 2 } ] }
-
Error Response: Product already exists in wishlist
- Status Code: 400
- Body:
{ "message": "Product is already in the wishlist" }
Users should be able to delete products from their Wishlist.
-
Request Authentication: True
-
Request
- Method: DELETE
- Route path: /api/wishlist/:productId
- Body: None
-
Successful Response
- Status Code: 200
- Body:
{ "message": "Product removed from the wishlist" }
-
Error Response
- Status Code: 404
- Body:
{ "message": "Product not found in wishlist" }