create-entity-app-server 0.1.15 → 0.2.0

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 (52) hide show
  1. package/bin/create.js +2 -2
  2. package/dist-create/template/.env +2 -2
  3. package/dist-create/template/.env.example +2 -2
  4. package/dist-create/template/.gateway-version +1 -1
  5. package/dist-create/template/app/plugins/ocr/cache.ts +1 -1
  6. package/dist-create/template/app/plugins/ocr/config.ts +1 -1
  7. package/dist-create/template/app/plugins/ocr/direction.ts +1 -1
  8. package/dist-create/template/app/plugins/ocr/dispatch.ts +1 -1
  9. package/dist-create/template/app/plugins/ocr/entity-adapter.ts +1 -1
  10. package/dist-create/template/app/plugins/ocr/errors.ts +1 -1
  11. package/dist-create/template/app/plugins/ocr/handlers.ts +1 -1
  12. package/dist-create/template/app/plugins/ocr/index.ts +1 -1
  13. package/dist-create/template/app/plugins/ocr/llm-parser.ts +1 -1
  14. package/dist-create/template/app/plugins/ocr/parsing-pipeline.ts +1 -1
  15. package/dist-create/template/app/plugins/ocr/pdf-converter.ts +1 -1
  16. package/dist-create/template/app/plugins/ocr/preprocessor.ts +1 -1
  17. package/dist-create/template/app/plugins/ocr/providers/aws.ts +1 -1
  18. package/dist-create/template/app/plugins/ocr/providers/azure.ts +1 -1
  19. package/dist-create/template/app/plugins/ocr/providers/google.ts +1 -1
  20. package/dist-create/template/app/plugins/ocr/providers/index.ts +1 -1
  21. package/dist-create/template/app/plugins/ocr/providers/naver.ts +1 -1
  22. package/dist-create/template/app/plugins/ocr/providers/tesseract.ts +1 -1
  23. package/dist-create/template/app/plugins/ocr/providers/upstage.ts +1 -1
  24. package/dist-create/template/app/plugins/ocr/quota.ts +1 -1
  25. package/dist-create/template/app/plugins/ocr/refiner.ts +1 -1
  26. package/dist-create/template/app/plugins/ocr/routes.ts +1 -1
  27. package/dist-create/template/app/plugins/ocr/service.ts +1 -1
  28. package/dist-create/template/app/plugins/ocr/template-loader.ts +1 -1
  29. package/dist-create/template/app/plugins/ocr/template-matcher.ts +1 -1
  30. package/dist-create/template/app/plugins/ocr/types/config.ts +1 -1
  31. package/dist-create/template/app/plugins/ocr/types/driver.ts +1 -1
  32. package/dist-create/template/app/plugins/ocr/types/index.ts +1 -1
  33. package/dist-create/template/app/plugins/ocr/types/parsed.ts +1 -1
  34. package/dist-create/template/app/plugins/ocr/types/store.ts +1 -1
  35. package/dist-create/template/app/plugins/ocr/types/template.ts +1 -1
  36. package/dist-create/template/app/plugins/ocr/utils.ts +1 -1
  37. package/dist-create/template/app/plugins/smtp/config.ts +41 -1
  38. package/dist-create/template/app/plugins/smtp/handlers.ts +52 -1
  39. package/dist-create/template/app/plugins/smtp/index.ts +33 -1
  40. package/dist-create/template/app/plugins/smtp/routes.ts +19 -1
  41. package/dist-create/template/app/plugins/smtp/types/config.ts +8 -1
  42. package/dist-create/template/app/plugins/smtp/types/index.ts +1 -1
  43. package/dist-create/template/docs/configs.md +12 -14
  44. package/dist-create/template/docs/getting-started.md +5 -3
  45. package/dist-create/template/docs/scripts-guide.md +51 -22
  46. package/dist-create/template/scripts/run.sh +229 -6
  47. package/dist-create/template/scripts/service-install.sh +174 -0
  48. package/dist-create/template/scripts/service-remove.sh +102 -0
  49. package/dist-create/template/scripts/update-server.sh +25 -20
  50. package/dist-create/template/system-api.js +1 -1
  51. package/dist-create/template/system.js +1 -1
  52. package/package.json +1 -1
