Skip to content

Kien truc Core

1. Tong quan

@nx/core trien khai kien truc phan lop duoc xay dung tren nen IGNIS Framework. Moi microservice backend trong monorepo BANA deu mo rong DefaultApplication tu goi nay, ke thua mot tap hop nhat quan cac moi quan tam co so ha tang: xac thuc, CORS, kiem tra suc khoe, tai lieu Swagger, ket noi co so du lieu, va giao tiep lien dich vu.

Tai lieu nay bao gom:

  • Kien truc phan lop va cach cac primitive IGNIS anh xa toi tung lop
  • Vong doi ung dung va lop DefaultApplication
  • Cac mau dependency injection
  • Cac mau component, controller, repository, va service
  • Kien truc huong su kien (Redis Pub/Sub + hang doi BullMQ)
  • Bootstrap helper cho diem truy cap ung dung va migration
  • Giao tiep lien dich vu thong qua IdentityNetworkService
  • Luong xac thuc (JWT + Basic)
  • Chuoi phu thuoc goi

2. Kien truc Phan lop

Tat ca dich vu backend deu tuan theo kien truc nam lop. Moi lop co mot trach nhiem duy nhat va chi giao tiep voi cac lop lan can truc tiep.

LopThanh phanMo ta
ApplicationDefaultApplicationVong doi preConfigure() · CORS · BodyLimit 100 MB · Swagger Scalar
Bootstrap HelpersbootstrapApplication() · bootstrapMigration() · createAppConfig() · createMigrationProcessLoader()
Built-in ComponentsHealthCheck GET /health · Swagger Scalar /explorer · Xac thuc JWT stateless · Basic → Identity
Package ComponentsSignal · Payment · Commerce · Finance · Inventory · Search · Asset
ServiceBusiness ServicesLogic nghiep vu · Validation · Dieu phoi
IdentityNetworkServicesignIn() HTTP → Identity service · Uy quyen xac thuc Basic lien dich vu
Event HandlersRedis Pub/Sub — Kenh Payment · Onboarding · IEventBus · RedisPubSubAdapter
Queue ConsumersBullMQ — 4 he thong · 8 loai · 3 phan vung · Commerce · Finance · Inventory · Sale
BaseSocketEventServicebroadcast() · sendToRoom() · sendToClient() · Phan phoi lien instance qua Redis
RepositorySoftDeletableRepositoryXoa mem · Khoi phuc · Bo loc mac dinh deletedAt IS NULL tu dong ap dung
DefaultCRUDRepositoryfind · create · updateById · deleteById · count · withTransaction
InfrastructurePostgresCoreDataSourceDrizzle ORM · node-postgres Pool · 7 schema · 55 model
RedisConnectionFactoryCache · Pub/Sub · WebSocket · Che do Single · Che do Cluster
BullMQScheduler · Confirmation · Processing · 12 hang doi voi dinh tuyen phan vung hash
LopLop Co so IGNISTrach nhiem
ApplicationBaseApplicationQuan ly vong doi, thiet lap middleware, goc DI container
ComponentBaseComponentDang ky module tinh nang (repository, service, controller)
ServiceBaseServiceLogic nghiep vu, dieu phoi giao dich, giao tiep ben ngoai
RepositoryDefaultCRUDRepositoryTruu tuong truy cap du lieu, thao tac CRUD, xoa mem
DataSourceBaseDataSourceCau hinh driver co so du lieu, quan ly connection pool

3. Vong doi Ung dung

3.1 DefaultApplication

Moi dich vu backend deu mo rong DefaultApplication, lop nay lai mo rong IGNIS BaseApplication. No cung cap luong khoi tao co cau truc thong qua phuong thuc vong doi preConfigure().

typescript
export class DefaultApplication extends BaseApplication {
  protected applicationRoles: string[] = [];

  preConfigure() {
    this.applicationRoles = this.getApplicationRoles();

    this.configureDatasources();
    this.configureRepositories();
    this.configureServices();
    this.configureComponents();
    this.configureSecurity();
    this.configureControllers();
  }

  async postConfigure() {
    // Runs after all components are bound
  }
}

3.2 Trinh tu Vong doi

So do sau day cho thay toan bo trinh tu khoi dong, tu diem truy cap (index.ts) toi server HTTP dang chay.

3.3 Thu tu Phuong thuc preConfigure()

Thu tu goi phuong thuc ben trong preConfigure() la quan trong. Moi buoc phu thuoc vao buoc truoc da hoan thanh.

