늑대와 함께 춤을 팀의 디지털 유산 인계 서비스 백엔드입니다. 사용자가 생전에 계획을 작성해 봉인해 두면, 지정 확인자의 사망 신고와 증빙 검토를 거쳐 담당자에게 항목이 인계되는 흐름을 처리합니다.
- Java 21 (Gradle 툴체인)
- Spring Boot 4.1.0 / Spring Security 7.x / Spring Data JPA
- PostgreSQL
- JWT 기반 무상태 인증
- Resilience4j (이메일 발송, S3 재시도/회로차단)
- Gradle 9.5.1 (wrapper 포함)
-
저장소를 클론하고
.env.example을.env로 복사한 뒤, 필수 환경 변수를 채웁니다.cp .env.example .env
-
DB와 애플리케이션을 함께 띄웁니다.
docker compose up --build
db(PostgreSQL) 서비스가 정상 기동(healthy)된 뒤app서비스가 시작되며,http://localhost:8080에서 API에 접근할 수 있습니다. Swagger UI는http://localhost:8080/swagger-ui/index.html에서 확인할 수 있습니다. -
종료 시:
docker compose down
DB 데이터를 초기화하려면 볼륨까지 함께 제거합니다:
docker compose down -v
로컬에 PostgreSQL을 직접 띄워 실행할 수도 있습니다. .env의 DB_URL이 로컬 DB를 가리키도록 맞춘 뒤:
./gradlew bootRun.env.example에 전체 목록과 기본값이 있습니다. 애플리케이션은 spring.config.import로 .env 파일을 읽으므로,
로컬 개발에서는 저장소 루트에 .env 파일을 두면 됩니다(.gitignore에 포함되어 커밋되지 않습니다).
주요 항목:
| 구분 | 변수 | 설명 |
|---|---|---|
| DB | DB_URL, DB_USERNAME, DB_PASSWORD, POSTGRES_DB |
PostgreSQL 연결 정보 |
| AI | OPENAI_API_KEY, OPENAI_API_URL, OPENAI_MODEL |
대화 기반 계획 구조화에 사용하는 OpenAI 설정 |
| 메일 | MAIL_USERNAME, MAIL_PASSWORD, MAIL_HOST, MAIL_PORT |
Gmail SMTP 발송 계정 (앱 비밀번호 사용) |
| 저장소 | AWS_S3_BUCKET, AWS_S3_REGION, AWS_ACCESS_KEY_ID, AWS_SECRET_ACCESS_KEY |
증빙 파일 저장용 S3 자격 증명 |
| 인증 | JWT_SECRET(32자 이상), JWT_ACCESS_TOKEN_EXPIRATION_MS, JWT_REFRESH_TOKEN_EXPIRATION_MS |
JWT 서명 키와 만료 시간 |
| 앱 | APP_BASE_URL |
이메일 링크가 가리킬 프론트엔드 주소 |
비밀값 관리: .env는 절대 커밋하지 않습니다. 실제 자격 증명(메일 앱 비밀번호, AWS 키, OpenAI 키, JWT 시크릿)은 팀 내부
채널로만 공유하고, 커밋 전 git status로 .env가 스테이징되지 않았는지 항상 확인합니다.
전체 테스트 실행 (실제 로컬/Docker PostgreSQL 필요, 외부 서비스는 목 처리되어 있어 .env의 값이 더미여도 통과합니다):
./gradlew test특정 테스트 클래스만 실행:
./gradlew test --tests "com.mamoki.ieojuda.domain.plan.service.PlanOwnershipReaderTest"PR을 올리면 GitHub Actions(test.yml)가 별도 Postgres 컨테이너와 더미 자격 증명으로 전체
테스트를 자동 실행합니다.
이미지만 별도로 빌드하려면:
docker build -t ieoduda-backend .멀티스테이지 빌드로 eclipse-temurin:21-jdk-jammy에서 bootJar를 만들고, eclipse-temurin:21-jre-jammy 런타임 이미지에
결과 jar만 담아 non-root(app) 사용자로 실행합니다.
도메인별로 controller / service / repository / entity / dto를 두는 구조입니다.
src/main/java/com/mamoki/ieojuda/
├── domain/
│ ├── account/ # 회원가입·로그인, 필수 동의(Consent), 관리자 사용자 관리
│ ├── plan/ # 계획 생성, 삶의 구역/항목, AI 대화 기반 구조화, 항목 순서, 봉인(패키지)
│ ├── recipient/ # 역할 담당자 등록·초대·수락
│ ├── confirmer/ # 지정 확인자, 사망 신고, 이의 제기 연락처
│ ├── rolecheck/ # 역할 점검(담당자·확인자 현황) 화면
│ ├── stage/ # 인계 단계·의존성(발송 순서, 충돌 점검)
│ ├── handoffcheck/ # 생전 인계 점검(선택 기능)
│ ├── releasecase/ # 사망 확인 사건, 대기 기간, 사건 취소, 이의 제기
│ ├── evidence/ # 공식 증빙 제출·검토·삭제(관리자 감사 포함)
│ ├── partner/ # 외부 법무·장례 파트너의 증빙 검토
│ ├── postaccess/ # 사후 인계 접근 인증, 패키지 문제 신고
│ ├── securitytoken/ # 공개 링크(이메일 진입)용 목적별 단일 사용 토큰
│ └── audit/ # 이메일·인증·관리자 액션 감사 로그
│
├── global/
│ ├── config/ # SecurityConfig, AppProperties, SwaggerConfig 등
│ ├── consent/ # 필수 동의 미완료 사용자 접근 제한 필터
│ ├── email/ # 이메일 발송(outbox 큐, 발신자, 템플릿, 토큰)
│ ├── exception/ # CustomException, ErrorCode, GlobalExceptionHandler
│ ├── idempotency/ # 멱등성 키 기반 중복 요청 방지
│ ├── jwt/ # JWT 발급·검증 필터
│ ├── openai/ # OpenAI API 클라이언트
│ ├── ratelimit/ # 공개 링크(토큰) 조회 레이트 리밋·감사
│ ├── rsdata/ # 공통 API 응답 포맷(RsData)
│ ├── scan/ # 업로드 파일 악성코드/시그니처 스캔
│ ├── security/ # 권한·재인증 가드
│ ├── storage/ # 증빙 파일 S3 저장소 클라이언트
│ ├── util/ # 공통 유틸(IP 추출, 이메일 마스킹 등)
│ └── validation/ # 계획 내용 내 자격증명 노출 탐지 등 커스텀 검증
│
└── IeojudaApplication.java
- 기본 브랜치:
main(배포),develop(통합) — 작업은 항상develop에서 분기합니다. - 작업 브랜치명:
<Type>/#<이슈번호>-<작성자>(예:Fix/#150-mingu,Feat/#139-mingu). 이슈에 딸리지 않은 작업은 이슈 번호 없이<Type>/<설명>-<작성자>형태를 씁니다(예:Setting/cors-frontend-origin-sujong).Type은Feat/Fix/Refactor/Test/Docs/Setting/Chore등 변경 성격을 나타냅니다. - 커밋 메시지:
[Type/#이슈번호]: 설명형식, 한국어 서술형으로 무엇을 왜 바꿨는지 간결히 씁니다. 예:[Fix/#150]: 항목 삭제 시 배정된 담당자가 함께 정리되지 않던 문제 수정 - PR:
develop을 베이스로 생성하고, 병합 전./gradlew test전체 통과를 확인합니다. 병합은 Merge commit 방식을 사용하고, 병합 후 작업 브랜치는 삭제하지 않는 것이 최근 관행입니다. - Issue: 목적·범위(포함/제외)·작업 내용 체크리스트·완료 조건을 명시하는 형식을 따릅니다.