create-entity-server 0.0.9 → 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 (56) hide show
  1. package/bin/create.js +26 -8
  2. package/package.json +1 -1
  3. package/template/.env.example +20 -3
  4. package/template/configs/database.json +173 -10
  5. package/template/configs/jwt.json +1 -0
  6. package/template/configs/oauth.json +37 -0
  7. package/template/configs/push.json +26 -0
  8. package/template/entities/Account/account_audit.json +4 -5
  9. package/template/entities/README.md +4 -4
  10. package/template/entities/{Auth → System/Auth}/account.json +0 -14
  11. package/template/entities/System/system_audit_log.json +14 -8
  12. package/template/samples/README.md +43 -21
  13. package/template/samples/browser/entity-server-client.js +453 -0
  14. package/template/samples/browser/example.html +498 -0
  15. package/template/samples/entities/01_basic_fields.json +39 -0
  16. package/template/samples/entities/02_types_and_defaults.json +67 -0
  17. package/template/samples/entities/03_hash_and_unique.json +33 -0
  18. package/template/samples/entities/04_fk_and_composite_unique.json +29 -0
  19. package/template/samples/entities/05_cache.json +55 -0
  20. package/template/samples/entities/06_history_and_hard_delete.json +60 -0
  21. package/template/samples/entities/07_license_scope.json +52 -0
  22. package/template/samples/entities/08_hook_sql.json +52 -0
  23. package/template/samples/entities/09_hook_entity.json +65 -0
  24. package/template/samples/entities/10_hook_submit_delete.json +78 -0
  25. package/template/samples/entities/11_hook_webhook.json +84 -0
  26. package/template/samples/entities/12_hook_push.json +73 -0
  27. package/template/samples/entities/13_read_only.json +54 -0
  28. package/template/samples/entities/14_optimistic_lock.json +29 -0
  29. package/template/samples/entities/15_reset_defaults.json +94 -0
  30. package/template/samples/entities/16_isolated_license.json +62 -0
  31. package/template/samples/entities/README.md +91 -0
  32. package/template/samples/flutter/lib/entity_server_client.dart +261 -48
  33. package/template/samples/java/EntityServerClient.java +325 -61
  34. package/template/samples/java/EntityServerExample.java +4 -3
  35. package/template/samples/kotlin/EntityServerClient.kt +261 -45
  36. package/template/samples/node/src/EntityServerClient.js +348 -59
  37. package/template/samples/node/src/example.js +9 -9
  38. package/template/samples/php/ci4/Config/EntityServer.php +14 -0
  39. package/template/samples/php/ci4/Controllers/EntityController.php +202 -0
  40. package/template/samples/php/ci4/Controllers/ProductController.php +16 -76
  41. package/template/samples/php/ci4/Libraries/EntityServer.php +352 -60
  42. package/template/samples/php/laravel/Services/EntityServerService.php +245 -40
  43. package/template/samples/python/entity_server.py +287 -68
  44. package/template/samples/python/example.py +7 -6
  45. package/template/samples/react/src/example.tsx +41 -25
  46. package/template/samples/swift/EntityServerClient.swift +248 -37
  47. package/template/scripts/normalize-entities.sh +10 -10
  48. package/template/scripts/run.ps1 +12 -3
  49. package/template/scripts/run.sh +120 -37
  50. package/template/scripts/update-server.ps1 +160 -4
  51. package/template/scripts/update-server.sh +132 -4
  52. package/template/samples/react/src/api/entityServerClient.ts +0 -290
  53. package/template/samples/react/src/hooks/useEntity.ts +0 -105
  54. /package/template/entities/{Auth → System/Auth}/api_keys.json +0 -0
  55. /package/template/entities/{Auth → System/Auth}/license.json +0 -0
  56. /package/template/entities/{Auth → System/Auth}/rbac_roles.json +0 -0
