A sophisticated backend SaaS platform for managing multi-store mobile retail operations in real-time, combining advanced inventory management, transactional integrity, and enterprise-grade security.
MobileStore is an enterprise-level REST API backend designed for managing multi-store mobile phone retail operations. It provides:
- 🏪 Multi-store Management: Centralized control across distributed retail locations
- 📦 Intelligent Inventory Management: Real-time stock tracking with historical analytics
- 💼 Role-Based Access Control (RBAC): Granular security with employer and employee hierarchies
- 🛒 Order Management System: Complete order lifecycle from creation to fulfillment
- 💰 Financial Tracking: Sales analytics and spending management
- 🔐 Enterprise Security: JWT-based authentication with transactional integrity
This system is engineered for high-traffic retail environments requiring reliability, scalability, and rigorous data consistency.
┌─────────────────────────────────────┐
│ REST API Controllers Layer │ <- HTTP Request Handling
├─────────────────────────────────────┤
│ Service Layer (Business Logic) │ <- Orchestration & Validation
├─────────────────────────────────────┤
│ Repository Layer (Data Access) │ <- JPA/JDBC Abstraction
├─────────────────────────────────────┤
│ Database Layer (PostgreSQL) │ <- Persistent Storage
└─────────────────────────────────────┘
| Component | Purpose | Highlights |
|---|---|---|
| Controllers | Request routing & HTTP response handling | Clean request/response mapping with ResponseBuilder |
| Services | Business logic orchestration | @Transactional boundaries for data consistency |
| Repositories | Data persistence layer | Spring Data JPA with custom query methods |
| DTOs | Data transfer objects | Decoupling API contracts from domain models |
| Security | Authentication & Authorization | JWT tokens with SecurityValidator |
| Exceptions | Global error handling | Custom exception hierarchy with meaningful messages |
✓ @Transactional(rollbackOn = Exception.class) annotations
✓ Multi-entity operations atomically processed
✓ OrderContent service: Ensures order/stock synchronization
✓ Employer → Store Owner privileges
✓ Employee → Store Manager/Salesperson roles
✓ @PreAuthorize("hasRole('EMPLOYER')") method-level security
✓ SecurityValidator: Custom access validation per entity
- Stock Tracking: Real-time quantity updates with historical snapshots
- Restock Operations: Automated stock replenishment logic
- Sales Analytics: Product-level sales statistics over time periods
- Bulk Operations: Efficient multi-product updates via Map-based processing
Custom exception hierarchy for semantic error differentiation:
ElementNotFoundException- Resource not foundCreationFailedException- Creation operationsAccessDeniedException- Authorization failuresNotAuthenticatedException- Missing credentials
- JWT Authentication: JJWT library with 24-hour token expiration
- Password Encoding: Spring Security
PasswordEncoderintegration - OAuth2 Support: OAuth2 client configuration
- Stateless Security: Fully stateless API design
// Date-range filtering with relationship traversal
findAllByDateIsBetweenAndPreviousStockIsNotNullAndProductIdIn()
// Relationship validation across stores
existsAllByIdInAndStoreId()
// User context-aware queries
findStoresByEmployerIdOrEmployeesId()@Service
public class OrderContentService implements IOrderContent {
private final OrderRepository orderRepository;
private final ProductRepository productRepository;
private final StockService stockService;
private final SecurityValidator securityValidator;
// Constructor injection - explicit dependencies
public OrderContentService(
OrderService orderService,
SecurityValidator securityValidator,
OrderRepository orderRepository,
ProductRepository productRepository,
OrderContentRepository orderContentRepository,
ProductService productService,
CategoryRepository categoryRepository,
StockService stockService
) {
// Clean initialization
}Why this is excellent:
- ✅ No service locators or static dependencies
- ✅ Full testability via mock injection
- ✅ Clear contract through constructor signature
- ✅ Respects Single Responsibility Principle (SRP)
// Domain Model (Internal)
@Data
public class Order {
private UUID id;
private Store store;
private Person maker;
private OrderStatus status;
private Map<Product, OrderContent> products;
}
// DTO Layer (API Contract)
@Data
public class OrderDto {
private UUID orderId;
private String storeName;
private String makerUsername;
private OrderStatus status;
public void fromOrder(Order order) {
this.orderId = order.getId();
this.storeName = order.getStore().getName();
// Prevents exposing internal relationships
}
}Why this is excellent:
- ✅ Loose Coupling: API clients unaffected by domain changes
- ✅ Security: Sensitive fields never exposed
- ✅ Clean Contracts: Explicit API boundaries
- ✅ Respects Interface Segregation Principle (ISP)
@Service
public class OrderService implements IOrder {
@Override
@PreAuthorize("(@securityValidator.hasRole('EMPLOYER') || @securityValidator.hasRole('EMPLOYEE'))")
@Transactional(rollbackOn = Exception.class)
public Order create(Order order, UUID storeId)
throws CreationFailedException, NotAuthenticatedException, AccessDeniedException {
// 1. Security validation
secCheck.validateStoreAccess(storeId);
// 2. Context extraction
Authentication auth = secCheck.getAuthentication();
Person person = secCheck.findUserFromAuthentication(auth, Person.class);
// 3. Business logic with atomicity guarantee
Store store = storeRepository.getReferenceById(storeId);
order.setStore(store);
order.setMaker(person);
order.setStatus(OrderStatus.CREATED);
return orderRepository.save(order);
}
}Why this is excellent:
- ✅ Declarative Security: AOP-based authorization
- ✅ Transactional Safety: Complete operation atomicity
- ✅ Separation of Concerns: Security ≠ Business Logic
- ✅ Respects Open/Closed Principle (OCP) - extensible security rules
@Transactional
public List<Stock> sellManyProduct(Map<UUID, Double> sellProducts) {
List<UUID> productIds = sellProducts.keySet().stream().toList();
List<Product> products = productRepository.findAllById(productIds);
// Functional mapping: O(1) lookups for validation
Map<UUID, Stock> productsStocks = products.stream()
.collect(Collectors.toMap(Product::getId, Product::getStock));
List<Stock> updatedStocks = new ArrayList<>(productsStocks.size());
// Validation + Update in single pass
sellProducts.forEach((productId, quantity) -> {
Stock stock = productsStocks.get(productId);
if ((stock.getTotalSell() + quantity) > stock.getBaseStock()) {
throw new OperationFailedException("product out of stock");
}
stock.setTotalSell(stock.getTotalSell() + quantity);
updatedStocks.add(stock);
});
return stockRepository.saveAll(updatedStocks);
}Why this is excellent:
- ✅ Functional Programming: Immutable stream operations
- ✅ Performance: Single database query, O(1) validation lookups
- ✅ Bulk Operations: Batch saves reduce DB round-trips
- ✅ Respects Dependency Inversion Principle (DIP)
@Transactional
public Order update(Order order, UUID id)
throws UpdateFailedException, ElementNotFoundException, AccessDeniedException {
Authentication auth = secCheck.getAuthentication();
// Runtime polymorphism: determine user type dynamically
Class<? extends Person> userType = (auth.getAuthorities()
.stream()
.anyMatch(a -> Objects.requireNonNull(a.getAuthority()).contains("EMPLOYER")))
? Employer.class
: Employee.class;
Person user = secCheck.findUserFromAuthentication(auth, userType);
Order existingOrder = orderRepository.findById(id)
.orElseThrow(() -> new ElementNotFoundException("Order not found"));
// Authorization: only original maker can update
if (!existingOrder.getMaker().equals(user)) {
throw new AccessDeniedException("You're not the order maker");
}
// State machine: CREATED → VALIDATED → UPDATED
OrderStatus newStatus = switch (order.getStatus()) {
case CREATED -> OrderStatus.VALIDATED;
case VALIDATED -> OrderStatus.UPDATED;
default -> null;
};
order.setStatus(newStatus);
return orderRepository.save(order);
}Why this is excellent:
- ✅ Polymorphism: Type-safe user discrimination
- ✅ State Machines: Enforced valid transitions
- ✅ Authorization Semantics: Business rule enforcement
- ✅ Modern Java: Switch expressions (Java 21)
- ✅ Respects Liskov Substitution Principle (LSP)
- Java 21: Latest LTS with modern language features (records, pattern matching, sealed classes)
- Spring Boot 4.0.0: Enterprise application development
- Spring Security: Authentication & authorization framework
- Spring Data JPA: Object-relational mapping abstraction
- JJWT (JSON Web Tokens): JWT generation and validation
- Spring Security OAuth2 Client: OAuth2 authentication support
- BCrypt Password Encoder: Secure password hashing
- PostgreSQL: Enterprise relational database
- Spring Data JDBC: Alternative lightweight persistence
- Liquibase: Database schema versioning and migration
- Hibernate ORM: JPA implementation
- Maven 3.9.6: Dependency management and build automation
- Docker: Containerization (Alpine-based)
- Eclipse Temurin JDK 21: Official OpenJDK distribution
- Spring Boot Test: Integration testing framework
- AssertJ: Fluent assertion library
- JUnit 5: Modern testing framework
- Lombok: Boilerplate reduction (@Data, @Slf4j)
- Jackson: JSON serialization/deserialization
- SLF4J + Logback: Structured logging
- Java 21+ (JDK)
- Maven 3.9.0+
- PostgreSQL 14+
- Docker (optional)
git clone https://github.com/paka-ops/MobileStore.git
cd MobileStoreCreate application.properties or application-prod.properties:
# Database Configuration
spring.datasource.url=jdbc:postgresql://localhost:5432/mobilestore
spring.datasource.username=your_db_user
spring.datasource.password=your_db_password
# JWT Security
app.jwt.key=your_base64_encoded_secret_key
# Server Port
server.port=8080
# Liquibase Migrations
spring.liquibase.change-log=classpath:db/changelog/db.changelog-master.xml# Using Maven Wrapper (recommended)
./mvnw clean package
# Or standard Maven
mvn clean package -DskipTests# Run with Maven
./mvnw spring-boot:run
# Or run compiled JAR
java -Dspring.profiles.active=prod -jar target/eGestion-0.0.1-SNAPSHOT.jar# Build Docker image
docker build -t mobilestore:latest .
# Run container
docker run -d \
--name mobilestore \
-p 8080:8080 \
-e SPRING_DATASOURCE_URL=jdbc:postgresql://db:5432/mobilestore \
-e APP_JWT_KEY=your_secret_key \
mobilestore:latestPOST /api/v1/employers - Create employer account
POST /api/v1/auth/login - JWT token generation
GET /api/v1/stores - List all stores
POST /api/v1/stores - Create store
PATCH /api/v1/stores/{id} - Update store
DELETE /api/v1/stores/{id} - Delete store
GET /api/v1/products?storeId=uuid - List products by store
POST /api/v1/products?categoryId=uuid - Add product
PATCH /api/v1/products/{id}?quantity=50 - Restock product
GET /api/v1/products/{id}/stats - Product sales analytics
POST /api/v1/orders?storeId=uuid - Create order
GET /api/v1/orders?storeId=uuid&startDate=2026-01-01 - List orders (filtered)
PATCH /api/v1/orders/{id} - Update order status
DELETE /api/v1/orders/{id} - Cancel order
GET /api/v1/employee?storeId=uuid - List store employees
POST /api/v1/employee?storeId=uuid - Hire employee
PATCH /api/v1/employee/{id} - Update employee
┌─────────────┐
│ Client │
└──────┬──────┘
│ 1. POST /login (credentials)
▼
┌─────────────────────────────────┐
│ JwtService.jwtGenerator() │
│ - Generate HS256 signed token │
│ - 24-hour expiration │
│ - Username in subject claim │
└──────┬──────────────────────────┘
│ 2. Return JWT token
▼
┌─────────────┐
│ Client │ 3. Include token in Authorization header
└──────┬──────┘
│
▼
┌─────────────────────────────────┐
│ SecurityValidator │
│ - Verify token signature │
│ - Extract username │
│ - Load user roles │
│ - Apply @PreAuthorize rules │
└─────────────────────────────────┘
Employer (Admin)
├─ Manage stores
├─ Hire employees
├─ View all orders
└─ Access analytics
Employee (Manager/Salesperson)
├─ Create orders
├─ Update own orders
└─ View store inventory
Employer ◄──── Store ──────┬──► Category
│ │ │
│ └────────┼──► Product
│ │ │
├──────► Employee ─────────────► │ │
│ │ ▼
│ └──► Stock
│
└───────────────► Order ◄─────────────► OrderContent
│
└────────► Person (superclass)
| Pattern | Location | Purpose |
|---|---|---|
| Repository | services.interfaces |
Data access abstraction |
| Service Locator | SecurityValidator |
Centralized security rules |
| Strategy | OrderStatus enum with switch |
Flexible state transitions |
| Decorator | ResponseBuilder |
Consistent API responses |
| Factory | JwtService |
Token generation |
| Singleton | Spring @Component beans |
Single instance services |
This is a portfolio project showcasing enterprise-grade backend engineering. Contributions are welcome for educational purposes.
This project is provided as-is for educational and portfolio demonstration purposes.
Developed with meticulous attention to:
- Clean architecture principles
- SOLID design patterns
- Enterprise security standards
- Production-ready code quality
For inquiries or technical discussions:
- GitHub: @paka-ops
- Repository: MobileStore
⭐ If you find this project interesting, please consider starring it to show your support!