Thu tuPhuong thucChuc nang
1configureDatasources()Dang ky pool ket noi PostgreSQL (mac dinh khong lam gi, datasource tu dong phat hien tu glob)
2configureRepositories()Dang ky cac lop repository vao DI container (mac dinh khong lam gi, repository tu dong phat hien tu glob)
3configureServices()Dang ky IdentityNetworkService cho xac thuc lien dich vu
4configureComponents()Bind HealthCheckComponent tai /health va SwaggerComponent tai /doc
5configureSecurity()Cau hinh chien luoc xac thuc JWT va Basic thong qua AuthenticateComponent
6configureControllers()Dang ky HTTP controller (mac dinh khong lam gi, duoc ghi de theo tung goi)

3.4 Thiet lap Middleware

setupMiddlewares() cau hinh hai middleware Hono toan cuc:

MiddlewareCau hinh
CORSOrigin: *, tat ca phuong thuc, 86400s max-age, credentials duoc bat
Body LimitToi da 100 MB, tra ve 413 Content Too Large khi vuot qua

3.5 Ghi de trong Cac Goi Downstream

Moi dich vu backend tao lop Application rieng mo rong DefaultApplication va ghi de cac phuong thuc configure tuong ung:

typescript
// packages/sale/src/application.ts
export class Application extends DefaultApplication {
  override preConfigure(): void {
    this.configureServices();
    this.configureComponents();
    this.configureSecurity();
  }

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

  override async postConfigure(): Promise<void> {
    // Package-specific post-boot logic
  }
}

4. Dependency Injection

DI container cua IGNIS su dung constructor injection voi decorator @inject(). Cac phu thuoc duoc xac dinh bang khoa binding dua tren chuoi.

4.1 Mau Injection

typescript
import { inject, BaseService } from '@venizia/ignis';

export class SaleOrderService extends BaseService {
  constructor(
    @inject({ key: 'repositories.SaleOrderRepository' })
    private saleOrderRepository: SaleOrderRepository,

    @inject({ key: 'repositories.SaleOrderItemRepository' })
    private saleOrderItemRepository: SaleOrderItemRepository,
  ) {
    super({ scope: SaleOrderService.name });
  }
}

4.2 Quy uoc Khoa Binding

Khoa binding tuan theo mau {namespace}.{ClassName}:

NamespaceKhoa Vi duDang ky Thong qua
repositoriesrepositories.SaleOrderRepositorythis.application.repository(SaleOrderRepository)
servicesservices.IdentityNetworkServicethis.application.service(IdentityNetworkService)
controllerscontrollers.SaleOrderControllerthis.application.controller(SaleOrderController)
datasourcesdatasources.PostgresCoreDataSourcethis.application.datasource(PostgresCoreDataSource)

Ban cung co the xay dung khoa tuong minh su dung tien ich BindingKeys cua IGNIS:

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

const key = BindingKeys.build({
  namespace: BindingNamespaces.REPOSITORY,
  key: 'SaleOrderRepository',
});
// Result: 'repositories.SaleOrderRepository'

4.3 Value Binding

Doi voi cac doi tuong cau hinh, su dung mau bind().toValue():

typescript
this.bind<IHealthCheckOptions>({
  key: HealthCheckBindingKeys.HEALTH_CHECK_OPTIONS,
}).toValue({
  restOptions: { path: '/health' },
});

5. Mau Component

Component la co che chinh de to chuc cac module tinh nang. Moi component mo rong BaseComponent va dang ky cac repository, service, va controller trong phuong thuc vong doi binding().

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

  override async binding(): Promise<void> {
    this.application.repository(SaleOrderRepository);
    this.application.repository(SaleOrderItemRepository);

    this.application.service(SaleOrderService);
    this.application.service(CheckoutService);

    this.application.controller(SaleOrderController);
  }
}

Component duoc dang ky vao ung dung thong qua:

typescript
this.component(ApplicationSaleComponent);

5.1 To hop Component

Component co the tai cac component khac, tao cay to hop:

6. Mau Controller

6.1 ControllerFactory (CRUD Tu dong)

IGNIS ControllerFactory tao ra day du cac endpoint CRUD tu mot khai bao duy nhat. Day la mau chuan cho hau het cac controller trong BANA.

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

