Skip to main content

페이지네이션 및 무한 스크롤링 표준 가이드

이 문서는 vivid-ai 프로젝트의 데이터 처리 효율성과 사용자 경험(UX) 최적화를 위한 백엔드 페이지네이션 및 프론트엔드 무한 스크롤링 구현 표준을 정의합니다.

1. 개요​

사용자가 생성한 생성물(Creations), 페르소나(Personas), 커뮤니티 포스트(Posts) 등 데이터 양이 지속적으로 증가하는 리소스를 처리할 때, 서버 부하를 줄이고 클라이언트의 초기 로딩 속도를 보장하기 위해 표준화된 페이지네이션 방식을 적용합니다.

2. 백엔드 표준 (NestJS)​

2.1. 공통 DTO (PaginationQueryDto)​

모든 페이징 요청은 공통 DTO를 사용하여 page와 limit 파라미터를 받습니다.

export class PaginationQueryDto {
@IsOptional()
@Type(() => Number)
@IsInt()
@Min(1)
page?: number = 1;

@IsOptional()
@Type(() => Number)
@IsInt()
@Min(1)
@Max(100)
limit?: number = 20;
}

2.2. 공통 응답 구조 (PaginatedResult<T>)​

모든 페이징 API는 일관된 응답 형식을 반환하여 프론트엔드에서 쉽게 소비할 수 있도록 합니다.

export interface PaginatedResult<T> {
items: T[]; // 현재 페이지의 데이터 목록
total: number; // 전체 데이터 개수
page: number; // 현재 페이지 번호
limit: number; // 페이지당 데이터 개수
hasMore: boolean; // 다음 페이지 존재 여부
}

2.3. 서비스 구현 패턴​

TypeORM의 findAndCount를 사용하여 전체 개수와 데이터를 동시에 가져옵니다.

async findAll(query: PaginationQueryDto): Promise<PaginatedResult<Entity>> {
const { page, limit } = query;
const skip = (page - 1) * limit;

const [items, total] = await this.repository.findAndCount({
skip,
take: limit,
order: { createdAt: 'DESC' },
});

return {
items,
total,
page,
limit,
hasMore: total > skip + items.length,
};
}

3. 프론트엔드 표준 (Next.js & React Query)​

3.1. API 클라이언트 및 타입 정의​

src/features/creations/types.ts 등 관련 타입 정의 파일에 PaginatedResponse<T>를 정의하고 사용합니다.

3.2. 무한 스크롤링 Hook (useInfiniteQuery)​

@tanstack/react-query의 useInfiniteQuery를 사용하여 데이터를 관리합니다.

  • Query Key: 리소스별 고유 키 사용 (예: ['creations'])
  • pageParam: 1부터 시작하는 페이지 번호 사용
  • getNextPageParam: 응답의 hasMore 필드를 확인하여 다음 pageParam 결정

3.3. UI 컴포넌트 패턴​

가상 스크롤 (Virtual Scrolling)​

관리자 리스트 등 데이터가 매우 많고 행 높이가 일정한 경우 @tanstack/react-virtual을 활용한 가상 스크롤을 적용합니다.

갤러리 형태의 레이아웃에서는 @virtuoso.dev/masonry 또는 IntersectionObserver를 활용한 센티넬(Sentinel) 방식으로 하단 도달 시 fetchNextPage를 호출합니다.

3.4. 생성물 리스트 구현 패턴 (Creations Specific)​

생성물 데이터는 크게 두 가지 UI 패턴으로 렌더링되며, 각각의 목적에 맞게 페이지네이션 데이터가 처리됩니다.

A. 배치 로우 패턴 (Batch Row Pattern)​

  • 적용: 현재 /admin/generate, 향후 My Creations 탭 예정
  • 특징:
    • 개별 이미지가 아닌 '생성 시도(Creation)' 단위로 위아래 행을 구분하여 조회.
    • 각 행은 batch_size에 따른 결과물 묶음을 포함.
    • 우측 영역에 Positive Prompt, 파라미터 등 메타데이터를 상시 노출하여 관리 및 복기 용이성 확보.
    • 가상 스크롤(Virtual Scrolling)을 통한 대량의 배치 이력 성능 최적화 필수.
  • 적용: 현재 My Creations 탭, 향후 Community Feed 예정
  • 특징:
    • 개별 결과물(CreationResult) 단위로 격자형 렌더링.
    • 이미지의 시각적 완성도 강조.
    • IntersectionObserver 기반의 무한 스크롤을 통한 탐색형 UX 제공.

4. 적용 대상 및 현황 (2026-02-06 기준)​

리소스백엔드 적용 여부프론트엔드 적용 여부비고
Creations✅ 완료✅ 완료배치 로우 및 갤러리 패턴 공통 적용
Personas⏳ 예정⏳ 예정공통화 작업 후 적용 예정
Community Posts⏳ 예정⏳ 예정공유 기능 구현 시 함께 도입

5. 기대 효과​

  • 서버 자원 절약: 필요한 데이터만 데이터베이스에서 조회하고 네트워크로 전송합니다.
  • 메모리 최적화: 가상 스크롤을 통해 브라우저 DOM 엘리먼트 개수를 최소화합니다.
  • 사용자 경험 향상: 끊김 없는 데이터 로딩(Infinite Scroll)으로 현대적인 웹 환경을 제공합니다.
  • 데이터 일관성: 서로 다른 UI 패턴(배치형 vs 탐색형)에서도 동일한 페이징 아키텍처를 공유하여 유지보수성 향상.