새소식

Project

회고) BookBook 프로젝트 [2023.07.21 - 2023.08.03]

  • -

 

 

BookBook 프로젝트

 

 

 

 

 

 

 

👨‍🏫 프로젝트 요약

 

 

 

사용자가 작성한 게시글을 모아 책으로 출판할 수 있는 BrunchStory 스타일의 웹 서비스

 

프로젝트 설명은 Readme 참조

 

https://github.com/JUNKI007/BookBook

 

GitHub - JUNKI007/BookBook

Contribute to JUNKI007/BookBook development by creating an account on GitHub.

github.com

 

 

 

 

 

 

 

 

 

 

🎨 ERD

 

● 1차 ERD (2023.07.21)

팀원끼리 어떤 프로젝트를 진행할지 고민하였고 후보는 아래와 같습니다.

 

1) 배달어플같은 프로그램

일반회원, 패스 구매한 유료회원, 관리자가 있고 배달이 출발되면 이메일이 발송되는 프로그램.

주변에 위치한 음식점, 메뉴별 음식 조회가 가능한 프로그램

 

2) 포켓몬 게임

유저, 체육관관장, 관리자가 있고 상대방이 대결을 신청하면 이메일이 발송되는 프로그램

그리고 포켓몬 데이터들을 조회하고, 서로 싸울 수 있는 프로그램

 

3) BrunchStory 같은 작가와 독자 프로그램

현 프로젝트

 

지금껏 배운 내용을 제일 잘 시행해볼 수 있는 주제라고 생각하여 BrunchStory 느낌의 프로젝트를 만들기로 결정했습니다.

 어떤 기능이 있을지 아주 기초적인 구상을 하였습니다.

 

 

● 2차 ERD (2023.07.24)

https://www.erdcloud.com/d/jSQSELacfupGRbBEx

 

BrunchStory

Draw ERD with your team members. All states are shared in real time. And it's FREE. Database modeling tool.

www.erdcloud.com

 

제일 초기 시안으로 ERD CLOUD를 이용하여 구체적인 틀을 구성하였습니다.

 

User, Author, Book, Subject, Like, Subscribe의 큰 Entity를 만들고 그들간의 관계를 생각하고,

어떤 기능이 추가될 지 생각했습니다.

 

 

 

 

● 3차 ERD (2023.07.26)

 

IntelliJ에서 전체적인 Entity 코드를 작성하며 각 Entity 별 관계 맵핑을 해주었고,

mySQL을 연결하여 ERD를 추출하였습니다.

 

내용은 1차와 변경사항이 없었습니다.

 

 

 

● 4차 ERD (2023.07.27)

 

프로젝트 구조에 대해 생각해보다가 너무 복잡해질 것 같다는 의견이 나왔습니다.

ManytoMany 관계를 줄이는 쪽으로 변경되었습니다.

 

 

 

 

 

● 5차 ERD (2023.07.28)

 

Security 기능을 반드시 사용해보자는 의견으로, Role 테이블을 만들고 어떻게 구조가 바뀔지 생각하였습니다.

그리고 일반 멤버가 작가로 승급했을 때, 작가인지 여부를 파악하기위해 members에 Boolean isWriter column을 만들어서

true면 작가, false면 일반 유저로 구분하려 했습니다.

 

 

 

 

 

● 최종 ERD (2023.08.03)

 

승급신청으로 writerapply 테이블, 그리고 role 테이블은 만들지 않고 enum으로 값을 받아오게하였습니다.

 

member에서 작가여부를 확인하려했던 isWriter column은 없애고, role column을 만들어서

ROLE_MEMBER, ROLE_AUTHOR, ROLE_ADMIN으로 역할을 구분하였습니다.

 

ADMIN도 테이블을 만들지 않고

resource 패키지 안에 import.sql을 만들어 초기값으로 들어가게 해두었습니다.

 

 

 

 

 

 

 

 

 

 

 

 

📃 프로젝트 구조(아키텍쳐)

 

 

 

MVC 구조로 구성하려고 노력하였으나, View는 구현하지 못해 Model & Controller 까지 구현하였습니다.

JWT 기반 인증은 Spring security 대신 가벼운 AOP 기반 커스텀인증(@TokenRequired)를 이용하였고,

추후 React와 연동하기 위해 RestAPI 기반 구조로 만들었습니다.

 

지난 프로젝트에서 자바 8버전을 사용하였고, 이번에는 같은 LTS 버전 중에 최신문법을 공부하기위해 Java 17버전을 사용하였습니다. Spring Boot는 3.1.2버전을 사용하였고, 3.x버전부터 jakarta EE를 기반으로 작동하므로 java EE에서 바뀐 코드를 사용해볼 수 있었습니다.

 

 

 

 

 

아키텍처 계층 폴더 구조 경로 (패키지 기준)
Frontend (현재 미구현) — Postman을 통한 API 테스트로 대체
Controller com.example.bookBook.member.controller
com.example.bookBook.post.controller
com.example.bookBook.controller
AOP 인증 계층 com.example.bookBook.aspect
→ AuthAspect, @TokenRequired
Service Layer com.example.bookBook.member.service
com.example.bookBook.post.service
com.example.bookBook.service
Repository (DAO) com.example.bookBook.member.repository
com.example.bookBook.post.repository
DTO 계층 com.example.bookBook.member.domain.dto
com.example.bookBook.post.domain.dto
com.example.bookBook.domain.dto
com.example.bookBook.controller.dto
Entity 계층 com.example.bookBook.member.domain.entity
com.example.bookBook.post.domain.entity
com.example.bookBook.domain.entity
이벤트 처리 com.example.bookBook.post.domain.event
→ PostCreateEvent, PostCreateEventListener
JWT 인증 관련 com.example.bookBook.config.auth.AuthService
→ JWT 파싱 및 클레임 처리 기능
DB (MySQL) 외부 MySQL DB 사용
(JPA + Spring Data 기반, application.yml에 설정)

 

 

 

 

