Skip to content

Tổng quan về các package Backend

Trang này mô tả kiến trúc backend đầy đủ của hệ thống POS BANA. Nội dung bao gồm tất cả 18 package trong thư mục packages/, cơ sở dữ liệu PostgreSQL dùng chung với 14 schema, hạ tầng event-driven (Kafka domain event + Debezium CDC; Redis cho cache, WebSocket fan-out và BullMQ), các cơ chế bảo mật, và các pattern của framework IGNIS thống nhất toàn bộ codebase.

Stack công nghệ

Phiên bản được single-source - xem Platform Facts → Stack ứng dụng (tự sinh từ overrides trong package.json gốc; lint lúc build chặn drift). Backend dựng trên IGNIS (framework DI) + Hono (HTTP) + Drizzle ORM / Zod (dữ liệu + xác thực) trên runtime Bun.


Cấu trúc hệ thống

Tất cả 18 package Backend

PackagePortVai tròTrách nhiệm chínhPhụ thuộc chính
@nx/core--Nền tảngBase class, DB model trên 14 schema, tiện ích, cấu hình xác thực--
@nx/identity31010ServiceXác thực, phân quyền, quản lý người dùng, RBACcore
@nx/commerce31020ServiceSản phẩm, engine định giá, merchant, danh mục, CDCcore, asset, inventory, search
@nx/sale31030ServiceVòng đời đơn hàng, checkout, đơn bếp, điều phối thanh toáncore, mq-pay
@nx/inventory31050ServiceTheo dõi tồn kho, đơn mua hàng, quản lý nhà cung cấpcore
@nx/finance31040ServiceVí, theo dõi thu/chi, danh mục tài chínhcore
@nx/pricing31070ServiceBộ giá, engine thuế, khuyến mãi, quy tắc định giácore
@nx/payment31080ServiceCấu hình webhook, tải thông tin xác thực, phân phối thanh toáncore, mq-pay
@nx/ledger31060ServiceTạo sổ kế toán HKD (PDF/XLSX), mã hóa, S3core
@nx/outreach31110ServiceĐăng ký nhận tin, biểu mẫu liên hệcore
@nx/licensing31120ServiceQuản lý license theo policy, ký chứng chỉ, pipeline xác thựccore
@nx/helpdesk31032ServiceHỗ trợ khách hàng đa kênh - ticket, SLA, tự phân công, cơ sở tri thức, khảo sát (build hiện đang lỗi)core
@nx/taxation31130ServiceTra cứu thông tin thuế, đơn vị hành chính VN, nhóm thuế, tích hợp T-VANcore
@nx/signal31090ServiceWebSocket với mã hóa E2E ECDH, Redis Pub/Subcore
@nx/invoice1190ServiceTạo hóa đơn điện tử (IIAPI + T-VAN), base path /v1/apicore, iiapi, t-van
@nx/search--LibraryTích hợp Typesense, chuyển đổi filter, đồng bộ CDCcore
@nx/asset--LibraryLưu trữ file Minio/đĩa, quản lý MetaLinkcore
@nx/gateway--Hạ tầngAPI gateway và Astro portal (định tuyến, BFF, portal tĩnh)core

Các package được đánh dấu -- cho cột Port hoạt động như thư viện nhúng hoặc worker hướng sự kiện thay vì dịch vụ HTTP độc lập.

Kiến trúc Package

Sơ đồ phụ thuộc khi Build

Makefile thực thi theo thứ tự build này. Một package không thể được build cho đến khi tất cả dependencies của nó đã được biên dịch xong.

Sơ đồ phụ thuộc lúc Runtime


Tham chiếu từng Package

@nx/core -- Nền tảng

Mục đích: Nhân dùng chung cung cấp base class, toàn bộ 151 model cơ sở dữ liệu trải dài 14 schema PostgreSQL, tiện ích xuyên suốt, và cấu hình xác thực. Tất cả package khác đều phụ thuộc vào @nx/core.

Các export chính:

