ERP-node/docs/screen-implementation-guide/화면개발_표준_가이드.md

17 KiB

화면 개발 표준 가이드

목적: 어떤 개발자/AI가 화면을 개발하든 동일한 결과물이 나오도록 하는 표준 가이드 대상: 개발자, AI 에이전트 (Cursor 등) 버전: 1.0.0


1. 개요

이 문서는 WACE 솔루션에서 화면을 개발할 때 반드시 따라야 하는 표준입니다. 비즈니스 로직을 어떻게 설명하든, 최종 결과물은 이 가이드대로 생성되어야 합니다.

핵심 원칙

  1. V2 컴포넌트만 사용: v2- 접두사가 붙은 컴포넌트만 사용
  2. UI와 로직 분리: UI는 screen_layouts_v2, 비즈니스 로직은 dataflow_diagrams
  3. 멀티테넌시 필수: 모든 쿼리에 company_code 필터링

2. 사용 가능한 V2 컴포넌트 목록 (23개)

입력 컴포넌트

ID 이름 용도
v2-input 입력 텍스트, 숫자, 비밀번호, 이메일 등
v2-select 선택 드롭다운, 콤보박스, 라디오, 체크박스
v2-date 날짜 날짜, 시간, 날짜범위

표시 컴포넌트

ID 이름 용도
v2-text-display 텍스트 표시 라벨, 제목
v2-card-display 카드 디스플레이 테이블 데이터를 카드 형태로 표시
v2-aggregation-widget 집계 위젯 합계, 평균, 개수 등

테이블/데이터 컴포넌트

ID 이름 용도
v2-table-list 테이블 리스트 데이터 조회/편집 테이블
v2-table-search-widget 검색 필터 테이블 검색/필터
v2-pivot-grid 피벗 그리드 다차원 분석

레이아웃 컴포넌트

ID 이름 용도
v2-split-panel-layout 분할 패널 마스터-디테일 좌우 분할
v2-tabs-widget 탭 위젯 탭 전환
v2-section-card 섹션 카드 제목+테두리 그룹화
v2-section-paper 섹션 페이퍼 배경색 그룹화
v2-divider-line 구분선 영역 구분
v2-repeat-container 리피터 컨테이너 데이터 반복 렌더링
v2-repeater 리피터 반복 컨트롤
v2-repeat-screen-modal 반복 화면 모달 모달 반복

액션/특수 컴포넌트

ID 이름 용도
v2-button-primary 기본 버튼 저장, 삭제 등 액션
v2-numbering-rule 채번규칙 자동 코드 생성
v2-category-manager 카테고리 관리자 카테고리 관리
v2-location-swap-selector 위치 교환 위치 선택/교환
v2-rack-structure 랙 구조 창고 랙 시각화
v2-media 미디어 이미지/동영상 표시

3. 화면 패턴 (5가지)

패턴 A: 기본 마스터 화면

사용 조건: 단일 테이블 CRUD

컴포넌트 구성:

v2-table-search-widget (검색)
v2-table-list (테이블)
v2-button-primary (저장/삭제)

레이아웃:

┌─────────────────────────────────────────────────┐
│ [검색필드들] [조회] [엑셀]                       │ ← v2-table-search-widget
├─────────────────────────────────────────────────┤
│ 제목        [신규] [삭제]                        │
│ ─────────────────────────────────────────────── │
│ □ | 코드 | 이름 | 상태 | 등록일 |               │ ← v2-table-list
└─────────────────────────────────────────────────┘

패턴 B: 마스터-디테일 화면

사용 조건: 마스터 테이블 선택 → 디테일 테이블 표시

컴포넌트 구성:

v2-split-panel-layout (분할)
  ├─ 좌측: v2-table-list (마스터)
  └─ 우측: v2-table-list (디테일)

레이아웃:

┌──────────────────┬──────────────────────────────┐
│ 마스터 리스트    │ 디테일 리스트                │
│ ───────────────  │                              │
│ □ A001 항목1     │ [디테일 테이블]              │
│ □ A002 항목2 ←   │                              │
└──────────────────┴──────────────────────────────┘
        v2-split-panel-layout

필수 설정:

{
  "leftPanel": {
    "tableName": "마스터_테이블명"
  },
  "rightPanel": {
    "tableName": "디테일_테이블명",
    "relation": {
      "type": "detail",
      "foreignKey": "master_id"
    }
  },
  "splitRatio": 30
}

