TIL - 20260721

juni·2026년 7월 21일

TIL

목록 보기
410/468

0721 프론트엔드 실무 심화 (4/N): 관리자 테이블, 검색·필터·페이지네이션 설계


✅ 1. 관리자 테이블이란 무엇인가?

  • 관리자 테이블(Admin Table)은 운영자가 데이터를 한눈에 보고, 검색하고, 필터링하고, 수정하거나 처리할 수 있게 만드는 핵심 UI입니다.
  • 고객 화면이 “전환율” 중심이라면, 관리자 화면은 “업무 속도와 정확성”이 중심입니다.
  • 상담 목록, 주문 목록, 상품 목록, 배너 목록, 알림 발송 이력, ExportJob 목록, Webhook 실패 목록은 모두 관리자 테이블로 다루기 좋습니다.
데이터 조회
  ↓
검색/필터
  ↓
정렬/페이지네이션
  ↓
행 선택
  ↓
상세 확인
  ↓
상태 변경/수정/다운로드/재처리

➕ 1-1. 관리자 테이블이 중요한 이유

  • 운영자가 하루에 가장 많이 보는 화면입니다.
  • 데이터가 많아질수록 검색과 필터 품질이 중요해집니다.
  • 잘못된 테이블 설계는 운영 실수로 이어질 수 있습니다.
  • 상태 변경, 엑셀 다운로드, 대량 처리 같은 기능과 연결됩니다.
  • 관리자 페이지의 완성도는 테이블 품질에서 크게 갈립니다.
나쁜 테이블:
필터가 없음
상태 구분이 안 됨
로딩/에러/빈 상태가 없음
수정 후 목록이 안 갱신됨
컬럼이 너무 많아 보기 어려움

결과:
운영자가 엑셀로 따로 관리하거나 개발자에게 계속 확인 요청

✅ 2. 좋은 관리자 테이블의 기준

  • 좋은 테이블은 단순히 데이터를 많이 보여주는 것이 아닙니다.
  • 운영자가 “필요한 데이터를 빠르게 찾고, 안전하게 처리할 수 있게” 해야 합니다.

➕ 2-1. 좋은 테이블 조건

핵심 컬럼이 먼저 보임
검색/필터가 직관적임
상태값이 색상/라벨로 구분됨
페이지네이션이 안정적임
로딩/빈 상태/에러 상태가 있음
행 클릭 또는 상세 보기 흐름이 명확함
수정/삭제/상태 변경 액션이 안전함
엑셀 다운로드와 현재 필터 조건이 연결됨

➕ 2-2. 나쁜 테이블 예시

모든 DB 컬럼을 그대로 보여줌
전화번호/메모/날짜가 한 줄에 뒤섞임
검색 조건이 URL에 남지 않음
상태 변경 후 목록이 새로고침되지 않음
페이지 이동 시 필터가 초기화됨
빈 결과인데 그냥 빈 테이블만 보임
  • 관리자 테이블은 DB 구조를 그대로 보여주는 화면이 아닙니다.
  • 운영자가 실제로 판단하고 처리할 수 있게 재구성해야 합니다.

✅ 3. 테이블에 들어갈 기본 요소

요소설명
검색 영역keyword, 날짜, 상태, 유입경로 등
필터 영역상태, 카테고리, 담당자 등
액션 영역등록, 엑셀 다운로드, 대량 처리
테이블 헤더컬럼명, 정렬 가능 여부
테이블 바디실제 데이터 행
상태 배지PENDING, DONE 등
행 액션상세, 수정, 삭제, 재처리
페이지네이션page, limit, total
Empty 상태데이터 없음 안내
Error 상태조회 실패 안내
Loading 상태스켈레톤 또는 로딩 표시

➕ 3-1. 관리자 상담 목록 예시

상단:
검색어, 상태, 유입경로, 날짜 범위, 검색 버튼, 초기화 버튼

액션:
엑셀 다운로드, 선택 상담 담당자 변경

테이블:
신청일, 고객명, 전화번호, 상품명, 상태, 유입경로, 담당자, 최근 변경일, 액션