ExportLoạiMô tả
DefaultApplicationClassBase application với auth, CORS, Swagger, health check
SoftDeletableRepositoryClassRepository với soft-delete (đặt deletedAt thay vì xóa vật lý) - re-export từ @venizia/ignis
PostgresCoreDataSourceDataSourceData source Drizzle + node-postgres dùng chung
MigrationRepositoryRepositoryTheo dõi trạng thái migration trong cơ sở dữ liệu
IdGeneratorUtilitySingleton sinh Snowflake ID
IdentityNetworkServiceServiceGọi HTTP liên dịch vụ tới dịch vụ Identity
useRequestContext()FunctionTrích xuất người dùng đã xác thực, vai trò, và bộ chuẩn hóa response
CryptoUtilityUtilityMã hóa/giải mã AES-256-GCM cho thông tin xác thực
@loggedDecoratorGhi log đo lường hiệu năng
bootstrapApplication()HelperFactory điểm vào của application
bootstrapMigration()HelperFactory điểm vào của migration
createAppConfig()HelperBộ dựng cấu hình application tập trung
createMigrationProcessLoader()HelperBộ import tiến trình migration động

Hằng số:

Hằng sốGiá trị
AppFixedRolesSUPER_ADMIN (999), ADMIN (900), OPERATOR (600), OWNER/organizer-owner (500), CASHIER (110), EMPLOYEE (100), CUSTOMER (10), GUEST (1)
MerchantTypesDEFAULT, TICKET, FNB, THEATER
PaymentProvidersVNPAY_QR_MMS, SYSTEM
InvoiceProvidersT_VAN, IIAPI

TIP

Tài liệu chi tiết: @nx/core


@nx/identity -- Xác thực và Phân quyền

Mục đích: Xác thực người dùng, phân quyền, RBAC, và quản lý nhân viên. Chạy như một dịch vụ HTTP độc lập trên cổng 31010.

Các service:

ServiceTrách nhiệm
AuthenticationServiceĐăng nhập, đăng ký, đổi mật khẩu
UserServiceTạo người dùng liền mạch (user + identifiers + profile + roles)
EmployeeServiceQuản lý nhân viên với ánh xạ organizer/merchant
MailVerificationServiceXác minh email với mã 6 chữ số và token

Chiến lược xác thực: JWT, Basic (qua IGNIS AuthenticateComponent)

Loại định danh: USERNAME, EMAIL, PHONE_NUMBER, USER_NUMBER, NX_AUTH

Giới hạn xác minh Email:

  • Mã 6 chữ số: hết hạn sau 10 phút, tối đa 3 lần thử
  • Token 32 byte: hết hạn sau 24 giờ
  • Giới hạn tốc độ: thời gian chờ 60 giây, 5 lần gửi lại/ngày, khóa 15 phút

TIP

Tài liệu chi tiết: @nx/identity


@nx/commerce -- Danh mục sản phẩm và Định giá

Mục đích: Quản lý sản phẩm, engine định giá động, đăng ký merchant, và hệ thống danh mục. Chạy trên cổng 31020. Tích hợp asset storage, inventory tracking, và Typesense search.

Các service:

ServiceTrách nhiệm
ProductServiceTạo aggregate (info, identifiers, variants)
ProductVariantServiceQuản lý variant với tích hợp định giá
FareServiceĐịnh giá tĩnh/động với đánh giá quy tắc theo ngữ cảnh
MerchantServiceĐăng ký merchant với danh mục và kênh bán hàng

Engine định giá:

Khái niệmMô tả
FareĐiểm giá với số tiền, trạng thái, kích hoạt theo thời gian
FareRuleĐiều kiện động (số lượng, ngày, ngữ cảnh tùy chỉnh)
Rule OperatorsEQ, NE, GT, GTE, LT, LTE, IN, NIN
Rule TypesOVERRIDE (dừng đánh giá), DISCOUNT, MARKUP

Các component tích hợp: ApplicationAssetComponent, ApplicationInventoryComponent, ApplicationSearchComponent, NxTVanComponent

TIP

Tài liệu chi tiết: @nx/commerce


@nx/sale -- Quản lý đơn hàng

Mục đích: Vòng đời đơn hàng từ giỏ hàng đến hoàn thành, xác thực checkout, và tích hợp thanh toán qua MQ-Pay. Chạy trên cổng 31030.

Vòng đời đơn hàng:

Các service:

ServiceTrách nhiệm
SaleOrderServiceTạo đơn, thêm item, hủy đơn
CheckoutServiceChuyển DRAFT sang PROCESSING, xác thực
SaleOrderItemServiceCập nhật item theo lô với tự động gộp
PaymentWebhookServiceXử lý callback trạng thái thanh toán MQ-Pay

Giới hạn đơn hàng: Tối đa 9,999 số lượng mỗi item. Tối đa 100 item mỗi đơn hàng.

Các component: RedisComponent (cache + BullMQ + Pub/Sub), QueueComponent, ApplicationWebSocketComponent

