sonamu 0.8.24 → 0.8.26

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 (88) hide show
  1. package/dist/api/__tests__/config.test.js +189 -0
  2. package/dist/api/config.d.ts.map +1 -1
  3. package/dist/api/config.js +7 -2
  4. package/dist/api/sonamu.d.ts.map +1 -1
  5. package/dist/api/sonamu.js +14 -10
  6. package/dist/auth/index.d.ts +1 -0
  7. package/dist/auth/index.d.ts.map +1 -1
  8. package/dist/auth/index.js +2 -1
  9. package/dist/auth/knex-adapter.d.ts +23 -0
  10. package/dist/auth/knex-adapter.d.ts.map +1 -0
  11. package/dist/auth/knex-adapter.js +163 -0
  12. package/dist/auth/plugins/wrappers/admin.d.ts +2 -2
  13. package/dist/bin/__tests__/ts-loader-register.test.js +45 -0
  14. package/dist/bin/cli.js +47 -9
  15. package/dist/bin/ts-loader-register.js +3 -29
  16. package/dist/bin/ts-loader-registration.d.ts +2 -0
  17. package/dist/bin/ts-loader-registration.d.ts.map +1 -0
  18. package/dist/bin/ts-loader-registration.js +42 -0
  19. package/dist/cone/cone-generator.js +3 -3
  20. package/dist/database/puri-subset.test-d.js +9 -1
  21. package/dist/database/puri-subset.types.d.ts +1 -1
  22. package/dist/database/puri-subset.types.d.ts.map +1 -1
  23. package/dist/database/puri-subset.types.js +1 -1
  24. package/dist/testing/fixture-generator.js +5 -5
  25. package/dist/ui/ai-client.js +2 -2
  26. package/dist/ui/api.d.ts.map +1 -1
  27. package/dist/ui/api.js +14 -14
  28. package/dist/ui/cdd-service.d.ts +15 -18
  29. package/dist/ui/cdd-service.d.ts.map +1 -1
  30. package/dist/ui/cdd-service.js +246 -222
  31. package/dist/ui/cdd-types.d.ts +41 -68
  32. package/dist/ui/cdd-types.d.ts.map +1 -1
  33. package/dist/ui/cdd-types.js +2 -2
  34. package/dist/ui-web/assets/index-CKo0Z2Iu.css +1 -0
  35. package/dist/ui-web/assets/{index-CxiydzeC.js → index-DK-2aacv.js} +83 -83
  36. package/dist/ui-web/index.html +2 -2
  37. package/package.json +6 -2
  38. package/src/api/__tests__/config.test.ts +225 -0
  39. package/src/api/config.ts +10 -4
  40. package/src/api/sonamu.ts +16 -13
  41. package/src/auth/index.ts +1 -0
  42. package/src/auth/knex-adapter.ts +208 -0
  43. package/src/bin/__tests__/ts-loader-register.test.ts +62 -0
  44. package/src/bin/cli.ts +52 -9
  45. package/src/bin/ts-loader-register.ts +2 -32
  46. package/src/bin/ts-loader-registration.ts +55 -0
  47. package/src/cone/cone-generator.ts +2 -2
  48. package/src/database/puri-subset.test-d.ts +102 -0
  49. package/src/database/puri-subset.types.ts +1 -1
  50. package/src/skills/commands/sonamu-skills.md +20 -0
  51. package/src/skills/sonamu/SKILL.md +179 -137
  52. package/src/skills/sonamu/ai-agents.md +69 -69
  53. package/src/skills/sonamu/api.md +147 -147
  54. package/src/skills/sonamu/auth-migration.md +220 -220
  55. package/src/skills/sonamu/auth-plugins.md +83 -83
  56. package/src/skills/sonamu/auth.md +106 -106
  57. package/src/skills/sonamu/cdd.md +65 -200
  58. package/src/skills/sonamu/cone.md +138 -138
  59. package/src/skills/sonamu/config.md +191 -191
  60. package/src/skills/sonamu/create-sonamu.md +66 -66
  61. package/src/skills/sonamu/database.md +158 -158
  62. package/src/skills/sonamu/entity-basic.md +292 -293
  63. package/src/skills/sonamu/entity-relations.md +246 -246
  64. package/src/skills/sonamu/entity-validation-checklist.md +124 -124
  65. package/src/skills/sonamu/fixture-cli.md +231 -231
  66. package/src/skills/sonamu/framework-change.md +37 -37
  67. package/src/skills/sonamu/frontend.md +223 -223
  68. package/src/skills/sonamu/i18n.md +82 -82
  69. package/src/skills/sonamu/migration.md +77 -77
  70. package/src/skills/sonamu/model.md +222 -222
  71. package/src/skills/sonamu/naite.md +86 -86
  72. package/src/skills/sonamu/project-init.md +228 -228
  73. package/src/skills/sonamu/puri.md +122 -122
  74. package/src/skills/sonamu/scaffolding.md +154 -154
  75. package/src/skills/sonamu/skill-contribution.md +124 -124
  76. package/src/skills/sonamu/subset.md +46 -46
  77. package/src/skills/sonamu/tasks.md +82 -82
  78. package/src/skills/sonamu/testing-devrunner.md +147 -147
  79. package/src/skills/sonamu/testing.md +673 -673
  80. package/src/skills/sonamu/upsert.md +79 -79
  81. package/src/skills/sonamu/vector.md +67 -67
  82. package/src/testing/fixture-generator.ts +4 -4
  83. package/src/ui/ai-client.ts +1 -1
  84. package/src/ui/api.ts +18 -17
  85. package/src/ui/cdd-service.ts +264 -254
  86. package/src/ui/cdd-types.ts +40 -75
  87. package/dist/ui-web/assets/index-BrQKU3j9.css +0 -1
  88. package/src/skills/sonamu/workflow.md +0 -317
