Skip to content

MSG-498 feat: 행사 운영자가 콘솔에서 행사를 신청하고 반려본을 다시 낸다 - #243

Merged
s13121312 merged 12 commits into
developfrom
feature/MSG-498-event-submissions
Aug 29, 2026
Merged

MSG-498 feat: 행사 운영자가 콘솔에서 행사를 신청하고 반려본을 다시 낸다#243
s13121312 merged 12 commits into
developfrom
feature/MSG-498-event-submissions

Conversation

@s13121312

@s13121312 s13121312 commented Aug 29, 2026

Copy link
Copy Markdown
Member

🎫 관련 티켓

작업 내용

  • 행사 운영자 콘솔의 행사 등재 신청 API 5개를 열었다 — 대표 이미지 presign 발급, 신청 제출, 내 신청 목록(상태별 건수 동봉), 신청 상세(상태 이력·반려 사유 동봉), 반려본 수정 재제출. 전부 /api/org/event-submissions 아래라 인가 코드는 새로 만들지 않았다(MSG-496 matcher와 MSG-497 첫 로그인 게이트가 프리픽스로 자동 커버 — 인가 테스트 4건은 그 전제 확인).
  • 신청 저장 스키마 V49__event_submissions.sql — 신청·위치·영역 사각형·상태 이력 4테이블 + 신청 번호 전역 시퀀스(FM-{KST연도}-{4자리}). 반려 사유의 저장 원천은 이력 테이블 하나이고, CHECK 제약이 REJECTED 행에만 사유를 강제한다.
  • 등록 유형은 지역축제(FESTIVAL)·팝업스토어(POPUP) 2종. 유형별 필수/금지 필드 검증(13439), 위치당 영역은 사각형 합집합 기준 81칸 상한(13432), 격자 인덱스 범위·기간(KST 오늘 이상)·서술 길이(10~2000자) 검증.
  • 대표 이미지는 프로필 이미지(MSG-373) 2단 업로드 미러링 — pending presign 후 확정 시 HEAD 실측(0바이트 거부)과 새 uuid 복사, 롤백 보상 삭제, 커밋 후 pending 삭제.
  • 재제출은 REJECTED 한정·유형 불변·전체 교체. 상태 전이는 소유권 술어를 포함한 조건부 UPDATE 하나로 원자화했다.
  • 테스트 59건(단위 25 · 통합 34 — 동시 재제출 경합, 복사 응답 유실 보상, 게이트 커버 포함). 전체 빌드 2,811건 green.
  • 문서: 스펙 결정 기록 12건 + 작업 로그(실측 SQL·예외 흐름·트랜잭션 훅), SRS FR-EVENT-13·14 구현됨 승격 + RTM 재생성, 설명서 docs/explainers/MSG-498-submission-flow.html 신규.

🤔 고민한 내용

  • 연관 매핑은 다대일 양방향으로 확정(D-12) — 자식 @ManyToOne이 연관 주인, 부모는 mappedBy 컬렉션 + 편의 메서드. 중간에 단방향 @OneToMany + @JoinColumn으로 갔다가 주류 관행(일대다 단방향 지양)으로 되돌렸다. 왕복에서 실측 하나를 건졌다: @JoinColumn(nullable = false)면 단방향도 FK가 자식 INSERT에 함께 실려 NOT NULL에 걸리지 않는다 — 통설("INSERT 후 UPDATE")은 nullable 미지정 경우의 이야기다. 설명서 4절에 대비표로 정리했다.
  • 재제출 전이의 순서가 계약UPDATE ... WHERE id = ? AND user_id = ? AND status = 'REJECTED' 한 문장이 유일한 판정자다. 술어에 userId가 있어 남의 행은 어떤 경로로도 수정되지 않고, 영향 0행이면 소유 조회로 분기해 존재 은닉(13430)을 유지한다. clearAutomatically = true + 재로드가 UPDATE 뒤라 스테일 REJECTED가 복원될 경로가 없다(실 DB 동시성 테스트로 실증).
  • 81칸은 합산이 아니라 합집합 — 같은 영역을 어떤 사각형 조합으로 그렸든 판정이 같아야 해서다. 전개 전에 단일 사각형 칸 수를 long으로 선판정해 거대 입력의 OOM을 막고, 격자 인덱스 상한 상수는 RepresentativeGridResolver로 승격해 시더와 같은 값 하나를 쓴다.
  • S3 보상 삭제를 복사 호출보다 먼저 등록 (Codex 지적 반영) — 복사가 성공했는데 SDK 응답만 유실되면 보상 등록 전에 예외로 빠져 original 고아가 남던 경로를 닫았다. 복사 실패 시 보상은 없는 키 삭제라 no-op다. 순서를 되돌리면 실패하는 회귀 테스트를 동반했다.
  • 미채택 지적 2건 — POST 멱등 키(pending 클레임)는 스펙·구현 합쳐 6회 재등판했지만 일관 기각했다: 콘솔 수동 제출이라 중복 신청은 내 목록에서 보이고 심사에서 걸러지며, 데이터 손실 경로는 uuid 신규 발급으로 이미 닫혔다. 트랜잭션 안 S3 호출은 프로필 이미지 선례와 동일 구조라 이 티켓에서 갈라서지 않고 후속 티켓 후보로 기록했다(작업 로그).

