Skip to content

아카이브 월별 조회 API에 무한스크롤 지원 추가#297

Open
IENFI wants to merge 56 commits into
devfrom
feat/archive-infinite-scroll-#296
Open

아카이브 월별 조회 API에 무한스크롤 지원 추가#297
IENFI wants to merge 56 commits into
devfrom
feat/archive-infinite-scroll-#296

Conversation

@IENFI

@IENFI IENFI commented Jun 19, 2026

Copy link
Copy Markdown
Collaborator

요약 (연관 이슈 번호 포함)

그룹/개인 월별 아카이브 조회 API에 전체 기간 기준 무한스크롤 조회를 추가했습니다.
기존 연도별 조회는 유지하면서, allYears, cursor, limit 파라미터를 통해
월 카드 단위로 다음 페이지를 불러올 수 있도록 백엔드를 확장했습니다.

작업 내용 + 스크린샷

  • 그룹 월별 아카이브 조회 API에 전체 기간 조회 분기 추가
  • 개인 월별 아카이브 조회 API에 전체 기간 조회 분기 추가
  • 월별 아카이브 응답에 items, nextCursor 구조 적용
  • 월 단위 커서 인코딩/디코딩 및 페이지 계산 유틸 추가
  • 기존 getMonthlyArchive 내부 로직을 공통 메서드로 정리해 재사용 가능하게 분리
  • 기존 연도별 조회 API 동작은 유지

실제 걸린 시간

  • 약 3h

작업하며 고민했던 점(선택)

  • 무한스크롤 기준을 게시글이 아닌 월 카드 단위로 잡아야 해서, 포스트 커서가 아닌 월 커서를 별도로 두었습니다.
  • 기존 연도별 조회를 깨지 않기 위해 새 엔드포인트를 만들기보다 같은 API에서 조회 모드를 분기하는 방식을 선택했습니다.
  • 그룹/개인 아카이브가 유사한 구조를 가지므로, 월 커서 계산 로직은 공통 유틸로 분리했습니다.

테스트 실행 여부

  • 👍 네, 테스트했어요.
  • 🙅 아니요, 필요하지 않아요.
  • 🤯 아니요, 하지만 테스트가 필요해요.

리뷰 참고사항(선택)

시각 자료(이미지/영상, 있다면)(선택)

없음

