mega-framework 0.1.7 → 0.1.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.
Files changed (95) hide show
  1. package/README.md +9 -0
  2. package/package.json +3 -3
  3. package/sample/crud/.env +9 -0
  4. package/sample/crud/.env.example +9 -0
  5. package/sample/crud/apps/main/controllers/upload-controller.js +28 -5
  6. package/sample/crud/apps/main/locales/server/en.json +12 -1
  7. package/sample/crud/apps/main/locales/server/ko.json +12 -1
  8. package/sample/crud/apps/main/routes/upload.js +20 -1
  9. package/sample/crud/apps/main/services/guide-service.js +4 -3
  10. package/sample/crud/apps/main/services/upload-demo-service.js +6 -5
  11. package/sample/crud/apps/main/views/upload/index.ejs +4 -1
  12. package/sample/crud/docs/guide/01-cli.md +587 -0
  13. package/sample/crud/docs/guide/02-router-controller.md +497 -0
  14. package/sample/crud/docs/guide/03-service-model-db.md +929 -0
  15. package/sample/crud/docs/guide/04-websocket-asp.md +632 -0
  16. package/sample/crud/docs/guide/05-scheduler-job-worker.md +400 -0
  17. package/sample/crud/docs/guide/06-config-auth-session-security.md +495 -0
  18. package/sample/crud/docs/guide/07-view-i18n-static-multipart.md +462 -0
  19. package/sample/crud/docs/guide/08-observability.md +373 -0
  20. package/sample/crud/mega.config.js +7 -0
  21. package/sample/crud/package.json +2 -2
  22. package/sample/crud/scripts/start-ws-hub.sh +18 -4
  23. package/sample/crud/var/uploads/(/355/212/271/352/270/260/354/236/220) 2026 /353/251/264/354/240/221/354/225/210/353/202/264-mqbnwq5v-d2125aa8.txt" +1 -0
  24. package/sample/crud/var/uploads/(/355/212/271/352/270/260/354/236/220) 2026 /353/251/264/354/240/221/354/225/210/353/202/264-mqbo0nbf-842b6135.txt" +1 -0
  25. package/sample/crud/var/uploads/00_b-mqbnh7lc-c9790ab8.png +0 -0
  26. package/sample/crud/var/uploads/2025-07-22 13 35 56-mqbngvvk-e545e90e.png +0 -0
  27. package/sample/crud/var/uploads/big-file-mqbo1h9e-2957eaf5.png +0 -0
  28. package/sample/crud/var/uploads//341/204/200/341/205/247/341/206/274/341/204/200/341/205/265/341/204/211/341/205/265/341/206/257/341/204/214/341/205/245/341/206/250/341/204/214/341/205/263/341/206/274/341/204/206/341/205/247/341/206/274/341/204/211/341/205/245-mqbo5yxh-5288d8ef.pdf +0 -0
  29. package/sample/simple/node_modules/.vite/vitest/da39a3ee5e6b4b0d3255bfef95601890afd80709/results.json +1 -0
  30. package/src/adapters/adapter-options.js +14 -3
  31. package/src/adapters/file-adapter.js +9 -5
  32. package/src/adapters/file-session-adapter.js +4 -3
  33. package/src/adapters/maria-adapter.js +7 -4
  34. package/src/adapters/mega-cache-adapter.js +83 -6
  35. package/src/adapters/mega-db-adapter.js +4 -1
  36. package/src/adapters/mongo-adapter.js +21 -7
  37. package/src/adapters/postgres-adapter.js +8 -4
  38. package/src/adapters/redis-adapter.js +7 -3
  39. package/src/adapters/sqlite-adapter.js +6 -2
  40. package/src/cli/commands/console-cmd.js +3 -1
  41. package/src/cli/commands/scaffold.js +38 -2
  42. package/src/cli/generators/index.js +58 -1
  43. package/src/cli/index.js +88 -59
  44. package/src/cli/watch.js +188 -0
  45. package/src/core/ajv-mapper.js +3 -1
  46. package/src/core/ctx-builder.js +59 -1
  47. package/src/core/envelope.js +9 -2
  48. package/src/core/hub-link.js +24 -14
  49. package/src/core/index.js +1 -1
  50. package/src/core/mega-app.js +55 -45
  51. package/src/core/pipeline.js +8 -6
  52. package/src/core/scope-registry.js +1 -0
  53. package/src/core/security.js +3 -3
  54. package/src/core/session-store.js +14 -1
  55. package/src/core/ws-presence.js +17 -5
  56. package/src/core/ws-roster.js +49 -10
  57. package/src/core/ws-upgrade.js +105 -0
  58. package/src/lib/mega-circuit-breaker.js +5 -3
  59. package/src/lib/mega-health.js +10 -0
  60. package/src/lib/mega-job-queue.js +53 -13
  61. package/src/lib/mega-job.js +8 -1
  62. package/src/lib/mega-metrics.js +28 -1
  63. package/src/lib/mega-plugin.js +2 -2
  64. package/src/lib/mega-worker.js +28 -5
  65. package/src/lib/ws-hub.js +90 -9
  66. package/templates/adr/code.tpl +23 -0
  67. package/types/adapters/adapter-options.d.ts +2 -0
  68. package/types/adapters/file-adapter.d.ts +12 -1
  69. package/types/adapters/file-session-adapter.d.ts +4 -2
  70. package/types/adapters/maria-adapter.d.ts +5 -3
  71. package/types/adapters/mega-cache-adapter.d.ts +27 -1
  72. package/types/adapters/mega-db-adapter.d.ts +4 -1
  73. package/types/adapters/mongo-adapter.d.ts +13 -2
  74. package/types/adapters/postgres-adapter.d.ts +4 -2
  75. package/types/adapters/redis-adapter.d.ts +8 -0
  76. package/types/adapters/sqlite-adapter.d.ts +8 -2
  77. package/types/cli/generators/index.d.ts +11 -1
  78. package/types/cli/index.d.ts +12 -27
  79. package/types/cli/watch.d.ts +59 -0
  80. package/types/core/ctx-builder.d.ts +23 -0
  81. package/types/core/hub-link.d.ts +3 -1
  82. package/types/core/index.d.ts +1 -1
  83. package/types/core/mega-app.d.ts +1 -1
  84. package/types/core/pipeline.d.ts +2 -1
  85. package/types/core/security.d.ts +3 -3
  86. package/types/core/session-store.d.ts +7 -0
  87. package/types/core/ws-roster.d.ts +13 -1
  88. package/types/core/ws-upgrade.d.ts +29 -0
  89. package/types/lib/mega-circuit-breaker.d.ts +4 -2
  90. package/types/lib/mega-health.d.ts +7 -0
  91. package/types/lib/mega-job-queue.d.ts +16 -4
  92. package/types/lib/mega-job.d.ts +8 -1
  93. package/types/lib/mega-plugin.d.ts +1 -1
  94. package/types/lib/mega-worker.d.ts +3 -1
  95. package/types/lib/ws-hub.d.ts +27 -2
