ERP-node/popdocs/archive/COMPONENT_ROADMAP.md

8.9 KiB

POP 컴포넌트 로드맵

큰 그림: 3단계 접근

┌─────────────────────────────────────────────────────────────────┐
│                                                                 │
│  1단계: 기초 블록        2단계: 조합 블록       3단계: 완성 화면   │
│  ───────────────       ───────────────       ───────────────   │
│                                                                 │
│  [버튼] [입력창]        [폼 그룹]              [작업지시 화면]     │
│  [아이콘] [라벨]   →    [카드]           →     [실적입력 화면]     │
│  [뱃지] [로딩]          [리스트]               [모니터링 대시보드]  │
│                        [테이블]                                 │
│                                                                 │
└─────────────────────────────────────────────────────────────────┘

1단계: 기초 블록 (Primitive)

가장 작은 단위. 다른 곳에서 재사용됩니다.

필수 기초 블록

컴포넌트 역할 우선순위
PopButton 모든 버튼 1
PopInput 텍스트 입력 1
PopLabel 라벨/제목 1
PopIcon 아이콘 표시 1
PopBadge 상태 뱃지 2
PopLoading 로딩 스피너 2
PopDivider 구분선 3

PopButton 예시

interface PopButtonProps {
  children: React.ReactNode;
  variant: "primary" | "secondary" | "danger" | "success";
  size: "sm" | "md" | "lg" | "xl";
  disabled?: boolean;
  loading?: boolean;
  icon?: string;
  fullWidth?: boolean;
  onClick?: () => void;
}

// 사용
<PopButton variant="primary" size="lg">
  작업 완료
</PopButton>

PopInput 예시

interface PopInputProps {
  type: "text" | "number" | "date" | "time";
  value: string | number;
  onChange: (value: string | number) => void;
  label?: string;
  placeholder?: string;
  required?: boolean;
  error?: string;
  size: "md" | "lg";  // POP은 lg 기본
}

// 사용
<PopInput 
  type="number" 
  label="수량" 
  size="lg"
  value={qty}
  onChange={setQty}
/>

2단계: 조합 블록 (Compound)

기초 블록을 조합한 중간 단위.

조합 블록 목록

컴포넌트 구성 용도
PopFormField Label + Input + Error 폼 입력 그룹
PopCard Container + Header + Body 정보 카드
PopListItem Container + Content + Action 리스트 항목
PopNumberPad Grid + Buttons 숫자 입력
PopStatusBox Icon + Label + Value 상태 표시

PopFormField 예시

// 기초 블록 조합
function PopFormField({ label, required, error, children }) {
  return (
    <div className="pop-form-field">
      <PopLabel required={required}>{label}</PopLabel>
      {children}
      {error && <span className="error">{error}</span>}
    </div>
  );
}

// 사용
<PopFormField label="품번" required error={errors.itemCode}>
  <PopInput type="text" value={itemCode} onChange={setItemCode} />
</PopFormField>

PopCard 예시

function PopCard({ title, badge, children, onClick }) {
  return (
    <div className="pop-card" onClick={onClick}>
      <div className="pop-card-header">
        <PopLabel size="lg">{title}</PopLabel>
        {badge && <PopBadge>{badge}</PopBadge>}
      </div>
      <div className="pop-card-body">
        {children}
      </div>
    </div>
  );
}

// 사용
<PopCard title="작업지시 #1234" badge="진행중">
  <p>목표 수량: 100개</p>
  <p>완료 수량: 45개</p>
</PopCard>

3단계: 복합 컴포넌트 (Complex)

비즈니스 로직이 포함된 완성형.

복합 컴포넌트 목록

컴포넌트 기능 데이터
PopDataTable 대량 데이터 표시/편집 API 연동
PopCardList 카드 형태 리스트 API 연동
PopBarcodeScanner 바코드/QR 스캔 카메라/외부장치
PopKpiGauge KPI 게이지 실시간 데이터
PopAlarmList 알람 목록 웹소켓
PopProcessFlow 공정 흐름도 공정 데이터

PopDataTable 예시

interface PopDataTableProps {
  // 데이터
  data: any[];
  columns: Column[];
  
  // 기능
  selectable?: boolean;
  editable?: boolean;
  sortable?: boolean;
  
  // 반응형 (자동)
  responsiveColumns?: {
    tablet: string[];
    mobile: string[];
  };
  
  // 이벤트
  onRowClick?: (row: any) => void;
  onSelectionChange?: (selected: any[]) => void;
}