TIP

Tài liệu chi tiết: @nx/sale


@nx/inventory -- Quản lý kho

Mục đích: Theo dõi kho đa vị trí, xử lý đơn đặt hàng, và nhật ký kiểm toán. Hoạt động như thư viện nhúng được sử dụng bởi @nx/commerce.

Các service:

ServiceTrách nhiệm
InventoryServiceTạo/cập nhật tồn kho cho product variant
PurchaseOrderServiceQuy trình PO: DRAFT sang PROCESSING sang CONFIRMED sang COMPLETED
PurchaseOrderItemServiceQuản lý dòng item của PO

Các chỉ số kho:

TrườngÝ nghĩa
quantityOnHandTổng tồn kho vật lý
quantityAvailableTồn kho trừ đã giữ chỗ (sẵn sàng để bán)
quantityReservedĐã phân bổ cho đơn đang chờ

Loại theo dõi (20 loại đã định nghĩa sẵn):

  • Nhập kho: STOCK_IN, PURCHASE, TRANSFER_IN, RETURN_FROM_CUSTOMER, ADJUSTMENT_IN
  • Xuất kho: STOCK_OUT, SALE, TRANSFER_OUT, RETURN_TO_VENDOR, EXPIRED, LOST, DAMAGED
  • Trung lập: INVENTORY_COUNT, ADJUSTMENT_NEUTRAL

Mục đích: Tìm kiếm thời gian thực do Typesense cung cấp với chuyển đổi filter IGNIS sang query Typesense tự động. Dữ liệu chảy từ PostgreSQL qua Debezium CDC.

Các collection: products, organizers, merchants, categories, devices, sale-channels

Các service:

ServiceTrách nhiệm
SearchServiceTìm kiếm lõi với chuyển đổi filter
BaseTypesenseSearchServiceBase trừu tượng cho các triển khai tìm kiếm tùy chỉnh

Các toán tử TypesenseConverter: eq, neq, gt, gte, lt, lte, between, inq (IN), nin (NOT IN), and, or

Biến môi trường: APP_ENV_TYPESENSE_API_KEY, APP_ENV_TYPESENSE_NODES (định dạng: protocol:host:port, phân tách bằng dấu phẩy)


@nx/asset -- Lưu trữ Media

Mục đích: Lưu trữ file với 2 backend (Minio tương thích S3 + local disk) với theo dõi metadata qua entity MetaLink.

Cấu hình lưu trữ:

BackendEndpointTrường hợp sử dụng
Minio/assetsMedia tải lên (hình ảnh, tài liệu)
Local disk/resourcesTài nguyên tĩnh (template, banner)

Các trường MetaLink: bucketName, objectName, link (presigned URL), mimetype, size, etag, storageType, principalId, principalType

TIP

Tài liệu chi tiết: @nx/asset


@nx/finance -- Theo dõi tài chính

Mục đích: Theo dõi thu/chi với quản lý ví. Hướng sự kiện -- lắng nghe các sự kiện commerce và payment để tự động tạo bản ghi tài chính.

Các service:

ServiceTrách nhiệm
FinanceWorkerServiceBộ xử lý sự kiện và hàng đợi cho mọi nghiệp vụ tài chính

Các phương thức FinanceWorkerService:

Phương thứcKích hoạtHành động
handleCommerceInitialized()Sự kiện COMMERCE_INITIALIZEDTạo ví Cash mặc định cho merchant mới
handlePaymentSuccess()Sự kiện PAYMENT_SUCCESSTạo giao dịch INCOME
handlePurchaseOrderReceived()Job hàng đợi PURCHASE_ORDER_RECEIVEDTạo giao dịch EXPENSE

Loại ví: CASH, BANK, EWALLET, CREDIT_CARD

Loại giao dịch: INCOME, EXPENSE, TRANSFER

Các controller:

ControllerPathLoại
FinanceWalletController/finance-walletsControllerFactory CRUD
FinanceCategoryController/finance-categoriesControllerFactory CRUD
FinanceTransactionController/finance-transactionsControllerFactory CRUD

@nx/payment -- Điều phối thanh toán

Mục đích: Lớp cầu nối giữa MQ-Pay và ứng dụng. Quản lý cấu hình webhook, tải và giải mã thông tin xác thực thanh toán, và phân phối sự kiện webhook với logic retry.

Các service:

