ERP-node/frontend/lib/meta-components/examples/README.md

7.2 KiB

메타 컴포넌트 V3 사용 가이드 (Phase A)

개요

화면 디자이너 V3 메타 컴포넌트는 기존 70개+ 컴포넌트를 7개 메타 컴포넌트로 통합하는 시스템입니다. Phase A에서는 핵심 3개 메타 컴포넌트(Field, DataView, Action)를 구현했습니다.

Phase A 구현 범위

1. Field 메타 컴포넌트

  • 자동 생성: table_type_columnswebType 기반
  • 지원 타입: text, number, date, select, entity, checkbox, textarea, email, file
  • 자동 감지: FK 관계 자동 감지 → entity 타입 + join 설정
  • 유효성 검사: webType별 기본 validation 내장

2. DataView 메타 컴포넌트

  • 뷰 모드: table, card, list (전환 가능)
  • 기본 기능: 페이징, 정렬, 필터링
  • 액션: 등록, 수정, 삭제 버튼
  • 반응형: 모바일/데스크톱 최적화

3. Action 메타 컴포넌트

  • 버튼 렌더링: buttonType별 shadcn/ui variant 자동 매핑
  • 확인 대화상자: 위험한 작업 시 확인 요청
  • steps 파이프라인: Phase B에서 완전 구현 예정 (Phase A에서는 onClick 콜백만 실행)

4. Reactive Binding Engine

  • 이벤트 발행/구독: 컴포넌트 간 동적 연동
  • 조건부 실행: condition 평가 지원
  • 데이터 변환: transform 로직 적용
  • 우선순위: priority 기반 실행 순서 제어

백엔드 API 엔드포인트

Field Config 자동 생성

GET /api/meta/field-config/:tableName/:columnName

// 응답 예시
{
  "success": true,
  "data": {
    "webType": "entity",
    "label": "부서",
    "placeholder": "부서를 선택하세요",
    "required": true,
    "join": {
      "referenceTable": "dept_info",
      "referenceColumn": "dept_code",
      "displayColumn": "dept_name"
    }
  }
}

테이블 컬럼 목록 조회

GET /api/meta/table-columns/:tableName

// 응답 예시
{
  "success": true,
  "data": {
    "tableName": "user_info",
    "columns": [
      {
        "columnName": "user_id",
        "columnComment": "사용자 ID",
        "webType": "text",
        "required": true
      },
      {
        "columnName": "dept_code",
        "columnComment": "부서",
        "webType": "entity",
        "required": false,
        "join": {
          "referenceTable": "dept_info",
          "referenceColumn": "dept_code",
          "displayColumn": "dept_name"
        }
      }
    ]
  }
}

레이아웃 저장

POST /api/meta/layout/save

// 요청 예시
{
  "version": "3.0",
  "screenId": 123,
  "layerId": 1,
  "components": [
    {
      "id": "field_user_name",
      "type": "meta-field",
      "webType": "text",
      "label": "사용자명",
      "binding": "user_name",
      "required": true
    },
    {
      "id": "dataview_user_list",
      "type": "meta-dataview",
      "viewMode": "table",
      "tableName": "user_info"
    }
  ],
  "layers": [
    { "id": 1, "name": "기본", "visible": true, "order": 1 }
  ]
}

레이아웃 로드

GET /api/meta/layout/:screenId?layerId=1

Reactive Binding 저장

POST /api/meta/bindings/save

// 요청 예시
{
  "screenId": 123,
  "bindings": [
    {
      "id": "binding_dept_filter",
      "sourceComponent": "field_dept_code",
      "sourceEvent": "onChange",
      "targetComponent": "dataview_user_list",
      "targetAction": "filter",
      "condition": {
        "type": "expression",
        "expression": "source.value !== ''"
      },
      "transform": {
        "config": {
          "filterField": "dept_code",
          "filterValue": "{{source.value}}"
        }
      },
      "priority": 10,
      "enabled": true
    }
  ]
}

Reactive Binding 조회

GET /api/meta/bindings/:screenId

사용 예시

1. 간단한 Field 렌더링

import { FieldRenderer } from "@/lib/meta-components/Field/FieldRenderer";

<FieldRenderer
  config={{
    id: "field_user_name",
    type: "meta-field",
    webType: "text",
    label: "사용자명",
    binding: "user_name",
    required: true,
    maxLength: 50,
  }}
  value={userName}
  onChange={(value) => setUserName(value)}
/>

2. DataView 렌더링

import { DataViewRenderer } from "@/lib/meta-components/DataView/DataViewRenderer";

<DataViewRenderer
  config={{
    id: "dataview_user_list",
    type: "meta-dataview",
    viewMode: "table",
    tableName: "user_info",
    columns: [
      { field: "user_id", header: "사용자 ID", webType: "text" },
      { field: "user_name", header: "사용자명", webType: "text" },
      { field: "dept_code", header: "부서", webType: "entity" },
    ],
    pagination: {
      enabled: true,
      pageSize: 20,
    },
  }}
  data={users}
  onActionClick={(action, rowData) => {
    console.log("액션:", action, "데이터:", rowData);
  }}
/>

3. Reactive Binding 설정

import { ReactiveBindingEngine } from "@/lib/meta-components/bindings/ReactiveBindingEngine";

const bindingEngine = new ReactiveBindingEngine();

// 바인딩 설정
bindingEngine.setBindings([
  {
    id: "binding_1",
    sourceComponent: "field_dept_code",
    sourceEvent: "onChange",
    targetComponent: "dataview_user_list",
    targetAction: "filter",
    transform: {
      config: {
        filterField: "dept_code",
        filterValue: "{{source.value}}",
      },
    },
    priority: 10,
    enabled: true,
  },
]);

// 이벤트 발행 (Field onChange 시)
bindingEngine.emitEvent("field_dept_code", "onChange", { value: "IT" });

주의사항

1. API 클라이언트 (필수!)

// ❌ 금지: fetch() 직접 사용
const response = await fetch("/api/meta/field-config/user_info/user_name");

// ✅ 올바른 방법: apiClient 사용
import { getFieldConfig } from "@/lib/api/metaComponent";
const response = await getFieldConfig("user_info", "user_name");

2. 멀티테넌시

  • 모든 API 호출 시 req.user.companyCode 자동 필터링
  • 프론트엔드에서는 company_code를 직접 전달하지 않음

3. 버전 관리

  • V3 레이아웃은 반드시 version: "3.0" 명시
  • screen_layouts_v3 테이블에 CHECK 제약조건 있음

4. shadcn/ui 스타일 가이드

  • CSS 변수 사용: bg-primary, text-muted-foreground
  • 중첩 박스 금지: Card 안에 Card 넣지 않기
  • 반응형 디자인: 모바일 우선 접근

Phase B 예정 기능

  1. UnifiedConfigPanel: 통합 설정 패널 (5탭)
  2. 테이블 드롭 자동 생성: 테이블 이름 드롭 → 전체 CRUD 화면 자동 생성
  3. steps 파이프라인 완전 구현: validate, api, transform, condition, loop, parallel, error 타입
  4. 고급 Reactive Binding: 복잡한 조건, 다중 타겟, 비동기 변환

참고 문서