EventHub Monorepo Migration Plan
Trạng thái: Architecture proposal — chưa thay đổi source code.
Cập nhật: 2026-10-15.
Phạm vi: chuyển EventHub hiện tại thành npm Workspaces gồm hai ứng dụng Nuxt độc lập:webvàconsole.Nguồn:
- Source EventHub hiện tại.
monorepo-migration-proposal.md.monorepo-target-architecture.md.2026-10-13-technical-seed-next-monorepo-anatomy.md.
Kiến trúc đích được đề xuất:
- Một repository, quản lý bằng npm Workspaces.
apps/web: EventHub public hiện tại, Nuxt 3,ssr: true, không còn route hoặc dependency của Builder.apps/console: Event Builder nội bộ,ssr: false, đích cuối là Nuxt 4 và static output.- Mỗi app sở hữu
package.json,nuxt.config.ts, source, test, Docker/hosting contract và artifact riêng. - Toàn workspace dùng một
package-lock.jsonở root. apps/webtạo Nitro Node artifact tạiapps/web/.output/.apps/consolechạynuxi generate, tạo static artifact tạiapps/console/.output/public/.- Hai app có pipeline, release version, deploy target và rollback độc lập.
- Chỉ extract shared package khi cả Web và Console thực sự dùng và có ownership rõ ràng. Shared boundary đầu tiên có bằng chứng rõ nhất là event-page runtime, đặc biệt
EventPageRenderer, model/validation và preview protocol. - Migration đầu tiên không nâng Web lên Nuxt 4. Builder nên được tách và kiểm chứng độc lập trên Nuxt 3 trước; việc nâng riêng Console lên Nuxt 4 là một phase có quality gate riêng.
#Quyết định kiến trúc
| Chủ đề | Quyết định đề xuất |
|---|---|
| Monorepo tool | npm Workspaces; chưa cần Nx hoặc Turborepo |
| App structure | apps/web + apps/console |
| Dependency declaration | Mỗi app/package có package.json riêng |
| Lockfile | Một package-lock.json tại root |
| Web | Nuxt 3, SSR, Nitro Node server |
| Console | Tách trên Nuxt 3 trước, sau đó nâng riêng lên Nuxt 4; CSR với ssr: false |
| Console output | Static output bằng nuxt generate |
| Web output | Node artifact bằng nuxt build |
| Shared code | Extract theo nhu cầu thực tế, không tạo một package common tổng hợp ngay từ đầu |
| CI/CD | Hai pipeline release độc lập; shared package change có thể trigger cả hai |
#Điều chỉnh so với yêu cầu ban đầu
package-lock.json riêng cho từng app mâu thuẫn với mô hình npm Workspaces chuẩn:
npm citại root dùng một dependency graph và một lockfile.- Mỗi app vẫn sở hữu dependency trực tiếp qua
apps/<app>/package.json. - Root lockfile có thể chứa đồng thời Nuxt 3 của Web và Nuxt 4 của Console.
- Nếu mỗi app bắt buộc có lockfile riêng và cài đặt riêng, nên dùng hai repository hoặc bỏ workspace relationship; không nên gọi đó là một npm workspace thống nhất.
#1.1 Background
EventHub hiện là một Nuxt application duy nhất:
- Root app phục vụ public EventHub.
layers/collab-eventvàlayers/promotioncung cấp public routes và event runtime.layers/event-buildercung cấp route/builder.- Builder chỉ được đăng ký với các
RUN_TYPEdev,dev2,qa2. - Web và Builder hiện dùng chung Nuxt config, dependency graph, plugin, middleware, runtime config và một
.output.
Cấu trúc này làm hai product có cùng release boundary dù mục đích vận hành khác nhau:
- Web là public product cần SSR, SEO, Nitro server và độ ổn định production cao.
- Console là internal authoring tool, ưu tiên CSR, access control và release độc lập.
#1.2 Objective
Migration phải đạt các kết quả:
- Tạo một npm workspace cài đặt được bằng một lệnh từ root.
- Tách Web và Console thành hai Nuxt app độc lập.
- Mỗi app có config, dependency, build command và artifact riêng.
- Web giữ nguyên hành vi SSR và public routes, ngoại trừ Builder.
- Console sở hữu toàn bộ Event Builder.
- Hai app có thể build, deploy và rollback độc lập.
- Shared code có dependency direction rõ ràng, không import chéo giữa hai app.
#1.3 In scope
- Thay đổi layout repository.
- Tách
package.jsonvà Nuxt config theo app. - Tách artifact và pipeline.
- Di chuyển Builder sang Console.
- Extract event runtime thực sự được cả hai app dùng.
- Cập nhật alias, auto-import, tests, Docker context và CI path rules.
- Thiết lập Console
ssr: falsevà static output. - Nâng riêng Console lên Nuxt 4 sau khi đã tách thành công.
#1.4 Out of scope
- Không nâng Web lên Nuxt 4 trong migration này.
- Không refactor business logic không liên quan.
- Không đưa Nx/Turborepo vào giai đoạn đầu.
- Không chuyển toàn bộ code hiện tại thành shared packages.
- Không thay đổi API contract nếu không cần cho auth, CORS hoặc authorization của Console.
- Không gộp release version của Web và Console.
#2.1 Cấu trúc hiện tại
event-hub/
├── nuxt.config.ts
├── package.json
├── package-lock.json
├── Dockerfile
├── pages/ layouts/ components/
├── composables/ stores/ services/ apis/ utils/
├── plugins/ middleware/ server/
├── configs/
│ └── runtime/run-type/
├── layers/
│ ├── collab-event/
│ ├── promotion/
│ └── event-builder/
├── public/ markup/ tests/
└── .output/ # một artifact cho toàn ứng dụng
#2.2 Nuxt composition hiện tại
Root nuxt.config.ts đang:
- Cấu hình
ssr: true. - Luôn extend
collab-eventvàpromotion. - Chỉ extend
event-builderkhiRUN_TYPEthuộcdev,dev2,qa2. - Dùng chung modules, aliases, i18n, runtime config, Sentry, Vite, sitemap, robots và server config.
Root Nuxt app
├── collab-event layer
├── promotion layer
└── event-builder layer # chỉ dev/dev2/qa2
Vì Builder là một layer của Web, nó hiện thừa hưởng:
- Web
app.vuevà layout behavior. - Global middleware.
- Auth/plugin của Web.
- Public runtime config.
- Root aliases.
- Toàn bộ dependency của Web.
- Cùng build artifact và release lifecycle.
#2.3 Build và artifact hiện tại
Các build script hiện tại đều chạy tại root:
npm run build:dev
npm run build:dev2
npm run build:qa
npm run build:qa2
npm run build:sandbox
npm run build:live
Tất cả gọi nuxt build với RUN_TYPE tương ứng và ghi:
.output/
├── public/
├── server/
│ └── index.mjs
└── nitro.json
Dockerfile hiện tại:
- Dùng Node
20.11.1. - Copy root
.output/. - Chạy
node server/index.mjs.
Repository không chứa Jenkinsfile, .gitlab-ci.yml, Helm chart hoặc Kubernetes manifest. Pipeline Web thực tế nằm ngoài repository và phải được Infra cung cấp trước khi cutover.
#2.4 Coupling cần xử lý
Research hiện tại ghi nhận:
layers/promotion: 79 file import root qua@/.layers/collab-event: 14 file import root qua@/.layers/event-builder: 13 file import root qua@/.- Builder import
@promotion/entities/event-pagevới mật độ rất cao. - Builder dùng
@promotion/shared/lib,@promotion/shared/ui. - Codegen của Builder sinh import dành cho Web.
- Preview iframe hiện trỏ tới public promotion route và giả định same-origin.
Các dependency Builder cần phân loại:
Event Builder
├── Builder-only
│ ├── canvas
│ ├── inspector
│ ├── workflow
│ ├── persistence UI
│ └── code generation UI
├── Shared event runtime
│ ├── event-page model/validation
│ ├── EventPageRenderer
│ ├── preview messaging
│ ├── stage policy
│ └── event config helpers
└── Platform dependencies
├── useRequest / API client
├── auth
├── runtime config
├── alert/tooltip
└── shared constants/types
#2.5 Current deployment view
#2.6 Những điểm phải giữ nguyên cho Web
- Public route list, trừ Builder.
- SSR behavior và hydration.
- Locale redirect.
- Runtime config theo
RUN_TYPE. - Sentry behavior.
.well-knownassets.- API/auth behavior.
- Nitro start command.
- Existing environment matrix.
- Markup mode nếu team vẫn sử dụng.
#3.1 Directory structure
event-hub/
├── apps/
│ ├── web/ # @event-hub/web
│ │ ├── package.json
│ │ ├── nuxt.config.ts # Nuxt 3, ssr:true
│ │ ├── app.vue
│ │ ├── error.vue
│ │ ├── configs/
│ │ ├── pages/
│ │ ├── layouts/
│ │ ├── components/
│ │ ├── composables/
│ │ ├── stores/
│ │ ├── services/
│ │ ├── apis/
│ │ ├── plugins/
│ │ ├── middleware/
│ │ ├── server/
│ │ ├── public/
│ │ ├── markup/
│ │ ├── layers/
│ │ │ ├── promotion/ # Web-only local layer
│ │ │ └── collab-event/ # Web-only local layer
│ │ ├── tests/
│ │ └── Dockerfile # Node/Nitro image
│ │
│ └── console/ # @event-hub/console
│ ├── package.json
│ ├── nuxt.config.ts # ssr:false
│ ├── app.vue
│ ├── configs/
│ ├── pages/
│ │ ├── index.vue
│ │ ├── builder/index.vue
│ │ └── preview/[slug].vue
│ ├── layouts/
│ ├── plugins/
│ ├── middleware/
│ ├── layers/
│ │ └── event-builder/ # Console-only local layer
│ ├── public/
│ ├── tests/
│ ├── deploy/
│ │ └── nginx.conf
│ └── Dockerfile # static image, nếu deploy bằng container
│
├── packages/
│ ├── nuxt-layers/
│ │ └── event-runtime/ # chỉ code thực sự dùng bởi cả hai app
│ │ ├── package.json
│ │ ├── nuxt.config.ts
│ │ ├── entities/event-page/
│ │ ├── widgets/event-renderer/
│ │ ├── shared/lib/
│ │ ├── shared/ui/
│ │ └── config/events/
│ ├── event-contract/ # optional: TS thuần sau khi boundary ổn định
│ │ ├── package.json
│ │ └── src/
│ └── configs/ # optional: eslint/tsconfig/tailwind khi có lợi ích rõ
│
├── scripts/
│ └── ci/
├── docs/
├── patches/
├── package.json # workspace orchestration
├── package-lock.json # lockfile duy nhất
├── .npmrc
├── .nvmrc
└── .gitlab-ci.yml # nếu Console dùng GitLab CI
#3.2 Ownership boundary
apps/web
Sở hữu:
- Public pages và layouts.
promotionvàcollab-event.- Web-only plugins: launcher, mobile SDK, ads, SEO, sitemap, robots.
- Nitro server,
.well-known, Sentry server. - Public Web Docker image và deployment.
Không được:
- Import source từ
apps/console. - Đăng ký
event-builder. - Chứa route
/builder.
apps/console
Sở hữu:
- Builder page, layout, canvas, inspector, workflow và persistence UX.
- Console auth guard và access policy.
- Console runtime config.
- Same-origin preview shell.
- Static hosting config và Console release.
Không được:
- Import source từ
apps/web. - Kế thừa Web app hoặc Web-only plugins.
- Dựa vào route guard phía client như lớp authorization duy nhất.
packages/nuxt-layers/event-runtime
Chỉ chứa code có ít nhất hai consumer:
EventPageRenderer.- Event page model, validation và stage policy.
- Preview messaging contract.
- Helper/UI primitive gắn trực tiếp với event runtime.
- Event config dùng cho render/preview.
Không dùng @/ hoặc ~/, vì các alias này trỏ về app consumer. Import nội bộ phải dùng package name hoặc alias riêng của layer.
packages/event-contract
Chỉ tạo khi model thuần đã tách khỏi Nuxt/Vue:
- TypeScript types.
- Validation.
- Factory.
- Stage policy.
- Preview message types.
Không chứa component, composable, useRuntimeConfig hoặc Nuxt auto-import.
#3.3 Vì sao chọn cấu trúc này
So với giữ Builder trong Web
- Loại Builder khỏi public artifact.
- Không buộc Console theo release cadence của Web.
- Giảm blast radius khi thay đổi authoring tool.
- Có thể nâng Console lên Nuxt 4 mà không chạm Web.
- Rõ trách nhiệm vận hành và access control.
So với tách thành repository riêng
- Có thể thay đổi event contract và hai consumer trong cùng một MR.
- Một lockfile giúp dependency graph có thể tái tạo.
- Dùng lại code runtime mà không phải publish package lên registry.
- CI có thể xác định app bị ảnh hưởng từ dependency graph.
- Dễ thực hiện migration từng phase hơn.
Vì sao chưa cần Nx/Turborepo
- Chỉ có hai app và một số ít shared packages.
- npm Workspaces đã giải quyết install và package linking.
- Build của mỗi app đã độc lập.
- Path-based CI đủ cho giai đoạn đầu.
- Có thể bổ sung task runner sau nếu build time, caching hoặc graph orchestration trở thành vấn đề thực tế.
#3.4 Dependency direction
Quy tắc:
webvàconsolekhông import lẫn nhau.- Package shared không import app.
- Builder là Console-only, nên không cần biến thành shared package.
- Promotion và Collab là Web-only, nên ở trong
apps/web/layers. - Dependency phải được khai báo trong
package.jsoncủa đúng consumer; không dựa vào npm hoisting.
#3.5 Nuxt version strategy
Đích cuối:
- Web: giữ Nuxt 3.
- Console: Nuxt 4.
Thứ tự migration được khuyến nghị:
- Tạo Console tối thiểu và tách Builder trên cùng Nuxt major với Web.
- Chứng minh Builder build/chạy độc lập.
- Cắt Builder khỏi Web.
- Nâng riêng Console lên Nuxt 4.
Lý do không nâng Console đồng thời với lần move Builder:
- Nếu build hỏng, có thể phân biệt lỗi do move source với lỗi do Nuxt major.
- Shared layer có thời gian để loại bỏ
@/, auto-import ngầm và Nuxt 3-only behavior. - Rollback đơn giản hơn.
Nếu team quyết định tạo Console trực tiếp bằng Nuxt 4, phải có một compatibility spike trước khi migrate Builder và không được tính spike là bằng chứng production readiness.
#3.6 Lockfile và version policy
Root workspace:
{
“name”: “event-hub-monorepo”,
“private”: true,
“workspaces”: [
“apps/*“,
“packages/*“,
“packages/nuxt-layers/*“,
“packages/configs/*”
]
}
Quy tắc:
- Một
package-lock.jsonở root. npm cichỉ chạy từ root.- Mỗi app pin exact Nuxt major/version của chính nó trong app
package.json. - Không dùng root
overridesđể ép Nuxt 3 và Nuxt 4 thành một version. - Shared package không khai báo Nuxt/Vue là runtime dependency nếu không cần; dùng peer dependency có range đã được kiểm thử.
- Sau khi Console lên Nuxt 4, CI phải build shared runtime với cả hai app.
patch-packagecủa Nuxt 3 cần một CI assertion riêng vì npm có thể hoist/nest khác sau khi thêm Nuxt 4.
#4.1 Root commands
Root package.json chỉ orchestration:
{
“scripts”: {
“dev:web”: “npm run serve --workspace=@event-hub/web”,
“dev:console”: “npm run serve --workspace=@event-hub/console”,
“build:web:dev”: “npm run build:dev --workspace=@event-hub/web”,
“build:web:qa”: “npm run build:qa --workspace=@event-hub/web”,
“build:web:sandbox”: “npm run build:sandbox --workspace=@event-hub/web”,
“build:web:live”: “npm run build:live --workspace=@event-hub/web”,
“build:console:dev”: “npm run build:dev --workspace=@event-hub/console”,
“build:console:qa”: “npm run build:qa --workspace=@event-hub/console”,
“build:console:live”: “npm run build:live --workspace=@event-hub/console”,
“build:all:dev”: “npm run build:web:dev && npm run build:console:dev”,
“lint”: “npm run lint --workspaces --if-present”,
“typecheck”: “npm run typecheck --workspaces --if-present”,
“test”: “npm run test --workspaces --if-present”
}
}
build:all:* chỉ dùng cho local validation hoặc quality gate. Release pipeline phải gọi build của từng app riêng.
#4.2 Web build
apps/web/package.json giữ script hiện tại:
{
“name”: “@event-hub/web”,
“private”: true,
“scripts”: {
“serve”: “cross-env RUN_TYPE=dev nuxt dev”,
“build:dev”: “cross-env NODE_OPTIONS=--max-old-space-size=4096 BUILD_VERSION=$BUILD_VERSION RUN_TYPE=dev SENTRY=off nuxt build”,
“build:qa”: “cross-env NODE_OPTIONS=--max-old-space-size=4096 BUILD_VERSION=$BUILD_VERSION RUN_TYPE=qa SENTRY=off nuxt build”,
“build:sandbox”: “cross-env NODE_OPTIONS=--max-old-space-size=4096 BUILD_VERSION=$BUILD_VERSION RUN_TYPE=sandbox SENTRY=on nuxt build”,
“build:live”: “cross-env NODE_OPTIONS=--max-old-space-size=4096 BUILD_VERSION=$BUILD_VERSION RUN_TYPE=live SENTRY=on nuxt build”
}
}
Build:
npm ci
npm run build:web:live
Artifact:
apps/web/.output/
├── nitro.json
├── public/
└── server/
└── index.mjs
Runtime:
node apps/web/.output/server/index.mjs
#4.3 Console build
apps/console/package.json:
{
“name”: “@event-hub/console”,
“private”: true,
“scripts”: {
“serve”: “cross-env RUN_TYPE=dev nuxt dev”,
“build:dev”: “cross-env RUN_TYPE=dev nuxi generate”,
“build:qa”: “cross-env RUN_TYPE=qa nuxi generate”,
“build:live”: “cross-env RUN_TYPE=live nuxi generate”
}
}
apps/console/nuxt.config.ts:
export default defineNuxtConfig({
ssr: false,
extends: [‘./layers/event-builder’, ‘@event-hub/event-runtime’],
app: {
head: {
meta: [{ name: ‘robots’, content: ‘noindex, nofollow’ }]
}
}
});
Build:
npm ci
npm run build:console:dev
Artifact:
apps/console/.output/public/
├── index.html
├── 200.html
├── 404.html
├── _nuxt/
└── assets copied from public/
Console không có Node/Nitro runtime sau deploy. Static server phải có SPA fallback:
location / {
try_files $uri $uri/ /200.html;
}
#4.4 Hai instance, hai artifact
Mỗi artifact phải có:
- App name.
- Commit SHA.
- Build environment.
- Build timestamp.
- Version/release tag.
- Sentry release nếu áp dụng.
#4.5 Temporary Jenkins compatibility
Trong phase đầu, có thể giữ nguyên Jenkins command hiện tại:
npm run build:live
Root script proxy sang Web rồi copy artifact về root:
{
“scripts”: {
“build:live”: “npm run build:live --workspace=@event-hub/web && node scripts/ci/sync-web-output.mjs”
}
}
sync-web-output.mjs phải copy bảo toàn symlink:
apps/web/.output/ → ./.output/
Sau một release cycle ổn định, Jenkins chuyển sang native:
npm ci
npm run build:live --workspace=@event-hub/web
docker build -f apps/web/Dockerfile apps/web
Khi đó bỏ root .output, compatibility script và root Dockerfile.
#Phase 0 — Baseline và quyết định
Mục tiêu: có bằng chứng trước khi move source.
Actions:
- Lấy Jenkins job/pipeline thật từ Infra.
- Ghi lại install command, build command, Docker context, runtime env và probe.
- Build baseline cho
dev,qa,sandbox,live. - Lưu route list,
nitro.json, bundle/chunk list và kích thước artifact. - Chốt Console domain, auth, CORS, preview và static hosting.
- Chốt Nuxt 4 timing cho Console.
- Commit các script verify cần dùng; hiện
scripts/đang bị.gitignore.
Exit criteria:
- Baseline có thể chạy lại.
- Infra xác nhận pipeline hiện tại.
- Các quyết định security/runtime của Console có owner.
#Phase 1 — Setup npm workspace
Mục tiêu: đổi repository layout nhưng chưa migrate Builder behavior.
Actions:
- Thêm root workspaces.
- Tạo
apps/web/package.json. - Move root Nuxt app vào
apps/web. - Move
promotionvàcollab-eventvàoapps/web/layers. - Giữ Builder tạm thời ở vị trí có thể được Web consume trong transition.
- Tạo
apps/consoletối thiểu, chưa có Builder. - Tạo lại root
package-lock.json. - Pin dependency để tránh nâng version ngoài ý muốn.
- Thêm root build proxy để Jenkins chưa phải đổi.
Exit criteria:
npm citại root thành công.- Web artifact parity với baseline.
- Console tối thiểu build static độc lập.
- Jenkins Web chạy mà không đổi deployment behavior.
Rollback:
- Revert workspace/move MRs.
- Jenkins tiếp tục dùng layout cũ.
#Phase 2 — Independent build validation
Mục tiêu: chứng minh hai app có build boundary thật.
Actions:
- Chạy Web build cho toàn bộ
RUN_TYPE. - Chạy Console build từ clean install.
- Kiểm tra output path không đè nhau.
- Kiểm tra dependency của Console không xuất hiện trong Web artifact.
- Kiểm tra build Web không cần source Console.
- Kiểm tra Docker build context mới.
- Thêm quality gate cho package boundaries.
Exit criteria:
- Hai build có thể chạy riêng và chạy đồng thời.
- Xóa
.outputcủa app này không ảnh hưởng app kia. - Web SSR smoke test pass.
- Console static hosting smoke test pass với deep-link fallback.
#Phase 3 — Extract shared event runtime
Mục tiêu: tạo shared boundary tối thiểu đủ để Builder và Web cùng render event.
Actions:
- Tạo
packages/nuxt-layers/event-runtime. - Move
EventPageRenderer. - Move event-page model, validation, stage policy và preview contract cần cho cả hai.
- Đổi import khỏi
@promotion/*sang package name. - Loại
@/và~/khỏi shared package. - Chỉ tạo
event-contractnếu phần model đã thực sự framework-agnostic. - Giữ Web behavior không đổi.
Exit criteria:
- Web render public event qua shared runtime.
- Console preview render cùng runtime.
- Shared package không import app.
- Shared package build được trong cả Web và Console.
#Phase 4 — Migrate Builder sang Console
Mục tiêu: Console sở hữu Builder nhưng Web vẫn có fallback tạm thời nếu cần.
Actions:
- Move
layers/event-buildervàoapps/console/layers/event-builder. - Tách Console plugins, config và auth.
- Sửa alias và auto-import.
- Di chuyển Builder tests.
- Thêm same-origin preview route trong Console.
- Cập nhật codegen contract.
- Deploy Console dev/QA.
Exit criteria:
- Builder load/list/create/save/promote theo acceptance flow.
- Preview desktop/mobile hoạt động.
- Không import source từ
apps/web. - Console artifact chỉ là static output.
#Phase 5 — Upgrade Console lên Nuxt 4
Mục tiêu: nâng riêng Console, không thay đổi Web.
Actions:
- Pin Nuxt 4 và dependency tương thích trong Console.
- Cập nhật directory semantics hoặc
srcDirtường minh. - Kiểm tra shared event runtime trên Nuxt 3 và Nuxt 4.
- Sửa API deprecated và auto-import khác biệt.
- Regenerate root lockfile.
- Chạy full Builder acceptance test.
Exit criteria:
- Web vẫn build bằng Nuxt 3.
- Console build static bằng Nuxt 4.
- Root install chứa đúng hai dependency trees.
- Shared runtime pass test trên cả hai app.
Rollback:
- Revert riêng Console dependency/config về Nuxt 3.
- Không rollback Web.
#Phase 6 — Cut Builder khỏi Web
Actions:
- Xóa
SUPPORTED_BUILDER_ENABLED_RUN_TYPES. - Xóa Builder khỏi Web
extends. - Xóa alias và dependency Builder khỏi Web.
- Assert Web route manifest không có
/builder. - Thông báo URL Console mới cho Product/QA/Content.
Exit criteria:
- Web artifact không còn Builder source/chunk/route.
- Console đã được dùng ổn định ít nhất một sprint hoặc release window đã thống nhất.
#Phase 7 — Native CI/CD và cleanup
Actions:
- Jenkins build trực tiếp
apps/web. - Console dùng pipeline riêng.
- Xóa compatibility artifact copy.
- Thêm affected path rules.
- Cập nhật AGENTS/CLAUDE/rules/docs theo layout mới.
- Thiết lập release tag riêng, ví dụ
[email protected],[email protected].
Exit criteria:
- Hai pipeline release độc lập.
- Mỗi app rollback độc lập.
- Shared change trigger đúng consumer.
#6.1 Source code impact
Mức ảnh hưởng: cao trong migration, thấp sau khi ổn định.
Thay đổi:
- Hầu hết root path chuyển xuống
apps/web. - Relative path trong Nuxt config fragments phải cập nhật.
process.cwd()trong build hooks sẽ thay đổi thành app directory.- Alias
@/trong layers không còn an toàn. - Tests, fixtures và generated output path phải cập nhật.
- i18n, OpenAPI generation và
.well-knowncopy phải chạy với đúng app cwd.
Giảm thiểu:
- Move bằng MR riêng với sửa behavior.
- Baseline artifact trước move.
- Build mọi
RUN_TYPE. - Cấm cross-app import bằng ESLint.
#6.2 Dependency impact
Mức ảnh hưởng: cao.
Rủi ro:
- Regenerate root lockfile có thể resolve version mới.
- Nuxt 3 và Nuxt 4 có thể được hoist/nest khác dự kiến.
patch-packagecó thể patch sai Nuxt location.- Phantom dependency có thể chạy local nhưng fail trong CI.
- Shared Vue component có thể gặp khác biệt compiler/runtime.
Giảm thiểu:
- Pin exact version trong từng app khi migration.
- So sánh
npm ls --alltrước/sau. - CI clean install.
- Mỗi package khai báo dependency trực tiếp.
- Test shared runtime bằng cả hai build.
#6.3 Web runtime impact
Mức ảnh hưởng: trung bình, nhưng blast radius production cao.
Các vùng nhạy cảm:
- SSR và hydration.
- Locale redirect.
- Server plugins.
- Auth cookie.
- Sentry.
- Sitemap/robots.
.well-known.- Healthcheck.
Lưu ý hiện tại:
- Có route
/api/healthz. - Probe
/healthcheck/_check.htmlcần Infra xác nhận vì không phải explicit route trong source. RUN_TYPE,SENTRY,BUILD_VERSIONphải được bảo toàn.
#6.4 Console runtime impact
Mức ảnh hưởng: cao, vì từ một layer thành một product.
Static Console không có Nitro server, do đó:
- Không thể tự tạo BFF/proxy bằng server routes.
- Runtime config public bị bake tại build time.
- Mỗi environment cần artifact riêng nếu endpoint khác nhau.
- Healthcheck do Nginx/ingress/static host cung cấp.
- Auth/CORS phải giải quyết ở API gateway hoặc edge.
#6.5 Preview impact
Preview hiện giả định same-origin với public promotion route.
Khuyến nghị:
- Console có route
/preview/[slug]. - Route này render
EventPageRenderertừ shared runtime. - Iframe và parent cùng Console origin.
- Thêm action “Open on Web” để QA kiểm tra public shell thật.
Nếu bắt buộc iframe Web thật:
- Phải cấu hình target origin allowlist.
- Web phải cho phép Console origin qua CSP
frame-ancestors. postMessagephải validateoriginvàsource.- Preview bị phụ thuộc vào version Web đang deploy.
#6.6 Security impact
“Internal” không thay thế authentication và authorization.
Phải xác nhận:
- Console domain có nằm dưới
.onstove.comhay không. - Cookie của
seed-corecó đọc được trên domain Console hay không. - Backend có role check cho API ghi event page hay không.
- CORS allowlist có Console origin hay không.
- Có VPN, corporate network, IP allowlist hoặc SSO ở edge hay không.
- Static bundle không chứa secret.
Nếu Console ở domain không thuộc .onstove.com, cookie .onstove.com không thể được browser gửi như same-site app cookie. Cần corporate SSO, edge proxy hoặc backend admin API phù hợp; không thể sửa bằng Nuxt route guard.
#7.1 Web pipeline
Giai đoạn compatibility
- Install vẫn là
npm citại root. - Command Jenkins hiện tại có thể giữ nguyên qua root proxy.
- Root
.outputđược tạo tạm từapps/web/.output. - Root Dockerfile chưa đổi.
Giai đoạn native
- Build command:
npm ci
npm run build:live --workspace=@event-hub/web
- Docker command:
docker build -f apps/web/Dockerfile apps/web
- Artifact path:
apps/web/.output/
Infra phải cập nhật:
- Jenkins workspace path.
- Docker build context.
- Artifact collection path.
- Sentry sourcemap path.
- Healthcheck route nếu cần.
- Cache key dựa trên root
package-lock.json.
#7.2 Console pipeline
Build command:
npm ci
npm run build:live --workspace=@event-hub/console
Artifact path:
apps/console/.output/public/
#7.3 Pipeline independence
Path rule ban đầu:
apps/web/** → Web
apps/console/** → Console
packages/nuxt-layers/event-runtime/** → Web + Console
packages/event-contract/** → Web + Console
package.json → Web + Console
package-lock.json → Web + Console
patches/** → app liên quan; mặc định cả hai nếu chưa xác định
Release build sandbox/live không nên bị skip chỉ vì path filter; khi được trigger release, app đó phải build đầy đủ.
#7.4 Artifact contract
| Contract | Web | Console |
|---|---|---|
| Build command | nuxt build | nuxi generate |
| Render | SSR | CSR |
| Output | apps/web/.output | apps/console/.output/public |
| Runtime | Node/Nitro | Static host/Nginx |
| Health | Nitro route | Edge/Nginx route |
| Config | Build-time + server runtime hiện tại | Build-time public config |
| Rollback | Previous Node image | Previous static image/bundle |