# ð¯ ë
žë êž°ë° ë°ìŽí° ì ìŽ ìì€í
ê°ì ê³í
## ð 묞ì ì 볎
- **ìì±ìŒ**: 2025-10-02
- **ìµì¢
ìì ìŒ**: 2025-10-02
- **ë²ì **: 1.5
- **ìí**: ð Phase 1 ìë£! (100%)
- **ëŽë¹**: ê°ë°í
## ð 구í ì§í ìí©
### â
ìë£ë ìì
(Phase 1)
#### Week 1 - ìë£ â
- â
React Flow 11.10.4 íµí© ë° êž°ë³ž ì€ì
- â
ëŒìŽëžë¬ëЬ ì€ì¹ ë° ì€ì
- â
Ʞ볞 ìºë²ì€ 구í
- â
귞늬ë 배겜 ë° ì€/í¬ êž°ë¥
- â
Ʞ볞 ë
žë íì
구í (3ê°/3ê°)
- â
í
ìŽëž ìì€ ë
žë (TableSourceNode)
- â
INSERT ì¡ì
ë
žë (InsertActionNode)
- â
íë ë§€í ë
žë (FieldMappingNode)
- â
íµì¬ ìžíëŒ
- â
TypeScript íì
ì ì ìë£ (types/node-editor.ts)
- â
Zustand ìí êŽëЬ ì€í ìŽ (flowEditorStore.ts)
- â
ë
žë íë íž ì€ì (nodePaletteConfig.ts)
#### Week 2 - ìë£ â
- â
ëëê·ž ì€ ëë¡ êž°ë¥
- â
ë구 íšëìì ìºë²ì€ë¡ ëëê·ž
- â
ë
žë ìŽë ë° ì¬ë°°ì¹
- â
ë€ì€ ì í ë° ê·žë£¹ ìŽë
- â
ì°ê²°ì 귞늬Ʞ
- â
Ʞ볞 ì°ê²° ìì±
- â
ì°ê²° ê²ìŠ (íì
ížíì±, ìí ì°žì¡°, ì€ë³µ ì°ê²°)
- â
ì°ê²° ì€íìŒë§ (smoothstep)
- â
ì¶ê° ë
žë íì
구í (4ê° ìë£)
- â
조걎 ë¶êž° ë
žë (ConditionNode) - TRUE/FALSE 2ê° ì¶ë ¥
- â
ìžë¶ DB ìì€ ë
žë (ExternalDBSourceNode) - DB íì
ë³ ìì
- â
UPDATE ì¡ì
ë
žë (UpdateActionNode) - WHERE 조걎 í¬íš
- â
DELETE ì¡ì
ë
žë (DeleteActionNode) - ê²œê³ ë©ìì§
**ë§ìŒì€í€ 1 ìë£**: 7ê° ë
žë íì
구í ìë£ (58%)
#### Week 3 - ìë£ â
- â
ìì± ížì§ êž°ë¥ (ìë£)
- â
ë
žë ì í ìŽë²€íž ížë€ë¬ (onSelectionChange)
- â
ìì± íšë íë ììí¬ (PropertiesPanel)
- â
ë
žë íì
ë³ ìì± ëŒì°í
- â
7ê° ë
žë ìì± ížì§ UI ìì±
- â
TableSource: í
ìŽëžëª
, ì€í€ë§, ì¶ë ¥ íë
- â
InsertAction: íë ë§€í, ë°°ì¹ í¬êž°, ìµì
- â
FieldMapping: ìì€âíê² ë§€í, ë³í íšì
- â
Condition: 12ê°ì§ ì°ì°ì, AND/OR ë¡ì§
- â
UpdateAction: WHERE 조걎, ì
ë°ìŽíž íë
- â
DeleteAction: WHERE 조걎, ìí ê²œê³ UI
- â
ExternalDBSource: DB íì
ë³ ìì, ì°ê²° ì 볎
**ë§ìŒì€í€ 2 ìë£**: ìì± ížì§ êž°ë¥ 100% ìë£ (7/7 ë
žë)
#### Week 4 - ìë£ â
- â
ì ì¥/ë¶ë¬ì€êž° êž°ë¥ (ìë£)
- â
íë¡ì° ì ì¥ API (ì ê·/ìì )
- â
íë¡ì° ëª©ë¡ ì¡°í API
- â
íë¡ì° ììž ì¡°í API
- â
íë¡ì° ìì API
- â
JSON ì§ë ¬í/ìì§ë ¬í
- â
ë¶ë¬ì€êž° ë€ìŽìŒë¡ê·ž UI
- â
JSON íìŒ ëŽë³ŽëŽêž°
- â
node_flows í
ìŽëž ìì±
- â
API íŽëŒìŽìžíž íµí©
- â
JSONB íì
ì²ëЬ (묞ììŽ/ê°ì²Ž ìë ë³í)
- â
**ì€ì ì ì¥/ë¶ë¬ì€êž° ëì ê²ìŠ ìë£**
**ë§ìŒì€í€ 3 ìë£**: ì ì¥/ë¶ë¬ì€êž° 100% ìë£ ë° ê²ìŠ
## ð Phase 1 & Phase 2 ìë£!
몚ë íµì¬ êž°ë¥ìŽ êµ¬í ë° í
ì€íž ìë£ëììµëë€:
**Phase 1 (ìë£)**
- â
7ê° ë
žë íì
구í
- â
7ê° ìì± ížì§ UI
- â
ì ì¥/ë¶ë¬ì€êž° ìì€í
(DB + JSON)
- â
ê²ìŠ ìì€í
- â
ëëê·žì€ëë¡ ìëí°
- â
**ì€ì ì ì¥/ë¶ë¬ì€êž° í
ì€íž ìë£**
**Phase 2 (ìë£)**
- â
12ê° ë
žë íì
구í (100%)
- â
12ê° ìì± ížì§ UI (100%)
- â
REST API, UPSERT, ë°ìŽí° ë³í, 죌ì, ë¡ê·ž ë
žë ì¶ê°
### ð¯ ë€ì ìì
(Phase 3)
#### Week 5 - ìë£ â
- â
ëšì ë
žë íì
구í (5ê°)
- â
UpsertAction: INSERT + UPDATE ê²°í© (ON CONFLICT)
- â
DataTransform: ë°ìŽí° ë³í (UPPERCASE, LOWERCASE, TRIM ë±)
- â
RestAPISource: REST API ížì¶
- â
Comment: 죌ì ë
žë
- â
Log: ë¡ê·ž ì¶ë ¥ ë
žë
- â
ëšì ìì± ížì§ íšë 구í (5ê°)
- â
UpsertActionProperties: ì¶©ë í€, íë ë§€í, ìµì
- â
DataTransformProperties: ë³í ê·ì¹, ííì
- â
RestAPISourceProperties: URL, ë©ìë, í€ë, ìžìŠ
- â
CommentProperties: ë©ëªš ëŽì©
- â
LogProperties: ë¡ê·ž ë 벚, ë©ìì§, ë°ìŽí° í¬íš
**ë§ìŒì€í€ 4 ìë£**: ë
žë íì
100% ìë£ (12/12)
**ë§ìŒì€í€ 5 ìë£**: ìì± íšë 100% ìë£ (12/12)
## ð Phase 2 ìë£!
몚ë ë
žë íì
곌 ìì± íšëìŽ êµ¬íëììµëë€!
### ð¯ Phase 3 ê³í: ê²ìŠ ë° ì€í ìì€í
#### Week 6 - ìë£ â
- â
ê²ìŠ ìì€í
ê°í
- â
ìí ì°žì¡° ê²ìŠ (DFS ìê³ ëŠ¬ìŠ)
- â
ë
žëë³ íì ìì± ê²ìŠ (12ê° ë
žë íì
)
- â
Comment/Log ë
žë ë
늜 íì©
- â
ììží ì€ë¥ ë©ìì§ ë° ë
žë ID í¬íš
**ë§ìŒì€í€ 6 ìë£**: ê²ìŠ ìì€í
100% ìë£
#### ì°ì ìì 1: ê²ìŠ ìì€í
ê°í â
ìë£
#### ì°ì ìì 2: íë¡ì° ì€í ìì§ (ì¶í 구í)
- â³ ë
žë ì€í ë¡ì§
- â³ ë°ìŽí° íëŠ ì²ëЬ
- â³ ìë¬ ížë€ë§
- â³ ížëìì
êŽëЬ
- â³ íë¡ì° ëª©ë¡ ì¡°í
### ðŠ êµ¬íë 컎í¬ëíž
```
frontend/
âââ types/
â âââ node-editor.ts â
(ìë£)
âââ lib/
â âââ stores/
â âââ flowEditorStore.ts â
(ìë£)
âââ components/dataflow/node-editor/
â âââ FlowEditor.tsx â
(ìë£)
â âââ FlowToolbar.tsx â
(ìë£)
â âââ nodes/
â â âââ TableSourceNode.tsx â
(ìë£)
â â âââ ExternalDBSourceNode.tsx â
(ìë£)
â â âââ ConditionNode.tsx â
(ìë£)
â â âââ FieldMappingNode.tsx â
(ìë£)
â â âââ InsertActionNode.tsx â
(ìë£)
â â âââ UpdateActionNode.tsx â
(ìë£)
â â âââ DeleteActionNode.tsx â
(ìë£)
â â âââ RestAPISourceNode.tsx â
(ìë£)
â â âââ DataTransformNode.tsx â
(ìë£)
â â âââ UpsertActionNode.tsx â
(ìë£)
â â âââ CommentNode.tsx â
(ìë£)
â â âââ LogNode.tsx â
(ìë£)
â âââ sidebar/
â â âââ NodePalette.tsx â
(ìë£)
â â âââ nodePaletteConfig.ts â
(ìë£)
â âââ panels/
â âââ PropertiesPanel.tsx â
(ìë£)
â âââ properties/
â âââ TableSourceProperties.tsx â
(ìë£)
â âââ ExternalDBSourceProperties.tsx â
(ìë£)
â âââ ConditionProperties.tsx â
(ìë£)
â âââ FieldMappingProperties.tsx â
(ìë£)
â âââ InsertActionProperties.tsx â
(ìë£)
â âââ UpdateActionProperties.tsx â
(ìë£)
â âââ DeleteActionProperties.tsx â
(ìë£)
â âââ UpsertActionProperties.tsx â
(ìë£)
â âââ DataTransformProperties.tsx â
(ìë£)
â âââ RestAPISourceProperties.tsx â
(ìë£)
â âââ CommentProperties.tsx â
(ìë£)
â âââ LogProperties.tsx â
(ìë£)
âââ app/(main)/admin/dataflow/
âââ node-editor/
âââ page.tsx â
(ìë£)
```
### ð® íì¬ ì¬ì© ê°ë¥í êž°ë¥
- â
ë
žë ëëê·ž ì€ ëë¡ìŒë¡ ìºë²ì€ì ì¶ê°
- â
ë
žë ê° ì°ê²°ì 귞늬Ʞ
- â
ë
žë ì í ë° ìì± ížì§ (100%)
- â
ì€/í¬ ì»šížë¡€ (íë/ì¶ì/ì 첎볎Ʞ)
- â
믞ëë§µ íì
- â
íë¡ì° ê²ìŠ (ìì€/ì¡ì
첎í¬, ê³ ì ë
žë ê°ì§)
- â
ë°ìí ë ìŽìì (250px ì¬ìŽëë° + ìºë²ì€ + 350px ìì±)
- â
7ê° ë
žë íì
구í (58%)
- ë°ìŽí° ìì€: í
ìŽëž, ìžë¶ DB
- ë³í/조걎: íë ë§€í, 조걎 ë¶êž° (TRUE/FALSE ì¶ë ¥)
- ì¡ì
: INSERT, UPDATE, DELETE
- â
7ê° ë
žë ìì± ížì§ ìì± (100%)
- TableSource: í
ìŽëž/ì€í€ë§ ì€ì
- InsertAction: íë ë§€í, ë°°ì¹ ìµì
- FieldMapping: ìì€âíê², ë³í íšì
- Condition: 12ê°ì§ ì°ì°ì, AND/OR
- UpdateAction: WHERE 조걎, ì
ë°ìŽíž íë
- DeleteAction: WHERE 조걎, ìí 겜ê³
- ExternalDBSource: DB íì
ë³ UI
- â
ì ì¥/ë¶ë¬ì€êž° ìì€í
(100%)
- DB ì ì¥ (ì ê·/ìì )
- íë¡ì° ëª©ë¡ ì¡°í
- íë¡ì° ë¶ë¬ì€êž°
- íë¡ì° ìì
- JSON íìŒ ëŽë³ŽëŽêž°
### ð í
ì€íž URL
```
http://localhost:3000/admin/dataflow/node-editor
```
---
## ð íì¬ ìì€í
ë¶ì
### íì¬ êµ¬ì¡°
íì¬ ë°ìŽí° ì ìŽ ìì€í
ì 4ëšê³ ë§ë²ì¬ ë°©ìì ì¬ì©í©ëë€:
```
Step 1: ì°ê²° ì€ì (FROM/TO í
ìŽëž ì í)
â
Step 2: ë°ìŽí° ì í (ì»¬ëŒ ë§€í)
â
Step 3: 조걎 ì€ì (ì ìŽ ì¡°ê±Ž)
â
Step 4: ì¡ì
ì€ì (INSERT/UPDATE/DELETE)
```
### 묞ì ì
#### 1. ì¬ì©ì± 묞ì
- â **ì 첎 íëŠ íì
ìŽë €ì**: 4ëšê³ë¥Œ 몚ë ê±°ì³ìŒ ì 첎 구조 ìŽíŽ ê°ë¥
- â **ìì ë¶íž**: ìŽì ëšê³ë¡ ëìê°ì ìì íêž° ë²ê±°ë¡ì
- â **ë³µì¡í ë¡ì§ íí ì í**: ë€ì€ ë¶êž°, ì¡°ê±Žë¶ ì€í ë± íí ìŽë €ì
- â **ìê°í ì í**: "íëŠ ë¯žëŠ¬ë³Žêž°" íììë§ ì 첎 구조 íìž ê°ë¥
#### 2. êž°ë¥ì ì í
- ëšì í íëŠë§ ì§ì (A â B â C)
- ë³µì¡í ë°ìŽí° ë³í ë¡ì§ 구í ìŽë €ì
- ëë²ê¹
ì ìŽë ëšê³ìì 묞ì ê° ë°ìíëì§ íì
ìŽë €ì
- ì¬ì¬ì© ê°ë¥í ë¡ì§ íšíŽ ì ì¥ ë¶ê°
#### 3. íìµ ê³¡ì
- ìë¡ìŽ ì¬ì©ìê° 4ëšê³ íë¡ìžì€ë¥Œ ìŽíŽíëë° ìê° ìì
- ê° ëšê³ì ì€ì ìŽ ìµì¢
결곌ì ìŽë€ ìí¥ì 죌ëì§ ì§êŽì ìŽì§ ìì
---
## ð ì ì: ë
žë êž°ë° ë¹ì£ŒìŒ ìëí°
### íµì¬ ê°ë
**ëžë£šíëŠ°íž ì€íìŒ ë
žë íë¡ê·žëë°**
- ìžëŠ¬ìŒ ìì§, N8N, Node-REDì ê°ì ë¹ì£ŒìŒ íë¡ê·žëë° ë°©ì ì±í
- ëëê·ž ì€ ëë¡ìŒë¡ ë
žë ë°°ì¹
- ë
žë ê° ì°ê²°ì ìŒë¡ ë°ìŽí° íëŠ íí
- ì€ìê° ìê°ì íŒëë°±
### 죌ì ì¥ì
#### 1. ì§êŽì±
- â
ì 첎 ë°ìŽí° íëŠì í í멎ìì íì
- â
ìê°ì ìŒë¡ ë¡ì§ 구조 ìŽíŽ
- â
ë
žë ê° êŽê³ê° ëª
ííê² ííëš
#### 2. ì ì°ì±
- â
ìì ë¡ìŽ ë
žë ë°°ì¹ ë° ì¬ë°°ì¹
- â
ë³µì¡í ë¶êž° ë¡ì§ ìœê² 구í
- â
ëì ìŒë¡ ë
žë ì¶ê°/ì ê±°
#### 3. ìì°ì±
- â
ëëê·ž ì€ ëë¡ìŒë¡ ë¹ ë¥ž 구ì±
- â
í
í늿 ìì€í
ìŒë¡ ì¬ì¬ì©
- â
ì€ìê° ê²ìŠìŒë¡ ì€ë¥ ì¡°êž° ë°ê²¬
#### 4. ëë²ê¹
- â
ê° ë
žëë³ ì€í ìí ìê°í
- â
ë°ìŽí° íëŠ ì¶ì ê°ë¥
- â
ë³ëª© ì§ì ìœê² íì
---
## ðš UI/UX ëììž
### ì 첎 ë ìŽìì
```
âââââââââââââââââââââââââââââââââââââââââââââââââââââââââââââââââââââââââââââ
â ð ì ìŽ êŽëЬ: ì€ëŒíŽ í
ì€íž2 [ì ì¥] [í
ì€íž ì€í] [ë«êž°] â
ââââââââââââââââââ¬âââââââââââââââââââââââââââââââââââââââââââââââââââââââââââ€
â ð§ ë구 íšë â ðš ìºë²ì€ (ë
žë ë°°ì¹ ìì) â
â (250px) â (ëëšžì§ ìì) â
â â â
â ââ ë°ìŽí° ìì€ â ââââââââââââââââââââââââââââââââââââââââââââââââââââââ â
â â ð í
ìŽëž â â â â
â â ð ìžë¶ DB â â ë
žë륌 ì¬êž°ì ëëê·ž ì€ ëë¡íìžì â â
â â ð REST API â â â â
â â ð GraphQL â â [ë¹ ìºë²ì€] â â
â ââââââââââââââââ â â â
â â ââââââââââââââââââââââââââââââââââââââââââââââââââââââ â
â ââ ë³í/조걎 â â
â â ð íë ë§€í â âââââââââââââââââââ â
â â ⡠조걎 ë¶êž° â â 믞ëë§µ â â
â â ð§ ë°ìŽí° ë³íâ â âââââââââââââ â â
â â ð 룚í â â â ⪠⪠⪠â â 150x100px â
â ââââââââââââââââ â â ⪠⪠â â â
â â â âââââââââââââ â â
â ââ ì¡ì
â âââââââââââââââââââ â
â â â INSERT â â
â â âïž UPDATE â 컚ížë¡€ ë°: [íë/ì¶ì] [ì 첎볎Ʞ] [귞늬ë ON/OFF] â
â â â DELETE â â
â â ð UPSERT â â
â ââââââââââââââââ â
â â â
â ââ ì ížëŠ¬í° â â
â â ð¬ 죌ì â â
â â ðŠ ê·žë£¹ â â
â â ð ë¡ê·ž â â
â ââââââââââââââââ â
ââââââââââââââââââŽâââââââââââââââââââââââââââââââââââââââââââââââââââââââââââ
```
### ë구 íšë ììž
#### ë°ìŽí° ìì€ ì¹ì
```
ââ ë°ìŽí° ìì€ ââââââââââââââââââ
â â
â ð ëŽë¶ í
ìŽëž â
â âââââââââââââââââââââââââââ â
â â [ëìŽì ìºë²ì€ì ë°°ì¹] â â
â âââââââââââââââââââââââââââ â
â â
â ð ìžë¶ DB ì°ê²° â
â âââââââââââââââââââââââââââ â
â â [ìžë¶ ë°ìŽí°ë² ìŽì€] â â
â âââââââââââââââââââââââââââ â
â â
â ð REST API â
â âââââââââââââââââââââââââââ â
â â [HTTP ìì² ë
žë] â â
â âââââââââââââââââââââââââââ â
â â
â ð GraphQL â
â âââââââââââââââââââââââââââ â
â â [GraphQL 쿌늬 ë
žë] â â
â âââââââââââââââââââââââââââ â
â â
âââââââââââââââââââââââââââââââââ
```
---
## ð¯ ë
žë íì
ì ì
### 1. ë°ìŽí° ìì€ ë
žë
#### 1.1 í
ìŽëž ìì€ ë
žë
```
âââââââââââââââââââââââââââââââââââââââ
â ð ì¬ì©ìì 볎 â â íëì í€ë (#3B82F6)
â user_info â
âââââââââââââââââââââââââââââââââââââââ€
â ð ì°ê²°: ë©ìž DB â
â ð ì€í€ë§: public â
â â
â ì¶ë ¥ íë: [몚ë 볎Ʞ âŒ] â
â âââââââââââââââââââââââââââââââââââ â
â â â user_id (integer) â â â â íëë³ ì°ê²° í¬ìžíž
â â â user_name (varchar) â â â
â â â email (varchar) â â â
â â â created_at (timestamp) â â â
â â â updated_at (timestamp) â â â
â âââââââââââââââââââââââââââââââââââ â
â â
â [ì€ì âïž] [í늬뷰 ðïž] â
âââââââââââââââââââââââââââââââââââââââ
ë
žë ë°ìŽí° 구조:
{
type: 'tableSource',
data: {
connectionId: 0,
tableName: 'user_info',
schema: 'public',
fields: [
{ name: 'user_id', type: 'integer', nullable: false },
{ name: 'user_name', type: 'varchar', nullable: false },
// ...
]
}
}
```
#### 1.2 ìžë¶ DB ìì€ ë
žë
```
âââââââââââââââââââââââââââââââââââââââ
â ð Oracle DB â â 죌í©ì í€ë (#F59E0B)
â USERS í
ìŽëž â
âââââââââââââââââââââââââââââââââââââââ€
â ð ì°ê²°: Oracle ìŽì ìë² â
â ð ìí: ì°ê²°ëš â
â
â â
â ì¶ë ¥ íë: â
â â SALT (VARCHAR2) â â
â â USERNAME (VARCHAR2) â â
â â EMAIL (VARCHAR2) â â
â â
â [ì°ê²° í
ì€íž] [ìë¡ê³ 칚] â
âââââââââââââââââââââââââââââââââââââââ
```
#### 1.3 REST API ë
žë
```
âââââââââââââââââââââââââââââââââââââââ
â ð HTTP ìì² â â ìŽë¡ì í€ë (#10B981)
âââââââââââââââââââââââââââââââââââââââ€
â ë©ìë: [GET âŒ] â
â URL: https://api.example.com/users â
â â
â í€ë: â
â Authorization: Bearer {token} â
â â
â ìëµ íë: â
â â data.users â â
â â data.total â â
â â
â [ìì² í
ì€íž] [ì ì¥] â
âââââââââââââââââââââââââââââââââââââââ
```
### 2. ë³í/조걎 ë
žë
#### 2.1 조걎 ë¶êž° ë
žë
```
âââââââââââââââââââââââââââââââââââââââ
â ⡠조걎 ê²ì¬ â â ë
žëì í€ë (#EAB308)
âââââââââââââââââââââââââââââââââââââââ€
â â ì
ë ¥ ë°ìŽí° â
â â
â 조걎ì: â
â âââââââââââââââââââââââââââââââââââ â
â â [user_id] [IS NOT NULL] [â] â â
â â [AND] â â
â â [email] [LIKE] [%@%] [â] â â
â âââââââââââââââââââââââââââââââââââ â
â â
â [+ 조걎 ì¶ê°] â
â â
â ë¶êž°: â
â â
TRUE â â â 조걎 충족 ì
â â FALSE â â â 조걎 ë¶ì¶©ì¡± ì
âââââââââââââââââââââââââââââââââââââââ
ë
žë ë°ìŽí° 구조:
{
type: 'condition',
data: {
conditions: [
{ field: 'user_id', operator: 'IS_NOT_NULL', value: null },
{ field: 'email', operator: 'LIKE', value: '%@%' }
],
logic: 'AND'
}
}
```
#### 2.2 íë ë§€í ë
žë
```
âââââââââââââââââââââââââââââââââââââââ
â ð íë ë§€í â â 볎ëŒì í€ë (#8B5CF6)
âââââââââââââââââââââââââââââââââââââââ€
â ì
ë ¥: â
â â user_id â
â â user_name â
â â email â
â â created_at â
â â
â ë§€í ê·ì¹: â
â âââââââââââââââââââââââââââââââââââ â
â â user_id â SALT â â
â â user_name â USERNAME â â
â â email â EMAIL â â
â â NOW() â CREATED_AT â â â íšì/ìì
â âââââââââââââââââââââââââââââââââââ â
â â
â [+ ë§€í ì¶ê°] [ìë ë§€í] â
â â
â ì¶ë ¥ â â
âââââââââââââââââââââââââââââââââââââââ
ë
žë ë°ìŽí° 구조:
{
type: 'fieldMapping',
data: {
mappings: [
{ source: 'user_id', target: 'SALT', transform: null },
{ source: 'user_name', target: 'USERNAME', transform: null },
{ source: 'email', target: 'EMAIL', transform: null },
{ source: null, target: 'CREATED_AT', transform: 'NOW()' }
]
}
}
```
#### 2.3 ë°ìŽí° ë³í ë
žë
```
âââââââââââââââââââââââââââââââââââââââ
â ð§ ë°ìŽí° ë³í â â ì²ë¡ì í€ë (#06B6D4)
âââââââââââââââââââââââââââââââââââââââ€
â â ì
ë ¥ ë°ìŽí° â
â â
â ë³í ê·ì¹: â
â âââââââââââââââââââââââââââââââââââ â
â â UPPER(user_name) â â
â â TRIM(email) â â
â â CONCAT(first_name, last_name) â â
â âââââââââââââââââââââââââââââââââââ â
â â
â [+ ë³í ì¶ê°] [íšì ëìë§] â
â â
â ì¶ë ¥ â â
âââââââââââââââââââââââââââââââââââââââ
```
### 3. ì¡ì
ë
žë
#### 3.1 INSERT ë
žë
```
âââââââââââââââââââââââââââââââââââââââ
â â INSERT â â ìŽë¡ì í€ë (#22C55E)
âââââââââââââââââââââââââââââââââââââââ€
â íê²: USERS â
â ì°ê²°: Oracle ìŽì ìë² â
â â
â â ë§€í ë°ìŽí° ì
ë ¥ â
â â
â ìœì
íë: â
â âââââââââââââââââââââââââââââââââââ â
â â ⢠SALT â user_id â â
â â ⢠USERNAME â user_name â â
â â ⢠EMAIL â email â â
â â ⢠PASSWORD â [믞맀í] â ïž â â
â âââââââââââââââââââââââââââââââââââ â
â â
â ìµì
: â
â â ì€ë³µ ì 묎ì â
â â ë°°ì¹ ì²ëЬ (1000걎) â
â â
â â
ìë£ â â
âââââââââââââââââââââââââââââââââââââââ
```
#### 3.2 UPDATE ë
žë
```
âââââââââââââââââââââââââââââââââââââââ
â âïž UPDATE â â íëì í€ë (#3B82F6)
âââââââââââââââââââââââââââââââââââââââ€
â íê²: user_info â
â ì°ê²°: ë©ìž DB â
â â
â â ë°ìŽí° ì
ë ¥ â
â â
â 조걎 (WHERE): â
â user_id = {input.user_id} â
â â
â ì
ë°ìŽíž íë: â
â âââââââââââââââââââââââââââââââââââ â
â â ⢠user_name â new_name â â
â â ⢠updated_at â NOW() â â
â âââââââââââââââââââââââââââââââââââ â
â â
â â
ìë£ â â
âââââââââââââââââââââââââââââââââââââââ
```
#### 3.3 DELETE ë
žë
```
âââââââââââââââââââââââââââââââââââââââ
â â DELETE â â 빚ê°ì í€ë (#EF4444)
âââââââââââââââââââââââââââââââââââââââ€
â íê²: temp_data â
â ì°ê²°: ë©ìž DB â
â â
â â ë°ìŽí° ì
ë ¥ â
â â
â 조걎 (WHERE): â
â created_at < DATE_SUB(NOW(), 7) â
â â
â â ïž ê²œê³ : â
â ìì ìì
ì ëë늎 ì ììµëë€ â
â â
â â ìì ì íìž â
â â
â â
ìë£ â â
âââââââââââââââââââââââââââââââââââââââ
```
### 4. ì ížëŠ¬í° ë
žë
#### 4.1 죌ì ë
žë
```
âââââââââââââââââââââââââââââââââââââââ
â ð¬ 죌ì â â íì í€ë (#6B7280)
âââââââââââââââââââââââââââââââââââââââ€
â â
â ì¬ì©ì ë°ìŽí°ë¥Œ Oracle DBë¡ ëêž°í â
â â
â ìì±ì: ê¹ì£Œì â
â ë ì§: 2025-10-02 â
â â
âââââââââââââââââââââââââââââââââââââââ
```
#### 4.2 ë¡ê·ž ë
žë
```
âââââââââââââââââââââââââââââââââââââââ
â ð ë¡ê·ž ì¶ë ¥ â â íì í€ë
âââââââââââââââââââââââââââââââââââââââ€
â â ì
ë ¥ ë°ìŽí° â
â â
â ë¡ê·ž ë 벚: [INFO âŒ] â
â ë©ìì§: "ë°ìŽí° ì²ëЬ ìë£: {count}" â
â â
â ì¶ë ¥ â â
âââââââââââââââââââââââââââââââââââââââ
```
---
## ð ì€ì ì¬ì© ìì
### ìì 1: ê°ëší ë°ìŽí° ë³µì¬
#### íì¬ ìì€í
```
Step 1: user_info ì í
Step 2: USERS (Oracle) ì í
Step 3: 조걎 ìì
Step 4: INSERT + íë ë§€í 4ê°
```
#### ë
žë êž°ë° ìì€í
```
ìºë²ì€ ë·°:
ââââââââââââââââ ââââââââââââââââ ââââââââââââââââ
â ð user_info â â ð íë ë§€í â â â INSERT â
â ââââââââ>â ââââââââ>â USERS â
â user_id âââŒâââââââ>â 4ê° ë§€í â â (Oracle) â
â user_name âââŒâââââââ>â â â â
â email âââŒâââââââ>â â â â
ââââââââââââââââ ââââââââââââââââ ââââââââââââââââ
```
### ìì 2: ì¡°ê±Žë¶ ë°ìŽí° ì²ëЬ
#### ìë늬ì€
- user_infoìì ë°ìŽí° ìœêž°
- user_idê° NULLìŽ ìëê³ emailìŽ ì íší 겜ì°ë§ ì²ëЬ
- 조걎 íµê³Œ ì Oracle DBì INSERT
#### ë
žë ë°°ì¹
```
ââââââââââââââââ ââââââââââââââââ TRUE ââââââââââââââââ ââââââââââââââââ
â ð user_info â â ⡠조걎 ê²ì¬ ââââââââ>â ð íë ë§€í â â â INSERT â
â ââââââââ>â â â ââââââââ>â USERS â
â user_id âââŒâââââââ>â user_id â â 4ê° ë§€í â â â
â user_name âââŒââ â IS NOT NULL â â â â â
â email âââŒââŒâââââ>â AND â â â â â
ââââââââââââââââ â â email LIKE â FALSE â â â â
â â '%@%' ââââââââ>â [ì€ëš] â â â
â ââââââââââââââââ ââââââââââââââââ ââââââââââââââââ
â â
âââââââââââââââââââââââââââââââââââââââ
```
### ìì 3: ë³µì¡í ë€ì€ ë¶êž°
#### ìë늬ì€
- ì¬ì©ì íì
ì ë°ëŒ ë€ë¥ž í
ìŽëžì ì ì¥
- êŽëЬì â admin_users
- ìŒë° ì¬ì©ì â regular_users
- ê²ì€íž â guest_logs
#### ë
žë ë°°ì¹
```
ââââââââââââââââ ââââââââââââââââ
â ð ë§€í1 â â â INSERT â
admin âââ>â ââââââââ>â admin_users â
â± ââââââââââââââââ ââââââââââââââââ
ââââââââââââââââ ââââ±ââââââââââââ
â ð user_info â â â¡ íì
ë¶êž° â ââââââââââââââââ ââââââââââââââââ
â ââââââââ>â â user âââ>â ð ë§€í2 â â â INSERT â
â user_type âââŒâââââââ>â user_type â â ââââââââ>â regular_usersâ
ââââââââââââââââ â â ââââââââââââââââ ââââââââââââââââ
ââââ²ââââââââââââ
â² ââââââââââââââââ ââââââââââââââââ
guest ââââ>â ð ë§€í3 â â â INSERT â
â ââââââââ>â guest_logs â
ââââââââââââââââ ââââââââââââââââ
```
---
## ð® 죌ì êž°ë¥ ëª
ìž
### 1. ëëê·ž ì€ ëë¡
#### 1.1 ë
žë ì¶ê°
```typescript
// ì¬ì©ì ì¡ì
1. ì¢ìž¡ ë구 íšëìì ë
žë ììŽí
íŽëŠ
2. ìºë²ì€ë¡ ëëê·ž
3. ìíë ìì¹ì ëë¡
// ìì€í
ëì
- ë§ì°ì€ 컀ì륌 ë°ëŒ ë
žë í늬뷰 íì
- ëë¡ ê°ë¥ ìì íìŽëŒìŽíž
- ëë¡ ì ì ë
žë ìì± ë° ë°°ì¹
```
#### 1.2 ë
žë ìŽë
```typescript
// ì¬ì©ì ì¡ì
1. ìºë²ì€ì ë
žë í€ë íŽëŠ
2. ìíë ìì¹ë¡ ëëê·ž
3. ëë¡íì¬ ì¬ë°°ì¹
// ìì€í
ëì
- ì°ê²°ë ì ë€ìŽ íšê» ìì§ì
- 귞늬ë ì€ë
ìµì
(10px ëšì)
- ë€ì€ ì í ì ì¬ë¬ ë
žë ëì ìŽë
```
#### 1.3 ë€ì€ ì í
```typescript
// ë°©ë² 1: Shift + íŽëŠ
ë
žë륌 íëì© Shift + íŽëŠíì¬ ì í
// ë°©ë² 2: ëëê·ž ìì ì í
ë¹ ê³µê°ì ëëê·žíì¬ ì¬ê°í ìì ëŽ ë
žë ì í
// ë°©ë² 3: Ctrl + A
ì 첎 ë
žë ì í
```
### 2. ì°ê²°ì 귞늬Ʞ
#### 2.1 ì°ê²° ìì±
```typescript
// ëšê³ë³ íë¡ìžì€
1. ì¶ë ¥ í¬ìžíž(â) íŽëŠ
2. ë§ì°ì€ë¥Œ ëëê·žíì¬ ì 귞늬Ʞ
3. ì
ë ¥ í¬ìžížì ëë¡íì¬ ì°ê²°
// ìê°ì íŒëë°±
- ëëê·ž ì€ ìì ì íì
- ížíëë ì
ë ¥ í¬ìžíž íìŽëŒìŽíž
- ížíëì§ ìë í¬ìžíž ë¹íì±í
```
#### 2.2 ì°ê²° ê²ìŠ
```typescript
// íì
ê²ìŠ
const validateConnection = (source, target) => {
// ë°ìŽí° íì
ížíì± ì²Ží¬
if (!isCompatibleType(source.dataType, target.dataType)) {
return { valid: false, error: "ë°ìŽí° íì
ë¶ìŒì¹" };
}
// ìí ì°žì¡° 첎í¬
if (hasCircularReference(source, target)) {
return { valid: false, error: "ìí ì°žì¡° ê°ì§" };
}
// ì€ë³µ ì°ê²° 첎í¬
if (isDuplicateConnection(source, target)) {
return { valid: false, error: "ìŽë¯ž ì°ê²°ëìŽ ìì" };
}
return { valid: true };
};
```
#### 2.3 ì°ê²° ì€íìŒ
```typescript
// ì°ê²°ì ì¢
ë¥
1. ë°ìŽí° íëŠ: êµµì 곡ì (ë² ì§ìŽ ì»€ëž)
2. íë ì°ê²°: ê°ë ì§ì
3. 조걎 ë¶êž°: ì ì (TRUE/FALSE)
// ìì ìœë©
- ì ì: #3B82F6 (íëì)
- ê²œê³ : #F59E0B (죌í©ì)
- ì€ë¥: #EF4444 (빚ê°ì)
- ë¹íì±: #9CA3AF (íì)
```
### 3. ì€ìê° ê²ìŠ
#### 3.1 구묞 ê²ìŠ
```typescript
// íëëª
ê²ìŠ
validateFieldName(fieldName) {
// 졎ì¬íì§ ìë íë
if (!sourceFields.includes(fieldName)) {
return error('íë륌 ì°Ÿì ì ììµëë€');
}
}
// SQL ííì ê²ìŠ
validateSQLExpression(expression) {
try {
// Ʞ볞 SQL íì±
parseSQLExpression(expression);
return success();
} catch (e) {
return error('ì못ë SQL ííì');
}
}
```
#### 3.2 ë
ŒëЬ ê²ìŠ
```typescript
// íì ì°ê²° 첎í¬
validateRequiredConnections(node) {
if (node.type === 'action' && !node.hasInput) {
return error('ì
ë ¥ ë°ìŽí°ê° íìí©ëë€');
}
}
// ê³ ì ë
žë ê°ì§
findOrphanNodes() {
return nodes.filter(node =>
!node.hasInput &&
!node.hasOutput &&
node.type !== 'source'
);
}
```
#### 3.3 ìê°ì íŒëë°±
```
ë
žë ìí íì:
â
ì ì: ìŽë¡ì 첎í¬ë§í¬
â ïž ê²œê³ : ë
žëì ê²œê³ ììŽìœ
â ì€ë¥: 빚ê°ì X ììŽìœ
Ⳡ믞ìì±: íì ì ì í
ë늬
```
### 4. 귞룹í ë° ì£Œì
#### 4.1 귞룹 ë
žë
```
ââ ì¬ì©ì ë°ìŽí° ì²ëЬ 귞룹 ââââââââââââââââââââââââââââââââââ
â â
â ââââââââââââ ââââââââââââ ââââââââââââ â
â â ìì€ ââââââââ>â ë³í ââââââââ>â ì¡ì
â â
â ââââââââââââ ââââââââââââ ââââââââââââ â
â â
â ð¬ 죌ì: Oracle DB ëêž°í ë¡ì§ â
ââââââââââââââââââââââââââââââââââââââââââââââââââââââââââââââ
êž°ë¥:
- 귞룹 ëšì ìŽë
- 귞룹 ì êž°/íŒì¹êž°
- 귞룹 ìì ì§ì
- 귞룹 ëŽë³ŽëŽêž°/ê°ì žì€êž°
```
#### 4.2 죌ì ìì€í
```
죌ì íì
:
1. ë
žë 죌ì: í¹ì ë
žëì 첚ë¶
2. íë¡í
죌ì: ìºë²ì€ì ë
늜ì ìŒë¡ ë°°ì¹
3. ì°ê²°ì 죌ì: ì°ê²°ì ì ë ìŽëž ì¶ê°
íì ìµì
:
- íì íì
- ë§ì°ì€ ì€ë² ì íì
- íŽëŠ ì íì
```
---
## ð§ êž°ì ì€í
### 1. ë
žë ìëí° ëŒìŽëžë¬ëЬ ë¹êµ
| ëŒìŽëžë¬ëЬ | ì¥ì | ëšì | ì¶ì²ë |
| ----------------- | ---------------------------------------------------------------------------- | ----------------------------------------- | ---------- |
| **React Flow** | ⢠ê°ì¥ ìžêž°ìì
⢠íë¶í ìì
⢠TypeScript ì§ì
⢠컀ì€í°ë§ìŽì§ ì©ìŽ | ⢠복ì¡í ë¡ì§ì ì§ì 구í | âââââ |
| **Rete.js** | ⢠ê°ë ¥í íë¬ê·žìž ìì€í
⢠ìë ë ìŽìì | ⢠íìµ ê³¡ì ëì
⢠React íµí© ê¹ë€ë¡ì | ââââ |
| **react-diagram** | ⢠ê°ëší 구조 | â¢ êž°ë¥ ì íì
⢠ì
ë°ìŽíž ë늌 | âââ |
### 2. React Flow ì í ìŽì
```typescript
// 1. ì¬ìŽ ì€ì¹ ë° ì€ì
npm install reactflow
// 2. ê°ëší ìŽêž° ì€ì
import ReactFlow, { MiniMap, Controls, Background } from 'reactflow';
import 'reactflow/dist/style.css';
function FlowEditor() {
return (
);
}
// 3. 컀ì€í
ë
žë ìœê² 구í
const nodeTypes = {
tableSource: TableSourceNode,
condition: ConditionNode,
action: ActionNode,
};
```
### 3. íµì¬ 컎í¬ëíž êµ¬ì¡°
```
frontend/components/dataflow/node-editor/
âââ FlowEditor.tsx # ë©ìž ìëí° ì»Ží¬ëíž
âââ nodes/ # ë
žë 컎í¬ëížë€
â âââ TableSourceNode.tsx
â âââ ExternalDBNode.tsx
â âââ ConditionNode.tsx
â âââ FieldMappingNode.tsx
â âââ InsertActionNode.tsx
â âââ UpdateActionNode.tsx
â âââ DeleteActionNode.tsx
â âââ index.ts
âââ edges/ # 컀ì€í
ì£ì§
â âââ DataFlowEdge.tsx
â âââ ConditionEdge.tsx
â âââ index.ts
âââ sidebar/ # ë구 íšë
â âââ NodePalette.tsx
â âââ NodeLibrary.tsx
â âââ index.ts
âââ panels/ # ì€ì íšë
â âââ NodePropertiesPanel.tsx
â âââ ValidationPanel.tsx
â âââ index.ts
âââ hooks/ # 컀ì€í
í
â âââ useNodeValidation.ts
â âââ useAutoLayout.ts
â âââ useFlowExecution.ts
âââ utils/ # ì ížëЬí°
âââ nodeFactory.ts
âââ flowValidator.ts
âââ flowSerializer.ts
```
### 4. ë°ìŽí° 구조
#### 4.1 ë
žë ë°ìŽí° 몚ëž
```typescript
// Ʞ볞 ë
žë ìží°íìŽì€
interface BaseNode {
id: string;
type: string;
position: { x: number; y: number };
data: any;
style?: CSSProperties;
}
// í
ìŽëž ìì€ ë
žë
interface TableSourceNode extends BaseNode {
type: "tableSource";
data: {
connectionId: number;
tableName: string;
schema: string;
fields: Array<{
name: string;
type: string;
nullable: boolean;
primaryKey: boolean;
}>;
filters?: Array<{
field: string;
operator: string;
value: any;
}>;
};
}
// 조걎 ë
žë
interface ConditionNode extends BaseNode {
type: "condition";
data: {
conditions: Array<{
field: string;
operator:
| "EQUALS"
| "NOT_EQUALS"
| "GREATER_THAN"
| "LESS_THAN"
| "LIKE"
| "IN"
| "IS_NULL"
| "IS_NOT_NULL";
value: any;
}>;
logic: "AND" | "OR";
};
}
// ì¡ì
ë
žë
interface ActionNode extends BaseNode {
type: "insertAction" | "updateAction" | "deleteAction" | "upsertAction";
data: {
targetConnection: number;
targetTable: string;
fieldMappings: Array<{
sourceField: string;
targetField: string;
transform?: string;
}>;
options?: {
batchSize?: number;
ignoreErrors?: boolean;
upsertKey?: string[];
};
};
}
```
#### 4.2 ì°ê²°ì ë°ìŽí° 몚ëž
```typescript
interface Edge {
id: string;
source: string; // ì¶ë° ë
žë ID
target: string; // ëì°© ë
žë ID
sourceHandle?: string; // ì¶ë° ížë€ ID (íëë³ ì°ê²° ì)
targetHandle?: string; // ëì°© ížë€ ID
type?: "default" | "smoothstep" | "step" | "straight";
animated?: boolean;
label?: string;
style?: CSSProperties;
data?: {
dataType?: string;
validation?: {
valid: boolean;
errors?: string[];
};
};
}
// 조걎 ë¶êž° ì£ì§
interface ConditionalEdge extends Edge {
data: {
condition: "TRUE" | "FALSE";
label: string;
};
}
```
#### 4.3 ì 첎 íë¡ì° ë°ìŽí°
```typescript
interface DataFlow {
id: number;
name: string;
description: string;
companyCode: string;
nodes: BaseNode[];
edges: Edge[];
viewport: {
x: number;
y: number;
zoom: number;
};
metadata: {
createdAt: string;
updatedAt: string;
createdBy: string;
version: number;
tags?: string[];
};
}
```
### 5. ìí êŽëЬ
```typescript
// Zustand륌 ì¬ì©í íë¡ì° ìí êŽëЬ
import create from "zustand";
interface FlowState {
nodes: Node[];
edges: Edge[];
selectedNodes: string[];
selectedEdges: string[];
// ë
žë êŽëЬ
addNode: (node: Node) => void;
updateNode: (id: string, data: Partial) => void;
removeNode: (id: string) => void;
// ì£ì§ êŽëЬ
addEdge: (edge: Edge) => void;
updateEdge: (id: string, data: Partial) => void;
removeEdge: (id: string) => void;
// ì í êŽëЬ
selectNode: (id: string, multi?: boolean) => void;
clearSelection: () => void;
// ê²ìŠ
validateFlow: () => ValidationResult;
// ì€í
executeFlow: () => Promise;
}
const useFlowStore = create((set, get) => ({
// ... 구í
}));
```
---
## ð ë¹êµ ë¶ì
### íì¬ ìì€í
vs ë
žë êž°ë° ìì€í
| 잡멎 | íì¬ ìì€í
| ë
žë êž°ë° ìì€í
| ê°ì ë |
| --------------- | --------------------- | -------------------- | ------ |
| **íìµ ê³¡ì ** | ì€ê° (4ëšê³ íë¡ìžì€) | ì¬ì (ìê°ì ì§êŽì±) | +40% |
| **ì 첎 íì
** | ìŽë €ì (ëšê³ë³ ë¶ëЬ) | ì¬ì (íëì íì
) | +60% |
| **ìì ížìì±** | ë¶íž (ëšê³ ìŽë íì) | ížëЬ (ì§ì ìì ) | +50% |
| **ë³µì¡í ë¡ì§** | ì íì (ì í íëŠ) | ì°ì (ë€ì€ ë¶êž°) | +80% |
| **ì¬ì¬ì©ì±** | ë®ì (ìë ë³µì¬) | ëì (í
í늿 ìì€í
) | +70% |
| **ëë²ê¹
** | ìŽë €ì (ë¡ê·ž íìž) | ì¬ì (ìê°ì ì¶ì ) | +65% |
| **íì
** | ë³Žíµ (ì€ëª
íì) | ì°ì (ì첎 묞ìí) | +55% |
| **ì±ë¥** | ìíž | ìíž (ëìŒ) | 0% |
### ì¬ì©ì ìë늬ì€ë³ ë¹êµ
#### ìëëŠ¬ì€ 1: ê°ëší í
ìŽëž ë³µì¬
```
íì¬: 4ëšê³ à íê· 2ë¶ = 8ë¶
ë
žë: ëëê·ž 3ê° + ì°ê²° 2ê° = 3ë¶
ê°ì : 62.5% ëšì¶
```
#### ìëëŠ¬ì€ 2: ì¡°ê±Žë¶ ë€ì€ ì¡ì
```
íì¬: 4ëšê³ à 5ë¶ + 조걎 ì€ì 5ë¶ = 25ë¶
ë
žë: ëëê·ž 7ê° + ì°ê²° 8ê° + ì€ì 5ë¶ = 12ë¶
ê°ì : 52% ëšì¶
```
#### ìëëŠ¬ì€ 3: ë³µì¡í ë°ìŽí° ë³í
```
íì¬: ì¬ë¬ ì ìŽë¥Œ ìì°šì ìŒë¡ ìì± = 45ë¶
ë
žë: íëì íë¡ì°ìì 몚ë ì²ëЬ = 20ë¶
ê°ì : 55.5% ëšì¶
```
---
## ð 구í ë¡ëë§µ
### Phase 1: Ʞ볞 ë
žë ìëí° (2죌)
#### Week 1
- [ ] React Flow íµí© ë° êž°ë³ž ì€ì
- [ ] ëŒìŽëžë¬ëЬ ì€ì¹ ë° ì€ì
- [ ] Ʞ볞 ìºë²ì€ 구í
- [ ] 귞늬ë 배겜 ë° ì€/í¬ êž°ë¥
- [ ] Ʞ볞 ë
žë íì
구í
- [ ] í
ìŽëž ìì€ ë
žë
- [ ] INSERT ì¡ì
ë
žë
- [ ] íë ë§€í ë
žë
#### Week 2
- [ ] ëëê·ž ì€ ëë¡ êž°ë¥
- [ ] ë구 íšëìì ìºë²ì€ë¡ ëëê·ž
- [ ] ë
žë ìŽë ë° ì¬ë°°ì¹
- [ ] ë€ì€ ì í ë° ê·žë£¹ ìŽë
- [ ] ì°ê²°ì 귞늬Ʞ
- [ ] Ʞ볞 ì°ê²° ìì±
- [ ] ì°ê²° ê²ìŠ
- [ ] ì°ê²° ì€íìŒë§
- [ ] ë°ìŽí° ì ì¥/ë¶ë¬ì€êž°
- [ ] JSON ì§ë ¬í
- [ ] ë°±ìë API ì°ë
**ë§ìŒì€í€ 1**: Ʞ볞ì ìž í
ìŽëž â íë ë§€í â INSERT íë¡ì° 구í
### Phase 2: ê³ êž êž°ë¥ (2죌)
#### Week 3
- [ ] ì¶ê° ë
žë íì
- [ ] ìžë¶ DB ìì€ ë
žë
- [ ] 조걎 ë¶êž° ë
žë
- [ ] UPDATE/DELETE ì¡ì
ë
žë
- [ ] ë°ìŽí° ë³í ë
žë
- [ ] SQL íšì ì§ì
- [ ] 컀ì€í
ííì
- [ ] ë
žë ì€ì íšë
- [ ] ì°ìž¡ ìì± íšë
- [ ] ìžëŒìž ížì§
- [ ] íë ìë ìì±
#### Week 4
- [ ] ì€ìê° ê²ìŠ ìì€í
- [ ] 구묞 ê²ìŠ
- [ ] ë
ŒëЬ ê²ìŠ
- [ ] íì
ê²ìŠ
- [ ] ì¡°ê±Žë¶ ì€í
- [ ] TRUE/FALSE ë¶êž°
- [ ] ë€ì€ 조걎 ì²ëЬ
- [ ] ì€ë¥ íì ë° íŽê²°
- [ ] ì€ë¥ íìŽëŒìŽíž
- [ ] ì€ë¥ ë©ìì§ íŽí
- [ ] ìë ìì ì ì
**ë§ìŒì€í€ 2**: 조걎 ë¶êž° ë° ë€ì€ ì¡ì
ì í¬íší ë³µì¡í íë¡ì° 구í
### Phase 3: UX ê°ì (1죌)
#### Week 5
- [ ] 믞ëë§µ
- [ ] ì 첎 íë¡ì° 믞늬볎Ʞ
- [ ] íì¬ ë·°í¬íž íì
- [ ] 믞ëë§µ íŽëŠ ë€ë¹ê²ìŽì
- [ ] ì€/í¬ ì»šížë¡€
- [ ] ì€ ìž/ìì ë²íŒ
- [ ] ì 첎 볎Ʞ ë²íŒ
- [ ] ì íë ë
žëë¡ í¬ì»€ì€
- [ ] ë
žë í
í늿 ìì€í
- [ ] ì죌 ì¬ì©íë íšíŽ ì ì¥
- [ ] í
í늿 ê°€ë¬ëЬ
- [ ] ëëê·žë¡ í
í늿 ì ì©
- [ ] í€ë³Žë ëšì¶í€
- [ ] Ctrl+C/V: ë³µì¬/ë¶ì¬ë£êž°
- [ ] Delete: ìì
- [ ] Ctrl+Z/Y: ì€í ì·šì/ë€ì ì€í
- [ ] Ctrl+A: ì 첎 ì í
- [ ] Space + Drag: í¬
- [ ] íí ëŠ¬ìŒ ë° ëìë§
- [ ] 첫 방묞ì ê°ìŽë
- [ ] ìží°ëí°ëž íí 늬ìŒ
- [ ] 컚í
ì€íž ëìë§
**ë§ìŒì€í€ 3**: ì¬ì©ì ì¹íì ìž ìží°íìŽì€ ìì±
### Phase 4: ê³ êž êž°ë¥ (1죌)
#### Week 6
- [ ] 귞룹í êž°ë¥
- [ ] ë
žë 귞룹 ìì±
- [ ] 귞룹 ì êž°/íŒì¹êž°
- [ ] 귞룹 ìì ë° ëŒë²š
- [ ] 죌ì ìì€í
- [ ] ë
žë 죌ì
- [ ] íë¡í
죌ì
- [ ] ì°ê²°ì ëŒë²š
- [ ] ì€í ì¶ì (ëë²ê·ž 몚ë)
- [ ] ë
žëë³ ì€í ìí íì
- [ ] ë°ìŽí° íëŠ ì ëë©ìŽì
- [ ] ì€í ë¡ê·ž íšë
- [ ] ì€ëšì ì€ì
- [ ] ë²ì êŽëЬ
- [ ] íë¡ì° ë²ì íì€í 늬
- [ ] ë²ì ë¹êµ
- [ ] ìŽì ë²ì ë³µì
- [ ] ëŽë³ŽëŽêž°/ê°ì žì€êž°
- [ ] JSON íìŒ ëŽë³ŽëŽêž°
- [ ] JSON íìŒ ê°ì žì€êž°
- [ ] ìŽë¯žì§ ëŽë³ŽëŽêž° (PNG/SVG)
- [ ] í
í늿 ê³µì
**ë§ìŒì€í€ 4**: íë¡ëì
ë ë êž°ë¥ ìì±
### Phase 5: ìµì í ë° í
ì€íž (1죌)
#### Week 7
- [ ] ì±ë¥ ìµì í
- [ ] ëê·ëªš íë¡ì° ë ëë§ ìµì í
- [ ] ê°ì ì€í¬ë¡€ë§
- [ ] ë ìŽì§ ë¡ë©
- [ ] ëšì í
ì€íž
- [ ] ë
žë 컎í¬ëíž í
ì€íž
- [ ] ê²ìŠ ë¡ì§ í
ì€íž
- [ ] íë¡ì° ì€í í
ì€íž
- [ ] íµí© í
ì€íž
- [ ] E2E ìëëŠ¬ì€ í
ì€íž
- [ ] í¬ë¡ì€ ëžëŒì°ì í
ì€íž
- [ ] ì¬ì©ì í
ì€íž
- [ ] ë² í í
ì€í° 몚ì§
- [ ] íŒëë°± ìì§ ë° ë°ì
- [ ] 묞ìí
- [ ] ì¬ì©ì ê°ìŽë
- [ ] API 묞ì
- [ ] ê°ë°ì 묞ì
**ìµì¢
ë§ìŒì€í€**: íë¡ëì
ë°°í¬ ì€ë¹ ìë£
---
## ð¡ ì¶ê° êž°ë¥ ììŽëìŽ
### 1. í
í늿 ê°€ë¬ëЬ
#### 1.1 ëŽì¥ í
í늿
```
ð í
í늿 칎í
ê³ ëŠ¬:
1ïžâ£ ë°ìŽí° ëêž°í
- í
ìŽëž â í
ìŽëž ë³µì¬
- í
ìŽëž â ìžë¶ DB ëêž°í
- ìë°©í¥ ëêž°í
- ìŠë¶ ëêž°í (ë³ê²œë¶ë§)
2ïžâ£ ë°ìŽí° ì ì
- ì€ë³µ ì ê±°
- NULL ê° ì²ëЬ
- ë°ìŽí° íì ë³í
- ë°ìŽí° ê²ìŠ
3ïžâ£ ë°ìŽí° ì§ê³
- ê·žë£¹ë³ ì§ê³
- ìê³ìŽ ì§ê³
- íŒë² í
ìŽëž ìì±
4ïžâ£ ìžë¶ ì°ë
- REST API â DB
- DB â REST API
- íìŒ â DB
- DB â íìŒ
5ïžâ£ ë°°ì¹ ì²ëЬ
- ìŒìŒ ë°°ì¹
- ëì©ë ë°ìŽí° ì²ëЬ
- ìë¬ ížë€ë§
```
#### 1.2 ì¬ì©ì ì ì í
í늿
```typescript
// í
í늿 ì ì¥
const saveAsTemplate = () => {
const template = {
name: "ì¬ì©ì ë°ìŽí° ëêž°í",
description: "user_info륌 Oracle USERSë¡ ëêž°í",
category: "custom",
nodes: currentNodes,
edges: currentEdges,
thumbnail: generateThumbnail(),
parameters: extractParameters(), // ë§€ê°ë³ìí
};
saveTemplate(template);
};
// í
í늿 ì ì©
const applyTemplate = (template) => {
// ë§€ê°ë³ì ì
ë ¥ ë°êž°
const params = promptParameters(template.parameters);
// ë
žë ìì±
const nodes = template.nodes.map((node) => replaceParameters(node, params));
addNodes(nodes);
addEdges(template.edges);
};
```
### 2. AI ìŽìì€íŽíž
#### 2.1 ìì°ìŽ íë¡ì° ìì±
```
ì¬ì©ì: "ì¬ì©ì í
ìŽëžì Oracle DBë¡ ë³µì¬íê³ ì¶ìŽì"
AI ë¶ì:
1. ìì€: user_info í
ìŽëž
2. íê²: Oracle USERS í
ìŽëž
3. ì¡ì
: INSERT
AI ì ì:
ââââââââââââââââ ââââââââââââââââ ââââââââââââââââ
â ð user_info ââââââââ>â ð íë ë§€í ââââââââ>â â INSERT â
â â â ìë ë§€í â â USERS â
ââââââââââââââââ ââââââââââââââââ ââââââââââââââââ
"ìŽ íë¡ì°ë¥Œ ìì±í ê¹ì? [ìì±] [ìì ]"
```
#### 2.2 ì€ë¥ ìë ìì
```
ì€ë¥ ê°ì§:
â user_name íëê° ë§€íëì§ ìììµëë€
AI ì ì:
"user_nameì USERNAMEìŒë¡ ìë ë§€íí ê¹ì?"
[ìë ìì ] [묎ì] [ìë ìì ]
```
#### 2.3 ìµì í ì ì
```
AI ë¶ì:
â ïž íì¬ íë¡ì°ë 10,000걎 ìŽìì ë°ìŽí°ë¥Œ ì²ëЬí©ëë€.
AI ì ì:
1. ë°°ì¹ ì²ëЬ íì±í (1000걎ì©)
2. ìžë±ì€ê° ìë íë 조걎 ì ê±°
3. ë¶íìí íë ë³í ìµì í
ìì ì±ë¥ ê°ì : 3ë°°
[ì ì©íêž°] [ììž ë³Žêž°]
```
### 3. ì€í ì¶ì (ëë²ê·ž 몚ë)
#### 3.1 ì€ìê° ì€í ìí
```
ì€í ì€ ë
žë ìí:
ââââââââââââââââ ââââââââââââââââ ââââââââââââââââ
â ð user_info â â ð íë ë§€í â â â INSERT â
â â
ìë£ ââââââââ>â â¡ ì€í ì€ ââââââââ>â â³ ëêž° ì€ â
â 100걎 ìœì â â 47/100 â â â
ââââââââââââââââ ââââââââââââââââ ââââââââââââââââ
ì§íë¥ : ââââââââââ 80%
ìì ìê°: 00:00:23
ìì ìë£: 00:00:29
```
#### 3.2 ë°ìŽí° 믞늬볎Ʞ
```
ë
žë íŽëŠ ì ë°ìŽí° ìí:
ââ user_info ì¶ë ¥ ë°ìŽí° ââââââââââââââ
â Row 1: â
â user_id: 1001 â
â user_name: "íêžžë" â
â email: "hong@example.com" â
â â
â Row 2: â
â user_id: 1002 â
â user_name: "ê¹ì² ì" â
â ... â
â â
â [ì 첎 볎Ʞ] [CSV ë€ìŽë¡ë] â
âââââââââââââââââââââââââââââââââââââââ
```
#### 3.3 ì€ëšì ì€ì
```
ëë²ê·ž êž°ë¥:
1. ì€ëšì ì€ì
- ë
žëìì ì°íŽëŠ â "ì€ëšì ì€ì "
- íŽë¹ ë
žëìì ì€í ìŒì ì ì§
2. ëšê³ë³ ì€í
[â¶ïž ë€ì ë
žë] [âïž ìë£ê¹ì§] [â¹ïž ì€ì§]
3. ë³ì ê°ì
- í¹ì íë ê° ì¶ì
- 조걎 ë³í 몚ëí°ë§
```
### 4. íì
êž°ë¥
#### 4.1 ì€ìê° ê³µë ížì§
```
ì¬ì©ì íì:
- ð€ ê¹ì£Œì (ë)
- ð€ ìŽì² ì (ížì§ ì€) â 빚ê°ì 컀ì
- ð€ ë°ìí¬ (볎Ʞë§) â ìŽë¡ì 컀ì
ëì ížì§:
- ê° ì¬ì©ìì 컀ì ìì¹ íì
- ë
žë ì êž (ížì§ ì€ìž ë
žë)
- ì¶©ë ë°©ì§ ë©ì»€ëìŠ
```
#### 4.2 ë³ê²œ ìŽë ¥ ë° ëêž
```
ââââââââââââââââ
â íë ë§€í â
â â ð¬ 3
â â
ââââââââââââââââ
ëêž:
ê¹ì£Œì: "user_id륌 SALTë¡ ë§€ííëê² ë§ëì?"
ìŽì² ì: "ë€, ë§ìµëë€. 볎ìì ìí íëì
ëë€."
ë°ìí¬: "묞ìì ì¶ê°íìµëë€."
```
#### 4.3 ì¹ìž ìí¬íë¡ì°
```
íë¡ì° ë³ê²œ ì¹ìž íë¡ìžì€:
1. ê°ë°ì: íë¡ì° ìì
â
2. ê²í ìì²
â
3. êŽëЬì: ë³ê²œ ì¬í ê²í
- ë³ê²œ ì /í ë¹êµ
- ìí¥ë ë¶ì
â
4. ì¹ìž/ë°ë €
â
5. ë°°í¬ ëë ì¬ìì
```
---
## ð íìµ ëŠ¬ìì€ ë° ìšë³Žë©
### 1. ìží°ëí°ëž íí 늬ìŒ
#### ëšê³ë³ ê°ìŽë
```
íí ëŠ¬ìŒ 1: 첫 ë²ì§ž íë¡ì° ë§ë€êž° (5ë¶)
âââââââââââââââââââââââââââââââââââââââ
â 1ëšê³: ë°ìŽí° ìì€ ì¶ê° â
â "ì¢ìž¡ìì 'í
ìŽëž' ë
žë륌 ëëê·ž" â
â â
â [ë€ì] [걎ëë°êž°] â
âââââââââââââââââââââââââââââââââââââââ
íí ëŠ¬ìŒ 2: 조걎 ë¶êž° ì¬ì©íêž° (7ë¶)
íí ëŠ¬ìŒ 3: ë³µì¡í ë³í 구ííêž° (10ë¶)
íí ëŠ¬ìŒ 4: ëë²ê¹
ë° ìµì í (8ë¶)
```
### 2. ëìë§ ìì€í
#### 컚í
ì€íž ëìë§
```
ë
žë ìì ë§ì°ì€ ì€ë²:
âââââââââââââââââââââââââââââââââââââââ
â ð¡ íë ë§€í ë
žë â
â â
â ìì€ íë륌 íê² íëë¡ ë§€íí©ëë€.â
â â
â ì¬ì© ë°©ë²: â
â 1. ì
ë ¥ ë°ìŽí° ì°ê²° â
â 2. ë§€í ê·ì¹ ì ì â
â 3. ì¶ë ¥ì ë€ì ë
žëë¡ ì°ê²° â
â â
â [ììží 볎Ʞ] [íí ëŠ¬ìŒ ë³Žêž°] â
âââââââââââââââââââââââââââââââââââââââ
```
### 3. ìì ê°€ë¬ëЬ
```
ð ìì íë¡ì° ê°€ë¬ëЬ
ìŽêž:
- ëšì í
ìŽëž ë³µì¬
- íëëª
ë³ê²œíì¬ ë³µì¬
- í¹ì ë ìœëë§ ë³µì¬
ì€êž:
- ì¡°ê±Žë¶ ë°ìŽí° ì²ëЬ
- ë€ì€ í
ìŽëž ë³í©
- ë°ìŽí° íì ë³í
ê³ êž:
- ë³µì¡í ë°ìŽí° ì ì
- ë€ì€ ë¶êž° ì²ëЬ
- ë°°ì¹ ìµì í
[ìì ìŽêž°] [í
í늿ìŒë¡ ì ì¥]
```
---
## ð ì±ê³µ ì§í (KPI)
### ì¬ì©ì 겜í ì§í
```
1. íìµ ìê°
- 목í: Ʞ졎 ëë¹ 40% ëšì¶
- ìž¡ì : 첫 íë¡ì° ìì±ê¹ì§ ìì ìê°
- íì¬: íê· 15ë¶
- 목í: íê· 9ë¶
2. ìì
íšìšì±
- 목í: íë¡ì° ìì± ìê° 50% ëšì¶
- ìž¡ì : ëìŒ êž°ë¥ êµ¬í ìì ìê°
- íì¬: íê· 20ë¶
- 목í: íê· 10ë¶
3. ì€ë¥ ê°ì
- 목í: ì€ì ì€ë¥ 60% ê°ì
- ìž¡ì : ì€í ì€íšìš
- íì¬: 12%
- 목í: 4.8%
4. ì¬ì©ì ë§ì¡±ë
- 목í: NPS 40ì ìŽì
- ìž¡ì : ì€ë¬ž ì¡°ì¬
- 죌Ʞ: ë¶êž°ë³
```
### êž°ì ì±ë¥ ì§í
```
1. ë ëë§ ì±ë¥
- 목í: 100ê° ë
žë ë ëë§ < 100ms
- ìž¡ì : React Profiler
2. ë©ëªšëЬ ì¬ì©
- 목í: ëê·ëªš íë¡ì° < 100MB
- ìž¡ì : Chrome DevTools
3. ì ì¥/ë¡ë ìë
- 목í: íë¡ì° ì ì¥ < 500ms
- ìž¡ì : Network í
4. ê²ìŠ ìë
- 목í: ì€ìê° ê²ìŠ < 50ms
- ìž¡ì : Performance API
```
### ë¹ìŠëì€ ì§í
```
1. ëì
ë¥
- 목í: ì ê· ì¬ì©ì 60% ìŽììŽ ë
žë ìëí° ì í
- ìž¡ì : ì¬ì© íµê³
2. ì¬ì¬ì©ë¥
- 목í: í
í늿 ì¬ì¬ì© 40% ìŽì
- ìž¡ì : í
í늿 ì¬ì© íì
3. ìì°ì±
- 목í: íë¡ì° ìì± ì 2ë°° ìŠê°
- ìž¡ì : ìë³ ìì±ë íë¡ì° ì
4. ì ì§ë³Žì
- 목í: íë¡ì° ìì ìê° 30% ëšì¶
- ìž¡ì : íê· ìì ìì ìê°
```
---
## ð 볎ì ë° ê¶í
### 1. ì ê·Œ ì ìŽ
```typescript
// íë¡ì° ê¶í ë 벚
enum FlowPermission {
VIEW = "view", // 볎Ʞë§
EDIT = "edit", // ížì§ ê°ë¥
EXECUTE = "execute", // ì€í ê°ë¥
ADMIN = "admin", // 몚ë ê¶í
}
// ê¶í 첎í¬
const checkPermission = (
userId: string,
flowId: number,
permission: FlowPermission
) => {
const userPermissions = getUserFlowPermissions(userId, flowId);
return userPermissions.includes(permission);
};
```
### 2. ë¯Œê° ì 볎 볎íž
```typescript
// ë¹ë°ë²íž ë± ë¯Œê° ì 볎 ë§ì€í¹
const renderSensitiveField = (value: string, fieldType: string) => {
if (fieldType === "password" || fieldType === "secret") {
return "â¢â¢â¢â¢â¢â¢â¢â¢";
}
return value;
};
// ì€í ë¡ê·žìì ë¯Œê° ì 볎 ì ìž
const sanitizeLog = (log: string) => {
return log
.replace(/password=\w+/gi, "password=***")
.replace(/token=\w+/gi, "token=***");
};
```
### 3. ê°ì¬ ë¡ê·ž
```typescript
// 몚ë íë¡ì° ë³ê²œ êž°ë¡
interface AuditLog {
timestamp: Date;
userId: string;
flowId: number;
action: "create" | "update" | "delete" | "execute";
changes: {
before: any;
after: any;
};
ipAddress: string;
}
// ë¡ê·ž êž°ë¡
const logFlowChange = (log: AuditLog) => {
saveAuditLog(log);
if (isCriticalChange(log)) {
notifyAdmins(log);
}
};
```
---
## ð êµì í (i18n)
### ì§ì ìžìŽ
```
- íêµìŽ (ko) - Ʞ볞
- ììŽ (en)
- ìŒë³žìŽ (ja)
- ì€êµìŽ ê°ì²Ž (zh-CN)
```
### ë²ì ëì
```
1. UI ëŒë²š ë° ë²íŒ
2. ë
žë íì
ëª
ë° ì€ëª
3. ì€ë¥ ë©ìì§
4. ëìë§ ë° íí 늬ìŒ
5. í
í늿ëª
ë° ì€ëª
```
---
## ð± ë°ìí ëììž
### í멎 í¬êž°ë³ ëì
```
1. ë°ì€í¬í± (1920px+)
- ì 첎 êž°ë¥ ì¬ì© ê°ë¥
- 3ìŽ ë ìŽìì (ë구-ìºë²ì€-ìì±)
2. ë
žížë¶ (1366px ~ 1920px)
- ìì± íšë ì êž° ê°ë¥
- 2ìŽ ë ìŽìì
3. íëžëŠ¿ (768px ~ 1366px)
- ë구 íšë ì€ë²ë ìŽ
- 1ìŽ ë ìŽìì + íë¡í
íšë
4. 몚ë°ìŒ (~ 768px)
- ë·°ìŽ ëªšëë§ ì§ì (ížì§ ë¶ê°)
- íë¡ì° ì€í ë° ëªšëí°ë§ ê°ë¥
```
---
## ð ê²°ë¡
ë
žë êž°ë° ë°ìŽí° ì ìŽ ìì€í
ì íì¬ì ëšê³ë³ ë§ë²ì¬ ë°©ìì ë¹íŽ ë€ì곌 ê°ì íì ì ìž ê°ì ì ì ê³µí©ëë€:
### íµì¬ ê°ì¹
1. **ì§êŽì±**: ë¹ê°ë°ìë ìœê² ìŽíŽíê³ ì¬ì©
2. **íšìšì±**: ìì
ìê° 50% ìŽì ëšì¶
3. **ì ì°ì±**: ë³µì¡í ë¡ì§ë ìœê² íí
4. **íì
**: í ê° ìíµ ë° íì
í¥ì
5. **íì§**: ì€ìê° ê²ìŠìŒë¡ ì€ë¥ ê°ì
### êž°ë íšê³Œ
- ì¬ì©ì ë§ì¡±ë í¥ì
- ê°ë° ìì°ì± ìŠê°
- ì ì§ë³Žì ë¹ì© ê°ì
- ìì€í
ìì ì± í¥ì
### ë€ì ëšê³
1. ìŽíŽêŽê³ì 늬뷰 ë° íŒëë°±
2. íë¡í íì
ê°ë° (1죌)
3. ì¬ì©ì í
ì€íž (1죌)
4. 볞격 ê°ë° ìì
---
## ð ì°žê³ ìë£
### ì ì¬ ìì€í
1. **n8n**: ìí¬íë¡ì° ìëí íë«íŒ
- https://n8n.io/
2. **Node-RED**: IoT íë¡ì° êž°ë° íë¡ê·žëë°
- https://nodered.org/
3. **Unreal Blueprint**: ê²ì ê°ë° ë¹ì£ŒìŒ ì€í¬ëŠœí
- https://docs.unrealengine.com/en-US/ProgrammingAndScripting/Blueprints/
### êž°ì 묞ì
1. **React Flow ê³µì 묞ì**
- https://reactflow.dev/
2. **React Flow ìì **
- https://reactflow.dev/examples
3. **TypeScript ë² ì€íž íëí°ì€**
- https://www.typescriptlang.org/docs/
### ëììž ê°ìŽë
1. **Material Design - Data Visualization**
- https://material.io/design/communication/data-visualization.html
2. **Blueprint UI Framework**
- https://blueprintjs.com/
---
**묞ì ë²ì **: 1.0
**ìµì¢
ìì **: 2025-10-02
**ìì±ì**: ê°ë°í
**ê²í ì**: ì íí, ëììží
**ì¹ìžì**: CTO