페이지네이션 및 무한 스크롤링 표준 가이드
이 문서는 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을 활용한 가상 스크롤을 적용합니다.
Masonry 레이아웃 (Gallery)
갤러리 형태의 레이아웃에서는 @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)을 통한 대량의 배치 이력 성능 최적화 필수.
B. 메이슨리 갤러리 패턴 (Masonry Gallery Pattern)
- 적용: 현재
My Creations탭, 향후Community Feed예정 - 특징:
- 개별 결과물(CreationResult) 단위로 격자형 렌더링.
- 이미지의 시각적 완성도 강조.
IntersectionObserver기반의 무한 스크롤을 통한 탐색형 UX 제공.
4. 적용 대상 및 현황 (2026-02-06 기준)
| 리소스 | 백엔드 적용 여부 | 프론트엔드 적용 여부 | 비고 |
|---|---|---|---|
| Creations | ✅ 완료 | ✅ 완료 | 배치 로우 및 갤러리 패턴 공통 적용 |
| Personas | ⏳ 예정 | ⏳ 예정 | 공통화 작업 후 적용 예정 |
| Community Posts | ⏳ 예정 | ⏳ 예정 | 공유 기능 구현 시 함께 도입 |
5. 기대 효과
- 서버 자원 절약: 필요한 데이터만 데이터베이스에서 조회하고 네트워크로 전송합니다.
- 메모리 최적화: 가상 스크롤을 통해 브라우저 DOM 엘리먼트 개수를 최소화합니다.
- 사용자 경험 향상: 끊김 없는 데이터 로딩(Infinite Scroll)으로 현대적인 웹 환경을 제공합니다.
- 데이터 일관성: 서로 다른 UI 패턴(배치형 vs 탐색형)에서도 동일한 페이징 아키텍처를 공유하여 유지보수성 향상.