하단:
총 건수, 페이지네이션, 페이지 크기 선택

✅ 4. 테이블 컬럼 설계

  • 컬럼은 많이 넣는 것보다 “업무 판단에 필요한 순서”로 넣는 것이 중요합니다.
  • 모든 정보를 한 화면에 넣으려고 하면 오히려 보기 어려워집니다.

➕ 4-1. 컬럼 우선순위 기준

1순위:
운영자가 즉시 판단해야 하는 값

2순위:
검색/필터 결과 확인에 필요한 값

3순위:
상세에서 봐도 되는 값

4순위:
개발자만 필요한 내부 ID

➕ 4-2. 상담 목록 컬럼 예시

컬럼필요성
신청일최신 신청 확인
고객명상담 대상 확인
전화번호연락 대상 확인
상품명어떤 상품 문의인지 확인
상태처리 단계 확인
유입경로광고/검색 성과 확인
담당자누가 처리 중인지 확인
액션상세/상태 변경

➕ 4-3. 상세로 빼도 되는 정보

긴 상담 메모
상태 변경 전체 이력
알림톡 발송 이력
Webhook 원본 payload
내부 requestId
외부 API 응답 전문
  • 목록은 빠른 판단용입니다.
  • 긴 정보는 상세 모달이나 상세 페이지로 빼는 것이 좋습니다.

✅ 5. 검색과 필터의 차이

  • 검색과 필터는 비슷해 보이지만 성격이 다릅니다.
구분의미예시
검색자유 텍스트로 찾기고객명, 전화번호, 상품명
필터정해진 조건으로 좁히기상태, 유입경로, 담당자
날짜 조건기간 기준으로 조회신청일, 완료일
정렬순서 변경최신순, 오래된순

➕ 5-1. 검색어 예시

keyword:
홍길동
01012345678
아이폰
갤럭시

➕ 5-2. 필터 예시

status:
전체, 대기, 상담중, 완료, 취소

source:
전체, 네이버광고, 네이버쇼핑, 자연유입, 당근

assignee:
전체, 미배정, 담당자별
  • 검색어는 자유 입력입니다.
  • 필터는 가능한 값을 제한해 실수를 줄입니다.

✅ 6. 검색 조건은 URL에 남겨야 한다

  • 관리자 목록의 검색 조건은 URL query string에 남기는 것이 좋습니다.
  • 새로고침, 뒤로가기, 링크 공유, 장애 재현에 모두 유리합니다.

➕ 6-1. 좋은 URL 예시

/admin/consults?page=2&status=PENDING&source=NAVER_AD&keyword=아이폰&startDate=2026-07-01&endDate=2026-07-21

➕ 6-2. URL 상태로 남길 값

page
limit
keyword
status
source
assigneeId
startDate
endDate
sort
order

➕ 6-3. URL 상태로 남기지 않아도 되는 값

상세 모달 열림 여부
드롭다운 열림 여부
행 hover 상태
confirm 모달 열림 여부
toast 메시지
  • 검색 결과를 결정하는 조건은 URL에 남기는 것이 좋습니다.
  • 단순 UI 상태는 로컬 상태로 충분합니다.

✅ 7. 검색 폼과 URL 연결 흐름

검색 폼 입력
  ↓
검색 버튼 클릭
  ↓
URL query string 업데이트
  ↓
URL에서 조건 파싱
  ↓
TanStack Query queryKey 변경
  ↓
API 재호출
  ↓
테이블 갱신

➕ 7-1. 검색 제출 예시

const onSubmit = (values: SearchConsultFormValues) => {
  const params = new URLSearchParams();

  if (values.keyword) params.set('keyword', values.keyword);
  if (values.status) params.set('status', values.status);
  if (values.source) params.set('source', values.source);
  if (values.startDate) params.set('startDate', values.startDate);
  if (values.endDate) params.set('endDate', values.endDate);

  params.set('page', '1');
  params.set('limit', String(values.limit ?? 20));

  router.push(`/admin/consults?${params.toString()}`);
};
  • 검색 조건이 바뀌면 보통 page는 1로 초기화합니다.
  • 기존 page를 유지하면 결과가 적은 조건에서 빈 화면이 나올 수 있습니다.

