Skip to content

modusplant/backend

Repository files navigation

🪴ModusPlant

DDD + Clean Architecture 기반으로 외부 환경 변화에 유연하게 대응하는 반려식물 관리 및 커뮤니티 플랫폼 서버

진행 기간

  • 2024.12 ~ 현재

핵심 가치

  • 관심사 분리: DDD + Clean Architecture 적용 후 인프라 변경(JPA -> JPA + jOOQ)에도 도메인 로직 수정 없음
  • 비용 최적화: 커뮤니티의 규모에 맞게 AWS가 아닌 Wasabi를 채택하는 등 요구사항과 환경에 맞는 기능 개발
  • 데이터 무결성: Bean Validation + 도메인 검증 로직 + 테스트 코드로 데이터 정합성 확보
팀원 역할
박준희 • Spring Security 인증/인가, 전역적 예외 핸들링
• 비속어 필터링, 일반 회원가입/댓글 Rest API
박준혁 • AWS 및 Vercel 배포/관리
• 회원 프로필/좋아요/신고/북마크/건의 및 버그 제보 Rest API
송유정 • 소셜 로그인(OAuth 2.0), JWT 생성 및 관리
• 비동기 푸시알림, 클라우드 스토리지 관리
• 게시글/게시글 1차+2차 카테고리/알림함 Rest API
고동혁 • 이메일 서비스 연동, 로깅, 모니터링
• 개발 및 프로덕션 환경 운영, 회원 약관 REST API

📝주요 기능

1. 인증 및 사용자 관리

  • 회원가입(email/password), 소셜 로그인, 이메일 인증
  • 사용자 프로필 관리, 비밀번호 재설정

2. 커뮤니티 기능

  • 게시글 및 댓글 작성/조회/수정/삭제
  • 게시글 검색 및 대표사진 지정, 게시글 이미지 업로드
  • 카테고리/최신순/좋아요/북마크에 따른 게시글 조회
  • 게시글/작성자에 따른 댓글 조회
  • 좋아요 및 북마크

3. 운영 및 피드백

  • 게시글 및 댓글 신고
  • 건의사항 및 버그 제보

🛠기술 스택 & 도입 이유

1. 백엔드 & 영속성

  • Spring Boot 3.x & Java 21: 알림 기능의 신속한 처리를 위한 가상 스레드 도입
  • PostgreSQL 17: JSONB, GIN INDEX로 비정형 데이터 검색 성능 개선
  • Hybrid DB 접근 방식
    • JPA/Hibernate: 영속성 맥락 기반 단순 DML 작업, dirty checking으로 데이터 무결성 확보
    • jOOQ: 영속성이 불필요한 대규모 READ, 복잡한 집계 쿼리 최적화
  • Flyway: DB 스키마 변경 히스토리 관리 및 환경 간 스키마 동기화 자동화

2. 인프라 & 모니터링

  • Redis: 캐싱을 통한 조회 성능 개선 및 토큰 blacklist 관리로 보안 강화
  • LGTM Stack (Grafana, Loki, Prometheus, Tempo): 소규모에 적합한 로그, 매트릭, 트레이싱 통합 관찰 환경 구축
  • Spring AOP & Logback: 로깅을 비즈니스와 분리하여 로직의 순수성 유지

3. 보안 & 품질

  • Spring Security & JWT: Stateless 인증 구조로 서버 확장성 확보 및 DB 조회 비용 절감
  • JaCoCo: 테스트 커버리지 기반 코드 품질 관리
  • MapStruct: boilerplate 매핑 로직 제거, 매핑 과정 단순화

4. 외부 서비스

  • Mailjet: 인증 코드로 사용자 이메일 정보의 신뢰성 확보
  • OAuth 2.0 (Google/Kakao): 사용자 로그인 편의성 제공 및 가입 장벽 감소

🗺️아키텍처 설계

1. 설계 원칙

  • 경량의 도메인 객체: 도메인 객체는 상태와 검증 로직만 지니며, 외부 시스템 호출 및 비즈니스 흐름 제어는 adapter 계층에서 처리
  • UseCase 계층 단순화: 프로젝트 복잡도 고려 후 UseCase 시스템 사양(인터페이스) 중심으로 설계하고, 불필요한 클래스 생성을 지양
  • 프레임워크 격리: Spring, Redis 등 외부 기술 의존 코드를 framework 계층으로 분리하여 도메인 계층의 순수성 유지

3. 설계 도면(Diagram)

소스 코드 아키텍처
프로덕션 환경 아키텍처
프로덕션 아키텍처
데이터 모델링
게시글 테이블 댓글 테이블

4. 패키지 레이아웃(Code Block)

📂 modusplant
  │ 📜 ModusplantApplication.java
  ├─📂 domains          # 📋 핵심 비즈니스 로직 및 도메인 모델
  │  ├─📂 account       # 계정 (Email, Social, Normal)
  │  ├─📂 post          # 게시글
  │  └─ 📂 ...          # member, comment, term
  ├─📂 framework        # ✈️ 외부 기술 스택 연동 (JPA, jOOQ, Redis 등)
  ├─📂 infrastructure   # 🔨 애플리케이션 공통 기반 (Security, AOP, Config 등)
  └─📂 shared           # 🧺 전역 공통 모듈 및 유틸리티 (Kernel, Exception 등)
