create-entity-server 0.0.31 → 0.2.5

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.
Files changed (47) hide show
  1. package/bin/create.js +4 -0
  2. package/package.json +1 -1
  3. package/template/configs/database.json +2 -2
  4. package/template/entities/README.md +3 -3
  5. package/template/entities/System/Address/addr_dong.json +10115 -0
  6. package/template/entities/System/Address/addr_sido.json +39 -0
  7. package/template/entities/System/Address/addr_sigungu.json +1398 -0
  8. package/template/entities/System/Auth/account.json +0 -64
  9. package/template/entities/System/Auth/account_device.json +7 -22
  10. package/template/entities/System/Auth/account_login_log.json +3 -8
  11. package/template/entities/System/Auth/anon_device.json +56 -0
  12. package/template/scripts/api-key.sh +5 -2
  13. package/template/scripts/cleanup-history.sh +9 -4
  14. package/template/scripts/cli.sh +5 -2
  15. package/template/scripts/entity.sh +9 -4
  16. package/template/scripts/install-systemd.sh +7 -3
  17. package/template/scripts/normalize-entities.sh +9 -4
  18. package/template/scripts/rbac-role.sh +5 -2
  19. package/template/scripts/reset-all.sh +91 -13
  20. package/template/scripts/run.sh +73 -27
  21. package/template/scripts/sync.sh +9 -4
  22. package/template/configs/auth/oauth.json +0 -40
  23. package/template/configs/auth/password.json +0 -45
  24. package/template/configs/keys/apns.p8.example +0 -7
  25. package/template/configs/keys/firebase.pem.example +0 -7
  26. package/template/configs/notification/push.json +0 -25
  27. package/template/entities/System/Auth/account_oauth.json +0 -74
  28. package/template/entities/System/Auth/identity_verification.json +0 -106
  29. package/template/entities/System/Auth/password_history.json +0 -19
  30. package/template/entities/System/Notification/alimtalk_log.json +0 -65
  31. package/template/entities/System/Notification/alimtalk_msg.json +0 -53
  32. package/template/entities/System/Notification/friendtalk_log.json +0 -89
  33. package/template/entities/System/Notification/friendtalk_msg.json +0 -91
  34. package/template/entities/System/Notification/sms_log.json +0 -65
  35. package/template/entities/System/Notification/sms_msg.json +0 -82
  36. package/template/entities/System/Notification/sms_verification.json +0 -50
  37. package/template/entities/System/Payment/pg_cancel.json +0 -60
  38. package/template/entities/System/Payment/pg_order.json +0 -115
  39. package/template/entities/System/Payment/pg_webhook_log.json +0 -52
  40. package/template/entities/System/Push/push_log.json +0 -86
  41. package/template/entities/System/Push/push_msg.json +0 -56
  42. package/template/templates/email/auth/2fa_disabled.html +0 -23
  43. package/template/templates/email/auth/2fa_recovery_regenerated.html +0 -31
  44. package/template/templates/email/auth/2fa_setup_complete.html +0 -43
  45. package/template/templates/email/auth/welcome.html +0 -18
  46. package/template/templates/email/order/order_confirmation.html +0 -30
  47. /package/template/configs/{notification/smtp.json → smtp.json} +0 -0
@@ -54,6 +54,70 @@ get_server_value() {
54
54
  fi
55
55
  }
56
56
 