✅ 8. URL 파싱과 기본값

  • URL query string에서 값을 읽을 때는 기본값을 명확히 정해야 합니다.
  • 잘못된 값이 들어왔을 때도 안전하게 처리해야 합니다.

➕ 8-1. 기본값 예시

const page = Number(searchParams.get('page') ?? 1);
const limit = Number(searchParams.get('limit') ?? 20);
const status = searchParams.get('status') ?? undefined;
const keyword = searchParams.get('keyword') ?? undefined;

➕ 8-2. 안전한 page 처리

function parsePage(value: string | null) {
  const page = Number(value);

  if (!Number.isInteger(page) || page < 1) {
    return 1;
  }

  return page;
}

➕ 8-3. limit 제한

function parseLimit(value: string | null) {
  const limit = Number(value);

  if (![20, 50, 100].includes(limit)) {
    return 20;
  }

  return limit;
}
  • URL은 사용자가 직접 수정할 수 있습니다.
  • 프론트에서도 기본 방어를 하고, 백엔드에서도 다시 검증해야 합니다.

✅ 9. queryKey 설계

  • 테이블 데이터는 서버 상태입니다.
  • 따라서 TanStack Query의 queryKey에 검색 조건을 모두 포함해야 합니다.

➕ 9-1. 상담 목록 queryKey

const queryKey = [
  'admin',
  'consults',
  {
    page,
    limit,
    keyword,
    status,
    source,
    startDate,
    endDate,
    sort,
    order,
  },
];

➕ 9-2. useQuery 예시

const consultsQuery = useQuery({
  queryKey: [
    'admin',
    'consults',
    {
      page,
      limit,
      keyword,
      status,
      source,
      startDate,
      endDate,
      sort,
      order,
    },
  ],
  queryFn: () =>
    adminConsultApi.getConsults({
      page,
      limit,
      keyword,
      status,
      source,
      startDate,
      endDate,
      sort,
      order,
    }),
  placeholderData: (previousData) => previousData,
});
  • queryKey에 조건이 빠지면 캐시가 섞이거나 화면이 갱신되지 않을 수 있습니다.
  • API 요청 파라미터와 queryKey 조건을 맞추는 습관이 중요합니다.

✅ 10. 페이지네이션 설계

  • 페이지네이션(Pagination)은 데이터가 많을 때 일정 개수씩 나누어 보여주는 방식입니다.
  • 관리자 테이블에서는 거의 필수입니다.

➕ 10-1. 기본 응답 구조

{
  "items": [],
  "meta": {
    "page": 1,
    "limit": 20,
    "total": 135,
    "totalPages": 7
  }
}

➕ 10-2. 페이지네이션 UI에 필요한 값

현재 페이지
페이지 크기
전체 데이터 수
전체 페이지 수
이전/다음 가능 여부

➕ 10-3. 페이지 이동 예시

function goToPage(nextPage: number) {
  const params = new URLSearchParams(searchParams.toString());

  params.set('page', String(nextPage));

  router.push(`/admin/consults?${params.toString()}`);
}
  • 페이지 이동도 URL query string을 업데이트하는 방식이 좋습니다.
  • 그래야 뒤로가기/앞으로가기가 자연스럽습니다.

✅ 11. 페이지 크기 변경

  • 관리자 테이블에서는 20개, 50개, 100개 단위로 볼 수 있게 하는 경우가 많습니다.
  • 페이지 크기를 바꾸면 보통 page는 1로 초기화합니다.

➕ 11-1. 예시

function changeLimit(nextLimit: number) {
  const params = new URLSearchParams(searchParams.toString());

  params.set('limit', String(nextLimit));
  params.set('page', '1');

  router.push(`/admin/consults?${params.toString()}`);
}

➕ 11-2. 기준

20:
기본값

50:
운영자가 넓게 보고 싶을 때

100:
엑셀 대신 빠르게 확인할 때

