O-O-O
🤚
😣/
_/||
_/¯ ¯\_
O’Reilly
👋
\😩
|| \_
_/¯¯\_
Auto Parts
🤚
😳/
_/||
_/¯ ¯\_
An e-commerce platform inspired by O'Reilly, implemented using Spring Boot and Spring Data JPA for the backend. React, JS, and TailWind CSS for the front end.
This project is using an N-tier architecture, which divides the application into three logical layers: the presentation layer, the business layer, and the data layer. The presentation layer handles the user interface and interactions, while the business layer implements the application's logic and processes, and the data layer stores and retrieves data. By separating these layers, we can create a flexible and modular system that's easier to develop, test, and maintain.
-
Sign In:
- Click on the "Sign In" button.
- Enter your username in the "email" field.
- Enter your password in the "password" field.
- Click on the "Login" button.
-
Register:
- If you're a new user, click on the "Register" option.
- Fill in the required details to create a new account.
- Click on the "Register" button to complete the registration process.
- Select a Category:
- Navigate through the website using the drop-down navigation menu.
- Select a desired category to explore items.
- Add Items to Cart:
- Browse through the items and select one that you wish to purchase.
- Click on the "Add to Cart" button.
- Manage Cart:
- Visit the cart page to view selected items.
- Adjust the quantity of the items or remove items as per your need.
- Enter Address Information:
- On the checkout page, fill in your address details.
- Click on "Deliver Here" after ensuring the address is correct.
- Order Confirmation:
- Review and confirm the details of your order.
- Ensure all items, quantities, and pricing are correct.
- Payment:
- Select a payment method and enter the necessary payment details.
- You can use a real credit card and pay me or use a test CC with the number 4242 4242 4242 4242
- Click on "Submit Payment" to finalize your purchase.
- Select a payment method and enter the necessary payment details.
- Application Layer: Manages API endpoints and HTTP request handling.
- Shopping API: Contains business logic and interacts with models and repositories for data access.
- Data Access Objects: Manages data access, potentially interacting with a database.
- Model Layer: Defines data structures and ORM entities.
- Authentication Layer: Manages auth configuration of rest endpoints using JWT token management.
graph TB
subgraph "Frontend Layer"
ViewLayer[View Layer]
end
subgraph "Backend Layer"
subgraph controllerLayer["Application Layer"]
authController[AuthController]
adminOrderController[AdminOrderController]
otherControllers[OtherControllers]
end
subgraph serviceLayer["Service Layer"]
cartService[cartServices]
customerUserService[productServices]
otherServices[OtherServices]
end
subgraph modelLayer["Model Layer"]
cartModel[Cart]
productModel[Product]
otherModels[OtherModels]
end
subgraph repositoryLayer["DAO Layer"]
cartRepository[CartRepository]
productRepository[ProductRepository]
OtherRepositories[OtherRespositories]
end
subgraph authLayer["Authentication Layer"]
Auth[Authentication Layer]
end
subgraph databaseLayer["Database Layer"]
database[Database]
end
end
%% Interaction Flow
ViewLayer -->|HTTP Requests & Responses| controllerLayer
controllerLayer -->|Method Calls| serviceLayer
serviceLayer -->|Data & Logic Processing| modelLayer
serviceLayer -->|CRUD Operations| repositoryLayer
repositoryLayer -->|Data Access| modelLayer
repositoryLayer -->|CRUD Operations| databaseLayer
controllerLayer -->|Utilize Auth| authLayer
serviceLayer -->|Utilize Auth| authLayer
style ViewLayer fill:#f9a826,stroke:#333,stroke-width:2px
style controllerLayer fill:#4caf50,stroke:#333,stroke-width:2px
style serviceLayer fill:#2196f3,stroke:#333,stroke-width:2px
style modelLayer fill:#ff5722,stroke:#333,stroke-width:2px
style repositoryLayer fill:#9c27b0,stroke:#333,stroke-width:2px
style authLayer fill:#e91e63,stroke:#333,stroke-width:2px
style databaseLayer fill:#607d8b,stroke:#333,stroke-width:2px
- Frontend Layer Responsibility: Manages user interface and experience. Interaction: Communicates with the backend through HTTP requests and updates the UI based on the responses.
- Backend Layer
- Controller Layer
- Responsibility: Handles HTTP requests and responses.
- Interaction: Receives requests from the frontend, interacts with the service layer for data processing, and sends back responses.
- Service Layer
- Responsibility: Manages business logic and data processing.
- Interaction: Communicates with the controller layer and accesses/modifies data through the repository layer, utilizing models for data structure.
- Model Layer
- Responsibility: Defines data structures.
- Interaction: Used by the service and repository layers to define and manage data.
- Repository Layer
- Responsibility: Manages data access and CRUD operations.
- Interaction: Interacts with the database and the service layer, using models to manage data.
- Controller Layer
- Auth Layer
- Responsibility: Secures rest endpoints.
- Interaction: Provides authentication settings (like security and JWT management) to the controller and service layers.
The Frontend Layer sends HTTP requests to the Controller Layer and receives responses to update the UI. The Controller Layer communicates with the Service Layer to process requests and manage business logic. The Service Layer interacts with the Repository Layer to access and manage data in the database, utilizing the Model Layer for data structures. The Repository Layer performs CRUD operations directly on the Database. Both the Controller and Service Layers utilize configurations from the Auth Layer.
erDiagram
address {
bigint id
bigint user_id
varchar city
varchar first_name
varchar last_name
varchar mobile
varchar state
varchar street_address
varchar zip_code
}
cart {
bigint id
bigint user_id
int total_items
double total_price
}
cart_item {
bigint id
double price
int quantity
bigint cart_id
bigint product_pid
bigint user_id
}
categories {
bigint id
int level
varchar name
bigint parent_category_id
}
customer_order {
bigint id
bigint user_id
bigint shipping_address_id
double amount_paid
int num_items
double total_price
datetime created_at
datetime order_date
datetime payment_date
datetime delivery_date
varchar order_id
varchar order_status
varchar payment_id
varchar payment_method
varchar status
varchar transaction_id
}
order_item {
bigint id
double price
int quantity
bigint order_id
bigint product_pid
bigint user_id
}
payment_information {
bigint user_id
varchar card_number
varchar cardholder_name
varchar cvv
date expiration_date
}
product {
bigint pid
double price
int quantity
int num_ratings
bigint category_id
varchar title
varchar description
varchar image_url
varchar product_line
varchar product_family
varchar stock
datetime created_at
}
rating {
bigint id
bigint user_id
bigint product_id
double rating
datetime created_at
}
review {
bigint id
bigint user_id
bigint product_id
varchar review
datetime created_at
}
user {
bigint id
varchar first_name
varchar last_name
varchar email
varchar password
varchar mobile
varchar role
datetime created_at
}
address ||--o{ user : "belongs_to"
user ||--o{ cart : "has_one"
user ||--o{ cart_item : "has_many"
user ||--o{ payment_information : "has_many"
user ||--o{ rating : "has_many"
user ||--o{ review : "has_many"
user ||--o{ customer_order : "has_many"
cart ||--o{ cart_item : "has_many"
cart_item ||--o{ product : "belongs_to"
categories ||--o{ product : "has_many"
categories }|..|{ categories : "has_many"
product ||--o{ rating : "has_many"
product ||--o{ review : "has_many"
customer_order ||--o{ address : "has_one"
customer_order ||--o{ order_item : "has_many"
order_item ||--o{ product : "belongs_to"
- Rapid Development Consequences:
- Quick design choices for speedy app development led to intricate debugging due to runtime issues.
- Learning: Embrace a "think twice, code once" mindset.
- Usage of useEffect and React.StrictMode:
- Challenges with doubled component loads and subsequent dual database calls.
- Learning: Utilize loading states/spinners to manage null states and enhance UX.
- State Management and Child Components:
- Struggles in managing multiple states and effective use of child components.
- Learning: Explore using session or local storage as alternatives or supplements to Redux states.
- Props Passing to Child Components:
- Faced re-renders and bugs due to unnecessary prop passing through component chains.
- Product Catalog Fetching:
- Direct fetching from the database led to redundant data retrieval.
- Learning: Employ caching mechanisms for optimized data fetching.
- Z-Index Issues in UI:
- Confronted issues with z-index values from various packages.
- Learning: Gain a thorough understanding of third-party libraries to manage conflicts effectively.
- Gradle Commands and Dependency Refresh:
- Manual refreshing in IntelliJ was required for expected dependency refresh.
- Deployment Configuration Challenges:
- Learning: Ensure tailored configurations per environment for seamless deployment.
- CORS Filters:
- Realized the crucial impact of the sequential arrangement of CORS filters.
- Runtime Errors with Foreign Key Constraints:
- Faced runtime errors related to Foreign Key constraints during schema changes.
- Learning: Consider using Flyaway or Liquibase for efficient database schema updates in production.
- Incremental Development and Testing:
- Learning: Adopt a methodology of building and testing each feature incrementally.
- Database Interaction Issues:
- Encountered various database-related issues, like
HttpMessageNotWritableException. - Learning: Utilize DTOs to manage dependency cycles and mitigate initialization issues.
- Encountered various database-related issues, like
- Package Detection through Component Scanning:
- Issues with package detection during component scanning due to package structures.
- Learning: Ensure logical package structures for flawless component scanning.
- Proactive Logging:
- Lack of a proactive logging strategy hindered efficient debugging.
- Learning: Implement comprehensive logging from the development onset.
- Availability of API Endpoints:
- Restricted API testing due to limited endpoint availability.
- Learning: Develop a robust set of API endpoints for versatile application interactions.
- Controllers should be as thin as possible, and they should only call at most one service layer method and not catch or throw exceptions.
- Delegate response code and error message responsibilities to a global exception handler. Exceptions should be called from the service layer which is intercepted by Spring exception handlers (ex: ControllerAdvice) where exceptions are then transformed into HTTP responses and returned to the client.
- Do not add business logic to this layer or have multiple calls within an endpoint, this is easier for testing purposes
- Validate input received in the request to ensure it is valid and meets the expected format.
- Modularity and reusability are key.
- Logging and HTTP responses should NOT be handled in the service layer. They should use exception propoagation to relay errors to the controller layer for proper logging and HTTP response translation.
- Exception handling should generally follow two rules:
- Some sort of recovery logic
- throw an api level exception to be handled by the controller layer
- Use DTOs to transfer data between the controller and the service. This helps keep the service layer decoupled from the controller layer and allows for better control over the data being transferred.
Ex: Propagating exceptions in the service layer
@Service
public class orderService {
@Autowired
private orderRepository orderRepository;
pulbic Order createOrder(Order order) {
try {
Order createOrder = orderRepository.save(order);
} catch (specificException e) {
throw new ClientErrorException("Order already exists");
}
}
}
- They represent the data used by the service layer. Don't prematurely handle exceptions here.
- The only exceptions the model should handle are related to DB access. Propoage all other exceptions to the service layer.
- Use flyaway or something else for DB versioning for long term maintainability
- HTTP response codes should be converted into java exception types so the caller can hanlde the possible reponses a client call can return.
- Use localstorage/ sessionStorage / caching
- Minimize the amount of DB calls you need to make, networking limitations are real
- Continously deploy changes - something might work in a dev environment but not another
- Take the time to test early and test often
- Create wireframes for what user flows and user interactions should occur - when building on the fly you will miss these




