Introduction
In the previous posts, I shared an overview of POS Lite and how I designed the backend using Spring Boot, JWT authentication, PostgreSQL and REST APIs.
In this third post, I want to focus on the frontend.
The frontend is the part of the application that users interact with directly, so my goal was not only to build screens that work, but also to create an interface that feels practical, clean and easy to use for a real point of sale system.
For this part of the project, I used React, Next.js and Material UI.
Frontend Goals
Before building the interface, I defined a few goals.
The frontend needed to be:
- Clean and simple
- Easy to navigate
- Fast for daily operations
- Connected to the backend API
- Useful for business users, not only developers
- Organized enough to grow as the project evolves
A point of sale system should not feel complicated. Users need to manage products, check inventory, process sales and review reports without wasting time.
That idea guided many of the UI decisions in the project.
Tech Stack
The frontend uses:
- React
- Next.js
- Material UI
- TypeScript
- Axios
- React Hook Form
- React Context
- React Hot Toast
- Barcode scanner support
This stack helped me build a modern interface while keeping the project organized and maintainable.
Main Frontend Modules
POS Lite includes several frontend modules.
Authentication
The authentication module handles the login flow.
The user enters their credentials, the frontend sends the request to the backend and then uses the authentication token to access protected pages.
This module was important because most of the application should only be available to authenticated users.
Dashboard
The dashboard gives users a quick overview of the business.
It can show useful information such as:
- Total products
- Recent sales
- Low stock alerts
- Sales metrics
- General system activity
The dashboard is important because it is usually the first screen users see after logging in.
Products
The products module allows users to manage product information.
This includes:
- Creating products
- Editing products
- Viewing product details
- Assigning categories
- Managing prices
- Tracking stock
This is one of the core parts of the system because products are used in inventory, sales and reports.
Categories
The categories module helps organize products.
As the inventory grows, categories make the system easier to use and search.
Sales
The sales module is one of the most important screens in the project.
The goal was to create a flow where users can:
- Search or scan a product
- Add it to the sale
- Adjust quantities
- Review totals
- Complete the transaction
This module helped me think more about usability because a sales screen needs to be fast and clear.
Inventory
The inventory module helps users monitor product stock.
It can also show low stock alerts so that users know when they need to restock certain products.
Reports
The reports module is used to review business information.
Some examples are:
- Sales reports
- Inventory reports
- Low stock reports
This helped me think beyond forms and tables and more about how the frontend can support decision-making.
Application Structure
I organized the frontend into reusable sections.
A simplified structure looks like this:
/app
/(auth)
login
/(dashboard)
dashboard
products
categories
sales
inventory
reports
/components
/ui
/forms
/tables
/layout
/context
AuthContext
/services
api.ts
/types
index.ts
The goal was to avoid putting all the logic inside pages.
By separating components, services, context and types, the project becomes easier to maintain and extend.
API Communication
The frontend communicates with the backend through an API service.
Instead of writing API calls directly in every component, I created a reusable setup using Axios.
A simplified example looks like this:
import axios from "axios";
const api = axios.create({
baseURL: process.env.NEXT_PUBLIC_API_URL,
});
api.interceptors.request.use((config) => {
const token = localStorage.getItem("token");
if (token) {
config.headers.Authorization = `Bearer ${token}`;
}
return config;
});
export default api;
This makes it easier to send authenticated requests to protected backend endpoints.
It also keeps API configuration in one place instead of repeating the same logic across the app.
Authentication Flow
The frontend authentication flow works like this:
- The user submits the login form.
- The frontend sends the credentials to the backend.
- The backend returns a JWT token.
- The frontend stores the token.
- Protected requests include the token in the Authorization header.
- The user can access private pages.
This helped me understand how frontend authentication connects with backend security.
UI/UX Decisions
Since POS Lite is a business application, the interface needed to be practical.
Some of the decisions I focused on were:
- Clear navigation
- Simple forms
- Readable tables
- Fast access to common actions
- Feedback messages after user actions
- Consistent layout across pages
- Responsive design for different screen sizes
Small details matter in this type of application.
For example, after creating or updating a product, the user should immediately know if the action was successful.
That is why notifications and clear feedback are important.
Forms and Validation
Forms are used across many modules, especially products, categories and sales.
I used form handling to make the user experience smoother and reduce errors.
Some examples of validation include:
- Required fields
- Valid prices
- Valid stock quantities
- Product category selection
- Login credentials
Good validation improves the user experience because users can correct mistakes before submitting incorrect data.
Barcode Scanner Support
One of the features I wanted to include was barcode scanner support.
For a point of sale system, barcode scanning can make product search and sales faster.
The idea is simple:
- The user scans a barcode.
- The frontend reads the barcode value.
- The system searches for the matching product.
- The product is added to the sale or displayed for editing.
This feature made the project feel much closer to a real POS system.
Challenges
One of the biggest challenges was keeping the frontend organized as the number of screens increased.
At the beginning, it is easy to build each page separately.
But as the project grows, duplicated code becomes a problem.
Some questions I had to think about were:
- Which components should be reusable?
- Where should API calls live?
- How should authenticated state be managed?
- How should forms be structured?
- How can the UI remain simple as features are added?
These decisions helped me understand that frontend development is not only about making the interface look good.
It is also about structure, usability and maintainability.
What I Learned
Building the frontend helped me improve in several areas:
- Creating reusable components
- Managing authentication state
- Connecting React with a Spring Boot backend
- Structuring a Next.js application
- Working with API services
- Building forms and tables
- Thinking about user experience
- Designing screens for real workflows
The biggest lesson was that a good frontend is not just about visuals.
A good frontend should help users complete their tasks clearly and efficiently.
What’s Next
In the next post, I will focus on deployment.
I will share how I deployed POS Lite using AWS EC2, Docker, Vercel and Cloudflare, and what I learned from connecting the frontend and backend in a production-like environment.
Thanks for reading.





















