시스템 아키텍처 개요
본 프로젝트는 유료 자습실 운영을 위한 통합 관리 솔루션으로, 백엔드는 SpringBoot를, 프론트엔드는 Vue.js와 Uniapp을 활용하여 개발되었다. 전반적인 시스템은 모던 웹 아키텍처 기반의 분산 구조로 설계되어 유지보수성과 확장성을 극대화하였다.
기술 스택 구성
백엔드: SpringBoot 기반 서비스 계층
SpringBoot는 내장형 서블릿 컨테이너(Tomcat/Undertow)를 제공하여 별도의 WAS 설치 없이 애플리케이션을 즉시 실행할 수 있다. 의존성 기반 자동 설정(auto-configuration) 기능을 통해 데이터소스, 보안, 캐싱 등 공통 모듈을 간편하게 구성할 수 있으며, RESTful API 개발에 최적화된 환경을 제공한다. 또한 Spring AOP와 Transaction Management를 통해 비즈니스 로직의 일관성과 안정성을 보장한다.
프론트엔드: Vue.js + Uniapp 기반 UI 계층
Vue.js는 반응형 데이터 바인딩과 가상 DOM(Virtual DOM)을 활용해 뛰어난 렌더링 성능을 제공한다. 컴포넌트 기반 아키텍처로 UI 재사용성을 극대화하였으며, Vuex를 통한 상태 관리를 통해 복잡한 사용자 인터랙션을 효율적으로 처리한다. 모바일 앱 호환성을 위해 Uniapp 프레임워크를 도입하여 단일 코드베이스로 iOS/Android 앱 배포가 가능하도록 구성하였다.
데이터 접근 계층: MyBatis-Plus 활용
MyBatis-Plus는 기존 MyBatis의 단점을 보완한 강화형 ORM 프레임워크로, 기본 CRUD 연산을 어노테이션 기반으로 자동 생성한다. 코드 제너레이터를 이용해 엔티티 클래스, 매퍼 인터페이스, XML 매핑 파일을 일괄 생성함으로써 개발 생산성을 크게 향상시켰다. 또한 내장된 페이지 어드민, 조건 생성기(Wrapper), 성능 분석 플러그인 등을 통해 데이터 조작의 안정성과 가시성을 확보하였다.
핵심 기능 구현
JWT 기반 인증 시스템
사용자 인증은 토큰 기반 세션 관리 방식을 채택하였다. 로그인 요청 시 사용자 정보를 검증하고, 유효한 경우 32자리 난수 토큰을 발급하며 만료 시간(1시간)을 함께 저장한다. 이후 모든 요청은 HTTP 헤더에 포함된 토큰을 기준으로 인가 여부를 판단한다.
@PostMapping("/auth/login")
public ResponseEntity<Map<String, Object>> authenticate(
@RequestParam String userId,
@RequestParam String password,
HttpServletRequest req) {
UserRecord user = userService.findByUserId(userId);
if (user == null || !passwordEncoder.matches(password, user.getPasswordHash())) {
return errorResponse("잘못된 계정 정보입니다.");
}
String accessToken = tokenManager.createSession(user.getId(), user.getRole());
Map<String, Object> result = new HashMap<>();
result.put("token", accessToken);
result.put("role", user.getRole());
result.put("username", user.getName());
return ok(result);
}
토큰 인가 인터셉터
모든 보호된 엔드포인트에 대해 인가 검사를 수행하는 인터셉터를 구현하였다. 특정 메서드는 @AnonymousAccess 어노테이션으로 검사를 우회할 수 있도록 하였으며, OPTIONS 사전 요청(CORS)에 대해서는 바로 통과시키는 정책을 적용하였다.
@Component
public class AuthInterceptor implements HandlerInterceptor {
@Autowired private SessionService sessionStore;
@Override
public boolean preHandle(HttpServletRequest request,
HttpServletResponse response,
Object handler) throws IOException {
// CORS 사전 요청 처리
handleCorsHeaders(response, request);
if ("OPTIONS".equalsIgnoreCase(request.getMethod())) {
response.setStatus(HttpStatus.OK.value());
return false;
}
// 인증 우회 어노테이션 확인
if (isAnnotatedWith(handler, AnonymousAccess.class)) {
return true;
}
String token = extractTokenFromHeader(request);
SessionRecord session = sessionStore.validate(token);
if (session != null) {
request.setAttribute("CURRENT_USER_ID", session.getUserId());
request.setAttribute("CURRENT_ROLE", session.getRole());
return true;
}
sendUnauthorizedResponse(response);
return false;
}
}
데이터베이스 설계
세션 정보를 저장하기 위한 토큰 테이블은 다음과 같이 구성된다. 사용자 ID, 역할(Role), 토큰 문자열, 만료 시간 등을 포함하며, 인덱스를 통해 조회 성능을 최적화하였다.
CREATE TABLE `session_token` (
`id` BIGINT UNSIGNED AUTO_INCREMENT PRIMARY KEY,
`user_id` BIGINT NOT NULL COMMENT '사용자 식별자',
`username` VARCHAR(100) NOT NULL,
`role` VARCHAR(50) NOT NULL COMMENT '접근 권한',
`access_token` CHAR(32) NOT NULL UNIQUE,
`login_time` DATETIME DEFAULT CURRENT_TIMESTAMP,
`expiry_time` DATETIME NOT NULL COMMENT '세션 만료 시간',
INDEX idx_user_role (`user_id`, `role`),
INDEX idx_token_expires (`access_token`, `expiry_time`)
) ENGINE=InnoDB DEFAULT CHARSET=utf8mb4 COMMENT='사용자 세션 토큰';
시스템 테스트 전략
주요 기능 검증을 위해 블랙박스 테스트 중심의 테스트 케이스를 설계하였다. 입력값의 경계 조건, 필수 항목 누락, 중복 데이터 처리 등을 포함하여 시스템의 견고성을 검증하였다.
| 테스트 시나리오 | 기대 결과 | 실제 결과 | 판단 |
|---|---|---|---|
| 정상 아이디/비밀번호 입력 | 로그인 성공, 토큰 반환 | 200 OK, 토큰 포함 응답 | 일치 |
| 잘못된 비밀번호 입력 | 401 오류 응답 | 401 Unauthorized | 일치 |
| 빈 아이디 제출 | "아이디를 입력하세요" 경고 | 클라이언트에서 유효성 검사 수행 | 일치 |
사용자 관리 기능 테스트
사용자 등록, 수정, 삭제 기능에 대해 CRUD 테스트를 수행하였다. 중복 아이디 방지, 필수 필드 검증, 삭제 후 조회 불가 여부 등을 확인함으로써 데이터 무결성을 보장하였다.
결론
본 시스템은 SpringBoot와 Vue.js의 통합을 통해 안정적인 백엔드 서비스와 직관적인 사용자 인터페이스를 제공한다. JWT 기반 인증, 자동화된 코드 생성, 체계적인 테스트 전략을 통해 개발 효율성과 시스템 신뢰성을 동시에 달성하였다. 추후 결제 연동, 예약 알림, 실시간 좌석 현황 기능을 추가하여 완성도를 높일 계획이다.