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
@@ -22,10 +22,6 @@
22
22
  "type": ["active", "inactive", "blocked", "dormant"],
23
23
  "default": "active"
24
24
  },
25
- "user_seq": {
26
- "index": true,
27
- "comment": "사용자번호"
28
- },
29
25
  "max_session_cnt": {
30
26
  "type": "uint"
31
27
  },
@@ -50,26 +46,6 @@
50
46
  "type": "bool",
51
47
  "default": false,
52
48
  "comment": "다음 로그인 시 비밀번호 변경 강제"
53
- },
54
- "name": {
55
- "no_store": true,
56
- "comment": "가입 요청 시 전달되는 이름. account에는 저장되지 않고 after_insert 훅(user 엔티티 생성 등)에서만 사용됩니다."
57
- },
58
- "phone": {
59
- "no_store": true,
60
- "comment": "가입 요청 시 전달되는 전화번호. no_store."
61
- },
62
- "birth_date": {
63
- "no_store": true,
64
- "comment": "가입 요청 시 전달되는 생년월일. no_store."
65
- },
66
- "gender": {
67
- "no_store": true,
68
- "comment": "가입 요청 시 전달되는 성별. no_store."
69
- },
70
- "profile_image": {
71
- "no_store": true,
72
- "comment": "가입 요청 시 전달되는 프로필 이미지. no_store."
73
49
  }
74
50
  },
75
51
  "reset_defaults": [
@@ -129,21 +105,6 @@
129
105
  "query": "INSERT INTO account_audit (account_seq, action, email, created_time) VALUES (?, ?, ?, NOW())",
130
106
  "params": ["${new.seq}", "INSERT", "${new.email}"],
131
107
  "required": true
132
- },
133
- {
134
- "_comment": "가입 시 user 엔티티 자동 생성. enabled: true로 바꾸면 활성화됩니다. assign_seq_to로 account.user_seq에 자동 반영됩니다.",
135
- "type": "submit",
136
- "enabled": false,
137
- "entity": "user",
138
- "data": {
139
- "account_seq": "${new.seq}",
140
- "name": "${new.name}",
141
- "phone": "${new.phone}",
142
- "birth_date": "${new.birth_date}",
143
- "gender": "${new.gender}",
144
- "profile_image": "${new.profile_image}"
145
- },
146
- "assign_seq_to": "user_seq"
147
108
  }
148
109
  ],
149
110
  "after_update": [
@@ -152,22 +113,6 @@
152
113
  "query": "INSERT INTO account_audit (account_seq, action, email, created_time) VALUES (?, ?, ?, NOW())",
153
114
  "params": ["${new.seq}", "UPDATE", "${new.email}"],
154
115
  "required": true
155
- },
156
- {
157
- "_comment": "계정 업데이트 시 user 프로필 동기화. enabled: true로 바꾸면 활성화됩니다.",
158
- "type": "submit",
159
- "enabled": false,
160
- "entity": "user",
161
- "match": {
162
- "account_seq": "${new.seq}"
163
- },
164
- "data": {
165
- "name": "${new.name}",
166
- "phone": "${new.phone}",
167
- "birth_date": "${new.birth_date}",
168
- "gender": "${new.gender}",
169
- "profile_image": "${new.profile_image}"
170
- }
171
116
  }
172
117
  ],
173
118
  "after_delete": [
@@ -179,15 +124,6 @@
179
124
  }
180
125
  ],