ServiceTrách nhiệm
PaymentConfigurationServiceLấy và giải mã cấu hình thanh toán từ bảng Configuration
WebhookDispatcherServicePhân phối webhook fire-and-forget với exponential backoff

Các controller:

ControllerPathLoại
WebhookConfigController/webhook-configsControllerFactory CRUD

Nhà cung cấp được hỗ trợ: VNPAY_QR_MMS, VNPAY_PHONE_POS

Migration seed: payment-0001-seed-vnpay-qr-mms-configuration, payment-0002-seed-vnpay-phone-pos-configuration

TIP

Tài liệu chi tiết: @nx/payment


@nx/signal -- Dịch vụ WebSocket

Mục đích: Giao tiếp thời gian thực tập trung với mã hóa đầu cuối. Stateless (không có database, không có migration). Sử dụng Redis Pub/Sub để phân phối message giữa các instance.

Các service:

Phương thứcMô tả
broadcast({ topic, data })Gửi tới tất cả client đang kết nối trên mọi instance
sendToRoom({ room, topic, data })Gửi tới tất cả client trong một room
sendToClient({ clientId, topic, data })Gửi tới một client cụ thể (cục bộ hoặc từ xa qua Redis)
disconnectClient({ clientId })Buộc đóng kết nối của một client

REST API (base: /socket/websocket/clients):

MethodPathAuthMô tả
GET/statusNoneSẵn sàng server + số lượng client
GET/JWT/BasicLiệt kê client đang kết nối
POST/broadcastJWT/BasicPhát sóng tới tất cả client
POST/rooms/:roomName/sendJWT/BasicGửi tới một room
POST/:clientId/sendJWT/BasicGửi tới client cụ thể
POST/:clientId/disconnectJWT/BasicNgắt kết nối một client

Mã hóa: Trao đổi khóa ECDH P-256, mã hóa AES-256-GCM theo từng message. WebSocket endpoint: /stream.

Chế độ Redis: Single instance (mặc định) hoặc Cluster mode qua APP_ENV_WEBSOCKET_REDIS_MODE.

TIP

Tài liệu chi tiết: @nx/signal


@nx/invoice -- Tạo hóa đơn điện tử

Mục đích: Tích hợp hóa đơn điện tử Việt Nam thông qua IIAPI (VNPAY viiAPI) và nhà cung cấp T-VAN. Hỗ trợ hóa đơn GTGT, hóa đơn bán hàng, hóa đơn POS, v.v.

Phụ thuộc: @nx/core, @nx/iiapi (third-party), @nx/t-van (third-party)

TIP

Tài liệu chi tiết: @nx/invoice


Kiến trúc phân lớp

Mọi dịch vụ backend đều tuân theo pattern Controller-Service-Repository được thực thi bởi framework IGNIS.

LớpTrách nhiệmIGNIS Base Class
ControllerVận chuyển HTTP, xác thực đầu vào qua Zod, định dạng responseControllerFactory.defineCrudController() hoặc tùy chỉnh
ServiceLogic nghiệp vụ thuần, điều phối, xử lý sự kiệnBaseService
RepositoryTrừu tượng truy cập cơ sở dữ liệu, query Drizzle ORMSoftDeletableRepository hoặc DefaultCRUDRepository
ComponentMối quan tâm xuyên suốt: Redis, queue, tích hợp bên ngoàiBaseComponent
DataSourcePool kết nối và thiết lập connector DrizzleBaseDataSource

Luồng request

1. HTTP Request --> Controller (route handler)
2. Controller validates input with Zod schemas via @hono/zod-openapi
3. Controller calls Service layer via DI
4. Service executes business logic
5. Service calls Repository for data access
6. Repository executes Drizzle ORM queries against PostgreSQL
7. Response flows back through layers

Tổng quan cơ sở dữ liệu

Tất cả model cơ sở dữ liệu được định nghĩa trong @nx/core dưới src/models/schemas/. Các service dùng chung một kết nối PostgresCoreDataSource.

14 schema PostgreSQL, 151 entity

