mega-framework 0.1.0
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/.env +127 -0
- package/.env.example +186 -0
- package/.prettierrc.json +8 -0
- package/CHANGELOG.md +259 -0
- package/LICENSE +21 -0
- package/README.md +153 -0
- package/bin/mega-ws-hub.js +15 -0
- package/bin/mega.js +38 -0
- package/docker-compose.yml +201 -0
- package/eslint.config.js +57 -0
- package/infra/otel-collector-config.yaml +43 -0
- package/jsconfig.json +18 -0
- package/package.json +121 -0
- package/sample/crud/.env +18 -0
- package/sample/crud/.env.example +50 -0
- package/sample/crud/README.md +85 -0
- package/sample/crud/apps/main/app.config.js +114 -0
- package/sample/crud/apps/main/channels/chat-bus.js +115 -0
- package/sample/crud/apps/main/channels/chat-channel.js +145 -0
- package/sample/crud/apps/main/controllers/auth-controller.js +144 -0
- package/sample/crud/apps/main/controllers/cron-controller.js +34 -0
- package/sample/crud/apps/main/controllers/guide-controller.js +37 -0
- package/sample/crud/apps/main/controllers/jobs-controller.js +43 -0
- package/sample/crud/apps/main/controllers/logs-controller.js +35 -0
- package/sample/crud/apps/main/controllers/metrics-controller.js +22 -0
- package/sample/crud/apps/main/controllers/note-controller.js +116 -0
- package/sample/crud/apps/main/controllers/perf-controller.js +38 -0
- package/sample/crud/apps/main/controllers/redis-controller.js +36 -0
- package/sample/crud/apps/main/controllers/tracing-controller.js +43 -0
- package/sample/crud/apps/main/controllers/upload-controller.js +98 -0
- package/sample/crud/apps/main/controllers/user-controller.js +34 -0
- package/sample/crud/apps/main/controllers/web-controller.js +137 -0
- package/sample/crud/apps/main/controllers/worker-controller.js +57 -0
- package/sample/crud/apps/main/controllers/ws-controller.js +29 -0
- package/sample/crud/apps/main/jobs/email-job.js +72 -0
- package/sample/crud/apps/main/locales/client/en.json +3 -0
- package/sample/crud/apps/main/locales/client/ko.json +3 -0
- package/sample/crud/apps/main/locales/server/en.json +316 -0
- package/sample/crud/apps/main/locales/server/ko.json +316 -0
- package/sample/crud/apps/main/middleware/web-auth.js +40 -0
- package/sample/crud/apps/main/middleware/ws-auth.js +48 -0
- package/sample/crud/apps/main/migrations/20260606000001-create-users.js +27 -0
- package/sample/crud/apps/main/migrations/20260606000002-add-auth-to-users.js +30 -0
- package/sample/crud/apps/main/models/note.js +71 -0
- package/sample/crud/apps/main/models/user.js +86 -0
- package/sample/crud/apps/main/public/css/app.css +101 -0
- package/sample/crud/apps/main/public/css/guide.css +137 -0
- package/sample/crud/apps/main/public/js/app.js +54 -0
- package/sample/crud/apps/main/public/js/perf.js +129 -0
- package/sample/crud/apps/main/public/js/theme-init.js +12 -0
- package/sample/crud/apps/main/public/js/upload-demo.js +63 -0
- package/sample/crud/apps/main/public/js/worker-demo.js +92 -0
- package/sample/crud/apps/main/public/js/ws-chat.js +161 -0
- package/sample/crud/apps/main/public/vendor/bootstrap/bootstrap.bundle.min.js +7 -0
- package/sample/crud/apps/main/public/vendor/bootstrap/bootstrap.min.css +6 -0
- package/sample/crud/apps/main/public/vendor/highlight/github-dark.css +109 -0
- package/sample/crud/apps/main/public/vendor/highlight/github.css +118 -0
- package/sample/crud/apps/main/public/vendor/mega-client-wasm/README.md +19 -0
- package/sample/crud/apps/main/public/vendor/mega-client-wasm/mega_client_wasm.d.ts +196 -0
- package/sample/crud/apps/main/public/vendor/mega-client-wasm/mega_client_wasm.js +1187 -0
- package/sample/crud/apps/main/public/vendor/mega-client-wasm/mega_client_wasm_bg.wasm +0 -0
- package/sample/crud/apps/main/routes/auth.js +15 -0
- package/sample/crud/apps/main/routes/cron.js +14 -0
- package/sample/crud/apps/main/routes/guide.js +25 -0
- package/sample/crud/apps/main/routes/jobs.js +14 -0
- package/sample/crud/apps/main/routes/logs.js +28 -0
- package/sample/crud/apps/main/routes/metrics.js +13 -0
- package/sample/crud/apps/main/routes/notes.js +19 -0
- package/sample/crud/apps/main/routes/perf.js +47 -0
- package/sample/crud/apps/main/routes/redis.js +14 -0
- package/sample/crud/apps/main/routes/tracing.js +14 -0
- package/sample/crud/apps/main/routes/upload.js +16 -0
- package/sample/crud/apps/main/routes/users.js +54 -0
- package/sample/crud/apps/main/routes/web.js +23 -0
- package/sample/crud/apps/main/routes/worker.js +15 -0
- package/sample/crud/apps/main/routes/ws.js +30 -0
- package/sample/crud/apps/main/schedules/cron-counter-schedule.js +30 -0
- package/sample/crud/apps/main/services/auth-service.js +74 -0
- package/sample/crud/apps/main/services/cron-demo-service.js +66 -0
- package/sample/crud/apps/main/services/guide-service.js +145 -0
- package/sample/crud/apps/main/services/jobs-demo-service.js +83 -0
- package/sample/crud/apps/main/services/logs-demo-service.js +59 -0
- package/sample/crud/apps/main/services/metrics-demo-service.js +144 -0
- package/sample/crud/apps/main/services/note-service.js +75 -0
- package/sample/crud/apps/main/services/perf-service.js +302 -0
- package/sample/crud/apps/main/services/redis-demo-service.js +75 -0
- package/sample/crud/apps/main/services/tracing-demo-service.js +69 -0
- package/sample/crud/apps/main/services/upload-demo-service.js +48 -0
- package/sample/crud/apps/main/services/user-service.js +65 -0
- package/sample/crud/apps/main/views/auth/login.ejs +57 -0
- package/sample/crud/apps/main/views/auth/register.ejs +71 -0
- package/sample/crud/apps/main/views/cron/index.ejs +92 -0
- package/sample/crud/apps/main/views/guide/index.ejs +24 -0
- package/sample/crud/apps/main/views/guide/page.ejs +64 -0
- package/sample/crud/apps/main/views/home.ejs +82 -0
- package/sample/crud/apps/main/views/jobs/index.ejs +113 -0
- package/sample/crud/apps/main/views/layouts/main.ejs +112 -0
- package/sample/crud/apps/main/views/logs/index.ejs +80 -0
- package/sample/crud/apps/main/views/metrics/index.ejs +123 -0
- package/sample/crud/apps/main/views/notes/edit.ejs +45 -0
- package/sample/crud/apps/main/views/notes/list.ejs +74 -0
- package/sample/crud/apps/main/views/notes/new.ejs +45 -0
- package/sample/crud/apps/main/views/perf/index.ejs +90 -0
- package/sample/crud/apps/main/views/redis/index.ejs +65 -0
- package/sample/crud/apps/main/views/tracing/index.ejs +106 -0
- package/sample/crud/apps/main/views/upload/index.ejs +79 -0
- package/sample/crud/apps/main/views/users/edit.ejs +48 -0
- package/sample/crud/apps/main/views/users/list.ejs +81 -0
- package/sample/crud/apps/main/views/users/new.ejs +48 -0
- package/sample/crud/apps/main/views/worker/index.ejs +70 -0
- package/sample/crud/apps/main/views/ws/index.ejs +62 -0
- package/sample/crud/apps/main/workers/hash-worker.js +17 -0
- package/sample/crud/apps/main/workers/hash.task.js +22 -0
- package/sample/crud/ecosystem.config.cjs +9 -0
- package/sample/crud/mega.config.js +105 -0
- package/sample/crud/package-lock.json +5665 -0
- package/sample/crud/package.json +28 -0
- package/sample/crud/test/apps/main/auth-flow.integration.test.js +177 -0
- package/sample/crud/test/apps/main/auth-service.test.js +93 -0
- package/sample/crud/test/apps/main/chat-bus.test.js +101 -0
- package/sample/crud/test/apps/main/chat-channel.test.js +144 -0
- package/sample/crud/test/apps/main/cron-demo-service.test.js +93 -0
- package/sample/crud/test/apps/main/demo-flow.integration.test.js +386 -0
- package/sample/crud/test/apps/main/email-job.test.js +76 -0
- package/sample/crud/test/apps/main/guide-service.test.js +68 -0
- package/sample/crud/test/apps/main/hash-task.test.js +30 -0
- package/sample/crud/test/apps/main/jobs-demo-service.test.js +88 -0
- package/sample/crud/test/apps/main/logs-demo-service.test.js +85 -0
- package/sample/crud/test/apps/main/metrics-demo-service.test.js +90 -0
- package/sample/crud/test/apps/main/note-service.test.js +68 -0
- package/sample/crud/test/apps/main/perf-service.test.js +121 -0
- package/sample/crud/test/apps/main/perf.integration.test.js +202 -0
- package/sample/crud/test/apps/main/redis-demo-service.test.js +98 -0
- package/sample/crud/test/apps/main/tracing-demo-service.test.js +90 -0
- package/sample/crud/test/apps/main/upload-demo-service.test.js +61 -0
- package/sample/crud/test/apps/main/user-service.test.js +65 -0
- package/sample/crud/test/apps/main/ws-chat.integration.test.js +232 -0
- package/sample/crud/vitest.config.js +8 -0
- package/sample/crud/yarn.lock +2142 -0
- package/sample/simple/.env.example +15 -0
- package/sample/simple/README.md +52 -0
- package/sample/simple/apps/main/app.config.js +35 -0
- package/sample/simple/apps/main/controllers/pages-controller.js +22 -0
- package/sample/simple/apps/main/locales/client/en.json +3 -0
- package/sample/simple/apps/main/locales/client/ko.json +3 -0
- package/sample/simple/apps/main/locales/server/en.json +23 -0
- package/sample/simple/apps/main/locales/server/ko.json +23 -0
- package/sample/simple/apps/main/public/css/app.css +101 -0
- package/sample/simple/apps/main/public/hello.txt +1 -0
- package/sample/simple/apps/main/public/js/app.js +54 -0
- package/sample/simple/apps/main/public/js/theme-init.js +12 -0
- package/sample/simple/apps/main/public/vendor/bootstrap/bootstrap.bundle.min.js +7 -0
- package/sample/simple/apps/main/public/vendor/bootstrap/bootstrap.min.css +6 -0
- package/sample/simple/apps/main/routes/index.js +9 -0
- package/sample/simple/apps/main/routes/pages.js +12 -0
- package/sample/simple/apps/main/views/index.ejs +56 -0
- package/sample/simple/apps/main/views/layouts/main.ejs +74 -0
- package/sample/simple/ecosystem.config.cjs +10 -0
- package/sample/simple/mega.config.js +27 -0
- package/sample/simple/package-lock.json +1851 -0
- package/sample/simple/package.json +25 -0
- package/sample/simple/test/apps/main/index.test.js +13 -0
- package/sample/simple/vitest.config.js +8 -0
- package/src/adapters/adapter-manager.js +305 -0
- package/src/adapters/adapter-options.js +208 -0
- package/src/adapters/file-adapter.js +350 -0
- package/src/adapters/file-session-adapter.js +363 -0
- package/src/adapters/index.js +38 -0
- package/src/adapters/maria-adapter.js +425 -0
- package/src/adapters/mega-adapter.js +511 -0
- package/src/adapters/mega-bus-adapter.js +81 -0
- package/src/adapters/mega-cache-adapter.js +94 -0
- package/src/adapters/mega-db-adapter.js +72 -0
- package/src/adapters/mega-lock-adapter.js +118 -0
- package/src/adapters/mega-log-sink-adapter.js +46 -0
- package/src/adapters/mega-session-adapter.js +72 -0
- package/src/adapters/mongo-adapter.js +396 -0
- package/src/adapters/nats-adapter.js +370 -0
- package/src/adapters/postgres-adapter.js +341 -0
- package/src/adapters/redis-adapter.js +331 -0
- package/src/adapters/redis-session-adapter.js +261 -0
- package/src/adapters/redlock-adapter.js +385 -0
- package/src/adapters/registry.js +157 -0
- package/src/adapters/sqlite-adapter.js +309 -0
- package/src/auth/index.js +103 -0
- package/src/cli/commands/console-cmd.js +56 -0
- package/src/cli/commands/new.js +101 -0
- package/src/cli/commands/routes.js +107 -0
- package/src/cli/commands/scaffold.js +120 -0
- package/src/cli/commands/test-cmd.js +45 -0
- package/src/cli/generators/index.js +368 -0
- package/src/cli/index.js +472 -0
- package/src/cli/template-engine.js +72 -0
- package/src/cli/ws-hub.js +582 -0
- package/src/core/ajv-mapper.js +80 -0
- package/src/core/boot.js +323 -0
- package/src/core/cluster-metrics.js +278 -0
- package/src/core/config-loader.js +115 -0
- package/src/core/config-validator.js +322 -0
- package/src/core/ctx-builder.js +253 -0
- package/src/core/envelope.js +88 -0
- package/src/core/error-mapper.js +116 -0
- package/src/core/formbody.js +69 -0
- package/src/core/hub-link.js +552 -0
- package/src/core/i18n.js +525 -0
- package/src/core/index.js +63 -0
- package/src/core/mega-app.js +1138 -0
- package/src/core/mega-cluster.js +232 -0
- package/src/core/mega-server.js +176 -0
- package/src/core/mega-service.js +41 -0
- package/src/core/migration-runner.js +196 -0
- package/src/core/multipart.js +282 -0
- package/src/core/openapi.js +114 -0
- package/src/core/router.js +388 -0
- package/src/core/routes-loader.js +57 -0
- package/src/core/scope-registry.js +53 -0
- package/src/core/security.js +275 -0
- package/src/core/services-loader.js +98 -0
- package/src/core/session-cleanup-schedule.js +57 -0
- package/src/core/session-store.js +55 -0
- package/src/core/session.js +414 -0
- package/src/core/static-assets.js +126 -0
- package/src/core/template.js +294 -0
- package/src/core/workers-manager.js +193 -0
- package/src/core/ws-compression.js +112 -0
- package/src/core/ws-controller.js +109 -0
- package/src/core/ws-message.js +176 -0
- package/src/core/ws-upgrade.js +445 -0
- package/src/errors/config-error.js +16 -0
- package/src/errors/http-errors.js +130 -0
- package/src/errors/index.js +19 -0
- package/src/errors/mega-error.js +34 -0
- package/src/eslint-plugin/index.js +15 -0
- package/src/eslint-plugin/no-direct-model-import.js +113 -0
- package/src/index.js +131 -0
- package/src/lib/asp/config.js +83 -0
- package/src/lib/asp/crypto.js +145 -0
- package/src/lib/asp/errors.js +49 -0
- package/src/lib/asp/nonce-cache.js +94 -0
- package/src/lib/asp/plugin.js +263 -0
- package/src/lib/asp/ws-terminator.js +101 -0
- package/src/lib/env-mapper.js +222 -0
- package/src/lib/hub-protocol.js +322 -0
- package/src/lib/index.js +42 -0
- package/src/lib/logger/telegram-core.js +150 -0
- package/src/lib/logger/telegram-transport.js +126 -0
- package/src/lib/mega-brute-force.js +225 -0
- package/src/lib/mega-circuit-breaker.js +412 -0
- package/src/lib/mega-cron.js +169 -0
- package/src/lib/mega-hash.js +179 -0
- package/src/lib/mega-health.js +91 -0
- package/src/lib/mega-job-queue.js +600 -0
- package/src/lib/mega-job-worker.js +295 -0
- package/src/lib/mega-job.js +140 -0
- package/src/lib/mega-logger.js +128 -0
- package/src/lib/mega-metrics.js +661 -0
- package/src/lib/mega-plugin.js +650 -0
- package/src/lib/mega-retry.js +95 -0
- package/src/lib/mega-schedule.js +507 -0
- package/src/lib/mega-shutdown.js +176 -0
- package/src/lib/mega-tracing.js +715 -0
- package/src/lib/mega-worker.js +653 -0
- package/src/lib/worker-runner/process-entry.js +30 -0
- package/src/lib/worker-runner/task-dispatch.js +72 -0
- package/src/lib/worker-runner/thread-entry.js +26 -0
- package/src/models/index.js +7 -0
- package/src/models/mega-model.js +151 -0
- package/src/test/index.js +288 -0
- package/templates/adapter/code.tpl +40 -0
- package/templates/adapter/test.tpl +13 -0
- package/templates/app/app.config.tpl +10 -0
- package/templates/app/route.tpl +10 -0
- package/templates/app/test.tpl +13 -0
- package/templates/channel/code.tpl +38 -0
- package/templates/channel/test.tpl +19 -0
- package/templates/controller/code.tpl +16 -0
- package/templates/controller/route.tpl +9 -0
- package/templates/controller/test.tpl +14 -0
- package/templates/job/code.tpl +23 -0
- package/templates/job/test.tpl +17 -0
- package/templates/locale/code.tpl +3 -0
- package/templates/locale/test.tpl +13 -0
- package/templates/middleware/code.tpl +13 -0
- package/templates/middleware/test.tpl +11 -0
- package/templates/migration/code.tpl +20 -0
- package/templates/migration/test.tpl +14 -0
- package/templates/model/code.tpl +21 -0
- package/templates/model/test.tpl +29 -0
- package/templates/project/app.config.tpl +8 -0
- package/templates/project/app.config.views.tpl +37 -0
- package/templates/project/ecosystem.config.tpl +10 -0
- package/templates/project/env.tpl +12 -0
- package/templates/project/gitignore.tpl +8 -0
- package/templates/project/locales/client/en.json.tpl +3 -0
- package/templates/project/locales/client/ko.json.tpl +3 -0
- package/templates/project/locales/server/en.json.tpl +17 -0
- package/templates/project/locales/server/ko.json.tpl +17 -0
- package/templates/project/mega.config.tpl +11 -0
- package/templates/project/package.tpl +25 -0
- package/templates/project/public/css/app.css +101 -0
- package/templates/project/public/js/app.js +54 -0
- package/templates/project/public/js/theme-init.js +12 -0
- package/templates/project/public/vendor/bootstrap/bootstrap.bundle.min.js +7 -0
- package/templates/project/public/vendor/bootstrap/bootstrap.min.css +6 -0
- package/templates/project/readme.tpl +48 -0
- package/templates/project/route.test.tpl +13 -0
- package/templates/project/route.test.views.tpl +15 -0
- package/templates/project/route.tpl +10 -0
- package/templates/project/route.views.tpl +10 -0
- package/templates/project/views/index.ejs.tpl +58 -0
- package/templates/project/views/layout.ejs.tpl +73 -0
- package/templates/project/vitest.config.tpl +8 -0
- package/templates/route/code.tpl +11 -0
- package/templates/route/test.tpl +26 -0
- package/templates/schedule/code.tpl +19 -0
- package/templates/schedule/test.tpl +17 -0
- package/templates/service/code.tpl +18 -0
- package/templates/service/test.tpl +17 -0
- package/templates/worker/code.tpl +14 -0
- package/templates/worker/task.tpl +13 -0
- package/templates/worker/test.tpl +18 -0
- package/vitest.config.js +33 -0
package/LICENSE
ADDED
|
@@ -0,0 +1,21 @@
|
|
|
1
|
+
MIT License
|
|
2
|
+
|
|
3
|
+
Copyright (c) 2026 Henry Chu
|
|
4
|
+
|
|
5
|
+
Permission is hereby granted, free of charge, to any person obtaining a copy
|
|
6
|
+
of this software and associated documentation files (the "Software"), to deal
|
|
7
|
+
in the Software without restriction, including without limitation the rights
|
|
8
|
+
to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
|
|
9
|
+
copies of the Software, and to permit persons to whom the Software is
|
|
10
|
+
furnished to do so, subject to the following conditions:
|
|
11
|
+
|
|
12
|
+
The above copyright notice and this permission notice shall be included in all
|
|
13
|
+
copies or substantial portions of the Software.
|
|
14
|
+
|
|
15
|
+
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
|
|
16
|
+
IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
|
|
17
|
+
FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
|
|
18
|
+
AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
|
|
19
|
+
LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
|
|
20
|
+
OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
|
|
21
|
+
SOFTWARE.
|
package/README.md
ADDED
|
@@ -0,0 +1,153 @@
|
|
|
1
|
+
# MEGA-FRAMEWORK
|
|
2
|
+
|
|
3
|
+
Node.js 마이크로프레임웍 + CLI. **Slim** 의 가벼움(import 한 줄로 시작)과 **Ruby on Rails** 의
|
|
4
|
+
convention-over-configuration(네이밍·구조·사용법을 코어가 정함) 철학을 합친 프레임워크.
|
|
5
|
+
HTTP·WebSocket 을 동급 일급으로 다루고, 데이터 어댑터·잡/스케줄러·트레이싱·보안·세션·i18n·SSR 을
|
|
6
|
+
검증된 라이브러리 위에 얇게 래핑한다.
|
|
7
|
+
|
|
8
|
+
## 상태
|
|
9
|
+
|
|
10
|
+
**Phase 1~6 완료.** (version `0.1.0`)
|
|
11
|
+
|
|
12
|
+
- Phase 1 코어 골격 · Phase 2 WebSocket+Hub · Phase 3 데이터 어댑터+트레이싱 · Phase 4 잡/스케줄러/워커 ·
|
|
13
|
+
Phase 5 SSR+세션+보안+i18n 전부 완료.
|
|
14
|
+
- Phase 6(CLI 스캐폴드 + 안정화 + 0.1.0): 이월 부채 2건 청산 완료(wsHub embedded ADR-137, native query span ADR-138).
|
|
15
|
+
**CLI 스캐폴드 본체 구현 완료** — `mega new` / `mega g <type>` 제너레이터(`src/cli/generators/index.js`) / `mega routes·test·console`(`src/cli/commands/`) 전부 배선됨(`src/cli/index.js`) — [05-roadmap §Phase 6](./docs/05-roadmap.md).
|
|
16
|
+
- 검증: `npm test` **1510 그린 / 3 skip**(mongo RS 트랜잭션은 standalone 의도 skip, ADR-108), typecheck 0, lint 0, prod audit 0.
|
|
17
|
+
|
|
18
|
+
## 핵심 기능
|
|
19
|
+
|
|
20
|
+
| 영역 | 제공 |
|
|
21
|
+
|---|---|
|
|
22
|
+
| **HTTP** | `MegaApp`(Fastify v5 래퍼) · `MegaServer`(멀티앱 vhost 라우팅) · 단일 시그니처 `router.http.<method>(path, handler, opts?)` · 라우트 자동 로드 · 자동 envelope(`{ok, data\|error, meta}`) · AJV 검증 에러 → `details` 자동 매핑 |
|
|
23
|
+
| **WebSocket** | `MegaWebSocketController`(타입 자동 디스패치) · Bridge↔Hub 12-타입 프로토콜 · presence · `broadcast`/`directToUser` fan-out · per-message deflate 압축 · embedded/별도 프로세스 hub |
|
|
24
|
+
| **데이터** | `MegaModel`(ORM 없음, native API + 트랜잭션) · 어댑터 베이스 트리(Db/Cache/Bus/Lock/Session) · 드라이버: Postgres·MariaDB·SQLite·MongoDB·Redis·NATS·File · `MegaRedlockAdapter`(분산 락) |
|
|
25
|
+
| **운영(잡/스케줄)** | `MegaJobQueue`(NATS JetStream + 재시도 + DLQ) · `MegaJobWorker` · `MegaScheduler`(croner + 분산 중복방지) · `MegaWorker`(worker_threads CPU 풀) |
|
|
26
|
+
| **복원력** | `MegaRetry`(p-retry 지수 백오프) · `MegaCircuitBreaker`(opossum) · `MegaHealth`(`/health`·`/health/ready`) · `MegaShutdown`(LIFO graceful) |
|
|
27
|
+
| **관측성** | `MegaTracing`(OpenTelemetry 옵트인, HTTP/WS/어댑터/native query 자동 span, Zipkin) · `MegaMetrics`(Prometheus `/metrics`) |
|
|
28
|
+
| **보안** | helmet·CORS·rate-limit·CSRF 자동 등록 · `MegaHash`(scrypt) · `MegaBruteForce` · ASP 종단 암호화(HTTP/WS) · 파일 업로드 MIME 화이트리스트 + path traversal 방어 |
|
|
29
|
+
| **세션·인증** | `MegaSessionAdapter`(file/redis) · ULID sid · 쿠키 HMAC · rolling TTL · CSRF 세션 모드 |
|
|
30
|
+
| **SSR·i18n** | `MegaTemplate`(EJS + ejs-mate, XSS auto-escape) · `registerI18n`(i18next, 쿠키 locale, 에러코드↔locale 자동 번역) |
|
|
31
|
+
| **확장** | `MegaPluginHost`(install 패턴 + apiVersion 호환 강제) · CLI 명령 등록 |
|
|
32
|
+
|
|
33
|
+
## 빠른 시작
|
|
34
|
+
|
|
35
|
+
```bash
|
|
36
|
+
npm install
|
|
37
|
+
npm run infra:up # docker 인프라 가동(postgres/maria/mongo/redis/nats/otel/zipkin) — 통합 테스트용
|
|
38
|
+
npm test # 전체 테스트(실 인프라). .env 자동 로드(ADR-128)
|
|
39
|
+
npm run infra:down # 인프라 종료
|
|
40
|
+
```
|
|
41
|
+
|
|
42
|
+
프로젝트 루트에 `mega.config.js`(글로벌) + 앱별 `apps/<name>/app.config.js` 를 둔다.
|
|
43
|
+
|
|
44
|
+
```js
|
|
45
|
+
// mega.config.js — 글로벌 설정(활성 앱·서비스·플러그인)
|
|
46
|
+
export default {
|
|
47
|
+
apps: ['main'],
|
|
48
|
+
services: {
|
|
49
|
+
databases: {
|
|
50
|
+
maindb: { driver: 'postgres', url: process.env.MEGA_PG_URL },
|
|
51
|
+
},
|
|
52
|
+
},
|
|
53
|
+
plugins: [],
|
|
54
|
+
}
|
|
55
|
+
```
|
|
56
|
+
|
|
57
|
+
```js
|
|
58
|
+
// apps/main/app.config.js — 앱 단위 설정(호스트·DB 별명 참조)
|
|
59
|
+
export default {
|
|
60
|
+
name: 'main',
|
|
61
|
+
hosts: ['main.localhost'],
|
|
62
|
+
databases: { db: 'maindb' }, // services.databases.maindb 를 ctx.db('db') 로 참조
|
|
63
|
+
}
|
|
64
|
+
```
|
|
65
|
+
|
|
66
|
+
```js
|
|
67
|
+
// apps/main/routes/ping.js — 자동 로드되는 라우트(함수 default export)
|
|
68
|
+
export default (router) => {
|
|
69
|
+
// 반환값은 자동으로 envelope 으로 감싸진다.
|
|
70
|
+
router.http.get('/api/ping', async () => ({ pong: true }))
|
|
71
|
+
router.http.get('/api/who', async (req, reply, ctx) => ({
|
|
72
|
+
driver: await ctx.db('db').ping(),
|
|
73
|
+
}))
|
|
74
|
+
}
|
|
75
|
+
```
|
|
76
|
+
|
|
77
|
+
```bash
|
|
78
|
+
mega start --port 3000 # 앱 부팅 + HTTP listen
|
|
79
|
+
# → main.localhost:3000/api/ping → { "ok": true, "data": { "pong": true }, "meta": {...} }
|
|
80
|
+
```
|
|
81
|
+
|
|
82
|
+
## CLI
|
|
83
|
+
|
|
84
|
+
```
|
|
85
|
+
mega start [--port N] [--host H] [--root DIR] 앱 부팅 + HTTP listen (별칭: serve)
|
|
86
|
+
mega worker [--root DIR] 잡 소비 워커 런타임 호스트
|
|
87
|
+
mega scheduler [--root DIR] 분산 스케줄러 호스트
|
|
88
|
+
mega migrate [--db KEY] DB 마이그레이션 적용(up, ADR-149)
|
|
89
|
+
mega migrate:down [--db KEY] 마이그레이션 롤백(down)
|
|
90
|
+
mega migrate:status [--db KEY] 마이그레이션 적용 상태 출력
|
|
91
|
+
mega new <project> [--views] [--force] 멀티앱 hello world 스캐폴드
|
|
92
|
+
mega generate <kind> <name> [--app A] 코드+테스트 제너레이터 (별칭: g)
|
|
93
|
+
mega routes 등록된 라우트 트리 출력
|
|
94
|
+
mega test [args...] vitest 실행(인자 그대로 전달)
|
|
95
|
+
mega console 앱 컨텍스트 로딩 REPL
|
|
96
|
+
mega <plugin:command> [args...] 플러그인이 등록한 CLI 명령 실행
|
|
97
|
+
mega help 도움말
|
|
98
|
+
mega-ws-hub WebSocket Hub 독립 프로세스(MEGA_WSHUB_* 환경변수)
|
|
99
|
+
```
|
|
100
|
+
|
|
101
|
+
## 디렉토리 구조
|
|
102
|
+
|
|
103
|
+
```
|
|
104
|
+
src/
|
|
105
|
+
├── core/ HTTP 서버 + WS + 부팅 orchestrator(MegaApp/MegaServer/Router/boot/security/session/i18n/template)
|
|
106
|
+
├── lib/ 코어 라이브러리(스케줄·잡·워커·플러그인·트레이싱·메트릭·재시도·서킷·헬스·해시) + asp/(종단 암호화)
|
|
107
|
+
├── adapters/ 어댑터 베이스 트리 + 구체 드라이버(postgres/maria/sqlite/mongo/redis/nats/file/redlock/session)
|
|
108
|
+
├── models/ MegaModel 데이터 모델 베이스(ORM 없음)
|
|
109
|
+
├── middleware/ (예약)
|
|
110
|
+
├── errors/ MegaError 계층(config/route/http/validation/auth/...)
|
|
111
|
+
├── cli/ CLI 디스패처 + WS Hub
|
|
112
|
+
├── eslint-plugin/ 커스텀 룰(라우트에서 모델 직접 import 차단)
|
|
113
|
+
└── index.js 공개 entry point
|
|
114
|
+
|
|
115
|
+
bin/ mega.js(CLI) · mega-ws-hub.js(Hub 런처)
|
|
116
|
+
packages/ mega-client-wasm(Rust/WASM ASP 클라이언트)
|
|
117
|
+
docs/ 설계·ADR·운영 문서
|
|
118
|
+
```
|
|
119
|
+
|
|
120
|
+
## 의존성
|
|
121
|
+
|
|
122
|
+
- **런타임**: Node.js `>=20` (engines)
|
|
123
|
+
- **HTTP/WS**: `fastify` v5 + `@fastify/*`(cookie/cors/csrf/helmet/multipart/rate-limit) · `ws`
|
|
124
|
+
- **데이터**: `pg` · `mariadb` · `mongodb` · `better-sqlite3` · `ioredis` · `nats` · `redlock`
|
|
125
|
+
- **복원력·운영**: `p-retry` · `opossum` · `croner`
|
|
126
|
+
- **관측성**: `@opentelemetry/*`(api/sdk-trace/sdk-metrics/exporter-zipkin/exporter-prometheus/exporter-otlp)
|
|
127
|
+
- **SSR·i18n·검증**: `ejs` + `ejs-mate` · `i18next` · `ajv`
|
|
128
|
+
|
|
129
|
+
> 모든 신규 의존성은 [docs/09](./docs/09-decisions-and-open-questions.md) 에 ADR 로 1줄 기록(P8). 커스텀 구현은 Node 빌트인만 사용(scrypt/HMAC/cluster/worker_threads).
|
|
130
|
+
|
|
131
|
+
## 문서
|
|
132
|
+
|
|
133
|
+
| 문서 | 내용 |
|
|
134
|
+
|---|---|
|
|
135
|
+
| [CLAUDE.md](./CLAUDE.md) | 절대 원칙·네이밍·개발 원칙(P1~P8) |
|
|
136
|
+
| [docs/01-vision.md](./docs/01-vision.md) | 비전·핵심 가치·차별점 |
|
|
137
|
+
| [docs/02-architecture.md](./docs/02-architecture.md) | 전체 아키텍처 |
|
|
138
|
+
| [docs/03-api-spec.md](./docs/03-api-spec.md) | 클래스/메서드 시그니처 |
|
|
139
|
+
| [docs/04-data-models.md](./docs/04-data-models.md) | config 스키마·타입 |
|
|
140
|
+
| [docs/05-roadmap.md](./docs/05-roadmap.md) | Phase 0~6 로드맵 + 현재 위치 |
|
|
141
|
+
| [docs/06-class-diagrams.md](./docs/06-class-diagrams.md) | 클래스 다이어그램(Mermaid) |
|
|
142
|
+
| [docs/07-sequence-diagrams.md](./docs/07-sequence-diagrams.md) | 시퀀스 다이어그램 |
|
|
143
|
+
| [docs/08-class-specs.md](./docs/08-class-specs.md) | 클래스별 행동 스펙 |
|
|
144
|
+
| [docs/09-decisions-and-open-questions.md](./docs/09-decisions-and-open-questions.md) | 결정 기록(ADR-001~138) + 미해결 질문(OQ) |
|
|
145
|
+
| [docs/10-state-diagrams.md](./docs/10-state-diagrams.md) | 상태 다이어그램 |
|
|
146
|
+
| [docs/11-test-scenarios.md](./docs/11-test-scenarios.md) | 테스트 시나리오 |
|
|
147
|
+
| [docs/12-performance-security.md](./docs/12-performance-security.md) | 성능 목표 + STRIDE 위협 모델 |
|
|
148
|
+
| [docs/13-sample-code.md](./docs/13-sample-code.md) | 동작 코드 묶음 |
|
|
149
|
+
| [docs/INFRA.md](./docs/INFRA.md) | 로컬 docker 인프라·트레이싱·메트릭·DLQ 운영 가이드 |
|
|
150
|
+
|
|
151
|
+
## 라이선스
|
|
152
|
+
|
|
153
|
+
MIT
|
|
@@ -0,0 +1,15 @@
|
|
|
1
|
+
#!/usr/bin/env node
|
|
2
|
+
// @ts-check
|
|
3
|
+
/**
|
|
4
|
+
* `mega ws-hub` 실행 launcher (ADR-032). 실제 로직은 src/cli/ws-hub.js.
|
|
5
|
+
*
|
|
6
|
+
* 사용: MEGA_WSHUB_TOKENS=tok1,tok2 [MEGA_WSHUB_PORT=3100] [MEGA_WSHUB_HOST=0.0.0.0]
|
|
7
|
+
* [MEGA_WSHUB_HEARTBEAT_MS=25000] mega-ws-hub
|
|
8
|
+
*/
|
|
9
|
+
import { runWsHubCli } from '../src/cli/ws-hub.js'
|
|
10
|
+
|
|
11
|
+
runWsHubCli().catch((err) => {
|
|
12
|
+
// 부팅 실패는 fail-fast — 메시지 출력 후 비정상 종료 (P4: 이유 명확, silent X).
|
|
13
|
+
console.error(`[mega:ws-hub] failed to start: ${err.message}`)
|
|
14
|
+
process.exitCode = 1
|
|
15
|
+
})
|
package/bin/mega.js
ADDED
|
@@ -0,0 +1,38 @@
|
|
|
1
|
+
#!/usr/bin/env node
|
|
2
|
+
// @ts-check
|
|
3
|
+
/**
|
|
4
|
+
* `mega` CLI 실행 launcher (Phase 4 Step 6, ADR-123). 실제 로직은 src/cli/index.js.
|
|
5
|
+
*
|
|
6
|
+
* 사용:
|
|
7
|
+
* mega start [--port N] [--host H] [--root DIR]
|
|
8
|
+
* mega worker | scheduler [--root DIR]
|
|
9
|
+
* mega <plugin:command> [args...]
|
|
10
|
+
* mega help
|
|
11
|
+
*/
|
|
12
|
+
import { runCli } from '../src/cli/index.js'
|
|
13
|
+
import { MegaShutdown } from '../src/lib/mega-shutdown.js'
|
|
14
|
+
|
|
15
|
+
runCli(process.argv.slice(2))
|
|
16
|
+
.then((code) => {
|
|
17
|
+
// 명령 핸들러가 정한 exit code 를 반영. start/worker/scheduler 는 0 을 돌려주지만 시그널
|
|
18
|
+
// 대기로 프로세스가 살아 있으므로 즉시 종료되지 않는다(MegaShutdown 이 SIGTERM 에 종료).
|
|
19
|
+
process.exitCode = code
|
|
20
|
+
})
|
|
21
|
+
.catch(async (err) => {
|
|
22
|
+
// 부팅·명령 실패는 fail-fast — 메시지 출력 후 비정상 종료 (P4: 이유 명확, silent X).
|
|
23
|
+
console.error(`[mega] failed: ${err?.message ?? err}`)
|
|
24
|
+
// M-1 — 부팅이 어댑터 connect(buildFromGlobalConfig 가 'adapters:disconnect' hook 등록)까지 진행한 뒤
|
|
25
|
+
// 후속 단계(예: server.listen EADDRINUSE, beforeBoot hook throw)에서 실패하면, 연결된 어댑터가 정리
|
|
26
|
+
// 없이 남아 이벤트루프를 살려 프로세스가 hang 한다(boot.js:116 주석이 약속한 정리). 등록된 cleanup
|
|
27
|
+
// hook 을 LIFO 로 실행해(어댑터 disconnect 등) 자원을 회수한 뒤 exit 1 한다. MegaShutdown.now 가
|
|
28
|
+
// 마지막에 process.exit 하므로 정상 경로에선 아래 process.exit 는 도달하지 않는다.
|
|
29
|
+
try {
|
|
30
|
+
await MegaShutdown.now({ exitCode: 1 })
|
|
31
|
+
} catch (cleanupErr) {
|
|
32
|
+
// 정리 중 예외(now 의 per-hook catch 를 벗어난 드문 경우)도 묻지 않는다(P4) — 메시지 후 강제 종료.
|
|
33
|
+
console.error(`[mega] cleanup failed: ${cleanupErr?.message ?? cleanupErr}`)
|
|
34
|
+
process.exit(1)
|
|
35
|
+
}
|
|
36
|
+
// now() 가 exit 하지 않은 경우(테스트 mock 등)를 위한 보장.
|
|
37
|
+
process.exit(1)
|
|
38
|
+
})
|
|
@@ -0,0 +1,201 @@
|
|
|
1
|
+
# MEGA-FRAMEWORK — Phase 3 통합 테스트 인프라 (ADR-103)
|
|
2
|
+
#
|
|
3
|
+
# Step 3~6 어댑터 통합 테스트가 실 인스턴스로 검증되도록, Step 9 산출물을
|
|
4
|
+
# Step 3 이전으로 당겨온 docker-compose 정의.
|
|
5
|
+
#
|
|
6
|
+
# 포함 서비스 (docker 필요한 5종):
|
|
7
|
+
# - Postgres 16 (Step 4, pg)
|
|
8
|
+
# - MariaDB 11 (Step 4, mariadb)
|
|
9
|
+
# - MongoDB 7 (Step 5, mongodb)
|
|
10
|
+
# - Redis 7 (Step 6, ioredis)
|
|
11
|
+
# - NATS 2.10 (Step 6, nats) — JetStream 활성(-js, Phase 4 Step 3 MegaJob)
|
|
12
|
+
#
|
|
13
|
+
# 제외 (docker 불필요):
|
|
14
|
+
# - Sqlite (Step 3, better-sqlite3 file-based / in-memory)
|
|
15
|
+
# - File (Step 6, 로컬 파일시스템)
|
|
16
|
+
#
|
|
17
|
+
# 데이터 정책: ephemeral (tmpfs). 컨테이너 종료 시 데이터 소멸 → 테스트 격리.
|
|
18
|
+
# `npm run infra:down` 은 `down -v` 로 익명 볼륨까지 청소.
|
|
19
|
+
#
|
|
20
|
+
# 비밀번호는 모두 dev/test 전용 약한 값. ⚠️ 운영 환경 사용 금지.
|
|
21
|
+
#
|
|
22
|
+
# docker compose v2 (subcommand) 기준. legacy `docker-compose`(하이픈) 아님.
|
|
23
|
+
# 모든 포트/credential 은 .env 로 오버라이드 가능 (.env.example 참조).
|
|
24
|
+
#
|
|
25
|
+
# ── 어댑터 옵션과의 관계 (ADR-109) ────────────────────────────────────
|
|
26
|
+
# 아래 각 컨테이너 environment 의 MEGA_<SERVICE>_USER/PASSWORD/DB/PORT 는 **컨테이너 초기화용**이다.
|
|
27
|
+
# 같은 이름들이 services.<domain>.<key>.envPrefix 지정 시 어댑터 연결필드로도 매핑된다(env-mapper).
|
|
28
|
+
# 어댑터의 advanced 옵션(pool.*, options.*, mariadb bigIntStrategy 등)은 컨테이너가 아니라 **앱**이
|
|
29
|
+
# 읽으므로 docker-compose 가 아닌 .env(MEGA_<SERVICE>_POOL_*/OPTIONS_*)에 둔다 — 예시는 .env.example.
|
|
30
|
+
# (DB 컨테이너 environment 에 풀/드라이버 옵션을 넣는 것은 의미가 없어 의도적으로 분리.)
|
|
31
|
+
|
|
32
|
+
name: mega-test
|
|
33
|
+
|
|
34
|
+
services:
|
|
35
|
+
# ── Postgres (Step 4) ─────────────────────────────────────────────
|
|
36
|
+
postgres:
|
|
37
|
+
image: postgres:16-alpine
|
|
38
|
+
container_name: mega-postgres
|
|
39
|
+
restart: ${MEGA_INFRA_RESTART:-unless-stopped}
|
|
40
|
+
ports:
|
|
41
|
+
- "${MEGA_PG_PORT:-5432}:5432"
|
|
42
|
+
environment:
|
|
43
|
+
POSTGRES_USER: ${MEGA_PG_USER:-mega}
|
|
44
|
+
POSTGRES_PASSWORD: ${MEGA_PG_PASSWORD:-mega-dev-only}
|
|
45
|
+
POSTGRES_DB: ${MEGA_PG_DB:-mega_test}
|
|
46
|
+
# ephemeral: 데이터 디렉토리를 tmpfs(RAM)에 둬 종료 시 소멸
|
|
47
|
+
tmpfs:
|
|
48
|
+
- /var/lib/postgresql/data
|
|
49
|
+
healthcheck:
|
|
50
|
+
test: ["CMD-SHELL", "pg_isready -U ${MEGA_PG_USER:-mega} -d ${MEGA_PG_DB:-mega_test}"]
|
|
51
|
+
interval: 3s
|
|
52
|
+
timeout: 3s
|
|
53
|
+
retries: 10
|
|
54
|
+
start_period: 5s
|
|
55
|
+
networks:
|
|
56
|
+
- mega-test-net
|
|
57
|
+
|
|
58
|
+
# ── MariaDB (Step 4) ──────────────────────────────────────────────
|
|
59
|
+
mariadb:
|
|
60
|
+
image: mariadb:11
|
|
61
|
+
container_name: mega-mariadb
|
|
62
|
+
restart: ${MEGA_INFRA_RESTART:-unless-stopped}
|
|
63
|
+
ports:
|
|
64
|
+
- "${MEGA_MARIA_PORT:-3306}:3306"
|
|
65
|
+
environment:
|
|
66
|
+
MARIADB_ROOT_PASSWORD: ${MEGA_MARIA_ROOT_PASSWORD:-mega-dev-only}
|
|
67
|
+
MARIADB_DATABASE: ${MEGA_MARIA_DB:-mega_test}
|
|
68
|
+
MARIADB_USER: ${MEGA_MARIA_USER:-mega}
|
|
69
|
+
MARIADB_PASSWORD: ${MEGA_MARIA_PASSWORD:-mega-dev-only}
|
|
70
|
+
tmpfs:
|
|
71
|
+
- /var/lib/mysql
|
|
72
|
+
# mariadb 공식 이미지 제공 스크립트 (innodb 초기화까지 확인)
|
|
73
|
+
healthcheck:
|
|
74
|
+
test: ["CMD", "healthcheck.sh", "--connect", "--innodb_initialized"]
|
|
75
|
+
interval: 3s
|
|
76
|
+
timeout: 3s
|
|
77
|
+
retries: 15
|
|
78
|
+
start_period: 8s
|
|
79
|
+
networks:
|
|
80
|
+
- mega-test-net
|
|
81
|
+
|
|
82
|
+
# ── MongoDB (Step 5) ──────────────────────────────────────────────
|
|
83
|
+
# ⚠️ standalone 모드 — 도큐먼트 CRUD 통합은 동작하나 **트랜잭션은 미지원**이다
|
|
84
|
+
# (MongoDB 트랜잭션은 replica set/mongos 필요, ADR-108). 트랜잭션 통합 테스트는
|
|
85
|
+
# replica set Mongo(예: MEGA_MONGO_URL 에 ?replicaSet=rs0)를 주입할 때만 실행되고
|
|
86
|
+
# standalone 이면 해당 테스트만 자동 skip 된다. auth 활성 상태에서 replSet 을 켜려면
|
|
87
|
+
# 멤버 간 keyFile + rs.initiate() 가 필요해 docker 가용 환경에서 별도 검증 후 결정(ADR-103 갱신).
|
|
88
|
+
mongodb:
|
|
89
|
+
image: mongo:7
|
|
90
|
+
container_name: mega-mongodb
|
|
91
|
+
restart: ${MEGA_INFRA_RESTART:-unless-stopped}
|
|
92
|
+
ports:
|
|
93
|
+
- "${MEGA_MONGO_PORT:-27017}:27017"
|
|
94
|
+
environment:
|
|
95
|
+
MONGO_INITDB_ROOT_USERNAME: ${MEGA_MONGO_USER:-mega}
|
|
96
|
+
MONGO_INITDB_ROOT_PASSWORD: ${MEGA_MONGO_PASSWORD:-mega-dev-only}
|
|
97
|
+
MONGO_INITDB_DATABASE: ${MEGA_MONGO_DB:-mega_test}
|
|
98
|
+
tmpfs:
|
|
99
|
+
- /data/db
|
|
100
|
+
# mongo:7 은 mongosh 내장
|
|
101
|
+
healthcheck:
|
|
102
|
+
test: ["CMD", "mongosh", "--quiet", "--eval", "db.adminCommand('ping').ok"]
|
|
103
|
+
interval: 3s
|
|
104
|
+
timeout: 5s
|
|
105
|
+
retries: 15
|
|
106
|
+
start_period: 8s
|
|
107
|
+
networks:
|
|
108
|
+
- mega-test-net
|
|
109
|
+
|
|
110
|
+
# ── Redis (Step 6) ────────────────────────────────────────────────
|
|
111
|
+
redis:
|
|
112
|
+
image: redis:7-alpine
|
|
113
|
+
container_name: mega-redis
|
|
114
|
+
restart: ${MEGA_INFRA_RESTART:-unless-stopped}
|
|
115
|
+
ports:
|
|
116
|
+
- "${MEGA_REDIS_PORT:-6379}:6379"
|
|
117
|
+
# dev/test 전용 패스워드. persistence off (--save "") → 인메모리, 종료 시 소멸
|
|
118
|
+
command: >
|
|
119
|
+
redis-server
|
|
120
|
+
--requirepass ${MEGA_REDIS_PASSWORD:-mega-dev-only}
|
|
121
|
+
--save ""
|
|
122
|
+
--appendonly no
|
|
123
|
+
healthcheck:
|
|
124
|
+
test: ["CMD", "redis-cli", "-a", "${MEGA_REDIS_PASSWORD:-mega-dev-only}", "ping"]
|
|
125
|
+
interval: 3s
|
|
126
|
+
timeout: 3s
|
|
127
|
+
retries: 10
|
|
128
|
+
start_period: 3s
|
|
129
|
+
networks:
|
|
130
|
+
- mega-test-net
|
|
131
|
+
|
|
132
|
+
# ── NATS (Step 6 + Phase 4 Step 3 JetStream) ──────────────────────
|
|
133
|
+
nats:
|
|
134
|
+
image: nats:2.10-alpine
|
|
135
|
+
container_name: mega-nats
|
|
136
|
+
restart: ${MEGA_INFRA_RESTART:-unless-stopped}
|
|
137
|
+
ports:
|
|
138
|
+
- "${MEGA_NATS_PORT:-4222}:4222" # client
|
|
139
|
+
- "${MEGA_NATS_MONITOR_PORT:-8222}:8222" # HTTP monitoring (/healthz)
|
|
140
|
+
# -m 8222: HTTP 모니터링 활성 → healthcheck 가 /healthz 폴링
|
|
141
|
+
# -js -sd /data/jetstream: JetStream(영속 큐) 활성화 + store dir 지정. MegaJob/MegaJobQueue
|
|
142
|
+
# (Phase 4 Step 3, ADR-119)가 영속 큐·재시도·DLQ 에 JetStream 을 쓴다. store dir 은 아래 tmpfs
|
|
143
|
+
# (RAM)에 둬 **데이터 정책(ephemeral)을 유지** — 종료 시 스트림·메시지 소멸 → 테스트 격리.
|
|
144
|
+
command: ["--name", "mega-nats", "-m", "8222", "-js", "-sd", "/data/jetstream"]
|
|
145
|
+
tmpfs:
|
|
146
|
+
- /data/jetstream
|
|
147
|
+
# nats:2.10-alpine 은 busybox wget 내장 (non-alpine scratch 이미지는 shell 없어 불가)
|
|
148
|
+
healthcheck:
|
|
149
|
+
test: ["CMD", "wget", "--no-verbose", "--tries=1", "--spider", "http://localhost:8222/healthz"]
|
|
150
|
+
interval: 3s
|
|
151
|
+
timeout: 3s
|
|
152
|
+
retries: 10
|
|
153
|
+
start_period: 3s
|
|
154
|
+
networks:
|
|
155
|
+
- mega-test-net
|
|
156
|
+
|
|
157
|
+
# ── Zipkin (Phase 5 Step 1 트레이싱 백엔드, ADR-128) ───────────────
|
|
158
|
+
# OTLP collector 가 변환·전달한 span 을 저장·조회하는 백엔드 + UI(:9411).
|
|
159
|
+
# 통합 테스트는 /api/v2/traces 로 span 도달을 검증한다. 저장은 in-memory(종료 시 소멸).
|
|
160
|
+
zipkin:
|
|
161
|
+
image: openzipkin/zipkin:3.4
|
|
162
|
+
container_name: mega-zipkin
|
|
163
|
+
restart: ${MEGA_INFRA_RESTART:-unless-stopped}
|
|
164
|
+
ports:
|
|
165
|
+
- "${MEGA_ZIPKIN_PORT:-9411}:9411"
|
|
166
|
+
# openzipkin/zipkin 이미지에 healthcheck 용 wget 내장. /health 는 zipkin 자체 헬스 엔드포인트.
|
|
167
|
+
healthcheck:
|
|
168
|
+
test: ["CMD", "wget", "--no-verbose", "--tries=1", "--spider", "http://localhost:9411/health"]
|
|
169
|
+
interval: 3s
|
|
170
|
+
timeout: 3s
|
|
171
|
+
retries: 20
|
|
172
|
+
start_period: 5s
|
|
173
|
+
networks:
|
|
174
|
+
- mega-test-net
|
|
175
|
+
|
|
176
|
+
# ── OpenTelemetry Collector (ADR-128) ─────────────────────────────
|
|
177
|
+
# 앱(OTLP exporter) → collector → zipkin. config 는 infra/otel-collector-config.yaml.
|
|
178
|
+
# 이미지가 distroless 라 컨테이너 내 shell 이 없어 compose healthcheck(CMD-SHELL)는 불가.
|
|
179
|
+
# → health_check extension(:13133)을 노출하고, 통합 테스트가 HTTP 폴링으로 준비를 확인한다.
|
|
180
|
+
# collector 가 config 오류로 죽으면 depends_on(zipkin) 과 무관하게 컨테이너가 Exit → 테스트가 즉시 감지.
|
|
181
|
+
otel-collector:
|
|
182
|
+
image: otel/opentelemetry-collector-contrib:0.110.0
|
|
183
|
+
container_name: mega-otel-collector
|
|
184
|
+
restart: ${MEGA_INFRA_RESTART:-unless-stopped}
|
|
185
|
+
command: ["--config=/etc/otel-collector-config.yaml"]
|
|
186
|
+
volumes:
|
|
187
|
+
- ./infra/otel-collector-config.yaml:/etc/otel-collector-config.yaml:ro
|
|
188
|
+
ports:
|
|
189
|
+
- "${MEGA_OTEL_OTLP_GRPC_PORT:-4317}:4317" # OTLP gRPC
|
|
190
|
+
- "${MEGA_OTEL_OTLP_HTTP_PORT:-4318}:4318" # OTLP HTTP
|
|
191
|
+
- "${MEGA_OTEL_HEALTH_PORT:-13133}:13133" # health_check extension
|
|
192
|
+
depends_on:
|
|
193
|
+
zipkin:
|
|
194
|
+
condition: service_healthy
|
|
195
|
+
networks:
|
|
196
|
+
- mega-test-net
|
|
197
|
+
|
|
198
|
+
networks:
|
|
199
|
+
mega-test-net:
|
|
200
|
+
name: mega-test-net
|
|
201
|
+
driver: bridge
|
package/eslint.config.js
ADDED
|
@@ -0,0 +1,57 @@
|
|
|
1
|
+
// eslint.config.js — ESLint v9 flat config
|
|
2
|
+
// MEGA-FRAMEWORK 린트 정책 (ADR-026 promise plugin + CLAUDE.md P4 silent catch 금지)
|
|
3
|
+
|
|
4
|
+
import js from '@eslint/js'
|
|
5
|
+
import promise from 'eslint-plugin-promise'
|
|
6
|
+
import globals from 'globals'
|
|
7
|
+
import mega from './src/eslint-plugin/index.js'
|
|
8
|
+
|
|
9
|
+
export default [
|
|
10
|
+
js.configs.recommended,
|
|
11
|
+
{
|
|
12
|
+
languageOptions: {
|
|
13
|
+
ecmaVersion: 'latest',
|
|
14
|
+
sourceType: 'module',
|
|
15
|
+
globals: { ...globals.node, ...globals.es2024 },
|
|
16
|
+
},
|
|
17
|
+
plugins: { promise, mega },
|
|
18
|
+
rules: {
|
|
19
|
+
// CLAUDE.md P4 — silent catch 절대 금지
|
|
20
|
+
'no-empty': ['error', { allowEmptyCatch: false }],
|
|
21
|
+
'no-unused-vars': ['warn', { argsIgnorePattern: '^_' }],
|
|
22
|
+
|
|
23
|
+
// ADR-026 — Promise 안전성 정적 보강.
|
|
24
|
+
// 주의: no-floating-promises 는 @typescript-eslint 의 타입 기반 룰이며
|
|
25
|
+
// JS 전용 eslint-plugin-promise(v7)에는 존재하지 않는다. 타입 정보 없이
|
|
26
|
+
// floating promise 를 정적 검출할 수단이 없으므로, JS 환경에서는
|
|
27
|
+
// catch-or-return(then 체인 미처리 검출)으로 대체한다. (docs/09 ADR-026)
|
|
28
|
+
'promise/catch-or-return': 'error',
|
|
29
|
+
|
|
30
|
+
// ADR-022 — 라우트·컨트롤러는 모델 직접 import 금지
|
|
31
|
+
'mega/no-direct-model-import': 'error',
|
|
32
|
+
},
|
|
33
|
+
},
|
|
34
|
+
{
|
|
35
|
+
// 테스트 파일은 vitest 글로벌 (describe/test/expect 등) 노출
|
|
36
|
+
files: ['test/**/*.js', '**/*.test.js'],
|
|
37
|
+
languageOptions: {
|
|
38
|
+
globals: { ...globals.node, ...globals.es2024 },
|
|
39
|
+
},
|
|
40
|
+
rules: {
|
|
41
|
+
'no-unused-vars': ['warn', { argsIgnorePattern: '^_', varsIgnorePattern: '^_' }],
|
|
42
|
+
},
|
|
43
|
+
},
|
|
44
|
+
{
|
|
45
|
+
ignores: [
|
|
46
|
+
'node_modules/**',
|
|
47
|
+
'dist/**',
|
|
48
|
+
'coverage/**',
|
|
49
|
+
'packages/*/pkg/**',
|
|
50
|
+
'packages/*/target/**',
|
|
51
|
+
'logs/**',
|
|
52
|
+
'storage/**',
|
|
53
|
+
'.git/**',
|
|
54
|
+
'.idea/**',
|
|
55
|
+
],
|
|
56
|
+
},
|
|
57
|
+
]
|
|
@@ -0,0 +1,43 @@
|
|
|
1
|
+
# MEGA-FRAMEWORK — OpenTelemetry Collector 설정 (ADR-128)
|
|
2
|
+
#
|
|
3
|
+
# 역할: 앱(OTLP HTTP/gRPC exporter)이 보낸 trace span 을 수신해 Zipkin 백엔드로 전달.
|
|
4
|
+
# 파이프라인: 앱 ──OTLP──▶ collector ──Zipkin v2──▶ mega-zipkin(:9411)
|
|
5
|
+
# └─debug(stdout) ── infra:logs 로 span 확인
|
|
6
|
+
#
|
|
7
|
+
# 통합 테스트(tracing/otel-collector-e2e)는 앱에서 OTLP 로 span 을 보내고, Zipkin API
|
|
8
|
+
# (/api/v2/traces)를 폴링해 collector→zipkin 경로가 실제로 동작함을 검증한다.
|
|
9
|
+
#
|
|
10
|
+
# ⚠️ dev/test 전용. 운영용 보안(인증/TLS/샘플링 정책)은 포함하지 않는다.
|
|
11
|
+
# collector-contrib 0.110.0 기준. 이미지는 distroless 라 컨테이너 내 shell 없음.
|
|
12
|
+
|
|
13
|
+
receivers:
|
|
14
|
+
# OTLP receiver — HTTP(4318)/gRPC(4317) 둘 다 수신.
|
|
15
|
+
# 0.110 대에서 디폴트 bind 가 localhost 로 바뀌어, 컨테이너 외부(호스트) 접근을
|
|
16
|
+
# 위해 0.0.0.0 으로 명시한다(미명시 시 컨테이너 내부에서만 listen → 호스트 연결 거부).
|
|
17
|
+
otlp:
|
|
18
|
+
protocols:
|
|
19
|
+
http:
|
|
20
|
+
endpoint: 0.0.0.0:4318
|
|
21
|
+
grpc:
|
|
22
|
+
endpoint: 0.0.0.0:4317
|
|
23
|
+
|
|
24
|
+
exporters:
|
|
25
|
+
# Zipkin v2 JSON 으로 변환해 zipkin 컨테이너로 전송.
|
|
26
|
+
zipkin:
|
|
27
|
+
endpoint: http://mega-zipkin:9411/api/v2/spans
|
|
28
|
+
# stdout 디버그(개발 편의 — `docker compose logs mega-otel-collector` 로 span 확인).
|
|
29
|
+
debug:
|
|
30
|
+
verbosity: normal
|
|
31
|
+
|
|
32
|
+
extensions:
|
|
33
|
+
# 헬스 체크 엔드포인트(:13133). distroless 라 compose healthcheck(shell)는 불가하나,
|
|
34
|
+
# 통합 테스트가 이 엔드포인트를 HTTP 폴링해 collector 준비 완료를 확인한다.
|
|
35
|
+
health_check:
|
|
36
|
+
endpoint: 0.0.0.0:13133
|
|
37
|
+
|
|
38
|
+
service:
|
|
39
|
+
extensions: [health_check]
|
|
40
|
+
pipelines:
|
|
41
|
+
traces:
|
|
42
|
+
receivers: [otlp]
|
|
43
|
+
exporters: [zipkin, debug]
|
package/jsconfig.json
ADDED
|
@@ -0,0 +1,18 @@
|
|
|
1
|
+
{
|
|
2
|
+
"compilerOptions": {
|
|
3
|
+
"checkJs": false,
|
|
4
|
+
"allowJs": true,
|
|
5
|
+
"noEmit": true,
|
|
6
|
+
"noImplicitAny": true,
|
|
7
|
+
"strict": false,
|
|
8
|
+
"target": "ES2022",
|
|
9
|
+
"module": "NodeNext",
|
|
10
|
+
"moduleResolution": "NodeNext",
|
|
11
|
+
"lib": ["ES2022"],
|
|
12
|
+
"types": ["node"],
|
|
13
|
+
"skipLibCheck": true,
|
|
14
|
+
"resolveJsonModule": true
|
|
15
|
+
},
|
|
16
|
+
"include": ["src/**/*.js", "test/**/*.js", "bin/**/*.js"],
|
|
17
|
+
"exclude": ["node_modules", "coverage", "packages/**/pkg"]
|
|
18
|
+
}
|