@@ -1,11 +1,11 @@
1
1
  ---
2
2
  name: sonamu-i18n
3
- description: Sonamu 다국어(i18n) 지원. 딕셔너리 설정, SD 함수 사용, 헬퍼 함수. Use when implementing internationalization.
3
+ description: Sonamu internationalization (i18n) support. Dictionary configuration, SD function usage, helper functions. Use when implementing internationalization.
4
4
  ---
5
5
 
6
- # i18n (다국어 지원)
6
+ # i18n (Internationalization)
7
7
 
8
- ## 설정
8
+ ## Configuration
9
9
 
10
10
  `sonamu.config.ts`:
11
11
 
@@ -19,18 +19,18 @@ export default defineConfig({
19
19
  });
20
20
  ```
21
21
 
22
- ## 파일 구조
22
+ ## File Structure
23
23
 
24
24
  ```
25
25
  packages/api/src/i18n/
26
- ├── ko.ts # 기본 locale (defaultLocale)
27
- ├── en.ts # 추가 locale
28
- └── sd.generated.ts # 자동 생성 (pnpm sync)
26
+ ├── ko.ts # Default locale (defaultLocale)
27
+ ├── en.ts # Additional locale
28
+ └── sd.generated.ts # Auto-generated (pnpm sync)
29
29
  ```
30
30
 
31
- ## 딕셔너리 파일
31
+ ## Dictionary Files
32
32
 
33
- ### 기본 locale (ko.ts)
33
+ ### Default locale (ko.ts)
34
34
 
35
35
  ```typescript
36
36
  import { createFormat, josa } from "sonamu/dict";
@@ -46,7 +46,7 @@ export default {
46
46
  } as const;
47
47
  ```
48
48
 
49
- ### 추가 locale (en.ts)
49
+ ### Additional locale (en.ts)
50
50
 
51
51
  ```typescript
52
52
  import { plural } from "sonamu/dict";
@@ -61,51 +61,51 @@ export default defineLocale({
61
61
  });
62
62
  ```
63
63
 
64
- ## SD 함수 사용
64
+ ## Using the SD Function
65
65
 
66
- ### 기본 사용
66
+ ### Basic Usage
67
67
 
68
68
  ```typescript
69
69
  import { SD } from "@/i18n/sd.generated";
70
70
 
71
- // 단순 문자열
71
+ // Simple string
72
72
  SD("common.save"); // → "저장" (ko) / "Save" (en)
73
73
 
74
- // 함수형 (파라미터)
74
+ // Function form (with parameters)
75
75
  SD("validation.required")("이메일"); // → "이메일은 필수입니다"
76
76
  SD("common.results")(5); // → "5개 결과" (ko) / "5 results" (en)
77
77
  ```
78
78
 
79
- ### 특정 locale 강제
79
+ ### Force a Specific Locale
80
80
 
81
81
  ```typescript
82
82
  const EN = SD.locale("en");
83
- EN("common.save"); // → "Save" (항상 영어)
83
+ EN("common.save"); // → "Save" (always English)
84
84
  ```
85
85
 
86
- ### Enum 라벨
86
+ ### Enum Labels
87
87
 
88
88
  ```typescript
89
- // entity.json에 정의된 enum 라벨
89
+ // Enum labels defined in entity.json
90
90
  SD.enumLabels("ProjectStatus")["in_progress"]; // → "진행중"
91
91
  ```
92
92
 
93
- ## 헬퍼 함수
93
+ ## Helper Functions
94
94
 
95
- ### plural (복수형)
95
+ ### plural (pluralization)
96
96
 
97
97
  ```typescript
98
98
  import { plural } from "sonamu/dict";
99
99
 
100
- // 영어에서 단수/복수 처리
100
+ // Handle singular/plural in English
101
101
  plural(count, {
102
102
  zero: "No items", // count === 0
103
103
  one: "1 item", // count === 1
104
- other: `${count} items`, //
104
+ other: `${count} items`, // everything else
105
105
  });