SchemaModelsSố lượngEntity chính
helpdeskHỗ trợ khách hàng30Agent, AgentGroup, AgentGroupMember, Article, ArticleCategory, AssignmentRule, SlaEscalation, Notification, NotificationTemplate, FeatureRequest, Compensation, v.v.
publicMiền tổng quát26Product, ProductInfo, ProductIdentifier, ProductVariant, ProductOption, Merchant, Organizer, Category, Device, SaleChannel, Configuration, Setting, MetaLink, ReceiptTemplate, WebhookConfig, v.v.
inventoryQuản lý kho17InventoryItem, InventoryLocation, InventoryStock, InventoryTracking, Material, MaterialRecipe, PurchaseOrder, PurchaseOrderItem, ProductionOrder, UnitOfMeasure, Vendor, VendorItem, v.v.
saleĐơn hàng21SaleOrder, SaleItem, SaleCheck, SaleCheckItem, Customer, KitchenStation, KitchenTicket, KitchenTicketItem, PointTransaction, PosSession, PosSessionReport, Reservation, EntitlementPolicy, v.v.
invoiceHóa đơn điện tử9Invoice, InvoiceIssuance, InvoiceRequest, InvoiceProvider, InvoiceProviderConfig, InvoiceAuditTracing, InvoiceConfigMapping, MerchantInvoiceProfile, MerchantProfileEnrollment
pricingEngine định giá9Fare, FareSet, Cost, Promotion, PromotionMethod, Rule, Tax, TaxSet, TaxType
identityXác thực & người dùng8User, UserCredential, UserIdentifier, UserProfile, UserConfiguration, Role, Permission, PolicyDefinition
ledgerSổ kế toán HKD8Ledger, LedgerIdentifier, LedgerJob, LedgerSnapshot, LedgerSnapshotEntry, LedgerTaxConfig, MerchantTaxConfig, TaxTier
financeTheo dõi tài chính6FinanceAccount, FinanceCategory, FinanceTransaction, FinanceVoucher, FinanceVoucherSequence, PaymentIntegration
taxThuế & hành chính VN6TaxGroup, TaxGroupItem, TaxInfo, VnAdministrativeUnit, VnProvince, VnWard
licensingQuản lý license5Activation, License, LicenseEvent, Policy, PolicyFeature
allocationXếp chỗ sự kiện4AllocationLayout, AllocationUnit, AllocationUsage, AllocationZone
outreachNgười đăng ký2Inquiry, Subscriber
paymentNamespace dự trữ0-

Pattern Soft-Delete

Tất cả entity có thể xóa đều sử dụng SoftDeletableRepository từ @nx/core. Thay vì xóa vật lý, một timestamp deletedAt được đặt. Bản ghi có thể khôi phục bằng restoreById().

typescript
// Schema includes deletedAt column
deletedAt: (timestamp('deleted_at', { withTimezone: true }),
  // Repository extends SoftDeletableRepository
  @repository({ dataSource: PostgresCoreDataSource, model: Category })
  export class CategoryRepository extends SoftDeletableRepository<
    typeof Category.schema,
    TCategory,
    TCategoryPersist
  > {});

// deleteById sets deletedAt instead of removing the row
// restoreById sets deletedAt back to null
// Pass { shouldHardDelete: true } for physical deletion

Kiến trúc hướng sự kiện

Hệ thống sử dụng hai pattern messaging bổ sung cho nhau: Redis Pub/Sub cho phát sóng sự kiện thời gian thực và BullMQ cho xử lý job bất đồng bộ đáng tin cậy.

Các kênh Redis Pub/Sub

ChannelPublisherSubscribersMục đích
PaymentSuccessPayment / SaleFinanceGhi nhận giao dịch thu khi thanh toán thành công
SellerRegisteredIdentityCommerceKhởi tạo mặc định merchant khi người bán đăng ký mới
CommerceInitializedCommerceFinanceTạo ví Cash mặc định cho merchant mới

Hệ thống hàng đợi BullMQ

Mỗi loại hàng đợi sử dụng 3 partition (P01, P02, P03) để phân phối tải.

PackageLoại hàng đợiMục đích
Commerce3 loạiĐánh chỉ mục sản phẩm, đồng bộ danh mục, thiết lập merchant
Finance2 loạiPURCHASE_ORDER_RECEIVED (ghi nhận chi phí), xử lý giao dịch
Inventory1 loạiXử lý điều chỉnh tồn kho
Sale2 loạiLập lịch hết hạn đơn hàng, xác nhận thanh toán
MQ-Pay2 loại (scheduler, confirmation)Hết hạn lần thử thanh toán, xác nhận IPN/webhook

Ví dụ luồng sự kiện


Bảo mật

Xác thực và Phân quyền

Cơ chếVị tríMô tả
JWT AuthenticationDefaultApplication.configureSecurity()Xác thực dựa trên token cho truy cập API
Basic AuthenticationDefaultApplication.configureSecurity()Username/password qua IdentityNetworkService
bcrypt Hashing@nx/identityLưu mật khẩu với bcrypt (^6.0.0)
Role-Based AccessTất cả controller8 vai trò cố định với mức ưu tiên số

