create-entity-server 0.0.9
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/bin/create.js +280 -0
- package/package.json +42 -0
- package/template/.env.example +14 -0
- package/template/configs/cache.json +22 -0
- package/template/configs/cors.json +7 -0
- package/template/configs/database.json +23 -0
- package/template/configs/jwt.json +7 -0
- package/template/configs/logging.json +45 -0
- package/template/configs/security.json +21 -0
- package/template/configs/server.json +10 -0
- package/template/entities/Account/account_audit.json +17 -0
- package/template/entities/Auth/account.json +60 -0
- package/template/entities/Auth/api_keys.json +26 -0
- package/template/entities/Auth/license.json +36 -0
- package/template/entities/Auth/rbac_roles.json +76 -0
- package/template/entities/README.md +380 -0
- package/template/entities/System/system_audit_log.json +65 -0
- package/template/entities/company.json +22 -0
- package/template/entities/product.json +36 -0
- package/template/entities/todo.json +16 -0
- package/template/samples/README.md +65 -0
- package/template/samples/flutter/lib/entity_server_client.dart +218 -0
- package/template/samples/flutter/pubspec.yaml +14 -0
- package/template/samples/java/EntityServerClient.java +304 -0
- package/template/samples/java/EntityServerExample.java +49 -0
- package/template/samples/kotlin/EntityServerClient.kt +194 -0
- package/template/samples/node/package.json +16 -0
- package/template/samples/node/src/EntityServerClient.js +246 -0
- package/template/samples/node/src/example.js +39 -0
- package/template/samples/php/ci4/Controllers/ProductController.php +141 -0
- package/template/samples/php/ci4/Libraries/EntityServer.php +260 -0
- package/template/samples/php/laravel/Http/Controllers/ProductController.php +62 -0
- package/template/samples/php/laravel/Services/EntityServerService.php +210 -0
- package/template/samples/python/entity_server.py +225 -0
- package/template/samples/python/example.py +50 -0
- package/template/samples/react/src/api/entityServerClient.ts +290 -0
- package/template/samples/react/src/example.tsx +127 -0
- package/template/samples/react/src/hooks/useEntity.ts +105 -0
- package/template/samples/swift/EntityServerClient.swift +221 -0
- package/template/scripts/api-key.ps1 +123 -0
- package/template/scripts/api-key.sh +130 -0
- package/template/scripts/cleanup-history.ps1 +69 -0
- package/template/scripts/cleanup-history.sh +54 -0
- package/template/scripts/cli.ps1 +24 -0
- package/template/scripts/cli.sh +27 -0
- package/template/scripts/entity.ps1 +70 -0
- package/template/scripts/entity.sh +72 -0
- package/template/scripts/generate-env-keys.ps1 +125 -0
- package/template/scripts/generate-env-keys.sh +148 -0
- package/template/scripts/install-systemd.sh +222 -0
- package/template/scripts/normalize-entities.ps1 +87 -0
- package/template/scripts/normalize-entities.sh +132 -0
- package/template/scripts/rbac-role.ps1 +124 -0
- package/template/scripts/rbac-role.sh +127 -0
- package/template/scripts/remove-systemd.sh +158 -0
- package/template/scripts/reset-all.ps1 +83 -0
- package/template/scripts/reset-all.sh +95 -0
- package/template/scripts/run.ps1 +239 -0
- package/template/scripts/run.sh +315 -0
- package/template/scripts/sync.ps1 +145 -0
- package/template/scripts/sync.sh +178 -0
- package/template/scripts/update-server.ps1 +117 -0
- package/template/scripts/update-server.sh +165 -0
|
@@ -0,0 +1,76 @@
|
|
|
1
|
+
{
|
|
2
|
+
"name": "rbac_roles",
|
|
3
|
+
"description": "RBAC 역할 정의 예제",
|
|
4
|
+
"license_scope": false,
|
|
5
|
+
"index": {
|
|
6
|
+
"name": {
|
|
7
|
+
"comment": "역할 이름",
|
|
8
|
+
"required": true,
|
|
9
|
+
"unique": true
|
|
10
|
+
}
|
|
11
|
+
},
|
|
12
|
+
"types": {
|
|
13
|
+
"permissions": "text"
|
|
14
|
+
},
|
|
15
|
+
"hard_delete": true,
|
|
16
|
+
"reset_defaults": [
|
|
17
|
+
{
|
|
18
|
+
"name": "admin",
|
|
19
|
+
"description": "전체 권한 (모든 엔티티 CRUD + 관리)",
|
|
20
|
+
"permissions": ["*"]
|
|
21
|
+
},
|
|
22
|
+
{
|
|
23
|
+
"name": "editor",
|
|
24
|
+
"description": "읽기 + 쓰기 (생성/수정/삭제 가능)",
|
|
25
|
+
"permissions": [
|
|
26
|
+
"entity:meta",
|
|
27
|
+
"entity:validate",
|
|
28
|
+
"entity:read",
|
|
29
|
+
"entity:list",
|
|
30
|
+
"entity:count",
|
|
31
|
+
"entity:query",
|
|
32
|
+
"entity:create",
|
|
33
|
+
"entity:delete",
|
|
34
|
+
"entity:history",
|
|
35
|
+
"entity:rollback",
|
|
36
|
+
"admin:entities",
|
|
37
|
+
"admin:stats",
|
|
38
|
+
"admin:reindex"
|
|
39
|
+
]
|
|
40
|
+
},
|
|
41
|
+
{
|
|
42
|
+
"name": "viewer",
|
|
43
|
+
"description": "읽기 전용",
|
|
44
|
+
"permissions": [
|
|
45
|
+
"entity:meta",
|
|
46
|
+
"entity:read",
|
|
47
|
+
"entity:list",
|
|
48
|
+
"entity:count",
|
|
49
|
+
"entity:query",
|
|
50
|
+
"admin:entities",
|
|
51
|
+
"admin:stats"
|
|
52
|
+
]
|
|
53
|
+
},
|
|
54
|
+
{
|
|
55
|
+
"name": "auditor",
|
|
56
|
+
"description": "읽기 + history 조회 전용",
|
|
57
|
+
"permissions": [
|
|
58
|
+
"entity:read",
|
|
59
|
+
"entity:list",
|
|
60
|
+
"entity:history",
|
|
61
|
+
"admin:entities",
|
|
62
|
+
"admin:stats"
|
|
63
|
+
]
|
|
64
|
+
},
|
|
65
|
+
{
|
|
66
|
+
"name": "user",
|
|
67
|
+
"description": "일반 사용자 (기본 CRUD)",
|
|
68
|
+
"permissions": [
|
|
69
|
+
"entity:meta",
|
|
70
|
+
"entity:read",
|
|
71
|
+
"entity:list",
|
|
72
|
+
"entity:count"
|
|
73
|
+
]
|
|
74
|
+
}
|
|
75
|
+
]
|
|
76
|
+
}
|
|
@@ -0,0 +1,380 @@
|
|
|
1
|
+
# Example Entities
|
|
2
|
+
|
|
3
|
+
이 폴더는 배포용 예제 엔티티 스키마입니다.
|
|
4
|
+
|
|
5
|
+
## 예제 엔티티 목록
|
|
6
|
+
|
|
7
|
+
| 파일 | 설명 | 주요 특징 |
|
|
8
|
+
| -------------------------------------------------------------------------- | -------------- | ------------------------------------------------------------------------- |
|
|
9
|
+
| [todo.json](#1-todojson) | 할 일 목록 | 기본 인덱스, 해시 필드 |
|
|
10
|
+
| [product.json](#2-productjson) | 제품 관리 | 유니크 제약, reset_defaults 시딩 |
|
|
11
|
+
| [examples/Auth/account.json](#3-examplesauthaccountjson) | 사용자 관리 | rbac_role, 인증 훅 / **JWT 사용 시 필수** |
|
|
12
|
+
| [examples/Auth/rbac_roles.json](#4-examplesauthrbac_rolesjson) | RBAC 역할 정의 | permissions 포함 5개 역할, reset-all 시 자동 시딩 / **RBAC 사용 시 필수** |
|
|
13
|
+
| [examples/Auth/api_keys.json](#5-examplesauthauthapi_keysjson) | API 키 관리 | HMAC 인증 키, 역할 연결, user_seq 연결 / **HMAC 사용 시 필수** |
|
|
14
|
+
| [license.json](#6-licensejson) | 라이선스 관리 | 계약/만료일, 유니크 제약, 자동 시딩 |
|
|
15
|
+
| [company.json](#7-companyjson) | 회사 정보 | license_scope, 사업자번호 해시, 캐시 |
|
|
16
|
+
| [examples/Account/account_audit.json](#8-examplesaccountaccount_auditjson) | 감사 로그 | INSERT 전용, 훅으로 자동 기록 |
|
|
17
|
+
|
|
18
|
+
## 문서 바로가기
|
|
19
|
+
|
|
20
|
+
| 섹션 | 내용 |
|
|
21
|
+
| ------------------------------------------------------------ | ----------------------------------------- |
|
|
22
|
+
| [포함된 예제](#포함된-예제) | 각 예제 파일 상세 설명 |
|
|
23
|
+
| [엔티티 설정 규칙](#엔티티-설정-규칙) | 자동 추론 필드, Types, index 형식, 복합키 |
|
|
24
|
+
| [훅 (Hooks)](#훅-hooks) | SQL 훅, Entity 훅, 실행 시점, 템플릿 변수 |
|
|
25
|
+
| [라이선스 스코프](#라이선스-스코프란) | 멀티테넌트 / 단일 시스템 모드 |
|
|
26
|
+
| [Entity Config Guide](../../docs/ops/entity-config-guide.md) | 전체 엔티티 설정 레퍼런스 |
|
|
27
|
+
|
|
28
|
+
---
|
|
29
|
+
|
|
30
|
+
## 포함된 예제
|
|
31
|
+
|
|
32
|
+
### 1. todo.json
|
|
33
|
+
|
|
34
|
+
간단한 할 일 목록 엔티티
|
|
35
|
+
|
|
36
|
+
**특징**:
|
|
37
|
+
|
|
38
|
+
- 기본 인덱스 필드 (`title`, `status`, `created_time`)
|
|
39
|
+
- 해시 필드 (`user_id`) - 암호화되어 저장
|
|
40
|
+
|
|
41
|
+
### 2. product.json
|
|
42
|
+
|
|
43
|
+
제품 관리 엔티티
|
|
44
|
+
|
|
45
|
+
**특징**:
|
|
46
|
+
|
|
47
|
+
- 유니크 제약 (`name`) - 제품명 중복 방지
|
|
48
|
+
- `reset_defaults` - 초기 데이터 시딩
|
|
49
|
+
- `stock` 필드는 자동 추론 (int)
|
|
50
|
+
|
|
51
|
+
### 3. examples/Auth/account.json
|
|
52
|
+
|
|
53
|
+
사용자 관리 엔티티 (`entities/examples/Auth/` 에 위치 → 배포 시 `dist/entities/Auth/account.json`)
|
|
54
|
+
|
|
55
|
+
> **⚠️ JWT 인증을 사용하려면 필수입니다.**
|
|
56
|
+
> HMAC 인증만 사용하는 경우에는 필요하지 않습니다.
|
|
57
|
+
> `jwt.json`에 `secret`이 설정된 경우 서버 기동 시 `entities/Auth/account.json`이 존재하지 않으면 오류가 발생합니다.
|
|
58
|
+
> `email`, `rbac_role` 필드가 index에 포함되어 있어야 합니다.
|
|
59
|
+
> `./scripts/reset-all.sh --apply` 실행 시 파일이 없으면 자동으로 생성됩니다.
|
|
60
|
+
|
|
61
|
+
**특징**:
|
|
62
|
+
|
|
63
|
+
- `rbac_role` 필드 - JWT 토큰에 포함되는 RBAC 역할 (인증/인가에 사용)
|
|
64
|
+
- 해시 필드 (`password_hash`) - 비밀번호 암호화
|
|
65
|
+
- 유니크 제약 (`email`) - 이메일 중복 방지
|
|
66
|
+
- **훅 예제**:
|
|
67
|
+
- `after_insert`: 감사 로그 기록 (SQL 훅)
|
|
68
|
+
|
|
69
|
+
### 4. examples/Auth/rbac_roles.json
|
|
70
|
+
|
|
71
|
+
RBAC 역할 정의 엔티티 (`entities/examples/Auth/` 에 위치 → 배포 시 `dist/entities/Auth/rbac_roles.json`)
|
|
72
|
+
|
|
73
|
+
> **⚠️ RBAC 인증을 사용하려면 필수입니다.**
|
|
74
|
+
> `reset-all` 실행 시 `reset_defaults`의 5개 역할이 자동 시딩됩니다.
|
|
75
|
+
> `/v1/admin/roles` API 및 `scripts/rbac-roles.sh` 로 역할 조회/추가/삭제가 가능합니다.
|
|
76
|
+
> `security.json`의 `roles`는 더 이상 사용하지 않습니다 (`{}`로 비워져 있음).
|
|
77
|
+
|
|
78
|
+
**특징**:
|
|
79
|
+
|
|
80
|
+
- `name` 유니크 제약 - 역할명 중복 방지
|
|
81
|
+
- `reset_defaults` - 기본 역할 5개 (`admin`, `editor`, `viewer`, `auditor`, `user`) 자동 시딩
|
|
82
|
+
- `hard_delete: true` - 논리 삭제 없이 실제 삭제
|
|
83
|
+
- `account.rbac_role` 필드와 구성이 일치해야 함
|
|
84
|
+
|
|
85
|
+
### 5. examples/Auth/api_keys.json
|
|
86
|
+
|
|
87
|
+
API 키 관리 엔티티 (`entities/examples/Auth/` 에 위치 → 배포 시 `dist/entities/Auth/api_keys.json`)
|
|
88
|
+
|
|
89
|
+
> **⚠️ HMAC 인증을 사용하려면 필수입니다.**
|
|
90
|
+
> `reset-all` 실행 시 admin 역할의 API 키 1개가 자동 생성되며 `key_value`와 `hmac_secret`이 출력됩니다.
|
|
91
|
+
> `/v1/admin/api-keys` API 및 `scripts/api-keys.sh` 로 키 조회/추가/삭제/재생성이 가능합니다.
|
|
92
|
+
> JWT 전용으로 운영하는 경우에는 이 엔티티 없이도 동작합니다.
|
|
93
|
+
|
|
94
|
+
**특징**:
|
|
95
|
+
|
|
96
|
+
- `key_value` 해시 저장 - 원본 키는 생성 시 1회만 노출
|
|
97
|
+
- `hmac_secret` - HMAC 서명 검증용 시크릿 (재생성 가능)
|
|
98
|
+
- `role` 필드 - `rbac_roles` 엔티티의 역할명 참조
|
|
99
|
+
- `user_seq` 필드 (nullable) - 특정 사용자에게 키를 귀속시킬 수 있음 (확장성)
|
|
100
|
+
- `entities` 필드 - 접근 가능한 엔티티 목록 (기본값 `["*"]`)
|
|
101
|
+
- `hard_delete: true` - 완전 삭제
|
|
102
|
+
|
|
103
|
+
**CLI 사용 예**:
|
|
104
|
+
|
|
105
|
+
```bash
|
|
106
|
+
API_KEY=<admin-key> ./scripts/api-keys.sh list
|
|
107
|
+
API_KEY=<admin-key> ./scripts/api-keys.sh create --role=viewer --description="대시보드 읽기 전용"
|
|
108
|
+
API_KEY=<admin-key> ./scripts/api-keys.sh create --role=editor --user-seq=5
|
|
109
|
+
API_KEY=<admin-key> ./scripts/api-keys.sh regenerate 3
|
|
110
|
+
API_KEY=<admin-key> ./scripts/api-keys.sh delete 3
|
|
111
|
+
```
|
|
112
|
+
|
|
113
|
+
### 6. license.json
|
|
114
|
+
|
|
115
|
+
라이선스 관리 엔티티
|
|
116
|
+
|
|
117
|
+
**특징**:
|
|
118
|
+
|
|
119
|
+
- 계약일/만료일 관리
|
|
120
|
+
- 유니크 제약으로 라이선스명 중복 방지
|
|
121
|
+
- `reset_defaults`로 Trial 라이선스 자동 생성
|
|
122
|
+
|
|
123
|
+
### 7. company.json
|
|
124
|
+
|
|
125
|
+
회사 정보 엔티티 (라이선스 스코프)
|
|
126
|
+
|
|
127
|
+
**특징**:
|
|
128
|
+
|
|
129
|
+
- **`license_scope: true`** - 라이선스별 데이터 분리
|
|
130
|
+
- 해시 필드 (`tax_id`) - 사업자번호 암호화
|
|
131
|
+
- 캐시 활성화 (TTL 300초)
|
|
132
|
+
|
|
133
|
+
### 8. examples/Account/account_audit.json
|
|
134
|
+
|
|
135
|
+
사용자 감사 로그 엔티티
|
|
136
|
+
|
|
137
|
+
**특징**:
|
|
138
|
+
|
|
139
|
+
- **`license_scope: false`** - 전체 시스템 감사 로그 통합 관리
|
|
140
|
+
- 훅을 통해 자동 기록 (`account.json`의 `after_insert` 훅)
|
|
141
|
+
- 읽기 전용 로그 (INSERT만 허용)
|
|
142
|
+
- action 타입: `INSERT`, `UPDATE`, `DELETE`, `LOGIN`, `LOGOUT`
|
|
143
|
+
|
|
144
|
+
## 엔티티 설정 규칙
|
|
145
|
+
|
|
146
|
+
### 자동 추론되는 필드
|
|
147
|
+
|
|
148
|
+
필드명 패턴에 따라 타입이 자동으로 추론됩니다:
|
|
149
|
+
|
|
150
|
+
**식별자**:
|
|
151
|
+
|
|
152
|
+
- `_seq`, `_id` → BIGINT UNSIGNED
|
|
153
|
+
|
|
154
|
+
**날짜/시간**:
|
|
155
|
+
|
|
156
|
+
- `_date` → DATE
|
|
157
|
+
- `_time`, `_at` → DATETIME
|
|
158
|
+
|
|
159
|
+
**불리언**:
|
|
160
|
+
|
|
161
|
+
- `is_*`, `has_*`, `can_*` → TINYINT(1)
|
|
162
|
+
|
|
163
|
+
**숫자**:
|
|
164
|
+
|
|
165
|
+
- `_count`, `_cnt`, `_qty`, `_quantity` → INT
|
|
166
|
+
- `_amount`, `_price`, `_total`, `_cost` → DECIMAL(15,2)
|
|
167
|
+
|
|
168
|
+
**문자열**:
|
|
169
|
+
|
|
170
|
+
- `name`, `*_name` → VARCHAR(100)
|
|
171
|
+
- `*email*` → VARCHAR(255)
|
|
172
|
+
- `*phone*`, `*tel*` → VARCHAR(50)
|
|
173
|
+
|
|
174
|
+
### Types 정의
|
|
175
|
+
|
|
176
|
+
필드명 패턴으로 자동 추론이 안되는 경우에만 types를 명시적으로 정의합니다.
|
|
177
|
+
|
|
178
|
+
#### 사용 가능한 타입
|
|
179
|
+
|
|
180
|
+
| 타입 | 사용 예시 | MySQL 매핑 | 설명 |
|
|
181
|
+
| --------------------------------- | ------------------------------ | ----------------- | -------------------------- |
|
|
182
|
+
| **enum** | `["active", "expired"]` | `ENUM(...)` | 허용 값 목록 (배열로 정의) |
|
|
183
|
+
| `"int"` / `"number"` / `"bigint"` | `"count": "int"` | `BIGINT` | 정수 (음수 가능) |
|
|
184
|
+
| `"uint"` | `"max_users": "uint"` | `BIGINT UNSIGNED` | 양의 정수 |
|
|
185
|
+
| `"string"` | `"code": "string"` | `VARCHAR(255)` | 일반 문자열 |
|
|
186
|
+
| `"text"` | `"description": "text"` | `TEXT` | 긴 텍스트 |
|
|
187
|
+
| `"boolean"` / `"bool"` | `"enabled": "bool"` | `TINYINT(1)` | 참/거짓 |
|
|
188
|
+
| `"date"` | `"birth_date": "date"` | `DATE` | 날짜 (시간 제외) |
|
|
189
|
+
| `"datetime"` / `"timestamp"` | `"scheduled_time": "datetime"` | `DATETIME` | 날짜+시간 |
|
|
190
|
+
| `"decimal"` | `"tax_rate": "decimal"` | `DECIMAL(15,2)` | 소수점 숫자 |
|
|
191
|
+
| `"email"` | `"contact": "email"` | `VARCHAR(255)` | 이메일 (검증 포함) |
|
|
192
|
+
| `"phone"` | `"mobile": "phone"` | `VARCHAR(50)` | 전화번호 (검증 포함) |
|
|
193
|
+
|
|
194
|
+
**참고**: 자동 추론 가능한 필드는 types 정의를 생략하세요 (위 "자동 추론되는 필드" 섹션 참고)
|
|
195
|
+
|
|
196
|
+
### Comments
|
|
197
|
+
|
|
198
|
+
- **인덱스 필드만** 코멘트 작성
|
|
199
|
+
- 해시 필드나 자동 추론 필드는 불필요
|
|
200
|
+
- enum 값 설명은 types에 정의하고 comments는 간결하게
|
|
201
|
+
|
|
202
|
+
### index 확장 형식 (하위 호환)
|
|
203
|
+
|
|
204
|
+
- `index`는 문자열 배열(간단 모드) 또는 객체맵(확장 모드)을 지원
|
|
205
|
+
- 객체맵 키는 필드명이며 값에 `comment`, `type`, `required`, `unique`, `hash`를 선언
|
|
206
|
+
- 권장 키 순서: `comment` → `type` → `required` → `unique` → `hash`
|
|
207
|
+
- `type`은 대소문자 구분 없이 동작하며 소문자 통일 권장 (예: `bigint`, `varchar(32)`)
|
|
208
|
+
|
|
209
|
+
```json
|
|
210
|
+
{
|
|
211
|
+
"index": {
|
|
212
|
+
"user_seq": {
|
|
213
|
+
"comment": "사용자 seq",
|
|
214
|
+
"type": "bigint",
|
|
215
|
+
"required": true
|
|
216
|
+
},
|
|
217
|
+
"action": {
|
|
218
|
+
"comment": "작업 유형",
|
|
219
|
+
"type": "varchar(32)",
|
|
220
|
+
"required": true,
|
|
221
|
+
"unique": true,
|
|
222
|
+
"hash": true
|
|
223
|
+
}
|
|
224
|
+
}
|
|
225
|
+
}
|
|
226
|
+
```
|
|
227
|
+
|
|
228
|
+
### 복합키(복합 유니크) 설정
|
|
229
|
+
|
|
230
|
+
- `index.<field>.unique=true`는 단일 유니크만 설정합니다.
|
|
231
|
+
- 두 개 이상 필드의 복합키는 `unique`에 배열로 선언합니다.
|
|
232
|
+
|
|
233
|
+
```json
|
|
234
|
+
{
|
|
235
|
+
"index": {
|
|
236
|
+
"user_seq": {
|
|
237
|
+
"comment": "사용자seq",
|
|
238
|
+
"required": true
|
|
239
|
+
},
|
|
240
|
+
"device_id": {
|
|
241
|
+
"comment": "기기ID",
|
|
242
|
+
"required": true
|
|
243
|
+
}
|
|
244
|
+
},
|
|
245
|
+
"unique": [["user_seq", "device_id"]]
|
|
246
|
+
}
|
|
247
|
+
```
|
|
248
|
+
|
|
249
|
+
## 훅 (Hooks)
|
|
250
|
+
|
|
251
|
+
훅은 엔티티 이벤트 발생 시 자동으로 실행되는 기능입니다.
|
|
252
|
+
|
|
253
|
+
### 사용 가능한 훅 타이프
|
|
254
|
+
|
|
255
|
+
**SQL 훅** - 직접 SQL 실행:
|
|
256
|
+
|
|
257
|
+
```json
|
|
258
|
+
{
|
|
259
|
+
"type": "sql",
|
|
260
|
+
"query": "INSERT INTO account_audit (account_seq, action, created_time) VALUES (?, ?, NOW())",
|
|
261
|
+
"params": ["${new.seq}", "INSERT"],
|
|
262
|
+
"async": false
|
|
263
|
+
}
|
|
264
|
+
```
|
|
265
|
+
|
|
266
|
+
**Entity 훅** - 다른 엔티티 조작:
|
|
267
|
+
|
|
268
|
+
```json
|
|
269
|
+
{
|
|
270
|
+
"type": "entity",
|
|
271
|
+
"entity": "todo",
|
|
272
|
+
"action": "list",
|
|
273
|
+
"conditions": {
|
|
274
|
+
"user_id": "${new.seq}"
|
|
275
|
+
},
|
|
276
|
+
"assign_to": "todos"
|
|
277
|
+
}
|
|
278
|
+
```
|
|
279
|
+
|
|
280
|
+
### 훅 실행 시점
|
|
281
|
+
|
|
282
|
+
| 이벤트 | 설명 | 사용 예시 |
|
|
283
|
+
| -------------- | ------------------- | ------------------------------- |
|
|
284
|
+
| `after_insert` | 데이터 삽입 후 실행 | 감사 로그, 알림 발송 |
|
|
285
|
+
| `after_update` | 데이터 수정 후 실행 | 변경 이력 기록, 캐시 무효화 |
|
|
286
|
+
| `after_delete` | 데이터 삭제 후 실행 | 관련 데이터 정리, 파일 삭제 |
|
|
287
|
+
| `after_get` | 데이터 조회 후 실행 | 관련 데이터 병합 (join 과 유사) |
|
|
288
|
+
| `after_list` | 목록 조회 후 실행 | 각 항목에 추가 정보 부착 |
|
|
289
|
+
|
|
290
|
+
### 테플릿 변수
|
|
291
|
+
|
|
292
|
+
훅에서 사용 가능한 변수:
|
|
293
|
+
|
|
294
|
+
- `${new.field}` - 새로 삽입/수정된 데이터의 필드
|
|
295
|
+
- `${old.field}` - 수정 이전 데이터의 필드
|
|
296
|
+
- `${ctx.license_seq}` - 현재 라이선스 seq
|
|
297
|
+
- `${ctx.user_seq}` - 현재 사용자 seq
|
|
298
|
+
|
|
299
|
+
**참고**: 자세한 내용은 [Hooks Guide](../../docs/hooks.md)를 참고하세요.
|
|
300
|
+
|
|
301
|
+
## 라이선스 스코프란?
|
|
302
|
+
|
|
303
|
+
### 전역 설정 (권장)
|
|
304
|
+
|
|
305
|
+
**server.json**에서 전체 시스템의 기본 동작을 설정할 수 있습니다:
|
|
306
|
+
|
|
307
|
+
**멀티테넌트 SaaS 모드** (기본값):
|
|
308
|
+
|
|
309
|
+
```json
|
|
310
|
+
{
|
|
311
|
+
"global_license_scope": true
|
|
312
|
+
}
|
|
313
|
+
```
|
|
314
|
+
|
|
315
|
+
- 라이선스별 데이터 완전 분리
|
|
316
|
+
- `license` 엔티티 필수
|
|
317
|
+
- 각 라이선스의 `secret_key`로 암호화
|
|
318
|
+
|
|
319
|
+
**단일 시스템 모드**:
|
|
320
|
+
|
|
321
|
+
```json
|
|
322
|
+
{
|
|
323
|
+
"global_license_scope": false
|
|
324
|
+
}
|
|
325
|
+
```
|
|
326
|
+
|
|
327
|
+
- `license` 엔티티 불필요
|
|
328
|
+
- 모든 사용자가 동일한 데이터 공유
|
|
329
|
+
- `.env`의 `ENCRYPTION_KEY`로 암호화
|
|
330
|
+
- 소규모 팀, 내부 시스템에 적합
|
|
331
|
+
|
|
332
|
+
**개별 엔티티**에서 이 설정을 덮어쓸 수 있습니다:
|
|
333
|
+
|
|
334
|
+
```json
|
|
335
|
+
{
|
|
336
|
+
"name": "shared_config",
|
|
337
|
+
"license_scope": false,
|
|
338
|
+
"index": ["key", "value"]
|
|
339
|
+
}
|
|
340
|
+
```
|
|
341
|
+
|
|
342
|
+
### 멀티테넌트 모드 (license_scope: true)
|
|
343
|
+
|
|
344
|
+
라이선스별로 데이터가 **완전히 분리**됩니다:
|
|
345
|
+
|
|
346
|
+
- A 라이선스 사용자는 B 라이선스의 데이터를 볼 수 없습니다
|
|
347
|
+
- 멀티테넌트 SaaS 구조에 적합합니다
|
|
348
|
+
- **암호화 키**: 각 라이선스의 `secret_key` 사용
|
|
349
|
+
- `license` 엔티티 필수
|
|
350
|
+
|
|
351
|
+
**예시**: `license.json` + `company.json` 조합
|
|
352
|
+
|
|
353
|
+
- `license`: 라이선스별 계약/만료 관리
|
|
354
|
+
- `company`: 각 라이선스가 관리하는 회사 목록 (분리 저장)
|
|
355
|
+
|
|
356
|
+
### 단일 시스템 모드 (license_scope: false)
|
|
357
|
+
|
|
358
|
+
라이선스 구분 없이 단일 시스템으로 동작합니다:
|
|
359
|
+
|
|
360
|
+
- `license` 엔티티 불필요
|
|
361
|
+
- 모든 사용자가 동일한 데이터 공유
|
|
362
|
+
- **암호화 키**: `.env`의 `ENCRYPTION_KEY` 사용
|
|
363
|
+
- 소규모 팀, 내부 시스템에 적합
|
|
364
|
+
|
|
365
|
+
**설정 우선순위**:
|
|
366
|
+
|
|
367
|
+
1. 엔티티 개별 설정 (`license_scope`)
|
|
368
|
+
2. server.json 전역 설정 (`global_license_scope`)
|
|
369
|
+
3. 기본값 (`true`)
|
|
370
|
+
|
|
371
|
+
예제 파일을 복사하여 수정 후 사용하세요:
|
|
372
|
+
|
|
373
|
+
```bash
|
|
374
|
+
# 서버 실행 시 자동으로 인덱스 테이블 생성됩니다
|
|
375
|
+
./scripts/run.sh dev
|
|
376
|
+
```
|
|
377
|
+
|
|
378
|
+
## 더 많은 예제
|
|
379
|
+
|
|
380
|
+
전체 문서는 [Entity Config Guide](../../docs/entity-config-guide.md)를 참고하세요.
|
|
@@ -0,0 +1,65 @@
|
|
|
1
|
+
{
|
|
2
|
+
"name": "system_audit_log",
|
|
3
|
+
"description": "시스템 감사 로그. 서버 레벨에서 자동 기록되며 API를 통한 직접 수정은 허용되지 않습니다.",
|
|
4
|
+
"db_group": "system",
|
|
5
|
+
"hard_delete": true,
|
|
6
|
+
"history_ttl": 0,
|
|
7
|
+
"read_only": true,
|
|
8
|
+
"license_scope": false,
|
|
9
|
+
"index": {
|
|
10
|
+
"transaction_id": {
|
|
11
|
+
"comment": "요청 트랜잭션 ID. entity_history 테이블과 JOIN 키",
|
|
12
|
+
"type": "varchar(64)"
|
|
13
|
+
},
|
|
14
|
+
"entity_name": {
|
|
15
|
+
"comment": "대상 엔티티 이름",
|
|
16
|
+
"type": "varchar(100)",
|
|
17
|
+
"required": true
|
|
18
|
+
},
|
|
19
|
+
"entity_seq": {
|
|
20
|
+
"comment": "대상 엔티티 레코드 seq. 로그인/로그아웃 등 레코드 없는 경우 NULL",
|
|
21
|
+
"type": "bigint"
|
|
22
|
+
},
|
|
23
|
+
"action": {
|
|
24
|
+
"comment": "수행된 작업 유형",
|
|
25
|
+
"type": [
|
|
26
|
+
"INSERT",
|
|
27
|
+
"UPDATE",
|
|
28
|
+
"DELETE_SOFT",
|
|
29
|
+
"DELETE_HARD",
|
|
30
|
+
"LOGIN",
|
|
31
|
+
"LOGOUT",
|
|
32
|
+
"ROLLBACK"
|
|
33
|
+
],
|
|
34
|
+
"required": true
|
|
35
|
+
},
|
|
36
|
+
"account_seq": {
|
|
37
|
+
"comment": "작업을 수행한 계정 seq. 비인증 요청은 NULL",
|
|
38
|
+
"type": "bigint"
|
|
39
|
+
},
|
|
40
|
+
"ip_address": {
|
|
41
|
+
"comment": "요청 IP 주소 (IPv4/IPv6)",
|
|
42
|
+
"type": "varchar(45)"
|
|
43
|
+
},
|
|
44
|
+
"endpoint": {
|
|
45
|
+
"comment": "요청 API 엔드포인트",
|
|
46
|
+
"type": "varchar(200)"
|
|
47
|
+
},
|
|
48
|
+
"request_method": {
|
|
49
|
+
"comment": "HTTP 메서드 (GET/POST/PUT/DELETE 등)",
|
|
50
|
+
"type": "varchar(10)"
|
|
51
|
+
},
|
|
52
|
+
"request_payload": {
|
|
53
|
+
"comment": "요청 본문 JSON. 민감 필드(password, token 등) 자동 마스킹 후 저장. ServerConfig.AuditLogPayload = true 일 때만 기록",
|
|
54
|
+
"type": "text"
|
|
55
|
+
},
|
|
56
|
+
"result_code": {
|
|
57
|
+
"comment": "HTTP 응답 코드 (200, 400, 401, 403, 500 등)",
|
|
58
|
+
"type": "int"
|
|
59
|
+
},
|
|
60
|
+
"error_message": {
|
|
61
|
+
"comment": "실패 시 오류 메시지 요약",
|
|
62
|
+
"type": "varchar(500)"
|
|
63
|
+
}
|
|
64
|
+
}
|
|
65
|
+
}
|
|
@@ -0,0 +1,22 @@
|
|
|
1
|
+
{
|
|
2
|
+
"name": "company",
|
|
3
|
+
"description": "company Entity",
|
|
4
|
+
"index": {
|
|
5
|
+
"company_name": {
|
|
6
|
+
"comment": "회사명",
|
|
7
|
+
"required": true
|
|
8
|
+
},
|
|
9
|
+
"industry": {
|
|
10
|
+
"comment": "업종"
|
|
11
|
+
},
|
|
12
|
+
"tax_id": {
|
|
13
|
+
"comment": "사업자번호",
|
|
14
|
+
"hash": true
|
|
15
|
+
}
|
|
16
|
+
},
|
|
17
|
+
"license_scope": true,
|
|
18
|
+
"cache": {
|
|
19
|
+
"enabled": true,
|
|
20
|
+
"ttl_seconds": 300
|
|
21
|
+
}
|
|
22
|
+
}
|
|
@@ -0,0 +1,36 @@
|
|
|
1
|
+
{
|
|
2
|
+
"name": "product",
|
|
3
|
+
"description": "product Entity",
|
|
4
|
+
"index": {
|
|
5
|
+
"name": {
|
|
6
|
+
"comment": "제품명",
|
|
7
|
+
"required": true,
|
|
8
|
+
"unique": true
|
|
9
|
+
},
|
|
10
|
+
"category": {
|
|
11
|
+
"comment": "카테고리",
|
|
12
|
+
"type": [
|
|
13
|
+
"전자제품",
|
|
14
|
+
"가구",
|
|
15
|
+
"생활용품"
|
|
16
|
+
]
|
|
17
|
+
},
|
|
18
|
+
"price": {
|
|
19
|
+
"comment": "가격"
|
|
20
|
+
}
|
|
21
|
+
},
|
|
22
|
+
"reset_defaults": [
|
|
23
|
+
{
|
|
24
|
+
"name": "샘플 제품 A",
|
|
25
|
+
"category": "전자제품",
|
|
26
|
+
"price": 10000,
|
|
27
|
+
"stock": 50
|
|
28
|
+
},
|
|
29
|
+
{
|
|
30
|
+
"name": "샘플 제품 B",
|
|
31
|
+
"category": "가구",
|
|
32
|
+
"price": 50000,
|
|
33
|
+
"stock": 20
|
|
34
|
+
}
|
|
35
|
+
]
|
|
36
|
+
}
|
|
@@ -0,0 +1,65 @@
|
|
|
1
|
+
# Entity Server — 클라이언트 라이브러리 샘플
|
|
2
|
+
|
|
3
|
+
백엔드 서버에서 Entity Server와 HMAC 인증으로 통신하는 클라이언트 구현 샘플입니다.
|
|
4
|
+
|
|
5
|
+
> **Admin API(`/v1/admin/...`)는 포함하지 않습니다.**
|
|
6
|
+
> 관리 작업(초기화·스키마 동기화·사용자·API 키 관리 등)은 `scripts/` 스크립트 또는 Admin Web UI를 통해 수행합니다.
|
|
7
|
+
> 앱 코드에서 파괴적 admin 작업을 직접 호출하는 것은 권장하지 않습니다.
|
|
8
|
+
|
|
9
|
+
## 아키텍처 패턴
|
|
10
|
+
|
|
11
|
+
```
|
|
12
|
+
Client / Browser
|
|
13
|
+
│
|
|
14
|
+
▼ (기존 인증: 세션, JWT 등)
|
|
15
|
+
Backend Server ←── 이 샘플이 구현하는 부분
|
|
16
|
+
│
|
|
17
|
+
▼ HMAC 서명 (서버 간 통신)
|
|
18
|
+
Entity Server (Go)
|
|
19
|
+
```
|
|
20
|
+
|
|
21
|
+
> **React (SPA)** 샘플은 HMAC 대신 JWT Bearer 토큰을 사용합니다.
|
|
22
|
+
> 브라우저 환경에서는 HMAC secret을 노출할 수 없기 때문입니다.
|
|
23
|
+
|
|
24
|
+
## HMAC 서명 공식
|
|
25
|
+
|
|
26
|
+
```
|
|
27
|
+
payload = METHOD|PATH|UNIX_TIMESTAMP|NONCE|BODY
|
|
28
|
+
signature = HMAC-SHA256(hmacSecret, payload) → hex
|
|
29
|
+
```
|
|
30
|
+
|
|
31
|
+
**요청 헤더:**
|
|
32
|
+
|
|
33
|
+
| 헤더 | 내용 |
|
|
34
|
+
| ------------- | -------------------------------- |
|
|
35
|
+
| `X-API-Key` | API 키 |
|
|
36
|
+
| `X-Timestamp` | 현재 Unix 타임스탬프(초) |
|
|
37
|
+
| `X-Nonce` | 요청마다 다른 랜덤 문자열 (UUID) |
|
|
38
|
+
| `X-Signature` | HMAC-SHA256 hex 서명 |
|
|
39
|
+
|
|
40
|
+
## API 엔드포인트
|
|
41
|
+
|
|
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}` |
|
|
52
|
+
|
|
53
|
+
- `list` 쿼리 파라미터: `?page=1&limit=20&order_by=<field>`
|
|
54
|
+
- `submit` — body에 `seq` 포함 시 수정, 없으면 생성
|
|
55
|
+
|
|
56
|
+
## 샘플 목록
|
|
57
|
+
|
|
58
|
+
| 디렉토리 | 프레임워크 | 인증 방식 |
|
|
59
|
+
| -------------- | ---------------------- | --------- |
|
|
60
|
+
| `php/ci4/` | CodeIgniter 4 | HMAC |
|
|
61
|
+
| `php/laravel/` | Laravel | HMAC |
|
|
62
|
+
| `java/` | Java (표준 라이브러리) | HMAC |
|
|
63
|
+
| `node/` | Node.js (fetch) | HMAC |
|
|
64
|
+
| `python/` | Python (requests) | HMAC |
|
|
65
|
+
| `react/` | React + TypeScript | JWT |
|