create-entity-server 0.0.15 → 0.0.23

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 (42) hide show
  1. package/bin/create.js +15 -7
  2. package/package.json +1 -1
  3. package/template/.env.example +8 -7
  4. package/template/configs/database.json +173 -10
  5. package/template/entities/Account/account_audit.json +4 -5
  6. package/template/entities/System/system_audit_log.json +14 -8
  7. package/template/samples/README.md +28 -22
  8. package/template/samples/browser/entity-server-client.js +453 -0
  9. package/template/samples/browser/example.html +498 -0
  10. package/template/samples/entities/02_types_and_defaults.json +15 -16
  11. package/template/samples/entities/04_fk_and_composite_unique.json +0 -2
  12. package/template/samples/entities/05_cache.json +9 -8
  13. package/template/samples/entities/06_history_and_hard_delete.json +27 -9
  14. package/template/samples/entities/07_license_scope.json +40 -31
  15. package/template/samples/entities/09_hook_entity.json +0 -6
  16. package/template/samples/entities/10_hook_submit_delete.json +5 -2
  17. package/template/samples/entities/11_hook_webhook.json +9 -7
  18. package/template/samples/entities/12_hook_push.json +3 -3
  19. package/template/samples/entities/13_read_only.json +13 -10
  20. package/template/samples/entities/15_reset_defaults.json +0 -1
  21. package/template/samples/entities/16_isolated_license.json +62 -0
  22. package/template/samples/entities/README.md +36 -39
  23. package/template/samples/flutter/lib/entity_server_client.dart +170 -48
  24. package/template/samples/java/EntityServerClient.java +208 -61
  25. package/template/samples/java/EntityServerExample.java +4 -3
  26. package/template/samples/kotlin/EntityServerClient.kt +175 -45
  27. package/template/samples/node/src/EntityServerClient.js +232 -59
  28. package/template/samples/node/src/example.js +9 -9
  29. package/template/samples/php/ci4/Config/EntityServer.php +0 -1
  30. package/template/samples/php/ci4/Libraries/EntityServer.php +206 -53
  31. package/template/samples/php/laravel/Services/EntityServerService.php +190 -41
  32. package/template/samples/python/entity_server.py +181 -68
  33. package/template/samples/python/example.py +7 -6
  34. package/template/samples/react/src/example.tsx +41 -25
  35. package/template/samples/swift/EntityServerClient.swift +143 -37
  36. package/template/scripts/run.ps1 +12 -3
  37. package/template/scripts/run.sh +12 -8
  38. package/template/scripts/update-server.ps1 +68 -2
  39. package/template/scripts/update-server.sh +59 -2
  40. package/template/samples/entities/order_notification.json +0 -51
  41. package/template/samples/react/src/api/entityServerClient.ts +0 -413
  42. package/template/samples/react/src/hooks/useEntity.ts +0 -173
package/bin/create.js CHANGED
@@ -228,11 +228,14 @@ async function run() {
228
228
  );
229
229
  console.warn(` https://github.com/${REPO}/releases\n`);
