Appearance
Monorepo Architecture & 5 PM2 Runtime Processes
1. Cấu trúc Thư mục Monorepo (Gotrace-portal)
Dự án sử dụng Yarn Workspaces (1.22.22) kết hợp Turborepo (turbo.json) để quản lý 4 applications độc lập trong apps/ và 6 shared packages trong packages/:
text
Gotrace-portal/
├── apps/
│ ├── frontend/ # Next.js 16.1.1 (App Router, Standalone) — Multi-brand Web Portal (:3000)
│ ├── backend/ # NestJS 11 — Core API (:3001) + VC Worker (main.ts & vc-worker.main.ts)
│ ├── zalo-be/ # NestJS 11 — Dedicated Backend cho Zalo MiniApp (:3002)
│ └── integration-gateway/ # NestJS 11 — Gateway đồng bộ 12 cổng Quốc gia (:3003 public / 127.0.0.1:3013 internal)
├── packages/
│ ├── shared-types/ # Shared TypeScript interfaces/enums/contracts (@gotrace/shared-types)
│ ├── integration-client/ # HMAC-SHA256 signed HTTP Client gọi sang integration-gateway (@gotrace/integration-client)
│ ├── integration-crypto/ # AES-256-GCM Envelope Encryption cho integration credentials (@gotrace/integration-crypto)
│ ├── integration-outbox/ # Helper enqueueInTx() ghi event vào bảng integration_outbox trong cùng DB transaction
│ ├── eslint-config/ # Shared ESLint configuration
│ └── typescript-config/ # Base tsconfig profiles
├── docs/ # Tài liệu SRS (docs/srs/), 5-Layer Architecture (docs/technical/), User Guides (docs/hdsd-modules/)
├── docker-compose.dev.yml # Local infra: PostgreSQL 16, Redis 7, MinIO, Backend, Frontend
├── ecosystem.config.js # PM2 configuration điều phối 5 processes trên Production
└── turbo.json # Turborepo pipeline (build / dev / lint / check-types)2. Năm PM2 Runtime Processes trong ecosystem.config.js
Mặc dù có 4 thư mục trong apps/, hệ thống chạy 5 PM2 processes độc lập trên môi trường Production (do apps/backend được build ra 2 entrypoints khác nhau là dist/src/main.js và dist/src/vc-worker.main.js):
| STT | PM2 Process Name | Source App & Entrypoint | Exec Mode | Port | Vai trò & Lý do Tách Process |
|---|---|---|---|---|---|
| 1 | gotrace-backend | apps/backend (dist/src/main.js) | cluster (API_INSTANCES hoặc max) | :3001 | Phục vụ toàn bộ HTTP REST API /api/v1/* cho Web Portal, Public QR Trace, Cronjobs nội bộ và Bull Board (/api/v1/admin/queues/vc). Đặt VC_ISSUANCE_WORKER_ENABLED=false để không làm nghẽn Event Loop khi ký số. |
| 2 | gotrace-vc-worker | apps/backend (dist/src/vc-worker.main.js) | fork (1 instance + Piscina thread pool) | Headless Worker (ApplicationContext) | Background worker chuyên biệt (VcWorkerModule) lắng nghe BullMQ queue vc-issuance và vc-status, điều phối Piscina Worker Threads để ký Ed25519 W3C Verifiable Credentials cho hàng vạn SGTIN mà không ảnh hưởng latency của API chính. |
| 3 | gotrace-zalo-be | apps/zalo-be (dist/main.js) | fork (1 instance) | :3002 | Phục vụ API /api/v1/zalo/* cho Zalo MiniApp (Driver, Enterprise, Consumer) và nhận Webhook Zalo OA (/api/v1/zalo/webhook). Tích hợp sẵn VC worker cho các sự kiện phát sinh từ Zalo (SHIP, RECEIVE, SOLD). |
| 4 | gotrace-integration-gateway | apps/integration-gateway (dist/main.js) | fork (1 instance) | :3003 (Public) & 127.0.0.1:3013 (Internal) | Poll bảng integration_outbox, quản lý state của 12 National Connectors, thực thi push/pull dữ liệu qua BullMQ (integration-delivery, integration-archive, integration-callback) với Circuit Breaker và Rate Limiter riêng. |
| 5 | gotrace-frontend | apps/frontend (.next/standalone/apps/frontend/server.js) | fork (1 instance) | :3000 | Next.js 16 Standalone SSR server phục vụ giao diện Multi-brand (gotrace / hanoitrace). |
IMPORTANT
CPU Isolation Principle: Phép ký mật mã học Ed25519 trên tập lớn SGTIN (ví dụ một batch 50.000 tem) là tác vụ CPU-bound. Việc tách gotrace-vc-worker khỏi gotrace-backend (qua cờ VC_ISSUANCE_WORKER_ENABLED=false trên tiến trình API) đảm bảo response time của HTTP API luôn ổn định ngay cả khi hệ thống đang batch-sign hàng vạn W3C VC.
3. Dependency Graph giữa 6 Internal Packages (packages/*)
Rendering diagram...
@gotrace/shared-types: Chứa các contract types (IntegrationEventType,IntegrationEntityType,IntegrationErrorCode,IntegrationResultMessage...) giúpbackend,integration-gatewayvàfrontendđồng bộ tuyệt đối về kiểu dữ liệu tại compile-time.@gotrace/integration-outbox: Cung cấp hàmenqueueInTx(tx, event)được gọi ngay bên trongprisma.$transaction(...)củaapps/backend. Khi doanh nghiệp tạo/cập nhật Product (gtin), Batch (batch), Input Source (input_source)..., bản ghi nghiệp vụ và bản ghiintegration_outboxđược atomic commit trong cùng một PostgreSQL transaction.@gotrace/integration-crypto: Cung cấp cơ chế AES-256-GCM Envelope Encryption (hỗ trợ key rotationmasterKeystheokeyVersion) để bảo vệ credentials nhạy cảm trong bảngintegration_company_credentials.@gotrace/integration-client: Cung cấp internal HTTP client đểapps/backendgọi sang cổng nội bộ127.0.0.1:3013củaapps/integration-gatewaykèm header xác thựcx-internal-key.
4. BullMQ Queues & Dual Object Storage (MinIO / S3)
4.1. BullMQ Queues trên Redis
vc-issuance&vc-status(apps/backend&apps/zalo-be): Xử lý phát hành (issuance) và thu hồi/cập nhật trạng thái W3C Verifiable Credentials từ bảngvc_outbox.vc-anchor(apps/backend/src/modules/vc-anchor): Gom các VC leaves đã phát hành thành Merkle Batch và gửi giao dịch neo lên Spores Blockchain.recall-cascade(apps/backend/src/modules/batchs): Khi một batch nguyên liệu hoặc bán thành phẩm bị recall, worker tự động trace ngược/xuôi để Cascading Recall các bộ Combo (ComboAssembly) có chứa SGTIN thuộc batch đó trong SLA ≤ 60 giây (TXNG-F32).integration-delivery,integration-archive,integration-callback(apps/integration-gateway): Điều phối gửi dữ liệu ra 12 cổng quốc gia, archive HTTP request/response payload vào MinIO/S3 (integration-archive), và xử lý async webhook callback trả về.
4.2. Dual Storage Driver Architecture (STORAGE_DRIVER=minio | s3)
Hệ thống hỗ trợ 2 storage drivers qua interface IStorageService (apps/backend/src/common/interfaces/storage.interface.ts):
minio(MinioStorageService): Tự động khởi tạo bucket và gắn bucket policyPublicReadForUploadstrên prefixpublic/*. URL trả về trỏ trực tiếp tới MinIO endpoint.s3(S3StorageService+PublicFilesController): Giữ bucket ở chế độ 100% Private (tương thích AWS S3 Directory Buckets hoặc S3 chuẩn chặn public bucket). Mọi file dướipublic/*được phục vụ qua proxy route của BackendGET /api/v1/files/public/*pathvới headerCache-Control: public, max-age=31536000, immutableđể CDN/Cloudflare cache phía trước.