573 lines
13 KiB
Markdown
573 lines
13 KiB
Markdown
|
|
# 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` |
|