Các vai trò mặc định

Vai tròPhạm vi
SUPER_ADMIN999Toàn quyền hệ thống
ADMIN900Vận hành quản trị
OPERATOR600Quản lý vận hành
OWNER (organizer-owner)500Truy cập theo phạm vi organizer
CASHIER110Thu ngân / nhân viên POS
EMPLOYEE100Truy cập theo phạm vi nhân viên
CUSTOMER10Khách hàng cuối
GUEST1Chưa xác thực / toàn cục

Mã hóa

Cơ chếThuật toánSử dụng
WebSocket E2EECDH P-256 + AES-256-GCMPackage Signal -- dẫn xuất khóa theo client
Credential StorageAES-256-GCMCryptoUtility -- bí mật nhà cung cấp thanh toán
Password HashingbcryptPackage Identity -- thông tin xác thực người dùng

Các pattern của IGNIS Framework

Vòng đời Application

Mọi service mở rộng DefaultApplication cung cấp xác thực, CORS, Swagger, và cấu hình health check sẵn có.

typescript
// packages/sale/src/application.ts
import {
  createAppConfig,
  VerifierApplication,
  MigrationRepository,
  PostgresCoreDataSource,
} from '@nx/core';
import { CoreBindings, IApplicationInfo } from '@venizia/ignis';

export const appConfig = createAppConfig();

export class Application extends VerifierApplication {
  override getAppInfo(): IApplicationInfo {
    return {
      name: '@nx/sale',
      version: '0.0.0',
      description: 'Sale order management with payment integration',
      author: { name: 'Nexpando', email: 'contact@nexpando.com' },
    };
  }

  override getProjectRoot(): string {
    const projectRoot = __dirname;
    this.bind<string>({ key: CoreBindings.APPLICATION_PROJECT_ROOT }).toValue(projectRoot);
    return projectRoot;
  }

  override configureComponents(): void {
    super.configureComponents(); // HealthCheck + Swagger + Auth
    this.component(RedisComponent);
    this.component(QueueComponent);
  }

  override preConfigure(): void {
    super.preConfigure();
    this.dataSource(PostgresCoreDataSource);
    this.repository(SaleOrderRepository);
    this.service(SaleOrderService);
    this.service(CheckoutService);
    this.controller(SaleOrderController);
  }
}

Bootstrap Helper

Điểm vào của application và migration được chuẩn hóa qua các hàm helper của @nx/core.

typescript
// packages/sale/src/index.ts -- Application entry point
import { bootstrapApplication } from '@nx/core';
import { resolve } from 'node:path';
import { appConfig, Application } from './application';

bootstrapApplication({
  ApplicationClass: Application,
  config: appConfig,
  options: { bannerPath: resolve(process.cwd(), 'resources/banner.txt') },
});
typescript
// packages/sale/src/migrations/processes/migration-process.ts
import { createMigrationProcessLoader } from '@nx/core';

export const getMigrationProcesses = createMigrationProcessLoader({
  seedPaths: ['sale-0001-seed-data', 'sale-0002-seed-channels'],
  importFn: path => import(`../processes/${path}.js`),
});

Dependency Injection

IGNIS sử dụng constructor injection với decorator @inject(). Binding key tuân theo quy ước namespace.ClassName.

typescript
// Service with repository injection
import { BaseService, BindingKeys, BindingNamespaces, inject } from '@venizia/ignis';

export class CheckoutService extends BaseService {
  constructor(
    @inject({
      key: BindingKeys.build({
        namespace: BindingNamespaces.REPOSITORY,
        key: SaleOrderRepository.name,
      }),
    })
    private readonly _saleOrderRepository: SaleOrderRepository,

    @inject({
      key: BindingKeys.build({
        namespace: BindingNamespaces.SERVICE,
        key: SaleSocketEventService.name,
      }),
    })
    private readonly _saleSocketEventService: SaleSocketEventService,
  ) {
    super({ scope: CheckoutService.name });
  }
}

Helper BindingKeys.build() tạo ra key như repositories.SaleOrderRepositoryservices.SaleSocketEventService. Bạn cũng có thể viết binding key dưới dạng chuỗi thuần:

typescript
@inject({ key: 'repositories.SaleOrderRepository' })
private readonly saleOrderRepository: SaleOrderRepository,