106
106
  ```
107
107
 
108
- ### josa (한국어 조사)
108
+ ### josa (Korean postposition helper)
109
109
 
110
110
  ```typescript
111
111
  import { josa } from "sonamu/dict";
@@ -117,7 +117,7 @@ josa("회사", "과와"); // → "회사와"
117
117
  josa("서울", "으로"); // → "서울로"
118
118
  ```
119
119
 
120
- ### createFormat (숫자/날짜 포맷)
120
+ ### createFormat (number/date formatting)
121
121
 
122
122
  ```typescript
123
123
  import { createFormat } from "sonamu/dict";
@@ -127,17 +127,17 @@ format.number(1234567); // → "1,234,567"
127
127
  format.date(new Date()); // → "2024. 1. 15."
128
128
  ```
129
129
 
130
- ## Entity 연동
130
+ ## Entity Integration
131
131
 
132
- Entity title, prop desc, enum label이 자동으로 딕셔너리에 포함됨.
132
+ Entity title, prop descriptions, and enum labels are automatically included in the dictionary.
133
133
 
134
134
  ```
135
- entity.{EntityId} → Entity 타이틀
136
- entity.{EntityId}.{propName} → 속성 설명
137
- enum.{EnumId}.{value} → Enum 라벨
135
+ entity.{EntityId} → Entity title
136
+ entity.{EntityId}.{propName} → Property description
137
+ enum.{EnumId}.{value} → Enum value label
138
138
  ```
139
139
 
140
- 예시:
140
+ Example:
141
141
  ```typescript
142
142
  SD("entity.User"); // → "사용자"
143
143
  SD("entity.User.email"); // → "이메일"
@@ -146,7 +146,7 @@ SD("enum.UserRole.admin"); // → "관리자"
146
146
 
147
147
  ## localizedColumn
148
148
 
149
- DB에 locale별 컬럼이 있을 현재 locale 맞는 반환:
149
+ Returns the value for the current locale when locale-specific columns exist in the DB:
150
150
 
151
151
  ```typescript
152
152
  import { localizedColumn } from "@/i18n/sd.generated";
@@ -155,98 +155,98 @@ import { localizedColumn } from "@/i18n/sd.generated";
155
155
  localizedColumn(tag, "name"); // → "태그" (ko) / "Tag" (en)
156
156
  ```
157
157
 
158
- ## Sonamu UI 관리
158
+ ## Sonamu UI Management
159
159
 
160
- `http://localhost:34900/sonamu-ui` → i18n 탭에서:
161
- - 딕셔너리 조회/수정
162
- - 추가/삭제
160
+ `http://localhost:34900/sonamu-ui` → i18n tab:
161
+ - Browse/edit dictionary
162
+ - Add/delete keys
163
163
  - Excel import/export
164
- - 미사용 검사
164
+ - Detect unused keys
165
165
 
166
- ## 네이밍 규칙
166
+ ## Key Naming Conventions
167
167
 
168
- | 패턴 | 용도 | 예시 |
169
- |------|------|------|
170
- | `common.*` | 공통 UI 텍스트 | `common.save`, `common.cancel` |
171
- | `error.*` | 에러 메시지 | `error.notFound`, `error.forbidden` |
172
- | `validation.*` | 유효성 검사 | `validation.required`, `validation.email` |
173
- | `entity.*` | Entity 관련 | `entity.User`, `entity.User.email` |
174
- | `enum.*` | Enum 라벨 | `enum.UserRole.admin` |
175
- | `menu.*` | 메뉴/네비게이션 | `menu.home`, `menu.settings` |
176
- | `rc.*` | react-components 내장 | `rc.pagination.next` |
168
+ | Pattern | Purpose | Example |
169
+ |---------|---------|---------|
170
+ | `common.*` | Common UI text | `common.save`, `common.cancel` |
171
+ | `error.*` | Error messages | `error.notFound`, `error.forbidden` |
172
+ | `validation.*` | Validation messages | `validation.required`, `validation.email` |
173
+ | `entity.*` | Entity-related | `entity.User`, `entity.User.email` |
174
+ | `enum.*` | Enum labels | `enum.UserRole.admin` |
175
+ | `menu.*` | Menu/navigation | `menu.home`, `menu.settings` |
176
+ | `rc.*` | react-components built-in | `rc.pagination.next` |
177
177
 
178
- ## 트러블슈팅
178
+ ## Troubleshooting
179
179
 
180
- ### LocalizedString 타입 오류
180
+ ### LocalizedString Type Error
181
181
 
182
- `Type 'string' is not assignable to type '{ __brand: "LocalizedString"; }'` 오류가 발생하는 경우:
182
+ When you see `Type 'string' is not assignable to type '{ __brand: "LocalizedString"; }'`:
183
183
 