IENFI and others added 30 commits June 20, 2026 02:50
- `User` 엔티티의 OAuth 식별자 제약을 활성 사용자 기준으로 변경
- 탈퇴한 계정과 재가입 계정이 공존할 수 있는 구조를 반영
- users 테이블의 OAuth 유니크 제약을 활성 사용자 기준 partial unique index로 전환
- 탈퇴 계정과 재가입 계정이 공존할 수 있도록 provider_id 기준 제약 구조 변경
- OAuth 로그인 시 soft-deleted 사용자 조회 및 recover 흐름 제거
- 동일 OAuth 식별자로 재로그인해도 기존 탈퇴 계정을 복원하지 않도록 변경
- active user만 기존 계정으로 간주하고 없으면 새 사용자 생성
- OAuth 로그인 시 active user는 기존 계정으로 갱신되는 케이스 추가
- 탈퇴 계정은 복구하지 않고 새 사용자로 생성되는 케이스 추가
- 테스트 파일에서 jest 전역 타입을 인식할 수 있도록 compilerOptions.types 설정 추가
- describe, it, expect, jest 관련 에디터 경고가 발생하지 않도록 정리
- 회원 탈퇴 시 refresh token 정리를 위해 RefreshToken 엔티티를 모듈에 등록
- 마이페이지 서비스에서 refresh token 리포지토리를 사용할 수 있도록 의존성 구성 반영
- 회원 탈퇴 성공 시 해당 사용자의 refresh token을 일괄 revoke 하도록 변경
- 탈퇴 이후 기존 세션으로 토큰 재발급이 되지 않도록 정리
- 회원 탈퇴 시 사용자 soft delete와 refresh token revoke가 함께 수행되는 케이스 추가
- 이미 삭제된 사용자 처리 시 refresh token 정리가 실행되지 않는 케이스 검증
- 회원 탈퇴 시 소유 그룹 조회를 위해 Group 엔티티를 모듈에 등록
- 마이페이지 서비스에서 그룹 소유 여부를 확인할 수 있도록 DI 구성 반영
- 회원 탈퇴 전에 사용자가 소유한 그룹이 있는지 먼저 조회하도록 변경
- 소유 그룹이 있으면 그룹 이름을 포함한 안내 메시지와 함께 탈퇴를 차단
- owner 그룹이 없을 때만 기존 탈퇴 및 refresh token revoke 로직 수행
- 소유 그룹이 없을 때 정상 탈퇴되는 케이스 검증
- owner 그룹이 있으면 탈퇴가 차단되고 후속 정리가 실행되지 않는 케이스 추가
- 회원 탈퇴 시 공유 글의 share token revoke, refresh token revoke, user soft delete를 한 트랜잭션으로 처리
- 관련 탈퇴 흐름 테스트를 보강해 revoke 동작을 검증
- 그룹 나가기 시 groups.owner_id 대신 group_members.role 기준으로 관리자 여부를 확인하도록 변경
- 관리자인 사용자가 그룹을 나가려는 경우 관리자 그룹 여부를 검사하도록 로직 정리
- owner_id와 실제 그룹 권한 간 불일치로 인해 관리자가 그대로 탈퇴되는 문제를 완화
- 그룹 나가기 전 관리자 수 조회를 count 조건에서 query builder 기반 조회로 변경
- users.deleted_at IS NULL 조건을 추가해 탈퇴 유저를 관리자 수 산정에서 제외
- 유일한 관리자 판단 시 soft delete 상태의 사용자까지 고려하도록 정리
- 그룹 나가기 처리에서 별도 그룹 존재 조회를 제거하고 멤버 삭제 결과로 실패 여부를 판단
- 같은 그룹의 active 관리자 멤버 row에 pessimistic write lock을 적용
- 관리자 수 확인과 멤버 삭제를 하나의 트랜잭션으로 묶어 유일한 관리자 이탈을 방지
- group_members에 deleted_at 컬럼을 추가해 탈퇴한 멤버를 soft delete로 관리
- 기존 group_id, user_id unique constraint를 제거
- active 멤버만 유니크하도록 partial unique index 추가
- 마이그레이션 이름을 인자로 받도록 db:mig:gen 스크립트 수정
- 이름 없이 실행할 경우 잘못된 파일이 생성되지 않도록 사용법 안내 후 종료
- 테스트 환경 마이그레이션 생성 스크립트에도 동일한 검증 적용
- 그룹 설정 DTO에서 ownerUserId 필드 제거
- 그룹 설정 조회 시 owner relation 로드를 제거하고 응답에서 ownerUserId 제외
- 프론트 그룹 설정 타입과 mock 데이터를 변경된 응답 구조에 맞게 수정
- 그룹 삭제 권한 확인 기준을 최초 생성자 owner에서 active ADMIN 멤버로 변경
- ownerId와 그룹 내 관리자 권한 간의 정책 불일치를 제거
- 그룹 최상위 권한 판단을 group_members.role 기준으로 일원화

Co-authored-by: Copilot <copilot@github.com>
- 멤버 추방 시 owner 기준 방장 확인을 제거하고 ADMIN 멤버 추방을 차단하도록 변경
- 멤버 추방을 soft delete로 처리하고 target membership row에 pessimistic lock 적용
- 권한 변경 시 active ADMIN row와 target membership row를 트랜잭션에서 잠그도록 변경
- 유일한 ADMIN을 non-ADMIN으로 변경하지 못하도록 방어 로직 추가
- 그룹 나가기 시 active ADMIN row와 본인 membership row를 잠그고 현재 membership id 기준으로 soft delete
- 그룹 내 프로필 수정 시 profileMediaId null 요청을 변경 없음으로 오인하지 않도록 undefined 기준으로 검사
- 멤버 추방 API endpoint를 렌더 시점의 deleteMember 상태값으로 생성하던 문제 수정
- 삭제 버튼 클릭 시점의 member 정보를 mutate 변수로 전달해 정확한 userId로 요청하도록 변경
- 추방 성공 처리에서도 상태값 대신 mutation variables를 사용해 제거 대상 정보를 참조
- 그룹 정보 수정 시 사용하지 않는 owner relation 로드를 제거
- owner 기준 권한 판단 제거 이후 남은 불필요한 관계 조회 정리
- 초대 링크 조회 시 멤버 수 계산에 active user 조건 추가
- group_members의 soft delete 기본 필터와 별도로 users.deleted_at IS NULL 조건을 반영

