create-entity-server 0.0.31 → 0.2.2
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/package.json +1 -1
- package/template/configs/database.json +18 -7
- package/template/entities/README.md +3 -3
- package/template/entities/System/Address/addr_dong.json +10115 -0
- package/template/entities/System/Address/addr_sido.json +39 -0
- package/template/entities/System/Address/addr_sigungu.json +1398 -0
- package/template/entities/System/Auth/account.json +0 -64
- package/template/entities/System/Auth/account_device.json +7 -22
- package/template/entities/System/Auth/account_login_log.json +3 -8
- package/template/entities/System/Auth/anon_device.json +56 -0
- package/template/scripts/reset-all.sh +78 -5
- package/template/scripts/run.sh +73 -27
- package/template/configs/auth/oauth.json +0 -40
- package/template/configs/auth/password.json +0 -45
- package/template/configs/keys/apns.p8.example +0 -7
- package/template/configs/keys/firebase.pem.example +0 -7
- package/template/configs/notification/push.json +0 -25
- package/template/entities/System/Auth/account_oauth.json +0 -74
- package/template/entities/System/Auth/identity_verification.json +0 -106
- package/template/entities/System/Auth/password_history.json +0 -19
- package/template/entities/System/Notification/alimtalk_log.json +0 -65
- package/template/entities/System/Notification/alimtalk_msg.json +0 -53
- package/template/entities/System/Notification/friendtalk_log.json +0 -89
- package/template/entities/System/Notification/friendtalk_msg.json +0 -91
- package/template/entities/System/Notification/sms_log.json +0 -65
- package/template/entities/System/Notification/sms_msg.json +0 -82
- package/template/entities/System/Notification/sms_verification.json +0 -50
- package/template/entities/System/Payment/pg_cancel.json +0 -60
- package/template/entities/System/Payment/pg_order.json +0 -115
- package/template/entities/System/Payment/pg_webhook_log.json +0 -52
- package/template/entities/System/Push/push_log.json +0 -86
- package/template/entities/System/Push/push_msg.json +0 -56
- package/template/templates/email/auth/2fa_disabled.html +0 -23
- package/template/templates/email/auth/2fa_recovery_regenerated.html +0 -31
- package/template/templates/email/auth/2fa_setup_complete.html +0 -43
- package/template/templates/email/auth/welcome.html +0 -18
- package/template/templates/email/order/order_confirmation.html +0 -30
- /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": "계정 기기 정보 및 푸시 토큰 관리.
|
|
3
|
+
"description": "회원 계정 기기 정보 및 푸시 토큰 관리. account_seq로 계정과 연결되며 회원 전용으로 사용합니다. 사용자 환경에 맞게 fields를 자유롭게 확장할 수 있습니다.",
|
|
4
4
|
"license_scope": false,
|
|
5
5
|
"fields": {
|
|
6
6
|
"account_seq": {
|
|
7
7
|
"index": true,
|
|
8
|
-
"
|
|
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
|
-
"
|
|
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
|
+
}
|
|
@@ -25,6 +25,75 @@ if [ -f .env ]; then
|
|
|
25
25
|
fi
|
|
26
26
|
LANGUAGE=${LANGUAGE:-ko}
|
|
27
27
|
|
|
28
|
+
get_env_value() {
|
|
29
|
+
local key="$1"
|
|
30
|
+
local value="${!key}"
|
|
31
|
+
|
|
32
|
+
if [ -n "$value" ]; then
|
|
33
|
+
echo "$value"
|
|
34
|
+
return
|
|
35
|
+
fi
|
|
36
|
+
|
|
37
|
+
if [ -f .env ]; then
|
|
38
|
+
value=$(grep -E "^${key}=" .env | tail -n 1 | cut -d '=' -f2-)
|
|
39
|
+
echo "$value"
|
|
40
|
+
fi
|
|
41
|
+
}
|
|
42
|
+
|
|
43
|
+
get_database_default_group() {
|
|
44
|
+
grep -E '"default"[[:space:]]*:' "$PROJECT_ROOT/configs/database.json" \
|
|
45
|
+
| head -n 1 \
|
|
46
|
+
| sed -E 's/.*:[[:space:]]*"([^"]+)".*/\1/'
|
|
47
|
+
}
|
|
48
|
+
|
|
49
|
+
get_database_group_field() {
|
|
50
|
+
local group="$1"
|
|
51
|
+
local field="$2"
|
|
52
|
+
|
|
53
|
+
awk -v group="$group" -v field="$field" '
|
|
54
|
+
$0 ~ "^[[:space:]]*\"" group "\"[[:space:]]*:[[:space:]]*\\{" { in_group=1; next }
|
|
55
|
+
in_group && $0 ~ "^[[:space:]]*}" { exit }
|
|
56
|
+
in_group && $0 ~ "^[[:space:]]*\"" field "\"[[:space:]]*:" {
|
|
57
|
+
match($0, /"[^"]+"[[:space:]]*:[[:space:]]*"([^"]+)"/, arr)
|
|
58
|
+
if (arr[1] != "") {
|
|
59
|
+
print arr[1]
|
|
60
|
+
}
|
|
61
|
+
exit
|
|
62
|
+
}
|
|
63
|
+
' "$PROJECT_ROOT/configs/database.json"
|
|
64
|
+
}
|
|
65
|
+
|
|
66
|
+
resolve_database_name() {
|
|
67
|
+
local group="$1"
|
|
68
|
+
local raw_value
|
|
69
|
+
raw_value=$(get_database_group_field "$group" "database")
|
|
70
|
+
|
|
71
|
+
if [[ "$raw_value" =~ ^\$\{([A-Z0-9_]+)\}$ ]]; then
|
|
72
|
+
get_env_value "${BASH_REMATCH[1]}"
|
|
73
|
+
return
|
|
74
|
+
fi
|
|
75
|
+
|
|
76
|
+
echo "$raw_value"
|
|
77
|
+
}
|
|
78
|
+
|
|
79
|
+
print_target_database() {
|
|
80
|
+
local group
|
|
81
|
+
local database_name
|
|
82
|
+
|
|
83
|
+
group=$(get_database_default_group)
|
|
84
|
+
database_name=$(resolve_database_name "$group")
|
|
85
|
+
|
|
86
|
+
echo ""
|
|
87
|
+
if [ "$LANGUAGE" = "en" ]; then
|
|
88
|
+
echo "Target database group: ${group:-<unknown>}"
|
|
89
|
+
echo "Target database name : ${database_name:-<unknown>}"
|
|
90
|
+
else
|
|
91
|
+
echo "대상 DB 그룹 : ${group:-<unknown>}"
|
|
92
|
+
echo "대상 DB 이름 : ${database_name:-<unknown>}"
|
|
93
|
+
fi
|
|
94
|
+
echo ""
|
|
95
|
+
}
|
|
96
|
+
|
|
28
97
|
# Show usage if no arguments
|
|
29
98
|
if [ $# -eq 0 ]; then
|
|
30
99
|
if [ "$LANGUAGE" = "en" ]; then
|
|
@@ -78,9 +147,11 @@ fi
|
|
|
78
147
|
# Execute based on flag
|
|
79
148
|
case "$1" in
|
|
80
149
|
--dry-run)
|
|
150
|
+
print_target_database
|
|
81
151
|
"$PROJECT_ROOT/bin/entity-cli" reset-all
|
|
82
152
|
;;
|
|
83
153
|
--force|--apply)
|
|
154
|
+
print_target_database
|
|
84
155
|
# 필수 엔티티 없으면 자동 생성 (api_keys, rbac_roles, account, user)
|
|
85
156
|
if [ "$LANGUAGE" = "en" ]; then
|
|
86
157
|
echo "⚙️ Checking required entities..."
|
|
@@ -88,6 +159,7 @@ case "$1" in
|
|
|
88
159
|
echo "⚙️ 필수 엔티티 확인 중..."
|
|
89
160
|
fi
|
|
90
161
|
LANGUAGE="$LANGUAGE" "$SCRIPT_DIR/normalize-entities.sh" --apply
|
|
162
|
+
|
|
91
163
|
RESET_LOG=$(mktemp)
|
|
92
164
|
if [ "$1" = "--force" ]; then
|
|
93
165
|
set +e
|
|
@@ -123,15 +195,16 @@ case "$1" in
|
|
|
123
195
|
echo " ENTITY_API_KEY = $NEW_API_KEY"
|
|
124
196
|
echo " ENTITY_HMAC_SECRET = $NEW_HMAC"
|
|
125
197
|
|
|
126
|
-
# 게이트웨이 .env 자동 업데이트 (같은
|
|
127
|
-
|
|
128
|
-
|
|
198
|
+
# 게이트웨이 .env 자동 업데이트 (개발 환경: entity-app-server/ 폴더가 같은 레벨에 있을 때만)
|
|
199
|
+
GW_DIR="$(dirname "$PROJECT_ROOT")/entity-app-server"
|
|
200
|
+
GW_ENV="$GW_DIR/.env"
|
|
201
|
+
if [ -d "$GW_DIR" ] && [ -f "$GW_ENV" ]; then
|
|
129
202
|
sed -i "s|^ENTITY_API_KEY=.*|ENTITY_API_KEY=$NEW_API_KEY|" "$GW_ENV"
|
|
130
203
|
sed -i "s|^ENTITY_HMAC_SECRET=.*|ENTITY_HMAC_SECRET=$NEW_HMAC|" "$GW_ENV"
|
|
131
204
|
if [ "$LANGUAGE" = "en" ]; then
|
|
132
|
-
echo " ✓ Updated:
|
|
205
|
+
echo " ✓ Updated: entity-app-server/.env"
|
|
133
206
|
else
|
|
134
|
-
echo " ✓ 업데이트 완료:
|
|
207
|
+
echo " ✓ 업데이트 완료: entity-app-server/.env"
|
|
135
208
|
fi
|
|
136
209
|
fi
|
|
137
210
|
fi
|
package/template/scripts/run.sh
CHANGED
|
@@ -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 "
|
|
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
|
|
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
|
|
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
|
|
301
|
-
echo " start environment=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
|
-
|
|
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
|
-
|
|
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 &
|
|
@@ -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,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
|
-
}
|