This repository contains my solution for Factorial's challenge on managing sporting equipment in a retail environment.
This exercise is designed as a framework-less solution using Java-based technologies for the backend, along with PostgreSQL and React.
The application allows users to:
- View a list of available products.
- Create and manage new orders.
- Log in as a user or admin for role-based access.
- Modify existing products and their available parts.
- Delete existing products from the system.
- Apply various types of restrictions to customer product selections.
- Customize and select parts for a specific product.
- View detailed product information and part availability.
- Manage the product parts related to each product (add, remove, update).
- Add products and product parts via admin interface.
- Add selected products with customized parts to the shopping cart.
- Display and handle error messages for invalid selections or actions.
The solution is based on the purchase of customizable sporting goods, meaning that an order consists of multiple components or parts.
The app currently contains the following views:
- Home Page: Placeholder page with no significant functionality.
- Product List Page: Displays a list of available products.
- Order Creation Page: Allows users to create an order by selecting multiple options, validating selections, checking prices, and finalizing the order.
- 404 Page: Displays an error page for invalid routes.
Admin Views:
- Admin Dashboard: Provides three buttons for managing products, parts, and orders (currently without significant functionality).
- Product Management Modal (Admin): Opens for adding, editing, and deleting products.
- Parts Management Modal (Admin): Opens for adding, editing, and deleting product parts.
- Conditions Management Modal (Admin): Opens for adding and deleting product part conditions.
- β Java 17 β Required for backend development. Install from Oracle or your preferred JDK provider.
- βοΈ Maven β Used for managing backend dependencies. Install from Apache Maven.
- ποΈ PostgreSQL β Relational database for storing application data. Install from PostgreSQL You can also use a .
- π’ Node.js (LTS version) β Required for frontend development. Install from Node.js.
- π¦ npm or yarn β Package managers for installing frontend dependencies (npm is part of Node.js).
- Java 17 β Programming language used for backend development.
- Maven β Dependency manager and build automation tool.
- Undertow β Lightweight and high-performance web server.
- PostgreSQL β Relational database used for data storage.
- HikariCP β High-performance JDBC connection pool for efficient database access.
- Flyway β Database migration and version control tool.
- Jackson Databind β JSON serialization and deserialization library.
- Jackson JSR310 β Provides support for Java Date/Time API in JSON processing.
- SLF4J β Logging abstraction framework.
- Logback β Logging implementation for SLF4J.
- JWT (JSON Web Token) β For handling authentication and authorization with tokens.
- Exec Maven Plugin β Enables running Java applications using Maven.
- Flyway Maven Plugin β Automates and manages database migrations.
- DBeaver β GUI-based database management tool for PostgreSQL.
- React β JavaScript library for building dynamic user interfaces.
- React DOM β React package for interacting with the browser DOM.
- React Router DOM β Enables client-side routing for single-page applications.
- Axios β HTTP client for making API requests.
- Formik β Form management library for handling user input in React.
- React Icons β Collection of vector icons for React applications.
- Styled Components β Library for writing CSS directly inside React components.
- TypeScript β Strongly typed superset of JavaScript for better maintainability.
- Vite β Modern build tool and fast development server.
- ESLint β Linter for enforcing code quality and best practices.
- Prettier β Code formatter to maintain consistent style.
- TypeScript ESLint β Integrates ESLint with TypeScript.
- React Hooks ESLint Plugin β Ensures correct usage of React Hooks.
- Vite React Plugin β Provides React support for Vite.
- Globals β Defines global variables for ESLint.
git clone https://github.com/ezepsosa/marcus_bike_project.git
cd <project-folder>
Make sure you have PostgreSQL running with a properly configured database.
Modify the flyway.conf file located at:
marcus-bike-api/src/main/resources/flyway.conf
Update only the following lines with your PostgreSQL credentials:
flyway.url=POSTGRESQL-URL
flyway.user=POSTGRESQL-USER
flyway.password=POSTGRESQL-PASSWORD
π Important: Only edit these lines.
Execute the following command to apply the database scripts:
mvn flyway:migrate
π οΈ If you want to clean the database before running the migrations, execute:
mvn flyway:clean
Ensure you are in the marcus-bike-api directory and run:
mvn clean package
mvn exec:java
cd marcus-bike-client
npm install
npm run dev
Once both the backend and frontend are running:
- The backend will be available at:
http://localhost:8080/api - The frontend will be available at:
http://localhost:5173
You can test the API using Postman, cURL, or any other API testing tool.
.
marcus-bike-project
βββ marcus-bike-api
β βββ pom.xml
β βββ src
β β βββ main
β β β βββ java/com/ezepsosa/marcusbike
β β β β βββ App.java
β β β β βββ config/ (Application Configuration)
β β β β βββ controllers/ (REST API Controllers)
β β β β βββ dto/ (Data Transfer Objects)
β β β β βββ mappers/ (Object Mappers)
β β β β βββ models/ (Database Models)
β β β β βββ repositories/ (Data Access Layer)
β β β β βββ routes/ (API Routing and CORS)
β β β β βββ security/ (JWT handling security)
β β β β βββ services/ (Business Logic)
β β β β βββ utils/ (Helper Utilities)
β β β βββ resources/
β β β β βββ flyway.conf
β β β β βββ logback.xml
β β β β βββ db/migration/ (Database Migration Scripts)
β β βββ test/
β β β βββ java/com/ezepsosa/marcusbike/AppTest.java
βββ marcus-bike-client
β βββ package.json
β βββ tsconfig.json
β βββ vite.config.ts
β βββ src/
β β βββ assets/ (Static Images & Icons)
β β βββ components/ (Reusable UI Components)
β β βββ conext/ (Context components)
β β βββ models/ (Type Definitions)
β β βββ pages/ (Application Views)
β β βββ routes/ (Client-side Routing)
β β βββ server/ (API Service Calls)
β β βββ styles/ (Global & Shared Styles)
- GET
/usersβ Retrieves a list of all users (Requires ADMIN role). - GET
/users/{id}β Retrieves details of a specific user (Requires ADMIN role). - POST
/usersβ Creates a new user. - PUT
/users/{id}β Updates an existing user (Requires USER or ADMIN role). - DELETE
/users/{id}β Deletes a user by ID (Requires ADMIN role).
- GET
/productpartconditionsβ Retrieves all product part conditions. - POST
/productpartconditionsβ Creates a new product part condition (Requires ADMIN role). - DELETE
/productpartconditions/{productpartid}/{dependantproductpartid}β Deletes a product part condition (Requires ADMIN role).
- GET
/productpartsβ Retrieves all product parts. - POST
/productpartsβ Creates a new product part (Requires ADMIN role). - PUT
/productparts/{id}β Updates an existing product part (Requires ADMIN role). - DELETE
/productparts/{id}β Deletes a product part by ID (Requires ADMIN role). - GET
/products/{id}/productpartsβ Retrieves all product parts related to a specific product. - POST
/products/{id}/productpartsβ Adds a relation between a product and a product part (Requires ADMIN role). - DELETE
/products/{productId}/productparts/{id}β Removes a product part from a product (Requires ADMIN role).
- GET
/productsβ Retrieves a list of all products. - GET
/products/{id}β Retrieves details of a specific product. - POST
/productsβ Creates a new product (Requires ADMIN role). - PUT
/products/{id}β Updates an existing product (Requires ADMIN role). - DELETE
/products/{id}β Deletes a product by ID (Requires ADMIN role).
- GET
/ordersβ Retrieves a list of all orders. - GET
/orders/{id}β Retrieves details of a specific order. - GET
/users/{userId}/ordersβ Retrieves all orders placed by a specific user. - POST
/ordersβ Creates a new order (Requires USER or ADMIN role). - DELETE
/orders/{id}β Deletes an order by ID (Requires USER or ADMIN role). - GET
/orders/{id}/orderlinesβ Retrieves order lines associated with a specific order.
- POST
/loginβ Authenticates a user and returns an authentication token.
The system follows a modular design based on the following principles:
-
Separation of Concerns (SoC):
- Each layer of the application has a clear and specific responsibility.
- Business logic, data access, and presentation layers are strictly separated.
-
Manual Dependency Injection:
- Avoids the use of IoC frameworks, providing full control over the lifecycle of objects.
- Ensures transparency in dependency management.
-
DAO-Based Data Access with Raw SQL:
- No ORM is used, allowing full control over SQL queries.
- Queries are optimized manually for performance and efficiency.
-
Explicit and Lightweight Configuration:
- The system is fully configurable without relying on annotations or implicit framework configurations.
The project leverages lightweight, modern, and well-maintained libraries to ensure high performance, maintainability, and efficiency while avoiding unnecessary dependencies:
- Undertow: Selected for its simplicity and superior efficiency in high-concurrency environments compared to Jetty and Tomcat.
- HikariCP: A high-performance JDBC connection pool optimized for heavy workloads, offering significantly better performance than Apache DBCP.
- PostgreSQL JDBC Driver: Provides full control over SQL queries, enhancing database efficiency and allowing for manual query optimization. The decision to avoid Hibernate was also driven by the desire to increase project complexity and challenge.
- Flyway: Chosen for its simplicity and effectiveness in managing database migrations, ensuring a structured and version-controlled approach.
- Jackson: A highly efficient and configurable JSON serialization library, widely adopted in Java applications.
- SLF4J + Logback: A flexible and lightweight logging solution, offering easy configuration and broad industry adoption.
- JWT (JSON Web Token): Chosen for its simplicity and security in handling user authentication and authorization. It enables secure, stateless authentication by generating tokens upon user login.
The frontend follows a modular and scalable structure to ensure maintainability and efficiency.
-
Component-Based Structure
- The UI is built with React functional components, making it reusable and easy to maintain.
- Each component focuses on a single responsibility, improving organization.
-
Routing & Navigation
- Uses React Router DOM to manage navigation between pages.
-
Styling Approach
- Uses Styled Components to apply CSS within components, keeping styles modular and easy to manage.
-
API Integration
- Uses Axios to fetch and send data from the backend, handling requests efficiently.
This framework-less approach was chosen to keep the application lightweight, scalable, and fully customizable. The selected libraries ensure:
- High performance, avoiding unnecessary abstractions.
- Scalability, with a modular structure that can be expanded easily.
- Full control, allowing direct management of configurations and dependencies.*
- Implement tests for both backend and frontend to improve reliability.
- Add a dedicated login endpoint.
- Add more business logic validations to enforce data integrity and application rules.
- Improve error handling by making responses more consistent and easier to debug.
- Refine how user conditions are managed (currently handled via a database trigger but could also be controlled in frontend and backend).
- Optimize database queries by reducing redundancy and improving indexing.
- Implement a refresh token mechanism to avoid requiring frequent logins.
- Improve logging and monitoring.
- Provide API documentation using Swagger/OpenAPI for better maintainability and ease of use.
- Add new attributes to the models, such as the product category attribute, to enable future filtering by specific product categories when the store expands beyond just selling bicycles.
- Improve UI and styling for better consistency and user experience.
- Add a registration page
- Add JWT authentication to manage user sessions securely.
- Improve user experience by adding better loading indicators, clearer error messages, and stronger validation.
- Add more client-side validation to reduce unnecessary API calls.
- Improve product search and filtering options.
- Add pagination.
- Improve type safety in the React application.
- Fix the issue with select fields where Formik doesn't maintain the initial value when left as default in some selects.
- Error propagation.
This project was built as part of a technical challenge, focusing on backend and frontend development, database design, and API architecture.
If any clarifications are needed, feel free to reach out. π