@@ -0,0 +1,202 @@
1
+ <?php
2
+
3
+ namespace App\Controllers;
4
+
5
+ use App\Controllers\BaseController;
6
+ use App\Libraries\EntityServer;
7
+
8
+ /**
9
+ * EntityServer CRUD를 CI4 컨트롤러에서 공통으로 사용하는 베이스 컨트롤러.
10
+ *
11
+ * 사용법:
12
+ * class ProductController extends EntityController {
13
+ * protected string $entity = 'product';
14
+ * }
15
+ */
16
+ abstract class EntityController extends BaseController
17
+ {
18
+ protected EntityServer $es;
19
+
20
+ /** 대상 엔티티명 (하위 컨트롤러에서 지정) */
21
+ protected string $entity = '';
22
+
23
+ /**
24
+ * 푸시 트리거용 엔티티명 (기본: 시스템 엔티티 push_msg)
25
+ *
26
+ * 주의: push 인프라 필수 엔티티는 account_device / push_msg / push_log 이며,
27
+ * 이 값은 "어떤 엔티티 insert로 push hook를 트리거할지"를 결정합니다.
28
+ */
29
+ protected string $pushEntity = 'push_msg';
30
+
31
+ /** pushEntity에서 수신자를 가리키는 필드명 */
32
+ protected string $pushTargetField = 'account_seq';
33
+
34
+ public function __construct()
35
+ {
36
+ $this->es = new EntityServer();
37
+ }
38
+
39
+ /** GET /{entity}/list?page=1&limit=20 */
40
+ public function list(): string
41
+ {
42
+ $page = (int) ($this->request->getGet('page') ?? 1);
43
+ $limit = (int) ($this->request->getGet('limit') ?? 20);
44
+
45
+ $result = $this->es->list($this->entity, [
46
+ 'page' => $page,
47
+ 'limit' => $limit,
48
+ ]);
49
+
50
+ return $this->response->setJSON($result)->getBody();
51
+ }
52
+
53
+ /** GET /{entity}/get/(:num) */
54
+ public function get(int $seq): string
55
+ {
56
+ $result = $this->es->get($this->entity, $seq);
57
+ return $this->response->setJSON($result)->getBody();
58
+ }
59
+
60
+ /** POST /{entity}/query */
61
+ public function query(): string
62
+ {
63
+ try {
64
+ $body = $this->es->readRequestBody($this->request);
65
+ } catch (\Throwable $e) {
66
+ return $this->response->setStatusCode(400)
67
+ ->setJSON(['ok' => false, 'message' => $e->getMessage()])
68
+ ->getBody();
69
+ }
70
+
71
+ $filter = $body['filter'] ?? [];
72
+ $params = [
73
+ 'page' => $body['page'] ?? 1,
74
+ 'limit' => $body['limit'] ?? 20,
75
+ ];
76
+
77
+ $result = $this->es->query($this->entity, $filter, $params);
78
+ return $this->response->setJSON($result)->getBody();
79
+ }
80
+
81
+ /**
82
+ * POST /{entity}/submit
83
+ * POST /{entity}/submit/(:num) (seq route param을 body에 주입)
84
+ */
85
+ public function submit(?int $seq = null): string
86
+ {
87
+ try {
88
+ $data = $this->es->readRequestBody($this->request);
89
+ } catch (\Throwable $e) {
90
+ return $this->response->setStatusCode(400)
91
+ ->setJSON(['ok' => false, 'message' => $e->getMessage()])
92
+ ->getBody();
93
+ }
94
+
95
+ if ($seq !== null) {
96
+ $data['seq'] = $seq;
97
+ }
98
+
99
+ $result = $this->es->submit($this->entity, $data);
100
+ return $this->response->setJSON($result)->getBody();
101
+ }
102
+
103
+ /** DELETE /{entity}/delete/(:num) */
104
+ public function delete(int $seq): string
105
+ {
106
+ $result = $this->es->delete($this->entity, $seq);
107
+ return $this->response->setJSON($result)->getBody();
108
+ }
109
+
110
+ /** GET /{entity}/history/(:num) */
111
+ public function history(int $seq): string
112
+ {
113
+ $result = $this->es->history($this->entity, $seq);
114
+ return $this->response->setJSON($result)->getBody();
115
+ }
116
+
117
+ /** POST /{entity}/rollback/(:num) */
118
+ public function rollback(int $historySeq): string
119
+ {
120
+ $result = $this->es->rollback($this->entity, $historySeq);
121
+ return $this->response->setJSON($result)->getBody();
122
+ }
123
+
124
+ /**
125
+ * POST /{entity}/push
126
+ *
127
+ * push hook가 연결된 엔티티(push_msg 등)에 submit하여 푸시를 발행합니다.
128
+ * 요청 예:
129
+ * {
130
+ * "account_seq": 1,
131
+ * "title": "알림 제목",
132
+ * "message": "알림 본문",
133
+ * "ref_entity": "order",
134
+ * "ref_seq": 123,
135
+ * "data": {"order_seq": "123"}
136
+ * }
137
+ */
138
+ public function push(): string
139
+ {
140
+ try {
141
+ $body = $this->es->readRequestBody($this->request);
142
+ } catch (\Throwable $e) {
143
+ return $this->response->setStatusCode(400)
144
+ ->setJSON(['ok' => false, 'message' => $e->getMessage()])
145
+ ->getBody();
146
+ }
147
+
148
+ $target = (int) ($body[$this->pushTargetField] ?? 0);
149
+ if ($target <= 0) {
150
+ return $this->response->setStatusCode(400)
151
+ ->setJSON([
152
+ 'ok' => false,
153
+ 'message' => sprintf('%s required', $this->pushTargetField),
154
+ ])
155
+ ->getBody();
156
+ }
157
+
158
+ $title = (string) ($body['title'] ?? '');
159
+ $message = (string) ($body['message'] ?? $body['body'] ?? '');
160
+
161
+ $payload = [
162
+ $this->pushTargetField => $target,
163
+ 'title' => $title,
164
+ 'message' => $message,
165
+ ];
166
+
167
+ if (isset($body['ref_entity'])) {
168
+ $payload['ref_entity'] = (string) $body['ref_entity'];
169
+ }
170
+ if (isset($body['ref_seq'])) {
171
+ $payload['ref_seq'] = (int) $body['ref_seq'];
172
+ }
173
+ if (isset($body['data']) && is_array($body['data'])) {
174
+ $payload['data'] = $body['data'];
175
+ }
176
+
177
+ $result = $this->es->push($this->pushEntity, $payload);
178
+ return $this->response->setJSON($result)->getBody();
179
+ }
180
+
181
+ /**
182
+ * GET /{entity}/push-log/list?page=1&limit=20&account_seq=1
183
+ */
184
+ public function pushLogList(): string
185
+ {
186
+ $page = (int) ($this->request->getGet('page') ?? 1);
187
+ $limit = (int) ($this->request->getGet('limit') ?? 20);
188
+
189
+ $params = [
190
+ 'page' => $page,
191
+ 'limit' => $limit,
192
+ ];
193
+
194
+ $accountSeq = (int) ($this->request->getGet('account_seq') ?? 0);
195
+ if ($accountSeq > 0) {
196
+ $params['account_seq'] = $accountSeq;
197
+ }
198
+
199
+ $result = $this->es->pushLogList($params);
200
+ return $this->response->setJSON($result)->getBody();
201
+ }
202
+ }
@@ -2,81 +2,14 @@
2
2
 