57
+ get_database_default_group() {
58
+ local value
59
+ value=$(grep -E '"default"[[:space:]]*:' "$DATABASE_CONFIG" | head -n 1 | sed -E 's/.*:[[:space:]]*"([^"]+)".*/\1/')
60
+ echo "$value"
61
+ }
62
+
63
+ list_database_groups() {
64
+ grep -E '^[[:space:]]*"[^"]+"[[:space:]]*:[[:space:]]*\{' "$DATABASE_CONFIG" \
65
+ | sed -E 's/^[[:space:]]*"([^"]+)"[[:space:]]*:[[:space:]]*\{.*/\1/' \
66
+ | grep -v '^groups$' \
67
+ | awk 'BEGIN { first = 1 } { if (!first) printf ", "; printf "%s", $0; first = 0 } END { printf "\n" }'
68
+ }
69
+
70
+ print_missing_database_group_error() {
71
+ local expected_group="$1"
72
+ local line_no="$2"
73
+ local current_default
74
+ local available_groups
75
+
76
+ current_default=$(get_database_default_group)
77
+ available_groups=$(list_database_groups)
78
+
79
+ if [ "$LANGUAGE" = "en" ]; then
80
+ echo "❌ database group '$expected_group' not found"
81
+ echo " at: scripts/run.sh:$line_no"
82
+ echo " config: $DATABASE_CONFIG"
83
+ echo " current default: ${current_default:-<empty>}"
84
+ echo " available groups: ${available_groups:-<none>}"
85
+ echo " cause: run.sh $MODE hardcodes '$expected_group' as the target default group."
86
+ else
87
+ echo "❌ configs/database.json에 '$expected_group' 그룹이 없습니다"
88
+ echo " 위치: scripts/run.sh:$line_no"
89
+ echo " 설정파일: $DATABASE_CONFIG"
90
+ echo " 현재 default: ${current_default:-<empty>}"
91
+ echo " 사용 가능한 groups: ${available_groups:-<none>}"
92
+ echo " 원인: run.sh $MODE 모드는 '$expected_group' 그룹을 기본 DB 그룹으로 강제하도록 작성되어 있습니다."
93
+ fi
94
+ }
95
+
96
+ sync_database_default_for_environment() {
97
+ local environment_value
98
+ environment_value=$(get_server_value "environment" "development")
99
+
100
+ if [ "$environment_value" != "production" ]; then
101
+ return 0
102
+ fi
103
+
104
+ # 현재 default 그룹이 database.json 안에 존재하면 그대로 유지
105
+ local current_default
106
+ current_default=$(get_database_default_group)
107
+ if [ -n "$current_default" ] && grep -Eq "\"${current_default}\"[[:space:]]*:" "$DATABASE_CONFIG"; then
108
+ return 0
109
+ fi
110
+
111
+ # 현재 default 그룹이 없을 때만 production으로 fallback
112
+ if ! grep -Eq '"production"[[:space:]]*:' "$DATABASE_CONFIG"; then
113
+ print_missing_database_group_error "production" "$1"
114
+ return 1
115
+ fi
116
+
117
+ sed -E -i 's/("default"[[:space:]]*:[[:space:]]*")[^"]+(")/\1production\2/' "$DATABASE_CONFIG"
118
+ return 0
119
+ }
120
+
57
121
  is_running() {
58
122
  local port_pid
59
123
  port_pid=$(find_pid_by_port)
@@ -146,7 +210,7 @@ stop_pid_with_confirm() {
146
210
  read -r -p "이 프로세스를 중지할까요? [y/N]: " input
147
211
  fi
148
212
  input=$(echo "$input" | tr '[:upper:]' '[:lower:]')
149
- if [ "$input" != "y" ] && [ "$input" != "yes" ]; then
213
+ if [ "$input" != "y" ] && [ "$input" != "yes" ] && [ "$input" != "ㅛ" ]; then
150
214
  if [ "$LANGUAGE" = "en" ]; then
151
215
  echo "Canceled."
152
216
  else
@@ -273,13 +337,13 @@ if [ $# -eq 0 ]; then
273
337
  echo "Entity Server - Run Script"
274
338
  echo "=========================="
275
339
  echo ""
276
- echo "Force configs/server.json environment and configs/database.json default group, then start compiled server binary."
340
+ echo "Adjust configs/server.json environment as needed, then start the compiled server binary."
277
341
  echo ""
278
342
  echo "Usage: $0 <mode>"
279
343
  echo ""
280
344
  echo "Modes:"
281
- echo " dev environment=development, database.default=development, then run binary"
282
- echo " start environment=production, database.default=production, then run in background"
345
+ echo " dev environment=development, keep database.default, then run binary"
346
+ echo " start environment=production, use database.default=production only in production, then run in background"
283
347
  echo " stop stop background server started by this script"
284
348
  echo " status show server status"
285
349
  echo ""
@@ -292,13 +356,13 @@ if [ $# -eq 0 ]; then
292
356
  echo "Entity Server - 실행 스크립트"
293
357
  echo "==========================="
294
358
  echo ""
295
- echo "configs/server.json의 environment configs/database.json의 default를 강제 설정하고 바이너리를 실행합니다."
359
+ echo "configs/server.json의 environment 기준으로 필요한 경우에만 database.default를 조정한 바이너리를 실행합니다."
296
360
  echo ""
297
361
  echo "사용법: $0 <모드>"
298
362
  echo ""
299
363
  echo "모드:"
300
- echo " dev environment=development, database.default=development 강제 바이너리 실행"
301
- echo " start environment=production, database.default=production 강제 백그라운드 실행"
364
+ echo " dev environment=development 설정하고 database.default 유지한 바이너리 실행"
365
+ echo " start environment=production으로 설정하고 production일 때만 database.default=production으로 맞춘 백그라운드 실행"
302
366
  echo " stop run.sh로 백그라운드 실행한 서버 중지"
303
367
  echo " status 서버 상태 조회"
304
368
  echo ""
@@ -357,17 +421,8 @@ case "$MODE" in
357
421
  exit 1
358
422
  fi
359
423
 
360
- if ! grep -Eq '"development"[[:space:]]*:' "$DATABASE_CONFIG"; then
361
- if [ "$LANGUAGE" = "en" ]; then
362
- echo "❌ database group 'development' not found in configs/database.json"
363
- else
364
- echo "❌ configs/database.json에 'development' 그룹이 없습니다"
365
- fi
366
- exit 1
367
- fi
368
-
369
424
  sed -E -i 's/("environment"[[:space:]]*:[[:space:]]*")[^"]+(")/\1development\2/' "$SERVER_CONFIG"
370
- sed -E -i 's/("default"[[:space:]]*:[[:space:]]*")[^"]+(")/\1development\2/' "$DATABASE_CONFIG"
425
+ sync_database_default_for_environment "$LINENO" || exit 1
371
426
  "$SERVER_BIN"
372
427
  ;;
373
428
 
@@ -387,17 +442,8 @@ case "$MODE" in
387
442
  exit 1
388
443
  fi
389
444
 
390
- if ! grep -Eq '"production"[[:space:]]*:' "$DATABASE_CONFIG"; then
391
- if [ "$LANGUAGE" = "en" ]; then
392
- echo "❌ database group 'production' not found in configs/database.json"
393
- else
394
- echo "❌ configs/database.json에 'production' 그룹이 없습니다"
395
- fi
396
- exit 1
397
- fi
398
-
399
445
  sed -E -i 's/("environment"[[:space:]]*:[[:space:]]*")[^"]+(")/\1production\2/' "$SERVER_CONFIG"
400
- sed -E -i 's/("default"[[:space:]]*:[[:space:]]*")[^"]+(")/\1production\2/' "$DATABASE_CONFIG"
446
+ sync_database_default_for_environment "$LINENO" || exit 1
401
447
 
402
448
  "$SERVER_BIN" banner
403
449
  nohup "$SERVER_BIN" >> "$STDOUT_LOG" 2>&1 &
@@ -7,6 +7,11 @@ PROJECT_ROOT="$(dirname "$SCRIPT_DIR")"
7
7
 
8
8
  cd "$PROJECT_ROOT"
9
9
 
10
+ ENTITY_CLI_BIN="$PROJECT_ROOT/bin/entity-cli"
11
+ if [ ! -f "$ENTITY_CLI_BIN" ] && [ -f "$PROJECT_ROOT/entity-cli" ]; then
12
+ ENTITY_CLI_BIN="$PROJECT_ROOT/entity-cli"
13
+ fi
14
+
10
15
  # Load language from .env
11
16
  if [ -f .env ]; then
12
17
  LANGUAGE=$(grep '^LANGUAGE=' .env | cut -d '=' -f2)
@@ -70,11 +75,11 @@ if [ $# -eq 0 ]; then
70
75
  fi
71
76
 
72
77
  # Require prebuilt CLI binary
73
- if [ ! -f "$PROJECT_ROOT/bin/entity-cli" ]; then
78
+ if [ ! -f "$ENTITY_CLI_BIN" ]; then
74
79
  if [ "$LANGUAGE" = "en" ]; then
75
- echo "❌ bin/entity-cli not found"
80
+ echo "❌ entity-cli not found (bin/entity-cli or ./entity-cli)"
76
81
  else
77
- echo "❌ bin/entity-cli 파일이 없습니다"
82
+ echo "❌ entity-cli 파일이 없습니다 (bin/entity-cli 또는 ./entity-cli)"
78
83
  fi
79
84
  exit 1
80
85
  fi
@@ -115,7 +120,7 @@ fi
115
120
 
116
121
  build_cmd() {
117
122
  local entity_name="$1"
118
- local cmd=("$PROJECT_ROOT/bin/entity-cli" sync-index --entity="$entity_name")
123
+ local cmd=("$ENTITY_CLI_BIN" sync-index --entity="$entity_name")
119
124
  if [ "$APPLY_MODE" = "--apply" ]; then
120
125
  cmd+=(--apply)
121
126
  fi
@@ -1,40 +0,0 @@
1
- {
2
- "_comment": "OAuth 2.0 설정 예시. 사용할 프로바이더만 남기고 실제 값으로 교체하세요.",
3
- "enabled": false,
4
-
5
- "state_secret": "${OAUTH_STATE_SECRET}",
6
- "state_ttl_sec": 600,
7
- "success_redirect_url": "/auth/callback",
8
- "failure_redirect_url": "/auth/error",
9
-
10
- "providers": {
11
- "google": {
12
- "client_id": "${GOOGLE_CLIENT_ID}",
13
- "client_secret": "${GOOGLE_CLIENT_SECRET}",
14
- "redirect_url": "/v1/oauth/google/callback",
15
- "scopes": ["openid", "email", "profile"]
16
- },
17
- "github": {
18
- "client_id": "${GITHUB_CLIENT_ID}",
19
- "client_secret": "${GITHUB_CLIENT_SECRET}",
20
- "redirect_url": "/v1/oauth/github/callback"
21
- },
22
- "naver": {
23
- "client_id": "${NAVER_CLIENT_ID}",
24
- "client_secret": "${NAVER_CLIENT_SECRET}",
25
- "redirect_url": "/v1/oauth/naver/callback"
26
- },
27
- "kakao": {
28
- "_comment": "Kakao — 커스텀 엔드포인트 예시",
29
- "client_id": "${KAKAO_CLIENT_ID}",
30
- "client_secret": "${KAKAO_CLIENT_SECRET}",
31
- "redirect_url": "/v1/oauth/kakao/callback",
32
- "auth_url": "https://kauth.kakao.com/oauth/authorize",
33
- "token_url": "https://kauth.kakao.com/oauth/token",
34
- "user_info_url": "https://kapi.kakao.com/v2/user/me",
35
- "scopes": ["profile_nickname", "account_email"],
36
- "email_field": "kakao_account.email",
37
- "name_field": "properties.nickname"
38
- }
39
- }
40
- }
@@ -1,45 +0,0 @@
1
- {
2
- "password_policy": {
3
- "min_length": 8,
4
- "max_length": 128,
5
- "require_mixed_case": false,
6
- "require_number": false,
7
- "require_special": false,
8
- "history_count": 5,
9
- "forbidden_patterns": {
10
- "sequential_digits": true,
11
- "repeated_chars": true,
12
- "keyboard_patterns": false,
13
- "sequential_length": 4
14
- },
15
- "pii_check": {
16
- "enabled": false,
17
- "entity": "user",
18
- "fields": ["phone", "birthday"]
19
- }
20
- },
21
- "admin_force_reset": {
22
- "temp_password_length": 12,
23
- "require_change": true,
24
- "notify_email": true
25
- },
26
- "password_reset": {
27
- "enabled": true,
28
- "temp_password_ttl_sec": 300,
29
- "temp_password_length": 12,
30
- "rate_limit": {
31
- "per_email_per_hour": 5,
32
- "per_ip_per_minute": 10
33
- }
34
- },
35
- "email_verification": {
36
- "enabled": true,
37
- "required": false,
38
- "code_length": 6,
39
- "code_ttl_sec": 300,
40
- "max_attempts": 5,
41
- "rate_limit": {
42
- "per_email_per_hour": 5
43
- }
44
- }
45
- }
@@ -1,7 +0,0 @@
1
- -----BEGIN PRIVATE KEY-----
2
- (샘플) Apple Developer Console → Certificates, Identifiers & Profiles
3
- → Keys → "+" 버튼으로 APNs 키 생성 후 다운로드한 .p8 파일 내용을 여기에 붙여넣으세요.
4
-
5
- 실제 키는 아래와 같은 형식입니다:
6
- MIGHAgEAMBMGByqGSM49AgEGCCqGSM49AwEHBG0wawIBAQQg...
7
- -----END PRIVATE KEY-----
@@ -1,7 +0,0 @@
1
- -----BEGIN PRIVATE KEY-----
2
- (샘플) Firebase Console → 프로젝트 설정 → 서비스 계정 → 새 비공개 키 생성
3
- 으로 다운로드한 JSON 파일의 private_key 값을 여기에 붙여넣으세요.
4
-
5
- 실제 키는 아래와 같은 형식입니다:
6
- MIIEvgIBADANBgkqhkiG9w0BAQEFAASCBKgwggSkAgEAAoIBAQC...
7
- -----END PRIVATE KEY-----
@@ -1,25 +0,0 @@
1
- {
2
- "workers": 2,
3
- "queue_size": 500,
4
- "fcm": {
5
- "enabled": false,
6
- "type": "service_account",
7
- "project_id": "your-firebase-project-id",
8
- "private_key_id": "abc123def456...",
9
- "private_key_file": "./configs/keys/firebase.pem",
10
- "client_email": "firebase-adminsdk-xxxxx@your-firebase-project-id.iam.gserviceaccount.com",
11
- "client_id": "123456789012345678901",
12
- "auth_uri": "https://accounts.google.com/o/oauth2/auth",
13
- "token_uri": "https://oauth2.googleapis.com/token",
14
- "auth_provider_x509_cert_url": "https://www.googleapis.com/oauth2/v1/certs",
15
- "client_x509_cert_url": "https://www.googleapis.com/robot/v1/metadata/x509/firebase-adminsdk-xxxxx%40your-firebase-project-id.iam.gserviceaccount.com"
16
- },
17
- "apns": {
18
- "enabled": false,
19
- "key_file": "./configs/keys/apns.p8",
20
- "key_id": "ABCDE12345",
21
- "team_id": "FGHIJ67890",
22
- "bundle_id": "com.example.myapp",
23
- "production": false
24
- }
25
- }
@@ -1,74 +0,0 @@
1
- {
2
- "name": "account_oauth",
3
- "description": "소셜 로그인 OAuth 프로바이더 연동 정보. 사용자 환경에 맞게 fields를 자유롭게 확장할 수 있습니다.",
4
- "history": false,
5
- "hard_delete": true,
6
- "fields": {
7
- "account_seq": {
8
- "index": true,
9
- "required": true,
10
- "comment": "계정 seq"
11
- },
12
- "provider": {
13
- "index": true,
14
- "type": [
15
- "google",
16
- "github",
17
- "naver",
18
- "kakao",
19
- "apple"
20
- ],
21
- "required": true
22
- },
23
- "provider_id": {
24
- "index": true,
25
- "type": "string",
26
- "required": true,
27
- "comment": "프로바이더 고유 사용자 ID"
28
- },
29
- "status": {
30
- "index": true,
31
- "type": [
32
- "active",
33
- "unlinked"
34
- ],
35
- "default": "active"
36
- },
37
- "email": {
38
- "type": "email",
39
- "comment": "프로바이더에서 제공한 이메일"
40
- },
41
- "name": {
42
- "type": "string",
43
- "comment": "프로바이더에서 제공한 이름"
44
- },
45
- "profile_image": {
46
- "type": "string",
47
- "comment": "프로필 이미지 URL"
48
- },
49
- "access_token": {
50
- "type": "string",
51
- "comment": "OAuth access token (암호화 저장)"
52
- },
53
- "refresh_token": {
54
- "type": "string",
55
- "comment": "OAuth refresh token (암호화 저장)"
56
- },
57
- "token_expires_at": {
58
- "type": "string",
59
- "comment": "access token 만료 시각 (RFC3339)"
60
- },
61
- "raw": {
62
- "type": "json",
63
- "comment": "프로바이더 원본 응답 (디버깅용)"
64
- },
65
- "linked_at": {
66
- "type": "string",
67
- "comment": "연결 시각"
68
- },
69
- "unlinked_at": {
70
- "type": "string",
71
- "comment": "연결 해제 시각"
72
- }
73
- }
74
- }
@@ -1,106 +0,0 @@
1
- {
2
- "name": "identity_verification",
3
- "description": "휴대폰 본인인증 요청 및 결과 저장. 사용자 환경에 맞게 fields를 자유롭게 확장할 수 있습니다.",
4
- "history": false,
5
- "hard_delete": false,
6
- "compress": true,
7
- "fields": {
8
- "request_id": {
9
- "index": true,
10
- "type": "string",
11
- "required": true,
12
- "unique": true,
13
- "comment": "인증 요청 고유 ID (32바이트 hex)"
14
- },
15
- "status": {
16
- "index": true,
17
- "type": [
18
- "pending",
19
- "verified",
20
- "failed",
21
- "expired"
22
- ],
23
- "default": "pending"
24
- },
25
- "purpose": {
26
- "index": true,
27
- "type": [
28
- "signup",
29
- "find_account",
30
- "password_reset",
31
- "adult_verify",
32
- "identity_change"
33
- ],
34
- "required": true
35
- },
36
- "provider": {
37
- "index": true,
38
- "type": [
39
- "nice",
40
- "kmc",
41
- "danal"
42
- ],
43
- "required": true
44
- },
45
- "ci_hash": {
46
- "type": "string",
47
- "comment": "CI의 SHA-256 해시 (중복 조회용)"
48
- },
49
- "di": {
50
- "type": "string",
51
- "comment": "DI 원문 (암호화 저장)"
52
- },
53
- "name": {
54
- "type": "string",
55
- "comment": "인증된 실명"
56
- },
57
- "birth_date": {
58
- "type": "string",
59
- "comment": "생년월일 (YYYYMMDD)"
60
- },
61
- "gender": {
62
- "type": "string",
63
- "comment": "성별 (M/F)"
64
- },
65
- "carrier": {
66
- "type": "string",
67
- "comment": "통신사 코드"
68
- },
69
- "phone": {
70
- "type": "string",
71
- "comment": "인증 휴대폰 번호"
72
- },
73
- "nationality": {
74
- "type": "string",
75
- "comment": "내/외국인 (local/foreign)"
76
- },
77
- "account_seq": {
78
- "type": "int",
79
- "comment": "연결된 계정 seq (인증 완료 후 설정)"
80
- },
81
- "ip_address": {
82
- "type": "string",
83
- "comment": "요청 IP 주소"
84
- },
85
- "user_agent": {
86
- "type": "string",
87
- "comment": "요청 User-Agent"
88
- },
89
- "verified_at": {
90
- "type": "string",
91
- "comment": "인증 완료 시각 (RFC3339)"
92
- },
93
- "expires_at": {
94
- "type": "string",
95
- "comment": "요청 만료 시각 (RFC3339)"
96
- },
97
- "error_message": {
98
- "type": "string",
99
- "comment": "실패 시 에러 메시지"
100
- },
101
- "raw_response": {
102
- "type": "json",
103
- "comment": "중계사 원본 응답 (디버깅용, 암호화)"
104
- }
105
- }
106
- }
@@ -1,19 +0,0 @@
1
- {
2
- "name": "password_history",
3
- "description": "비밀번호 변경 이력 (재사용 금지 정책용) 사용자 환경에 맞게 fields를 자유롭게 확장할 수 있습니다.",
4
- "hard_delete": true,
5
- "fields": {
6
- "account_seq": {
7
- "index": true,
8
- "comment": "계정 seq",
9
- "type": "integer",
10
- "required": true
11
- },
12
- "passwd_hash": {
13
- "comment": "변경 시점의 비밀번호 해시 (salt 포함)"
14
- },
15
- "changed_time": {
16
- "comment": "비밀번호 변경 시각"
17
- }
18
- }
19
- }
@@ -1,65 +0,0 @@
1
- {
2
- "name": "alimtalk_log",
3
- "description": "알림톡 발송 로그 — 워커가 소비하는 DB 큐 역할을 합니다. 사용자 환경에 맞게 fields를 자유롭게 확장할 수 있습니다.",
4
- "history": false,
5
- "read_only": true,
6
- "compress": true,
7
- "fields": {
8
- "status": {
9
- "index": true,
10
- "type": [
11
- "pending",
12
- "processing",
13
- "sent",
14
- "delivered",
15
- "failed",
16
- "expired"
17
- ],
18
- "default": "pending",
19
- "comment": "발송 상태 (delivered = 프로바이더 수신 확인)"
20
- },
21
- "template_code": {
22
- "index": true,
23
- "comment": "카카오 알림톡 템플릿 코드",
24
- "required": true
25
- },
26
- "receiver": {
27
- "index": true,
28
- "hash": true,
29
- "comment": "수신자 전화번호",
30
- "required": true
31
- },
32
- "alimtalk_msg_seq": {
33
- "index": true,
34
- "comment": "alimtalk_msg 참조 seq"
35
- },
36
- "template_name": {
37
- "comment": "내부 템플릿 이름"
38
- },
39
- "variables_json": {
40
- "type": "text",
41
- "comment": "템플릿 변수 JSON"
42
- },
43
- "provider": {
44
- "comment": "사용 프로바이더"
45
- },
46
- "provider_msg_id": {
47
- "comment": "프로바이더 메시지 ID"
48
- },
49
- "error_message": {
50
- "type": "text",
51
- "comment": "오류 메시지"
52
- },
53
- "retry_count": {
54
- "type": "uint",
55
- "default": 0
56
- },
57
- "sent_at": {
58
- "type": "string"
59
- },
60
- "delivered_at": {
61
- "type": "string",
62
- "comment": "프로바이더 수신 확인 시각"
63
- }
64
- }
65
- }
@@ -1,53 +0,0 @@
1
- {
2
- "name": "alimtalk_msg",
3
- "description": "알림톡 발송 트리거 엔티티 — Hook 또는 API를 통해 생성되면 알림톡 발송이 시작됩니다. 사용자 환경에 맞게 fields를 자유롭게 확장할 수 있습니다.",
4
- "history": false,
5
- "fields": {
6
- "template_code": {
7
- "index": true,
8
- "comment": "카카오 알림톡 템플릿 코드",
9
- "required": true
10
- },
11
- "receiver": {
12
- "index": true,
13
- "hash": true,
14
- "comment": "수신자 전화번호",
15
- "required": true
16
- },
17
- "status": {
18
- "index": true,
19
- "type": [
20
- "pending",
21
- "processing",
22
- "sent",
23
- "delivered",
24
- "failed"
25
- ],
26
- "default": "pending",
27
- "comment": "발송 상태 (delivered = 프로바이더 수신 확인)"
28
- },
29
- "variables_json": {
30
- "type": "text",
31
- "comment": "템플릿 변수 JSON (#{key} 바인딩)"
32
- },
33
- "provider": {
34
- "comment": "프로바이더 키 (빈 값이면 default)"
35
- },
36
- "ref_entity": {
37
- "comment": "참조 엔티티 이름"
38
- },
39
- "ref_seq": {
40
- "type": "int"
41
- }
42
- },
43
- "hooks": {
44
- "after_insert": [
45
- {
46
- "type": "alimtalk",
47
- "alimtalk_receiver": "${new.receiver}",
48
- "alimtalk_template_code": "${new.template_code}",
49
- "alimtalk_variables": "${new.variables_json}"
50
- }
51
- ]
52
- }
53
- }