Skip to content

refactor: 어드민 콘텐츠 API TMP 테이블 → 실제 테이블 전환 (#60) - #62

Merged
hyunbin7664 merged 6 commits into
mainfrom
refactor/#60-admin-tmp-to-real
Oct 27, 2026
Merged

hyunbin7664 merged 6 commits into
mainfrom
refactor/#60-admin-tmp-to-real

Conversation

@hyunbin7664

@hyunbin7664 hyunbin7664 commented Oct 25, 2026 •

Copy link
Copy Markdown
Member

📌 작업 개요

관련 이슈

작업 배경 및 목적

어드민의 기업/밋업 프로젝트·학회원 후기 API가 테스트용 TMP* 테이블에 저장하고 있어, 운영진이 어드민에서 등록·수정한 내용이 실제 사이트에 반영되지 않았습니다.
개발 컨벤션(1.2 임시 코드 네이밍 규칙)에 따라 TMP* 엔티티를 실제 엔티티로 통합하고 제거합니다. 이제 운영진이 개발팀 요청 없이 사이트 콘텐츠를 직접 관리할 수 있습니다.

🛠️ 주요 변경 사항

1. 어드민 API 실제 테이블 전환

  • 기업 프로젝트(CorporateProject), 밋업 프로젝트(MeetupProject, MeetupTeam), 학회원 후기(Review)를 어드민에서 직접 CRUD
  • 실제 엔티티에 생성(@Builder) 및 update 메서드 추가

2. 태그 연관관계 저장

  • 기업/밋업 등록·수정 시 태그를 Tag 테이블과 M:N 연관관계로 저장 (공개 API는 원래 이 연관관계로 태그를 응답함)
  • 태그명 앞의 #·공백·중복 제거, 기존 태그 재사용, 없으면 생성
  • 수정 시 tag를 보내지 않으면 기존 태그 유지 (기존 어드민 FE는 밋업 tag를 보내지 않으므로, 수정할 때마다 공개 사이트 태그가 지워지는 문제 방지)
  • 기업 프로젝트는 기존 공개 응답 호환을 위해 category 문자열도 함께 저장
  • 밋업 요청에 tag, webThumbnailFile 추가

3. 수정 시 기존 값 유지

  • 이미지 파일을 보내지 않으면 기존 이미지 URL 유지 (기업 프로젝트 수정 시 매번 업로드를 시도하던 문제 해결)
  • 밋업 팀원은 orphanRemoval로 요청 값으로 교체

4. 응답 보정

  • 어드민 밋업 조회는 MeetupDetailResponse.forAdmin()으로 실제 기수를 응답 (공개 API의 meetupId 55 → 30 보정이 어드민 수정 폼을 거쳐 DB에 저장되는 문제 방지)
  • 웹 썸네일이 없으면 ".../null" 대신 null 응답
  • 태그가 없는 기업 프로젝트의 category는 [""] 대신 [] 응답
  • 밋업 type이 null이어도 상세 조회가 실패하지 않도록 처리

5. 정리

  • 미사용 TMPCorporateProject, TMPMeetupProject, TMPMeetupTeam, TMPReview 엔티티·레포지토리 및 DTO의 TMP 생성자 제거
  • MeetupProject.updateTeam() 제거 (orphanRemoval 컬렉션 참조 교체 시 예외 발생)
  • Swagger 설명의 (test db) 표기 정리

✅ 완료 조건

  • 어드민에서 등록/수정/삭제한 기업·밋업 프로젝트와 학회원 후기가 공개 API에 바로 반영된다
  • 기업·밋업 태그가 Tag 연관관계로 저장되어 공개 API tags에 노출된다
  • 수정 시 이미지·태그를 보내지 않으면 기존 값이 유지된다
  • TMPBlogReview를 제외한 TMP* 코드가 제거된다
  • 기존 테스트(어드민 인가 포함)가 모두 통과한다

🧪 테스트 및 검증 결과

테스트 항목 검증 방법 결과
기업 프로젝트 등록 → 공개 API 노출 (태그 포함) AdminContentTest.corporateProject 성공
기업 프로젝트 파일 없이 수정 시 이미지 유지, 태그 교체·재사용 AdminContentTest.corporateProject 성공
기업 프로젝트 tag 없이 수정 시 태그·분류 유지 AdminContentTest.corporateProject 성공
밋업 등록 → 공개 API 노출 (썸네일·팀원) AdminContentTest.meetupProject 성공
밋업 수정 시 이미지 유지, 팀원·태그 교체 / tag 없이 수정 시 태그 유지 AdminContentTest.meetupProject 성공
밋업 삭제 시 팀원 함께 삭제 AdminContentTest.meetupProject 성공
썸네일 없음 → null, 태그 없음 → category: [] AdminContentTest.optionalFieldsAreEmpty 성공
학회원 후기 등록/수정/삭제 → 공개 API 반영 AdminContentTest.review 성공
meetupId 55 기수 보정은 공개 응답에만 적용 MeetupDetailResponseTest 성공
어드민 인가 (비로그인 401 / 학회원 403 / 운영진 200) 회귀 AdminAuthorizationTest (기존 10건) 성공

테스트 환경

  • 환경: 로컬, JDK 17, H2 in-memory (PostgreSQL 모드)
  • 테스트 도구: JUnit 5, Spring MockMvc, Mockito (S3Service mock)

테스트 증빙

AdminContentTest           tests=4  failures=0 errors=0
AdminAuthorizationTest     tests=10 failures=0 errors=0
MeetupDetailResponseTest   tests=1  failures=0 errors=0
WebsiteApplicationTests    tests=1  failures=0 errors=0

미검증 항목

  • 실제 S3 업로드: 테스트에서 S3Service를 mock 처리
  • 실제 PostgreSQL 환경: H2로만 검증
  • 어드민 FE 연동: FE 작업 후 확인 필요
  • 운영 DB에 category가 null인 기존 기업 프로젝트 존재 여부: null이어도 빈 목록으로 응답하도록 처리함

🔍 리뷰 요청 사항

  • displayFlag는 이번 범위에서 제외했습니다. 컬럼은 있지만 공개 API 어디에서도 읽지 않아, 어드민 입력으로 받으면 숨김 기능처럼 오해할 수 있습니다. 노출 제어가 필요하면 별도 이슈로 진행하는 것을 제안합니다.
  • 태그 수정 방식: tag 미입력 시 기존 유지, 입력 시 교체합니다. multipart 요청은 빈 목록을 보낼 수 없어서 "태그 전체 삭제"는 현재 지원하지 않습니다. 필요하면 별도 플래그 추가를 검토하겠습니다.
  • 기업 프로젝트 태그를 category 문자열과 Tag 연관관계에 이중 저장합니다. 기존 공개 응답(category, tags)을 유지하기 위한 선택인데, 한쪽으로 통일할지 의견 부탁드립니다.
  • 알려진 이슈 (이번 범위 외)
    • 같은 새 태그를 동시에 저장하면 unique 제약 충돌 가능 (운영진 소수 사용이라 확률 낮음)
    • 이미지를 교체해도 이전 S3 파일은 삭제되지 않음 (기존 코드 공통 패턴)
    • 날짜 등 입력값 검증 부재 (기존 코드 공통)
    • 후기 team 응답이 기획/디자인/개발만 매핑됨 (기존 공개 응답 DTO 동작)
    • meetupId 55 하드코딩은 별도 이슈로 진행

⚠️ 배포 영향 및 참고 사항

  • DB 스키마/데이터 변경
    • 실제 테이블 스키마 변경 없음 (orphanRemoval은 매핑 옵션)
    • TMP 테이블의 기존 데이터는 테스트 데이터로 보고 이관하지 않음
    • ddl-auto=update라 TMP 테이블이 DB에 남습니다. 물리 삭제는 이 PR 범위 밖이며, 정리할 때 아래 SQL을 참고하세요 (tmpblog_review는 유지, 실행 전 \dt tmp*로 테이블명 확인)
      DROP TABLE IF EXISTS tmpmeetup_team;
      DROP TABLE IF EXISTS tmpmeetup_project;
      DROP TABLE IF EXISTS tmpcorporate_project;
      DROP TABLE IF EXISTS tmpreview;
  • 환경 변수 및 설정 변경: 없음
  • API 명세 변경
    • 밋업 등록/수정 요청에 webThumbnailFile, tag 추가 (선택)
    • 기업·밋업 tag는 선택값: 등록 시 미입력이면 태그 없음, 수정 시 미입력이면 기존 태그 유지
    • 공개 응답: web_thumbnail_url이 없으면 null, 기업 프로젝트 category가 비어 있으면 []
  • 기타 주의 사항
    • 배포 후 어드민의 등록/수정/삭제가 실제 사이트에 바로 반영됩니다. 운영진·FE에 공유 필요
    • 어드민 조회 API도 실제 데이터를 응답하므로, 기존에 TMP 테이블로 보던 테스트 데이터와 그 ID는 더 이상 유효하지 않습니다

☑️ PR 체크리스트

  • 관련 이슈를 연결했습니다.
  • 코드 및 Git 컨벤션을 준수했습니다.
  • 불필요한 코드와 디버깅 로그를 제거했습니다.
  • 필요한 테스트를 수행하고 결과를 기록했습니다.
  • 미검증 항목이나 알려진 문제를 기록했습니다.
  • API, DB, 설정 변경 시 관련 문서를 업데이트했습니다.
  • 민감 정보가 포함되지 않았는지 확인했습니다.

@hyunbin7664 hyunbin7664 self-assigned this Oct 25, 2026
@github-actions

Copy link
Copy Markdown

Unit Test Results

16 tests   16 ✔️  3s ⏱️
  4 suites    0 💤
  4 files      0 ❌

Results for commit 57daa91.

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

Projects

None yet

Development

Successfully merging this pull request may close these issues.

refactor: 어드민 콘텐츠 API TMP 테이블 → 실제 테이블 전환

1 participant