@controller({ path: '/sale-orders' })
export class SaleOrderController extends ControllerFactory.defineCrudController({
  repository: { name: SaleOrderRepository.name },
  authenticate: { strategies: ['jwt', 'basic'] },
  controller: { name: 'SaleOrderController', basePath: '/sale-orders' },
  entity: () => SaleOrderEntity,
}) {
  constructor(
    @inject({ key: 'repositories.SaleOrderRepository' })
    repository: SaleOrderRepository,
  ) {
    super(repository);
  }
}

Factory tao ra cac endpoint sau:

Phuong thucDuong danMo ta
GET/sale-ordersDanh sach voi bo loc, phan trang, sap xep
GET/sale-orders/:idTim theo ID
GET/sale-orders/countDem theo bo loc
POST/sale-ordersTao moi
PUT/sale-orders/:idCap nhat theo ID
DELETE/sale-orders/:idXoa theo ID (xoa mem)

6.2 Endpoint Controller Tuy chinh

Cac endpoint bo sung duoc dinh nghia cung voi cac endpoint do factory tao bang cach them phuong thuc vao lop controller. He thong Bo loc cua IGNIS co san tren tat ca endpoint list/count.

7. Repository va SoftDeletableRepository

7.1 Khai bao Repository

Repository duoc khai bao voi decorator @repository, lien ket model voi datasource:

typescript
import { repository } from '@venizia/ignis';
import { PostgresCoreDataSource } from '@nx/core';

@repository({ dataSource: PostgresCoreDataSource, model: SaleOrderEntity })
export class SaleOrderRepository extends SoftDeletableRepository<
  TSaleOrderSchema,
  TSaleOrder,
  TSaleOrderPersist
> {}

7.2 SoftDeletableRepository

Tat ca repository BANA deu mo rong SoftDeletableRepository thay vi DefaultCRUDRepository. Dieu nay dam bao rang cac thao tac DELETE dat dau thoi gian deletedAt thay vi xoa vat ly cac dong.

Phuong thucHanh vi
deleteById(id)Dat deletedAt = NOW() thay vi DELETE FROM
restoreById(id)Dat deletedAt = NULL de khoi phuc xoa mem
find(filter)Tu dong loai tru cac dong co deletedAt IS NOT NULL

7.3 Giao dich Co so Du lieu

Repository cung cap datasource de ho tro giao dich:

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

7.4 PostgresCoreDataSource

Datasource dung chung su dung node-postgres voi Drizzle ORM. No tu dong phat hien model tu cac binding @repository thong qua getSchema():

typescript
@datasource({ driver: 'node-postgres' })
export class PostgresCoreDataSource extends BaseDataSource<IPostgresDataSourceSettings> {
  override configure(): void {
    const schema = this.getSchema(); // Auto-discovers @repository models
    this.pool = new Pool(this.settings);
    this.connector = drizzle({ client: this.pool, schema });
  }
}

Tat ca goi backend deu re-export PostgresCoreDataSource tu datasources/index.ts cuc bo, de repository luon tham chieu toi cung datasource dung chung.

8. Kien truc Huong Su kien

BANA su dung hai he thong su kien bo sung cho giao tiep bat dong bo giua cac dich vu:

Co cheCong ngheTruong hop Su dungPhan phoi
Event BusRedis Pub/SubThong bao thoi gian thuc giua cac dich vu dang chayAt-most-once, fire-and-forget
Hang doi Cong viecBullMQ (Redis)Xu ly tac vu bat dong bo dang tin cay voi thu laiAt-least-once, voi thu lai va luu tru

8.1 So do Luong Su kien

8.2 Event Bus (Redis Pub/Sub)

RedisPubSubAdapter trien khai giao dien IEventBus duoc dinh nghia trong @nx/core. No bao boc thong diep trong phong bi chuan hoa:

typescript
interface IEventBusMessage<T> {
  id: string;          // Snowflake ID
  type: string;        // Channel name
  publishedAt: string; // ISO timestamp
  data: T;             // Event payload
}

Kenh Su kien duoc dinh nghia trong @nx/core:

KenhNha phat hanhNguoi tieu thuKich hoat
payment.order.successSale ServiceFinance, InventoryThanh toan hoan tat
user.seller.registeredIdentity ServiceCommerce ServiceDang ky nguoi ban
commerce.initializedCommerce ServiceFinance, InventoryHoan tat onboarding merchant

8.3 Hang doi Cong viec (BullMQ)

Moi mien hang doi su dung 3 phan vung (P01, P02, P03) de phan phoi tai. Bo chon phan vung dua tren hash dinh tuyen cong viec toi phan vung cu the dua tren khoa (thuong la ID thuc the).

Dinh nghia Hang doi trong @nx/core:

Mien Hang doiLoai Hang doiNha san xuatNguoi tieu thu
Commerceseller-registeredIdentityCommerce
Commercecommerce-initialized-for-financeCommerceFinance
Commercecommerce-initialized-for-inventoryCommerceInventory
Financepurchase-order-receivedInventoryFinance
Financesale-order-completedSaleFinance
Salepayment-success-for-financeSaleFinance
Salepayment-success-for-inventorySaleInventory
Inventoryproduct_variant_createdCommerceInventory

Quy uoc dat ten hang doi theo mau: @nx/{package}/{queue-type}/{partition}

Vi du: @nx/sale/payment-success-for-finance/01

8.4 Su kien WebSocket

@nx/core cung cap cac lop tien ich de xay dung dinh danh phong va chu de WebSocket, duoc su dung boi dich vu Signal:

Tien ichDinh dangVi du
WebSocketRooms.build()wr:{prefix}/{paths}wr:observation/merchants/abc-123
WebSocketTopics.build()ws:{paths joined by .}ws:observation.sale.sale-order

9. Bootstrap Helper

@nx/core cung cap hai ham bootstrap chuan hoa diem truy cap tren tat ca cac goi. Xem tham chieu Bootstrapping cua IGNIS cho cac khai niem framework co so.

9.1 Bootstrap Ung dung

Duoc su dung trong src/index.ts cua moi goi de khoi dong HTTP server:

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

bootstrapApplication({
  ApplicationClass: Application,
  config: appConfig,
  options: { bannerPath: resolve(__dirname, '../resources/banner.txt') },
});

Trinh tu bootstrap la: new Application() --> init() --> boot() --> start().

9.2 Bootstrap Migration

Duoc su dung trong src/migrate.ts cua moi goi de chay seed va migration co so du lieu:

typescript
// packages/sale/src/migrate.ts
import { bootstrapMigration } from '@nx/core';
import { Application } from './application';
import { getMigrationProcesses } from './migrations/processes/migration-process';

bootstrapMigration({
  ApplicationClass: Application,
  getMigrationProcesses,
});

9.3 createMigrationProcessLoader

Ham factory tao trinh lay quy trinh migration tu danh sach duong dan file seed:

typescript
// packages/sale/src/migrations/processes/migration-process.ts
import { createMigrationProcessLoader } from '@nx/core';

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

Moi quy trinh migration la mot doi tuong voi name, migrateFn, va cleanFn tuy chon. Lop MigrationHelper theo doi trang thai thuc thi trong co so du lieu de ngan chay trung lap.

9.4 createAppConfig

Tap trung cau hinh ung dung de moi goi su dung cung cau truc:

typescript
// packages/sale/src/common/app-config.ts
import { createAppConfig } from '@nx/core';

export const appConfig = createAppConfig();

Ham nay doc tu bien moi truong va tra ve doi tuong IApplicationConfigs voi host, port, base path, cai dat debug, va boot option (mau glob de tu dong phat hien datasource va repository tu @nx/core).

10. Giao tiep Lien Dich vu

10.1 IdentityNetworkService

Client mang lien dich vu duy nhat trong he thong. No mo rong AxiosNetworkRequest tu @venizia/ignis-helpers/axios va giao tiep voi dich vu Identity de xac minh thong tin dang nhap.

typescript
export class IdentityNetworkService extends AxiosNetworkRequest {
  constructor() {
    super({
      name: IdentityNetworkService.name,
      networkOptions: {
        baseUrl: applicationEnvironment.get<string>(
          EnvironmentKeys.APP_ENV_IDENTITY_SERVICE_BASE_URL,
        ),
      },
    });
  }

  async signIn(opts: {
    identifier: { scheme: string; value: string };
    credential: { scheme: string; value: string };
  }) {
    const networkService = this.getNetworkService();
    const response = await networkService.post({
      url: '/auth/sign-in',
      body: opts,
    });
    return response.data;
  }
}

Dich vu nay duoc dang ky mac dinh trong DefaultApplication.configureServices(), giup no co san cho tat ca goi downstream de xac minh thong tin dang nhap Basic auth.

10.2 Topology Giao tiep

Khong co API gateway. Moi dich vu tu xu ly xac thuc cua rieng minh va cung cap HTTP API truc tiep. Cuoc goi HTTP lien dich vu duy nhat la de xac minh thong tin dang nhap Basic auth.

Tat ca giao tiep lien dich vu khac deu thong qua su kien Redis Pub/Sub hoac hang doi BullMQ (xem Phan 8).