100 이상:
성능과 UX를 보고 신중하게
  • 너무 큰 limit은 API와 브라우저 렌더링에 부담을 줄 수 있습니다.
  • 대량 확인은 테이블보다 엑셀 Export로 분리하는 것이 좋습니다.

✅ 12. 정렬 설계

  • 정렬은 테이블에서 특정 기준으로 순서를 바꾸는 기능입니다.
  • 신청일, 수정일, 완료일, 금액, 상태 같은 컬럼에 적용할 수 있습니다.

➕ 12-1. 정렬 URL 예시

/admin/consults?sort=createdAt&order=desc

➕ 12-2. 정렬 가능한 컬럼 기준

createdAt
updatedAt
completedAt
price
status
source

➕ 12-3. 정렬하면 위험하거나 애매한 컬럼

긴 메모
복합 계산 값
외부 API 응답 상태 원문
배열/JSON 필드
프론트에서만 가공한 값
  • 정렬은 백엔드와 인덱스 설계가 함께 맞아야 합니다.
  • 프론트에서 현재 페이지의 20개만 정렬하면 전체 데이터 정렬이 아니므로 주의해야 합니다.

✅ 13. 클라이언트 정렬과 서버 정렬

방식설명적합한 경우
클라이언트 정렬현재 받아온 데이터만 정렬데이터 적음, 전체 데이터 로드됨
서버 정렬API에서 정렬해 반환관리자 목록, 대량 데이터

➕ 13-1. 관리자 페이지 기준

상담 목록
주문 목록
상품 목록
알림 이력
ExportJob 목록

→ 서버 정렬 권장
  • 관리자 데이터는 계속 늘어나므로 서버 정렬이 안전합니다.
  • 정렬 조건은 URL과 API 파라미터에 포함합니다.

✅ 14. 필터 초기화

  • 필터가 많아지면 사용자가 현재 어떤 조건이 걸려 있는지 놓치기 쉽습니다.
  • 필터 초기화 버튼은 관리자 테이블에서 매우 중요합니다.

➕ 14-1. 초기화 대상

keyword 제거
status 전체
source 전체
assignee 전체
startDate/endDate 제거
sort 기본값
page 1

➕ 14-2. 초기화 예시

function resetFilters() {
  router.push('/admin/consults?page=1&limit=20');
}

➕ 14-3. UX 기준

필터가 하나라도 적용되어 있을 때 초기화 버튼 노출
현재 적용된 필터 개수를 표시하면 더 좋음
Empty 상태에서도 필터 초기화 버튼 제공
  • 검색 결과가 없을 때 필터 초기화 버튼이 있으면 운영자가 빠르게 복구할 수 있습니다.

✅ 15. 적용된 필터 표시

  • 필터가 여러 개일 때는 현재 적용된 조건을 chip 형태로 보여주면 좋습니다.

➕ 15-1. 예시

[상태: 대기]
[유입경로: 네이버광고]
[검색어: 아이폰]
[날짜: 2026-07-01 ~ 2026-07-21]

➕ 15-2. 장점

현재 조건을 한눈에 확인 가능
개별 필터 제거 가능
검색 결과 없음의 원인 파악 쉬움
운영자 실수 감소

➕ 15-3. 개별 필터 제거 예시

function removeFilter(key: string) {
  const params = new URLSearchParams(searchParams.toString());

  params.delete(key);
  params.set('page', '1');

  router.push(`/admin/consults?${params.toString()}`);
}

✅ 16. 행 클릭과 액션 버튼

  • 테이블 행을 클릭해서 상세를 열지, 별도 상세 버튼을 둘지 기준을 정해야 합니다.

➕ 16-1. 행 클릭이 적합한 경우

상세 확인이 가장 주요 행동
행 전체가 클릭 가능해도 혼란이 없음
체크박스/버튼과 충돌하지 않음

➕ 16-2. 별도 버튼이 적합한 경우

행 안에 버튼이 여러 개 있음
체크박스 선택이 있음
상태 변경/삭제 같은 위험 액션이 있음
모바일에서 오작동 가능성이 있음