230
230
  } else {
231
+ const binDir = path.join(targetDir, "bin");
232
+ fs.mkdirSync(binDir, { recursive: true });
233
+
231
234
  for (const bin of ["entity-server", "entity-cli"]) {
232
235
  const ext = platform === "windows" ? ".exe" : "";
233
236
  const fileName = `${bin}-${platform}-${arch}${ext}`;
234
237
  const url = `https://github.com/${REPO}/releases/download/v${VERSION}/${fileName}`;
235
- const dest = path.join(targetDir, bin + ext);
238
+ const dest = path.join(binDir, bin + ext);
236
239
 
237
240
  process.stdout.write(` ↓ ${fileName} 다운로드 중...`);
238
241
  try {
@@ -253,8 +256,9 @@ async function run() {
253
256
  // ── 3. 완료 안내 ─────────────────────────────────────────────────────────
254
257
 
255
258
  const relDir = path.relative(process.cwd(), targetDir) || dirName;
256
- const serverExe = isWin ? ".\\entity-server.exe" : "./entity-server";
257
- const cliExe = isWin ? ".\\entity-cli.exe" : "./entity-cli";
259
+ const serverExe = isWin
260
+ ? ".\\bin\\entity-server.exe"
261
+ : "./bin/entity-server";
258
262
  const runScript = isWin
259
263
  ? ".\\scripts\\run.ps1 start"
260
264
  : "./scripts/run.sh start";
@@ -264,8 +268,9 @@ async function run() {
264
268
  ✓ 완료!
265
269
 
266
270
  ${relDir}/
267
- ├── entity-server${binExt} ← 서버 바이너리
268
- ├── entity-cli${binExt} CLI 도구
271
+ ├── bin/
272
+ ├── entity-server${binExt} 서버 바이너리
273
+ │ └── entity-cli${binExt} ← CLI 도구
269
274
  ├── .env ← 환경 변수 설정 (여기를 먼저 수정하세요)
270
275
  ├── configs/ ← CORS, JWT 등 서버 설정
271
276
  ├── entities/ ← 엔티티 스키마 JSON (샘플 포함)
@@ -274,8 +279,11 @@ async function run() {
274
279
 
275
280
  다음 단계:
276
281
  ${cdCmd ? ` ${cdCmd}` : ""}
277
- nano .env # PORT, DB_PATH, 암호화 설정
278
- ${serverExe} # 서버 실행
282
+ ./scripts/generate-env-keys${isWin ? ".ps1 -Apply" : ".sh --apply"} # ENCRYPTION_KEY/JWT_SECRET 생성 .env 반영
283
+ vim .env # PORT, DB_PATH 등 기본 환경값 확인/수정
284
+ vim configs/*.json # database/server/jwt 등 운영 설정
285
+ vim entities/*.json # 사용할 엔티티 스키마 정의
286
+ ${serverExe} # 마지막: 서버 실행
279
287
 
280
288
  서버마다 .env 의 PORT 와 DB_PATH 를 다르게 설정하면
281
289
  같은 머신에서 여러 프로젝트를 동시에 운영할 수 있습니다.
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "create-entity-server",
3
- "version": "0.0.15",
3
+ "version": "0.0.23",
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,8 +1,10 @@
1
1
  # Entity Server 환경변수 설정 예시
2
2
  # 실제 사용시 이 파일을 .env로 복사하고 값을 변경하세요: cp .env.example .env
3
+ # ./scripts/generate-env-keys.sh 를 사용하여 랜덤 시크릿을 생성할 수 있습니다.
3
4
 
4
- # 기본 암복호화 (license 엔티티 등 공통 fallback 키)
5
- # 32자 16진수 문자열 (128bit AES-CTR 키)
5
+ # 기본 암복호화 마스터 시크릿 (license 엔티티 등 공통 fallback 키)
6
+ # HKDF-SHA256 으로 32바이트(256-bit) XChaCha20-Poly1305 키를 유도하는 마스터 시크릿입니다.
7
+ # 충분한 엔트로피를 가진 임의 문자열이면 됩니다 (예: openssl rand -hex 32 으로 생성).
6
8
  ENCRYPTION_KEY=your-32-char-hex-encryption-key-here
7
9
 
8
10
  # JWT 서명 키 (HS256)
@@ -13,18 +15,17 @@ JWT_SECRET=your-jwt-secret-here
13
15
  SERVER_PORT=47200
14
16
 
15
17
  # Database values (database.json의 ${ENV_VAR}와 매핑)
18
+ DB_HOST_DEVELOPMENT=127.0.0.1
19
+ DB_PORT_DEVELOPMENT=3306
16
20
  DB_NAME_DEVELOPMENT=your-development-db-name
17
21
  DB_USER_DEVELOPMENT=your-development-db-user
18
22
  DB_PASSWORD_DEVELOPMENT=your-development-db-password
19
23
 
24
+ DB_HOST_PRODUCTION=127.0.0.1
25
+ DB_PORT_PRODUCTION=3306
20
26
  DB_NAME_PRODUCTION=your-production-db-name
21
27
  DB_USER_PRODUCTION=your-production-db-user
22
28
  DB_PASSWORD_PRODUCTION=your-production-db-password
23
29
 
24
- # PostgreSQL group (선택)
25
- # DB_NAME_POSTGRESQL=your-postgresql-db-name
26
- # DB_USER_POSTGRESQL=your-postgresql-db-user
27
- # DB_PASSWORD_POSTGRESQL=your-postgresql-db-password
28
-
29
30
  # 푸시 알림 (push.json에서 ${FCM_PROJECT_ID} 등으로 참조 가능)
30
31
  # FCM_PROJECT_ID=your-firebase-project-id
@@ -1,23 +1,186 @@
1
+ // ──────────────────────────────────────────────────────────────────────────
2
+ // database.json 설정 예시 (주석 포함 예시 전용 파일 — 실제 파일은 순수 JSON)
3
+ //
4
+ // "default" : 사용할 그룹 이름 (groups 키 중 하나)
5
+ // "groups" : 드라이버별 연결 설정 모음
6
+ // driver : "mysql" | "postgres" | "mongodb" | "dynamodb" |
7
+ // "firestore" | "scylladb" | "couchdb"
8
+ //
9
+ // 환경 변수 참조: "${ENV_VAR_NAME}" 형식으로 값을 주입합니다.
10
+ // ──────────────────────────────────────────────────────────────────────────
1
11
  {
2
12
  "default": "development",
3
13
  "groups": {
14
+ // ── MySQL (SQL) ─────────────────────────────────────────────────
4
15
  "development": {
5
16
  "driver": "mysql",
6
- "host": "127.0.0.1",
7
- "port": 3306,
8
- "database": "entity_server",
9
- "user": "root",
17
+ "host": "${DB_HOST_DEVELOPMENT}",
18
+ "port": "${DB_PORT_DEVELOPMENT}",
19
+ "database": "${DB_NAME_DEVELOPMENT}",
20
+ "user": "${DB_USER_DEVELOPMENT}",
10
21
  "password": "${DB_PASSWORD_DEVELOPMENT}",
11
- "maxOpenConns": 20
22
+ "maxOpenConns": 20,
23
+ "maxIdleConns": 10,
24
+ "connMaxLifetimeSec": 3600
12
25
  },
13
26
  "production": {
14
27
  "driver": "mysql",
15
- "host": "127.0.0.1",
16
- "port": 3306,
17
- "database": "entity_server",
18
- "user": "entity_user",
28
+ "host": "${DB_HOST_PRODUCTION}",
29
+ "port": "${DB_PORT_PRODUCTION}",
30
+ "database": "${DB_NAME_PRODUCTION}",
31
+ "user": "${DB_USER_PRODUCTION}",
19
32
  "password": "${DB_PASSWORD_PRODUCTION}",
20
- "maxOpenConns": 50
33
+ "maxOpenConns": 50,
34
+ "maxIdleConns": 25,
35
+ "connMaxLifetimeSec": 3600
36
+ },
37
+
38
+ // ── MongoDB ─────────────────────────────────────────────────────
39
+ // URI 우선 사용. uri 가 없으면 host/port/database/username/password 조합.
40
+ "mongodb_dev": {
41
+ "driver": "mongodb",
42
+ "uri": "mongodb://localhost:27017/entity_dev",
43
+ "database": "entity_dev"
44
+ },
45
+ "mongodb_prod": {
46
+ "driver": "mongodb",
47
+ "host": "${MONGO_HOST}",
48
+ "port": 27017,
49
+ "database": "${MONGO_DB}",
50
+ "username": "${MONGO_USER}",
51
+ "password": "${MONGO_PASSWORD}",
52
+ "uri": ""
53
+ },
54
+ "mongodb_replica": {
55
+ "driver": "mongodb",
56
+ "uri": "mongodb://${MONGO_USER}:${MONGO_PASS}@mongo1:27017,mongo2:27017,mongo3:27017/${MONGO_DB}?replicaSet=rs0&authSource=admin",
57
+ "database": "${MONGO_DB}"
58
+ },
59
+
60
+ // ── Amazon DynamoDB ─────────────────────────────────────────────
61
+ // region 과 IAM 인증이 필요합니다.
62
+ // 로컬 테스트: endpoint 에 "http://localhost:8000" 지정.
63
+ "dynamodb_dev": {
64
+ "driver": "dynamodb",
65
+ "region": "ap-northeast-2",
66
+ "endpoint": "http://localhost:8000",
67
+ "access_key_id": "${AWS_ACCESS_KEY_ID}",
68
+ "secret_access_key": "${AWS_SECRET_ACCESS_KEY}"
69
+ },
70
+ "dynamodb_prod": {
71
+ "driver": "dynamodb",
72
+ "region": "${AWS_REGION}",
73
+ "access_key_id": "${AWS_ACCESS_KEY_ID}",
74
+ "secret_access_key": "${AWS_SECRET_ACCESS_KEY}"
75
+ },
76
+
77
+ // ── Google Cloud Firestore ──────────────────────────────────────
78
+ // GCP 프로젝트 ID 와 서비스 계정 JSON 파일(또는 ADC)이 필요합니다.
79
+ // credentials_file : 서비스 계정 키 파일 경로 (선택)
80
+ // ADC 자동 사용 시 credentials_file 생략 가능.
81
+ "firestore_dev": {
82
+ "driver": "firestore",
83
+ "project_id": "${GCP_PROJECT_ID}",
84
+ "credentials_file": "${GOOGLE_APPLICATION_CREDENTIALS}"
85
+ },
86
+ "firestore_prod": {
87
+ "driver": "firestore",
88
+ "project_id": "${GCP_PROJECT_ID}"
89
+ },
90
+
91
+ // ── ScyllaDB / Apache Cassandra ────────────────────────────────
92
+ // hosts 는 쉼표 구분 문자열 또는 배열 모두 허용합니다.
93
+ // keyspace 가 없으면 자동 생성됩니다.
94
+ "scylladb_dev": {
95
+ "driver": "scylladb",
96
+ "hosts": "localhost:9042",
97
+ "keyspace": "entity_dev",
98
+ "username": "",
99
+ "password": ""
100
+ },
101
+ "scylladb_prod": {
102
+ "driver": "scylladb",
103
+ "hosts": "${SCYLLA_HOSTS}",
104
+ "keyspace": "${SCYLLA_KEYSPACE}",
105
+ "username": "${SCYLLA_USER}",
106
+ "password": "${SCYLLA_PASSWORD}",
107
+ "consistency": "quorum",
108
+ "timeout": "10s"
109
+ },
110
+
111
+ // ── Apache CouchDB ──────────────────────────────────────────────
112
+ // URI 우선 사용. uri 가 없으면 host/port/username/password 조합.
113
+ // 포트 기본값: 5984
114
+ "couchdb_dev": {
115
+ "driver": "couchdb",
116
+ "host": "localhost",
117
+ "port": 5984,
118
+ "username": "admin",
119
+ "password": "password"
120
+ },
121
+ "couchdb_uri": {
122
+ "driver": "couchdb",
123
+ "uri": "http://admin:password@localhost:5984/"
124
+ },
125
+ "couchdb_prod": {
126
+ "driver": "couchdb",
127
+ "uri": "http://${COUCH_USER}:${COUCH_PASS}@${COUCH_HOST}:${COUCH_PORT}/"
21
128
  }
22
129
  }
23
130
  }
131
+
132
+ // ──────────────────────────────────────────────────────────────────────────
133
+ // DataStore 단독 사용 — flat 형식 (groups 없이 최상위에 driver 직접 지정)
134
+ //
135
+ // SQL 없이 NoSQL DataStore만 단독으로 사용할 때는 groups 없이
136
+ // database.json 최상위에 driver 를 직접 지정합니다.
137
+ // store_loader.go 가 groups 키가 없고 NoSQL driver 인 경우에만 DataStore로 인식합니다.
138
+ // ──────────────────────────────────────────────────────────────────────────
139
+
140
+ // MongoDB flat 형식
141
+ {
142
+ "driver": "mongodb",
143
+ "uri": "mongodb://localhost:27017",
144
+ "database": "entity_server"
145
+ }
146
+
147
+ // MongoDB — 환경변수 방식
148
+ {
149
+ "driver": "mongodb",
150
+ "host": "${MONGO_HOST}",
151
+ "port": "${MONGO_PORT}",
152
+ "username": "${MONGO_USER}",
153
+ "password": "${MONGO_PASSWORD}",
154
+ "database": "${MONGO_DATABASE}"
155
+ }
156
+
157
+ // DynamoDB flat 형식
158
+ {
159
+ "driver": "dynamodb",
160
+ "region": "${AWS_REGION}",
161
+ "access_key_id": "${AWS_ACCESS_KEY_ID}",
162
+ "secret_access_key": "${AWS_SECRET_ACCESS_KEY}"
163
+ }
164
+
165
+ // Firestore flat 형식
166
+ {
167
+ "driver": "firestore",
168
+ "project_id": "${GCP_PROJECT_ID}",
169
+ "credentials_file": "${GOOGLE_APPLICATION_CREDENTIALS}"
170
+ }
171
+
172
+ // ScyllaDB flat 형식
173
+ {
174
+ "driver": "scylladb",
175
+ "host": "${SCYLLA_HOST}",
176
+ "port": 9042,
177
+ "database": "${SCYLLA_KEYSPACE}",
178
+ "username": "${SCYLLA_USER}",
179
+ "password": "${SCYLLA_PASSWORD}"
180
+ }
181
+
182
+ // CouchDB flat 형식
183
+ {
184
+ "driver": "couchdb",
185
+ "uri": "http://${COUCH_USER}:${COUCH_PASS}@${COUCH_HOST}:5984/"
186
+ }
@@ -1,17 +1,16 @@
1
1
  {
2
2
  "name": "account_audit",
3
- "description": "account_audit Entity",
3
+ "description": "account 감사 로그. JWT 인증 시에만 account_seq는 required",
4
4
  "index": {
5
5
  "account_seq": {
6
- "comment": "계정 seq",
6
+ "comment": "계정 seq (JWT 인증 시 account.seq 참조. HMAC은 nullable)",
7
7
  "type": "bigint",
8
- "required": true
8
+ "nullable": true
9
9
  },
10
10
  "action": {
11
11
  "comment": "작업 유형",
12
12
  "type": ["INSERT", "UPDATE", "DELETE", "LOGIN", "LOGOUT"],
13
13
  "required": true
14
14
  }
15
- },
16
- "license_scope": false
15
+ }
17
16
  }
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "system_audit_log",
3
- "description": "시스템 감사 로그. 서버 레벨에서 자동 기록되며 API를 통한 직접 수정은 허용되지 않습니다.",
3
+ "description": "시스템 감사 로그. 서버 레벨에서 자동 기록되며 API를 통한 직접 수정은 허용되지 않습니다. JWT 인증 시에만 account_seq 기록",
4
4
  "db_group": "system",
5
5
  "hard_delete": true,
6
6
  "history_ttl": 0,
@@ -18,7 +18,8 @@
18
18
  },
19
19
  "entity_seq": {
20
20
  "comment": "대상 엔티티 레코드 seq. 로그인/로그아웃 등 레코드 없는 경우 NULL",
21
- "type": "bigint"
21
+ "type": "bigint",
22
+ "nullable": true
22
23
  },
23
24
  "action": {
24
25
  "comment": "수행된 작업 유형",
@@ -34,16 +35,19 @@
34
35
  "required": true
35
36
  },
36
37
  "account_seq": {
37
- "comment": "작업을 수행한 계정 seq. 비인증 요청은 NULL",
38
- "type": "bigint"
38
+ "comment": "작업을 수행한 계정 seq. JWT 인증 요청은 account.seq, 비인증/HMAC 요청은 NULL",
39
+ "type": "bigint",
40
+ "nullable": true
39
41
  },
40
42
  "ip_address": {
41
43
  "comment": "요청 IP 주소 (IPv4/IPv6)",
42
- "type": "varchar(45)"
44
+ "type": "varchar(45)",
45
+ "nullable": true
43
46
  },
44
47
  "endpoint": {
45
48
  "comment": "요청 API 엔드포인트",
46
- "type": "varchar(200)"
49
+ "type": "varchar(200)",
50
+ "nullable": true
47
51
  },
48
52
  "request_method": {
49
53
  "comment": "HTTP 메서드 (GET/POST/PUT/DELETE 등)",
@@ -51,7 +55,8 @@
51
55
  },
52
56
  "request_payload": {
53
57
  "comment": "요청 본문 JSON. 민감 필드(password, token 등) 자동 마스킹 후 저장. ServerConfig.AuditLogPayload = true 일 때만 기록",
54
- "type": "text"
58
+ "type": "text",
59
+ "nullable": true
55
60
  },
56
61
  "result_code": {
57
62
  "comment": "HTTP 응답 코드 (200, 400, 401, 403, 500 등)",
@@ -59,7 +64,8 @@
59
64
  },
60
65
  "error_message": {
61
66
  "comment": "실패 시 오류 메시지 요약",
62
- "type": "varchar(500)"
67
+ "type": "varchar(500)",
68
+ "nullable": true
63
69
  }
64
70
  }
65
71
  }
@@ -15,11 +15,12 @@ Client / Browser
15
15
  Backend Server ←── 이 샘플이 구현하는 부분
16
16
 
17
17
  ▼ HMAC 서명 (서버 간 통신)
18
- Entity Server (Go)
18
+ Entity Server
19
19
  ```
20
20
 
21
- > **React (SPA)** 샘플은 HMAC 대신 JWT Bearer 토큰을 사용합니다.
22
- > 브라우저 환경에서는 HMAC secret노출할 없기 때문입니다.
21
+ > **브라우저(React·Vanilla)** 환경에서도 HMAC / JWT 모두 사용 가능합니다.
22
+ > 단, 브라우저에서 HMAC을 사용하면 `hmacSecret`이 클라이언트에 노출되므로,
23
+ > **프론트엔드 프로덕션 환경에서는 JWT 사용을 권장합니다.**
23
24
 
24
25
  ## HMAC 서명 공식
25
26
 
@@ -39,31 +40,36 @@ signature = HMAC-SHA256(hmacSecret, payload) → hex
39
40
 
40
41
  ## API 엔드포인트
41
42
 
42
- | 동작 | 메서드 | 경로 |
43
- | --------- | ------ | ---------------------------------- |
44
- | 단건 조회 | GET | `/v1/entity/{name}/{seq}` |
45
- | 목록 조회 | GET | `/v1/entity/{name}/list` |
46
- | 필터 검색 | POST | `/v1/entity/{name}/query` |
47
- | 건수 조회 | GET | `/v1/entity/{name}/count` |
48
- | 생성/수정 | POST | `/v1/entity/{name}/submit` |
49
- | 삭제 | DELETE | `/v1/entity/{name}/delete/{seq}` |
50
- | 이력 조회 | GET | `/v1/entity/{name}/history/{seq}` |
51
- | 롤백 | POST | `/v1/entity/{name}/rollback/{seq}` |
43
+ | 동작 | 메서드 | 경로 |
44
+ | -------------- | ------ | ---------------------------------- |
45
+ | 단건 조회 | GET | `/v1/entity/{name}/{seq}` |
46
+ | 조건 단건 조회 | POST | `/v1/entity/{name}/find` |
47
+ | 목록 조회 | POST | `/v1/entity/{name}/list` |
48
+ | 필터 검색 | POST | `/v1/entity/{name}/query` |
49
+ | 건수 조회 | POST | `/v1/entity/{name}/count` |
50
+ | 생성/수정 | POST | `/v1/entity/{name}/submit` |
51
+ | 삭제 | POST | `/v1/entity/{name}/delete/{seq}` |
52
+ | 이력 조회 | GET | `/v1/entity/{name}/history/{seq}` |
53
+ | 롤백 | POST | `/v1/entity/{name}/rollback/{seq}` |
52
54
 
53
55
  - `list` 쿼리 파라미터: `?page=1&limit=20&order_by=<field>`
54
56
  - `submit` — body에 `seq` 포함 시 수정, 없으면 생성
55
57
 
56
58
  ## 샘플 목록
57
59
 
58
- | 디렉토리 | 프레임워크 | 인증 방식 |
59
- | -------------- | ---------------------- | --------- |
60
- | `entities/` | 엔티티 설정 예제 | — |
61
- | `php/ci4/` | CodeIgniter 4 | HMAC |
62
- | `php/laravel/` | Laravel | HMAC |
63
- | `java/` | Java (표준 라이브러리) | HMAC |
64
- | `node/` | Node.js (fetch) | HMAC |
65
- | `python/` | Python (requests) | HMAC |
66
- | `react/` | React + TypeScript | JWT |
60
+ | 디렉토리 | 프레임워크 | 인증 방식 |
61
+ | -------------- | ---------------------------------------------- | ---------- |
62
+ | `entities/` | 엔티티 설정 예제 | — |
63
+ | `browser/` | 브라우저 (Vanilla ES Module, 빌드 도구 불필요) | HMAC / JWT |
64
+ | `php/ci4/` | CodeIgniter 4 | HMAC / JWT |
65
+ | `php/laravel/` | Laravel | HMAC / JWT |
66
+ | `java/` | Java (표준 라이브러리) | HMAC / JWT |
67
+ | `kotlin/` | Kotlin (표준 라이브러리) | HMAC / JWT |
68
+ | `swift/` | Swift (URLSession) | HMAC / JWT |
69
+ | `flutter/` | Flutter (Dart) | HMAC / JWT |
70
+ | `node/` | Node.js (fetch) | HMAC / JWT |
71
+ | `python/` | Python (requests) | HMAC / JWT |
72
+ | `react/` | React + TypeScript | HMAC / JWT |
67
73
 
68
74
  ### CI4 설정 방식
69
75