288 lines
13 KiB
Markdown
288 lines
13 KiB
Markdown
# WACE ERP 파이프라인 공통 룰 (모든 에이전트 필수 준수)
|
|
|
|
---
|
|
|
|
# !!!! STOP - 작업 시작 전 필수 게이트 (이것을 건너뛰면 모든 작업이 REJECT 된다) !!!!
|
|
|
|
## PRE-CHECK GATE: 파일 생성/수정 전 반드시 확인
|
|
|
|
**어떤 에이전트든 파일을 생성하거나 수정하기 전에 반드시 이 게이트를 통과해야 한다.**
|
|
**이 게이트를 건너뛰거나 무시한 작업은 전부 REJECT + ROLLBACK 대상이다.**
|
|
|
|
### GATE 1: 이 파일을 만들어도 되는가?
|
|
|
|
아래 경로에 `.tsx` 페이지 파일을 **절대 생성하지 마라**:
|
|
```
|
|
frontend/app/(main)/production/** ← 금지! 사용자 메뉴!
|
|
frontend/app/(main)/warehouse/** ← 금지! 사용자 메뉴!
|
|
frontend/app/(main)/quality/** ← 금지! 사용자 메뉴!
|
|
frontend/app/(main)/logistics/** ← 금지! 사용자 메뉴!
|
|
frontend/app/(main)/inventory/** ← 금지! 사용자 메뉴!
|
|
frontend/app/(main)/purchase/** ← 금지! 사용자 메뉴!
|
|
frontend/app/(main)/sales/** ← 금지! 사용자 메뉴!
|
|
frontend/app/(main)/bom/** ← 금지! 사용자 메뉴!
|
|
frontend/app/(main)/mold/** ← 금지! 사용자 메뉴!
|
|
frontend/app/(main)/packaging/** ← 금지! 사용자 메뉴!
|
|
frontend/app/(main)/document/** ← 금지! 사용자 메뉴!
|
|
frontend/app/(main)/work/** ← 금지! 사용자 메뉴!
|
|
frontend/app/(main)/order/** ← 금지! 사용자 메뉴!
|
|
frontend/app/(main)/material/** ← 금지! 사용자 메뉴!
|
|
frontend/app/(main)/equipment/** ← 금지! 사용자 메뉴!
|
|
frontend/app/(main)/inspection/** ← 금지! 사용자 메뉴!
|
|
```
|
|
|
|
**유일하게 React 페이지(.tsx)를 만들 수 있는 경로:**
|
|
```
|
|
frontend/app/(main)/admin/** ← 허용! 관리자 메뉴만!
|
|
```
|
|
|
|
**판단 로직 (의사코드):**
|
|
```
|
|
IF 생성하려는 파일 경로가 "frontend/app/(main)/admin/" 하위가 아니다
|
|
AND 파일이 page.tsx 또는 layout.tsx 또는 React 컴포넌트다
|
|
THEN
|
|
!!!! 즉시 중단 !!!!
|
|
→ 이것은 사용자 메뉴다
|
|
→ React 페이지를 만들면 안 된다
|
|
→ DB 등록 방식(screen_definitions + screen_layouts_v2 + menu_info)으로 전환하라
|
|
→ pipeline-common-rules.md의 "사용자 메뉴 구현 방법" 섹션을 따르라
|
|
END IF
|
|
```
|
|
|
|
### GATE 2: 사용자 메뉴인데 코드로 만들려고 하는가?
|
|
|
|
아래 키워드가 요구사항에 포함되어 있으면 **사용자 메뉴**일 가능성이 높다:
|
|
- 포장, 적재, 금형, BOM, 입출고, 품질, 검사, 재고, 자재, 문서, 생산, 작업, 설비
|
|
- "목록 + 상세" 구조, "좌측 테이블 + 우측 폼" 구조
|
|
- 일반 업무 화면, CRUD 화면
|
|
|
|
**사용자 메뉴라면:**
|
|
- .tsx 페이지 파일 생성 → 금지
|
|
- screen_definitions + screen_layouts_v2 + menu_info INSERT → 올바른 방법
|
|
- 백엔드 API(controller/routes)는 필요하면 코드로 작성 가능
|
|
- 프론트엔드 API 클라이언트(lib/api/)도 필요하면 코드로 작성 가능
|
|
- 하지만 **프론트엔드 화면 UI 자체**는 절대 코드로 만들지 않는다!
|
|
|
|
### GATE 3: 관리자 메뉴가 맞는가?
|
|
|
|
관리자 메뉴는 다음 조건을 **전부** 만족해야 한다:
|
|
- 시스템 관리자만 사용하는 기능 (사용자 관리, 권한 관리, 시스템 설정 등)
|
|
- URL이 `/admin/*` 패턴
|
|
- `frontend/app/(main)/admin/` 하위에만 page.tsx 생성
|
|
|
|
**이 3가지 게이트를 모두 통과한 후에만 작업을 시작하라.**
|
|
|
|
---
|
|
|
|
## 1. 화면 유형 구분 (절대 규칙!)
|
|
|
|
이 시스템은 **관리자 메뉴**와 **사용자 메뉴**가 완전히 다른 방식으로 동작한다.
|
|
기능 구현 시 반드시 어느 유형인지 먼저 판단하라.
|
|
|
|
### 관리자 메뉴 (Admin)
|
|
- **구현 방식**: React 코드 기반 페이지 (`.tsx` 파일)
|
|
- **경로**: `frontend/app/(main)/admin/{기능명}/page.tsx` **이 경로만 허용!**
|
|
- **메뉴 등록**: `menu_info` 테이블에 INSERT 필수 (코드만 만들고 메뉴 등록 안 하면 미완성!)
|
|
- **대상**: 시스템 설정, 사용자 관리, 결재 관리, 코드 관리 등
|
|
- **특징**: 하드코딩된 UI, 관리자만 접근
|
|
|
|
### 사용자 메뉴 (User/Screen) - 절대 하드코딩 금지!!!
|
|
- **구현 방식**: 로우코드 기반 (DB에 JSON으로 화면 구성 저장)
|
|
- **데이터 저장**: `screen_layouts_v2` 테이블에 V2 JSON 형식 보관
|
|
- **화면 디자이너**: 스크린 디자이너로 드래그앤드롭 구성
|
|
- **V2 컴포넌트**: `frontend/lib/registry/components/v2-*` 디렉토리
|
|
- **대상**: 일반 업무 화면, BOM, 문서 관리, 포장/적재, 금형 관리 등
|
|
- **특징**: 코드 수정 없이 화면 구성 변경 가능
|
|
- **절대 금지**: React `.tsx` 페이지 파일로 직접 UI를 하드코딩하는 것!
|
|
- **위반 시**: 해당 작업 전체 REJECT + 파일 삭제 + 처음부터 DB 등록 방식으로 재작업
|
|
|
|
### 판단 기준
|
|
|
|
| 질문 | 관리자 메뉴 | 사용자 메뉴 |
|
|
|------|-------------|-------------|
|
|
| 누가 쓰나? | 시스템 관리자 | 일반 사용자 |
|
|
| 화면 구조 고정? | 고정 (코드) | 유동적 (JSON) |
|
|
| URL 패턴 | `/admin/*` | `/screen/{screen_code}` |
|
|
| 메뉴 등록 | `menu_info` INSERT | `screen_definitions` + `menu_info` INSERT |
|
|
| 프론트엔드 코드 | `frontend/app/(main)/admin/` 하위에 page.tsx 작성 | **코드 작성 금지!** DB에 스크린 정의만 등록 |
|
|
|
|
### 사용자 메뉴 구현 방법 (반드시 이 방식으로!)
|
|
|
|
**절대 규칙: 사용자 메뉴는 React 페이지(.tsx)를 직접 만들지 않는다!**
|
|
이미 `/screen/[screenCode]/page.tsx` → `/screens/[screenId]/page.tsx` 렌더링 시스템이 존재한다.
|
|
새 화면이 필요하면 DB에 등록만 하면 자동으로 렌더링된다.
|
|
|
|
#### Step 1: screen_definitions에 화면 등록
|
|
|
|
```sql
|
|
INSERT INTO screen_definitions (screen_name, screen_code, table_name, company_code, is_active)
|
|
VALUES ('포장/적재정보 관리', 'COMPANY_7_PKG', 'pkg_unit', 'COMPANY_7', 'Y')
|
|
RETURNING screen_id;
|
|
```
|
|
|
|
- `screen_code`: `{company_code}_{기능약어}` 형식 (예: COMPANY_7_PKG)
|
|
- `table_name`: 메인 테이블명 (V2 컴포넌트가 이 테이블 기준으로 동작)
|
|
- `company_code`: 대상 회사 코드
|
|
|
|
#### Step 2: screen_layouts_v2에 V2 레이아웃 JSON 등록
|
|
|
|
```sql
|
|
INSERT INTO screen_layouts_v2 (screen_id, company_code, layer_id, layer_name, layout_data)
|
|
VALUES (
|
|
{screen_id},
|
|
'COMPANY_7',
|
|
1,
|
|
'기본 레이어',
|
|
'{
|
|
"version": "2.0",
|
|
"components": [
|
|
{
|
|
"id": "comp_split_1",
|
|
"url": "@/lib/registry/components/v2-split-panel-layout",
|
|
"position": {"x": 0, "y": 0},
|
|
"size": {"width": 1200, "height": 800},
|
|
"displayOrder": 0,
|
|
"overrides": {
|
|
"leftTitle": "포장단위 목록",
|
|
"rightTitle": "상세 정보",
|
|
"splitRatio": 40,
|
|
"leftTableName": "pkg_unit",
|
|
"rightTableName": "pkg_unit",
|
|
"tabs": [
|
|
{"id": "basic", "label": "기본정보"},
|
|
{"id": "items", "label": "매칭품목"}
|
|
]
|
|
}
|
|
}
|
|
]
|
|
}'::jsonb
|
|
);
|
|
```
|
|
|
|
- V2 컴포넌트 목록: v2-split-panel-layout, v2-table-list, v2-table-search-widget, v2-repeater, v2-button-primary, v2-tabs-widget 등
|
|
- 상세 컴포넌트 가이드: `.cursor/rules/component-development-guide.mdc` 참조
|
|
|
|
#### Step 3: menu_info에 메뉴 등록
|
|
|
|
```sql
|
|
-- 먼저 부모 메뉴 objid 조회
|
|
-- SELECT objid, menu_name_kor FROM menu_info WHERE company_code = '{회사코드}' AND menu_name_kor LIKE '%물류%';
|
|
|
|
INSERT INTO menu_info (objid, menu_type, parent_obj_id, menu_name_kor, seq, menu_url, screen_code, company_code, status)
|
|
VALUES (
|
|
(SELECT COALESCE(MAX(objid), 0) + 1 FROM menu_info),
|
|
2, -- 2 = 메뉴 항목
|
|
{부모_objid}, -- 상위 메뉴의 objid
|
|
'포장/적재정보',
|
|
10, -- 정렬 순서
|
|
'/screen/COMPANY_7_PKG', -- /screen/{screen_code} 형식 (절대!)
|
|
'COMPANY_7_PKG', -- screen_definitions.screen_code와 일치
|
|
'COMPANY_7',
|
|
'Y'
|
|
);
|
|
```
|
|
|
|
**핵심**: `menu_url`은 반드시 `/screen/{screen_code}` 형식이어야 한다!
|
|
프론트엔드가 이 URL을 받아 `screen_definitions`에서 screen_id를 찾고, `screen_layouts_v2`에서 레이아웃을 로드한다.
|
|
|
|
## 2. 관리자 메뉴 등록 (코드 구현 후 필수!)
|
|
|
|
관리자 기능을 코드로 만들었으면 반드시 `menu_info`에 등록해야 한다.
|
|
|
|
```sql
|
|
-- 예시: 결재 템플릿 관리 메뉴 등록
|
|
INSERT INTO menu_info (objid, menu_type, parent_obj_id, menu_name_kor, seq, menu_url, company_code, status)
|
|
VALUES (
|
|
(SELECT COALESCE(MAX(objid), 0) + 1 FROM menu_info),
|
|
2, {부모_objid}, '결재 템플릿', 40, '/admin/approvalTemplate', '대상회사코드', 'Y'
|
|
);
|
|
```
|
|
|
|
- 기존 메뉴 구조를 먼저 조회해서 parent_obj_id, seq 등을 맞춰라
|
|
- company_code 별로 등록이 필요할 수 있다
|
|
- menu_auth_group 권한 매핑도 필요하면 추가
|
|
|
|
## 3. 하드코딩 금지 / 범용성 필수
|
|
|
|
- 특정 회사에만 동작하는 코드 금지
|
|
- 특정 사용자 ID에 의존하는 로직 금지
|
|
- 매직 넘버 사용 금지 (상수 또는 설정 파일로 관리)
|
|
- 하드코딩 색상 금지 (CSS 변수 사용: bg-primary, text-destructive 등)
|
|
- 하드코딩 URL 금지 (환경 변수 또는 API 클라이언트 사용)
|
|
|
|
## 4. 테스트 환경 정보
|
|
|
|
- **테스트 계정**: userId=`wace`, password=`qlalfqjsgh11`
|
|
- **역할**: SUPER_ADMIN (company_code = "*")
|
|
- **개발 프론트엔드**: http://localhost:9771
|
|
- **개발 백엔드 API**: http://localhost:8080
|
|
- **개발 DB**: postgresql://postgres:ph0909!!@39.117.244.52:11132/plm
|
|
|
|
## 5. 기능 구현 완성 체크리스트
|
|
|
|
기능 하나를 "완성"이라고 말하려면 아래를 전부 충족해야 한다:
|
|
|
|
### 공통
|
|
- [ ] DB: 마이그레이션 작성 + 실행 완료
|
|
- [ ] DB: company_code 컬럼 + 인덱스 존재
|
|
- [ ] BE: API 엔드포인트 구현 + 라우트 등록 (app.ts에 import + use 추가!)
|
|
- [ ] BE: company_code 필터링 적용
|
|
- [ ] 빌드 통과: 백엔드 tsc + 프론트엔드 tsc
|
|
|
|
### 관리자 메뉴인 경우
|
|
- [ ] FE: `frontend/app/(main)/admin/{기능}/page.tsx` 작성
|
|
- [ ] FE: API 클라이언트 함수 작성 (lib/api/)
|
|
- [ ] DB: `menu_info` INSERT (menu_url = `/admin/{기능}`)
|
|
|
|
### 사용자 메뉴인 경우 (코드 작성 금지!)
|
|
- [ ] DB: `screen_definitions` INSERT (screen_code, table_name, company_code)
|
|
- [ ] DB: `screen_layouts_v2` INSERT (V2 레이아웃 JSON)
|
|
- [ ] DB: `menu_info` INSERT (menu_url = `/screen/{screen_code}`)
|
|
- [ ] BE: 필요한 경우 전용 API 작성 (범용 table-management API로 커버 안 되는 경우만)
|
|
- [ ] FE: .tsx 페이지 파일 만들지 않음 (이미 `/screens/[screenId]/page.tsx`가 렌더링)
|
|
|
|
## 6. 절대 하지 말 것 (위반 시 전체 작업 REJECT)
|
|
|
|
1. 페이지 파일만 만들고 메뉴 등록 안 하기 (미완성!)
|
|
2. fetch() 직접 사용 (lib/api/ 클라이언트 필수)
|
|
3. company_code 필터링 빠뜨리기
|
|
4. 하드코딩 색상/URL/사용자ID 사용
|
|
5. Card 안에 Card 중첩 (중첩 박스 금지)
|
|
6. 백엔드 재실행하기 (nodemon이 자동 재시작)
|
|
7. **[최우선 금지] 사용자 메뉴를 React 하드코딩(.tsx)으로 만들기**
|
|
- `frontend/app/(main)/` 하위에서 `/admin/` 이외의 경로에 page.tsx를 만드는 것은 절대 금지
|
|
- 구체적 금지 경로: production/, warehouse/, quality/, logistics/, inventory/, purchase/, sales/, bom/, mold/, packaging/, document/, work/, order/, material/, equipment/, inspection/ 및 기타 모든 비-admin 경로
|
|
- 사용자 메뉴는 반드시 `screen_definitions` + `screen_layouts_v2` + `menu_info` DB 등록 방식으로 구현
|
|
- 이미 `/screen/[screenCode]` → `/screens/[screenId]` 렌더링 시스템이 존재함
|
|
- 백엔드 API(controller/routes)와 프론트엔드 API 클라이언트(lib/api/)는 필요하면 코드로 작성 가능
|
|
- 하지만 프론트엔드 화면 UI 자체는 DB의 V2 레이아웃 JSON으로만 구성
|
|
- **위반 발견 시: 해당 라운드 전체 FAIL 처리, 생성된 파일 즉시 삭제, DB 등록 방식으로 처음부터 재작업**
|
|
|
|
## 7. 위반 사례 및 올바른 대응
|
|
|
|
### 위반 사례 (실제 발생한 문제)
|
|
```
|
|
# 이런 파일을 만들면 절대 안 된다!
|
|
frontend/app/(main)/production/packaging/page.tsx ← REJECT!
|
|
frontend/app/(main)/warehouse/inventory/page.tsx ← REJECT!
|
|
frontend/app/(main)/quality/inspection/page.tsx ← REJECT!
|
|
frontend/app/(main)/mold/management/page.tsx ← REJECT!
|
|
```
|
|
|
|
### 올바른 대응
|
|
```sql
|
|
-- 1. screen_definitions에 등록
|
|
INSERT INTO screen_definitions (screen_name, screen_code, table_name, company_code, is_active)
|
|
VALUES ('포장관리', 'COMPANY_7_PKG', 'pkg_unit', 'COMPANY_7', 'Y');
|
|
|
|
-- 2. screen_layouts_v2에 V2 레이아웃 JSON 등록
|
|
INSERT INTO screen_layouts_v2 (screen_id, company_code, layer_id, layer_name, layout_data)
|
|
VALUES ({screen_id}, 'COMPANY_7', 1, '기본 레이어', '{...V2 JSON...}'::jsonb);
|
|
|
|
-- 3. menu_info에 메뉴 등록
|
|
INSERT INTO menu_info (..., menu_url, screen_code, ...)
|
|
VALUES (..., '/screen/COMPANY_7_PKG', 'COMPANY_7_PKG', ...);
|
|
```
|
|
|
|
**React 페이지(.tsx) 파일은 단 한 줄도 만들지 않는다. DB INSERT만으로 화면이 완성된다.**
|