➕ 16-3. 상담 목록 기준

추천:
행 클릭 → 상세 모달
행 오른쪽 액션 → 상태 변경, 수정, 이력 보기

주의:
상태 변경/삭제는 행 클릭만으로 실행하지 않기
  • 위험한 작업은 반드시 명확한 버튼과 confirm을 거쳐야 합니다.

✅ 17. 상세 모달과 상세 페이지

  • 테이블에서 상세 데이터를 보여줄 때 모달을 쓸지 페이지를 쓸지 결정해야 합니다.
방식장점단점
상세 모달목록 흐름 유지, 빠른 확인URL 공유 어려움, 깊은 정보에 부적합
상세 페이지URL 공유 가능, 정보 많을 때 좋음목록에서 벗어남

➕ 17-1. 모달이 좋은 경우

상담 상세 빠른 확인
간단한 상태 변경
메모 수정
알림 이력 간단 확인

➕ 17-2. 상세 페이지가 좋은 경우

주문 상세
결제/배송/상담/이력 모두 필요한 화면
Webhook 원본 확인
장애 재처리 상세
복잡한 설정 화면
  • 상담은 모달로 충분할 수 있지만, 주문이나 장애 이력은 상세 페이지가 더 나을 수 있습니다.

✅ 18. 선택 상태와 대량 작업

  • 관리자 테이블에서는 여러 행을 선택해서 대량 처리할 수 있습니다.
  • 예를 들어 담당자 배정, 상태 변경, 엑셀 다운로드, 삭제, 노출 변경 등이 있습니다.

➕ 18-1. 대량 작업이 필요한 경우

여러 상담 담당자 배정
여러 상품 노출/비노출 변경
여러 배너 삭제
여러 알림 재발송
여러 ExportJob 정리

➕ 18-2. 대량 작업 주의사항

선택된 개수 표시
작업 전 confirm
권한 검사
처리 실패 일부 발생 가능성 고려
성공/실패 결과 요약
백엔드에서도 대상별 권한/상태 검증

➕ 18-3. Confirm 메시지 예시

선택한 12건의 상담을 완료 처리하시겠습니까?
이미 완료/취소된 상담은 제외될 수 있습니다.
  • 대량 작업은 운영 실수 영향이 크기 때문에 반드시 확인 단계를 둬야 합니다.

✅ 19. 테이블 로딩/에러/빈 상태

  • 0720에서 다룬 화면 상태는 테이블에도 그대로 적용됩니다.

➕ 19-1. 테이블 상태 기준

Loading:
스켈레톤 row 표시

Fetching:
기존 목록 유지 + 상단 작은 로딩 표시

Empty:
조건에 맞는 데이터 없음 + 필터 초기화

Error:
조회 실패 + 다시 시도

Forbidden:
권한 없음 안내

Not Found:
상세 데이터 없음

➕ 19-2. 예시

if (consultsQuery.isLoading) {
  return <ConsultTableSkeleton />;
}

if (consultsQuery.isError) {
  return (
    <ErrorState
      message="상담 목록을 불러오지 못했습니다."
      onRetry={() => consultsQuery.refetch()}
    />
  );
}

if (!consultsQuery.data.items.length) {
  return (
    <EmptyState
      title="조건에 맞는 상담 신청이 없습니다"
      description="검색어나 필터 조건을 변경해 보세요."
      action={<button onClick={resetFilters}>필터 초기화</button>}
    />
  );
}

return <ConsultTable data={consultsQuery.data.items} />;
  • 테이블 영역 자체가 상태별로 명확히 바뀌어야 합니다.
  • 빈 테이블만 보여주는 것은 피하는 것이 좋습니다.

✅ 20. 컬럼 표시와 모바일 대응

  • 관리자 테이블은 PC 기준으로 만들 때가 많지만, 작은 화면에서도 최소한 사용할 수 있어야 합니다.
  • 모든 컬럼을 모바일에 그대로 넣으면 보기 어렵습니다.

➕ 20-1. 모바일에서 숨겨도 되는 컬럼