// 사용
<PopDataTable
  data={workOrders}
  columns={[
    { key: "orderNo", label: "지시번호" },
    { key: "itemName", label: "품명" },
    { key: "qty", label: "수량", align: "right" },
    { key: "status", label: "상태" },
  ]}
  responsiveColumns={{
    tablet: ["orderNo", "itemName", "qty", "status"],
    mobile: ["orderNo", "qty"],  // 모바일은 2개만
  }}
  onRowClick={(row) => openDetail(row.id)}
/>

개발 순서 제안

Phase 1: 기초 (1-2주)

Week 1:
- PopButton (모든 버튼의 기반)
- PopInput (모든 입력의 기반)
- PopLabel
- PopIcon

Week 2:
- PopBadge
- PopLoading
- PopDivider

Phase 2: 조합 (2-3주)

Week 3:
- PopFormField (폼의 기본 단위)
- PopCard (카드의 기본 단위)

Week 4:
- PopListItem
- PopStatusBox
- PopNumberPad

Week 5:
- PopModal
- PopToast

Phase 3: 복합 (3-4주)

Week 6-7:
- PopDataTable (가장 복잡)
- PopCardList

Week 8-9:
- PopBarcodeScanner
- PopKpiGauge
- PopAlarmList
- PopProcessFlow

컴포넌트 설계 원칙

1. 크기는 외부에서 제어

// 좋음: 크기를 props로 받음
<PopButton size="lg">확인</PopButton>

// 나쁨: 내부에서 크기 고정
<button style={{ height: "48px" }}>확인</button>

2. 최소 크기는 내부에서 보장

// 컴포넌트 내부
const styles = {
  minHeight: 48,  // 터치 최소 크기 보장
  minWidth: 80,
};

3. 반응형은 자동

// 좋음: 화면 크기에 따라 자동 조절
<PopFormField label="이름">
  <PopInput />
</PopFormField>

// 나쁨: 모드별로 다른 컴포넌트
{isMobile ? <MobileInput /> : <TabletInput />}

4. 데이터와 UI 분리

// 좋음: 데이터 로직은 훅으로
const { data, loading, error } = useWorkOrders();

<PopDataTable data={data} loading={loading} />

// 나쁨: 컴포넌트 안에서 fetch
function PopDataTable() {
  useEffect(() => {
    fetch('/api/work-orders')...
  }, []);
}

폴더 구조 제안

frontend/components/pop/
├── primitives/           # 1단계: 기초 블록
│   ├── PopButton.tsx
│   ├── PopInput.tsx
│   ├── PopLabel.tsx
│   ├── PopIcon.tsx
│   ├── PopBadge.tsx
│   ├── PopLoading.tsx
│   └── index.ts
│
├── compounds/            # 2단계: 조합 블록
│   ├── PopFormField.tsx
│   ├── PopCard.tsx
│   ├── PopListItem.tsx
│   ├── PopNumberPad.tsx
│   ├── PopStatusBox.tsx
│   └── index.ts
│
├── complex/              # 3단계: 복합 컴포넌트
│   ├── PopDataTable/
│   │   ├── PopDataTable.tsx
│   │   ├── PopTableHeader.tsx
│   │   ├── PopTableRow.tsx
│   │   └── index.ts
│   ├── PopCardList/
│   ├── PopBarcodeScanner/
│   └── index.ts
│
├── hooks/                # 공용 훅
│   ├── usePopTheme.ts
│   ├── useResponsiveSize.ts
│   └── useTouchFeedback.ts
│
└── styles/               # 공용 스타일
    ├── pop-variables.css
    └── pop-base.css

스타일 변수

/* pop-variables.css */

:root {
  /* 터치 크기 */
  --pop-touch-min: 48px;
  --pop-touch-industrial: 60px;
  
  /* 폰트 크기 */
  --pop-font-body: clamp(14px, 1.5vw, 18px);
  --pop-font-heading: clamp(18px, 2.5vw, 28px);
  --pop-font-caption: clamp(12px, 1vw, 14px);
  
  /* 간격 */
  --pop-gap-sm: 8px;
  --pop-gap-md: 16px;
  --pop-gap-lg: 24px;
  
  /* 색상 */
  --pop-primary: #2563eb;
  --pop-success: #16a34a;
  --pop-warning: #f59e0b;
  --pop-danger: #dc2626;
  
  /* 고대비 (야외용) */
  --pop-high-contrast-bg: #000000;
  --pop-high-contrast-fg: #ffffff;
}

다음 단계

  1. 기초 블록부터 시작: PopButton, PopInput 먼저 만들기
  2. 스토리북 설정: 컴포넌트별 문서화
  3. 테스트: 터치 크기, 반응형 확인
  4. 디자이너 연동: v4 레이아웃 시스템과 통합

최종 업데이트: 2026-02-03