🤼

Spring… 참10조?

Table
Search
이름
태그
MBTI
블로그
깃헙주소
한마디!

팀 소개

프로젝트 이름 : 뉴스피드 프로젝트
프로젝트 소개 : 취준생을 위한 뉴스피드

KPT

프로젝트

팀명 : Spring… 참 10조?
팀원 : 김진훈, 김지현, 장동하, 최혁
개발 기간 : 2023.11.21 ~ 2023.11.27
개발 내용 : 뉴스피드 사이트 백엔드 API 만들기

KPT 회고

1. KEEP (잘 한 것)

협업

기능별로 개발 역할 분담
Git, Github를 적극적으로 사용하려고 시도함
main, dev, feature branch를 나누고, dev branch에 pull request를 요청해서 코드 리뷰 후에 merge 하는 방식으로 협업함
pull request마다 코드 리뷰를 진행함
application.yml 설정 파일을 개인별로 잘 관리함
코딩 컨벤션과 커밋 컨벤션을 정하고 지키려고 노력함
저녁에 매일 기능 개발 상황을 공유하는 시간을 갖음

기술

필요한 기능을 구현하기 위해 필요한 기술을 공부하고 잘 적용했음
Swagger를 통한 API 명세 작성과 테스트
AWS s3 버킷을 이용한 이미지 서버 연동
Gmail SMTP를 이용한 이메일 자동 전송 기능 활용
Github의 Read me 작성을 통한 꼼꼼한 문서화

2. PROBLEM (아쉬운 것)

협업

Git commit 로그에 의미 없는 merge 로그가 많이 생성되어 지저분함
Git pull reqeust 올리기 전에 pull을 받지 않고 올린 경우가 있음

기술

tokenvalue에 jwt 형식이 아닌 값이 들어왔을 때의 허용하는 페이지에 대한 예외처리 미흡
다대다 연관관계 테이블에 복합키 개념을 적용하지 않음

3. TRY (하고싶은 것)

협업

팀원 개인의 역량을 파악하는 시간을 갖기
할 수 있는 것과 없는 것의 명확한 구분 필요
Git commit 로그를 깔끔하게 관리해보고 싶음

기술

리팩토링 시도
코드 리뷰를 통한 더 나은 코드 모색
기능별 함수 모듈화 적극 시도
다대다 연관관계에 복합키 개념을 적용 시도

# FEEL

김진훈

얼떨결에 팀장을 맡았는데 다들 얘기도 잘 들어주시고 맡은 기능 개발도 열심히 해주셔서 좋은 경험이였습니다. 저번 프로젝트에서 협업할 때 하고 싶었던 것들을 이번 프로젝트에서 많이 적용할 수 있어서 좋았습니다. 프로젝트 시간이 촉박해서 여전히 리팩토링은 도전하지 못한 것이 조금 아쉽습니다.

김지현

프로젝트에서 많은 기능을 구현하였음에도 적절한 분배와 역할 분담, 꼼꼼한 설계, 테스트, 개개인의 노력이 잘 이루어져 완성도 높은 프로젝트를 함께 이룬 것이 좋았습니다. 또한 적극적인 git 사용과 코드 리뷰를 통해 git과 github에 익숙해질 수 있었습니다.

장동하

오랜만에 몰입하는 경험을 해서 개인적으로는 좋았지만, 몰입한 시간 대비 많은 성과물을 내지 못해 아쉽습니다. 기능 구현을 재촉하지 않고 기다려주시고 또 많은 개념들을 알려주신 팀원 분들에게 감사드리며 항상 건승하시길 바랍니다.

최혁

잘 하는 분들 사이에서 정말 많이 배우고 갑니다.

개발 일정

캘린더 보기
Search
2023/11/21
2023/11/22 → 2023/11/23
2023/11/23 → 2023/11/24
2023/11/21 → 2023/11/23
2023/11/23 → 2023/11/24
2023/11/21 → 2023/11/22
2023/11/23 → 2023/11/24
2023/11/23 → 2023/11/24
2023/11/21 → 2023/11/23
2023/11/25 → 2023/11/26
2023/11/25 → 2023/11/26
2023/11/25 → 2023/11/26
May
June
S4
S5
M6
T7
W8
T9
F10
S11
S12
M13
T14
W15
T16
F17
S18
S19
M20
T21
W22
T23
F24
S25
S26
M27
T28
W29
T30
F31
S1
S2
M3
T4
W5
T6
F7
S8
S9
M10
T11
W12
T13
F14
S15
S16
M17
T18
W19
T20
F21
S22
S23
M24
F
11
May 2024
Week
Today

