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. 대응 방식
가로 스크롤 허용
중요 컬럼 고정
카드형 목록으로 전환
상세 정보는 펼침 영역으로 제공
- 관리자 화면이 내부용이라도 모바일에서 급하게 확인할 일이 생길 수 있습니다.
- 최소한 핵심 정보는 확인 가능해야 합니다.
- 컬럼이 많거나 데이터가 길어질 때는 고정 컬럼과 Sticky Header가 유용합니다.
➕ 21-1. 고정하면 좋은 컬럼
고객명
주문번호
상담 ID
상태
액션 버튼
행이 많은 테이블
세로 스크롤이 긴 화면
컬럼명이 많아 중간에서 의미를 잃기 쉬운 화면
- 고정 컬럼은 편하지만 구현 복잡도가 올라갑니다.
- 처음에는 컬럼 수를 줄이고, 필요할 때 적용하는 것이 좋습니다.
✅ 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. 테이블 설계 체크리스트
- 목록에서 꼭 필요한 컬럼만 먼저 보여주는가?
- 긴 정보는 상세 모달/페이지로 분리했는가?
- 상태값이 라벨/배지로 명확히 구분되는가?
- 행 액션이 명확하고 위험 작업은 confirm을 거치는가?
- 모바일 또는 작은 화면에서 핵심 정보가 보이는가?
- 로딩/에러/빈 상태가 모두 처리되어 있는가?
- 권한 없는 사용자의 액션 버튼이 적절히 제한되는가?
- 백엔드에서도 권한 검사가 되어 있는가?
➕ 26-2. 검색·필터 체크리스트
- 검색어와 필터 조건이 URL에 남는가?
- 새로고침해도 검색 조건이 유지되는가?
- 검색 조건 변경 시 page가 1로 초기화되는가?
- 적용된 필터를 사용자가 확인할 수 있는가?
- 필터 초기화 버튼이 있는가?
- Empty 상태에서 필터 초기화를 제공하는가?
- 잘못된 URL query 값이 들어와도 안전하게 처리되는가?
- 백엔드 API도 같은 조건을 지원하는가?
➕ 26-3. 페이지네이션 체크리스트
- 현재 페이지와 전체 페이지 수가 표시되는가?
- 전체 건수가 표시되는가?
- 이전/다음 버튼 disabled 처리가 되는가?
- 페이지 크기 변경 시 page가 1로 초기화되는가?
- limit 최대값이 제한되는가?
- 페이지 이동이 URL에 반영되는가?
- queryKey에 page와 limit이 포함되어 있는가?
- 데이터 refetch 중 기존 데이터 유지 여부가 자연스러운가?
➕ 26-4. 운영 액션 체크리스트
- 상태 변경 후 목록이 갱신되는가?
- 수정/삭제 후 관련 query가 invalidate되는가?
- 엑셀 다운로드가 현재 필터 조건과 연결되는가?
- 대량 작업에 선택 개수와 confirm이 있는가?
- 일부 실패 가능성을 고려한 결과 메시지가 있는가?
- 작업 중 버튼이 disabled되는가?
- 작업 실패 시 재시도 또는 안내가 있는가?
- 관리자 작업 이력과 연결되는가?
✅ 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 답변 검증 기준
- 검색 조건을 local state에만 두라고 하지 않는가?
- URL query string과 TanStack Query queryKey를 연결하는가?
- queryKey에 모든 필터 조건을 포함하는가?
- 검색 조건 변경 시 page를 1로 초기화하는가?
- Empty 상태와 Error 상태를 구분하는가?
- 권한 없는 버튼 숨김과 백엔드 권한 검사를 구분하는가?
- 엑셀 다운로드가 현재 필터 조건과 연결된다고 설명하는가?
- 현재 서비스 규모에 맞는 현실적인 구조인가?
📌 요약
- 관리자 테이블은 운영자가 데이터를 찾고, 판단하고, 처리하는 핵심 UI입니다.
- 좋은 테이블은 모든 DB 컬럼을 보여주는 것이 아니라, 운영자가 필요한 정보를 우선순위에 맞게 보여줍니다.
- 검색은 자유 텍스트, 필터는 정해진 조건, 정렬은 순서 변경으로 구분해 설계해야 합니다.
- 관리자 목록의 검색 조건은 URL query string에 남겨야 새로고침, 뒤로가기, 링크 공유, 장애 재현이 쉬워집니다.
- TanStack Query의 queryKey에는 page, limit, keyword, status, source, 날짜, 정렬 조건처럼 API 결과를 바꾸는 모든 값이 포함되어야 합니다.
- 검색 조건이나 페이지 크기가 바뀌면 보통 page는 1로 초기화하는 것이 좋습니다.
- Empty 상태에서는 “데이터 없음”만 보여주지 말고, 검색 조건 변경이나 필터 초기화 같은 다음 행동을 제공해야 합니다.
- 행 클릭, 상세 모달, 상세 페이지, 액션 버튼은 작업 위험도와 정보량에 따라 구분해야 합니다.
- 상태 변경, 삭제, 대량 작업처럼 운영 영향이 큰 액션은 confirm과 권한 검사를 반드시 거쳐야 합니다.
- 프론트 테이블 설계는 백엔드의 검색/필터/정렬/페이지네이션 API 계약과 함께 맞춰야 안정적으로 운영할 수 있습니다.