create-entity-server 0.7.12 → 0.9.13

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 CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "create-entity-server",
3
- "version": "0.7.12",
3
+ "version": "0.9.13",
4
4
  "description": "Create a new entity-server project in one command — like create-react-app or create-vite.",
5
5
  "keywords": [
6
6
  "entity-server",
@@ -1,6 +1,12 @@
1
1
  # 서버 포트 (configs/server.json의 port를 오버라이드)
2
2
  # SERVER_PORT=47200
3
3
 
4
+ # 서버 네임스페이스 (configs/server.json의 namespace보다 우선)
5
+ # SERVER_NAMESPACE=entity-prod
6
+
7
+ # 기본 이메일 도메인 (configs/server.json의 default_email_domain보다 우선)
8
+ # DEFAULT_EMAIL_DOMAIN=example.com
9
+
4
10
  # Entity Server 환경변수 설정 예시
5
11
  # 실제 사용시 이 파일을 .env로 복사하고 값을 변경하세요: cp .env.example .env
6
12
  # ./scripts/generate-env-keys.sh 를 사용하여 랜덤 시크릿을 생성할 수 있습니다.
@@ -0,0 +1,64 @@
1
+ {
2
+ "jpg": ["image/jpeg", "image/pjpeg"],
3
+ "jpeg": ["image/jpeg", "image/pjpeg"],
4
+ "png": "image/png",
5
+ "gif": "image/gif",
6
+ "webp": "image/webp",
7
+ "bmp": ["image/bmp", "image/x-bmp", "image/x-ms-bmp"],
8
+ "tif": "image/tiff",
9
+ "tiff": "image/tiff",
10
+ "svg": "image/svg+xml",
11
+ "pdf": [
12
+ "application/pdf",
13
+ "application/force-download",
14
+ "application/x-download"
15
+ ],
16
+ "csv": [
17
+ "text/csv",
18
+ "application/csv",
19
+ "application/vnd.ms-excel",
20
+ "text/plain"
21
+ ],
22
+ "xls": [
23
+ "application/vnd.ms-excel",
24
+ "application/msexcel",
25
+ "application/x-msexcel",
26
+ "application/x-ms-excel",
27
+ "application/x-excel",
28
+ "application/vnd.ms-office"
29
+ ],
30
+ "xlsx": [
31
+ "application/vnd.openxmlformats-officedocument.spreadsheetml.sheet",
32
+ "application/vnd.ms-excel",
33
+ "application/zip"
34
+ ],
35
+ "xlsm": [
36
+ "application/vnd.ms-excel.sheet.macroenabled.12",
37
+ "application/vnd.ms-excel",
38
+ "application/zip"
39
+ ],
40
+ "xlsb": [
41
+ "application/vnd.ms-excel.sheet.binary.macroenabled.12",
42
+ "application/vnd.ms-excel",
43
+ "application/zip"
44
+ ],
45
+ "doc": ["application/msword", "application/vnd.ms-office"],
46
+ "docx": [
47
+ "application/vnd.openxmlformats-officedocument.wordprocessingml.document",
48
+ "application/zip"
49
+ ],
50
+ "ppt": [
51
+ "application/vnd.ms-powerpoint",
52
+ "application/powerpoint",
53
+ "application/vnd.ms-office"
54
+ ],
55
+ "pptx": [
56
+ "application/vnd.openxmlformats-officedocument.presentationml.presentation",
57
+ "application/zip"
58
+ ],
59
+ "zip": [
60
+ "application/zip",
61
+ "application/x-zip",
62
+ "application/x-zip-compressed"
63
+ ]
64
+ }
@@ -6,6 +6,7 @@
6
6
  "timezone": "Asia/Seoul",
7
7
  "environment": "production",
8
8
  "port": 47200,
9
+ "min_search_token_length": 2,
9
10
  "enable_auto_schema_sync": true,
10
11
  "global_license_scope": true,
11
12
  "global_optimistic_lock": false
@@ -21,7 +21,8 @@
21
21
  },