🎈 데이터 흐름도

 

1. 데이터 입력

사용자가 데이터를 입력하는 단계입니다.
현재는 프론트엔드가 구현되지 않아, Postman을 이용한 API 테스트 방식으로 데이터를 입력받고 있습니다.

 

2. 전처리

클라이언트로부터 들어온 요청을 Controller가 먼저 받아, 요청 파라미터를 정리하고 유효성을 검사합니다.

요청 메서드에 @TokenRequired 어노테이션이 붙어 있는 경우, AOP 기반으로 AuthAspect 클래스가 작동하여 JWT 토큰을 검증하고 유효하지 않은 요청은 차단합니다.

 

3. 부분처리

인증을 통과한 요청은 서비스 계층으로 전달되고 비즈니스로직이 작동합니다.

각 서비스는 필요한 데이터를 DAO 계층에 요청하거나 응답을 구성합니다.

 

 

4. DB 처리 (DAO & MySQL)

Service 계층에서는 Spring Data JPA 기반의 Repository 인터페이스를 통해 MySQL DB와 연결됩니다.

쿼리 작성은 JPA 문법과 QueryDSL을 활용했으며, 데이터는 MySQL에 영속화되어 저장 및 조회됩니다.

 

 

 

 

🕵️‍♀️ 맡은 파트

① Event

② Scheduler

③ Security

④ Comment

 

 

 

👨‍🦲  좋았던 점

 

BookBook 서비스에 필요한 인증, 스케줄링, 알림, 이벤트 처리 등 다양한 기능을 설계하고 구현해볼 수 있었습니다.  
특히 Spring Security 대신 AOP 기반 JWT 인증을 적용하며, 토큰 발급은 `makeToken`, 검증은 `getClaims` 메서드로만 처리되도록 일관성 있게 구조화하였고, 인증 흐름은 `AuthAspect`에서 추출 → `AuthService`로 위임하는 방식으로 책임을 분리했습니다.  이 구조는 인증 방식이 변경되더라도 `AuthService`만 수정하면 전체 인증 흐름이 유지되도록 유연하게 설계되었습니다.

또한 `@Scheduled`를 활용한 정적 스케줄링과 Quartz를 활용한 동적이벤트 기반 스케줄링 구조 설계를 병행하며,  
두 방식의 차이를 직접 구성해보며 알아볼 수 있는 기회였습니다.
비록 Quartz 관련 코드들은 주석 처리된 상태지만, 게시글 작성 시 알림 트리거를 발행하고 처리하는 과정에서  
Spring의 Event 아키텍처 설계 방식을 학습하고 시도해볼 수 있었습니다.

이메일 발송 기능은 `@EnableAsync` 기반의 비동기 전송 구조로 설계하며 실제 메일 발송 흐름까지 구현해볼 수 있었고,  
단순 기능 구현을 넘어 확장성과 유지보수성을 고려한 설계 경험을 쌓을 수 있는 의미 있는 프로젝트였습니다.

 

 



👨‍🔧 어떤 문제가 있었고 어떻게 해결하였는가

 

① 문제 (@PreAuthorize가 작동하지 않음)

@PreAuthorize 어노테이션을 사용하여 사용자 Role에 따라 접근 권한을 제어하려 했지만, 모든 사용자에게 접근이 허용되는 문제가 발생했습니다.

 

② 원인분석

@PreAuthorize는 Spring Security에서 메서드 단위로 권한을 체크할 때 사용하는 어노테이션이었습니다.

하지만 프로젝트에서는 Spring Security를 사용하지 않고, AOP 기반의 JWT 인증을 구현한 구조였습니다.

그래서 @PreAuthorize 어노테이션을 사용하였지만 내부적으로 작동할 보안 필터 체인이나 권한 해석이 작동되지 않았기 때문에 아무런 효과가 없었던 것입니다.

 

 

 

③ 디버깅

메소드 진입시 print() 로그를 찍어보려했으나, Spring Security의 설정 자체가 적용되지 않아 아무런 프린트조차 되지 않았습니다.

구글링 및 공식문서를 찾아보았더니, Spring Security에서 @PreAuthorize를 사용하려면
@EnableGlobalMethodSecurity(prePostEnabled = true)가 명시적으로 선언되어 있어야 한다는 점을 알게되었습니다.

 

 

 

 

④ 해결

@PreAuthorize를 사용하지 않고, AOP와 @TokenRequired를 사용하는 방식으로 변경하여 해결하였습니다.

특정 어노테이션을 사용하기위해서 단순 @어노테이션을 적는게 끝이 아니라, 전제조건이 마련되야함을 알 수 있었습니다.

 

 

 

 

🎁 팀원별 Comment

 

 

 

 

 

 

 

 

 

 

 

 

Contents

포스팅 주소를 복사했습니다

이 글이 도움이 되었다면 공감 부탁드립니다.