Spring Boot 기반의 현대적인 E-Commerce 플랫폼
Co's House는 '오늘의 집'을 벤치마킹 한 E-Commerce 플랫폼입니다.
- 다중 인증 방식
- 로컬 회원가입 (이메일/비밀번호)
- OAuth2 소셜 로그인 (카카오, 네이버)
- 이메일 인증 시스템
- 권한 기반 접근 제어 (USER, ADMIN, SUPER_ADMIN)
- 세션 기반 인증 (Spring Security)
- 다중 옵션 상품 지원
- 장바구니 시스템
- 주문 처리 및 배송 추적
- 쿠폰 및 할인 시스템
- 재고 관리 및 입고 이력
- Toss Payments API 통합
- 결제 성공/실패 처리
- 환불 처리 시스템
- 게시글 작성 및 카테고리 관리
- 좋아요, 스크랩, 댓글 기능
- 사용자 생성 콘텐츠 관리
- 상품 등록 및 관리
- 재고 조회 및 관리
- 주문 처리 및 상태 관리
- 사용자 활동 로깅 (AOP)
- Framework: Spring Boot 3.5.5
- Language: Java 21
- ORM: Spring Data JPA, Hibernate
- Query DSL: Querydsl 5.0.0
- Security: Spring Security 6 (Session-based)
- Template Engine: Thymeleaf
- Validation: Spring Validation
- Production: MySQL 8.4
- Test: H2 (in-memory)
- Connection Pool: HikariCP
- Containerization: Docker Compose
- Monitoring: Prometheus, Grafana
- Metrics: Micrometer, Spring Boot Actuator
- Payment: Toss Payments
- Email: Naver SMTP
- OAuth2: Kakao, Naver
- Build Tool: Gradle 8.x
- Code Generation: Lombok, Querydsl APT
- Version Control: Git
- Java: 21 이상
- Docker: 최신 버전 (Docker Compose 지원)
- MySQL: 8.4 (Docker로 자동 실행)
- Gradle: 8.x (Wrapper 포함)
git clone <repository-url>
cd cos# MySQL, Prometheus, Grafana 컨테이너 시작
docker-compose up -d
# 컨테이너 상태 확인
docker ps예상 출력:
CONTAINER ID IMAGE PORTS NAMES
... mysql:8.4 0.0.0.0:13306->3306/tcp cos-mysql
... prom/prometheus 0.0.0.0:9090->9090/tcp cos-prometheus
... grafana/grafana 0.0.0.0:3000->3000/tcp cos-grafana
# MySQL 접속
mysql -h 127.0.0.1 -P 13306 -u root -proot cos
# SQL 스크립트 실행 (순서 중요!)
source document/sql/1_table_insert.sql; # 테이블 생성
source document/sql/0_user_role_migration.sql; # 역할 마이그레이션 (필수)
source document/sql/2_basic_data_insert.sql; # 기본 데이터 삽입
source document/sql/3_test_queries.sql; # 테스트 쿼리 (선택)# 빌드 및 실행
./gradlew bootRun
# 또는 JAR 파일로 실행
./gradlew bootJar
java -jar build/libs/cos-0.0.1-SNAPSHOT.jar- 애플리케이션: http://localhost:8080
- Actuator Health: http://localhost:8080/actuator/health
- Prometheus: http://localhost:9090
- Grafana: http://localhost:3000 (admin/admin)
cos/
├── src/main/java/com/bird/cos/
│ ├── domain/ # JPA 엔티티 (도메인 별 구조화)
│ │ ├── user/ # 사용자 관리
│ │ ├── order/ # 주문 관리
│ │ ├── product/ # 상품 관리
│ │ ├── cart/ # 장바구니
│ │ ├── payment/ # 결제
│ │ ├── inventory/ # 재고
│ │ └── post/ # 게시판
│ ├── dto/ # 요청/응답 DTO
│ │ ├── order/
│ │ ├── product/
│ │ ├── auth/
│ │ └── admin/
│ ├── repository/ # Spring Data JPA 리포지토리
│ │ ├── *Repository.java
│ │ ├── *RepositoryCustom.java # Querydsl 커스텀 인터페이스
│ │ └── *RepositoryCustomImpl.java # Querydsl 구현체
│ ├── service/ # 비즈니스 로직
│ ├── controller/ # MVC 컨트롤러
│ ├── config/ # Spring 설정
│ │ ├── SecurityConfig.java
│ │ ├── QuerydslConfig.java
│ │ └── TossPaymentsProperties.java
│ ├── security/ # 보안 컴포넌트
│ │ ├── CustomUserDetails.java
│ │ ├── OAuth2LoginSuccessHandler.java
│ │ └── RegisterSecurityFilter.java
│ ├── exception/ # 예외 처리
│ │ ├── GlobalExceptionHandler.java
│ │ ├── ErrorResponse.java
│ │ └── ErrorCode.java
│ └── aop/ # AOP (로깅 등)
│ └── LoggingAspect.java
├── src/main/resources/
│ ├── application.yml # 애플리케이션 설정
│ ├── templates/ # Thymeleaf 템플릿
│ │ ├── layout/
│ │ ├── fragments/
│ │ ├── order/
│ │ ├── admin/
│ │ └── home/
│ └── static/ # 정적 리소스 (CSS, JS, 이미지)
├── document/
│ └── sql/ # SQL 초기화 스크립트
├── docker-compose.yml # Docker 컨테이너 설정
├── prometheus.yml # Prometheus 설정
├── build.gradle # Gradle 빌드 설정
├── CLAUDE.md # 개발자 가이드 (Claude Code용)
└── MONITORING.md # 모니터링 가이드
복잡한 쿼리는 Querydsl로 작성합니다:
// 1. Custom 인터페이스 정의
public interface OrderRepositoryCustom {
List<Order> findOrdersWithDetails(Long userId);
}
// 2. CustomImpl 구현체 작성
@Repository
public class OrderRepositoryCustomImpl implements OrderRepositoryCustom {
private final JPAQueryFactory queryFactory;
// Querydsl Q-class 사용
@Override
public List<Order> findOrdersWithDetails(Long userId) {
return queryFactory
.selectFrom(QOrder.order)
.join(QOrder.order.user).fetchJoin()
.where(QOrder.order.user.id.eq(userId))
.fetch();
}
}
// 3. Repository가 양쪽 모두 확장
public interface OrderRepository extends
JpaRepository<Order, Long>, OrderRepositoryCustom {
}Q-classes는 build/generated/querydsl/에 자동 생성됩니다.
- 세션 기반 인증 (JWT 아님)
- Form Login 비활성화, 커스텀 로그인:
/controller/register/login - OAuth2 지원: 카카오, 네이버
- RegisterSecurityFilter: Origin/Referer 검증, Rate Limiting
// 역할 기반 접근 제어
USER // 일반 사용자
ADMIN // 관리자
SUPER_ADMIN // 슈퍼 관리자
// 관리자 엔드포인트 자동 보호
/api/admin/** → admin_role 필요@PreAuthorize("hasAuthority('admin_role')")
public void adminMethod() { ... }모든 인증/인가 실패는 GlobalExceptionHandler에서 처리:
{
"timestamp": "2025-10-17T12:00:00",
"status": 401,
"code": "UNAUTHORIZED",
"message": "인증이 필요합니다",
"path": "/api/admin/products"
}# application.yml
spring:
security:
# 개발 환경: HTTP Basic 활성화
# 프로덕션: HTTP Basic 비활성화
session:
policy: IF_REQUIRED
fixation: newSession
max-sessions: 1 # 사용자당 최대 1개 세션application.yml에 테스트/개발용 크레덴셜이 포함되어 있습니다. 프로덕션 환경에서는 환경 변수나 Spring Cloud Config를 사용하세요.
- Spring Boot Actuator: 애플리케이션 메트릭 수집
- Prometheus: 메트릭 저장 및 쿼리
- Grafana: 시각화 대시보드
| 카테고리 | 메트릭 | 설명 |
|---|---|---|
| HTTP | http_server_requests_seconds |
요청 응답 시간 및 처리량 |
| JVM | jvm_memory_used_bytes |
JVM 메모리 사용량 |
| JVM | jvm_gc_pause_seconds |
GC 정지 시간 |
| 시스템 | system_cpu_usage |
CPU 사용률 |
| DB | hikaricp_connections_active |
활성 DB 커넥션 수 |
- Actuator: http://localhost:8080/actuator
- Prometheus: http://localhost:8080/actuator/prometheus
- Prometheus UI: http://localhost:9090
- Grafana: http://localhost:3000
# 1. Grafana 접속 (admin/admin)
# 2. Data Source 추가: Prometheus (http://prometheus:9090)
# 3. 대시보드 Import: ID 4701 (JVM Micrometer)
# 4. Application 이름: cos-house상세한 모니터링 가이드는 MONITORING.md를 참고하세요.
# 전체 빌드 (테스트 포함)
./gradlew build
# 테스트 제외 빌드
./gradlew build -x test
# 클린 빌드
./gradlew clean build
# 애플리케이션 실행
./gradlew bootRun
# JAR 파일 생성
./gradlew bootJar# 전체 테스트 실행
./gradlew test
# 특정 테스트 클래스 실행
./gradlew test --tests CartServiceTest
# 특정 테스트 메서드 실행
./gradlew test --tests CartServiceTest.testMethodName
# 상세 출력과 함께 테스트
./gradlew test --info- 엔티티 클래스 생성 (
domain/패키지)
@Entity
@Getter @Builder
@NoArgsConstructor @AllArgsConstructor
public class NewEntity {
@Id @GeneratedValue(strategy = GenerationType.IDENTITY)
private Long id;
// ... fields
}- 리포지토리 생성
public interface NewEntityRepository extends JpaRepository<NewEntity, Long> {
}- 복잡한 쿼리가 필요한 경우 Querydsl 추가
// NewEntityRepositoryCustom.java
public interface NewEntityRepositoryCustom {
List<NewEntity> complexQuery(String param);
}
// NewEntityRepositoryCustomImpl.java
@Repository
public class NewEntityRepositoryCustomImpl implements NewEntityRepositoryCustom {
private final JPAQueryFactory queryFactory;
// ... 구현
}
// NewEntityRepository.java (확장)
public interface NewEntityRepository extends
JpaRepository<NewEntity, Long>, NewEntityRepositoryCustom {
}- Q-class 생성
./gradlew clean compileJava- 서비스 및 컨트롤러 작성
Public 엔드포인트 (인증 불필요):
// SecurityConfig.java에 추가
.requestMatchers(HttpMethod.GET,
"/new-endpoint" // 추가
).permitAll()Admin 엔드포인트 (자동으로 admin_role 필요):
@GetMapping("/api/admin/new-feature")
public ResponseEntity<?> adminMethod() { ... }
// /api/admin/** 경로는 자동으로 보호됨메서드 레벨 보안:
@PreAuthorize("hasAuthority('admin_role')")
public void protectedMethod() { ... }데이터베이스 확인:
# MySQL 컨테이너 확인
docker ps
# MySQL 접속
mysql -h 127.0.0.1 -P 13306 -u root -proot cos
# SQL 로그 확인 (콘솔 출력, show-sql: true)Querydsl Q-class 누락 시:
./gradlew clean build
# Q-classes는 build/generated/querydsl/에 생성됨Host: localhost
Port: 13306 # 표준 3306이 아닌 13306 사용
Database: cos
Username: root
Password: root
JDBC URL: jdbc:mysql://localhost:13306/cosSpring Boot Docker Compose 지원으로 자동 관리:
- 애플리케이션 시작 시 자동으로 컨테이너 시작
lifecycle-management: start-and-stop
# 수동 관리
docker-compose up -d # 시작
docker-compose stop # 중지
docker-compose down # 중지 및 제거
docker-compose down -v # 볼륨까지 제거spring:
jpa:
hibernate:
ddl-auto: update # 엔티티 변경 시 자동 스키마 업데이트
show-sql: true # SQL 쿼리 로그 출력
database-platform: org.hibernate.dialect.MySQL8Dialectddl-auto: validate 사용 권장
file:
upload-dir: /Users/a/IdeaProjects/Co-s_House/uploads/이미지는 /images/uploaded/** 경로로 접근 가능합니다.
Naver SMTP 사용:
spring:
mail:
host: smtp.naver.com
port: 465
username: your-email@naver.com
password: your-passwordspring:
security:
oauth2:
client:
registration:
kakao:
client-id: your-kakao-client-id
naver:
client-id: your-naver-client-idtoss:
payments:
client-key: test_ck_...
secret-key: test_sk_...
success-url: http://localhost:8080/payment/success
fail-url: http://localhost:8080/payment/fail- Fork the Project
- Create your Feature Branch (
git checkout -b feature/AmazingFeature) - Commit your Changes (
git commit -m 'Add some AmazingFeature') - Push to the Branch (
git push origin feature/AmazingFeature) - Open a Pull Request
이 프로젝트는 LICENSE 파일에 명시된 라이선스를 따릅니다.
- CLAUDE.md - 개발자를 위한 상세 가이드
- MONITORING.md - 모니터링 시스템 설정 및 사용법
- HELP.md - Spring Boot 도움말
./gradlew clean compileJava
# build/generated/querydsl/ 확인docker ps # 컨테이너 실행 확인
docker logs cos-mysql # 로그 확인# H2 데이터베이스 사용 (in-memory)
./gradlew test --info # 상세 로그 확인- 8080 (애플리케이션), 13306 (MySQL), 9090 (Prometheus), 3000 (Grafana)
- 필요 시
application.yml및docker-compose.yml에서 포트 변경
Made with ☕ and Spring Boot