@@ -0,0 +1,587 @@
1
+ # CLI 사용법
2
+
3
+ > MEGA-FRAMEWORK 의 `mega` 명령줄 도구 사용 가이드
4
+
5
+ `mega` 는 앱 스캐폴드 · 코드 생성 · 서버 부팅 · 마이그레이션 · 라우트 점검 · 테스트 · REPL 을
6
+ 한 도구로 묶은 CLI 다. 패키지 `mega-framework` 가 두 개의 실행 파일을 제공한다.
7
+
8
+ | 실행 파일 | launcher | 본체 | 용도 |
9
+ | --- | --- | --- | --- |
10
+ | `mega` | `bin/mega.js` | `src/cli/index.js` | 앱 부팅·코드 생성·운영 명령 전체 |
11
+ | `mega-ws-hub` | `bin/mega-ws-hub.js` | `src/lib/ws-hub.js` | WebSocket Hub 독립 프로세스 |
12
+
13
+ ## 목차
14
+ - [설치 + 빠른 시작](#설치--빠른-시작)
15
+ - [`mega new` — 앱 스캐폴드](#mega-new)
16
+ - [`mega g` / `generate` — 자원 생성](#mega-g--generate)
17
+ - [`mega start` — 서버 부팅](#mega-start)
18
+ - [`mega migrate` — DB 마이그레이션](#mega-migrate)
19
+ - [`mega routes` — 라우트 목록](#mega-routes)
20
+ - [`mega test` — 테스트 실행](#mega-test)
21
+ - [`mega console` — REPL](#mega-console)
22
+ - [`mega <plugin:command>` — 플러그인 명령](#mega-plugincommand)
23
+ - [`mega-ws-hub` — WS Hub 호스트](#mega-ws-hub)
24
+ - [환경변수](#환경변수)
25
+
26
+ ---
27
+
28
+ ## 설치 + 빠른 시작
29
+
30
+ `mega` 는 보통 **프로젝트에 설치된 의존성**으로 쓴다. `mega new` 가 만들어 주는 `package.json` 은
31
+ `mega-framework` 를 의존성으로 넣고, `npm install` 하면 `node_modules/.bin/mega` 가 생긴다.
32
+ 그 뒤로는 `npm run dev` 같은 npm 스크립트나 `npx mega ...` 로 호출한다.
33
+
34
+ ```bash
35
+ # 1) 빈 폴더에 멀티앱 hello world 스캐폴드
36
+ npx mega-framework new myapp # 아직 mega 가 전역에 없을 때
37
+ # 또는 전역 설치 후: npm i -g mega-framework → mega new myapp
38
+
39
+ # 2) 의존성 설치 + 개발 서버
40
+ cd myapp
41
+ npm install
42
+ npm run dev # = mega start --watch (dev watch, 파일 변경 시 자동 재시작)
43
+ ```
44
+
45
+ `npm run dev` 는 내부에서 `mega start --watch` 를 부른다(dev watch — §`mega start` 의 `--watch` 참조). 부팅이 끝나면 다음과 같이 listen 주소를 출력한다.
46
+
47
+ ```
48
+ mega: listening on [http://main.localhost:3000]
49
+ ```
50
+
51
+ 도움말은 인자 없이, 또는 `help` / `--help` 로 본다.
52
+
53
+ ```bash
54
+ mega help # 전체 명령 표 출력 (exit 0)
55
+ mega # 같은 도움말 + exit 1 (쉘 스크립트 친화 — 명령 누락을 실패로 신호)
56
+ ```
57
+
58
+ > **참고** — `mega new` / `mega g` / `mega help` 는 프로젝트 `.env` 를 로드하지 않는다(대상
59
+ > 프로젝트가 아직 없거나 무관하기 때문). 그 외 런타임 명령(`start`/`worker`/`scheduler`/`migrate`/
60
+ > `routes`/`test`/`console`)은 config 로드 전에 프로젝트 루트의 `.env` 를 `process.env` 로 올린다
61
+ > (per ADR-152). 이미 설정된 실제 환경변수는 덮어쓰지 않는다.
62
+
63
+ 모든 명령은 `--root DIR` 로 기준 디렉토리를 바꿀 수 있다(기본: 현재 디렉토리).
64
+
65
+ ---
66
+
67
+ ## mega new
68
+
69
+ 빈 폴더에 `sample/crud` 데모앱(14기능) 전체를 스캐폴드한다 (per ADR-142/179).
70
+
71
+ ### 시그니처
72
+
73
+ ```bash
74
+ mega new <project> [--force]
75
+ ```
76
+
77
+ ### 옵션
78
+
79
+ | 옵션 | 설명 |
80
+ | --- | --- |
81
+ | `<project>` | 프로젝트 폴더 이름. `.` 이면 현재 디렉토리에 생성. |
82
+ | `--force` | 이미 존재하는 파일도 덮어씀(기본: 건너뜀). |
83
+
84
+ ### 생성 내용
85
+
86
+ 레포의 `sample/crud` 트리를 그대로 복사한다. 멀티앱(`main`) 구조 위에 14개 기능(auth·notes/users
87
+ CRUD·WS 채팅·jobs·cron·metrics·logs·perf·redis·tracing·upload·worker·guide)을 모두 갖춘 풀 데모다.
88
+
89
+ ```
90
+ myapp/
91
+ ├── mega.config.js # 전역 config (databases/caches/buses/schedules/jobs/workers)
92
+ ├── apps/main/app.config.js # main 앱 config (hosts·i18n·뷰·정적 자산)
93
+ ├── apps/main/{controllers,services,models,routes,views,...}/ # 14기능 소스
94
+ ├── apps/main/public/vendor/ # Bootstrap 5 + WASM 클라이언트(바이트 그대로 복사)
95
+ ├── apps/main/locales/ # i18next ko/en (서버·클라이언트)
96
+ ├── package.json # scripts + marked/highlight.js + concurrently/vitest
97
+ ├── README.md
98
+ ├── .env # 로컬 도커 접속 정보(그대로 동봉)
99
+ ├── .env.example
100
+ ├── .gitignore
101
+ ├── vitest.config.js
102
+ ├── ecosystem.config.cjs # PM2 프로세스 정의(server/scheduler/worker)
103
+ ├── docker-compose.yml # 로컬 인프라(postgres·redis·mongo·nats·zipkin·otel)
104
+ └── var/uploads/.gitkeep # 업로드 데모 디렉토리 placeholder
105
+ ```
106
+
107
+ 프로젝트 이름이 박힌 소수 파일(`package.json`·`README.md`·`ecosystem.config.cjs`·`.env`·`.env.example`)
108
+ 만 토큰 치환한다 — `sample-crud` → 프로젝트명, dep `mega-framework` 는 퍼블리시된 버전(`^x.y.z`)으로 핀.
109
+ 나머지 소스·정적 자산은 바이트 그대로 복사된다. 복사 제외: `node_modules`·빌드 산출물·로크파일·런타임
110
+ 로그(`*.log`)·런타임 업로드 데이터(`var/uploads/*`).
111
+
112
+ > 신규 의존성 설치(`npm install`)는 하지 않는다(네트워크 회피) — 안내만 출력한다.
113
+
114
+ ### 예시
115
+
116
+ ```bash
117
+ mega new shop # ./shop 에 풀 데모 생성
118
+ mega new . --force # 현재 폴더에 생성(기존 파일 덮어쓰기)
119
+ ```
120
+
121
+ 출력 끝에 다음 단계를 안내한다.
122
+
123
+ ```
124
+ mega: scaffolded project at /abs/path/shop
125
+ create mega.config.js
126
+ create apps/main/controllers/note-controller.js
127
+ ...
128
+ 다음 단계:
129
+ cd shop
130
+ npm install
131
+ docker compose up -d # 로컬 인프라 기동(postgres·redis·mongo·nats)
132
+ npm run migrate # DB 스키마 생성
133
+ npm run dev # 개발 서버
134
+ ```
135
+
136
+ ### 함정
137
+
138
+ - 풀 데모는 postgres·mongo·redis·nats 가 있어야 부팅된다. `docker compose up -d` 로 먼저 인프라를
139
+ 띄운 뒤 `npm run migrate` → `npm run dev` 순서로 실행한다.
140
+ - 동봉된 `.env` 는 로컬 도커 접속 정보 그대로다(시크릿 포함) — **운영 배포 전 반드시 교체**한다.
141
+ - 이미 파일이 있으면 기본은 `skip` 이다. 출력에 `skip ... (exists — use --force)` 로 표시되니
142
+ 덮어쓰려면 `--force` 를 준다.
143
+
144
+ ---
145
+
146
+ ## mega g / generate
147
+
148
+ 코드 + 테스트를 **함께** 생성한다 (per ADR-012 / ADR-142). 테스트는 `test/` 아래에 소스 경로를
149
+ 미러링한 위치에 두고, 테스트→소스 import 경로는 자동 계산한다. **이미 있는 파일은 덮어쓰지 않고
150
+ 건너뛴다**(`--force` 로만 덮어씀).
151
+
152
+ ### 시그니처
153
+
154
+ ```bash
155
+ mega g <kind> <name> [--app A] [--version vN] [--kind K] [--lng L] [--force]
156
+ mega generate <kind> <name> ... # g 는 generate 의 별칭
157
+ ```
158
+
159
+ ### 옵션
160
+
161
+ | 옵션 | 기본 | 설명 |
162
+ | --- | --- | --- |
163
+ | `--app <app>` | `main` | 대상 앱(멀티앱 인지). |
164
+ | `--version <vN>` | — | controller API 버전(예 `v2`). `v2`/`2`/`V2` 모두 `v2` 로 정규화 (per ADR-069). |
165
+ | `--kind <K>` | `db` | adapter 종류: `db` / `cache` / `bus` / `session` / `log`. |
166
+ | `--lng <L>` | `en` | locale 언어. |
167
+ | `--force` | — | 기존 파일 덮어쓰기. |
168
+
169
+ ### 13종 generator
170
+
171
+ | kind | 생성 위치(`--app main` 기준) | 비고 |
172
+ | --- | --- | --- |
173
+ | `app` | `apps/<name>/{app.config.js, routes/index.js}` + 테스트 | 새 앱 골격 |
174
+ | `controller` | `apps/main/controllers/<name>-controller.js` + 테스트 | `--version` 시 `controllers/vN/` + `routes/vN/` wiring (per ADR-069) |
175
+ | `channel` | `apps/main/channels/<name>-channel.js` + 테스트 | WebSocket 채널 |
176
+ | `service` | `apps/main/services/<name>-service.js` + 테스트 | |
177
+ | `model` | `apps/main/models/<name>.js` + 테스트 | `table` 토큰 = snake_case |
178
+ | `middleware` | `apps/main/middlewares/<name>.js` + 테스트 | |
179
+ | `route` | `apps/main/routes/<name>.js` + 테스트 | |
180
+ | `schedule` | `apps/main/schedules/<name>.js` + 테스트 | 기본 cron `0 3 * * *` |
181
+ | `job` | `apps/main/jobs/<name>.js` + 테스트 | `subject` 토큰 = name |
182
+ | `worker` | `apps/main/workers/<name>.js` + `<name>.task.js` + 테스트 | taskFile 분리 (per ADR-124) |
183
+ | `locale` | `apps/main/locales/<lng>/<name>.json` + 테스트 | `--lng` 로 언어 지정 (per ADR-039) |
184
+ | `adapter` | `shared/adapters/mega-<name>-adapter.js` + 테스트 | `--kind` 베이스 상속 (per ADR-045) |
185
+ | `migration` | `apps/main/migrations/<timestamp>-<name>.js` + 테스트 | up/down 골격 |
186
+
187
+ ### 예시
188
+
189
+ ```bash
190
+ mega g model user # apps/main/models/user.js + test
191
+ mega g controller post --version v2 # apps/main/controllers/v2/post-controller.js + routes/v2/post.js wiring
192
+ mega g service mailer --app admin # apps/admin/services/mailer-service.js + test
193
+ mega g adapter clickhouse --kind db # shared/adapters/mega-clickhouse-adapter.js (MegaDbAdapter 상속)
194
+ mega g locale common --lng ko # apps/main/locales/ko/common.json + test
195
+ mega g migration add-users-table # apps/main/migrations/20260607HHmmss-add-users-table.js
196
+ ```
197
+
198
+ 출력은 생성/건너뜀을 줄 단위로 보고한다.
199
+
200
+ ```
201
+ mega: generated model 'user'
202
+ create apps/main/models/user.js
203
+ create test/apps/main/models/user.test.js
204
+ ```
205
+
206
+ ### 함정
207
+
208
+ - **건너뛰면 exit 1** — 계획된 파일이 모두 이미 존재해 하나도 쓰지 않으면 명령은 exit code 1 을
209
+ 돌려준다. 덮어쓰려면 `--force`.
210
+ - `adapter` 의 `--kind` 는 `db`/`cache`/`bus`/`session`/`log` 중 하나여야 한다. 그 외 값은 즉시
211
+ 에러.
212
+ - `--version` 값엔 숫자가 들어 있어야 한다(`v2`, `2` OK / `vX` 는 에러).
213
+
214
+ ---
215
+
216
+ ## mega start
217
+
218
+ 앱을 부팅하고 HTTP listen 한다(별칭 `serve`). 부팅 orchestrator(`bootApp`) → 어댑터 connect →
219
+ HTTP listen → graceful 시그널 핸들러 순으로 진행한다.
220
+
221
+ ### 시그니처
222
+
223
+ ```bash
224
+ mega start [--port N] [--host H] [--cluster N|max] [--watch] [--root DIR]
225
+ mega serve ... # 별칭
226
+ ```
227
+
228
+ ### 옵션
229
+
230
+ | 옵션 | 설명 |
231
+ | --- | --- |
232
+ | `--port N` | listen 포트. 0~65535 정수. 미지정 시 server/global 설정 또는 3000. |
233
+ | `--host H` | listen 호스트. 미지정 시 config 위임. |
234
+ | `--cluster N\|max` | 워커 프로세스 수. 정수 N 또는 `max`(CPU 코어 수). `1`/미지정 = 단일 프로세스. |
235
+ | `--watch` | **dev watch** — 파일 변경 시 자동 재시작(아래 §watch). |
236
+ | `--root DIR` | 프로젝트 루트. |
237
+
238
+ ### dev watch (`--watch`) — ADR-220 (ADR-182 개정)
239
+
240
+ `mega start --watch` 는 **파일 변경 시 자동 재시작**한다(nodemon 불요 — CLI 내장 supervisor,
241
+ fs.watch + ignore 패턴 + 500ms debounce).
242
+
243
+ ```bash
244
+ mega start --watch # = sample 의 `npm run dev`
245
+ mega start --watch --watch-ignore 'data/**,seeds/**' # ignore 추가(콤마 구분 glob)
246
+ ```
247
+
248
+ - 동작: CLI(supervisor)가 자식 `mega start --cluster 1` 을 띄우고 `apps/`·`shared/`·`mega.config.js`
249
+ 를 감시한다. 변경이 ignore 를 통과하면 SIGTERM graceful 종료(어댑터 정리·포트 해제) 후 respawn.
250
+ 자식이 스스로 죽으면(crash) 재시작 폭주 대신 다음 변경을 기다린다.
251
+ - **ignore 정본 = `.env` 의 `WATCH_IGNORE`** — 숨은 코드 디폴트는 없다(개발자가 보지 못하는 목록은
252
+ 폴더명이 다른 프로젝트에서 오히려 혼란). 스캐폴드 `.env` 가 권장 목록을 실값으로 동봉한다:
253
+ `locales/`(dev 의 i18n saveMissing 자동 기입 — 안 빼면 재시작 무한 루프), `views/`(EJS 는 dev 에서
254
+ 매 요청 재컴파일), `public/`(정적 자산), `uploads/`·`var/`(사용자 업로드), `.mega/`(journal),
255
+ `.env*`(시크릿은 수동 재시작), `logs/`·`tmp/`·`node_modules/`·테스트 파일. **폴더명을 바꿨으면
256
+ `.env` 의 그 줄만 고친다.** 배선은 `mega.config.js`:
257
+ `watch: { ignore: (process.env.WATCH_IGNORE ?? '').split(',').map(s => s.trim()).filter(Boolean) }`.
258
+ - **합성**: config `watch.ignore` + CLI `--watch-ignore <globs>`(추가, 콤마 구분). **미설정이면
259
+ ignore 0** — 모든 변경이 재시작 대상이며 기동 시 경고 1줄을 낸다(런타임 쓰기 폴더가 있으면 설정 권장).
260
+ - **단일 프로세스 강제**(`--cluster 1`): 멀티워커에서 각 워커가 자기-watch 로 폭주하는 것을 막는다. dev 는 워커 1개면 충분하다(클러스터는 prod throughput 용).
261
+ - **dev 기본**: `--watch` 면 `NODE_ENV` 미설정 시 `development` 로 띄운다(뷰 캐시 off·i18n saveMissing 등 dev 분기).
262
+ - ⚠️ 멀티워커+watch 를 굳이 쓰려고 `node --watch … mega start --cluster N` 을 직접 돌려도, 코어가 워커 `execArgv` 에서 `--watch*` 를 제거해 폭주를 막는다(방어 가드).
263
+
264
+ `--port` / `--host` / `--cluster` 는 모두 **fail-closed 검증**이다 — 잘못된 값을 조용히 강등하지
265
+ 않고 부팅(어댑터 connect) **전에** 즉시 에러로 멈춘다 (per ADR-154 / ADR-168). 예를 들어 값 없는
266
+ 베어 `--port`(`mega start --port`)나 빈 값(`--port=`)은 "값 필요" 에러다. 명시적 `--port 0`(OS
267
+ 랜덤 포트)은 정상 허용한다.
268
+
269
+ ### cluster 우선순위
270
+
271
+ 워커 수는 다음 순서로 정한다 (per ADR-154).
272
+
273
+ ```
274
+ --cluster 플래그 > MEGA_CLUSTER_WORKERS env > server.cluster config
275
+ ```
276
+
277
+ - `max` / 베어 `--cluster` = CPU 코어 수(`os.availableParallelism()` → cgroup 인식).
278
+ - 해석 결과가 1 이면(설정 `1`, 또는 단일 코어의 `max`) 단일 프로세스로 본다(마스터+워커 2프로세스는
279
+ 오버헤드만 더하므로).
280
+ - 양의 정수도 `max` 도 아닌 값(0·음수·소수·임의 문자열)은 fail-closed 로 에러.
281
+
282
+ 클러스터 모드에선 마스터가 워커 N개를 fork·respawn·graceful 협응하고, 각 워커가 `bootApp` + listen
283
+ 한다. Node cluster 가 공유 listen 소켓을 워커에 분배하므로 `SO_REUSEPORT` 는 필요 없다 (per ADR-030 /
284
+ ADR-154). 마스터엔 메트릭 집계기, 워커엔 응답기가 설치된다(메트릭 옵트인 시).
285
+
286
+ ### NODE_ENV 동작
287
+
288
+ 생성된 `package.json` 의 스크립트가 `NODE_ENV` 를 명시한다(`sample/crud` 정본 패턴).
289
+
290
+ ```jsonc
291
+ // package.json scripts
292
+ "dev": "NODE_ENV=development mega start", // 개발
293
+ "start": "NODE_ENV=production mega start" // 운영(권장)
294
+ ```
295
+
296
+ 운영에선 `NODE_ENV=production` 을 권장한다.
297
+
298
+ ### 예시
299
+
300
+ ```bash
301
+ npm run dev # NODE_ENV=development mega start
302
+ NODE_ENV=production mega start # 운영 부팅
303
+ mega start --port 8080 --host 0.0.0.0 # 포트/호스트 override
304
+ mega start --cluster max # CPU 코어 수만큼 워커
305
+ MEGA_CLUSTER_WORKERS=4 mega start # env 로 워커 수
306
+ ```
307
+
308
+ 단일 프로세스면 `mega: listening on [...]`, 클러스터면 워커별
309
+ `mega: worker <pid> listening on [...]` + `mega: cluster master <pid> forked N worker(s)` 를 출력한다.
310
+
311
+ > **잡 워커 / 스케줄러** — `mega start` 와 별개로, 잡 소비 워커는 `mega worker`, 분산 스케줄러는
312
+ > `mega scheduler` 로 띄운다. 둘 다 `config.jobs`/`config.schedules`(정적) + 플러그인 등록분(동적)을
313
+ > 등록 소스로 합친다 (per ADR-123). `sample/crud` 의 `npm run worker` / `npm run scheduler` 참고.
314
+
315
+ ---
316
+
317
+ ## mega migrate
318
+
319
+ DB 마이그레이션을 일회성으로 실행한다 (per ADR-149). 워커/wsHub/메트릭은 띄우지 않고, config 로드 →
320
+ 플러그인 install → DB connect → 러너 실행 → disconnect 만 한다.
321
+
322
+ ### 시그니처
323
+
324
+ ```bash
325
+ mega migrate [--db KEY] [--root DIR] # pending 일괄 적용(up)
326
+ mega migrate:down [--db KEY] [--root DIR] # 마지막 적용분 1개 롤백(down)
327
+ mega migrate:status [--db KEY] [--root DIR] # 적용/미적용 목록 (+[!] 적용 후 수정 드리프트)
328
+ mega migrate:generate [name] [--dry-run] [--check] [--renames "old:new"] [--allow-destroy-drops]
329
+ [--concurrent] [--adapter KEY] [--app NAME]
330
+ # 모델 static schema ↔ journal diff 로 마이그레이션 자동 생성 (ADR-204/205,
331
+ # postgres — 사용법은 guide/03-service-model-db.md §5-1)
332
+ ```
333
+
334
+ ### 옵션
335
+
336
+ | 옵션 | 설명 |
337
+ | --- | --- |
338
+ | `--db KEY` | 대상 DB. `services.databases` 의 키. 미지정 규칙은 아래 참조. |
339
+ | `--root DIR` | 프로젝트 루트. |
340
+
341
+ ### `--db` 해석 규칙
342
+
343
+ `--db` 미지정 시:
344
+
345
+ 1. 선언된 db 가 **하나뿐**이면 그것을 쓴다.
346
+ 2. `primary` 키가 있으면 `primary`.
347
+ 3. 둘 다 아니면(다중 선언인데 `primary` 없음) **fail-fast** — `--db <key>` 로 명시를 요구한다.
348
+
349
+ 선언에 없는 키를 주면 선언된 키 목록과 함께 에러를 낸다.
350
+
351
+ ### 동작
352
+
353
+ ```bash
354
+ npm run migrate # = mega migrate (up)
355
+ mega migrate:status # 현재 상태 점검
356
+ mega migrate --db primary # 다중 db 일 때 대상 명시
357
+ mega migrate:down # 가장 최근 적용분 롤백
358
+ ```
359
+
360
+ 출력 예:
361
+
362
+ ```
363
+ # migrate (up)
364
+ applied 2 migration(s): 20260607...-add-users, 20260607...-add-posts
365
+ no pending migrations # 적용할 게 없을 때
366
+
367
+ # migrate:status
368
+ migrations — applied: 2, pending: 1
369
+ [x] 20260607...-add-users
370
+ [x] 20260607...-add-posts
371
+ [ ] 20260607...-add-comments
372
+
373
+ # migrate:down
374
+ rolled back: 20260607...-add-posts
375
+ nothing to roll back # 롤백할 게 없을 때
376
+ ```
377
+
378
+ > **빌트인 어댑터 자기등록** — CLI 부팅 경로는 빌트인 DB 어댑터 8종(postgres/mongodb/mariadb/
379
+ > sqlite/redis/file/nats/redlock)의 driver 자기등록을 보장한다 (per ADR-150). 사용자 코드가
380
+ > `mega-framework` 를 import 하기 전에도 `services.databases` 의 driver 가 resolve 된다.
381
+
382
+ ---
383
+
384
+ ## mega routes
385
+
386
+ 서버를 **띄우지 않고** 앱별 등록 라우트 트리를 출력한다 (per ADR-142 / ADR-167). 부팅·어댑터
387
+ connect·listen 없이 각 `apps/<name>/routes/*.js` 를 import 해 "기록용 라우터 stub" 으로
388
+ 등록 호출만 잡는다 — 운영 환경에서도 안전하다.
389
+
390
+ ### 시그니처
391
+
392
+ ```bash
393
+ mega routes [--root DIR]
394
+ ```
395
+
396
+ ### 출력 형식
397
+
398
+ 앱 이름 + 호스트 한 줄, 그 아래 `METHOD path` 들을 path → method 순으로 정렬해 출력한다.
399
+
400
+ ```
401
+ main [main.localhost]
402
+ GET /
403
+ POST /posts
404
+ GET /posts/:id
405
+ WS /live
406
+ admin [admin.localhost]
407
+ (no routes)
408
+ ```
409
+
410
+ `router.http.<method>(path)` 와 `router.ws(path)` 를 잡는다. `router.use(...)`(파일 레벨
411
+ 미들웨어)는 수집에 불필요하므로 no-op 으로 무시한다.
412
+
413
+ ### 비동기 라우트 처리
414
+
415
+ 라우트 모듈이 `export default async (router) => { ... }` 처럼 **async** 여도 끝까지 기다린다
416
+ (`await mod.default(router)`) — await 안 하면 await 경계 뒤에 등록된 라우트가 수집 전에 누락된다.
417
+ 이는 런타임 `loadRoutes` 와 동형이다 (per ADR-167). `.js` 로 끝나는 디렉토리 등 비파일은 `isFile`
418
+ 가드로 건너뛴다.
419
+
420
+ ---
421
+
422
+ ## mega test
423
+
424
+ 프로젝트가 설치한 vitest 를 `npx vitest run` 으로 실행하고 추가 인자를 그대로 넘긴다 (per ADR-142).
425
+ 별도 테스트 러너 의존성을 더하지 않는다.
426
+
427
+ ### 시그니처
428
+
429
+ ```bash
430
+ mega test [--root DIR] [-- <vitest args...>]
431
+ ```
432
+
433
+ `--` 뒤(또는 그냥 이어 붙인) 추가 인자는 vitest 로 그대로 전달된다(`allowUnknownOption`).
434
+
435
+ ### 예시
436
+
437
+ ```bash
438
+ npm test # = mega test
439
+ mega test # 전체 실행
440
+ mega test --coverage # 커버리지
441
+ mega test path/to/file.test.js # 특정 파일
442
+ mega test -t "renders home" # 이름 필터
443
+ ```
444
+
445
+ 실행 시 `mega: running vitest...` 를 출력하고, vitest 의 exit code 를 그대로 돌려준다.
446
+
447
+ ### 함정 — 시그널 종료 exit code
448
+
449
+ 자식 vitest 가 **시그널로 죽으면**(예: SIGINT, code=null) `128 + signo`(bash 관례)를 exit code 로
450
+ 돌려준다 (per ADR-167). `code ?? 0` 으로 0(성공)을 돌려주면 비정상 종료를 통과로 오판하므로 그렇게
451
+ 하지 않는다(fail-closed).
452
+
453
+ ---
454
+
455
+ ## mega console
456
+
457
+ 앱 컨텍스트를 로딩한 상태의 Node REPL 을 연다 (per ADR-142). `prepareRuntime`(config → 플러그인
458
+ install → 어댑터 connect → ctx)으로 런타임을 띄운 뒤 전역을 노출한다.
459
+
460
+ ### 시그니처
461
+
462
+ ```bash
463
+ mega console [--root DIR]
464
+ ```
465
+
466
+ ### 노출 전역
467
+
468
+ | 전역 | 내용 |
469
+ | --- | --- |
470
+ | `ctx` | 요청 무관 boot ctx(어댑터 등 배선). |
471
+ | `config` | global config. |
472
+ | `mega` | `{ config, host }`(플러그인 host 등). |
473
+
474
+ 시작 시 `mega: console ready — globals: ctx, config, mega` 를 출력하고 `mega>` 프롬프트를 띄운다.
475
+ 어댑터를 직접 만져 데이터 확인·디버깅을 할 수 있다.
476
+
477
+ ```
478
+ $ mega console
479
+ mega: console ready — globals: ctx, config, mega
480
+ mega> await ctx.db.query('select 1')
481
+ ```
482
+
483
+ ### graceful shutdown
484
+
485
+ REPL 종료(`.exit` / Ctrl-D / 이중 Ctrl-C)는 `exit` 이벤트로 잡아 graceful shutdown(어댑터
486
+ disconnect 등)을 돌린 뒤 프로세스를 닫는다 — 열린 핸들(DB 풀·redis·wsHub)로 프로세스가 행하지 않게
487
+ 한다. `SIGTERM` 은 graceful shutdown 으로 받지만, `SIGINT`(Ctrl-C)은 REPL 이 소유하므로 가로채지
488
+ 않는다 — 가로채면 한 번의 Ctrl-C 가 콘솔을 죽인다 (per ADR-167).
489
+
490
+ ---
491
+
492
+ ## mega <plugin:command>
493
+
494
+ 플러그인이 `mega.cli.command(...)` 로 등록한 CLI 명령을 dispatch 한다 (per ADR-123). config 로드 →
495
+ 플러그인 install → `host.getCommand(name)` 조회 순으로 동작하며, 어댑터 connect 는 하지 않는다(명령
496
+ 핸들러가 필요하면 자체 처리). 이름 컨벤션은 `<plugin>:<verb>` 지만 강제는 아니다.
497
+
498
+ ```bash
499
+ mega sample:ping # 플러그인 'sample' 이 등록한 'sample:ping' 명령
500
+ ```
501
+
502
+ 핸들러 반환값이 number 면 그대로 exit code 로 쓴다. 등록되지 않은 명령은
503
+ `mega: unknown command '...'` + 도움말 + exit 1.
504
+
505
+ ---
506
+
507
+ ## mega-ws-hub
508
+
509
+ WebSocket Hub 독립 프로세스를 띄운다 (per ADR-032 / ADR-033 / ADR-059). bridge(= mega 서버)들이
510
+ plaintext + Bearer 로 붙어 presence·broadcast·direct fan-out 프로토콜을 주고받는 hub 다.
511
+ **별도 실행 파일**이며 `mega` 의 서브명령이 아니다 — 설정은 모두 환경변수로 준다.
512
+
513
+ ### 시그니처
514
+
515
+ ```bash
516
+ MEGA_WSHUB_TOKENS=tok1,tok2 mega-ws-hub
517
+ ```
518
+
519
+ ### 환경변수
520
+
521
+ | env | 기본 | 설명 |
522
+ | --- | --- | --- |
523
+ | `MEGA_WSHUB_TOKENS` | **(필수)** | bridge Bearer 토큰 화이트리스트(콤마 구분). 비면 즉시 에러 (per ADR-059). |
524
+ | `MEGA_WSHUB_PORT` | `3100` | listen 포트. |
525
+ | `MEGA_WSHUB_HOST` | `0.0.0.0` | listen 호스트. |
526
+ | `MEGA_WSHUB_HEARTBEAT_MS` | `25000` | heartbeat 주기(ms). |
527
+ | `MEGA_WSHUB_MAX_PAYLOAD` | `1048576` | WS 프레임 최대 크기(bytes). 초과 시 ws 가 1009 close. |
528
+ | `MEGA_WSHUB_COMPRESSION` | off | `'true'` 면 per-message deflate 압축 ON (per ADR-078). |
529
+ | `MEGA_WSHUB_COMPRESSION_THRESHOLD` | ADR-078 기본 | 압축 ON 일 때만 적용(bytes). |
530
+
531
+ ### 예시
532
+
533
+ ```bash
534
+ MEGA_WSHUB_TOKENS=bridge-a,bridge-b \
535
+ MEGA_WSHUB_PORT=3100 \
536
+ MEGA_WSHUB_HEARTBEAT_MS=25000 \
537
+ mega-ws-hub
538
+ ```
539
+
540
+ 기동 시 `[mega:ws-hub] listening on <host>:<port> (hubId=...)` 를 출력한다. `SIGTERM`/`SIGINT`
541
+ 시 `hub.stop({ drain: true })`(bridge 소켓 4503 close + 서버 close)로 graceful 종료한다 — 독립
542
+ hub 종료는 "다른 인스턴스로 재연결" 신호다 (per ADR-098).
543
+
544
+ ### 함정
545
+
546
+ - `MEGA_WSHUB_TOKENS` 가 비거나 없으면 부팅 즉시 실패한다(`mega ws-hub: MEGA_WSHUB_TOKENS env is
547
+ required`). 토큰은 코드·로그가 아니라 `.env`/배포 시크릿으로 주입한다.
548
+
549
+ ---
550
+
551
+ ## 환경변수
552
+
553
+ CLI 동작에 직접 관여하는 핵심 env 만 아래에 정리한다. 그 외 앱 런타임 환경변수(DB/Redis/세션 등)는
554
+ **B6 환경변수 가이드** 를 참조한다.
555
+
556
+ | env | 적용 명령 | 설명 |
557
+ | --- | --- | --- |
558
+ | `NODE_ENV` | `start` 등 | `production` 권장(운영). 생성 스크립트가 `dev`=development / `start`=production 으로 명시. |
559
+ | `MEGA_CLUSTER_WORKERS` | `start` | 워커 프로세스 수. `--cluster` 플래그가 우선, 그다음 이 env, 그다음 `server.cluster` config (per ADR-154). |
560
+ | `PORT` | `start` | config(`server.port`)가 참조하는 listen 포트(`--port` 미지정 시). |
561
+ | `HOST` | `start` | config 가 참조하는 listen 호스트(`--host` 미지정 시). |
562
+ | `MEGA_WSHUB_*` | `mega-ws-hub` | [위 표](#mega-ws-hub) 참조. |
563
+
564
+ 비밀키·토큰은 코드·config·로그에 적지 않고 `.env`(또는 배포 시크릿)에만 둔다. 런타임 명령은
565
+ 프로젝트 루트의 `.env` 를 자동 로드하되 이미 설정된 실제 환경변수는 덮어쓰지 않는다 (per ADR-152).
566
+
567
+ ### CLI/부팅 시작 시간 팁 — `NODE_COMPILE_CACHE` (Node 22+)
568
+
569
+ Node 의 V8 on-disk compile cache 를 켜면 ESM 파싱/컴파일이 캐시되어 **모든 `mega` 명령의 시작
570
+ 시간이 약 10~12% 단축**된다(crud 부팅 실측 450→395ms). 코드 변경 없이 환경변수 하나로 켠다:
571
+
572
+ ```bash
573
+ # 셸 프로필 또는 배포 환경(systemd/k8s env, pm2 ecosystem env 블록 등)에 — Node 프로세스 시작
574
+ # 전에 설정돼야 하므로 .env(런타임 로드)가 아니라 실제 환경변수로 준다.
575
+ export NODE_COMPILE_CACHE="$HOME/.cache/node-compile-cache"
576
+ ```
577
+
578
+ 캐시 디렉토리는 자동 생성·관리되며(Node 공식 기능), 무효화도 Node 가 버전·파일 변경 기준으로
579
+ 처리한다. CI 처럼 일회성 실행 환경에선 이득이 없으니 켜지 않아도 된다.
580
+
581
+ ---
582
+
583
+ ## 관련 가이드
584
+
585
+ - 환경변수 전체 — B6 환경변수 가이드
586
+ - 프로젝트 구조 / config — 프레임워크 레포의 `docs/02-architecture.md`
587
+ - 결정 기록(ADR) — 프레임워크 레포의 `docs/09-decisions-and-open-questions.md` · `docs/adr/`