패턴 C: 마스터-디테일 + 탭

사용 조건: 마스터 선택 → 여러 탭으로 상세 정보 표시

컴포넌트 구성:

v2-split-panel-layout (분할)
  ├─ 좌측: v2-table-list (마스터)
  └─ 우측: v2-tabs-widget (탭)
           ├─ 탭1: v2-table-list
           ├─ 탭2: v2-table-list
           └─ 탭3: 폼 컴포넌트들

패턴 D: 카드 뷰

사용 조건: 이미지+정보 카드 형태 표시

컴포넌트 구성:

v2-table-search-widget (검색)
v2-card-display (카드)

필수 설정:

{
  "cardsPerRow": 3,
  "columnMapping": {
    "title": "name",
    "subtitle": "code",
    "image": "image_url",
    "status": "status"
  }
}

패턴 E: 피벗 분석

사용 조건: 다차원 집계/분석

컴포넌트 구성:

v2-pivot-grid (피벗)

필수 설정:

{
  "fields": [
    { "field": "region", "area": "row" },
    { "field": "year", "area": "column" },
    { "field": "amount", "area": "data", "summaryType": "sum" }
  ]
}

4. 데이터베이스 구조

화면 정의 테이블

-- screen_definitions: 화면 기본 정보
INSERT INTO screen_definitions (
  screen_id,
  screen_name,
  screen_code,
  description,
  table_name,
  company_code
) VALUES (...);

-- screen_layouts_v2: UI 레이아웃 (JSON)
INSERT INTO screen_layouts_v2 (
  screen_id,
  company_code,
  layout_data  -- JSON: 컴포넌트 배치 정보
) VALUES (...);

-- screen_menu_assignments: 메뉴 연결
INSERT INTO screen_menu_assignments (
  screen_id,
  menu_objid,
  company_code
) VALUES (...);

제어관리 테이블

-- dataflow_diagrams: 비즈니스 로직
INSERT INTO dataflow_diagrams (
  diagram_name,
  company_code,
  control,  -- JSON: 조건 설정
  plan      -- JSON: 실행 계획
) VALUES (...);

5. UI 설정 vs 비즈니스 로직 설정

UI 설정 (화면 디자이너에서 처리)

항목 저장 위치
컴포넌트 배치 screen_layouts_v2.layout_data
테이블명 layout_data 내 tableName
컬럼 표시/숨김 layout_data 내 columns
검색 필드 layout_data 내 searchFields
기본 저장/삭제 버튼 config.action.type

비즈니스 로직 (제어관리에서 처리)

항목 저장 위치
조건부 실행 dataflow_diagrams.control
다중 테이블 저장 dataflow_diagrams.plan
버튼 전/후 트리거 dataflow_diagrams.control.triggerType
필드 매핑 dataflow_diagrams.plan.mappings

6. 비즈니스 로직 설정 표준 형식

기본 구조

{
  "control": {
    "actionType": "update",
    "triggerType": "after",
    "conditions": [
      {
        "id": "조건ID",
        "type": "condition",
        "field": "status",
        "operator": "=",
        "value": "대기",
        "dataType": "string"
      }
    ]
  },
  "plan": {
    "mappings": [
      {
        "id": "매핑ID",
        "sourceField": "소스필드",
        "targetField": "타겟필드",
        "targetTable": "타겟테이블",
        "valueType": "field"
      }
    ]
  }
}

조건 연산자

연산자 설명
= 같음
!= 다름
>
< 작음
>= 크거나 같음
<= 작거나 같음
LIKE 포함
IN 목록에 포함
IS NULL NULL 값

액션 타입

타입 설명
insert 새 데이터 삽입
update 기존 데이터 수정
delete 데이터 삭제

트리거 타입

타입 설명
before 버튼 클릭 전 실행
after 버튼 클릭 후 실행

7. 화면 개발 순서

Step 1: 요구사항 분석

1. 어떤 테이블을 사용하는가?
2. 테이블 간 관계는? (FK)
3. 어떤 패턴인가? (A/B/C/D/E)
4. 어떤 버튼이 필요한가?
5. 각 버튼의 비즈니스 로직은?

Step 2: screen_definitions INSERT