184
- **원인 1: ko.ts에 i18n 누락**
184
+ **Cause 1: Missing i18n key in ko.ts**
185
185
  ```typescript
186
- // 잘못된 예: ko.ts에 키가 없으면 타입 오류
187
- SD("validation.password"); // 키가 ko.ts에 없음
186
+ // Wrong: type error when key is missing from ko.ts
187
+ SD("validation.password"); // key not in ko.ts
188
188
  ```
189
189
 
190
- 해결: ko.ts 추가 `pnpm sync`
190
+ Fix: Add the key to ko.ts and run `pnpm sync`
191
191
 
192
- **원인 2: 모델에서 SD() 미사용**
192
+ **Cause 2: Not using SD() in the model**
193
193
  ```typescript
194
- // 잘못된 예: 문자열 직접 사용
194
+ // Wrong: using a raw string directly
195
195
  throw new BadRequestException("이메일이 잘못되었습니다");
196
196
 
197
- // 올바른 예: SD() 함수 사용
197
+ // Correct: use the SD() function
198
198
  throw new BadRequestException(SD("error.invalidEmail"));
199
199
  ```
200
200
 
201
- 모든 사용자 노출 문자열은 반드시 SD() 함수로 감싸야 합니다.
201
+ All user-facing strings must be wrapped with the SD() function.
202
202
 
203
203
  ---
204
204
 
205
- ## 타입 안정성
205
+ ## Type Safety
206
206
 
207
- ### String PK 지원
207
+ ### String PK Support
208
208
 
209
- Entity String PK 사용하는 경우 i18n 함수 타입도 이를 반영해야 합니다.
209
+ When an Entity uses a String PK, the i18n function types must reflect this.
210
210
 
211
- **BAD: Number 지원**
211
+ **BAD: Number only**
212
212
  ```typescript
213
213
  // ko.ts
214
214
  notFound: (name: string, id: number) => `존재하지 않는 ${name} ID ${id}`,
215
215
 
216
- // String PK 엔티티에서 타입 오류 발생
217
- // Account, Session, User, Verification
216
+ // Type error when used with String PK entities
217
+ // Account, Session, User, Verification, etc.
218
218
  throw new NotFoundException(SD("notFound")(this.modelName, id));
219
219
  // Error: Argument of type 'string' is not assignable to parameter of type 'number'
220
220
  ```
221
221
 
222
- **GOOD: Union 타입으로 지원**
222
+ **GOOD: Support both with a union type**
223
223
  ```typescript
224
224
  // ko.ts
225
225
  notFound: (name: string, id: number | string) => `존재하지 않는 ${name} ID ${id}`,
226
226
 
227
- // Number PK, String PK 모두 사용 가능
227
+ // Works for both Number PK and String PK
228
228
  throw new NotFoundException(SD("notFound")(this.modelName, id));
229
229
  ```
230
230
 
231
- **적용 대상 i18n 키:**
232
- - `notFound`: Entity 조회 실패
233
- - `error.entityNotFound`: 구체적인 엔티티 조회 실패 (deprecated, notFound 사용 권장)
231
+ **Applicable i18n keys:**
232
+ - `notFound`: Entity lookup failure
233
+ - `error.entityNotFound`: Specific entity lookup failure (deprecated, prefer `notFound`)
234
234
 
235
- ### 네임스페이스별 타입 패턴
235
+ ### Type Patterns by Namespace
236
236
 
237
- | i18n | 파라미터 타입 | 용도 |
238
- |---------|--------------|------|
239
- | `notFound` | `(name: string, id: number \| string)` | Entity 조회 실패 |
240
- | `search.invalidField` | `(field: string)` | 잘못된 검색 필드 |
241
- | `validation.required` | `(field: string)` | 필수 필드 검증 |
242
- | `validation.maxLength` | `(field: string, max: number)` | 최대 길이 검증 |
243
- | `validation.minLength` | `(field: string, min: number)` | 최소 길이 검증 |
244
- | `entity.create` | `(name: string)` | Entity 생성 화면 |
245
- | `entity.edit` | `(name: string, id: number \| string)` | Entity 수정 화면 |
237
+ | i18n key | Parameter type | Purpose |
238
+ |---------|----------------|---------|
239
+ | `notFound` | `(name: string, id: number \| string)` | Entity lookup failure |
240
+ | `search.invalidField` | `(field: string)` | Invalid search field |
241
+ | `validation.required` | `(field: string)` | Required field validation |
242
+ | `validation.maxLength` | `(field: string, max: number)` | Max length validation |
243
+ | `validation.minLength` | `(field: string, min: number)` | Min length validation |
244
+ | `entity.create` | `(name: string)` | Entity creation screen |
245
+ | `entity.edit` | `(name: string, id: number \| string)` | Entity edit screen |
246
246
 
247
- ### PK 타입 확인 방법
247
+ ### How to Check PK Type
248
248
 
249
- Entity 파일에서 id 필드 타입을 확인:
249
+ Check the id field type in the Entity file:
250
250
 
