create-entity-server 0.0.9 → 0.0.23
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/bin/create.js +26 -8
- package/package.json +1 -1
- package/template/.env.example +20 -3
- package/template/configs/database.json +173 -10
- package/template/configs/jwt.json +1 -0
- package/template/configs/oauth.json +37 -0
- package/template/configs/push.json +26 -0
- package/template/entities/Account/account_audit.json +4 -5
- package/template/entities/README.md +4 -4
- package/template/entities/{Auth → System/Auth}/account.json +0 -14
- package/template/entities/System/system_audit_log.json +14 -8
- package/template/samples/README.md +43 -21
- package/template/samples/browser/entity-server-client.js +453 -0
- package/template/samples/browser/example.html +498 -0
- package/template/samples/entities/01_basic_fields.json +39 -0
- package/template/samples/entities/02_types_and_defaults.json +67 -0
- package/template/samples/entities/03_hash_and_unique.json +33 -0
- package/template/samples/entities/04_fk_and_composite_unique.json +29 -0
- package/template/samples/entities/05_cache.json +55 -0
- package/template/samples/entities/06_history_and_hard_delete.json +60 -0
- package/template/samples/entities/07_license_scope.json +52 -0
- package/template/samples/entities/08_hook_sql.json +52 -0
- package/template/samples/entities/09_hook_entity.json +65 -0
- package/template/samples/entities/10_hook_submit_delete.json +78 -0
- package/template/samples/entities/11_hook_webhook.json +84 -0
- package/template/samples/entities/12_hook_push.json +73 -0
- package/template/samples/entities/13_read_only.json +54 -0
- package/template/samples/entities/14_optimistic_lock.json +29 -0
- package/template/samples/entities/15_reset_defaults.json +94 -0
- package/template/samples/entities/16_isolated_license.json +62 -0
- package/template/samples/entities/README.md +91 -0
- package/template/samples/flutter/lib/entity_server_client.dart +261 -48
- package/template/samples/java/EntityServerClient.java +325 -61
- package/template/samples/java/EntityServerExample.java +4 -3
- package/template/samples/kotlin/EntityServerClient.kt +261 -45
- package/template/samples/node/src/EntityServerClient.js +348 -59
- package/template/samples/node/src/example.js +9 -9
- package/template/samples/php/ci4/Config/EntityServer.php +14 -0
- package/template/samples/php/ci4/Controllers/EntityController.php +202 -0
- package/template/samples/php/ci4/Controllers/ProductController.php +16 -76
- package/template/samples/php/ci4/Libraries/EntityServer.php +352 -60
- package/template/samples/php/laravel/Services/EntityServerService.php +245 -40
- package/template/samples/python/entity_server.py +287 -68
- package/template/samples/python/example.py +7 -6
- package/template/samples/react/src/example.tsx +41 -25
- package/template/samples/swift/EntityServerClient.swift +248 -37
- package/template/scripts/normalize-entities.sh +10 -10
- package/template/scripts/run.ps1 +12 -3
- package/template/scripts/run.sh +120 -37
- package/template/scripts/update-server.ps1 +160 -4
- package/template/scripts/update-server.sh +132 -4
- package/template/samples/react/src/api/entityServerClient.ts +0 -290
- package/template/samples/react/src/hooks/useEntity.ts +0 -105
- /package/template/entities/{Auth → System/Auth}/api_keys.json +0 -0
- /package/template/entities/{Auth → System/Auth}/license.json +0 -0
- /package/template/entities/{Auth → System/Auth}/rbac_roles.json +0 -0
|
@@ -0,0 +1,55 @@
|
|
|
1
|
+
{
|
|
2
|
+
"name": "config_item",
|
|
3
|
+
"description": "캐시 예제 — 자주 읽히고 드물게 변경되는 설정값에 엔티티 레벨 캐시 활성화",
|
|
4
|
+
"index": {
|
|
5
|
+
"key": {
|
|
6
|
+
"comment": "설정 키 (고유)",
|
|
7
|
+
"required": true,
|
|
8
|
+
"unique": true
|
|
9
|
+
},
|
|
10
|
+
"category": {
|
|
11
|
+
"comment": "설정 카테고리",
|
|
12
|
+
"type": ["system", "ui", "feature_flag", "notification"],
|
|
13
|
+
"default": "system"
|
|
14
|
+
},
|
|
15
|
+
"is_public": {
|
|
16
|
+
"comment": "공개 여부 (is_* → TINYINT(1) 자동 추론)"
|
|
17
|
+
}
|
|
18
|
+
},
|
|
19
|
+
"cache": {
|
|
20
|
+
"enabled": true,
|
|
21
|
+
"ttl_seconds": 600
|
|
22
|
+
},
|
|
23
|
+
"fields": {
|
|
24
|
+
"value": {
|
|
25
|
+
"comment": "설정 값 (문자열 저장, 타입은 애플리케이션에서 해석)",
|
|
26
|
+
"required": true
|
|
27
|
+
},
|
|
28
|
+
"description": {
|
|
29
|
+
"comment": "설정 항목 설명"
|
|
30
|
+
}
|
|
31
|
+
},
|
|
32
|
+
"reset_defaults": [
|
|
33
|
+
{
|
|
34
|
+
"key": "site.name",
|
|
35
|
+
"category": "system",
|
|
36
|
+
"value": "My Service",
|
|
37
|
+
"is_public": true,
|
|
38
|
+
"description": "서비스명"
|
|
39
|
+
},
|
|
40
|
+
{
|
|
41
|
+
"key": "feature.dark_mode",
|
|
42
|
+
"category": "feature_flag",
|
|
43
|
+
"value": "true",
|
|
44
|
+
"is_public": true,
|
|
45
|
+
"description": "다크모드 기능 활성화"
|
|
46
|
+
},
|
|
47
|
+
{
|
|
48
|
+
"key": "notification.email_enabled",
|
|
49
|
+
"category": "notification",
|
|
50
|
+
"value": "true",
|
|
51
|
+
"is_public": false,
|
|
52
|
+
"description": "이메일 알림 활성화"
|
|
53
|
+
}
|
|
54
|
+
]
|
|
55
|
+
}
|
|
@@ -0,0 +1,60 @@
|
|
|
1
|
+
{
|
|
2
|
+
"name": "article",
|
|
3
|
+
"description": "이력 보존(history_ttl) & 완전삭제(hard_delete) 예제 — 게시글 수정 이력 3년 보관",
|
|
4
|
+
"index": {
|
|
5
|
+
"author_seq": {
|
|
6
|
+
"comment": "작성자 user seq",
|
|
7
|
+
"required": true
|
|
8
|
+
},
|
|
9
|
+
"title": {
|
|
10
|
+
"comment": "제목",
|
|
11
|
+
"required": true
|
|
12
|
+
},
|
|
13
|
+
"category": {
|
|
14
|
+
"comment": "카테고리",
|
|
15
|
+
"type": ["notice", "blog", "faq", "news"],
|
|
16
|
+
"default": "blog"
|
|
17
|
+
},
|
|
18
|
+
"status": {
|
|
19
|
+
"comment": "게시 상태",
|
|
20
|
+
"type": ["draft", "published", "archived"],
|
|
21
|
+
"default": "draft"
|
|
22
|
+
},
|
|
23
|
+
"published_at": {
|
|
24
|
+
"comment": "게시일시 (*_at → DATETIME 자동 추론)"
|
|
25
|
+
},
|
|
26
|
+
"view_count": {
|
|
27
|
+
"comment": "조회 수 (*_count → INT 자동 추론)"
|
|
28
|
+
}
|
|
29
|
+
},
|
|
30
|
+
"fields": {
|
|
31
|
+
"content": {
|
|
32
|
+
"type": "longtext",
|
|
33
|
+
"comment": "게시글 본문",
|
|
34
|
+
"required": true
|
|
35
|
+
},
|
|
36
|
+
"summary": {
|
|
37
|
+
"type": "text",
|
|
38
|
+
"comment": "요약 (없으면 본문 앞 200자 자동 생성)"
|
|
39
|
+
},
|
|
40
|
+
"meta": {
|
|
41
|
+
"comment": "SEO / 부가 메타데이터 그룹 (중첩 fields 예제)",
|
|
42
|
+
"fields": {
|
|
43
|
+
"og_title": {
|
|
44
|
+
"type": "varchar(200)",
|
|
45
|
+
"comment": "OG 제목 (미입력 시 title 사용)"
|
|
46
|
+
},
|
|
47
|
+
"og_image_url": {
|
|
48
|
+
"type": "varchar(500)",
|
|
49
|
+
"comment": "OG 이미지 URL"
|
|
50
|
+
},
|
|
51
|
+
"tags_json": {
|
|
52
|
+
"type": "json",
|
|
53
|
+
"comment": "태그 목록 (JSON 배열)"
|
|
54
|
+
}
|
|
55
|
+
}
|
|
56
|
+
}
|
|
57
|
+
},
|
|
58
|
+
"history_ttl": 1095,
|
|
59
|
+
"hard_delete": false
|
|
60
|
+
}
|
|
@@ -0,0 +1,52 @@
|
|
|
1
|
+
{
|
|
2
|
+
"name": "exchange_rate",
|
|
3
|
+
"description": "license_scope: false 예제 — 전 라이선스 공용 기준 데이터 (환율). license_seq 컬럼 없이 모든 테넌트가 동일 데이터 공유",
|
|
4
|
+
"license_scope": false,
|
|
5
|
+
"index": {
|
|
6
|
+
"base_currency": {
|
|
7
|
+
"comment": "기준 통화 (ISO 4217)",
|
|
8
|
+
"type": "varchar(3)",
|
|
9
|
+
"required": true
|
|
10
|
+
},
|
|
11
|
+
"quote_currency": {
|
|
12
|
+
"comment": "환산 통화 (ISO 4217)",
|
|
13
|
+
"type": "varchar(3)",
|
|
14
|
+
"required": true
|
|
15
|
+
},
|
|
16
|
+
"rate": {
|
|
17
|
+
"comment": "환산 비율 (*_rate → 자동추론 없음, decimal 명시)",
|
|
18
|
+
"type": "decimal",
|
|
19
|
+
"required": true
|
|
20
|
+
},
|
|
21
|
+
"effective_date": {
|
|
22
|
+
"comment": "적용일 (*_date → DATE 자동 추론)",
|
|
23
|
+
"required": true
|
|
24
|
+
},
|
|
25
|
+
"source": {
|
|
26
|
+
"comment": "환율 출처",
|
|
27
|
+
"type": ["ecb", "openexchangerates", "manual"],
|
|
28
|
+
"default": "manual"
|
|
29
|
+
}
|
|
30
|
+
},
|
|
31
|
+
"cache": {
|
|
32
|
+
"enabled": true,
|
|
33
|
+
"ttl_seconds": 3600
|
|
34
|
+
},
|
|
35
|
+
"unique": [["base_currency", "quote_currency", "effective_date"]],
|
|
36
|
+
"reset_defaults": [
|
|
37
|
+
{
|
|
38
|
+
"base_currency": "USD",
|
|
39
|
+
"quote_currency": "KRW",
|
|
40
|
+
"rate": 1350.0,
|
|
41
|
+
"effective_date": "2025-01-01",
|
|
42
|
+
"source": "manual"
|
|
43
|
+
},
|
|
44
|
+
{
|
|
45
|
+
"base_currency": "EUR",
|
|
46
|
+
"quote_currency": "KRW",
|
|
47
|
+
"rate": 1480.0,
|
|
48
|
+
"effective_date": "2025-01-01",
|
|
49
|
+
"source": "manual"
|
|
50
|
+
}
|
|
51
|
+
]
|
|
52
|
+
}
|
|
@@ -0,0 +1,52 @@
|
|
|
1
|
+
{
|
|
2
|
+
"name": "user_point",
|
|
3
|
+
"description": "SQL 훅 예제 — INSERT/UPDATE 시 자동 감사 로그 기록 (실행형) + SELECT 결과 주입 (조회형)",
|
|
4
|
+
"index": {
|
|
5
|
+
"user_seq": {
|
|
6
|
+
"comment": "사용자 seq",
|
|
7
|
+
"required": true,
|
|
8
|
+
"unique": true
|
|
9
|
+
},
|
|
10
|
+
"point": {
|
|
11
|
+
"comment": "보유 포인트",
|
|
12
|
+
"type": "uint"
|
|
13
|
+
},
|
|
14
|
+
"grade": {
|
|
15
|
+
"comment": "등급",
|
|
16
|
+
"type": ["bronze", "silver", "gold", "platinum"],
|
|
17
|
+
"default": "bronze"
|
|
18
|
+
},
|
|
19
|
+
"updated_at": {
|
|
20
|
+
"comment": "마지막 포인트 변경일시 (*_at → DATETIME 자동 추론)"
|
|
21
|
+
}
|
|
22
|
+
},
|
|
23
|
+
"hooks": {
|
|
24
|
+
"after_insert": [
|
|
25
|
+
{
|
|
26
|
+
"comment": "포인트 생성 이력 기록 (실행형 SQL 훅)",
|
|
27
|
+
"type": "sql",
|
|
28
|
+
"query": "INSERT INTO point_history (user_seq, delta, reason, created_time) VALUES (?, ?, ?, NOW())",
|
|
29
|
+
"params": ["${new.user_seq}", "${new.point}", "initial_grant"],
|
|
30
|
+
"async": false
|
|
31
|
+
}
|
|
32
|
+
],
|
|
33
|
+
"after_update": [
|
|
34
|
+
{
|
|
35
|
+
"comment": "포인트 변경 이력 기록 (실행형 SQL 훅)",
|
|
36
|
+
"type": "sql",
|
|
37
|
+
"query": "INSERT INTO point_history (user_seq, delta, reason, created_time) VALUES (?, ?, ?, NOW())",
|
|
38
|
+
"params": ["${new.user_seq}", "${new.point}", "update"],
|
|
39
|
+
"async": true
|
|
40
|
+
}
|
|
41
|
+
],
|
|
42
|
+
"after_get": [
|
|
43
|
+
{
|
|
44
|
+
"comment": "최근 포인트 변경 이력 5건 주입 (조회형 SQL 훅)",
|
|
45
|
+
"type": "sql",
|
|
46
|
+
"query": "SELECT delta, reason, created_time FROM point_history WHERE user_seq = ? ORDER BY created_time DESC LIMIT 5",
|
|
47
|
+
"params": ["${new.user_seq}"],
|
|
48
|
+
"assign_to": "recent_history"
|
|
49
|
+
}
|
|
50
|
+
]
|
|
51
|
+
}
|
|
52
|
+
}
|
|
@@ -0,0 +1,65 @@
|
|
|
1
|
+
{
|
|
2
|
+
"name": "post",
|
|
3
|
+
"description": "entity 훅 예제 — after_get/after_list 시 관련 엔티티 데이터를 자동 주입",
|
|
4
|
+
"index": {
|
|
5
|
+
"author_seq": {
|
|
6
|
+
"comment": "작성자 user seq",
|
|
7
|
+
"required": true
|
|
8
|
+
},
|
|
9
|
+
"title": {
|
|
10
|
+
"comment": "제목",
|
|
11
|
+
"required": true
|
|
12
|
+
},
|
|
13
|
+
"status": {
|
|
14
|
+
"comment": "상태",
|
|
15
|
+
"type": ["draft", "published", "hidden"],
|
|
16
|
+
"default": "draft"
|
|
17
|
+
},
|
|
18
|
+
"comment_count": {
|
|
19
|
+
"comment": "댓글 수 (*_count → INT 자동 추론)"
|
|
20
|
+
},
|
|
21
|
+
"like_count": {
|
|
22
|
+
"comment": "좋아요 수 (*_count → INT 자동 추론)"
|
|
23
|
+
},
|
|
24
|
+
"published_at": {
|
|
25
|
+
"comment": "게시일시 (*_at → DATETIME 자동 추론)"
|
|
26
|
+
}
|
|
27
|
+
},
|
|
28
|
+
"hooks": {
|
|
29
|
+
"after_get": [
|
|
30
|
+
{
|
|
31
|
+
"comment": "게시글 조회 시 작성자 프로필 자동 주입",
|
|
32
|
+
"type": "entity",
|
|
33
|
+
"entity": "user",
|
|
34
|
+
"action": "get",
|
|
35
|
+
"conditions": {
|
|
36
|
+
"seq": "${new.author_seq}"
|
|
37
|
+
},
|
|
38
|
+
"assign_to": "author"
|
|
39
|
+
},
|
|
40
|
+
{
|
|
41
|
+
"comment": "게시글 조회 시 최근 댓글 10개 자동 주입",
|
|
42
|
+
"type": "entity",
|
|
43
|
+
"entity": "comment",
|
|
44
|
+
"action": "list",
|
|
45
|
+
"conditions": {
|
|
46
|
+
"post_seq": "${new.seq}",
|
|
47
|
+
"status": "visible"
|
|
48
|
+
},
|
|
49
|
+
"assign_to": "comments"
|
|
50
|
+
}
|
|
51
|
+
],
|
|
52
|
+
"after_list": [
|
|
53
|
+
{
|
|
54
|
+
"comment": "목록 조회 시 각 게시글에 작성자 이름 주입",
|
|
55
|
+
"type": "entity",
|
|
56
|
+
"entity": "user",
|
|
57
|
+
"action": "get",
|
|
58
|
+
"conditions": {
|
|
59
|
+
"seq": "${new.author_seq}"
|
|
60
|
+
},
|
|
61
|
+
"assign_to": "author"
|
|
62
|
+
}
|
|
63
|
+
]
|
|
64
|
+
}
|
|
65
|
+
}
|
|
@@ -0,0 +1,78 @@
|
|
|
1
|
+
{
|
|
2
|
+
"name": "project",
|
|
3
|
+
"description": "submit & delete 훅 예제 — 프로젝트 생성 시 기본 태스크 자동 생성, 삭제 시 연관 데이터 정리",
|
|
4
|
+
"index": {
|
|
5
|
+
"owner_seq": {
|
|
6
|
+
"comment": "프로젝트 소유자 user seq",
|
|
7
|
+
"required": true
|
|
8
|
+
},
|
|
9
|
+
"name": {
|
|
10
|
+
"comment": "프로젝트명",
|
|
11
|
+
"required": true
|
|
12
|
+
},
|
|
13
|
+
"status": {
|
|
14
|
+
"comment": "진행 상태",
|
|
15
|
+
"type": ["planning", "active", "on_hold", "completed", "cancelled"],
|
|
16
|
+
"default": "planning"
|
|
17
|
+
},
|
|
18
|
+
"due_date": {
|
|
19
|
+
"comment": "마감일 (*_date → DATE 자동 추론)"
|
|
20
|
+
},
|
|
21
|
+
"task_count": {
|
|
22
|
+
"comment": "태스크 수 (*_count → INT 자동 추론)"
|
|
23
|
+
}
|
|
24
|
+
},
|
|
25
|
+
"fields": {
|
|
26
|
+
"description": {
|
|
27
|
+
"type": "text",
|
|
28
|
+
"comment": "프로젝트 설명"
|
|
29
|
+
}
|
|
30
|
+
},
|
|
31
|
+
"hooks": {
|
|
32
|
+
"after_insert": [
|
|
33
|
+
{
|
|
34
|
+
"comment": "프로젝트 생성 시 기본 태스크 3개 자동 생성 (submit 훅)",
|
|
35
|
+
"type": "submit",
|
|
36
|
+
"entity": "task",
|
|
37
|
+
"data": {
|
|
38
|
+
"project_seq": "${new.seq}",
|
|
39
|
+
"title": "요구사항 분석",
|
|
40
|
+
"status": "todo",
|
|
41
|
+
"priority": "high"
|
|
42
|
+
}
|
|
43
|
+
},
|
|
44
|
+
{
|
|
45
|
+
"comment": "프로젝트 멤버에 소유자 자동 추가 (submit 훅 Upsert)",
|
|
46
|
+
"type": "submit",
|
|
47
|
+
"entity": "project_member",
|
|
48
|
+
"match": {
|
|
49
|
+
"project_seq": "${new.seq}",
|
|
50
|
+
"user_seq": "${new.owner_seq}"
|
|
51
|
+
},
|
|
52
|
+
"data": {
|
|
53
|
+
"project_seq": "${new.seq}",
|
|
54
|
+
"user_seq": "${new.owner_seq}",
|
|
55
|
+
"role": "owner"
|
|
56
|
+
}
|
|
57
|
+
}
|
|
58
|
+
],
|
|
59
|
+
"after_delete": [
|
|
60
|
+
{
|
|
61
|
+
"comment": "프로젝트 삭제 시 모든 태스크 삭제 (delete 훅)",
|
|
62
|
+
"type": "delete",
|
|
63
|
+
"entity": "task",
|
|
64
|
+
"match": {
|
|
65
|
+
"project_seq": "${old.seq}"
|
|
66
|
+
}
|
|
67
|
+
},
|
|
68
|
+
{
|
|
69
|
+
"comment": "프로젝트 삭제 시 멤버 목록 삭제 (delete 훅)",
|
|
70
|
+
"type": "delete",
|
|
71
|
+
"entity": "project_member",
|
|
72
|
+
"match": {
|
|
73
|
+
"project_seq": "${old.seq}"
|
|
74
|
+
}
|
|
75
|
+
}
|
|
76
|
+
]
|
|
77
|
+
}
|
|
78
|
+
}
|
|
@@ -0,0 +1,84 @@
|
|
|
1
|
+
{
|
|
2
|
+
"name": "payment",
|
|
3
|
+
"description": "webhook 훅 예제 — 결제 완료/환불 시 외부 정산 서비스 실시간 통보",
|
|
4
|
+
"index": {
|
|
5
|
+
"order_seq": {
|
|
6
|
+
"comment": "주문 seq",
|
|
7
|
+
"required": true
|
|
8
|
+
},
|
|
9
|
+
"user_seq": {
|
|
10
|
+
"comment": "결제자 user seq",
|
|
11
|
+
"required": true
|
|
12
|
+
},
|
|
13
|
+
"amount": {
|
|
14
|
+
"comment": "결제 금액 (*_amount → DECIMAL(15,2) 자동 추론)",
|
|
15
|
+
"required": true
|
|
16
|
+
},
|
|
17
|
+
"method": {
|
|
18
|
+
"comment": "결제 수단",
|
|
19
|
+
"type": ["card", "bank_transfer", "virtual_account", "point"],
|
|
20
|
+
"required": true
|
|
21
|
+
},
|
|
22
|
+
"status": {
|
|
23
|
+
"comment": "결제 상태",
|
|
24
|
+
"type": ["pending", "paid", "cancelled", "refunded"],
|
|
25
|
+
"default": "pending"
|
|
26
|
+
},
|
|
27
|
+
"paid_at": {
|
|
28
|
+
"comment": "결제 완료일시 (*_at → DATETIME 자동 추론)"
|
|
29
|
+
}
|
|
30
|
+
},
|
|
31
|
+
"fields": {
|
|
32
|
+
"pg_transaction_id": {
|
|
33
|
+
"type": "varchar(100)",
|
|
34
|
+
"comment": "PG사 거래 ID"
|
|
35
|
+
},
|
|
36
|
+
"failure_reason": {
|
|
37
|
+
"type": "text",
|
|
38
|
+
"comment": "결제 실패 사유"
|
|
39
|
+
}
|
|
40
|
+
},
|
|
41
|
+
"hooks": {
|
|
42
|
+
"after_insert": [
|
|
43
|
+
{
|
|
44
|
+
"comment": "결제 생성 시 정산 서버로 비동기 통보 (webhook 훅)",
|
|
45
|
+
"type": "webhook",
|
|
46
|
+
"url": "https://settlement.internal/hooks/payment-created",
|
|
47
|
+
"method": "POST",
|
|
48
|
+
"headers": {
|
|
49
|
+
"Authorization": "Bearer ${ctx.webhook_secret}",
|
|
50
|
+
"Content-Type": "application/json"
|
|
51
|
+
},
|
|
52
|
+
"body": {
|
|
53
|
+
"payment_seq": "${new.seq}",
|
|
54
|
+
"order_seq": "${new.order_seq}",
|
|
55
|
+
"user_seq": "${new.user_seq}",
|
|
56
|
+
"amount": "${new.amount}",
|
|
57
|
+
"method": "${new.method}",
|
|
58
|
+
"status": "${new.status}"
|
|
59
|
+
},
|
|
60
|
+
"async": true,
|
|
61
|
+
"timeout": 5000
|
|
62
|
+
}
|
|
63
|
+
],
|
|
64
|
+
"after_update": [
|
|
65
|
+
{
|
|
66
|
+
"comment": "결제 상태 변경(환불 등) 시 정산 서버에 동기 통보 (webhook 훅)",
|
|
67
|
+
"type": "webhook",
|
|
68
|
+
"url": "https://settlement.internal/hooks/payment-updated",
|
|
69
|
+
"method": "POST",
|
|
70
|
+
"headers": {
|
|
71
|
+
"Authorization": "Bearer ${ctx.webhook_secret}"
|
|
72
|
+
},
|
|
73
|
+
"body": {
|
|
74
|
+
"payment_seq": "${new.seq}",
|
|
75
|
+
"old_status": "${old.status}",
|
|
76
|
+
"new_status": "${new.status}",
|
|
77
|
+
"amount": "${new.amount}"
|
|
78
|
+
},
|
|
79
|
+
"async": false,
|
|
80
|
+
"timeout": 8000
|
|
81
|
+
}
|
|
82
|
+
]
|
|
83
|
+
}
|
|
84
|
+
}
|
|
@@ -0,0 +1,73 @@
|
|
|
1
|
+
{
|
|
2
|
+
"name": "delivery",
|
|
3
|
+
"description": "push 훅 예제 — 배송 상태 변경 시 고객에게 푸시 알림 전송 (FCM / APNs 공통, 다단계 상태 알림)",
|
|
4
|
+
"index": {
|
|
5
|
+
"order_seq": {
|
|
6
|
+
"comment": "주문 seq",
|
|
7
|
+
"required": true
|
|
8
|
+
},
|
|
9
|
+
"customer_seq": {
|
|
10
|
+
"comment": "고객 user seq",
|
|
11
|
+
"required": true
|
|
12
|
+
},
|
|
13
|
+
"tracking_number": {
|
|
14
|
+
"comment": "운송장 번호",
|
|
15
|
+
"unique": true
|
|
16
|
+
},
|
|
17
|
+
"carrier": {
|
|
18
|
+
"comment": "택배사",
|
|
19
|
+
"type": ["cj", "lotte", "hanjin", "post", "direct"],
|
|
20
|
+
"default": "cj"
|
|
21
|
+
},
|
|
22
|
+
"status": {
|
|
23
|
+
"comment": "배송 상태",
|
|
24
|
+
"type": [
|
|
25
|
+
"ready",
|
|
26
|
+
"picked_up",
|
|
27
|
+
"in_transit",
|
|
28
|
+
"out_for_delivery",
|
|
29
|
+
"delivered",
|
|
30
|
+
"failed"
|
|
31
|
+
],
|
|
32
|
+
"default": "ready"
|
|
33
|
+
},
|
|
34
|
+
"estimated_date": {
|
|
35
|
+
"comment": "예상 도착일 (*_date → DATE 자동 추론)"
|
|
36
|
+
},
|
|
37
|
+
"delivered_at": {
|
|
38
|
+
"comment": "배송 완료일시 (*_at → DATETIME 자동 추론)"
|
|
39
|
+
}
|
|
40
|
+
},
|
|
41
|
+
"hooks": {
|
|
42
|
+
"after_insert": [
|
|
43
|
+
{
|
|
44
|
+
"comment": "배송 시작 푸시 알림",
|
|
45
|
+
"type": "push",
|
|
46
|
+
"target_account_seq": "customer_seq",
|
|
47
|
+
"title": "배송 시작",
|
|
48
|
+
"push_body": "주문 #${new.order_seq}의 배송이 시작되었습니다. 운송장: ${new.tracking_number}",
|
|
49
|
+
"push_data": {
|
|
50
|
+
"action": "delivery_started",
|
|
51
|
+
"delivery_seq": "${new.seq}",
|
|
52
|
+
"tracking_number": "${new.tracking_number}"
|
|
53
|
+
}
|
|
54
|
+
}
|
|
55
|
+
],
|
|
56
|
+
"after_update": [
|
|
57
|
+
{
|
|
58
|
+
"comment": "배송 상태 변경 시 푸시 알림",
|
|
59
|
+
"type": "push",
|
|
60
|
+
"target_account_seq": "customer_seq",
|
|
61
|
+
"title": "배송 상태 업데이트",
|
|
62
|
+
"push_body": "배송 상태가 '${new.status}'(으)로 변경되었습니다. 운송장: ${new.tracking_number}",
|
|
63
|
+
"push_data": {
|
|
64
|
+
"action": "delivery_status_changed",
|
|
65
|
+
"delivery_seq": "${new.seq}",
|
|
66
|
+
"old_status": "${old.status}",
|
|
67
|
+
"new_status": "${new.status}",
|
|
68
|
+
"tracking_number": "${new.tracking_number}"
|
|
69
|
+
}
|
|
70
|
+
}
|
|
71
|
+
]
|
|
72
|
+
}
|
|
73
|
+
}
|
|
@@ -0,0 +1,54 @@
|
|
|
1
|
+
{
|
|
2
|
+
"name": "activity_log",
|
|
3
|
+
"description": "read_only 예제 — API를 통한 수정·삭제가 불가하고 서버 내부(훅/SP) 로만 기록되는 감사 로그",
|
|
4
|
+
"read_only": true,
|
|
5
|
+
"hard_delete": true,
|
|
6
|
+
"history_ttl": 0,
|
|
7
|
+
"index": {
|
|
8
|
+
"actor_seq": {
|
|
9
|
+
"comment": "행위자 user seq (null = 시스템)"
|
|
10
|
+
},
|
|
11
|
+
"entity_name": {
|
|
12
|
+
"comment": "대상 엔티티명",
|
|
13
|
+
"required": true
|
|
14
|
+
},
|
|
15
|
+
"entity_seq": {
|
|
16
|
+
"comment": "대상 레코드 seq"
|
|
17
|
+
},
|
|
18
|
+
"action": {
|
|
19
|
+
"comment": "수행된 작업",
|
|
20
|
+
"type": [
|
|
21
|
+
"INSERT",
|
|
22
|
+
"UPDATE",
|
|
23
|
+
"DELETE",
|
|
24
|
+
"LOGIN",
|
|
25
|
+
"LOGOUT",
|
|
26
|
+
"EXPORT",
|
|
27
|
+
"IMPORT"
|
|
28
|
+
],
|
|
29
|
+
"required": true
|
|
30
|
+
},
|
|
31
|
+
"ip_address": {
|
|
32
|
+
"comment": "요청 IP",
|
|
33
|
+
"type": "varchar(45)"
|
|
34
|
+
},
|
|
35
|
+
"result_code": {
|
|
36
|
+
"comment": "결과 코드 (HTTP 상태)",
|
|
37
|
+
"type": "int"
|
|
38
|
+
}
|
|
39
|
+
},
|
|
40
|
+
"fields": {
|
|
41
|
+
"before_snapshot": {
|
|
42
|
+
"type": "json",
|
|
43
|
+
"comment": "변경 전 데이터 스냅샷"
|
|
44
|
+
},
|
|
45
|
+
"after_snapshot": {
|
|
46
|
+
"type": "json",
|
|
47
|
+
"comment": "변경 후 데이터 스냅샷"
|
|
48
|
+
},
|
|
49
|
+
"detail": {
|
|
50
|
+
"type": "text",
|
|
51
|
+
"comment": "작업 상세 설명"
|
|
52
|
+
}
|
|
53
|
+
}
|
|
54
|
+
}
|
|
@@ -0,0 +1,29 @@
|
|
|
1
|
+
{
|
|
2
|
+
"name": "inventory",
|
|
3
|
+
"description": "optimistic_lock 예제 — 동시 수정 충돌 방지가 필요한 재고 엔티티",
|
|
4
|
+
"optimistic_lock": true,
|
|
5
|
+
"index": {
|
|
6
|
+
"product_seq": {
|
|
7
|
+
"comment": "상품 seq",
|
|
8
|
+
"required": true,
|
|
9
|
+
"unique": true
|
|
10
|
+
},
|
|
11
|
+
"warehouse_code": {
|
|
12
|
+
"comment": "창고 코드",
|
|
13
|
+
"required": true
|
|
14
|
+
},
|
|
15
|
+
"qty_available": {
|
|
16
|
+
"comment": "가용 재고 수량 (*_qty → INT 자동 추론)"
|
|
17
|
+
},
|
|
18
|
+
"qty_reserved": {
|
|
19
|
+
"comment": "예약된 재고 수량 (*_qty → INT 자동 추론)"
|
|
20
|
+
},
|
|
21
|
+
"location": {
|
|
22
|
+
"comment": "창고 내 위치 (예: A-01-03)"
|
|
23
|
+
},
|
|
24
|
+
"last_stocked_at": {
|
|
25
|
+
"comment": "마지막 입고일시 (*_at → DATETIME 자동 추론)"
|
|
26
|
+
}
|
|
27
|
+
},
|
|
28
|
+
"unique": [["product_seq", "warehouse_code"]]
|
|
29
|
+
}
|