INSERT INTO screen_definitions (
  screen_name,
  screen_code,
  description,
  table_name,
  company_code,
  created_at
) VALUES (
  '화면명',
  'SCREEN_CODE',
  '화면 설명',
  '메인테이블명',
  '회사코드',
  NOW()
) RETURNING screen_id;

Step 3: screen_layouts_v2 INSERT

INSERT INTO screen_layouts_v2 (
  screen_id,
  company_code,
  layout_data
) VALUES (
  위에서_받은_screen_id,
  '회사코드',
  '{"components": [...], "layout": {...}}'::jsonb
);

Step 4: dataflow_diagrams INSERT (비즈니스 로직 있는 경우)

INSERT INTO dataflow_diagrams (
  diagram_name,
  company_code,
  control,
  plan
) VALUES (
  '화면명_제어',
  '회사코드',
  '{"조건설정"}'::jsonb,
  '{"실행계획"}'::jsonb
);

Step 5: screen_menu_assignments INSERT

INSERT INTO screen_menu_assignments (
  screen_id,
  menu_objid,
  company_code
) VALUES (
  screen_id,
  메뉴ID,
  '회사코드'
);

8. 예시: 수주관리 화면

요구사항

화면명: 수주관리
패턴: B (마스터-디테일)
테이블:
  - 마스터: order_master
  - 디테일: order_detail
버튼:
  - [저장]: order_master에 저장
  - [확정]: 
    - 조건: status = '대기'
    - 동작: status를 '확정'으로 변경
    - 추가: order_history에 이력 저장

screen_definitions

INSERT INTO screen_definitions (
  screen_name, screen_code, description, table_name, company_code
) VALUES (
  '수주관리', 'ORDER_MNG', '수주를 관리하는 화면', 'order_master', 'COMPANY_A'
);

screen_layouts_v2 (layout_data)

{
  "components": [
    {
      "id": "search-1",
      "componentType": "v2-table-search-widget",
      "position": {"x": 0, "y": 0},
      "size": {"width": 1920, "height": 80}
    },
    {
      "id": "split-1",
      "componentType": "v2-split-panel-layout",
      "position": {"x": 0, "y": 80},
      "size": {"width": 1920, "height": 800},
      "componentConfig": {
        "leftPanel": {
          "tableName": "order_master"
        },
        "rightPanel": {
          "tableName": "order_detail",
          "relation": {
            "type": "detail",
            "foreignKey": "order_id"
          }
        },
        "splitRatio": 30
      }
    },
    {
      "id": "btn-save",
      "componentType": "v2-button-primary",
      "componentConfig": {
        "text": "저장",
        "action": {"type": "save"}
      }
    },
    {
      "id": "btn-confirm",
      "componentType": "v2-button-primary",
      "componentConfig": {
        "text": "확정",
        "enableDataflowControl": true,
        "dataflowDiagramId": 123
      }
    }
  ]
}

dataflow_diagrams (확정 버튼 로직)

{
  "control": {
    "actionType": "update",
    "triggerType": "after",
    "conditions": [
      {
        "id": "cond-1",
        "type": "condition",
        "field": "status",
        "operator": "=",
        "value": "대기",
        "dataType": "string"
      }
    ]
  },
  "plan": {
    "actions": [
      {
        "id": "action-1",
        "actionType": "update",
        "targetTable": "order_master",
        "fieldMappings": [
          {"targetField": "status", "defaultValue": "확정"}
        ]
      },
      {
        "id": "action-2",
        "actionType": "insert",
        "targetTable": "order_history",
        "fieldMappings": [
          {"sourceField": "order_no", "targetField": "order_no"},
          {"sourceField": "customer_name", "targetField": "customer_name"},
          {"defaultValue": "#NOW", "targetField": "confirmed_at"}
        ]
      }
    ]
  }
}

9. 지원하지 않는 UI (별도 개발 필요)

UI 유형 상태 대안
트리 뷰 미지원 테이블로 대체 or v2-tree-view 개발 필요
그룹화 테이블 미지원 일반 테이블로 대체 or v2-grouped-table 개발 필요
간트 차트 미지원 별도 개발 필요
드래그앤드롭 미지원 순서 컬럼으로 대체

10. 체크리스트

화면 생성 시