내부 ID
상세 메모 일부
보조 상태
긴 URL
생성자/수정자
부가 설명

➕ 20-2. 모바일에서도 중요한 컬럼

고객명
전화번호
상품명
상태
신청일
액션

➕ 20-3. 대응 방식

가로 스크롤 허용
중요 컬럼 고정
카드형 목록으로 전환
상세 정보는 펼침 영역으로 제공
  • 관리자 화면이 내부용이라도 모바일에서 급하게 확인할 일이 생길 수 있습니다.
  • 최소한 핵심 정보는 확인 가능해야 합니다.

✅ 21. 고정 컬럼과 Sticky Header

  • 컬럼이 많거나 데이터가 길어질 때는 고정 컬럼과 Sticky Header가 유용합니다.

➕ 21-1. 고정하면 좋은 컬럼

고객명
주문번호
상담 ID
상태
액션 버튼

➕ 21-2. Sticky Header가 좋은 경우

행이 많은 테이블
세로 스크롤이 긴 화면
컬럼명이 많아 중간에서 의미를 잃기 쉬운 화면
  • 고정 컬럼은 편하지만 구현 복잡도가 올라갑니다.
  • 처음에는 컬럼 수를 줄이고, 필요할 때 적용하는 것이 좋습니다.

✅ 22. 테이블 성능 문제

  • 행이 많아지면 브라우저 렌더링 성능이 떨어질 수 있습니다.
  • 관리자 테이블은 무조건 한 번에 많이 보여주기보다 페이지네이션과 서버 필터를 잘 써야 합니다.

➕ 22-1. 성능 문제 신호

스크롤이 버벅임
필터 변경 시 화면이 멈춤
1000개 이상 row를 한 번에 렌더링
각 row에서 무거운 컴포넌트 렌더링
불필요한 re-render가 많음

➕ 22-2. 해결 방향

서버 페이지네이션 사용
limit 제한
컬럼 렌더링 단순화
row 컴포넌트 memo 검토
가상 스크롤 검토
대량 데이터는 Export로 분리
  • 일반 관리자 목록은 서버 페이지네이션이 기본입니다.
  • 수천 건을 한 화면에 보여주는 것은 대부분 좋지 않습니다.

✅ 23. 테이블 라이브러리 선택

  • 직접 table을 만들 수도 있고, 라이브러리를 사용할 수도 있습니다.
  • 중요한 것은 현재 요구사항에 맞는 수준을 고르는 것입니다.

➕ 23-1. 직접 구현이 괜찮은 경우

컬럼이 적음
정렬/필터가 단순함
대량 선택이 없음
디자인 커스터마이징이 중요함

➕ 23-2. TanStack Table이 좋은 경우

컬럼 정의가 복잡함
정렬/필터/선택이 필요함
헤더 그룹이 필요함
테이블 상태를 세밀하게 제어하고 싶음

➕ 23-3. Handsontable류가 좋은 경우

엑셀처럼 셀 편집이 필요함
복사/붙여넣기가 중요함
대량 데이터 직접 편집이 필요함
스프레드시트 UX가 필요함
  • 일반 목록 관리는 TanStack Table + 서버 상태 관리 조합이 좋습니다.
  • 엑셀처럼 셀 단위 편집이 필요하면 Handsontable류가 맞을 수 있습니다.

✅ 24. 테이블 API 설계와 프론트의 관계

  • 좋은 테이블은 백엔드 API 설계와 함께 가야 합니다.
  • 프론트에서 아무리 잘 만들어도 백엔드가 검색/필터/정렬/페이지네이션을 지원하지 않으면 한계가 있습니다.

➕ 24-1. 목록 API 요청 예시

GET /api/admin/consults?page=1&limit=20&keyword=아이폰&status=PENDING&source=NAVER_AD&sort=createdAt&order=desc

➕ 24-2. 목록 API 응답 예시

{
  "items": [
    {
      "id": 123,
      "customerName": "홍길동",
      "phone": "010****5678",
      "productName": "iPhone 17 Pro",
      "status": "PENDING",
      "source": "NAVER_AD",
      "createdAt": "2026-07-21T09:00:00.000Z"
    }
  ],
  "meta": {
    "page": 1,
    "limit": 20,
    "total": 135,
    "totalPages": 7
  }
}