추가 할 일 메모

BaseResponse → API 명세와 동기화 해야함 → 처리했음
프로필 수정할 때 중복 닉네임 체크 해야함 - > 처리했음
유저 생성할 때 프로필 자동 생성되게 해야함 → 처리했음
모든 API 실행 테스트 해야함 → 했음
실행 테스트 끝나면 스웨거 적용 해야함 → 했음
스웨거 테스트 영상 만들어야함 → 햇음
ERD 수정해야함 → 했음
README → 했음
기능들 사용하는거 다 상상해보고 가능한 예외처리 해야함 → AOP로 하면 더 좋고

구현 기능 목록

사용자 인증 기능 - 장동하
회원가입 기능
새로운 사용자가 ID와 비밀번호의 형태로 서비스에 가입할 수 있어야 합니다.
이 때, 비밀번호는 안전하게 암호화되어 저장되어야 합니다!
로그인 및 로그아웃 기능
사용자는 자신의 계정으로 서비스에 로그인하고 로그아웃할 수 있어야 합니다.
로그인에 성공하면 Jwt를 발급한다.
비밀번호 수정 시에는 비밀번호를 한 번 더 입력받는 과정이 필요합니다.
기능 시나리오
회원가입을 요청하면 인증 없이, 이메일과 비밀번호를 전달하는데, 이메일 인증을 통과하기 전에는 GUEST 권한을 가진 유저고, 통과하면 USER 권한을 가진 유저가 된다. → 회원가입 요청 API, 이메일 인증 요청하는 API
GUEST의 권한: 이메일 인증 요청만 가능, USER의 권한: 모든 요청 가능
회원가입 요청에 대한 응답으로 성공 여부를 리턴한다.
로그인 요청을 하면, 이메일과 비밀번호를 전달하고 인증을 통과하면 응답으로 쿠키에 Jwt 토큰을 받는다.
로그아웃 요청을 하면, Jwt 토큰을 헤더에 넣고, 응답으로 쿠키에 로그아웃된 Jwt 토큰을 받는다.
이메일 인증 요청을 하면, 이메일 인증 값을 전달하고, 응답으로 성공 여부를 리턴한다. - 이메일 인증 값 생성 방법 구체화 필요
이메일 가입 및 인증 기능 - 장동하
이메일 가입 시 이메일 인증 기능을 포함하는 것이 좋습니다.
프로필 관리 - 김진훈
프로필 추가, 조회, 수정 기능
이름, 한 줄 소개와 같은 기본적인 정보를 볼 수 있어야 하며 수정할 수 있어야 합니다.
기능 시나리오
프로필은 유저가 이메일 인증을 통과했을 때, 함께 초기 생성되며 임시 닉네임(중복불가)이 부여되고 소개글은 비워져 있다.
프로필 조회 요청에 대한 응답으로 닉네임과 소개글을 리턴한다.
프로필 수정 요청 하면 Jwt 토큰을 헤더에 넣고, 닉네임과 소개글을 전달하는데, 응답으로 수정된 닉네임과 소개글을 리턴한다.
게시물 CRUD 기능 - 김지현
게시물 작성, 조회, 수정, 삭제 기능
게시물 조회를 제외한 나머지 기능들은 전부 인가(Authorization) 개념이 적용되어야 하며 이는 JWT와 같은 토큰으로 검증이 되어야 할 것입니다.
예컨대, 내가 작성한 글을 남이 삭제할 수는 없어야 하고 오로지 본인만 삭제할 수 있어야겠죠?
게시물 작성, 수정, 삭제 시 새로고침 기능
프론트엔드에서 게시물 작성, 수정 및 삭제를 할 때마다 조회 API를 다시 호출하여 자연스럽게 최신의 게시물 내용을 화면에 보여줄 수 있도록 해야 합니다!
기능 시나리오
게시글 작성 요청 하면 Jwt 토큰을 헤더에 넣고, 글 제목, 글 내용을 전달하고, 응답으로 글 id, 글 제목과 내용을 리턴한다.
게시글 조회 요청 하면 응답으로 글 id, 글 제목과 내용을 리턴한다.
게시글 수정 요청 하면 Jwt 토큰을 헤더에 넣고, 글 제목, 글 내용을 전달하고, 응답으로 수정한 게시글의 조회 요청으로 redirect한다.
게시글 삭제 요청 하면 Jwt 토큰을 헤더에 넣어 전달하고, 응답으로 뉴스피드 조회 요청 redirect 한다.
댓글 CRUD 기능 - 최혁
댓글 작성, 조회, 수정, 삭제 기능
사용자는 게시물에 댓글을 작성할 수 있고 본인의 댓글은 수정 및 삭제를 할 수 있어야 합니다.
게시글 내부에서 댓글을 조회할 때 해당 게시글에 포함된 댓글을 한번에 조회할 수 있어야 합니다.
또한, 게시물과 마찬가지로 댓글 조회를 제외한 나머지 기능들은 인가(Authorization)개념이 적용되어야 합니다.
댓글 작성, 수정, 삭제 시 새로고침 기능
프론트엔드에서 댓글 작성, 수정 및 삭제를 할 때마다 조회 API를 다시 호출하여 자연스럽게 최신의 댓글 목록을 화면에 보여줄 수 있도록 해야 합니다!
기능 시나리오
댓글 작성 요청 하면 Jwt 토큰을 헤더에 넣고, 댓글 내용을 전달하고, 응답으로 댓글 id, 댓글 내용, 좋아요 수, 작성자 닉네임, 작성일자를 리턴한다.
댓글 조회 요청 하면 응답으로 댓글 id, 댓글 내용, 좋아요 수, 작성자 닉네임, 작성일자 리스트를 리턴한다.
댓글 수정 요청 하면 Jwt 토큰을 헤더에 넣고, 댓글 내용을 전달하고, 응답으로 수정한 댓글의 내용을 리턴한다.
댓글 삭제 요청 하면 Jwt 토큰을 헤더에 넣어 전달하고, 응답으로 성공 여부를 리턴한다.
팔로우 기능 구현 - 김진훈
특정 사용자를 팔로우/언팔로우를 할 수 있으면 너무 좋습니다.
팔로우 기능이 구현되었다면 뉴스 피드에 팔로우하는 사용자의 게시물을 볼 수 있어야 하겠죠?
기능 시나리오
팔로우 요청을 하면 Jwt 토큰을 헤더에 넣어 전달하고, 응답으로 성공 여부를 반환한다.
언팔로우 요청을 하면 Jwt 토큰을 헤더에 넣어 전달하고, 응답으로 성공 여부를 반환한다.
뉴스 피드 기능 - 김지현
뉴스 피드 페이지
사용자가 다른 사용자의 게시물을 한 눈에 볼 수 있는 뉴스 피드 페이지가 있어야 합니다.
뉴스 피드 추천 변수: 팔로우(0.5) + 좋아요(0.4) + 작성일자(0.1)의 가중치를 가지고 추천 시스템을 만든다.
위의 추천 시스템에 따라 페이지네이션으로 조회한다.
기능 시나리오
뉴스 피드 요청을 하면 Jwt 토큰을 넣어서 보내면 추천 변수의 가중치를 위의 조건 그대로 하고, Jwt 토큰이 없다면 좋아요(0.8) + 작성일자(0.2)로 추천한다.
응답으로 추천하는 게시글 목록(글 id, 글 제목, 글 내용, 좋아요 수, 작성자, 작성일자)을 리턴한다.
좋아요 기능 - 김지현
게시물 및 댓글 좋아요/좋아요 취소 기능
사용자가 게시물이나 댓글에 좋아요를 남기거나 취소할 수 있어야 합니다.
이 때, 본인이 작성한 게시물과 댓글에 좋아요는 남길 수 없도록 해봅니다!
기능 시나리오
좋아요 요청을 하면 Jwt 토큰을 헤더에 넣어 전달하고, 응답으로 성공 여부 메세지와 좋아요 수를 리턴한다.
프로필에 사진 업로드 기능 구현 - 김진훈
프로필 사진을 저장할 때는 반드시 AWS S3를 이용해주세요!
기능 정리
프로필 사진 추가
http method post로 이미지 파일 받고 접근 가능한 s3의 url 리턴(파일명은 profile-image/userId.확장자 식으로 구성)
db에 접근 가능한 s3의 url 저장해두자
프로필 사진 수정
http method put으로 프로필 사진 추가와 동일
프로필 사진 삭제
http method delete로 s3에 저장된 image를 삭제하고 db의 url도 null로 변경하자