22
22
  "expire_date": {
23
23
  "index": true,
24
- "comment": "만료일"
24
+ "comment": "만료일",
25
+ "nullable": true
25
26
  },
26
27
  "name": {
27
28
  "index": true,
@@ -44,8 +45,11 @@
44
45
  "index": true,
45
46
  "comment": "시군구"
46
47
  },
47
- "max_user_cnt": {
48
- "type": "uint"
48
+ "max_account_cnt": {
49
+ "index": true,
50
+ "type": "uint",
51
+ "default": 0,
52
+ "nullable": false
49
53
  }
50
54
  },
51
55
  "reset_defaults": [
@@ -1,6 +1,7 @@
1
1
  {
2
2
  "name": "rbac_roles",
3
3
  "description": "역할 기반 접근 제어 역할 정의.",
4
+ "index_table_only": true,
4
5
  "license_scope": false,
5
6
  "hard_delete": true,
6
7
  "fields": {
@@ -10,8 +11,12 @@
10
11
  "required": true,
11
12
  "unique": true
12
13
  },
14
+ "description": {
15
+ "comment": "역할 설명"
16
+ },
13
17
  "permissions": {
14
- "type": "text"
18
+ "type": "json",
19
+ "comment": "권한 목록"
15
20
  }
16
21
  },
17
22
  "reset_defaults": [
@@ -12,7 +12,7 @@
12
12
  "default": "none"
13
13
  },
14
14
  "is_public": {
15
- "index_only": true,
15
+ "index": true,
16
16
  "comment": "공개 파일 여부 (인증 없이 GET 접근 가능)",
17
17
  "type": "boolean",
18
18
  "default": false
@@ -52,9 +52,12 @@
52
52
  "comment": "파일이 첨부된 필드 이름 (file/file[] 타입 필드)"
53
53
  },
54
54
  "mime_type": {
55
+ "index": true,
55
56
  "comment": "파일 MIME 타입 (image/jpeg, application/pdf 등)"
56
57
  },
57
58
  "original_name": {
59
+ "search": true,
60
+ "encrypt": true,
58
61
  "comment": "업로드 시 원본 파일명 (보안 대상 — 암호화 저장)"
59
62
  },
60
63
  "storage_key": {
@@ -19,8 +19,12 @@ fi
19
19
  mkdir -p "$RUN_DIR" "$PROJECT_ROOT/logs"
20
20
  SERVER_NAME="Entity Server"
21
21
 
22
- # Load language from .env
22
+ # Load environment from .env
23
23
  if [ -f .env ]; then
24
+ set -o allexport
25
+ # shellcheck disable=SC1091
26
+ source .env
27
+ set +o allexport
24
28
  LANGUAGE=$(grep '^LANGUAGE=' .env | cut -d '=' -f2)
25
29
  fi
26
30
  LANGUAGE=${LANGUAGE:-ko}
@@ -29,20 +33,25 @@ has_command() {
29
33
  command -v "$1" >/dev/null 2>&1
30
34
  }
31
35
 
32
- # 현재 프로젝트를 관리하는 systemd 서비스명을 반환합니다.
36
+ # 현재 프로젝트를 관리하는 systemd 서비스명을 반환합니다 (상태 무관).
33
37
  find_systemd_service() {
34
- local unit=""
35
- local exec_start=""
36
-
37
38
  has_command systemctl || return 1
38
39
 
39
- for unit in $(systemctl list-units --type=service --state=active,activating --no-legend 2>/dev/null | awk '{print $1}'); do
40
- exec_start=$(systemctl show -p ExecStart --value "$unit" 2>/dev/null || true)
41
- if [[ "$exec_start" == *"$PROJECT_ROOT/scripts/run.sh"* ]] || [[ "$exec_start" == *"$SERVER_BIN"* ]]; then
42
- echo "$unit"
43
- return 0
44
- fi
45
- done
40
+ local namespace="${SERVER_NAMESPACE:-${NAMESPACE:-}}"
41
+ if [ -z "$namespace" ] && [ -f "$SERVER_CONFIG" ]; then
42
+ namespace=$(sed -n 's/.*"namespace"[[:space:]]*:[[:space:]]*"\([^"]*\)".*/\1/p' "$SERVER_CONFIG" | head -n 1)
43
+ fi
44
+ namespace=$(echo "$namespace" | tr '[:upper:]' '[:lower:]' | sed 's/[^a-z0-9_-]/-/g')
45
+ [ -z "$namespace" ] && namespace="default"
46
+
47
+ local svc_name="${namespace}-entity-server.service"
48
+ local exec_start=""
49
+ exec_start=$(systemctl show -p ExecStart --value "$svc_name" 2>/dev/null || true)
50
+
51
+ if [[ "$exec_start" == *"$PROJECT_ROOT/scripts/run.sh"* ]] || [[ "$exec_start" == *"$SERVER_BIN"* ]]; then
52
+ echo "$svc_name"
53
+ return 0
54
+ fi
46
55
 
47
56
  return 1
48
57
  }
@@ -462,11 +471,17 @@ stop_server() {
462
471
  local svc=""
463
472
  svc=$(find_systemd_service || true)
464
473
  if [ -n "$svc" ]; then
465
- echo "ℹ️ systemd 서비스 중지: $svc"
466
- sudo systemctl stop "$svc"
474
+ local svc_state=""
475
+ svc_state=$(systemctl is-active "$svc" 2>/dev/null || true)
476
+ if [ "$svc_state" = "active" ] || [ "$svc_state" = "activating" ]; then
477
+ echo "ℹ️ systemd 서비스 중지: $svc"
478
+ sudo systemctl stop "$svc"
479
+ rm -f "$PID_FILE"
480
+ echo "✅ ${SERVER_NAME} 종료 완료 (systemd)"
481
+ return 0
482
+ fi
483
+ # systemd 서비스가 inactive 이어도 고아 프로세스가 남아 있을 수 있으므로 아래로 진행
467
484
  rm -f "$PID_FILE"
468
- echo "✅ ${SERVER_NAME} 종료 완료 (systemd)"
469
- return 0
470
485
  fi
471
486
 
472
487
  local pid=""
@@ -475,11 +490,25 @@ stop_server() {
475
490
  rm -f "$PID_FILE"
476
491
 
477
492
  if [ -n "$pid" ]; then
493
+ if [ -n "$svc" ]; then
494
+ if [ "$LANGUAGE" = "en" ]; then
495
+ echo "⚠️ systemd service ($svc) is inactive, but an orphan process was found."
496
+ else
497
+ echo "⚠️ systemd 서비스($svc)는 비활성이지만, 고아 프로세스가 발견되었습니다."
498
+ fi
499
+ fi
478
500
  stop_pid_with_confirm "$pid" "active process"
479
501
  return $?
480
502
  fi
481
503
 
482
504
  if is_port_in_use; then
505
+ if [ -n "$svc" ]; then
506
+ if [ "$LANGUAGE" = "en" ]; then
507
+ echo "⚠️ systemd service ($svc) is inactive, but the port is in use."
508
+ else
509
+ echo "⚠️ systemd 서비스($svc)는 비활성이지만, 포트가 사용 중입니다."
510
+ fi
511
+ fi
483
512
  show_unmanaged_server_message
484
513
  return 1
485
514
  fi
@@ -497,9 +526,14 @@ show_status() {
497
526
  local svc=""
498
527
  svc=$(find_systemd_service || true)
499
528
  if [ -n "$svc" ]; then
500
- echo "ℹ️ systemd 서비스로 관리 중: $svc"
501
- sudo systemctl status "$svc" --no-pager 2>/dev/null || true
502
- return
529
+ local svc_state=""
530
+ svc_state=$(systemctl is-active "$svc" 2>/dev/null || true)
531
+ if [ "$svc_state" = "active" ] || [ "$svc_state" = "activating" ]; then
532
+ echo "ℹ️ systemd 서비스로 관리 중: $svc"
533
+ sudo systemctl status "$svc" --no-pager 2>/dev/null || true
534
+ return
535
+ fi
536
+ # systemd inactive 일 때 고아 프로세스 여부까지 확인
503
537
  fi
504
538
 
505
539
  local status_pid=""
@@ -507,6 +541,13 @@ show_status() {
507
541
  status_pid=$(find_active_server_pid || true)
508
542
  if [ -n "$status_pid" ]; then
509
543
  "$SERVER_BIN" banner-status RUNNING
544
+ if [ -n "$svc" ]; then
545
+ if [ "$LANGUAGE" = "en" ]; then
546
+ echo "⚠️ systemd service ($svc) is inactive, but an orphan process is running."
547
+ else
548
+ echo "⚠️ systemd 서비스($svc)는 비활성이지만, 고아 프로세스가 실행 중입니다."
549
+ fi
550
+ fi
510
551
  if [ "$LANGUAGE" = "en" ]; then
511
552
  echo "PID: $status_pid (managed process)"
512
553
  echo "Stop: ./run.sh stop"
@@ -519,6 +560,9 @@ show_status() {
519
560
  if is_port_in_use; then
520
561
  show_unmanaged_server_message
521
562
  fi
563
+ if [ -n "$svc" ]; then
564
+ echo "ℹ️ systemd 서비스: $svc (inactive)"
565
+ fi
522
566
  if [ "$LANGUAGE" = "en" ]; then
523
567
  echo "Start: ./run.sh start"
524
568
  else
@@ -559,13 +603,15 @@ if [ $# -eq 0 ]; then
559
603
  echo "모드:"
560
604
  echo " dev environment=development로 설정하고 database.default는 유지한 채 바이너리 실행"
561
605
  echo " start 설정파일을 수정하지 않고 현재 설정 그대로 백그라운드 실행"
562
- echo " stop run.sh로 백그라운드 실행한 서버 중지"
563
- echo " status 서버 상태 조회"
606
+ echo " stop run.sh로 백그라운드 실행한 서버 중지"
607
+ echo " restart 서버 재시작"
608
+ echo " status 서버 상태 조회"
564
609
  echo ""
565
610
  echo "예제:"
566
611
  echo " $0 dev # 개발 모드로 시작"
567
612
  echo " $0 start # 현재 설정 그대로 시작(백그라운드)"
568
613
  echo " $0 stop # 서버 중지"
614
+ echo " $0 restart # 서버 재시작"
569
615
  echo " $0 status # 상태 조회"
570
616
  fi
571
617
 
@@ -641,6 +687,12 @@ case "$MODE" in
641
687
  ;;
642
688
 
643
689
  start)
690
+ # systemd 에서 ExecStart 로 호출된 경우 바이너리를 직접 exec 한다.
691
+ if [ -n "${INVOCATION_ID:-}" ]; then
692
+ sync_database_default_for_environment "$LINENO" || exit 1
693
+ exec "$SERVER_BIN"
694
+ fi
695
+
644
696
  # systemd 서비스가 등록되어 있으면 systemctl 로 관리한다.
645
697
  svc=$(find_systemd_service || true)
646
698
  if [ -n "$svc" ]; then
@@ -718,6 +770,19 @@ case "$MODE" in
718
770
  stop_server
719
771
  ;;
720
772
 
773
+ restart)
774
+ svc=$(find_systemd_service || true)
775
+ if [ -n "$svc" ]; then
776
+ echo "ℹ️ systemd 서비스 재시작: $svc"
777
+ sudo systemctl restart "$svc"
778
+ echo "✅ ${SERVER_NAME} 재시작 완료 (systemd)"
779
+ exit 0
780
+ fi
781
+
782
+ stop_server || exit $?
783
+ exec "$SCRIPT_DIR/run.sh" start
784
+ ;;
785
+
721
786
  status)
722
787
  show_status
723
788
  ;;
@@ -14,10 +14,8 @@ fi
14
14
  LANGUAGE=${LANGUAGE:-ko}
15
15
 
16
16
  SERVICE_NAME="entity-server"
17
- RUN_USER="${SUDO_USER:-$(stat -c '%U' "$PROJECT_ROOT")}"
18
- RUN_GROUP="$(id -gn "$RUN_USER" 2>/dev/null || true)"
19
- START_NOW=true
20
- INTERACTIVE=false
17
+ RUN_USER="$(id -un)"
18
+ RUN_GROUP="$(id -gn)"
21
19
  SERVER_CONFIG="$PROJECT_ROOT/configs/server.json"
22
20
  SERVER_BIN="$PROJECT_ROOT/bin/entity-server"
23
21
  if [ ! -f "$SERVER_BIN" ] && [ -f "$PROJECT_ROOT/entity-server" ]; then
@@ -25,8 +23,8 @@ if [ ! -f "$SERVER_BIN" ] && [ -f "$PROJECT_ROOT/entity-server" ]; then
25
23
  fi
26
24
 
27
25
  load_namespace() {
28
- local namespace=""
29
- if [ -f "$SERVER_CONFIG" ]; then
26
+ local namespace="${SERVER_NAMESPACE:-${NAMESPACE:-}}"
27
+ if [ -z "$namespace" ] && [ -f "$SERVER_CONFIG" ]; then
30
28
  namespace=$(sed -n 's/.*"namespace"[[:space:]]*:[[:space:]]*"\([^"]*\)".*/\1/p' "$SERVER_CONFIG" | head -n 1)
31
29
  fi
32
30
  namespace=$(echo "$namespace" | tr '[:upper:]' '[:lower:]' | sed 's/[^a-z0-9_-]/-/g')
@@ -38,89 +36,6 @@ load_namespace() {
38
36
 
39
37
  load_namespace
40
38
 
41
- if [ $# -eq 0 ]; then
42
- INTERACTIVE=true
43
- fi
44
-
45
- for arg in "$@"; do
46
- case "$arg" in
47
- --user=*)
48
- RUN_USER="${arg#*=}"
49
- ;;
50
- --group=*)
51
- RUN_GROUP="${arg#*=}"
52
- ;;
53
- --no-start)
54
- START_NOW=false
55
- ;;
56
- *)
57
- if [ "$LANGUAGE" = "en" ]; then
58
- echo "❌ Unknown option: $arg"
59
- echo " Service name is fixed: $SERVICE_NAME"
60
- else
61
- echo "❌ 알 수 없는 옵션: $arg"
62
- echo " 서비스명은 자동 고정값입니다: $SERVICE_NAME"
63
- fi
64
- exit 1
65
- ;;
66
- esac
67
- done
68
-
69
- if [ "$INTERACTIVE" = true ]; then
70
- if [ "$LANGUAGE" = "en" ]; then
71
- echo "[interactive] systemd service setup"
72
- echo "service name: $SERVICE_NAME"
73
- else
74
- echo "[interactive] systemd 서비스 설정"
75
- echo "서비스명: $SERVICE_NAME"
76
- fi
77
-
78
- read -r -p "Run user [$RUN_USER]: " input
79
- if [ -n "$input" ]; then
80
- RUN_USER="$input"
81
- fi
82
-
83
- if [ -z "$RUN_GROUP" ]; then
84
- RUN_GROUP="$(id -gn "$RUN_USER" 2>/dev/null || true)"
85
- fi
86
- read -r -p "Run group [$RUN_GROUP]: " input
87
- if [ -n "$input" ]; then
88
- RUN_GROUP="$input"
89
- fi
90
-
91
- if [ "$LANGUAGE" = "en" ]; then
92
- read -r -p "Start service now? [Y/n]: " input
93
- else
94
- read -r -p "서비스를 즉시 시작할까요? [Y/n]: " input
95
- fi
96
- input=$(echo "$input" | tr '[:upper:]' '[:lower:]')
97
- if [ "$input" = "n" ] || [ "$input" = "no" ]; then
98
- START_NOW=false
99
- fi
100
- fi
101
-
102
- if [ "$RUN_GROUP" = "" ]; then
103
- RUN_GROUP="$(id -gn "$RUN_USER")"
104
- fi
105
-
106
- if ! id -u "$RUN_USER" >/dev/null 2>&1; then
107
- if [ "$LANGUAGE" = "en" ]; then
108
- echo "❌ User not found: $RUN_USER"
109
- else
110
- echo "❌ 사용자를 찾을 수 없습니다: $RUN_USER"
111
- fi
112
- exit 1
113
- fi
114
-
115
- if ! getent group "$RUN_GROUP" >/dev/null 2>&1; then
116
- if [ "$LANGUAGE" = "en" ]; then
117
- echo "❌ Group not found: $RUN_GROUP"
118
- else
119
- echo "❌ 그룹을 찾을 수 없습니다: $RUN_GROUP"
120
- fi
121
- exit 1
122
- fi
123
-
124
39
  if [ ! -x "$PROJECT_ROOT/scripts/run.sh" ]; then
125
40
  chmod +x "$PROJECT_ROOT/scripts/run.sh"
126
41
  fi
@@ -140,11 +55,7 @@ UNIT_PATH="/etc/systemd/system/${SERVICE_NAME}.service"
140
55
 
141
56
  if [ "$EUID" -ne 0 ]; then
142
57
  if command -v sudo >/dev/null 2>&1; then
143
- SUDO_ARGS=("--user=$RUN_USER" "--group=$RUN_GROUP")
144
- if [ "$START_NOW" = false ]; then
145
- SUDO_ARGS+=("--no-start")
146
- fi
147
- exec sudo "$0" "${SUDO_ARGS[@]}"
58
+ exec sudo "$0"
148
59
  fi
149
60
  if [ "$LANGUAGE" = "en" ]; then
150
61
  echo "❌ This script requires root privileges"
@@ -177,20 +88,18 @@ EOF
177
88
  systemctl daemon-reload
178
89
  systemctl enable "$SERVICE_NAME"
179
90
 
180
- if [ "$START_NOW" = true ]; then
181
- systemctl restart "$SERVICE_NAME"
182
- fi
183
-
184
91
  if [ "$LANGUAGE" = "en" ]; then
185
92
  echo "✅ Service registered: $SERVICE_NAME"
186
93
  echo " Unit: $UNIT_PATH"
187
- echo " Start: sudo systemctl start $SERVICE_NAME"
188
- echo " Stop: sudo systemctl stop $SERVICE_NAME"
189
- echo " Status: sudo systemctl status $SERVICE_NAME"
94
+ echo " User: $RUN_USER"
95
+ echo " Start: ./run.sh start"
96
+ echo " Stop: ./run.sh stop"
97
+ echo " Status: ./run.sh status"
190
98
  else
191
99
  echo "✅ 서비스 등록 완료: $SERVICE_NAME"
192
100
  echo " Unit: $UNIT_PATH"
193
- echo " 시작: sudo systemctl start $SERVICE_NAME"
194
- echo " 중지: sudo systemctl stop $SERVICE_NAME"
195
- echo " 상태: sudo systemctl status $SERVICE_NAME"
101
+ echo " User: $RUN_USER"
102
+ echo " 시작: ./run.sh start"
103
+ echo " 중지: ./run.sh stop"
104
+ echo " 상태: ./run.sh status"
196
105
  fi
@@ -19,8 +19,8 @@ CONFIRMED=false
19
19
  SERVER_CONFIG="$PROJECT_ROOT/configs/server.json"
20
20
 
21
21
  load_namespace() {
22
- local namespace=""
23
- if [ -f "$SERVER_CONFIG" ]; then
22
+ local namespace="${SERVER_NAMESPACE:-${NAMESPACE:-}}"
23
+ if [ -z "$namespace" ] && [ -f "$SERVER_CONFIG" ]; then
24
24
  namespace=$(sed -n 's/.*"namespace"[[:space:]]*:[[:space:]]*"\([^"]*\)".*/\1/p' "$SERVER_CONFIG" | head -n 1)
25
25
  fi
26
26
  namespace=$(echo "$namespace" | tr '[:upper:]' '[:lower:]' | sed 's/[^a-z0-9_-]/-/g')