Full-Stack Food Ordering Platform: Technical Design and Cross-Platform Implementation
System Architecture
The platform adopts a microservices-oriented architecture with clear separation between data layer, business logic, and presentation tiers. The server-side levergaes Spring Boot 2.x with embedded Tomcat containerization, providing RESTful API endpoints for client consumption. Frontend implementation spans two domains: a responsive web dashboard built with Vue.js 3.x composition API, and a lightweight WeChat mini-program developed using uni-app framework for cross-platform compilation.
Backend Infrastructure
Authentication Mechanism
The security layer implements JWT-style token authentication with custom interceptors. User credentials undergo validation against encrypted storage before session tokens are generated with temporal constraints.
@RestController
@RequestMapping("/api/v1/auth")
public class AuthenticationController {
@AnonymousAccess
@PostMapping("/signin")
public ResponseEntity<AuthResult> authenticate(
@RequestParam String account,
@RequestParam String credentials,
@RequestParam String verificationCode,
HttpServletRequest request) {
AccountProfile profile = accountService.findByAccountName(account);
if (profile == null || !passwordEncoder.matches(credentials, profile.getEncryptedPassword())) {
return ResponseEntity.status(401).body(AuthResult.failure("Invalid credentials"));
}
String sessionToken = tokenManager.createToken(
profile.getId(),
account,
profile.getUserType(),
profile.getAccessLevel()
);
return ResponseEntity.ok(AuthResult.success(sessionToken));
}
}
@Service
public class TokenManager {
public String createToken(Long userId, String accountName, String tableIdentifier, String accessRole) {
SessionToken existingToken = tokenRepository.findByUserIdAndRole(userId, accessRole);
String jwtToken = RandomStringUtils.secureRandomAlphanumeric(32);
Instant expiration = Instant.now().plus(1, ChronoUnit.HOURS);
if (existingToken != null) {
existingToken.setTokenValue(jwtToken);
existingToken.setExpiresAt(Date.from(expiration));
tokenRepository.update(existingToken);
} else {
SessionToken newToken = new SessionToken();
newToken.setUserId(userId);
newToken.setAccountName(accountName);
newToken.setSourceTable(tableIdentifier);
newToken.setRoleType(accessRole);
newToken.setTokenValue(jwtToken);
newToken.setExpiresAt(Date.from(expiration));
tokenRepository.save(newToken);
}
return jwtToken;
}
}
Request Interception
The platform utilizes Spring HandlerInterceptor to enforce authentication boundaries and handle cross-origin resource sharing (CORS) preflight requests.
@Component
public class SecurityInterceptor implements HandlerInterceptor {
private static final String AUTH_HEADER = "Authorization";
@Autowired
private TokenManager tokenManager;
@Override
public boolean preHandle(HttpServletRequest request, HttpServletResponse response,
Object handler) throws Exception {
configureCorsHeaders(response, request);
if (RequestMethod.OPTIONS.name().equals(request.getMethod())) {
response.setStatus(HttpServlet.SC_OK);
return false;
}
if (handler instanceof HandlerMethod) {
HandlerMethod method = (HandlerMethod) handler;
if (method.hasMethodAnnotation(AnonymousAccess.class)) {
return true;
}
}
String bearerToken = request.getHeader(AUTH_HEADER);
if (!StringUtils.hasText(bearerToken)) {
sendUnauthorizedResponse(response);
return false;
}
SessionToken tokenData = tokenManager.validateToken(bearerToken);
if (tokenData == null || tokenData.isExpired()) {
sendUnauthorizedResponse(response);
return false;
}
request.setAttribute("currentUserId", tokenData.getUserId());
request.setAttribute("userRole", tokenData.getRoleType());
request.setAttribute("sourceTable", tokenData.getSourceTable());
request.setAttribute("accountName", tokenData.getAccountName());
return true;
}
private void configureCorsHeaders(HttpServletResponse response, HttpServletRequest request) {
response.setHeader("Access-Control-Allow-Methods", "GET, POST, PUT, DELETE, OPTIONS");
response.setHeader("Access-Control-Max-Age", "3600");
response.setHeader("Access-Control-Allow-Credentials", "true");
response.setHeader("Access-Control-Allow-Headers",
"Origin, Content-Type, Accept, Authorization, X-Requested-With");
response.setHeader("Access-Control-Allow-Origin", request.getHeader("Origin"));
}
private void sendUnauthorizedResponse(HttpServletResponse response) throws IOException {
response.setStatus(HttpServlet.SC_UNAUTHORIZED);
response.setContentType("application/json;charset=UTF-8");
response.getWriter().write("{\"code\":401,\"message\":\"Authentication required\"}");
}
}
Data Persistence Layer
MyBatis-Plus serves as the ORM framework, offering enhanced CRUD operations and dynamic SQL generation capabilities. The token storage schema maintains session state with expiration tracking.
DROP TABLE IF EXISTS `user_sessions`;
CREATE TABLE `user_sessions` (
`session_id` bigint(20) NOT NULL AUTO_INCREMENT,
`user_id` bigint(20) NOT NULL COMMENT 'Reference to user account',
`account_name` varchar(100) NOT NULL,
`entity_table` varchar(100) DEFAULT NULL COMMENT 'Source table discriminator',
`privilege_level` varchar(100) DEFAULT NULL,
`access_token` varchar(200) NOT NULL,
`created_at` timestamp NOT NULL DEFAULT CURRENT_TIMESTAMP,
`valid_until` timestamp NOT NULL DEFAULT '1970-01-01 00:00:00',
PRIMARY KEY (`session_id`) USING BTREE,
KEY `idx_token` (`access_token`),
KEY `idx_user` (`user_id`)
) ENGINE=InnoDB DEFAULT CHARSET=utf8mb4;
Frontend Implementation
Web Dashboard (Vue.js)
The administrative interface utilizes Vue 3 with Composition API, implementing virtual DOM diffing for efficient rendering. State management handles real-time order notifications and menu updates through WebSocket connections.
Mobile Client (uni-app)
The WeChat mini-program shares business logic across iOS and Android through uni-app's Vue-based syntax. Native API wrappers handle payment gateways, geolocation services, and push notifications while maintaining consistent UI components.
Quality Assurance
Functional Verification
Black-box testing validates business workflows without examining internal structures. Test scenarios cover authentication boundaries, data validation rules, and transaction integrity.
Authentication Test Matrix:
| Input Scenario | Expected Behavior | Validation |
|---|---|---|
| Valid credentials + correct verification | Session established, token returned | Pass |
| Valid username, invalid password | Access denied, error message displayed | Pass |
| Empty username field | Client-side validation triggers | Pass |
| Expired session token | 401 Unauthorized response | Pass |
User Management Verification:
| Operation | Test Case | Outcome |
|---|---|---|
| Create user | Duplicate username rejection | System prevents collision |
| Update profile | Data persistence verification | Changes reflect immediately |
| Delete account | Cascade validation | Related records handled appropriately |
| Permission change | Role-based access control | Privileges update dynamically |
Performance Validation
Load testing confirms the Spring Boot embedded containre handles concurrent order submissions. Connection pooling and MyBatis-Plus query optimization ensure sub-second response times for menu browsing and checkout processes under peak traffic conditions.