Co-authored-by: Copilot <copilot@github.com>
- .env.example에 ADMIN_KEY 예시 값을 추가
- 공지사항 관리자 키 용도와 보안 주석을 함께 정리
- 그룹 역할 우선순위 상수를 공용 유틸로 추출
- 관리자 승격 후보 선택 유틸을 추가해 역할 및 가입 순서 기준을 재사용 가능하게 정리
- 그룹 권한 가드가 동일한 우선순위 유틸을 사용하도록 변경
- 회원 탈퇴 트랜잭션에서 사용자 row를 잠그고 탈퇴 가능 여부를 먼저 확인하도록 변경
- 그룹 멤버십을 순회하며 비관리자 탈퇴, 공동 관리자 탈퇴, 유일 관리자 그룹 삭제, 관리자 양도 후 탈퇴를 처리하도록 추가
- share token revoke, refresh token revoke, user soft delete 전에 그룹 멤버십 정리가 함께 수행되도록 정리
- 유일한 관리자이자 유일한 멤버인 그룹 삭제 케이스를 검증
- 다른 멤버에게 관리자 권한을 양도한 뒤 탈퇴하는 케이스를 검증
- 공동 관리자 존재 시 단순 멤버십 삭제와 이미 탈퇴한 사용자 예외 케이스를 검증
- 회원 탈퇴 시 그룹별 멤버십 정리 분기를 private helper 메서드로 분리
- withdraw 본문이 전체 탈퇴 흐름만 드러나도록 그룹 삭제, 관리자 양도, 멤버십 삭제 로직을 정리
- 기존 동작은 유지하면서 탈퇴 로직의 가독성과 책임 분리를 개선
- GroupService에 transaction manager를 받는 deleteGroup helper를 추가
- 기존 그룹 삭제 API가 공용 helper를 통해 삭제를 수행하도록 정리
- 회원 탈퇴 시 빈 그룹 삭제도 동일한 그룹 삭제 helper를 재사용하도록 변경
- 마이페이지 모듈과 테스트 코드를 GroupService 주입 구조에 맞게 동기화
- draft 무효화와 draft media 정리를 공용 cleanup service로 추출
- 그룹 삭제 시 해당 그룹의 active draft를 일괄 무효화하고 draft snapshot을 갱신하도록 변경
- 그룹 나가기, 멤버 추방, VIEWER 강등, 회원 탈퇴 시 해당 사용자가 owner인 그룹 draft를 무효화하도록 추가
- draft invalidation 시 websocket 알림과 in-memory presence/lock 상태도 함께 정리되도록 보강
IENFI and others added 23 commits June 20, 2026 02:50
- 회원 탈퇴 트랜잭션에서 user_month_covers를 userId 기준으로 삭제하도록 추가
- 개인 포스트 삭제 이후 stale 상태로 남을 수 있는 월별 커버 설정 데이터를 함께 정리
- 마이페이지 탈퇴 테스트에 개인 월별 커버 삭제 호출 검증을 추가
- MediaService에 참조 없는 READY 미디어 자산 정리 cron 작업을 추가
- post, draft, 프로필, 그룹 커버, 월별 커버에서 참조되지 않는 asset만 orphan으로 판별하도록 구현
- orphan asset은 S3 원본 삭제 후 media_assets row도 함께 삭제하도록 정리
- media 모듈에 orphan 판별용 엔티티 의존성을 추가
- transaction-aware media cleanup helper 추가
- 삭제 흐름에서 수집한 candidate mediaIds 기준으로 active 참조 여부 확인 후 media_assets 정리
- 커밋 이후 S3 원본 삭제 처리
- 그룹 삭제, 회원 탈퇴, draft invalidation 경로에 미디어 정리 연결
- 기존 orphan sweep cron은 안전망으로 유지
Co-authored-by: Copilot <copilot@github.com>
- Group 엔티티에서 owner relation을 제거
- 그룹 생성 시 owner 컬럼 저장 없이 첫 멤버를 ADMIN으로 등록하도록 변경
- owner 기준 그룹 모델에서 group_members 기반 권한 구조로 일관되게 정리
- post e2e 테스트의 그룹 생성 fixture에서 owner relation 주입을 제거
- 그룹 정리 로직을 owner 기준 삭제 대신 테스트 그룹 이름 기준 삭제로 변경
- Group 엔티티 구조 변경 이후 발생하던 타입 및 lint 오류를 정리
- 자동 마이그레이션 생성 시 불필요한 스키마 변경이 섞이지 않도록 엔티티 정의를 현재 DB 구조에 가깝게 조정