@@ -19,6 +19,187 @@ cd "$PROJECT_ROOT"
19
19
  PID_FILE="$PROJECT_ROOT/.gateway.pid"
20
20
  LOG_FILE="$PROJECT_ROOT/logs/gateway.log"
21
21
 
22
+ is_placeholder_value() {
23
+ local value="$1"
24
+
25
+ [[ "$value" =~ ^(your-|replace-with|change-this) ]] && return 0
26
+ [[ "$value" = "shared-jwt-secret" ]] && return 0
27
+ [[ "$value" = "your-jwt-secret" ]] && return 0
28
+ [[ "$value" = "your-api-key" ]] && return 0
29
+ [[ "$value" = "your-hmac-secret" ]] && return 0
30
+
31
+ return 1
32
+ }
33
+
34
+ show_env_setup_error() {
35
+ local reason="$1"
36
+
37
+ echo "❌ .env 설정이 아직 완료되지 않았습니다."
38
+ echo " $reason"
39
+ echo ""
40
+ echo " 확인할 항목:"
41
+ echo " 1. .env 의 ENTITY_SERVER_URL"
42
+ echo " 2. .env 의 ENTITY_API_KEY"
43
+ echo " 3. .env 의 ENTITY_HMAC_SECRET (32자 이상)"
44
+ echo " 4. .env 의 JWT_SECRET (32자 이상, Entity Server와 동일)"
45
+ echo ""
46
+ echo " 예시 파일: .env.example"
47
+ exit 1
48
+ }
49
+
50
+ ensure_env_ready() {
51
+ if [ ! -f "$PROJECT_ROOT/.env" ]; then
52
+ show_env_setup_error ".env 파일이 없습니다. .env.example 을 참고해 .env 를 생성하세요."
53
+ fi
54
+
55
+ local entity_server_url="${ENTITY_SERVER_URL:-}"
56
+ local entity_api_key="${ENTITY_API_KEY:-}"
57
+ local entity_hmac_secret="${ENTITY_HMAC_SECRET:-}"
58
+ local jwt_secret="${JWT_SECRET:-}"
59
+
60
+ if [ -z "$entity_server_url" ]; then
61
+ show_env_setup_error "ENTITY_SERVER_URL 이 비어 있습니다."
62
+ fi
63
+
64
+ if [ -z "$entity_api_key" ]; then
65
+ show_env_setup_error "ENTITY_API_KEY 가 비어 있습니다."
66
+ fi
67
+
68
+ if [ -z "$entity_hmac_secret" ]; then
69
+ show_env_setup_error "ENTITY_HMAC_SECRET 이 비어 있습니다."
70
+ fi
71
+
72
+ if [ -z "$jwt_secret" ]; then
73
+ show_env_setup_error "JWT_SECRET 이 비어 있습니다."
74
+ fi
75
+
76
+ if is_placeholder_value "$entity_api_key"; then
77
+ show_env_setup_error "ENTITY_API_KEY 가 예시 값입니다. Entity Server에서 발급한 실제 키로 바꾸세요."
78
+ fi
79
+
80
+ if is_placeholder_value "$entity_hmac_secret"; then
81
+ show_env_setup_error "ENTITY_HMAC_SECRET 이 예시 값입니다. Entity Server에서 발급한 실제 시크릿으로 바꾸세요."
82
+ fi
83
+
84
+ if is_placeholder_value "$jwt_secret"; then
85
+ show_env_setup_error "JWT_SECRET 이 예시 값입니다. Entity Server와 동일한 실제 시크릿으로 바꾸세요."
86
+ fi
87
+
88
+ if [ "${#entity_hmac_secret}" -lt 32 ]; then
89
+ show_env_setup_error "ENTITY_HMAC_SECRET 은 32자 이상이어야 합니다."
90
+ fi
91
+
92
+ if [ "${#jwt_secret}" -lt 32 ]; then
93
+ show_env_setup_error "JWT_SECRET 은 32자 이상이어야 합니다."
94
+ fi
95
+ }
96
+
97
+ verify_entity_server_credentials() {
98
+ local result
99
+
100
+ result=$(node <<'NODE'
101
+ const { createHmac, randomUUID } = require("node:crypto");
102
+
103
+ const baseUrl = String(process.env.ENTITY_SERVER_URL || "").replace(/\/$/, "");
104
+ const apiKey = String(process.env.ENTITY_API_KEY || "");
105
+ const hmacSecret = String(process.env.ENTITY_HMAC_SECRET || "");
106
+
107
+ async function main() {
108
+ const healthUrl = `${baseUrl}/v1/health`;
109
+
110
+ try {
111
+ const health = await fetch(healthUrl, { signal: AbortSignal.timeout(5000) });
112
+ if (!health.ok) {
113
+ console.log(`HEALTH_HTTP:${health.status}`);
114
+ return;
115
+ }
116
+ } catch (error) {
117
+ console.log(`HEALTH_ERROR:${error instanceof Error ? error.message : String(error)}`);
118
+ return;
119
+ }
120
+
121
+ const method = "GET";
122
+ const path = "/v1/admin/configs";
123
+ const timestamp = String(Math.floor(Date.now() / 1000));
124
+ const nonce = randomUUID();
125
+ const payload = Buffer.from(`${method}|${path}|${timestamp}|${nonce}|`, "utf8");
126
+ const signature = createHmac("sha256", hmacSecret).update(payload).digest("hex");
127
+
128
+ try {
129
+ const response = await fetch(`${baseUrl}${path}`, {
130
+ method,
131
+ headers: {
132
+ "X-API-Key": apiKey,
133
+ "X-Timestamp": timestamp,
134
+ "X-Nonce": nonce,
135
+ "X-Signature": signature,
136
+ },
137
+ signal: AbortSignal.timeout(5000),
138
+ });
139
+
140
+ if (response.ok) {
141
+ console.log("OK");
142
+ return;
143
+ }
144
+
145
+ const text = (await response.text().catch(() => "")).trim();
146
+ console.log(`AUTH_HTTP:${response.status}:${text}`);
147
+ } catch (error) {
148
+ console.log(`AUTH_ERROR:${error instanceof Error ? error.message : String(error)}`);
149
+ }
150
+ }
151
+
152
+ main();
153
+ NODE
154
+ )
155
+
156
+ case "$result" in
157
+ OK)
158
+ return 0
159
+ ;;
160
+ HEALTH_HTTP:*)
161
+ echo "❌ Entity Server에 연결했지만 헬스체크가 실패했습니다."
162
+ echo " 주소: ${ENTITY_SERVER_URL}"
163
+ echo " 응답: ${result#HEALTH_HTTP:}"
164
+ exit 1
165
+ ;;
166
+ HEALTH_ERROR:*)
167
+ echo "❌ Entity Server에 연결할 수 없습니다."
168
+ echo " 주소: ${ENTITY_SERVER_URL}"
169
+ echo " 원인: ${result#HEALTH_ERROR:}"
170
+ echo " Entity Server가 실행 중인지 먼저 확인하세요."
171
+ exit 1
172
+ ;;
173
+ AUTH_HTTP:401:*|AUTH_HTTP:403:*)
174
+ echo "❌ .env 의 Entity Server 인증 정보가 맞지 않습니다."
175
+ echo " ENTITY_API_KEY 또는 ENTITY_HMAC_SECRET 이 Entity Server 값과 다릅니다."
176
+ echo " Entity Server 관리자에서 발급된 API Key / HMAC Secret 을 다시 복사하세요."
177
+ exit 1
178
+ ;;
179
+ AUTH_HTTP:404:*)
180
+ echo "❌ Entity Server 관리자 API 점검 경로를 찾지 못했습니다."
181
+ echo " 연결 대상: ${ENTITY_SERVER_URL}"
182
+ echo " /v1/admin/configs 가 없는 구버전 서버이거나 잘못된 주소일 수 있습니다."
183
+ exit 1
184
+ ;;
185
+ AUTH_HTTP:*)
186
+ echo "❌ Entity Server 인증 점검 중 오류가 발생했습니다."
187
+ echo " 응답: ${result#AUTH_HTTP:}"
188
+ exit 1
189
+ ;;
190
+ AUTH_ERROR:*)
191
+ echo "❌ Entity Server 인증 점검 요청을 보내지 못했습니다."
192
+ echo " 원인: ${result#AUTH_ERROR:}"
193
+ exit 1
194
+ ;;
195
+ *)
196
+ echo "❌ Entity Server 사전 점검 결과를 해석하지 못했습니다."
197
+ echo " 응답: $result"
198
+ exit 1
199
+ ;;
200
+ esac
201
+ }
202
+
22
203
  ensure_runtime_dependencies_installed() {
23
204
  if [ -d "$PROJECT_ROOT/node_modules/tsx" ]; then
24
205
  return 0
@@ -58,6 +239,30 @@ find_gateway_pids() {
58
239
  ss -ltnp 2>/dev/null | sed -n "s/.*:$port .*pid=\([0-9]\+\).*/\1/p" | sort -u
59
240
  }
60
241
 
242
+ show_status() {
243
+ local pid=""
244
+
245
+ if [ -f "$PID_FILE" ]; then
246
+ pid=$(cat "$PID_FILE" 2>/dev/null || true)
247
+ fi
248
+
249
+ if [ -n "$pid" ] && kill -0 "$pid" 2>/dev/null; then
250
+ echo "✅ Entity App Server가 실행 중입니다 (pid: $pid)"
251
+ echo "로그: $LOG_FILE"
252
+ return 0
253
+ fi
254
+
255
+ mapfile -t PORT_PIDS < <(find_gateway_pids)
256
+ if [ "${#PORT_PIDS[@]}" -gt 0 ]; then
257
+ echo "✅ Entity App Server가 실행 중입니다 (pid: ${PORT_PIDS[0]})"
258
+ echo "로그: $LOG_FILE"
259
+ return 0
260
+ fi
261
+
262
+ echo "ℹ️ Entity App Server가 실행 중이지 않습니다."
263
+ return 1
264
+ }
265
+
61
266
  show_port_in_use_error() {
62
267
  local port
63
268
  port=$(get_gateway_port)
@@ -109,11 +314,13 @@ _print_help() {
109
314
  echo " 명령:"
110
315
  echo " start 프로덕션 모드로 백그라운드 실행 (dist/system.js)"
111
316
  echo " stop 실행 중인 서버 종료"
317
+ echo " status 실행 상태 확인"
112
318
  echo " dev 개발 모드 실행 (tsx watch)"
113
319
  echo ""
114
320
  echo " 예제:"
115
321
  echo " $0 start # 서버 시작"
116
322
  echo " $0 stop # 서버 종료"
323
+ echo " $0 status # 실행 상태 확인"
117
324
  echo " $0 dev # 개발 모드"
118
325
  echo ""
119
326
  if [ -f "$PID_FILE" ]; then
@@ -130,13 +337,18 @@ _print_help() {
130
337
 
131
338
  if [ $# -eq 0 ]; then
132
339
  _print_help
340
+ echo ""
341
+ echo "현재 상태:"
342
+ show_status
133
343
  exit 0
134
344
  fi
135
345
 
136
346
  case "$1" in
137
347
  start)
138
348
  ensure_port_available
349
+ ensure_env_ready
139
350
  ensure_runtime_dependencies_installed
351
+ verify_entity_server_credentials
140
352
 
141
353
  if [ ! -f "dist/system.js" ]; then
142
354
  echo "❌ dist/system.js가 없습니다. 먼저 빌드하세요:"
@@ -160,12 +372,17 @@ case "$1" in
160
372
  echo $! > "$PID_FILE"
161
373
  PID=$(cat "$PID_FILE")
162
374
 
163
- echo ""
164
- echo " ✓ Entity App Server 시작됨"
165
- echo " PID: $PID"
166
- echo " 로그: $LOG_FILE"
167
- echo " 종료: $0 stop"
168
- echo ""
375
+ sleep 0.3
376
+ if kill -0 "$PID" 2>/dev/null; then
377
+ echo "✅ Entity App Server가 백그라운드에서 시작되었습니다 (pid: $PID)"
378
+ echo "상태: ./run.sh status"
379
+ echo "중지: ./run.sh stop"
380
+ else
381
+ rm -f "$PID_FILE"
382
+ echo "❌ Entity App Server 백그라운드 시작에 실패했습니다"
383
+ echo "로그 확인: $LOG_FILE"
384
+ exit 1
385
+ fi
169
386
  ;;
170
387
 
171
388
  stop)
@@ -195,13 +412,19 @@ case "$1" in
195
412
  fi
196
413
  ;;
197
414
 
415
+ status)
416
+ show_status
417
+ ;;
418
+
198
419
  dev)
199
420
  if [ -f "$PID_FILE" ] || [ -n "$(find_gateway_pids | head -n 1)" ]; then
200
421
  echo " 기존 Entity App Server 정리 중..."
201
422
  "$SCRIPT_DIR/run.sh" stop
202
423
  fi
203
424
 
425
+ ensure_env_ready
204
426
  ensure_runtime_dependencies_installed
427
+ verify_entity_server_credentials
205
428
 
206
429
  echo " Starting Entity App Server (dev mode)..."
207
430
  exec npm run dev
@@ -0,0 +1,174 @@
1
+ #!/bin/bash
2
+
3
+ set -euo pipefail
4
+
5
+ SCRIPT_DIR="$(cd "$(dirname "${BASH_SOURCE[0]}")" && pwd)"
6
+ PROJECT_ROOT="$(dirname "$SCRIPT_DIR")"
7
+ SERVER_CONFIG="$PROJECT_ROOT/configs/server.json"
8
+
9
+ if [ -f "$PROJECT_ROOT/.env" ]; then
10
+ LANGUAGE=$(grep '^LANGUAGE=' "$PROJECT_ROOT/.env" | cut -d '=' -f2)
11
+ fi
12
+ LANGUAGE=${LANGUAGE:-ko}
13
+
14
+ SERVICE_NAME="entity-app-server"
15
+ RUN_USER="${SUDO_USER:-$(stat -c '%U' "$PROJECT_ROOT")}"
16
+ RUN_GROUP="$(id -gn "$RUN_USER" 2>/dev/null || true)"
17
+ START_NOW=true
18
+ INTERACTIVE=false
19
+
20
+ load_service_name() {
21
+ local namespace=""
22
+ if [ -f "$SERVER_CONFIG" ]; then
23
+ namespace=$(sed -n 's/.*"namespace"[[:space:]]*:[[:space:]]*"\([^"]*\)".*/\1/p' "$SERVER_CONFIG" | head -n 1)
24
+ fi
25
+
26
+ namespace=$(echo "$namespace" | tr '[:upper:]' '[:lower:]' | sed 's/[^a-z0-9_-]/-/g')
27
+
28
+ if [ -z "$namespace" ]; then
29
+ SERVICE_NAME="entity-app-server"
30
+ elif [[ "$namespace" == "entity-app-server" ]] || [[ "$namespace" == *"-entity-app-server" ]]; then
31
+ SERVICE_NAME="$namespace"
32
+ else
33
+ SERVICE_NAME="${namespace}-entity-app-server"
34
+ fi
35
+ }
36
+
37
+ load_service_name
38
+
39
+ if [ $# -eq 0 ]; then
40
+ INTERACTIVE=true
41
+ fi
42
+
43
+ for arg in "$@"; do
44
+ case "$arg" in
45
+ --user=*)
46
+ RUN_USER="${arg#*=}"
47
+ ;;
48
+ --group=*)
49
+ RUN_GROUP="${arg#*=}"
50
+ ;;
51
+ --no-start)
52
+ START_NOW=false
53
+ ;;
54
+ *)
55
+ if [ "$LANGUAGE" = "en" ]; then
56
+ echo "❌ Unknown option: $arg"
57
+ else
58
+ echo "❌ 알 수 없는 옵션: $arg"
59
+ fi
60
+ exit 1
61
+ ;;
62
+ esac
63
+ done
64
+
65
+ if [ "$INTERACTIVE" = true ]; then
66
+ if [ "$LANGUAGE" = "en" ]; then
67
+ echo "[interactive] systemd service setup"
68
+ echo "service name: $SERVICE_NAME"
69
+ read -r -p "Run user [$RUN_USER]: " input
70
+ else
71
+ echo "[interactive] systemd 서비스 설정"
72
+ echo "서비스명: $SERVICE_NAME"
73
+ read -r -p "실행 사용자 [$RUN_USER]: " input
74
+ fi
75
+
76
+ if [ -n "$input" ]; then
77
+ RUN_USER="$input"
78
+ fi
79
+
80
+ if [ -z "$RUN_GROUP" ]; then
81
+ RUN_GROUP="$(id -gn "$RUN_USER" 2>/dev/null || true)"
82
+ fi
83
+
84
+ if [ "$LANGUAGE" = "en" ]; then
85
+ read -r -p "Run group [$RUN_GROUP]: " input
86
+ else
87
+ read -r -p "실행 그룹 [$RUN_GROUP]: " input
88
+ fi
89
+
90
+ if [ -n "$input" ]; then
91
+ RUN_GROUP="$input"
92
+ fi
93
+
94
+ if [ "$LANGUAGE" = "en" ]; then
95
+ read -r -p "Start service now? [Y/n]: " input
96
+ else
97
+ read -r -p "서비스를 즉시 시작할까요? [Y/n]: " input
98
+ fi
99
+
100
+ input=$(echo "$input" | tr '[:upper:]' '[:lower:]')
101
+ if [ "$input" = "n" ] || [ "$input" = "no" ]; then
102
+ START_NOW=false
103
+ fi
104
+ fi
105
+
106
+ if [ -z "$RUN_GROUP" ]; then
107
+ RUN_GROUP="$(id -gn "$RUN_USER")"
108
+ fi
109
+
110
+ if ! id -u "$RUN_USER" >/dev/null 2>&1; then
111
+ echo "❌ 사용자를 찾을 수 없습니다: $RUN_USER"
112
+ exit 1
113
+ fi
114
+
115
+ if ! getent group "$RUN_GROUP" >/dev/null 2>&1; then
116
+ echo "❌ 그룹을 찾을 수 없습니다: $RUN_GROUP"
117
+ exit 1
118
+ fi
119
+
120
+ if [ ! -x "$PROJECT_ROOT/scripts/run.sh" ]; then
121
+ chmod +x "$PROJECT_ROOT/scripts/run.sh"
122
+ fi
123
+
124
+ if [ ! -f "$PROJECT_ROOT/system.js" ]; then
125
+ echo "❌ system.js 파일이 없습니다. create-entity-app-server 로 생성된 프로젝트 루트인지 확인하세요."
126
+ exit 1
127
+ fi
128
+
129
+ UNIT_PATH="/etc/systemd/system/${SERVICE_NAME}.service"
130
+
131
+ if [ "$EUID" -ne 0 ]; then
132
+ if command -v sudo >/dev/null 2>&1; then
133
+ SUDO_ARGS=("--user=$RUN_USER" "--group=$RUN_GROUP")
134
+ if [ "$START_NOW" = false ]; then
135
+ SUDO_ARGS+=("--no-start")
136
+ fi
137
+ exec sudo "$0" "${SUDO_ARGS[@]}"
138
+ fi
139
+ echo "❌ 이 스크립트는 root 권한이 필요합니다"
140
+ exit 1
141
+ fi
142
+
143
+ cat > "$UNIT_PATH" <<EOF
144
+ [Unit]
145
+ Description=Entity App Server
146
+ After=network.target
147
+
148
+ [Service]
149
+ Type=simple
150
+ User=$RUN_USER
151
+ Group=$RUN_GROUP
152
+ WorkingDirectory=$PROJECT_ROOT
153
+ EnvironmentFile=-$PROJECT_ROOT/.env
154
+ ExecStart=$PROJECT_ROOT/scripts/run.sh start
155
+ Restart=always
156
+ RestartSec=3
157
+ LimitNOFILE=65535
158
+
159
+ [Install]
160
+ WantedBy=multi-user.target
161
+ EOF
162
+
163
+ systemctl daemon-reload
164
+ systemctl enable "$SERVICE_NAME"
165
+
166
+ if [ "$START_NOW" = true ]; then
167
+ systemctl restart "$SERVICE_NAME"
168
+ fi
169
+
170
+ echo "✅ 서비스 등록 완료: $SERVICE_NAME"
171
+ echo " Unit: $UNIT_PATH"
172
+ echo " 시작: sudo systemctl start $SERVICE_NAME"
173
+ echo " 중지: sudo systemctl stop $SERVICE_NAME"
174
+ echo " 상태: sudo systemctl status $SERVICE_NAME"
@@ -0,0 +1,102 @@
1
+ #!/bin/bash
2
+
3
+ set -euo pipefail
4
+
5
+ SCRIPT_DIR="$(cd "$(dirname "${BASH_SOURCE[0]}")" && pwd)"
6
+ PROJECT_ROOT="$(dirname "$SCRIPT_DIR")"
7
+ SERVER_CONFIG="$PROJECT_ROOT/configs/server.json"
8
+
9
+ if [ -f "$PROJECT_ROOT/.env" ]; then
10
+ LANGUAGE=$(grep '^LANGUAGE=' "$PROJECT_ROOT/.env" | cut -d '=' -f2)
11
+ fi
12
+ LANGUAGE=${LANGUAGE:-ko}
13
+
14
+ SERVICE_NAME="entity-app-server"
15
+ INTERACTIVE=false
16
+ CONFIRMED=false
17
+
18
+ load_service_name() {
19
+ local namespace=""
20
+ if [ -f "$SERVER_CONFIG" ]; then
21
+ namespace=$(sed -n 's/.*"namespace"[[:space:]]*:[[:space:]]*"\([^"]*\)".*/\1/p' "$SERVER_CONFIG" | head -n 1)
22
+ fi
23
+
24
+ namespace=$(echo "$namespace" | tr '[:upper:]' '[:lower:]' | sed 's/[^a-z0-9_-]/-/g')
25
+
26
+ if [ -z "$namespace" ]; then
27
+ SERVICE_NAME="entity-app-server"
28
+ elif [[ "$namespace" == "entity-app-server" ]] || [[ "$namespace" == *"-entity-app-server" ]]; then
29
+ SERVICE_NAME="$namespace"
30
+ else
31
+ SERVICE_NAME="${namespace}-entity-app-server"
32
+ fi
33
+ }
34
+
35
+ load_service_name
36
+
37
+ if [ $# -eq 0 ]; then
38
+ INTERACTIVE=true
39
+ fi
40
+
41
+ for arg in "$@"; do
42
+ case "$arg" in
43
+ --yes|-y)
44
+ CONFIRMED=true
45
+ ;;
46
+ *)
47
+ echo "❌ 알 수 없는 옵션: $arg"
48
+ exit 1
49
+ ;;
50
+ esac
51
+ done
52
+
53
+ if [ "$INTERACTIVE" = true ] && [ "$CONFIRMED" = false ]; then
54
+ echo "[interactive] systemd 서비스 제거"
55
+ echo "서비스명: $SERVICE_NAME"
56
+ read -r -p "'$SERVICE_NAME' 서비스를 제거할까요? [y/N]: " input
57
+ input=$(echo "$input" | tr '[:upper:]' '[:lower:]')
58
+ if [ "$input" != "y" ] && [ "$input" != "yes" ]; then
59
+ echo "취소되었습니다."
60
+ exit 0
61
+ fi
62
+ fi
63
+
64
+ UNIT_PATH="/etc/systemd/system/${SERVICE_NAME}.service"
65
+
66
+ if [ "$EUID" -ne 0 ]; then
67
+ if command -v sudo >/dev/null 2>&1; then
68
+ exec sudo "$0" --yes
69
+ fi
70
+ echo "❌ 이 스크립트는 root 권한이 필요합니다"
71
+ exit 1
72
+ fi
73
+
74
+ SERVICE_EXISTS=false
75
+ if systemctl list-unit-files | grep -q "^${SERVICE_NAME}\.service"; then
76
+ SERVICE_EXISTS=true
77
+ fi
78
+
79
+ if [ ! -f "$UNIT_PATH" ] && [ "$SERVICE_EXISTS" = false ]; then
80
+ echo "ℹ️ '$SERVICE_NAME' 서비스가 등록되어 있지 않습니다."
81
+ echo " 제거할 항목이 없습니다."
82
+ echo ""
83
+ echo " 서비스를 등록하려면:"
84
+ echo " sudo $(dirname "$0")/service-install.sh"
85
+ exit 0
86
+ fi
87
+
88
+ if [ "$SERVICE_EXISTS" = true ]; then
89
+ systemctl stop "$SERVICE_NAME" 2>/dev/null || true
90
+ systemctl disable "$SERVICE_NAME" 2>/dev/null || true
91
+ fi
92
+
93
+ if [ -f "$UNIT_PATH" ]; then
94
+ rm -f "$UNIT_PATH"
95
+ fi
96
+
97
+ systemctl daemon-reload
98
+
99
+ echo "✅ 서비스 제거 완료: $SERVICE_NAME"
100
+ echo ""
101
+ echo " 서비스를 다시 등록하려면:"
102
+ echo " sudo $(dirname "$0")/service-install.sh"
@@ -2,8 +2,7 @@
2
2
  # update-server.sh — Entity App Server 코어 업데이트
