부모의 추억을 자식과 공유하며 공감대를 찾는 문답형 아카이빙 서비스, 엄빠도 어렸다
ddongseop | 박예준 |
---|---|
ddongseop | jun02160 |
담당 역할 | Role |
---|---|
Nginx 배포, CI/CD 구축 | ddongseop |
DB 구축 (RDS) | ddongseop |
ERD 작성 | ddongseop, 박예준 |
API 개발 | ddongseop, 박예준 |
소셜로그인 기능 구현 | ddongseop |
푸시알림 기능 구현 | 박예준 |
통합 개발 환경 | IntelliJ |
Spring 버전 | 2.7.13 |
데이터베이스 | AWS RDS(MySQL), Redis |
배포 | AWS EC2(Ubuntu), S3 |
Project 빌드 관리 도구 | Gradle |
CI/CD 툴 | Github Actions, CodeDeploy |
ERD 다이어그램 툴 | ERDCloud |
Java version | Java 11 |
패키지 구조 | 도메인 패키지 구조 |
API 테스트 | PostMan, Swagger |
외부 연동 | Slack, FCM |
🔗 API Docs
📂 umbba-api
├── build.gradle
└── src
├── main
│ ├── 📂 java/sopt/org/umbba/api
│ │ ├── ApiApplication.java
│ │ ├── 🗂 config
│ │ │ ├── SecurityConfig.java
│ │ │ ├── 🗂 auth
│ │ │ │ ├── CustomJwtAuthenticationEntryPoint.java
│ │ │ │ ├── JwtAuthenticationFilter.java
│ │ │ │ └── UserAuthentication.java
│ │ │ ├── 🗂 jwt
│ │ │ │ ├── JwtProvider.java
│ │ │ │ ├── JwtValidationType.java
│ │ │ │ ├── TokenDto.java
│ │ │ │ └── TokenRepository.java
│ │ │ └── 🗂 sqs
│ │ │ ├── SqsConfig.java
│ │ │ └── 🗂 producer
│ │ │ └── SqsProducer.java
│ │ ├── 🗂 controller
│ │ │ ├── 🗂 advice
│ │ │ │ └── ControllerExceptionAdvice.java
│ │ │ ├── 🗂 health
│ │ │ │ ├── DemoController.java
│ │ │ │ ├── ServerProfileController.java
│ │ │ │ └── SlackTestController.java
│ │ │ ├── 🗂 parentchild
│ │ │ │ ├── ParentchildController.java
│ │ │ │ └── 🗂 dto
│ │ │ │ ├── 🗂 request
│ │ │ │ │ ├── InviteCodeRequestDto.java
│ │ │ │ │ ├── OnboardingInviteRequestDto.java
│ │ │ │ │ └── OnboardingReceiveRequestDto.java
│ │ │ │ └── 🗂 response
│ │ │ │ ├── InviteResultResponseDto.java
│ │ │ │ ├── OnboardingInviteResponseDto.java
│ │ │ │ └── OnboardingReceiveResponseDto.java
│ │ │ ├── 🗂 qna
│ │ │ │ ├── QnAController.java
│ │ │ │ └── 🗂 dto
│ │ │ │ ├── 🗂 request
│ │ │ │ │ └── TodayAnswerRequestDto.java
│ │ │ │ └── 🗂 response
│ │ │ │ ├── GetInvitationResponseDto.java
│ │ │ │ ├── GetMainViewResponseDto.java
│ │ │ │ ├── QnAListResponseDto.java
│ │ │ │ ├── SingleQnAResponseDto.java
│ │ │ │ └── TodayQnAResponseDto.java
│ │ │ └── 🗂 user
│ │ │ ├── AuthController.java
│ │ │ └── 🗂 dto
│ │ │ ├── 🗂 request
│ │ │ │ ├── RefreshRequestDto.java
│ │ │ │ ├── SocialLoginRequestDto.java
│ │ │ │ └── UserInfoDto.java
│ │ │ └── 🗂 response
│ │ │ └── UserLoginResponseDto.java
│ │ └── 🗂 service
│ │ ├── 🗂 notification
│ │ │ └── NotificationService.java
│ │ ├── 🗂 parentchild
│ │ │ └── ParentchildService.java
│ │ ├── 🗂 qna
│ │ │ └── QnAService.java
│ │ └── 🗂 user
│ │ ├── AuthService.java
│ │ └── 🗂 social
│ │ ├── 🗂 apple
│ │ │ ├── AppleLoginService.java
│ │ │ └── 🗂 verify
│ │ │ ├── AppleClaimsValidator.java
│ │ │ ├── AppleJwtParser.java
│ │ │ ├── EncryptUtils.java
│ │ │ └── PublicKeyGenerator.java
│ │ └── 🗂 kakao
│ │ └── KakaoLoginService.java
│ └── 📂 resources
└── application.yaml
📂 umbba-notification
├── build.gradle
└── src
└── main
├── 📂 java/sopt/org/umbba/notification
│ ├── NotificationApplication.java
│ ├── 🗂 config
│ │ ├── 🗂 fcm
│ │ │ └── FCMConfig.java
│ │ ├── 🗂 scheduler
│ │ │ └── ScheduleConfig.java
│ │ └── 🗂 sqs
│ │ ├── SqsConfig.java
│ │ └── 🗂 consumer
│ │ └── SqsConsumer.java
│ └── 🗂 service
│ ├── 🗂 fcm
│ │ ├── FCMController.java
│ │ ├── FCMService.java
│ │ └── 🗂 dto
│ │ └── FCMMessage.java
│ ├── 🗂 scheduler
│ │ └── FCMScheduler.java
│ └── 🗂 slack
│ └── SlackApi.java
└── 📂 resources
├── application.yaml
└── 🗂 firebase
└── umbba-fcm-firebase-adminsdk.json
📂 umbba-domain
├── build.gradle
└── src
└── main
└── 📂 java/sopt/org/umbba/domain
├── UmbbaDomainRoot.java
├── 🗂 config
│ └── 🗂 jpa
│ └── JpaConfig.java
└── 🗂 domain
├── 🗂 common
│ └── AuditingTimeEntity.java
├── 🗂 parentchild
│ ├── Parentchild.java
│ ├── ParentchildRelation.java
│ ├── 🗂 dao
│ │ └── ParentchildDao.java
│ └── 🗂 repository
│ └── ParentchildRepository.java
├── 🗂 qna
│ ├── OnboardingAnswer.java
│ ├── QnA.java
│ ├── Question.java
│ ├── QuestionSection.java
│ ├── QuestionType.java
│ ├── 🗂 dao
│ │ └── QnADao.java
│ └── 🗂 repository
│ ├── QnARepository.java
│ └── QuestionRepository.java
├── 🗂 redis
│ └── RefreshToken.java
└── 🗂 user
├── SocialPlatform.java
├── User.java
└── 🗂 repository
└── UserRepository.java
📂 umbba-common
├── build.gradle
└── src
└── main
└── 📂 java/sopt/org/umbba/common
├── UmbbaCommonRoot.java
├── 🗂 exception
│ ├── ErrorType.java
│ ├── SuccessType.java
│ ├── 🗂 dto
│ │ └── ApiResponse.java
│ └── 🗂 model
│ └── CustomException.java
└── 🗂 sqs
├── MessageType.java
├── MessageUtils.java
└── 🗂 dto
├── FCMPushRequestDto.java
├── FirebaseDto.java
├── MessageDto.java
├── PushMessage.java
└── SlackDto.java
📂 umbba-external
├── build.gradle
└── src
└── main
└── 📂 java/sopt/org/umbba/external
├── UmbbaExternalRoot.java
└── 🗂 client
└── 🗂 auth
├── 🗂 apple
│ ├── AppleApiClient.java
│ └── 🗂 response
│ ├── ApplePublicKey.java
│ └── ApplePublicKeys.java
└── 🗂 kakao
├── KakaoApiClient.java
├── KakaoAuthApiClient.java
└── 🗂 response
├── KakaoAccessTokenResponse.java
├── KakaoAccount.java
├── KakaoUserProfile.java
└── KakaoUserResponse.java
main, develop, feat, refactor, hotfix, release
main
: 최최최최최최종본 - stable all the time
develop
: 우리가 개발하면서 코드를 모을 공간, 배포하기 전까지는 이게 default로 하여 PR은 여기로 날립니다.
feat
: 기능을 개발하면서 각자가 사용할 브랜치
-
Git Flow 전략에 따라 → “feat/#이슈번호-구현하려는기능” 형식으로
-
ex. feat/#3-login, feat/#5-book_info_detail
-
해당 branch 작업 완료 후 PR 보내기
- 항상 local에서 충돌 해결 후 → remote에 올리기
- reviewer에 서로 tag후 code-review
- approve 전 merge 불가!
- 작동 확인된 기능의 branch는 삭제
-
코드리뷰 컨벤션
- 서로 상대 실수 한 것 없는지 귀찮아도 꼭 읽어보기
- 긍정적인 코멘트 적극적으로 남겨주기
- 우선순위 반영한 코드리뷰 진행하기 ex.
[P1] 이건 꼭 반영해주셔야해요!
- [CHORE] : 동작에 영향 없는 코드 or 변경 없는 변경사항(주석 추가 등) or 파일명, 폴더명 수정 or 파일, 폴더 삭제 or 디렉토리 구조 변경
- [RENAME] : 파일 이름 변경시
- [FEAT] : 새로운 기능 구현
- [FIX] : 버그, 오류 해결
- [REFACTOR] : 전면 수정, 코드 리팩토링
- [ADD] : Feat 이외의 부수적인 코드 추가, 라이브러리 추가, 새로운 파일 생성
- [DEL] : 쓸모없는 코드 삭제
- [CORRECT] : 주로 문법의 오류나 타입의 변경, 이름 변경시
- [DOCS] : README나 WIKI 등의 문서 수정
- [MERGE]: 다른 브랜치와 병합
- [TEST] : 테스트 코드 추가/작성
-
커밋은 세부 기능 기준
-
이슈번호 붙이는 단위 : FEAT, FIX, REFACTOR
ex.
git commit -m “[FEAT] 로그인 기능 구현 #2”
💡 동료들과 말투를 통일하기 위해 컨벤션을 지정합니다.
오합지졸의 코드가 아닌, 한 사람이 짠 것같은 코드를 작성하는 것이 추후 유지보수나 협업에서 도움이 됩니다. 내가 코드를 생각하면서 짤 수 있도록 해주는 룰이라고 생각해도 좋습니다!
- 기본적으로 네이밍은 누구나 알 수 있는 쉬운 단어를 선택한다.
- 우리는 외국인이 아니다. 쓸데없이 어려운 고급 어휘를 피한다.
- 변수는 CamelCase를 기본으로 한다.
- userEmail, userCellPhone ...
- URL, 파일명 등은 kebab-case를 사용한다.
- /user-email-page ...
- 패키지명은 단어가 달라지더라도 무조건 소문자를 사용한다.
- frontend, useremail ...
- ENUM이나 상수는 대문자로 네이밍한다.
- NORMAL_STATUS ...
- 함수명은 소문자로 시작하고동사로 네이밍한다.
- getUserId(), isNormal() ...
- 클래스명은명사로 작성하고 UpperCamelCase를 사용한다.
- UserEmail, Address ...
- 객체 이름을 함수 이름에 중복해서 넣지 않는다. (= 상위 이름을 하위 이름에 중복시키지 않는다.)
- line.getLength() (O) / line.getLineLength() (X)
- 컬렉션은 복수형을 사용하거나 컬렉션을 명시해준다.
- List ids, Map<User, Int> userToIdMap ...
- 이중적인 의미를 가지는 단어는 지양한다.
- event, design ...
- 의도가 드러난다면 되도록 짧은 이름을 선택한다.
- retreiveUser() (X) / getUser() (O)
- 단, 축약형을 선택하는 경우는 개발자의 의도가 명백히 전달되는 경우이다. 명백히 전달이 안된다면 축약형보다 서술형이 더 좋다.
- 함수의 부수효과를 설명한다.
- 함수는 한가지 동작만 수행하는 것이 좋지만, 때에 따라 부수 효과를 일으킬 수도 있다.
fun getOrder() { if (order == null) { order = Order() } return order }
- 위 함수는 단순히 order만 가져오는 것이 아니라, 없으면 생성해서 리턴한다.
- 그러므로 getOrder() (X) / getOrCreateOrder() (O)
- 함수는 한가지 동작만 수행하는 것이 좋지만, 때에 따라 부수 효과를 일으킬 수도 있다.
- LocalDateTime -> xxxAt, LocalDate -> xxxDt로 네이밍
- 객체를 조회하는 함수는 JPA Repository에서 findXxx 형식의 네이밍 쿼리메소드를 사용하므로 개발자가 작성하는 Service단에서는 되도록이면 getXxx를 사용하자.