251
251
  ```json
252
252
  // String PK
@@ -256,7 +256,7 @@ Entity 파일에서 id 필드 타입을 확인:
256
256
  }
257
257
  }
258
258
 
259
- // Number PK (기본값)
259
+ // Number PK (default)
260
260
  {
261
261
  "props": {
262
262
  "id": { "type": "int", "autoIncrement": true }
@@ -264,7 +264,7 @@ Entity 파일에서 id 필드 타입을 확인:
264
264
  }
265
265
  ```
266
266
 
267
- **KOPRI 프로젝트의 String PK 엔티티:**
267
+ **String PK entities in the KOPRI project:**
268
268
  - Account
269
269
  - Session
270
270
  - User
@@ -1,51 +1,51 @@
1
1
  ---
2
2
  name: sonamu-migration
3
- description: Sonamu 데이터베이스 마이그레이션. CREATE/ALTER TABLE, FK 순서, up/down 함수. Use when modifying database schema.
3
+ description: Sonamu database migration. CREATE/ALTER TABLE, FK ordering, up/down functions. Use when modifying database schema.
4
4
  ---
5
5
 
6
6
  # Migration
7
7
 
8
- ## CRITICAL: Migration은 Sonamu UI 또는 CLI로 생성한다
8
+ ## CRITICAL: Migrations are generated via Sonamu UI or CLI
9
9
 
10
- **Migration 파일을 직접 작성하거나 SQL을 직접 실행하지 않는다.** Sonamu entity.json 변경사항을 감지하여 정확한 migration 파일을 생성해준다.
10
+ **Do not write migration files manually or execute SQL directly.** Sonamu detects entity.json changes and generates accurate migration files.
11
11
 
12
- **사전 준비:**
13
- - `/packages/api`에서 `pnpm dev` 실행 중이어야
12
+ **Prerequisites:**
13
+ - `pnpm dev` must be running in `/packages/api`
14
14
 
15
- **방법 1: Sonamu UI (사용자에게 확인 선택)**
16
- 1. 브라우저에서 Sonamu UI 접속: `http://localhost:34900/sonamu-ui`
17
- 2. Migration 메뉴에서 prepared 리스트 확인
18
- 3. "Generate" 버튼으로 migration 파일 생성
19
- 4. "Apply" 버튼으로 실제 DB 적용
15
+ **Method 1: Sonamu UI (confirm with user before choosing)**
16
+ 1. Open Sonamu UI in browser: `http://localhost:34900/sonamu-ui`
17
+ 2. Check the prepared list in the Migration menu
18
+ 3. Generate a migration file with the "Generate" button
19
+ 4. Apply to the actual DB with the "Apply" button
20
20
 
21
- **방법 2: CLI**
21
+ **Method 2: CLI**
22
22
  ```bash
23
23
  cd packages/api
24
- pnpm sonamu migrate generate # migration 파일 생성
25
- pnpm sonamu migrate run # 실제 DB에 적용
24
+ pnpm sonamu migrate generate # Generate migration file
25
+ pnpm sonamu migrate run # Apply to actual DB
26
26
  ```
27
27
 
28
- **CRITICAL: 사용자에게 UI와 CLI 어떤 방식으로 진행할지 물어본 진행한다.**
28
+ **CRITICAL: Ask the user whether to proceed with UI or CLI before starting.**
29
29
 
30
30
  **DO NOT:**
31
- - Migration 파일을 수동으로 작성
32
- - `CREATE TABLE`, `ALTER TABLE` 등 SQL을 직접 실행
31
+ - Write migration files manually
32
+ - Execute SQL directly (`CREATE TABLE`, `ALTER TABLE`, etc.)
33
33
 
34
- **예외:** PK 타입 변경 Sonamu 자동 처리할 없는 특수 케이스만 raw SQL 허용 (아래 "PK 타입 변경" 섹션 참조)
34
+ **Exception:** Only raw SQL is allowed for special cases that Sonamu cannot handle automatically, such as PK type changes (see "PK Type Change" section below)
35
35
 
36
- **CRITICAL: Cross-table 연쇄 변경은 단일 파일로 처리한다.** FK drop → 타입 변경 → FK restore처럼 여러 테이블에 걸친 연쇄 변경은 반드시 하나의 migration 파일 안에서 순서대로 실행해야 한다. 파일을 나누면 중간 상태에서 constraint 위반이 발생한다. (상세: 아래 "PK 타입 변경" 섹션 참조)
36
+ **CRITICAL: Handle cross-table cascading changes in a single file.** Cascading changes across multiple tables — such as FK drop → type change → FK restore must be executed in order within a single migration file. Splitting into separate files causes constraint violations in intermediate states. (Details: see "PK Type Change" section below)
37
37
 
38
- ## 기본 구조
38
+ ## Basic Structure
39
39
 