3
3
  namespace App\Controllers;
4
4
 
5
- use App\Controllers\BaseController;
6
- use App\Libraries\EntityServer;
7
-
8
5
  /**
9
- * EntityServer 라이브러리를 사용하는 CI4 컨트롤러 예시
6
+ * Product 전용 컨트롤러 예시.
7
+ * 기본 CRUD는 EntityController를 상속받아 그대로 사용하고,
8
+ * 확장 기능(order)만 이 컨트롤러에서 구현합니다.
10
9
  */
11
- class ProductController extends BaseController
10
+ class ProductController extends EntityController
12
11
  {
13
- private EntityServer $es;
14
-
15
- public function __construct()
16
- {
17
- $this->es = new EntityServer();
18
- }
19
-
20
- /** GET /products */
21
- public function index(): string
22
- {
23
- $page = (int) ($this->request->getGet('page') ?? 1);
24
- $limit = (int) ($this->request->getGet('limit') ?? 20);
25
- $result = $this->es->list('product', ['page' => $page, 'limit' => $limit]);
26
-
27
- return $this->response->setJSON($result)->getBody();
28
- }
29
-
30
- /** GET /products/(:num) */
31
- public function show(int $seq): string
32
- {
33
- $result = $this->es->get('product', $seq);
34
- return $this->response->setJSON($result)->getBody();
35
- }
36
-
37
- /** POST /products/search */
38
- public function search(): string
39
- {
40
- $body = $this->request->getJSON(true);
41
- $filter = $body['filter'] ?? [];
42
- $params = ['page' => $body['page'] ?? 1, 'limit' => $body['limit'] ?? 20];
43
-
44
- // 필터 예: [['field' => 'category', 'op' => 'eq', 'value' => 'electronics']]
45
- $result = $this->es->query('product', $filter, $params);
46
- return $this->response->setJSON($result)->getBody();
47
- }
48
-
49
- /** POST /products */
50
- public function create(): string
51
- {
52
- $data = $this->request->getJSON(true);
53
- // seq 없이 submit → 생성
54
- $result = $this->es->submit('product', $data);
55
- return $this->response->setStatusCode(201)->setJSON($result)->getBody();
56
- }
57
-
58
- /** PUT /products/(:num) */
59
- public function update(int $seq): string
60
- {
61
- $data = $this->request->getJSON(true);
62
- $data['seq'] = $seq; // seq 포함 → 수정
63
- $result = $this->es->submit('product', $data);
64
- return $this->response->setJSON($result)->getBody();
65
- }
66
-
67
- /** DELETE /products/(:num) */
68
- public function delete(int $seq): string
69
- {
70
- $result = $this->es->delete('product', $seq);
71
- return $this->response->setJSON($result)->getBody();
72
- }
73
-
74
- /** GET /products/(:num)/history */
75
- public function history(int $seq): string
76
- {
77
- $result = $this->es->history('product', $seq);
78
- return $this->response->setJSON($result)->getBody();
79
- }
12
+ protected string $entity = 'product';
80
13
 
81
14
  /**
82
15
  * POST /products/order
@@ -90,7 +23,14 @@ class ProductController extends BaseController
90
23
  */
91
24
  public function order(): string
92
25
  {
93
- $body = $this->request->getJSON(true);
26
+ try {
27
+ $body = $this->es->readRequestBody($this->request);
28
+ } catch (\Throwable $e) {
29
+ return $this->response->setStatusCode(400)
30
+ ->setJSON(['ok' => false, 'message' => $e->getMessage()])
31
+ ->getBody();
32
+ }
33
+
94
34
  $productSeq = (int) ($body['product_seq'] ?? 0);
95
35
  $qty = (int) ($body['qty'] ?? 1);
96
36
  $buyer = $body['buyer'] ?? '';
@@ -101,16 +41,16 @@ class ProductController extends BaseController
101
41
  ->getBody();
102
42
  }
103
43
 
104
- $this->es->transStart(); // 서버 큐 등록, 이후 submit / delete 큐에씀임
44
+ $this->es->transStart(); // 서버 큐 등록, 이후 submit / delete 큐에 적재
105
45
 
106
46
  try {
107
47
  // 1) 상품 조회 후 재고 차감
108
- $product = $this->es->get('product', $productSeq);
48
+ $product = $this->es->get($this->entity, $productSeq);
109
49
  $stock = (int) ($product['data']['stock'] ?? 0);
110
50
  if ($stock < $qty) {
111
51
  throw new \RuntimeException('재고 부족');
112
52
  }
113
- $this->es->submit('product', [
53
+ $this->es->submit($this->entity, [
114
54
  'seq' => $productSeq,
115
55
  'stock' => $stock - $qty,
116
56
  ]);