3
3
  #
4
4
  # 사용법:
5
- # ./scripts/update-server.sh # 도움말
6
- # ./scripts/update-server.sh version # 현재 코어 버전 + 최신 태그 확인
5
+ # ./scripts/update-server.sh # 도움말 + 현재/최신 버전 확인
7
6
  # ./scripts/update-server.sh latest # 최신 태그로 업데이트
8
7
  # ./scripts/update-server.sh 0.0.8 # 특정 버전으로 업데이트
9
8
  # ./scripts/update-server.sh v0.0.8
@@ -15,7 +14,7 @@ PROJECT_ROOT="$(dirname "$SCRIPT_DIR")"
15
14
  PACKAGE_NAME="create-entity-app-server"
16
15
  VERSION_FILE="$PROJECT_ROOT/.gateway-version"
17
16
  PID_FILE="$PROJECT_ROOT/.gateway.pid"
18
- MANAGED_SCRIPTS=("run.sh" "entity.sh" "reset-all.sh" "update-server.sh")
17
+ MANAGED_SCRIPTS=("run.sh" "entity.sh" "reset-all.sh" "update-server.sh" "service-install.sh" "service-remove.sh")
19
18
  MANAGED_FILES=("system.js" "system-api.js" "tsconfig.json" ".env.example" ".gateway-version")