Co-authored-by: Copilot <copilot@github.com>
- groups 테이블의 owner_id foreign key constraint를 제거
- groups.owner_id 컬럼을 삭제하도록 마이그레이션 추가
- down 마이그레이션에서 owner_id 컬럼과 foreign key를 복구하도록 구성
- 공용 인증 Unauthorized 예외를 추가하고 401 응답에 세부 error.code를 담도록 정리
- 마이페이지 프로필 조회 시 사용자 없음 케이스를 USER_NOT_FOUND 코드로 구분
- 인증 코드 교환, refresh token 만료/재사용/세션 무효화 케이스도 각각 별도 401 코드로 분리
- auth error code를 refresh 대상과 terminal 세션 종료 대상으로 구분하도록 프론트 분기 추가
- USER_NOT_FOUND 같은 terminal 401에서는 refresh를 반복하지 않고 바로 로그아웃하도록 변경
- /api/auth/session 재호출 루프를 줄이기 위해 401 처리 조건을 세분화
- 회원 탈퇴 중 ADMIN 멤버십 정리 시 VIEWER를 관리자 이관 후보에서 제외
- 이관 가능한 ADMIN/EDITOR가 없으면 그룹을 삭제하도록 분기
- VIEWER를 ADMIN으로 승격시키던 흐름을 제거
- 프로필 수정 시 사용자 레코드 락 조회 및 기존 profileImageId 확인
- 프로필 이미지 교체 및 null 삭제 시 이전 이미지 orphan 정리
- 개인 프로필 이미지 삭제 요청 null 입력 허용 및 DTO 정합성 반영
- 프로필 이미지 교체 시 이전 이미지 정리 검증
- 프로필 이미지 null 삭제 시 이전 이미지 정리 검증
- 닉네임만 변경하는 경우 미디어 정리 미발생 검증
- 미디어 삭제 후보 예약을 위한 delete_requested_at, delete_retry_count, last_delete_error 컬럼 추가
- 요청 경로에서 orphan 판정 대신 삭제 후보 표시만 수행하는 구조로 전환
- 백그라운드 큐에서 참조 재확인 후 S3 병렬 삭제 및 성공 건 DB 최종 삭제 수행
- 삭제 실패 시 재시도 횟수와 마지막 오류 기록 유지
- orphan 정리 및 재시도 cron을 삭제 예약 기반 흐름으로 재구성
- 회원 탈퇴, 프로필 수정, 그룹 삭제, 그룹 멤버 정리 흐름의 미디어 정리 반환값을 후보 ID 기반으로 통일
- draft invalidation 결과 구조를 mediaDeletionCandidateIds 중심으로 정리
- 요청 완료 후 실제 삭제 대신 백그라운드 삭제 큐 적재 호출로 변경
- 미디어 삭제 후보 표시, orphan 삭제, 재참조 복구, 삭제 실패 재시도 메타 기록 검증
- 프로필 수정 및 회원 탈퇴 흐름의 삭제 후보 기반 미디어 정리 동작 검증
- 기존 미디어 정리 호출부 변경에 따른 반환값 구조와 후속 호출 정합성 검증
- 그룹 멤버 추방 시 멤버십 프로필 이미지를 삭제 후보로 함께 수집
- 그룹 나가기 시 멤버십 프로필 이미지를 삭제 후보로 함께 수집
- draft invalidation 결과와 프로필 이미지 후보를 합쳐 백그라운드 삭제 큐로 전달
- 그룹 멤버 추방 시 프로필 이미지가 삭제 후보에 포함되는지 검증
- 그룹 나가기 시 프로필 이미지가 삭제 후보에 포함되는지 검증
- draft invalidation 후보와 프로필 이미지 후보가 함께 전달되는지 검증
- 그룹 월별 아카이브 조회에 allYears, cursor, limit 쿼리 지원 추가
- 전체 연도 기준 월 카드 목록을 커서 기반으로 페이지네이션하도록 분기 추가
- 기존 getMonthlyArchive 내부 월별 조회 로직을 공통 메서드로 정리
- 월 단위 nextCursor 계산을 공통 유틸로 분리
- 기존 연도별 조회 동작은 유지
- month cursor 인코딩/디코딩 동작 검증
- 잘못된 cursor 입력을 무시하는 동작 검증
- 첫 페이지 및 다음 페이지 계산 로직 검증
- 사용자 월별 아카이브 조회에 allYears, cursor, limit 쿼리 지원 추가
- 전체 연도 기준 월 카드 목록을 커서 기반으로 페이지네이션하도록 분기 추가
- 기존 getMonthlyArchive 내부 월별 조회 로직을 공통 메서드로 정리
- 사용자 월별 아카이브 페이지 응답 DTO를 추가
- 기존 연도별 조회 동작은 유지
@IENFI IENFI linked an issue Jun 19, 2026 that may be closed by this pull request
6 tasks
@IENFI IENFI changed the title Feat/archive infinite scroll #296 아카이브 월별 조회 API에 무한스크롤 지원 추가 Jun 19, 2026
@IENFI IENFI requested a review from H-sooyeon June 19, 2026 18:38
@IENFI IENFI self-assigned this Jun 19, 2026
@IENFI IENFI added 🦉 feat New feature or request 🛠️ BE 백엔드 작업 labels Jun 19, 2026
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

🛠️ BE 백엔드 작업 🦉 feat New feature or request

Projects

None yet

Development

Successfully merging this pull request may close these issues.

아카이브 월별 조회 API에 무한스크롤 지원 추가

1 participant