ERP-node/docs/screen-implementation-guide/SCREEN_DEVELOPMENT_STANDARD.md

573 lines
13 KiB
Markdown
Raw Normal View History

# Screen Development Standard Guide (AI Agent Reference)
> **Purpose**: Ensure consistent screen development output regardless of who develops it
> **Target**: AI Agents (Cursor, etc.), Developers
> **Version**: 1.0.0
---
## CRITICAL RULES
1. **ONLY use V2 components** (components with `v2-` prefix)
2. **SEPARATE UI and Logic**: UI in `screen_layouts_v2`, Logic in `dataflow_diagrams`
3. **ALWAYS apply company_code filtering** (multi-tenancy)
---
## AVAILABLE V2 COMPONENTS (23 total)
### Input Components
| ID | Name | Purpose |
|----|------|---------|
| `v2-input` | Input | text, number, password, email, tel, url, textarea |
| `v2-select` | Select | dropdown, combobox, radio, checkbox |
| `v2-date` | Date | date, time, datetime, daterange, month, year |
### Display Components
| ID | Name | Purpose |
|----|------|---------|
| `v2-text-display` | Text Display | labels, titles |
| `v2-card-display` | Card Display | table data as cards |
| `v2-aggregation-widget` | Aggregation Widget | sum, avg, count, min, max |
### Table/Data Components
| ID | Name | Purpose |
|----|------|---------|
| `v2-table-list` | Table List | data grid with CRUD |
| `v2-table-search-widget` | Search Widget | table search/filter |
| `v2-pivot-grid` | Pivot Grid | multi-dimensional analysis |
### Layout Components
| ID | Name | Purpose |
|----|------|---------|
| `v2-split-panel-layout` | Split Panel | master-detail layout |
| `v2-tabs-widget` | Tabs Widget | tab navigation |
| `v2-section-card` | Section Card | titled grouping container |
| `v2-section-paper` | Section Paper | background grouping |
| `v2-divider-line` | Divider | area separator |
| `v2-repeat-container` | Repeat Container | data-driven repeat |
| `v2-repeater` | Repeater | repeat control |
| `v2-repeat-screen-modal` | Repeat Screen Modal | modal repeat |
### Action/Special Components
| ID | Name | Purpose |
|----|------|---------|
| `v2-button-primary` | Primary Button | save, delete, etc. |
| `v2-numbering-rule` | Numbering Rule | auto code generation |
| `v2-category-manager` | Category Manager | category management |
| `v2-location-swap-selector` | Location Swap | location selection |
| `v2-rack-structure` | Rack Structure | warehouse rack visualization |
| `v2-media` | Media | image/video display |
---
## SCREEN PATTERNS (5 types)
### Pattern A: Basic Master Screen
**When**: Single table CRUD
**Components**:
```
v2-table-search-widget
v2-table-list
v2-button-primary
```
### Pattern B: Master-Detail Screen
**When**: Master selection → Detail display
**Components**:
```
v2-split-panel-layout
├─ left: v2-table-list (master)
└─ right: v2-table-list (detail)
```
**Required Config**:
```json
{
"leftPanel": { "tableName": "master_table" },
"rightPanel": {
"tableName": "detail_table",
"relation": { "type": "detail", "foreignKey": "master_id" }
},
"splitRatio": 30
}
```
### Pattern C: Master-Detail + Tabs
**When**: Master selection → Multiple tabs
**Components**:
```
v2-split-panel-layout
├─ left: v2-table-list (master)
└─ right: v2-tabs-widget
```
### Pattern D: Card View
**When**: Image + info card display
**Components**:
```
v2-table-search-widget
v2-card-display
```
**Required Config**:
```json
{
"cardsPerRow": 3,
"columnMapping": {
"title": "name",
"subtitle": "code",
"image": "image_url"
}
}
```
### Pattern E: Pivot Analysis
**When**: Multi-dimensional aggregation
**Components**:
```
v2-pivot-grid
```
---
## DATABASE TABLES
### Screen Definition
```sql
-- screen_definitions: Screen basic info
INSERT INTO screen_definitions (
screen_name, screen_code, description, table_name, company_code
) VALUES (...) RETURNING screen_id;
-- screen_layouts_v2: UI layout (JSON)
INSERT INTO screen_layouts_v2 (
screen_id, company_code, layout_data
) VALUES (...);
-- screen_menu_assignments: Menu connection
INSERT INTO screen_menu_assignments (
screen_id, menu_objid, company_code
) VALUES (...);
```
### Control Management (Business Logic)
```sql
-- dataflow_diagrams: Business logic
INSERT INTO dataflow_diagrams (
diagram_name, company_code, control, plan
) VALUES (...);
```
---
## UI SETTING vs BUSINESS LOGIC
### UI Setting (Screen Designer)
| Item | Storage |
|------|---------|
| Component placement | screen_layouts_v2.layout_data |
| Table name | layout_data.tableName |
| Column visibility | layout_data.columns |
| Search fields | layout_data.searchFields |
| Basic save/delete | button config.action.type |
### Business Logic (Control Management)
| Item | Storage |
|------|---------|
| Conditional execution | dataflow_diagrams.control |
| Multi-table save | dataflow_diagrams.plan |
| Before/after trigger | control.triggerType |
| Field mapping | plan.mappings |
---
## BUSINESS LOGIC JSON STRUCTURE
### Control (Conditions)
```json
{
"control": {
"actionType": "update|insert|delete",
"triggerType": "before|after",
"conditions": [
{
"id": "unique-id",
"type": "condition",
"field": "column_name",
"operator": "=|!=|>|<|>=|<=|LIKE|IN|IS NULL",
"value": "compare_value",
"dataType": "string|number|date|boolean"
}
]
}
}
```
### Plan (Actions)
```json
{
"plan": {
"actions": [
{
"id": "action-id",
"actionType": "update|insert|delete",
"targetTable": "table_name",
"fieldMappings": [
{
"sourceField": "source_column",
"targetField": "target_column",
"defaultValue": "static_value",
"valueType": "field|static"
}
]
}
]
}
}
```
### Special Values
| Value | Meaning |
|-------|---------|
| `#NOW` | Current timestamp |
| `#USER` | Current user ID |
| `#COMPANY` | Current company code |
---
## DEVELOPMENT STEPS
### Step 1: Analyze Requirements
```
1. Which tables? (table names)
2. Table relationships? (FK)
3. Which pattern? (A/B/C/D/E)
4. Which buttons?
5. Business logic per button?
```
### Step 2: INSERT screen_definitions
```sql
INSERT INTO screen_definitions (
screen_name, screen_code, description, table_name, company_code, created_at
) VALUES (
'화면명', 'SCREEN_CODE', '설명', 'main_table', 'COMPANY_CODE', NOW()
) RETURNING screen_id;
```
### Step 3: INSERT screen_layouts_v2
```sql
INSERT INTO screen_layouts_v2 (
screen_id, company_code, layout_data
) VALUES (
{screen_id}, 'COMPANY_CODE', '{layout_json}'::jsonb
);
```
### Step 4: INSERT dataflow_diagrams (if complex logic)
```sql
INSERT INTO dataflow_diagrams (
diagram_name, company_code, control, plan
) VALUES (
'화면명_제어', 'COMPANY_CODE', '{control_json}'::jsonb, '{plan_json}'::jsonb
) RETURNING diagram_id;
```
### Step 5: Link button to dataflow
In layout_data, set button config:
```json
{
"id": "btn-action",
"componentType": "v2-button-primary",
"componentConfig": {
"text": "확정",
"enableDataflowControl": true,
"dataflowDiagramId": {diagram_id}
}
}
```
### Step 6: INSERT screen_menu_assignments
```sql
INSERT INTO screen_menu_assignments (
screen_id, menu_objid, company_code
) VALUES (
{screen_id}, {menu_objid}, 'COMPANY_CODE'
);
```
---
## EXAMPLE: Order Management
### Requirements
```
Screen: 수주관리 (Order Management)
Pattern: B (Master-Detail)
Tables:
- Master: order_master
- Detail: order_detail
Buttons:
- [저장]: Save to order_master
- [확정]:
- Condition: status = '대기'
- Action: Update status to '확정'
- Additional: Insert to order_history
```
### layout_data JSON
```json
{
"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 JSON (for 확정 button)
```json
{
"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"}
]
}
]
}
}
```
---
## NOT SUPPORTED (Requires Custom Development)
| UI Type | Status | Alternative |
|---------|--------|-------------|
| Tree View | ❌ | Develop `v2-tree-view` |
| Grouped Table | ❌ | Develop `v2-grouped-table` |
| Gantt Chart | ❌ | Separate development |
| Drag & Drop | ❌ | Use order column |
---
## CHECKLIST
### Screen Creation
```
□ screen_definitions INSERT completed
□ screen_layouts_v2 INSERT completed
□ screen_menu_assignments INSERT completed (if needed)
□ company_code filtering applied
□ All components have v2- prefix
```
### Business Logic
```
□ Basic actions (save/delete) → Screen designer setting
□ Conditional/Multi-table → dataflow_diagrams INSERT
□ Button config has dataflowDiagramId
□ control.conditions configured
□ plan.actions or plan.mappings configured
```
---
## BUSINESS LOGIC REQUEST FORMAT (MANDATORY)
> **WARNING**: No format = No processing. Write it properly, idiot.
> Vague input = vague output. No input = no output.
### Request Template
```
=== BUSINESS LOGIC REQUEST ===
【SCREEN INFO】
- Screen Name:
- Company Code:
- Menu ID (if any):
【TABLE INFO】
- Main Table:
- Detail Table (if any):
- FK Relation (if any):
【BUTTON LIST】
Button 1:
- Name:
- Action Type: (save/delete/update/query/other)
- Condition (if any):
- Target Table:
- Additional Actions (if any):
Button 2:
- Name:
- ...
【ADDITIONAL REQUIREMENTS】
-
```
### Valid Example
```
=== BUSINESS LOGIC REQUEST ===
【SCREEN INFO】
- Screen Name: 수주관리 (Order Management)
- Company Code: ssalmeog
- Menu ID: 55566
【TABLE INFO】
- Main Table: order_master
- Detail Table: order_detail
- FK Relation: order_id
【BUTTON LIST】
Button 1:
- Name: 저장 (Save)
- Action Type: save
- Condition: none
- Target Table: order_master, order_detail
- Additional Actions: none
Button 2:
- Name: 확정 (Confirm)
- Action Type: update
- Condition: status = '대기'
- Target Table: order_master
- Additional Actions:
1. Change status to '확정'
2. INSERT to order_history (order_no, customer_name, confirmed_at=NOW)
Button 3:
- Name: 삭제 (Delete)
- Action Type: delete
- Condition: status != '확정'
- Target Table: order_master, order_detail (cascade)
- Additional Actions: none
【ADDITIONAL REQUIREMENTS】
- Confirmed orders cannot be modified/deleted
- Auto-numbering for order_no (ORDER-YYYYMMDD-0001)
```
### Invalid Examples (DO NOT DO THIS)
```
❌ "Make an order management screen"
→ Which table? Buttons? Logic?
❌ "Save button should save"
→ To which table? Conditions?
❌ "Handle inventory when confirmed"
→ Which table? Increase? Decrease? By how much?
❌ "Similar to the previous screen"
→ What previous screen?
```
### Complex Logic Format
For multiple conditions or complex workflows:
```
【COMPLEX BUTTON LOGIC】
Button Name: 출고확정 (Shipment Confirm)
Execution Conditions:
Cond1: status = '출고대기' AND
Cond2: qty > 0 AND
Cond3: warehouse_id IS NOT NULL
Execution Steps (in order):
1. shipment_master.status → '출고완료'
2. Decrease qty in inventory (WHERE item_code = current_row.item_code)
3. INSERT to shipment_history:
- shipment_no ← current_row.shipment_no
- shipped_qty ← current_row.qty
- shipped_at ← #NOW
- shipped_by ← #USER
On Failure:
- Insufficient stock: Show "재고가 부족합니다"
- Condition not met: Show "출고대기 상태만 확정 가능합니다"
```
---
## REFERENCE PATHS
| Item | Path/Table |
|------|------------|
| Control Management Page | `/admin/systemMng/dataflow` |
| Screen Definition Table | `screen_definitions` |
| Layout Table | `screen_layouts_v2` |
| Control Table | `dataflow_diagrams` |
| Menu Assignment Table | `screen_menu_assignments` |