협업 방법

1.
기술 개발 및 결합 과정의 방법
기능 완성 시점에 PR을 요청하고, 1명 이상이 코드 리뷰 후에 병합한다.
브랜치는 main(배포용), dev(개발용), feature(기능 개발용)로 나눠서 관리한다.
일반적으로 브랜치를 이렇게 나눠요
배포 브랜치(main)
디벨롭 브랜치(dev)
기능 단위 별 브랜치(feature/user)
2.
코드 컨벤션
3.
커밋 컨벤션
4.
패키지 구조
도메인형 패키지 구조로 개발한다.
공통으로 사용하는 기능은 common 패키지에서 관리한다.

기술 스택

Java 17
Gradle - Groovy
Spring Boot 3.1.5
Lombok
Spring Boot DevTools
Spring Web
Spring Security
Spring Data JPA
MySQL Driver
Validation
Table
Search
담당
기능
Method
URL
RequestHeader
RequestBody
ResponseHeader
ResponseBody
비고
장동하
POST
/api/users/signup
{ username: String, password: String }
{ message: String, success: Boolean, payload: { username: String } }
장동하
POST
/api/users/login
{ username: String, password: String }
Authorization: Bearer jwtvalue
{ message: String, success: Boolean, payload: {} }
장동하
POST
/api/users/mail-auth
Authorization: Bearer jwtvalue
{ authcode: Integer }
{ message: String, success: Boolean, payload: {} }
장동하
PUT
/api/users/password
Authorization: Bearer jwtvalue
{ existingpassword: String, newpassword: String }
{ message: String, success: Boolean, payload: {} }
장동하
POST
/api/users/logout
Authorization: Bearer jwtvalue
Authorization: Bearer jwtvalue
{ message: String, success: Boolean, payload: {} }
이미 만료된 jwt를 반환.
김진훈
GET
/api/users/{userId}/profiles
{ message: String, success: Boolean, payload: { nickname: String, introduction: String, profileImageUrl: String } }
김진훈
PUT
POST
/api/users/{userId}/profiles
Authorization: Bearer jwtvalue
{ nickname: String, introduction: String }
{ message: String, success: Boolean, payload: { nickname: String, introduction: String, profileImageUrl: String } }
김진훈
POST
/api/users/{userId}/profiles/image?image={image}
Authorization: Bearer jwtvalue
{ message: String, success: Boolean, payload: { imageUrl: String } }
김진훈
GET
/api/users/{userId}/profiles/image
Authorization: Bearer jwtvalue
{ message: String, success: Boolean, payload: { imageUrl: String } }
김진훈
DELETE
/api/users/{userId}/profiles/image
Authorization: Bearer jwtvalue
{ message: String, success: Boolean, payload: {} }
김지현
POST
/api/posts
Authorization: Bearer jwtvalue
{ title: String, contents: String }
{ message: String, success: Boolean, payload: { id: Long, title: String, contents: Staring, username: String, likesCount: int, createdAt: LocalDateTime } }
김지현
GET
/api/posts/{postId}
{ message: String, success: Boolean, payload: { id: Long, title: String, contents: Staring, username: String, likesCount: int, createdAt: LocalDateTime } }
김지현
GET
/api/posts?page={page}&size={size}
Authorization: Bearer jwtvalue(required=false)
{ message: String, success: Boolean, payload: { [PostDto…] } }
김지현
PUT
/api/posts/{postId}
Authorization: Bearer jwtvalue
{ title: String, contents: String }
{ message: String, success: Boolean, payload: { title: String, contents: String } }
김지현
DELETE
/api/posts/{postId}
Authorization: Bearer jwtvalue
{ message: String, success: Boolean, payload: {} }
최혁
POST
/api/posts/{postId}/comments
Authorization: Bearer jwtvalue
{ text: String }
{ message: String, success: Boolean, payload: { username: String, text: String, comment_id: Long, date: ZonedDateTime, likesCount: int } }
최혁
GET
/api/posts/{postId}/comments
{ message: String, success: Boolean, payload: { [CommentDto…] } }
최혁
PUT
/api/posts/{postId}/comments/{commentId}
Authorization: Bearer jwtvalue
{ contents: String }
{ message: String, success: Boolean, payload: { username: String, text: String, comment_id: Long, date: ZonedDateTime, likesCount: int } }
최혁
DELETE
/api/posts/{postId}/comments/{commentId}
Authorization: Bearer jwtvalue
{ message: String, success: Boolean, payload: {} }
김지현
POST
/api/posts/{postId}/comments/{commentId}/likes
Authorization: Bearer jwtvalue
{ message: String, success: Boolean, payload: { likesCount: Integer } }
김지현
DELETE
/api/posts/{postId}/comments/{commentId}/likes
Authorization: Bearer jwtvalue
{ message: String, success: Boolean, payload: { likesCount: Integer } }
김지현
POST
/api/posts/{postId}/likes
Authorization: Bearer jwtvalue
{ message: String, success: Boolean, payload: { likesCount: Integer } }
김지현
DELETE
/api/posts/{postId}/likes
Authorization: Bearer jwtvalue
{ message: String, success: Boolean, payload: { likesCount: Integer } }
김진훈
POST
/api/users/{userId}/follows
Authorization: Bearer jwtvalue
{ message: String, success: Boolean, payload: { followers: [String…], followings: [Sring…] } }
김진훈
GET
/api/users/{userId}/follows
김진훈
DELETE
/api/users/{userId}/follows
Authorization: Bearer jwtvalue

