Files
sam-docs/frontend/v1/03-component-design.md
유병철 8f939d3609 docs: [frontend] 프론트엔드 아키텍처/가이드 문서 v1 작성
- _index.md: 문서 목록 및 버전 관리
- 01~09: 아키텍처, API패턴, 컴포넌트, 폼, 스타일, 인증, 대시보드, 컨벤션
- 10: 문서 API 연동 스펙 (api-specs에서 이관)

Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
2026-03-09 10:24:25 +09:00

4.9 KiB

03. 컴포넌트 설계

대상: 프론트엔드 개발자, 기획자 버전: 1.0.0 최종 수정: 2026-03-09


1. 설계 원칙

  • 모든 페이지는 Client Component ('use client' 필수)
  • Config-Driven: 설정 객체로 페이지 동작 정의 → 일관성 + 빠른 개발
  • 기존 패턴 우선: 새 컴포넌트 만들기 전 반드시 유사 컴포넌트 검색
  • 계층 준수: atoms → molecules → organisms → templates → pages

2. 페이지 3대 유형

2.1 리스트 페이지 → UniversalListPage

사용 현황: 59+ 페이지

// 패턴: page.tsx는 얇은 껍데기, 비즈니스 로직은 도메인 컴포넌트에
// src/app/[locale]/(protected)/accounting/bills/page.tsx
'use client';
import { BillManagement } from '@/components/accounting/BillManagement';
export default function BillsPage() {
  return <BillManagement />;
}

// src/components/accounting/BillManagement/index.tsx
export function BillManagement() {
  const config: UniversalListConfig<BillRecord> = {
    title: '어음관리',
    icon: FileText,
    columns: [...],
    actions: { getList: getBills },
    // ... 나머지 설정
  };
  return <UniversalListPage config={config} />;
}

config로 제어하는 것들:

  • 컬럼 정의, 정렬, 필터
  • 검색/날짜 선택기
  • 통계 카드
  • 체크박스/선택
  • 액션 버튼
  • 모바일 카드 렌더링
  • Excel 내보내기

2.2 상세/폼 페이지 → IntegratedDetailTemplate

모드: create(등록), view(조회), edit(수정)

<IntegratedDetailTemplate
  mode="create"
  title="품목 등록"
  fields={fieldDefinitions}
  onSave={handleSave}
  onDelete={handleDelete}
/>

또는 Card 기반 수동 구성 (기존 패턴):

<PageLayout>
  <PageHeader title="품목 상세" />
  <Card>
    <CardContent>
      {/* 폼 필드들 */}
    </CardContent>
  </Card>
</PageLayout>

2.3 대시보드 → 커스텀 섹션 조합

CEO 대시보드처럼 여러 섹션을 조합하는 경우:

<PageLayout>
  <SummaryNavBar />
  <div className="space-y-6">
    {sectionOrder.map(key => renderSection(key))}
  </div>
</PageLayout>

3. 컴포넌트 계층별 가이드

atoms (src/components/atoms/)

  • 가장 작은 재사용 단위
  • HTML 요소 확장 또는 단일 기능
  • 예: ScrollableButtonGroup, PhoneInput, BusinessNumberInput

molecules (src/components/molecules/)

  • atom 2개 이상 조합
  • FormField: Label + Input 통합 (신규 폼 필수)
  • 예: FormField, DateRangeFilter

organisms (src/components/organisms/)

  • 독립적 기능 블록, 페이지에 바로 배치 가능
  • 내보내기 확인: src/components/organisms/index.ts
컴포넌트 용도
PageHeader 페이지 제목 + 액션 버튼
PageLayout 페이지 콘텐츠 래퍼 (패딩/max-width)
DataTable 범용 데이터 테이블
StatCards 통계 카드 모음
SearchFilter 검색/필터 바
SearchableSelectionModal<T> 검색+선택 모달 (제네릭)
MobileCard 모바일 리스트 카드

templates (src/components/templates/)

  • 페이지 전체 구조 정의
  • config 객체로 동작 제어
템플릿 용도 사용 수
UniversalListPage 리스트/목록 페이지 59+
IntegratedDetailTemplate 상세/등록/수정 페이지 10+

도메인 컴포넌트 (src/components/{domain}/)

  • 비즈니스 로직 포함
  • 도메인별 폴더 분류
components/
├── accounting/     # 회계: 입금, 출금, 전표, 어음, 세금계산서
├── hr/             # 인사: 사원, 급여, 근태
├── production/     # 생산: 공정, 생산일보
├── orders/         # 영업: 주문, 견적, 수주
├── business/       # 경영: CEO 대시보드
└── common/         # 공통: 계정과목 설정 등 여러 도메인에서 사용

4. 새 페이지 만들기 체크리스트

리스트 페이지

  1. src/app/[locale]/(protected)/{domain}/{page}/page.tsx 생성
  2. src/components/{domain}/{ComponentName}/index.tsx 생성
  3. src/components/{domain}/{ComponentName}/actions.ts 생성
  4. UniversalListPage config 작성
  5. types 정의 (API 응답 → 프론트 타입 변환)

상세/폼 페이지

  1. 기존 유사 페이지 검색 (패턴 참고)
  2. IntegratedDetailTemplate 사용 가능한지 확인
  3. 아니면 Card 기반 수동 구성

모달/팝업

  1. SearchableSelectionModal<T> 사용 가능한지 먼저 확인
  2. 아니면 Radix Dialog 직접 사용
  3. alert(), confirm() 사용 금지 → Dialog 또는 toast

5. 컴포넌트 레지스트리

개발 환경에서 /dev/component-registry 접속하면:

  • 전체 컴포넌트 목록 (실시간 스캔)
  • 컴포넌트 간 관계도 (imports, usedBy)
  • 새 컴포넌트 생성 전 기존 컴포넌트 확인 필수