11. Luong Xac thuc

DefaultApplication.configureSecurity() thiet lap IGNIS AuthenticateComponent voi hai chien luoc.

11.1 Chien luoc JWT

Xac thuc dua tren token khong trang thai. Dich vu xac thuc token cuc bo ma khong can lien he dich vu khac.

Bien Moi truongMuc dich
APP_ENV_APPLICATION_SECRETSecret cap ung dung
APP_ENV_JWT_SECRETSecret ky JWT
APP_ENV_JWT_EXPIRES_INThoi gian het han token tinh bang giay

11.2 Chien luoc Basic

Uy quyen xac minh thong tin dang nhap cho dich vu Identity thong qua IdentityNetworkService.signIn():

11.3 Dang ky Chien luoc

Ca hai chien luoc deu duoc dang ky trong singleton AuthenticationStrategyRegistry:

typescript
AuthenticationStrategyRegistry.getInstance().register({
  container: this,
  strategies: [
    { name: Authentication.STRATEGY_JWT, strategy: JWTAuthenticationStrategy },
    { name: Authentication.STRATEGY_BASIC, strategy: BasicAuthenticationStrategy },
  ],
});

Controller chi dinh chien luoc nao duoc su dung trong cau hinh authenticate:

typescript
authenticate: { strategies: ['jwt', 'basic'] }

12. Tien ich Dung chung

@nx/core cung cap mot so tien ich singleton duoc su dung tren tat ca cac goi.

Tien ichMuc dich
IdGeneratorSingleton tao ID Snowflake (bao boc IGNIS SnowflakeUidHelper)
CryptoUtilityMa hoa AES-256-GCM va ky HMAC su dung APP_ENV_APPLICATION_SECRET
useRequestContext()Trich xuat nguoi dung da xac thuc, vai tro, va cung cap helper dinh dang phan hoi
@logged decoratorGhi log do luong hieu suat cap phuong thuc
RedisConnectionFactoryTao ket noi Redis che do single hoac cluster

12.1 IdGenerator

typescript
import { IdGenerator } from '@nx/core';

const id = IdGenerator.getInstance().nextId();
// Returns: '7193487234817024' (Snowflake ID string)

Cau hinh thong qua bien moi truong:

  • APP_ENV_SNOWFLAKE_WORKER_ID (0-1023, duy nhat cho moi instance dich vu)
  • APP_ENV_SNOWFLAKE_EPOCH_CHECKPOINT (epoch tuy chinh tinh bang mili giay)

12.2 useRequestContext()

Wrapper xung quanh useRequestContext cua IGNIS bo sung cac truong dac thu BANA:

typescript
const {
  context,        // Hono request context
  currentUser,    // JWT payload with userId, roles
  userId,         // Shortcut: currentUser.userId
  roles,          // Shortcut: currentUser.roles[].identifier
  isAlwaysAllowed, // true if user has SUPER_ADMIN or ADMIN role
  normalizeCountableData,  // Format list responses with count/range headers
  formatResponse,          // Format single-item responses
  formatArrayResponse,     // Format array responses
} = useRequestContext();

13. Chuoi Phu thuoc Goi

Tat ca goi backend deu phu thuoc vao @nx/core. So do sau day cho thay cay phu thuoc day du:

GoiPhu thuoc Truc tiep
@nx/coreKhong (nen tang)
@nx/asset@nx/core
@nx/search@nx/core
@nx/inventory@nx/core
@nx/identity@nx/core
@nx/finance@nx/core
@nx/signal@nx/core
@nx/payment@nx/core, @nx/mq-pay
@nx/sale@nx/core
@nx/commerce@nx/core, @nx/asset, @nx/search, @nx/inventory

14. Schema Co so Du lieu

@nx/core dinh nghia tat ca Drizzle ORM schema tap trung de moi dich vu truy cap cung cau truc co so du lieu. Schema duoc to chuc tren 7 schema PostgreSQL:

Schema PostgreSQLSo luong ModelMien
public30Nguoi dung, vai tro, san pham, merchant, to chuc, cau hinh
allocation4Cho ngoi su kien va bo cuc dia diem
pricing7Gia, quy tac dinh gia, chi phi, thue
inventory8Ton kho, don dat hang, nha cung cap, theo doi
finance3Vi, giao dich, danh muc
payment1Cau hinh webhook
sale2Don hang va san pham don hang

Tai lieu schema chi tiet, xem ERD Co so Du lieu.

15. Tai lieu Lien quan

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