181
126
  "after_get": [
182
- {
183
- "type": "entity",
184
- "entity": "user",
185
- "action": "find",
186
- "conditions": {
187
- "seq": "${new.user_seq}"
188
- },
189
- "assign_to": "user_profile"
190
- },
191
127
  {
192
128
  "type": "entity",
193
129
  "entity": "account_device",
@@ -1,11 +1,12 @@
1
1
  {
2
2
  "name": "account_device",
3
- "description": "계정 기기 정보 및 푸시 토큰 관리. JWT 인증 시 account_seq로 계정과 연결. 사용자 환경에 맞게 fields를 자유롭게 확장할 수 있습니다.",
3
+ "description": "회원 계정 기기 정보 및 푸시 토큰 관리. account_seq로 계정과 연결되며 회원 전용으로 사용합니다. 사용자 환경에 맞게 fields를 자유롭게 확장할 수 있습니다.",
4
4
  "license_scope": false,
5
5
  "fields": {
6
6
  "account_seq": {
7
7
  "index": true,
8
- "comment": "계정seq (JWT 인증 시 필수. HMAC 인증은 nullable)"
8
+ "required": true,
9
+ "comment": "계정seq (회원 계정 필수)"
9
10
  },
10
11
  "id": {
11
12
  "index": true,
@@ -19,24 +20,12 @@
19
20
  },
20
21
  "device_type": {
21
22
  "comment": "기기유형",
22
- "type": [
23
- "mobile",
24
- "tablet",
25
- "desktop",
26
- "watch"
27
- ],
23
+ "type": ["mobile", "tablet", "desktop", "watch"],
28
24
  "default": "mobile"
29
25
  },
30
26
  "platform": {
31
27
  "comment": "플랫폼",
32
- "type": [
33
- "android",
34
- "ios",
35
- "web",
36
- "windows",
37
- "macos",
38
- "linux"
39
- ]
28
+ "type": ["android", "ios", "web", "windows", "macos", "linux"]
40
29
  },
41
30
  "browser": {
42
31
  "comment": "브라우저"
@@ -55,10 +44,6 @@
55
44
  "comment": "마지막IP주소"
56
45
  }
57
46
  },
58
- "unique": [
59
- [
60
- "id",
61
- "account_seq"
62
- ]
63
- ]
47
+ "unique": [["id", "account_seq"]],
48
+ "history": false
64
49
  }
@@ -41,19 +41,14 @@
41
41
  "language": {
42
42
  "comment": "언어"
43
43
  },
44
- "user_seq": {
44
+ "account_seq": {
45
45
  "index": true,
46
- "comment": "사용자번호"
46
+ "comment": "계정번호"
47
47
  },
48
48
  "auth_method": {
49
49
  "index": true,
50
50
  "comment": "인증 방식",
51
- "type": [
52
- "password",
53
- "oauth",
54
- "2fa_totp",
55
- "2fa_recovery"
56
- ],
51
+ "type": ["password", "oauth", "2fa_totp", "2fa_recovery"],
57
52
  "default": "password"
58
53
  },
59
54
  "location_info": {
@@ -0,0 +1,56 @@
1
+ {
2
+ "name": "anon_device",
3
+ "description": "비회원 디바이스 식별 및 사용 제한 집계. device_id 쿠키 값 기반으로 추적하며 익명 사용자 전용으로 사용합니다. 사용자 환경에 맞게 fields를 자유롭게 확장할 수 있습니다.",
4
+ "license_scope": false,
5
+ "fields": {
6
+ "id": {
7
+ "index": true,
8
+ "required": true,
9
+ "unique": true,
10
+ "comment": "익명 디바이스 ID (cookie/device_id)"
11
+ },
12
+ "calc_count": {
13
+ "index": true,
14
+ "type": "uint",
15
+ "default": 0,
16
+ "comment": "거리 계산 사용 횟수"
17
+ },
18
+ "first_seen_time": {
19
+ "comment": "최초 식별 시각"
20
+ },
21
+ "last_seen_time": {
22
+ "index": true,
23
+ "comment": "마지막 식별 시각"
24
+ },
25
+ "last_calc_time": {
26
+ "index": true,
27
+ "comment": "마지막 거리 계산 시각"
28
+ },
29
+ "blocked_until_time": {
30
+ "index": true,
31
+ "comment": "차단 해제 시각"
32
+ },
33
+ "last_ip_addr": {
34
+ "comment": "마지막 IP주소"
35
+ },
36
+ "device_type": {
37
+ "comment": "기기유형",
38
+ "type": ["mobile", "tablet", "desktop", "watch"],
39
+ "default": "mobile"
40
+ },
41
+ "platform": {
42
+ "comment": "플랫폼",
43
+ "type": ["android", "ios", "web", "windows", "macos", "linux"]
44
+ },
45
+ "browser": {
46
+ "comment": "브라우저"
47
+ },
48
+ "browser_version": {
49
+ "comment": "브라우저버전"
50
+ },
51
+ "user_agent": {
52
+ "comment": "User Agent"
53
+ }
54
+ },
55
+ "history": false
56
+ }
@@ -6,6 +6,9 @@
6
6
  SCRIPT_DIR="$(cd "$(dirname "${BASH_SOURCE[0]}")" && pwd)"
7
7
  PROJECT_ROOT="$(dirname "$SCRIPT_DIR")"
8
8
  BIN_PATH="$PROJECT_ROOT/bin/entity-cli"
9
+ if [ ! -f "$BIN_PATH" ] && [ -f "$PROJECT_ROOT/entity-cli" ]; then
10
+ BIN_PATH="$PROJECT_ROOT/entity-cli"
11
+ fi
9
12
 
10
13
  cd "$PROJECT_ROOT"
11
14
 
@@ -100,9 +103,9 @@ fi
100
103
  # CLI 바이너리 존재 확인
101
104
  if [ ! -f "$BIN_PATH" ]; then
102
105
  if [ "$LANGUAGE" = "en" ]; then
103
- echo "❌ bin/entity-cli not found. Run: ./scripts/build.sh"
106
+ echo "❌ entity-cli not found (bin/entity-cli or ./entity-cli). Run: ./scripts/build.sh"
104
107
  else
105
- echo "❌ bin/entity-cli 파일이 없습니다. 먼저 ./scripts/build.sh 를 실행하세요."
108
+ echo "❌ entity-cli 파일이 없습니다 (bin/entity-cli 또는 ./entity-cli). 먼저 ./scripts/build.sh 를 실행하세요."
106
109
  fi
107
110
  exit 1
108
111
  fi
@@ -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)
@@ -41,14 +46,14 @@ if [ $# -eq 0 ]; then
41
46
  fi
42
47
 
43
48
  # Require prebuilt CLI binary
44
- if [ ! -f "$PROJECT_ROOT/bin/entity-cli" ]; then
49
+ if [ ! -f "$ENTITY_CLI_BIN" ]; then
45
50
  if [ "$LANGUAGE" = "en" ]; then
46
- echo "❌ bin/entity-cli not found"
51
+ echo "❌ entity-cli not found (bin/entity-cli or ./entity-cli)"
47
52
  else
48
- echo "❌ bin/entity-cli 파일이 없습니다"
53
+ echo "❌ entity-cli 파일이 없습니다 (bin/entity-cli 또는 ./entity-cli)"
49
54
  fi
50
55
  exit 1
51
56
  fi
52
57
 
53
58
  # Pass-through to CLI
54
- "$PROJECT_ROOT/bin/entity-cli" cleanup-history "$@"
59
+ "$ENTITY_CLI_BIN" cleanup-history "$@"
@@ -5,6 +5,9 @@
5
5
  SCRIPT_DIR="$(cd "$(dirname "${BASH_SOURCE[0]}")" && pwd)"
6
6
  PROJECT_ROOT="$(dirname "$SCRIPT_DIR")"
7
7
  BIN_PATH="$PROJECT_ROOT/bin/entity-cli"
8
+ if [ ! -f "$BIN_PATH" ] && [ -f "$PROJECT_ROOT/entity-cli" ]; then
9
+ BIN_PATH="$PROJECT_ROOT/entity-cli"
10
+ fi
8
11
 
9
12
  # Load language from .env
10
13
  if [ -f "$PROJECT_ROOT/.env" ]; then
@@ -15,9 +18,9 @@ LANGUAGE=${LANGUAGE:-ko}
15
18
  # Require prebuilt CLI binary
16
19
  if [ ! -f "$BIN_PATH" ]; then
17
20
  if [ "$LANGUAGE" = "en" ]; then
18
- echo "❌ bin/entity-cli not found"
21
+ echo "❌ entity-cli not found (bin/entity-cli or ./entity-cli)"
19
22
  else
20
- echo "❌ bin/entity-cli 파일이 없습니다"
23
+ echo "❌ entity-cli 파일이 없습니다 (bin/entity-cli 또는 ./entity-cli)"
21
24
  fi
22
25
  exit 1
23
26
  fi
@@ -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)
@@ -59,14 +64,14 @@ if [ $# -eq 0 ]; then
59
64
  fi
60
65
 
61
66
  # Require prebuilt CLI binary
62
- if [ ! -f "$PROJECT_ROOT/bin/entity-cli" ]; then
67
+ if [ ! -f "$ENTITY_CLI_BIN" ]; then
63
68
  if [ "$LANGUAGE" = "en" ]; then
64
- echo "❌ bin/entity-cli not found"
69
+ echo "❌ entity-cli not found (bin/entity-cli or ./entity-cli)"
65
70
  else
66
- echo "❌ bin/entity-cli 파일이 없습니다"
71
+ echo "❌ entity-cli 파일이 없습니다 (bin/entity-cli 또는 ./entity-cli)"
67
72
  fi
68
73
  exit 1
69
74
  fi
70
75
 
71
76
  # Pass-through to CLI
72
- "$PROJECT_ROOT/bin/entity-cli" init-entity "$@"
77
+ "$ENTITY_CLI_BIN" init-entity "$@"
@@ -19,6 +19,10 @@ RUN_GROUP="$(id -gn "$RUN_USER" 2>/dev/null || true)"
19
19
  START_NOW=true
20
20
  INTERACTIVE=false
21
21
  SERVER_CONFIG="$PROJECT_ROOT/configs/server.json"
22
+ SERVER_BIN="$PROJECT_ROOT/bin/entity-server"
23
+ if [ ! -f "$SERVER_BIN" ] && [ -f "$PROJECT_ROOT/entity-server" ]; then
24
+ SERVER_BIN="$PROJECT_ROOT/entity-server"
25
+ fi
22
26
 
23
27
  load_namespace() {
24
28
  local namespace=""
@@ -151,12 +155,12 @@ if [ ! -x "$PROJECT_ROOT/scripts/run.sh" ]; then
151
155
  chmod +x "$PROJECT_ROOT/scripts/run.sh"
152
156
  fi
153
157
 
154
- if [ ! -f "$PROJECT_ROOT/bin/entity-server" ]; then
158
+ if [ ! -f "$SERVER_BIN" ]; then
155
159
  if [ "$LANGUAGE" = "en" ]; then
156
- echo "❌ bin/entity-server not found"
160
+ echo "❌ entity-server not found (bin/entity-server or ./entity-server)"
157
161
  echo "Run ./scripts/build.sh first."
158
162
  else
159
- echo "❌ bin/entity-server 파일이 없습니다"
163
+ echo "❌ entity-server 파일이 없습니다 (bin/entity-server 또는 ./entity-server)"
160
164
  echo "먼저 ./scripts/build.sh 를 실행하세요."
161
165
  fi
162
166
  exit 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)
@@ -92,11 +97,11 @@ if [ $# -eq 0 ]; then
92
97
  fi
93
98
 
94
99
  # Require prebuilt CLI binary
95
- if [ ! -f "$PROJECT_ROOT/bin/entity-cli" ]; then
100
+ if [ ! -f "$ENTITY_CLI_BIN" ]; then
96
101
  if [ "$LANGUAGE" = "en" ]; then
97
- echo "❌ bin/entity-cli not found. Run scripts/build.sh first."
102
+ echo "❌ entity-cli not found (bin/entity-cli or ./entity-cli). Run scripts/build.sh first."
98
103
  else
99
- echo "❌ bin/entity-cli 파일이 없습니다. scripts/build.sh 를 먼저 실행하세요."
104
+ echo "❌ entity-cli 파일이 없습니다 (bin/entity-cli 또는 ./entity-cli). scripts/build.sh 를 먼저 실행하세요."
100
105
  fi
101
106
  exit 1
102
107
  fi
@@ -125,7 +130,7 @@ for arg in "$@"; do
125
130
  esac
126
131
  done
127
132
 
128
- CMD=("$PROJECT_ROOT/bin/entity-cli" normalize-entities)
133
+ CMD=("$ENTITY_CLI_BIN" normalize-entities)
129
134
  [ -n "$ENTITY_FLAG" ] && CMD+=("$ENTITY_FLAG")
130
135
  [ -n "$APPLY_FLAG" ] && CMD+=("$APPLY_FLAG")
131
136
 
@@ -5,6 +5,9 @@
5
5
  SCRIPT_DIR="$(cd "$(dirname "${BASH_SOURCE[0]}")" && pwd)"
6
6
  PROJECT_ROOT="$(dirname "$SCRIPT_DIR")"
7
7
  BIN_PATH="$PROJECT_ROOT/bin/entity-cli"
8
+ if [ ! -f "$BIN_PATH" ] && [ -f "$PROJECT_ROOT/entity-cli" ]; then
9
+ BIN_PATH="$PROJECT_ROOT/entity-cli"
10
+ fi
8
11
 
9
12
  cd "$PROJECT_ROOT"
10
13
 
@@ -97,9 +100,9 @@ fi
97
100
  # CLI 바이너리 존재 확인
98
101
  if [ ! -f "$BIN_PATH" ]; then
99
102
  if [ "$LANGUAGE" = "en" ]; then
100
- echo "❌ bin/entity-cli not found. Run: ./scripts/build.sh"
103
+ echo "❌ entity-cli not found (bin/entity-cli or ./entity-cli). Run: ./scripts/build.sh"
101
104
  else
102
- echo "❌ bin/entity-cli 파일이 없습니다. 먼저 ./scripts/build.sh 를 실행하세요."
105
+ echo "❌ entity-cli 파일이 없습니다 (bin/entity-cli 또는 ./entity-cli). 먼저 ./scripts/build.sh 를 실행하세요."
103
106
  fi
104
107
  exit 1
105
108
  fi
@@ -19,12 +19,86 @@ trap cleanup EXIT
19
19
 
20
20
  cd "$PROJECT_ROOT"
21
21
 
22
+ ENTITY_CLI_BIN="$PROJECT_ROOT/bin/entity-cli"
23
+ if [ ! -f "$ENTITY_CLI_BIN" ] && [ -f "$PROJECT_ROOT/entity-cli" ]; then
24
+ ENTITY_CLI_BIN="$PROJECT_ROOT/entity-cli"
25
+ fi
26
+
22
27
  # Load language from .env
23
28
  if [ -f .env ]; then
24
29
  LANGUAGE=$(grep '^LANGUAGE=' .env | cut -d '=' -f2 || true)
25
30
  fi
26
31
  LANGUAGE=${LANGUAGE:-ko}
27
32
 
33
+ get_env_value() {
34
+ local key="$1"
35
+ local value="${!key}"
36
+
37
+ if [ -n "$value" ]; then
38
+ echo "$value"
39
+ return
40
+ fi
41
+
42
+ if [ -f .env ]; then
43
+ value=$(grep -E "^${key}=" .env | tail -n 1 | cut -d '=' -f2-)
44
+ echo "$value"
45
+ fi
46
+ }
47
+
48
+ get_database_default_group() {
49
+ grep -E '"default"[[:space:]]*:' "$PROJECT_ROOT/configs/database.json" \
50
+ | head -n 1 \
51
+ | sed -E 's/.*:[[:space:]]*"([^"]+)".*/\1/'
52
+ }
53
+
54
+ get_database_group_field() {
55
+ local group="$1"
56
+ local field="$2"
57
+
58
+ awk -v group="$group" -v field="$field" '
59
+ $0 ~ "^[[:space:]]*\"" group "\"[[:space:]]*:[[:space:]]*\\{" { in_group=1; next }
60
+ in_group && $0 ~ "^[[:space:]]*}" { exit }
61
+ in_group && $0 ~ "^[[:space:]]*\"" field "\"[[:space:]]*:" {
62
+ match($0, /"[^"]+"[[:space:]]*:[[:space:]]*"([^"]+)"/, arr)
63
+ if (arr[1] != "") {
64
+ print arr[1]
65
+ }
66
+ exit
67
+ }
68
+ ' "$PROJECT_ROOT/configs/database.json"
69
+ }
70
+
71
+ resolve_database_name() {
72
+ local group="$1"
73
+ local raw_value
74
+ raw_value=$(get_database_group_field "$group" "database")
75
+
76
+ if [[ "$raw_value" =~ ^\$\{([A-Z0-9_]+)\}$ ]]; then
77
+ get_env_value "${BASH_REMATCH[1]}"
78
+ return
79
+ fi
80
+
81
+ echo "$raw_value"
82
+ }
83
+
84
+ print_target_database() {
85
+ local group
86
+ local database_name
87
+
88
+ group=$(get_database_default_group)
89
+ database_name=$(resolve_database_name "$group")
90
+
91
+ echo ""
92
+ if [ "$LANGUAGE" = "en" ]; then
93
+ echo "Target database group: ${group:-<unknown>}"
94
+ echo "Target database name : ${database_name:-<unknown>}"
95
+ else
96
+ echo "대상 DB 그룹 : ${group:-<unknown>}"
97
+ echo "대상 DB 이름 : ${database_name:-<unknown>}"
98
+ fi
99
+ echo ""
100
+ }
101
+
28
102
  # Show usage if no arguments
29
103
  if [ $# -eq 0 ]; then
30
104
  if [ "$LANGUAGE" = "en" ]; then
@@ -66,11 +140,11 @@ if [ $# -eq 0 ]; then
66
140
  fi
67
141
 
68
142
  # Require prebuilt CLI binary
69
- if [ ! -f "$PROJECT_ROOT/bin/entity-cli" ]; then
143
+ if [ ! -f "$ENTITY_CLI_BIN" ]; then
70
144
  if [ "$LANGUAGE" = "en" ]; then
71
- echo "❌ bin/entity-cli not found"
145
+ echo "❌ entity-cli not found (bin/entity-cli or ./entity-cli)"
72
146
  else
73
- echo "❌ bin/entity-cli 파일이 없습니다"
147
+ echo "❌ entity-cli 파일이 없습니다 (bin/entity-cli 또는 ./entity-cli)"
74
148
  fi
75
149
  exit 1
76
150
  fi
@@ -78,9 +152,11 @@ fi
78
152
  # Execute based on flag
79
153
  case "$1" in
80
154
  --dry-run)
81
- "$PROJECT_ROOT/bin/entity-cli" reset-all
155
+ print_target_database
156
+ "$ENTITY_CLI_BIN" reset-all
82
157
  ;;
83
158
  --force|--apply)
159
+ print_target_database
84
160
  # 필수 엔티티 없으면 자동 생성 (api_keys, rbac_roles, account, user)
85
161
  if [ "$LANGUAGE" = "en" ]; then
86
162
  echo "⚙️ Checking required entities..."
@@ -88,15 +164,16 @@ case "$1" in
88
164
  echo "⚙️ 필수 엔티티 확인 중..."
89
165
  fi
90
166
  LANGUAGE="$LANGUAGE" "$SCRIPT_DIR/normalize-entities.sh" --apply
167
+
91
168
  RESET_LOG=$(mktemp)
92
169
  if [ "$1" = "--force" ]; then
93
170
  set +e
94
- "$PROJECT_ROOT/bin/entity-cli" reset-all --apply --force 2>&1 | tee "$RESET_LOG"
171
+ "$ENTITY_CLI_BIN" reset-all --apply --force 2>&1 | tee "$RESET_LOG"
95
172
  RESET_STATUS=${PIPESTATUS[0]}
96
173
  set -e
97
174
  else
98
175
  set +e
99
- "$PROJECT_ROOT/bin/entity-cli" reset-all --apply 2>&1 | tee "$RESET_LOG"
176
+ "$ENTITY_CLI_BIN" reset-all --apply 2>&1 | tee "$RESET_LOG"
100
177
  RESET_STATUS=${PIPESTATUS[0]}
101
178
  set -e
102
179
  fi
@@ -110,8 +187,8 @@ case "$1" in
110
187
  fi
111
188
 
112
189
  # 새로 생성된 API 키 조회 후 .env 업데이트
113
- NEW_API_KEY=$("$PROJECT_ROOT/bin/entity-cli" api-key show --seq=1 --reveal-secret 2>/dev/null | grep -E '^key_value' | awk '{print $NF}')
114
- NEW_HMAC=$("$PROJECT_ROOT/bin/entity-cli" api-key show --seq=1 --reveal-secret 2>/dev/null | grep -E '^hmac_secret' | awk '{print $NF}')
190
+ NEW_API_KEY=$("$ENTITY_CLI_BIN" api-key show --seq=1 --reveal-secret 2>/dev/null | grep -E '^key_value' | awk '{print $NF}')
191
+ NEW_HMAC=$("$ENTITY_CLI_BIN" api-key show --seq=1 --reveal-secret 2>/dev/null | grep -E '^hmac_secret' | awk '{print $NF}')
115
192
 
116
193
  if [ -n "$NEW_API_KEY" ] && [ -n "$NEW_HMAC" ]; then
117
194
  echo ""
@@ -123,15 +200,16 @@ case "$1" in
123
200
  echo " ENTITY_API_KEY = $NEW_API_KEY"
124
201
  echo " ENTITY_HMAC_SECRET = $NEW_HMAC"
125
202
 
126
- # 게이트웨이 .env 자동 업데이트 (같은 저장소 내에 있는 경우)
127
- GW_ENV="$PROJECT_ROOT/packages/entity-app-server/.env"
128
- if [ -f "$GW_ENV" ]; then
203
+ # 게이트웨이 .env 자동 업데이트 (개발 환경: entity-app-server/ 폴더가 같은 레벨에 있을 때만)
204
+ GW_DIR="$(dirname "$PROJECT_ROOT")/entity-app-server"
205
+ GW_ENV="$GW_DIR/.env"
206
+ if [ -d "$GW_DIR" ] && [ -f "$GW_ENV" ]; then
129
207
  sed -i "s|^ENTITY_API_KEY=.*|ENTITY_API_KEY=$NEW_API_KEY|" "$GW_ENV"
130
208
  sed -i "s|^ENTITY_HMAC_SECRET=.*|ENTITY_HMAC_SECRET=$NEW_HMAC|" "$GW_ENV"
131
209
  if [ "$LANGUAGE" = "en" ]; then
132
- echo " ✓ Updated: packages/entity-app-server/.env"
210
+ echo " ✓ Updated: entity-app-server/.env"
133
211
  else
134
- echo " ✓ 업데이트 완료: packages/entity-app-server/.env"
212
+ echo " ✓ 업데이트 완료: entity-app-server/.env"
135
213
  fi
136
214
  fi
137
215
  fi