Pattern Component

Component đóng gói các mối quan tâm xuyên suốt (Redis, queue, dịch vụ bên ngoài) và đăng ký binding trong hook vòng đời binding().

typescript
import { BaseApplication, BaseComponent, CoreBindings, inject, RedisHelper } from '@venizia/ignis';

export class RedisComponent extends BaseComponent {
  constructor(
    @inject({ key: CoreBindings.APPLICATION_INSTANCE })
    protected application: BaseApplication,
  ) {
    super({
      scope: RedisComponent.name,
      initDefault: { enable: true, container: application },
      bindings: {},
    });
  }

  override async binding(): Promise<void> {
    const cacheRedis = new RedisHelper({ name: 'cache-redis', host: 'localhost', port: 6379 });
    await cacheRedis.connect();
    this.application.bind({ key: BindingKeys.APPLICATION_REDIS_CACHE }).toValue(cacheRedis);
  }
}

ControllerFactory (Auto CRUD)

ControllerFactory.defineCrudController() tạo một controller CRUD đầy đủ với tài liệu OpenAPI, xác thực, và các endpoint REST chuẩn.

typescript
import {
  ControllerFactory,
  controller,
  inject,
  BindingKeys,
  BindingNamespaces,
} from '@venizia/ignis';

const _Controller = ControllerFactory.defineCrudController({
  repository: { name: FinanceWalletRepository.name },
  authenticate: { strategies: ['jwt', 'basic'] },
  controller: {
    name: 'FinanceWalletController',
    basePath: '/finance-wallets',
    isStrict: { path: true, requestSchema: true },
  },
  entity: () => FinanceWallet,
});

@controller({ path: '/finance-wallets' })
export class FinanceWalletController extends _Controller {
  constructor(
    @inject({
      key: BindingKeys.build({
        key: FinanceWalletRepository.name,
        namespace: BindingNamespaces.REPOSITORY,
      }),
    })
    financeWalletRepository: FinanceWalletRepository,
  ) {
    super(financeWalletRepository);
  }

  // Override individual methods for custom logic (role-based filtering, etc.)
  @logged()
  override async findById(opts: { context: TRouteContext<Env> }) {
    // Custom implementation...
  }
}

Database Transaction

Repository hỗ trợ các thao tác giao dịch thông qua data source.

typescript
await this.repository.dataSource.withTransaction(async tx => {
  await this.repository.create({ data: orderData, options: { transaction: tx } });
  await this.itemRepository.create({ data: itemData, options: { transaction: tx } });
});

Cấu hình môi trường

Tất cả package sử dụng dotenv-flow để quản lý môi trường. Các biến tuân theo quy ước tiền tố APP_ENV_*.

Các file môi trường

FileMục đíchGit theo dõi
.env.exampleTemplate với tất cả biến bắt buộc
.env.developmentCài đặt development
.env.testMôi trường test
.env.localGhi đè cục bộKhông (gitignored)

Biến môi trường phổ biến

bash
# Application
APP_ENV_NODE_ENV=development
APP_ENV_APPLICATION_NAME=nx-sale
APP_ENV_APPLICATION_SECRET=<secret>
APP_ENV_SERVER_HOST=0.0.0.0
APP_ENV_SERVER_PORT=31030
APP_ENV_SERVER_BASE_PATH=/api

# Authentication
APP_ENV_JWT_SECRET=<jwt-secret>
APP_ENV_JWT_EXPIRES_IN=3600

# PostgreSQL
APP_ENV_POSTGRES_HOST=localhost
APP_ENV_POSTGRES_PORT=5432
APP_ENV_POSTGRES_DATABASE=bana
APP_ENV_POSTGRES_USERNAME=postgres
APP_ENV_POSTGRES_PASSWORD=password

# Redis (Cache)
APP_ENV_CACHE_REDIS_HOST=localhost
APP_ENV_CACHE_REDIS_PORT=6379
APP_ENV_CACHE_REDIS_DB=0

# Redis (BullMQ Queues)
APP_ENV_BULLMQ_REDIS_HOST=localhost
APP_ENV_BULLMQ_REDIS_PORT=6379
APP_ENV_BULLMQ_REDIS_DB=1

# Redis (Pub/Sub)
APP_ENV_PUBSUB_SUBSCRIBER_REDIS_HOST=localhost
APP_ENV_PUBSUB_PUBLISHER_REDIS_HOST=localhost