40
40
  ```typescript
41
41
  import type { Knex } from "knex";
42
42
 
43
43
  export async function up(knex: Knex): Promise<void> {
44
- // 변경 적용
44
+ // Apply changes
45
45
  }
46
46
 
47
47
  export async function down(knex: Knex): Promise<void> {
48
- // 변경 롤백
48
+ // Rollback changes
49
49
  }
50
50
  ```
51
51
 
@@ -71,14 +71,14 @@ export async function down(knex: Knex): Promise<void> {
71
71
  ## ALTER TABLE
72
72
 
73
73
  ```typescript
74
- // 컬럼 추가
74
+ // Add column
75
75
  export async function up(knex: Knex): Promise<void> {
76
76
  await knex.schema.alterTable("users", (table) => {
77
77
  table.string("phone", 20).nullable();
78
78
  });
79
79
  }
80
80
 
81
- // 컬럼 삭제
81
+ // Drop column
82
82
  export async function down(knex: Knex): Promise<void> {
83
83
  await knex.schema.alterTable("users", (table) => {
84
84
  table.dropColumns("phone");
@@ -104,100 +104,100 @@ export async function down(knex: Knex): Promise<void> {
104
104
  }
105
105
  ```
106
106
 
107
- ## PK 타입 변경
107
+ ## PK Type Change
108
108
 
109
- ### 상황
110
- 기존 테이블의 PK 타입을 변경해야 하는 경우 (예: integer -> text, bigint -> uuid). 해당 PK를 참조하는 FK들이 여러 테이블에 존재하는 상황.
109
+ ### Situation
110
+ When the PK type of an existing table must be changed (e.g. integer -> text, bigint -> uuid), with FKs referencing that PK in multiple tables.
111
111
 
112
- ### 필수 순서
112
+ ### Required Order
113
113
 
114
- 참조 무결성이 있는 컬럼(FK가 참조하는 PK)의 타입을 변경할 때는 반드시 다음 순서를 따라야 함:
114
+ When changing the type of a column that has referential integrity (a PK referenced by FKs), the following order must be followed:
115
115
 
116
116
  ```typescript
117
117
  export async function up(knex: Knex): Promise<void> {
118
- // 1단계: 해당 PK를 참조하는 모든 FK constraint DROP
118
+ // Step 1: DROP all FK constraints referencing this PK
119
119
  await knex.raw('ALTER TABLE "child_table_1" DROP CONSTRAINT "child_table_1_parent_id_foreign"');
120
120
  await knex.raw('ALTER TABLE "child_table_2" DROP CONSTRAINT "child_table_2_parent_id_foreign"');
121
121
 
122
- // 2단계: PK constraint DROP
122
+ // Step 2: DROP the PK constraint
123
123
  await knex.raw('ALTER TABLE "parent_table" DROP CONSTRAINT "parent_table_pkey"');
124
124
 
125
- // 3단계: PK 컬럼과 모든 FK 컬럼의 타입을 동시에 변경
125
+ // Step 3: Change types of the PK column and all FK columns simultaneously
126
126
  await knex.raw('ALTER TABLE "parent_table" ALTER COLUMN "id" TYPE new_type USING "id"::new_type');
127
127
  await knex.raw('ALTER TABLE "child_table_1" ALTER COLUMN "parent_id" TYPE new_type USING "parent_id"::new_type');
128
128
  await knex.raw('ALTER TABLE "child_table_2" ALTER COLUMN "parent_id" TYPE new_type USING "parent_id"::new_type');
129
129
 
130
- // 4단계: PK constraint ADD
130
+ // Step 4: ADD the PK constraint
131
131
  await knex.raw('ALTER TABLE "parent_table" ADD CONSTRAINT "parent_table_pkey" PRIMARY KEY ("id")');
132
132
 
133
- // 5단계: 모든 FK constraint ADD
133
+ // Step 5: ADD all FK constraints
134
134
  await knex.raw('ALTER TABLE "child_table_1" ADD CONSTRAINT "child_table_1_parent_id_foreign" FOREIGN KEY ("parent_id") REFERENCES "parent_table"("id") ON UPDATE RESTRICT ON DELETE CASCADE');
135
135
  await knex.raw('ALTER TABLE "child_table_2" ADD CONSTRAINT "child_table_2_parent_id_foreign" FOREIGN KEY ("parent_id") REFERENCES "parent_table"("id") ON UPDATE RESTRICT ON DELETE RESTRICT');
136
136
  }
137
137
  ```
138
138
 
139
- ### 핵심 원칙
139
+ ### Core Principles
140
140
 
141
- 1. **FK constraint가 존재하는 상태에서는 참조 컬럼 타입 변경 불가**: PostgreSQL FK 참조되는 PK 타입이 일치하지 않으면 에러 발생. 반드시 constraint를 먼저 제거해야 함.
141
+ 1. **Cannot change the type of a referenced column while FK constraints exist**: PostgreSQL throws an error if the types of the FK and referenced PK do not match. Constraints must be removed first.
142
142
 
143
- 2. **하나의 migration에서 모든 변경 처리**: 여러 migration으로 나누면 중간 상태에서 constraint 위반. PK 모든 FK의 타입 변경을 번에 수행.
143
+ 2. **Handle all changes in a single migration**: Splitting into multiple migrations causes constraint violations in intermediate states. Change the types of the PK and all FKs in one go.
144
144
 
145
- 3. **knex schema builder 대신 raw SQL 사용 권장**: 명확한 실행 순서 보장, constraint 이름 명시 가능, 복잡한 타입 변환(USING) 지원.
145
+ 3. **Prefer raw SQL over the knex schema builder**: Guarantees clear execution order, allows explicit constraint naming, and supports complex type conversions (USING).
146
146
 
147
- ### 실제 예시: users.id integer -> text
147
+ ### Real Example: users.id integer -> text
148
148
 
149
149
  ```typescript
150
150
  export async function up(knex: Knex): Promise<void> {
151
- // 1. FK 제약조건 제거
151
+ // 1. Remove FK constraints
152
152
  await knex.raw('ALTER TABLE "accounts" DROP CONSTRAINT "accounts_user_id_foreign"');
153
153
  await knex.raw('ALTER TABLE "sessions" DROP CONSTRAINT "sessions_user_id_foreign"');
154
154
 
155
- // 2. PK 제약조건 제거
155
+ // 2. Remove PK constraint
156
156
  await knex.raw('ALTER TABLE "users" DROP CONSTRAINT "users_pkey"');
157
157
 
158
- // 3. 타입 변경 (USING 절로 변환 명시)
158
+ // 3. Change types (explicit conversion with USING clause)
159
159
  await knex.raw('ALTER TABLE "users" ALTER COLUMN "id" TYPE text USING "id"::text');
160
160
  await knex.raw('ALTER TABLE "accounts" ALTER COLUMN "user_id" TYPE text USING "user_id"::text');
161
161
  await knex.raw('ALTER TABLE "sessions" ALTER COLUMN "user_id" TYPE text USING "user_id"::text');
162
162
 
163
- // 4. PK 제약조건 복구
163
+ // 4. Restore PK constraint
164
164
  await knex.raw('ALTER TABLE "users" ADD CONSTRAINT "users_pkey" PRIMARY KEY ("id")');
165
165
 
166
- // 5. FK 제약조건 복구
166
+ // 5. Restore FK constraints
167
167
  await knex.raw('ALTER TABLE "accounts" ADD CONSTRAINT "accounts_user_id_foreign" FOREIGN KEY ("user_id") REFERENCES "users"("id") ON UPDATE RESTRICT ON DELETE CASCADE');
168
168
  await knex.raw('ALTER TABLE "sessions" ADD CONSTRAINT "sessions_user_id_foreign" FOREIGN KEY ("user_id") REFERENCES "users"("id") ON UPDATE RESTRICT ON DELETE CASCADE');
169
169
  }
170
170
  ```
171
171
 
172
- ### FK 참조 테이블 찾기
172
+ ### Finding FK Reference Tables
173
173
 
174
174
  ```bash
175
- # Entity에서 특정 엔티티를 참조하는 relation 찾기
175
+ # Find relations referencing a specific entity in entity files
176
176
  grep -r "with.*User" --include="*.entity.json"
177
177
  ```
178
178
 
179
- ### 흔한 실수
179
+ ### Common Mistakes
180
180
 
181
- 1. **여러 migration으로 분리**: FK drop, 타입 변경, FK restore 별도 파일로 나누면 번째 파일 apply 직후 constraint 위반. 관련 변경은 항상 단일 파일로 통합할 것.
181
+ 1. **Splitting into multiple migrations**: Separating FK drop, type change, and FK restore into separate files causes a constraint violation immediately after the first file is applied. Always consolidate related changes into a single file.
182
182
 
183
- 2. **constraint 제거 없이 타입 변경**: `cannot alter type of a column used by a foreign key` 에러 발생
183
+ 2. **Changing type without removing constraint**: Causes `cannot alter type of a column used by a foreign key` error
184
184
 
185
- 3. **USING 누락**: `column "id" cannot be cast automatically to type text` 에러 발생. integer -> text는 `USING "id"::text` 필수.
185
+ 3. **Missing USING clause**: Causes `column "id" cannot be cast automatically to type text` error. `USING "id"::text` is required for integer -> text.
186
186
 
187
- 4. **constraint 이름 불일치**: `SELECT constraint_name FROM information_schema.table_constraints WHERE table_name = 'accounts'`로 정확한 constraint 이름 확인 필요.
187
+ 4. **Constraint name mismatch**: Verify the exact constraint name with `SELECT constraint_name FROM information_schema.table_constraints WHERE table_name = 'accounts'`.
188
188
 
189
- ## 명령어
189
+ ## Commands
190
190
 
191
- **`packages/api`** 디렉토리에서 실행:
191
+ Run from the **`packages/api`** directory:
192
192
 
193
193
  ```bash
194
194
  cd packages/api
195
- pnpm sonamu migrate run # 로컬 DB에 모든 Migration 실행
196
- pnpm sonamu migrate status # 상태 확인
197
- pnpm sonamu migrate apply # 특정 DB 설정 대상으로 적용
195
+ pnpm sonamu migrate run # Run all pending migrations on local DB
196
+ pnpm sonamu migrate status # Check migration status
197
+ pnpm sonamu migrate apply # Apply to a specific DB configuration target
198
198
  ```
199
199
 
200
- **주의**: `migrate up`, `migrate rollback`은 CLI에서 제공하지 않음. Sonamu UI에서 롤백 가능.
200
+ **Note**: `migrate up` and `migrate rollback` are not provided in the CLI. Rollback is available from Sonamu UI.
201
201
 
202
202
  ## Entity Type → DB Type
203
203
 
@@ -223,13 +223,13 @@ pnpm sonamu migrate apply # 특정 DB 설정 대상으로 적용
223
223
  | `vector[]` | `vector(n)[]` | `table.specificType(name, 'vector(n)[]')` |
224
224
  | `tsvector` | `tsvector` | `table.specificType(name, 'tsvector')` |
225
225
 
226
- ## 실행 순서 (중요!)
226
+ ## Execution Order (Important!)
227
227
 
228
228
  ```
229
- 1. CREATE TABLE companies (의존성 없음)
230
- 2. CREATE TABLE departments (company_id 컬럼만)
231
- 3. CREATE TABLE users (의존성 없음)
232
- 4. CREATE TABLE employees (user_id, department_id 컬럼만)
229
+ 1. CREATE TABLE companies (no dependencies)
230
+ 2. CREATE TABLE departments (company_id column only)
231
+ 3. CREATE TABLE users (no dependencies)
232
+ 4. CREATE TABLE employees (user_id, department_id columns only)
233
233
  5. FOREIGN KEY departments (company_id → companies.id)
234
234
  6. FOREIGN KEY employees (user_id → users.id, etc.)
235
235
  ```
@@ -244,50 +244,50 @@ pnpm sonamu migrate apply # 특정 DB 설정 대상으로 적용
244
244
 
245
245
  ### 1. MUST Build dist First
246
246
 
247
- sync 명령은 `dist/sonamu.config.js`를 참조합니다. 없으면 오류 발생.
247
+ The sync command references `dist/sonamu.config.js`. An error will occur if it does not exist.
248
248
 
249
249
  ```bash
250
250
  cd packages/api
251
251
  npx swc src/sonamu.config.ts -o dist/sonamu.config.js --config-file .swcrc
252
252
  ```
253
253
 
254
- ### 2. DB 연결 확인
254
+ ### 2. Verify DB Connection
255
255
 
256
256
  ```bash
257
- # Docker 컨테이너 확인
257
+ # Check Docker containers
258
258
  docker ps | grep container
259
259
 
260
- # sonamu.config.ts에서 DB 설정 확인
260
+ # Check DB configuration in sonamu.config.ts
261
261
  # - host, port, database, user, password
262
- # - PostgreSQL vs MySQL 구분
262
+ # - Distinguish PostgreSQL vs MySQL
263
263
  ```
264
264
 
265
- ### 3. 순환 참조 시
265
+ ### 3. Circular References
266
266
 
267
- 마이그레이션을 분리하거나, FK nullable 설정 나중에 추가.
267
+ Split the migration, or set the FK to nullable and add it later.
268
268
 
269
- ## 전체 워크플로우
269
+ ## Full Workflow
270
270
 
271
271
  ```bash
272
272
  cd packages/api
273
273
 
274
- # 1. config 빌드
274
+ # 1. Build config
275
275
  npx swc src/sonamu.config.ts -o dist/sonamu.config.js --config-file .swcrc
276
276
 
277
- # 2. sync 실행
277
+ # 2. Run sync
278
278
  pnpm sonamu sync
279
279
 
280
- # 3. Sonamu UI에서 마이그레이션 생성/실행
280
+ # 3. Generate/run migration from Sonamu UI
281
281
 
282
- # 4. 스캐폴딩 실행
282
+ # 4. Run scaffolding
283
283
 
284
- # 5. model orderBy 케이스 확인/추가 (model.md 참조)
284
+ # 5. Check/add orderBy cases in model (see model.md)
285
285
 
286
- # 6. API 빌드
286
+ # 6. Build API
287
287
  npm run build
288
288
 
289
- # 7. Web form 확인/수정 (frontend.md 참조)
289
+ # 7. Check/fix web form (see frontend.md)
290
290
 
291
- # 8. Web 빌드
291
+ # 8. Build web
292
292
  cd ../web && npm run build
293
293
  ```