➕ 24-3. 백엔드와 맞춰야 할 것

검색 가능한 필드
필터 가능한 값
정렬 가능한 컬럼
페이지네이션 방식
응답 meta 구조
마스킹된 개인정보 여부
권한별 컬럼 노출 여부
  • 프론트 테이블 설계는 API 계약과 같이 잡아야 합니다.
  • 특히 개인정보 마스킹은 프론트만 믿지 말고 백엔드 응답에서 처리하는 것이 안전합니다.

✅ 25. 관리자 테이블 컴포넌트 구조 예시

AdminConsultPage
  ├─ ConsultSearchForm
  ├─ ActiveFilterChips
  ├─ ConsultTableToolbar
  ├─ ConsultTable
  │   ├─ ConsultTableHeader
  │   ├─ ConsultTableRow
  │   └─ ConsultRowActions
  ├─ Pagination
  ├─ ConsultDetailModal
  └─ UpdateStatusModal

➕ 25-1. 역할

컴포넌트역할
ConsultSearchForm검색 조건 입력
ActiveFilterChips적용된 필터 표시
ConsultTableToolbar엑셀 다운로드, 대량 액션
ConsultTable목록 렌더링
ConsultRowActions상세/상태 변경 버튼
Pagination페이지 이동
ConsultDetailModal상세 정보
UpdateStatusModal상태 변경 폼
  • 화면이 커질수록 역할별로 나눠야 유지보수가 쉬워집니다.
  • 단, 처음부터 너무 잘게 나누기보다는 기능 단위로 분리하면 됩니다.

✅ 26. 실무 체크리스트

➕ 26-1. 테이블 설계 체크리스트

  1. 목록에서 꼭 필요한 컬럼만 먼저 보여주는가?
  2. 긴 정보는 상세 모달/페이지로 분리했는가?
  3. 상태값이 라벨/배지로 명확히 구분되는가?
  4. 행 액션이 명확하고 위험 작업은 confirm을 거치는가?
  5. 모바일 또는 작은 화면에서 핵심 정보가 보이는가?
  6. 로딩/에러/빈 상태가 모두 처리되어 있는가?
  7. 권한 없는 사용자의 액션 버튼이 적절히 제한되는가?
  8. 백엔드에서도 권한 검사가 되어 있는가?

➕ 26-2. 검색·필터 체크리스트

  1. 검색어와 필터 조건이 URL에 남는가?
  2. 새로고침해도 검색 조건이 유지되는가?
  3. 검색 조건 변경 시 page가 1로 초기화되는가?
  4. 적용된 필터를 사용자가 확인할 수 있는가?
  5. 필터 초기화 버튼이 있는가?
  6. Empty 상태에서 필터 초기화를 제공하는가?
  7. 잘못된 URL query 값이 들어와도 안전하게 처리되는가?
  8. 백엔드 API도 같은 조건을 지원하는가?

➕ 26-3. 페이지네이션 체크리스트

  1. 현재 페이지와 전체 페이지 수가 표시되는가?
  2. 전체 건수가 표시되는가?
  3. 이전/다음 버튼 disabled 처리가 되는가?
  4. 페이지 크기 변경 시 page가 1로 초기화되는가?
  5. limit 최대값이 제한되는가?
  6. 페이지 이동이 URL에 반영되는가?
  7. queryKey에 page와 limit이 포함되어 있는가?
  8. 데이터 refetch 중 기존 데이터 유지 여부가 자연스러운가?

➕ 26-4. 운영 액션 체크리스트

  1. 상태 변경 후 목록이 갱신되는가?
  2. 수정/삭제 후 관련 query가 invalidate되는가?
  3. 엑셀 다운로드가 현재 필터 조건과 연결되는가?
  4. 대량 작업에 선택 개수와 confirm이 있는가?
  5. 일부 실패 가능성을 고려한 결과 메시지가 있는가?
  6. 작업 중 버튼이 disabled되는가?
  7. 작업 실패 시 재시도 또는 안내가 있는가?
  8. 관리자 작업 이력과 연결되는가?