도메인 내부 구조
  • domain -> 외부 계층 의존 ❌
  • Use Case -> domain 의존 ⭕
  • adapter -> Use Case 의존 ⭕
  • framework -> adapter 의존 ⭕
📂 [domain_name]
 ├─📂 adapter    # Interface Adapter: 외부 시스템 연결, 데이터 매핑 및 오케스트레이션
 ├─📂 domain     # Enterprise Business Rules: 핵심 비즈니스 로직 (Aggregate, Entity, VO)
 ├─📂 framework  # Frameworks & Drivers: 기술 구현체 (Service, RestController, Persistence)
 └─📂 usecase    # Application Business Rules: 앱 사양 정의 (Port, DTO, Model)

💡기술적 의사결정 및 트러블슈팅

⭐ DDD + Clean Architecture를 통한 비즈니스와 인프라/프레임워크 분리

  • 문제: 기능이 확장됨에 따라 클래스 간 의존성 파악을 위한 불필요한 소통 발생, 불명확한 구조로 유지보수 어려움
  • 의사 결정: 비즈니스 로직 + 인프라/프레임워크 + 그 사이를 매개하는 계층형 아키텍처로 리팩토링
  • 성과: 도메인들 간 명확한 경계 설정, Jira 백로그 기준 신규 기능 개발 기간 약 30% 단축
Flyway로 DB 형상 관리
  • 문제: 수동 DDL 공유로 환경 간 스키마 불일치 발생, 변경 히스토리 추적 어려움
  • 의사 결정: Flyway 도입으로 실행 시 스키마 자동 마이그레이션
  • 성과: 스키마 정합성 문제 제거 및 롤백 가능 구조 확보
JPA의 N+1 문제 근절 및 대량 데이터 조회 최적화
  • 문제: 여러 테이블이 JOIN되는 대량의 데이터 조회 시 JPA의 N+1 발생, 성능 저하
  • 해결
    • 단순 CRUD는 JPA/Hibernate로 데이터 무결성 확보
    • 복잡한 통계와 Read 작업은 jOOQ로 Type-Safe하게 수행 및 성능 최적화
  • 성과: JPA의 N+1문제 근절 및 컴파일 타임 에러 확인 가능

📕API 명세서

설계 원칙

  • 일관된 응답 구조: status, code, data
  • 에러 코드 기반 클라이언트 처리 가능 구조
  • 버전 관리 가능한 REST URI (/api/v1/...)

API 명세서

모두의식물 API 명세서

댓글 추가 API 예시

요청
  • postId: 댓글이 속한 게시글 식별자 (ULID)
  • path: 계층형 댓글 구조를 표현하는 경로 값 (숫자.숫자.숫자...)
  • content: 댓글 내용
{
  "postId": "string"
  "path": "string"
  "content": "string"
}
응답
  • status: HTTP 상태 코드
  • code: 클라이언트 분기 처리를 위한 응답 코드
  • message: 사용자 또는 디버깅을 위한 메시지
{
  "status": 200,
  "code": "generic_success",
  "message": ""
}
{
  "status": 400,
  "code": "empty_post_id",
  "message": "게시글의 식별자 값이 비었습니다"
}

🖊️협업 방식

협업 구조 & 효과

  • Jira 기반 이슈 및 브랜치 관리 + Confluence 기반 문서 아카이브
  • Gitmoji 기반 커밋 메시지 형식 통일 -> 코드 변경 이력 파악 시간 감소
  • PR 기반 코드리뷰로 품질 관리 -> 코드 품질 향상

브랜치 전략

  • Jira 이슈 단위로 브랜치 생성 (ex. MP-123)
  • 작업 완료 후 PR -> 코드 리뷰 -> develop 병합

커밋 컨벤션

Gitmoji 목록
이모티콘 커밋 유형 의미
:sparkles: Feat 새로운 기능 추가
🐛 :bug: Fix 버그 해소
🚑 :ambulance: HOTFIX! 긴급 버그 해소
💄 :lipstick: Style CSS 및 UI 스타일 추가 및 수정
♻️ :recycle: Refactor 코드 리팩토링
🎨 :art: Format 코드 구조 / 서식 변경 (코드 자체 변경 없음)
💥 :boom: BREAKING! 거대한 변경
🔥 :fire: Remove 파일 삭제
🥅 :goal_net: Catch 잘못 작성된 코드 수정
:heavy_plus_sign: Dependency 의존성 추가
:heavy_minus_sign: Dependency 의존성 제거
📝 :memo: Docs 문서 추가 및 수정
⏪️ :rewind: Revert 변경 철회
💬 :speech_balloon: Comment 주석 추가 및 수정
🚚 :truck: Rename 파일 또는 폴더명 수정 및 이동
:white_check_mark: Test 테스트 코드 추가 및 수정
🔧 :wrench: Chore 잡다한 과업
🎉 :tada: Begin 프로젝트 시작
MP-289 :bug: Fix: 게시글 여러 번 수정 시 발생하는 낙관적 락 에러 해결

- 낙관적 락 충돌 문제를 방지하기 위해 전체 매핑 후 저장 방식을 제거하고 개별 필드 업데이트로 변경
- 엔티티 업데이트 메서드 추가

About

모두의식물 백엔드

Resources

License

Stars

Watchers

Forks

Packages

 
 
 

Contributors

Languages