👀 리뷰 포인트

  • 재제출의 에러 우선순위: 내 IN_REVIEW 신청에 형식이 깨진 본문을 보내면 13434보다 공통 400이 먼저 나간다(Bean Validation이 컨트롤러 진입 전). 스펙은 순서를 규정하지 않아 수용했는데 FE 관점에서 괜찮은지.
  • 내 목록의 상태별 건수를 별도 쿼리 없이 로드된 목록에서 센다 — 페이지네이션이 없어 목록 = 전량이라는 전제 위에 있고, 페이지네이션 도입 시 되돌려야 한다(리포지토리 주석 명시).
  • 배포 전 운영 필수: event-submissions/pending/ 프리픽스에 S3 라이프사이클 만료 규칙 추가(확정 없이 버려진 업로드 회수 — 작업 로그 런북 참조). 확정본 original은 공개 읽기를 열지 않는다(presigned GET만).

@claude

claude Bot commented Aug 29, 2026

Copy link
Copy Markdown

Claude finished @s13121312's task in 4m 17s —— View job


리뷰 완료

  • 병렬 브랜치 경합 확인 (마이그레이션 번호, developCode 대역, Owner A/B 계약)
  • 스펙(docs/spec/MSG-498.md) 대비 구현 검토
  • 실행 시 드러나는 결함 검토 (트랜잭션, 동시성, 시간대, 인가/소유권, N+1)
  • PR 본문 주장 검증
  • 발견 사항 정리

확인 범위: origin/develop 대비 diff 전체(46파일), EventSubmissionServiceImpl·EventSubmissionImageStore·EventSubmissionRepository(재제출 조건부 UPDATE + clearAutomatically)·엔티티 4종·V47 마이그레이션·인가/동시성 테스트 3종, docs/spec/MSG-498.md·SRS·RTM 갱신분.

병렬 경합: 마이그레이션 V47origin/develop 최신(V46__org_account_security.sql) 다음 번호로 충돌 없음. developCode 13430~13439origin/developEventErrorCode(13400~13422)와 겹치지 않고, 같은 13xxx 대역을 쓴 MSG-501(이미 develop에 병합)도 새 코드를 추가하지 않아 경합 없음. RepresentativeGridResolver에 추가된 GRID_INDEX_UPPER_EXCLUSIVE는 순수 추가(상수 승격)라 기존 시그니처·Owner A 계약 불변.

스펙·실행 결함: 재제출의 "조건부 UPDATE → 0행이면 소유 조회 분기 → 재로드"가 @Modifying(clearAutomatically = true)로 실제 뒷받침됨(벌크 UPDATE 후 영속성 컨텍스트를 비워 재로드가 스테일 캐시를 안 만남 — 문서 주장과 코드 일치, 동시 재제출 테스트로 실증). S3 보상 삭제 등록이 copyObject 호출보다 먼저 실행되는 순서도 코드·회귀 테스트로 확인됨. 81칸 검증은 long 산술로 사각형별 칸 수를 먼저 판정해 극단 입력에서의 정수 오버플로/OOM을 막음. 목록 응답(EventSubmissionSummaryResponseDto)은 locations에 접근하지 않아 N+1 없음. 시각 타입은 LocalDate(KST 라벨)/LocalDateTime(UTC) 구분이 컨벤션대로 지켜짐.

P3 (참고): PR 본문은 테스트 59건(통합 34)이라 하지만 실제 @Test 수를 세어보면 58건이고(status.md 작업 로그의 "58건·통합 33"과는 일치), 근소한 차이라 실질 영향 없음 — 추정컨대 카운트 스크립트의 사소한 오차로 보임.

라인 단위로 지적할 결함은 찾지 못해 인라인 코멘트는 남기지 않았습니다.

@github-actions

Copy link
Copy Markdown

@s13121312
s13121312 force-pushed the feature/MSG-498-event-submissions branch from e40a4ed to 1110d53 Compare August 29, 2026 08:16
@s13121312

Copy link
Copy Markdown
Member Author

V47 재번호가 필요합니다. MSG-499(PR #242, V48__org_account_requests)가 방금 먼저 머지돼서 develop 최신 마이그레이션이 V48입니다. 이 브랜치의 V47__event_submissions가 그대로 머지되면 CI(새 DB)는 버전 순서대로 적용돼 통과하지만, V48이 이미 적용된 dev·prod에서는 Flyway가 낮은 번호의 새 마이그레이션을 out-of-order로 무시해 event_submissions 테이블이 만들어지지 않습니다. V49로 재번호 후 머지해야 합니다.

🤖 AI 컨텍스트: 두 레인이 같은 날 V47을 잡은 경합 — 공유 로컬 DB에는 498의 V47이 먼저 적용돼 499가 V48로 밀었고(MSG-499 스펙 작업 로그), 머지는 499가 먼저였으므로 나중 쪽인 498이 재번호할 차례입니다(pr-base-sync 규칙).

@s13121312
s13121312 force-pushed the feature/MSG-498-event-submissions branch from 09ba5e7 to 1110d53 Compare August 29, 2026 08:18
@github-actions

Copy link
Copy Markdown

@github-actions

Copy link
Copy Markdown

@github-actions

Copy link
Copy Markdown

PR 리뷰 지적 반영. MSG-499(V48)가 먼저 머지돼 V47은 dev·prod에서 out-of-order로
무시된다(CI는 새 DB라 순서 적용돼 못 잡는 문제). 파일 내용 불변, 번호와 참조만 교체.
@github-actions

Copy link
Copy Markdown

@s13121312
s13121312 merged commit d6ddbd3 into develop Aug 29, 2026
1 check passed
@s13121312
s13121312 deleted the feature/MSG-498-event-submissions branch August 29, 2026 08:34
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

1 participant