✅ 27. AI를 활용해 관리자 테이블을 설계할 때 질문법

  • AI에게 관리자 테이블을 설계시킬 때는 화면 목적, 컬럼, 검색 조건, API 응답 구조, 액션, 권한, 빈 상태와 에러 상태까지 함께 알려줘야 합니다.

➕ 27-1. 좋은 질문 예시

React + TanStack Query + URL query string 기반으로 관리자 상담 목록 테이블을 만들고 싶어.

상황:
1. 상담 목록 API는 page, limit, keyword, status, source, startDate, endDate, sort, order를 지원함
2. 응답은 items와 meta(page, limit, total, totalPages) 구조임
3. 검색 조건은 새로고침해도 유지되어야 함
4. 검색어/상태/유입경로/날짜 범위 필터가 있음
5. 상태 변경, 상세 보기, 엑셀 다운로드 액션이 있음
6. 상태 변경 성공 후 목록이 갱신되어야 함
7. VIEWER 권한은 상태 변경 버튼을 볼 수 없음
8. Empty 상태에서는 필터 초기화 버튼을 보여주고 싶음
9. 모바일에서는 핵심 컬럼만 보이게 하고 싶음

요청:
- URL 상태 설계
- queryKey 설계
- 검색 폼 구조
- 테이블 컬럼 구성
- 페이지네이션 구조
- 적용된 필터 chip UX
- 상태 변경 mutation과 invalidate 기준
- 로딩/에러/빈 상태 처리
- 권한별 액션 노출 기준
- 컴포넌트 분리 구조
를 실무 기준으로 정리해줘.

➕ 27-2. AI 답변 검증 기준

  1. 검색 조건을 local state에만 두라고 하지 않는가?
  2. URL query string과 TanStack Query queryKey를 연결하는가?
  3. queryKey에 모든 필터 조건을 포함하는가?
  4. 검색 조건 변경 시 page를 1로 초기화하는가?
  5. Empty 상태와 Error 상태를 구분하는가?
  6. 권한 없는 버튼 숨김과 백엔드 권한 검사를 구분하는가?
  7. 엑셀 다운로드가 현재 필터 조건과 연결된다고 설명하는가?
  8. 현재 서비스 규모에 맞는 현실적인 구조인가?

📌 요약

  • 관리자 테이블은 운영자가 데이터를 찾고, 판단하고, 처리하는 핵심 UI입니다.
  • 좋은 테이블은 모든 DB 컬럼을 보여주는 것이 아니라, 운영자가 필요한 정보를 우선순위에 맞게 보여줍니다.
  • 검색은 자유 텍스트, 필터는 정해진 조건, 정렬은 순서 변경으로 구분해 설계해야 합니다.
  • 관리자 목록의 검색 조건은 URL query string에 남겨야 새로고침, 뒤로가기, 링크 공유, 장애 재현이 쉬워집니다.
  • TanStack Query의 queryKey에는 page, limit, keyword, status, source, 날짜, 정렬 조건처럼 API 결과를 바꾸는 모든 값이 포함되어야 합니다.
  • 검색 조건이나 페이지 크기가 바뀌면 보통 page는 1로 초기화하는 것이 좋습니다.
  • Empty 상태에서는 “데이터 없음”만 보여주지 말고, 검색 조건 변경이나 필터 초기화 같은 다음 행동을 제공해야 합니다.
  • 행 클릭, 상세 모달, 상세 페이지, 액션 버튼은 작업 위험도와 정보량에 따라 구분해야 합니다.
  • 상태 변경, 삭제, 대량 작업처럼 운영 영향이 큰 액션은 confirm과 권한 검사를 반드시 거쳐야 합니다.
  • 프론트 테이블 설계는 백엔드의 검색/필터/정렬/페이지네이션 API 계약과 함께 맞춰야 안정적으로 운영할 수 있습니다.

0개의 댓글