# ๐ ์กฐ๊ฑด๋ถ ์ฐ๊ฒฐ ๊ธฐ๋ฅ ๊ตฌํ ๊ณํ
## ๐ ํ๋ก์ ํธ ๊ฐ์
ํ์ฌ DataFlow ์์คํ
์์ 3๊ฐ์ง ์ฐ๊ฒฐ ์ข
๋ฅ๋ฅผ ์ง์ํ๊ณ ์์ผ๋ฉฐ, ์ด ์ค **๋ฐ์ดํฐ ์ ์ฅ**๊ณผ **์ธ๋ถ ํธ์ถ** ๊ธฐ๋ฅ์ ์คํ ์กฐ๊ฑด ๋ก์ง์ ์ถ๊ฐํด์ผ ํฉ๋๋ค.
### ํ์ฌ ์ฐ๊ฒฐ ์ข
๋ฅ
1. **๋จ์ ํค๊ฐ ์ฐ๊ฒฐ** - ์กฐ๊ฑด ์ค์ ๋ถํ์ (๊ธฐ์กด ๋ฐฉ์ ์ ์ง)
2. **๋ฐ์ดํฐ ์ ์ฅ** - ์คํ ์กฐ๊ฑด ์ค์ ํ์ โจ
3. **์ธ๋ถ ํธ์ถ** - ์คํ ์กฐ๊ฑด ์ค์ ํ์ โจ
## ๐ฏ ๊ธฐ๋ฅ ์๊ตฌ์ฌํญ
### ๋ฐ์ดํฐ ์ ์ฅ ๊ธฐ๋ฅ
```
"from ํ
์ด๋ธ์ ์ปฌ๋ผ์ด ํน์ ์กฐ๊ฑด์ ๋ง์กฑํ๋ฉด to ํ
์ด๋ธ์ ํน์ ์ก์
์ ์ทจํ ๊ฒ"
```
**์์ ์๋๋ฆฌ์ค:**
- `work_order` ํ
์ด๋ธ์ `status = 'APPROVED'` ์ด๊ณ `quantity > 0` ์ผ ๋
- `material_requirement` ํ
์ด๋ธ์ ์์ฌ ์์๋ ๋ฐ์ดํฐ INSERT
### ์ธ๋ถ ํธ์ถ ๊ธฐ๋ฅ
```
"fromํ
์ด๋ธ์ ์ปฌ๋ผ์ด ํน์ ์กฐ๊ฑด์ ๋ง์กฑํ๋ฉด ์ธ๋ถ apiํธ์ถ์ด๋ ์ด๋ฉ์ผ ๋ฐ์ก ๋ฑ์ ๋์์ ์ทจํด์ผ ํจ"
```
**์์ ์๋๋ฆฌ์ค:**
- `employee_master` ํ
์ด๋ธ์ `employment_status = 'APPROVED'` ์ผ ๋
- ์ธ๋ถ ์ด๋ฉ์ผ API ํธ์ถํ์ฌ ํ์ ๋ฉ์ผ ๋ฐ์ก
## ๐๏ธ ๋ฐ์ดํฐ๋ฒ ์ด์ค ์คํค๋ง ๋ณ๊ฒฝ
### 1. ์ปฌ๋ผ ์ถ๊ฐ
```sql
-- ๊ธฐ์กด ๋ฐ์ดํฐ ์ญ์ ํ dataflow_diagrams ํ
์ด๋ธ์ 3๊ฐ ์ปฌ๋ผ ์ถ๊ฐ
DELETE FROM dataflow_diagrams; -- ๊ธฐ์กด ๋ฐ์ดํฐ ์ ์ฒด ์ญ์
ALTER TABLE dataflow_diagrams
ADD COLUMN control JSONB, -- ์กฐ๊ฑด ์ค์
ADD COLUMN category JSONB, -- ์ฐ๊ฒฐ ์ข
๋ฅ ์ค์
ADD COLUMN plan JSONB; -- ์คํ ๊ณํ ์ค์
-- ์ธ๋ฑ์ค ์ถ๊ฐ
CREATE INDEX idx_dataflow_control_trigger ON dataflow_diagrams USING GIN ((control->'triggerType'));
CREATE INDEX idx_dataflow_category_type ON dataflow_diagrams USING GIN ((category->'type'));
```
### 2. ๋ฐ์ดํฐ ๊ตฌ์กฐ ์ค๊ณ
#### `control` ์ปฌ๋ผ - ์กฐ๊ฑด ์ค์
```json
{
"triggerType": "insert",
"conditionTree": {
"type": "group",
"operator": "AND",
"children": [
{
"type": "condition",
"field": "status",
"operator": "=",
"value": "APPROVED"
}
]
}
}
```
#### `category` ์ปฌ๋ผ - ์ฐ๊ฒฐ ์ข
๋ฅ
```json
{
"type": "data-save" // "simple-key" | "data-save" | "external-call"
}
```
#### `plan` ์ปฌ๋ผ - ์คํ ๊ณํ
```json
{
"sourceTable": "work_order",
"targetActions": [
{
"id": "action_1",
"actionType": "insert",
"targetTable": "material_requirement",
"enabled": true,
"fieldMappings": [
{
"sourceField": "work_order_id",
"targetField": "order_id"
}
]
}
]
}
```
## ๐จ ํ๋ก ํธ์๋ UI ๊ฐ์
### ConnectionSetupModal.tsx ์ฌ์ค๊ณ
#### ํ์ฌ ๊ตฌ์กฐ ๋ฌธ์ ์
- ๋ชจ๋ ์ฐ๊ฒฐ ์ข
๋ฅ์ ๋์ผํ UI ์ ์ฉ
- ์กฐ๊ฑด ์ค์ ๊ธฐ๋ฅ ์์
- ๋จ์ ํค๊ฐ ์ฐ๊ฒฐ๊ณผ ์กฐ๊ฑด๋ถ ์ฐ๊ฒฐ์ ๊ตฌ๋ถ ์์
#### ๊ฐ์ ๋ฐฉ์
##### 1. ์ฐ๊ฒฐ ์ข
๋ฅ๋ณ UI ๋ถ๊ธฐ
```tsx
// ์ฐ๊ฒฐ ์ข
๋ฅ ์ ํ ํ ์กฐ๊ฑด๋ถ ๋ ๋๋ง
{
config.connectionType === "simple-key" && ;
}
{
(config.connectionType === "data-save" ||
config.connectionType === "external-call") && (
);
}
```
##### 2. ์กฐ๊ฑด ์ค์ ์น์
์ถ๊ฐ
```tsx
// control.html์ ์ ์ด ์กฐ๊ฑด ์ค์ ์น์
์ ์ฐธ์กฐํ์ฌ ๊ตฌํ
๐ ์คํ ์กฐ๊ฑด ์ค์
```
##### 3. ์ก์
์ค์ ์น์
```tsx
โก ์คํ ์ก์
{config.connectionType === "data-save" && }
{config.connectionType === "external-call" && }
```
### ์๋ก์ด ์ปดํฌ๋ํธ ๊ตฌ์กฐ
```
ConnectionSetupModal.tsx
โโโ BasicConnectionInfo (๊ณตํต)
โโโ ConnectionTypeSelector (๊ณตํต)
โโโ SimpleKeyConnectionSettings (๋จ์ ํค๊ฐ ์ ์ฉ)
โโโ ConditionalConnectionSettings (์กฐ๊ฑด๋ถ ์ฐ๊ฒฐ ์ ์ฉ)
โโโ ConditionBuilder (์กฐ๊ฑด ์ค์ )
โโโ DataSaveActionSettings (๋ฐ์ดํฐ ์ ์ฅ ์ก์
)
โโโ ExternalCallActionSettings (์ธ๋ถ ํธ์ถ ์ก์
)
```
## โ๏ธ ๋ฐฑ์๋ ์๋น์ค ๊ตฌํ
### 1. EventTriggerService ์์ฑ
```typescript
// backend-node/src/services/eventTriggerService.ts
export class EventTriggerService {
static async executeEventTriggers(
triggerType: "insert" | "update" | "delete",
tableName: string,
data: Record,
companyCode: string
): Promise;
static async executeDataSaveAction(
action: TargetAction,
sourceData: Record
): Promise;
static async executeExternalCallAction(
action: ExternalCallAction,
sourceData: Record
): Promise;
}
```
### 2. DynamicFormService ์ฐ๋
```typescript
// ๊ธฐ์กด saveFormData ๋ฉ์๋์ ํธ๋ฆฌ๊ฑฐ ์คํ ์ถ๊ฐ
async saveFormData(screenId: number, tableName: string, data: Record) {
// ๊ธฐ์กด ์ ์ฅ ๋ก์ง
const result = await this.saveToDatabase(data);
// ๐ฅ ์กฐ๊ฑด๋ถ ์ฐ๊ฒฐ ์คํ
await EventTriggerService.executeEventTriggers("insert", tableName, data, companyCode);
return result;
}
```
### 3. API ์๋ํฌ์ธํธ ์ถ๊ฐ
```typescript
// backend-node/src/routes/dataflowRoutes.ts
router.post("/diagrams/:id/test-conditions", async (req, res) => {
// ์กฐ๊ฑด ํ
์คํธ ์คํ
});
router.post("/diagrams/:id/execute-actions", async (req, res) => {
// ์ก์
์๋ ์คํ
});
```
## ๐ ๊ตฌํ ๋จ๊ณ๋ณ ๊ณํ
### Phase 1: ๋ฐ์ดํฐ๋ฒ ์ด์ค ์ค๋น
- [ ] dataflow_diagrams ํ
์ด๋ธ ์ปฌ๋ผ ์ถ๊ฐ (๊ธฐ์กด ๋ฐ์ดํฐ ์ญ์ ํ ์งํ)
- [ ] Prisma ์คํค๋ง ์
๋ฐ์ดํธ
### Phase 2: ํ๋ก ํธ์๋ UI ๊ฐ์
- [ ] ConnectionSetupModal.tsx ์ฌ๊ตฌ์กฐํ
- [ ] ConditionBuilder ์ปดํฌ๋ํธ ๊ฐ๋ฐ
- [ ] ์ฐ๊ฒฐ ์ข
๋ฅ๋ณ ์ค์ ์ปดํฌ๋ํธ ๋ถ๋ฆฌ
- [ ] control.html ์ฐธ์กฐํ์ฌ ์กฐ๊ฑด ์ค์ UI ๊ตฌํ
### Phase 3: ๋ฐฑ์๋ ์๋น์ค ๊ฐ๋ฐ
- [ ] EventTriggerService ๊ธฐ๋ณธ ๊ตฌ์กฐ ์์ฑ
- [ ] ์กฐ๊ฑด ํ๊ฐ ์์ง ๊ตฌํ
- [ ] ๋ฐ์ดํฐ ์ ์ฅ ์ก์
์คํ ๋ก์ง
- [ ] DynamicFormService ์ฐ๋
### Phase 4: ์ธ๋ถ ํธ์ถ ๊ธฐ๋ฅ
- [ ] ์ธ๋ถ API ํธ์ถ ์๋น์ค
- [ ] ์ด๋ฉ์ผ ๋ฐ์ก ๊ธฐ๋ฅ
- [ ] ์นํ
์ง์
- [ ] ์ค๋ฅ ์ฒ๋ฆฌ ๋ฐ ์ฌ์๋ ๋ก์ง
## ๐ง ๊ธฐ์ ์ ๊ณ ๋ ค์ฌํญ
### 1. ์ฑ๋ฅ ์ต์ ํ
- ์กฐ๊ฑด ํ๊ฐ ์ ์ธ๋ฑ์ค ํ์ฉ
- ๋๋ ๋ฐ์ดํฐ ์ฒ๋ฆฌ ์ ๋ฐฐ์น ์ฒ๋ฆฌ
- ๋น๋๊ธฐ ์คํ์ผ๋ก ๋ฉ์ธ ๋ก์ง ๋ธ๋กํน ๋ฐฉ์ง
### 2. ์ค๋ฅ ์ฒ๋ฆฌ
- ํธ๋์ญ์
๋กค๋ฐฑ ์ง์
- ๋ถ๋ถ ์คํจ ์ ๋ณต๊ตฌ ๋ฉ์ปค๋์ฆ
### 3. ๋ณด์
- SQL ์ธ์ ์
๋ฐฉ์ง
- ์ธ๋ถ API ํธ์ถ ์ ์ธ์ฆ ์ฒ๋ฆฌ
- ๋ฏผ๊ฐ ๋ฐ์ดํฐ ๋ง์คํน
### 4. ํ์ฅ์ฑ
- ์๋ก์ด ์ก์
ํ์
์ถ๊ฐ ์ฉ์ด์ฑ
- ๋ณต์กํ ์กฐ๊ฑด๋ฌธ ์ง์
- ๋ค์ํ ์ธ๋ถ ์๋น์ค ์ฐ๋
## ๐ ์ฐธ๊ณ ์๋ฃ
- [control.html](../control.html) - ์ ์ด ์กฐ๊ฑด ์ค์ UI ์ฐธ์กฐ
- [ConnectionSetupModal.tsx](../frontend/components/dataflow/ConnectionSetupModal.tsx) - ํ์ฌ ๊ตฌํ
- [ํ๋ฉด๊ฐ*๋ฐ์ดํฐ*๊ด๊ณ*์ค์ *์์คํ
\_์ค๊ณ.md](./ํ๋ฉด๊ฐ_๋ฐ์ดํฐ_๊ด๊ณ_์ค์ _์์คํ
_์ค๊ณ.md) - ์ ์ฒด ์์คํ
์ค๊ณ
## ๐ ๋ค์ ๋จ๊ณ
1. **๋ฐ์ดํฐ๋ฒ ์ด์ค ์คํค๋ง ์
๋ฐ์ดํธ** ๋ถํฐ ์์
2. **UI ์ฌ์ค๊ณ** - control.html ์ฐธ์กฐํ์ฌ ์กฐ๊ฑด ์ค์ UI ๊ตฌํ
3. **๋ฐฑ์๋ ์๋น์ค** ๋จ๊ณ๋ณ ๊ตฌํ
4. **์ธ๋ถ ํธ์ถ ๊ธฐ๋ฅ** ๊ตฌํ
---
_์ด ๋ฌธ์๋ ์กฐ๊ฑด๋ถ ์ฐ๊ฒฐ ๊ธฐ๋ฅ ๊ตฌํ์ ์ํ ์ ์ฒด์ ์ธ ๋ก๋๋งต์ ์ ์ํฉ๋๋ค. ๊ฐ ๋จ๊ณ๋ณ๋ก ์์ธํ ๊ตฌํ ๊ณํ์ ์๋ฆฝํ์ฌ ์งํํ ์์ ์
๋๋ค._