Skip to content

[FIX] 컬렉션 작품 표시 순서를 요청 순서대로 보존 - #602

Merged
GiJungPark merged 3 commits into
devfrom
feat/#559
Aug 9, 2026
Merged

GiJungPark merged 3 commits into
devfrom
feat/#559

Conversation

@GiJungPark

@GiJungPark GiJungPark commented Aug 9, 2026

Copy link
Copy Markdown
Member

Related Issue

Key Changes

  • 컬렉션 생성·수정 요청의 novelIds 배열 인덱스를 collection_novel.display_order로 저장하고, 순서만 재배치할 때 기존 연결 행과 created_date를 유지합니다. (8bc84a8)
  • 상세 조회의 RECENT/OLD 정렬과 사용자별·좋아요한 컬렉션 카드의 작품 미리보기를 display_order 기준으로 통일했습니다. (8bc84a8)
  • 기존 추가 시점 인덱스를 표시 순서 인덱스로 교체하고, 생성·수정·상세·목록·좋아요 미리보기의 순서 보존 회귀 테스트와 정책/API 문서를 보완했습니다. (8bc84a8)
  • 최신 dev를 충돌 없이 병합해 현재 배포 대상 기준으로 검증했습니다.

신규 환경용 collection_novel 전체 DDL

CREATE TABLE collection_novel (
    collection_novel_id BIGINT NOT NULL AUTO_INCREMENT,
    collection_id BIGINT NOT NULL,
    novel_id BIGINT NOT NULL,
    display_order INT NOT NULL,
    created_date DATETIME(6) NOT NULL,
    modified_date DATETIME(6) NOT NULL,
    PRIMARY KEY (collection_novel_id),
    CONSTRAINT uk_collection_novel_collection_novel
        UNIQUE (collection_id, novel_id),
    CONSTRAINT fk_collection_novel_collection
        FOREIGN KEY (collection_id) REFERENCES collection (collection_id),
    CONSTRAINT fk_collection_novel_novel
        FOREIGN KEY (novel_id) REFERENCES novel (novel_id),
    INDEX idx_collection_novel_collection_display_order (collection_id, display_order)
);

기존 환경용 migration DDL

MySQL 8.0의 ROW_NUMBER()를 사용합니다. backfill 검증 두 쿼리가 모두 0을 반환한 경우에만 NOT NULL 전환 이후 단계를 진행해야 합니다.

-- 1. 기존 행을 안전하게 backfill할 수 있도록 nullable로 추가
ALTER TABLE collection_novel
    ADD COLUMN display_order INT NULL AFTER novel_id;

-- 2. 배포 전 조회 순서(created_date DESC, collection_novel_id DESC)를 0부터 연속된 값으로 보존
WITH ranked AS (
    SELECT
        collection_novel_id,
        ROW_NUMBER() OVER (
            PARTITION BY collection_id
            ORDER BY created_date DESC, collection_novel_id DESC
        ) - 1 AS display_order
    FROM collection_novel
)
UPDATE collection_novel AS target
JOIN ranked
  ON ranked.collection_novel_id = target.collection_novel_id
SET target.display_order = ranked.display_order;

-- 3-1. NULL이 남지 않았는지 검증: 결과는 0이어야 함
SELECT COUNT(*) AS null_display_order_count
FROM collection_novel
WHERE display_order IS NULL;

-- 3-2. 컬렉션별 값이 0..n-1로 연속되고 중복되지 않는지 검증: 결과는 0이어야 함
SELECT COUNT(*) AS invalid_collection_count
FROM (
    SELECT collection_id
    FROM collection_novel
    GROUP BY collection_id
    HAVING MIN(display_order) <> 0
        OR MAX(display_order) <> COUNT(*) - 1
        OR COUNT(DISTINCT display_order) <> COUNT(*)
) AS invalid_collections;

-- 4. 검증 통과 후 NOT NULL 전환
ALTER TABLE collection_novel
    MODIFY COLUMN display_order INT NOT NULL;

-- 5. 신규 조회 인덱스 생성
CREATE INDEX idx_collection_novel_collection_display_order
    ON collection_novel (collection_id, display_order);

-- 6. 신규 인덱스 생성 성공 후 기존 인덱스 제거
DROP INDEX idx_collection_novel_collection_created
    ON collection_novel;

To Reviewers

  • display_order는 컬렉션 안에서 애플리케이션이 0..n-1 연속성을 보장합니다. 순서 맞바꿈의 중간 상태에서 충돌하지 않도록 (collection_id, display_order) 유니크 제약은 두지 않았습니다.
  • 기존 환경 migration은 DB 제약조건 변경이므로, 3단계 검증 결과가 모두 0인지 확인한 뒤 NOT NULL과 인덱스 교체를 적용해야 합니다. 기존 행은 현재 화면 순서인 created_date DESC, collection_novel_id DESC를 보존합니다.
  • 생성·수정 요청 및 조회 응답 필드는 변경하지 않았고, 기존 응답 필드 recentNovels도 호환성을 위해 유지했습니다.

References

@GiJungPark
GiJungPark marked this pull request as ready for review August 9, 2026 09:17
@github-actions
github-actions Bot requested review from ljy1348 and sansan20535 August 9, 2026 09:17
@GiJungPark
GiJungPark merged commit fe85ce0 into dev Aug 9, 2026
3 checks passed
@GiJungPark GiJungPark mentioned this pull request Sep 16, 2026
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