# Minio (Assets)
APP_ENV_MINIO_HOST=localhost
APP_ENV_MINIO_API_PORT=9000
APP_ENV_MINIO_ACCESS_KEY=minioadmin
APP_ENV_MINIO_SECRET_KEY=minioadmin

# Typesense (Search)
APP_ENV_TYPESENSE_API_KEY=xyz
APP_ENV_TYPESENSE_NODES=http:localhost:8108

# Snowflake ID
APP_ENV_SNOWFLAKE_WORKER_ID=1
APP_ENV_SNOWFLAKE_EPOCH_CHECKPOINT=1704067200000

# Service URLs
APP_ENV_IDENTITY_SERVICE_URL=http://localhost:31010
APP_ENV_COMMERCE_SERVICE_URL=http://localhost:31020

Quy trình phát triển

Lệnh build

LệnhMô tả
make installCài đặt tất cả dependencies (bun install)
make buildBuild mọi thứ theo thứ tự phụ thuộc
make build-packagesChỉ build packages/*
make build-3rdChỉ build third-parties/*
make coreBuild @nx/core
make saleBuild @nx/sale
make commerceBuild @nx/commerce
make identityBuild @nx/identity
make financeBuild @nx/finance
make paymentBuild @nx/payment
make signalBuild @nx/signal

WARNING

Luôn sử dụng bun run rebuild trong một package. Không chạy tsc trực tiếp -- path alias (@/common, @/services) yêu cầu bước xử lý sau tsc-alias.

Development Server

LệnhServicePort
make dev-saleSale service31030
make dev-commerceCommerce service31020
make dev-identityIdentity service31010
make dev-financeFinance service31040
make dev-paymentPayment service31080
make dev-signalSignal (WebSocket)31090

Lệnh từng package

bash
cd packages/sale            # Navigate to package
bun run rebuild             # Clean + build (tsc + tsc-alias)
bun run server:dev          # Start with .env.development
bun run test                # Run tests (requires .env.test)
bun run test:watch          # Watch mode
bun run lint:fix            # ESLint + Prettier auto-fix
bun run migrate:dev         # Apply database migrations

Test

bash
# Run all tests for a package
cd packages/sale && bun run rebuild && bun run test

# Run a single test file
bun test --env-file=.env.test dist/__tests__/path/to/file.test.js

Lint

LệnhPhạm vi
make lintMọi thứ
make lint-packagesTất cả package
make lint-3rdTất cả third-party
make lint-saleChỉ @nx/sale
make lint-financeChỉ @nx/finance
make lint-paymentChỉ @nx/payment
make lint-signalChỉ @nx/signal

Git Hook

bash
make setup-tools    # Configure git to use .githooks directory
make pre-commit     # Run all linting checks (used by pre-commit hook)

Tiêu chuẩn API

Quy ước route

MethodMẫuMục đích
GET/resourcesLiệt kê với lọc, phân trang
GET/resources/:idLấy một resource
GET/resources/countĐếm resource khớp
POST/resourcesTạo resource
PUT/resources/:idCập nhật toàn bộ
PATCH/resources/:idCập nhật một phần
DELETE/resources/:idSoft delete (đặt deletedAt)

Tài liệu OpenAPI

Mỗi service cung cấp tài liệu Swagger/OpenAPI:

  • OpenAPI JSON: /doc/openapi.json
  • Scalar Explorer: /doc/explorer
  • Health Check: /health

Liên kết nhanh

Tài liệu package

PackageLiên kết
@nx/coreKiến trúc, component, cấu hình, cơ sở dữ liệu, tiện ích
@nx/identityXác thực, phân quyền, quản lý người dùng
@nx/commerceSản phẩm, định giá, merchant
@nx/saleĐơn hàng, checkout, thanh toán
@nx/paymentCấu hình webhook, điều phối thanh toán
@nx/signalWebSocket, mã hóa, nhắn tin thời gian thực
@nx/assetLưu trữ file, quản lý MetaLink
@nx/invoiceTạo hóa đơn điện tử
API GatewayĐịnh tuyến và middleware của Gateway

Tham khảo bên ngoài

Tài nguyênLiên kết
IGNIS Frameworkhttps://venizia-ai.github.io/ignis/
Honohttps://hono.dev
Drizzle ORMhttps://orm.drizzle.team
Zodhttps://zod.dev
BullMQhttps://docs.bullmq.io
Typesensehttps://typesense.org/docs

Proprietary and Confidential. Unauthorized copying, distribution, or use of this software is strictly prohibited.