ERD

Wire Frame

데일리 스크럼

하루 계획표를 작성하고 데일리 스크럼에서 공유합니다.
보드 보기
Search
예시
4
월요일(1주차)
0
화요일(1주차)
0
수요일(1주차)
1
목요일(1주차)
0
금요일(1주차)
0

 우리 팀 약속

1. 시간 약속을 철저히 지키겠습니다. 2. 소통을 중요시하며 자리 비움이나 문제가 생기면 빠르게 공유하겠습니다. 3. 실수나 문제가 있어도 남 탓하지말고 문제를 해결해나가는데 집중하겠습니다. 4. 파이팅하겠습니다! 5. Exception 만들기 전에 팀원 분들이 만든 것 있나 먼저 확인하기.
Java
복사

우리 팀의 목표는?

1. 매일 일정 소화하기 2. 부끄러워도 물어보기 3. 이번 프로젝트 포트폴리오로 사용하기 4. TIL 남은날까지 맨날 쓰기 📝 5. 11TIL, 1알고리즘
Java
복사

우리 팀 시간 약속

- 오전 - 09:00 ~ 10:30 : 알고리즘 학습 11문제 스터디 - 집중 코딩 시간 (14:00 ~ 18:00) - 프로젝트 개발 시간 - 오후 - 20:00 ~ 20:30 - TIL 작성 - 20:30 ~ 21:00 - 하루 회고 진행(개발 진척도 공유, 체크리스트 확인, TIL 댓글 달기)
Kotlin
복사
개발 진행에 따른 기록 작성 (개인)
1.
개발을 하면서 정리할 내용 또는 학습 한 내용이 있다면 블로그에 정리하기 (tistory, velog 추천!)
2.
정리할 때는 아래 내용들을 고민하여 작성해봅시다.
a.
어떤 의도, 이유로 해당 기능을 구현했는지 → 강의에서 배워서, 필수구현 사항이여서는 지양합시다!
b.
해당 기능은 어떤 로직으로 코드가 작동하는지 → 입력값이 들어가면 어떤 출력값이 나오는지 또는 어떤 변화가 있는지
c.
버그 또는 에러는 어떤 것이 있었고 어떻게 해결하였는지