20
19
 
21
20
  cd "$PROJECT_ROOT"
@@ -113,6 +112,28 @@ latest_gateway_version() {
113
112
  echo "$latest"
114
113
  }
115
114
 
115
+ print_version_status() {
116
+ local current
117
+ local latest
118
+
119
+ echo "🔍 버전 확인 중..."
120
+ current="$(current_gateway_version)"
121
+ latest="$(latest_gateway_version)"
122
+
123
+ echo ""
124
+ echo " 현재 코어 버전: v${current}"
125
+ echo " 최신 패키지 버전: v${latest}"
126
+ echo ""
127
+
128
+ if [ "$current" = "$latest" ]; then
129
+ echo "✅ 최신 버전입니다."
130
+ elif is_semver "$current" && [ "$(compare_versions "$current" "$latest")" = "1" ]; then
131
+ echo "ℹ️ 현재 코어가 npm 최신 버전보다 더 새롭습니다."
132
+ else
133
+ echo "💡 업데이트 가능: ./scripts/update-server.sh latest"
134
+ fi
135
+ }
136
+
116
137
  package_tarball_url() {
117
138
  local version="$1"
118
139
  local tarball
@@ -370,29 +391,13 @@ case "$ARG" in
370
391
  echo "update-server.sh — Entity App Server 코어 업데이트"
371
392
  echo ""
372
393
  echo "사용법:"
373
- echo " ./scripts/update-server.sh version"
374
394
  echo " ./scripts/update-server.sh latest"
375
395
  echo " ./scripts/update-server.sh <버전>"
376
396
  echo ""
377
397
  echo "업데이트 대상: system.js / system-api.js / scripts / docs / tsconfig.json / .env.example / package.json(deps)"
378
398
  echo "보존 대상: app/ / configs/ / .env / package.json의 name/version/private"
379
- ;;
380
-
381
- "version")
382
- echo "🔍 버전 확인 중..."
383
- CURRENT="$(current_gateway_version)"
384
- LATEST="$(latest_gateway_version)"
385
399
  echo ""
386
- echo " 현재 코어 버전: v${CURRENT}"
387
- echo " 최신 패키지 버전: v${LATEST}"
388
- echo ""
389
- if [ "$CURRENT" = "$LATEST" ]; then
390
- echo "✅ 최신 버전입니다."
391
- elif is_semver "$CURRENT" && [ "$(compare_versions "$CURRENT" "$LATEST")" = "1" ]; then
392
- echo "ℹ️ 현재 코어가 npm 최신 버전보다 더 새롭습니다."
393
- else
394
- echo "💡 업데이트 가능: ./scripts/update-server.sh latest"
395
- fi
400
+ print_version_status
396
401
  ;;
397
402
 
398
403
  "latest")