□ screen_definitions INSERT 완료
□ screen_layouts_v2 INSERT 완료
□ screen_menu_assignments INSERT 완료 (메뉴 연결 필요 시)
□ company_code 필터링 적용
□ 사용한 컴포넌트가 모두 v2- 접두사인지 확인

비즈니스 로직 설정 시

□ 기본 액션 (저장/삭제)만 → 화면 디자이너에서 설정
□ 조건부/다중테이블 → dataflow_diagrams INSERT
□ 버튼 config에 dataflowDiagramId 연결
□ control.conditions 설정
□ plan.actions 또는 plan.mappings 설정

11. 비즈니스 로직 요청 양식 (필수)

경고: 양식대로 안 쓰면 처리 안 함. 병신아 제대로 써. 대충 쓰면 대충 만들어지고, 안 쓰면 안 만들어줌.

11.1 양식 템플릿

=== 비즈니스 로직 요청서 ===

【화면 정보】
- 화면명: 
- 회사코드: 
- 메뉴ID (있으면): 

【테이블 정보】
- 메인 테이블: 
- 디테일 테이블 (있으면): 
- 관계 FK (있으면): 

【버튼 목록】
버튼1:
  - 버튼명: 
  - 동작 유형: (저장/삭제/수정/조회/기타)
  - 조건 (있으면): 
  - 대상 테이블: 
  - 추가 동작 (있으면): 

버튼2:
  - 버튼명: 
  - ...

【추가 요구사항】
- 

11.2 작성 예시 (올바른 예시)

=== 비즈니스 로직 요청서 ===

【화면 정보】
- 화면명: 수주관리
- 회사코드: ssalmeog
- 메뉴ID: 55566

【테이블 정보】
- 메인 테이블: order_master
- 디테일 테이블: order_detail
- 관계 FK: order_id

【버튼 목록】
버튼1:
  - 버튼명: 저장
  - 동작 유형: 저장
  - 조건: 없음
  - 대상 테이블: order_master, order_detail
  - 추가 동작: 없음

버튼2:
  - 버튼명: 확정
  - 동작 유형: 수정
  - 조건: status = '대기'
  - 대상 테이블: order_master
  - 추가 동작: 
    1. status를 '확정'으로 변경
    2. order_history에 이력 INSERT (order_no, customer_name, confirmed_at=현재시간)

버튼3:
  - 버튼명: 삭제
  - 동작 유형: 삭제
  - 조건: status != '확정'
  - 대상 테이블: order_master, order_detail (cascade)
  - 추가 동작: 없음

【추가 요구사항】
- 확정된 수주는 수정/삭제 불가
- 수주번호 자동채번 (ORDER-YYYYMMDD-0001)

11.3 잘못된 예시 (이렇게 쓰면 안 됨)

❌ "수주관리 화면 만들어줘"
   → 테이블이 뭔데? 버튼은? 로직은?

❌ "저장 버튼 누르면 저장해줘"
   → 어떤 테이블에? 조건은? 

❌ "확정하면 재고 처리해줘"
   → 어떤 테이블? 증가? 감소? 얼마나?

❌ "이전 화면이랑 비슷하게"
   → 이전 화면이 뭔데?

11.4 복잡한 로직 추가 양식

조건이 여러 개이거나 복잡한 경우:

【복잡한 버튼 로직】
버튼명: 출고확정

실행 조건:
  조건1: status = '출고대기' AND
  조건2: qty > 0 AND
  조건3: warehouse_id IS NOT NULL

실행 동작 (순서대로):
  1. shipment_master.status → '출고완료'
  2. inventory에서 qty만큼 감소 (WHERE item_code = 현재행.item_code)
  3. shipment_history에 INSERT:
     - shipment_no ← 현재행.shipment_no
     - shipped_qty ← 현재행.qty
     - shipped_at ← 현재시간
     - shipped_by ← 현재사용자

실패 시:
  - 재고 부족: "재고가 부족합니다" 메시지
  - 조건 불충족: "출고대기 상태만 확정 가능합니다" 메시지

12. 참고 경로

항목 경로/테이블
제어관리 페이지 /admin/systemMng/dataflow
화면 정의 테이블 screen_definitions
레이아웃 테이블 screen_layouts_v2
제어관리 테이블 dataflow_diagrams
메뉴 연결 테이블 screen_menu_assignments