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ả 14 package trong thư mục packages/, cơ sở dữ liệu PostgreSQL dùng chung với 10 schema, hạ tầng event-driven (Kafka + Redis Pub/Sub + 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ệ
Công nghệ lõi
| Technology | Version | Purpose |
|---|---|---|
| Bun | >=1.3.8 | JavaScript/TypeScript runtime |
| TypeScript | ~5.9.3 | Static type system |
| IGNIS Framework | 0.0.7-7 | IoC container, DI, application lifecycle |
| IGNIS Helpers | 0.0.6-7 | Framework utility extensions |
| Hono | 4.11.3 | Lightweight HTTP framework |
| Drizzle ORM | ^0.45.1 | Type-safe SQL ORM |
| Drizzle Kit | ^0.31.8 | Schema migrations CLI |
| Drizzle Zod | ^0.8.3 | Drizzle-to-Zod schema bridge |
| Zod | 4.1.13 | Runtime schema validation |
| PostgreSQL | 16+ | Primary relational database |
| Redis | 7+ | Caching, Pub/Sub, BullMQ |
API và tài liệu
| Technology | Version | Purpose |
|---|---|---|
| @hono/zod-openapi | 1.2.0 | OpenAPI route definitions |
| @scalar/hono-api-reference | ^0.9.28 | Interactive API explorer UI |
Thư viện hỗ trợ
| Technology | Version | Purpose |
|---|---|---|
| pg | ^8.16.3 | PostgreSQL client driver |
| bcrypt | ^6.0.0 | Password hashing (Identity) |
| dayjs | ^1.11.19 | Date/time manipulation |
| BullMQ | ^5.14.3 | Distributed job queues |
| dotenv-flow | ^4.1.0 | Environment variable management |
| nodemailer | ^7.0.12 | Transactional email |
Cấu trúc hệ thống
Tất cả 14 package Backend
| Package | Port | Role | Key Responsibilities | Primary Dependencies |
|---|---|---|---|---|
@nx/core | -- | Foundation | Base classes, DB models trên 10 schema, utilities, auth config | -- |
@nx/identity | 31010 | Service | Authentication, authorization, user management, RBAC | core |
@nx/commerce | 31020 | Service | Products, pricing engine, merchants, categories, CDC | core, asset, inventory, search |
@nx/sale | 31030 | Service | Order lifecycle, checkout, kitchen orders, payment orchestration | core, mq-pay |
@nx/inventory | 31050 | Service | Stock tracking, purchase orders, vendor management | core |
@nx/finance | 31040 | Service | Wallets, income/expense tracking, financial categories | core |
@nx/pricing | 31070 | Service | Fare sets, tax engine, promotions, pricing rules | core |
@nx/payment | 31080 | Service | Webhook config, credential loading, payment dispatch | core, mq-pay |
@nx/ledger | 31060 | Service | Tạo sổ kế toán HKD (PDF/XLSX), mã hóa, S3 | core |
@nx/outreach | 31110 | Service | Đăng ký nhận tin, biểu mẫu liên hệ | core |
@nx/licensing | 31120 | Service | Quản lý license theo policy, ký chứng chỉ, pipeline xác thực | core |
@nx/signal | 31090 | Service | WebSocket with ECDH E2E encryption, Redis Pub/Sub | core |
@nx/invoice | -- | Service | E-invoice generation (IIAPI + T-VAN) | core, iiapi, t-van |
@nx/search | -- | Library | Typesense integration, filter conversion, CDC sync | core |
@nx/asset | -- | Library | Minio/disk file storage, MetaLink management | 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ộ 55 model cơ sở dữ liệu trải dài 7 schema PostgreSQL, tiện ích dùng chung, 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:
| Export | Type | Description |
|---|---|---|
DefaultApplication | Class | Base application with auth, CORS, Swagger, health checks |
SoftDeletableRepository | Class | Repository with soft-delete (sets deletedAt instead of physical delete) |
PostgresCoreDataSource | DataSource | Shared Drizzle + node-postgres data source |
MigrationRepository | Repository | Tracks migration status in the database |
IdGenerator | Utility | Snowflake ID generation singleton |
IdentityNetworkService | Service | Cross-service HTTP calls to the Identity service |
useRequestContext() | Function | Extracts authenticated user, roles, and response normalizers |
CryptoUtility | Utility | AES-256-GCM encryption/decryption for credentials |
@logged | Decorator | Performance measurement logging |
bootstrapApplication() | Helper | Application entry point factory |
bootstrapMigration() | Helper | Migration entry point factory |
createAppConfig() | Helper | Centralized application configuration builder |
createMigrationProcessLoader() | Helper | Dynamic migration process importer |
Hằng số:
| Constant | Values |
|---|---|
FixedUserRoles | SUPER_ADMIN (999), ADMIN (998), OPERATOR (997), ORGANIZER_OWNER (899), EMPLOYEE (898) |
MerchantTypes | DEFAULT, TICKET, FNB, THEATER |
PaymentProviders | VNPAY_QR_MMS, SYSTEM |
InvoiceProviders | T_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 3001.
Các service:
| Service | Responsibility |
|---|---|
AuthenticationService | Sign-in, sign-up, password change |
UserService | Atomic user creation (user + identifiers + profile + roles) |
EmployeeService | Employee management with organizer/merchant mapping |
MailVerificationService | Email verification with 6-digit codes and tokens |
Chiến lược xác thực: JWT, Basic (via 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 3002. Tích hợp asset storage, inventory tracking, và Typesense search.
Các service:
| Service | Responsibility |
|---|---|
ProductService | Aggregate creation (info, identifiers, variants) |
ProductVariantService | Variant management with pricing integration |
FareService | Static/dynamic pricing with context-based rule evaluation |
MerchantService | Merchant onboarding with categories and sale channels |
Engine định giá:
| Concept | Description |
|---|---|
Fare | Price point with amount, status, time-based activation |
FareRule | Dynamic condition (quantity, date, custom context) |
| Rule Operators | EQ, NE, GT, GTE, LT, LTE, IN, NIN |
| Rule Types | OVERRIDE (stops evaluation), 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 3003.
Vòng đời đơn hàng:
Các service:
| Service | Responsibility |
|---|---|
SaleOrderService | Create orders, add items, cancel orders |
CheckoutService | DRAFT to PROCESSING transitions, validation |
SaleOrderItemService | Batch item updates with auto-merge |
PaymentWebhookService | Handle MQ-Pay payment status callbacks |
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:
| Service | Responsibility |
|---|---|
InventoryService | Create/update inventory for product variants |
PurchaseOrderService | PO workflow: DRAFT to PROCESSING to CONFIRMED to COMPLETED |
PurchaseOrderItemService | PO line item management |
Các chỉ số kho:
| Field | Meaning |
|---|---|
quantityOnHand | Total physical stock |
quantityAvailable | On-hand minus reserved (available for sale) |
quantityReserved | Allocated for pending orders |
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
@nx/search -- Tích hợp Typesense
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:
| Service | Responsibility |
|---|---|
SearchService | Core search with filter conversion |
BaseTypesenseSearchService | Abstract base for custom search implementations |
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 (format: protocol:host:port, comma-separated)
@nx/asset -- Lưu trữ Media
Mục đích: Lưu trữ file với 2 backend (Minio S3-compatible + local disk) với theo dõi metadata qua entity MetaLink.
Cấu hình lưu trữ:
| Backend | Endpoint | Use Case |
|---|---|---|
| Minio | /assets | Uploaded media (images, documents) |
| Local disk | /resources | Static resources (templates, banners) |
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:
| Service | Responsibility |
|---|---|
FinanceWorkerService | Event and queue handler for all financial operations |
Các phương thức FinanceWorkerService:
| Method | Trigger | Action |
|---|---|---|
handleCommerceInitialized() | COMMERCE_INITIALIZED event | Creates default Cash wallet for new merchant |
handlePaymentSuccess() | PAYMENT_SUCCESS event | Creates INCOME transaction |
handlePurchaseOrderReceived() | PURCHASE_ORDER_RECEIVED queue job | Creates EXPENSE transaction |
Loại ví: CASH, BANK, EWALLET, CREDIT_CARD
Loại giao dịch: INCOME, EXPENSE, TRANSFER
Các controller:
| Controller | Path | Type |
|---|---|---|
FinanceWalletController | /finance-wallets | ControllerFactory CRUD |
FinanceCategoryController | /finance-categories | ControllerFactory CRUD |
FinanceTransactionController | /finance-transactions | ControllerFactory 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:
| Service | Responsibility |
|---|---|
PaymentConfigurationService | Fetch and decrypt payment configs from Configuration table |
WebhookDispatcherService | Fire-and-forget webhook dispatch with exponential backoff |
Các controller:
| Controller | Path | Type |
|---|---|---|
WebhookConfigController | /webhook-configs | ControllerFactory 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:
| Method | Description |
|---|---|
broadcast({ topic, data }) | Send to all connected clients across all instances |
sendToRoom({ room, topic, data }) | Send to all clients in a room |
sendToClient({ clientId, topic, data }) | Send to a specific client (local or remote via Redis) |
disconnectClient({ clientId }) | Force-close a client connection |
REST API (base: /socket/websocket/clients):
| Method | Path | Auth | Description |
|---|---|---|---|
| GET | /status | None | Server readiness + client count |
| GET | / | JWT/Basic | List connected clients |
| POST | /broadcast | JWT/Basic | Broadcast to all clients |
| POST | /rooms/:roomName/send | JWT/Basic | Send to a room |
| POST | /:clientId/send | JWT/Basic | Send to specific client |
| POST | /:clientId/disconnect | JWT/Basic | Disconnect a client |
Mã hóa: ECDH P-256 key exchange, AES-256-GCM per-message encryption. WebSocket endpoint: /stream.
Chế độ Redis: Single instance (default) 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.
| Layer | Responsibility | IGNIS Base Class |
|---|---|---|
| Controller | HTTP transport, input validation via Zod, response formatting | ControllerFactory.defineCrudController() or custom |
| Service | Pure business logic, orchestration, event handling | BaseService |
| Repository | Database access abstraction, Drizzle ORM queries | SoftDeletableRepository or DefaultCRUDRepository |
| Component | Cross-cutting concerns: Redis, queues, external integrations | BaseComponent |
| DataSource | Connection pooling and Drizzle connector setup | BaseDataSource |
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 layersTổ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.
7 schema PostgreSQL, 55 model
| Schema | Models | Count | Key Entities |
|---|---|---|---|
public | General domain | 30 | User, UserCredential, UserProfile, Role, Permission, Product, ProductInfo, ProductIdentifier, ProductVariant, Merchant, Organizer, Category, Device, Terminal, SaleChannel, Configuration, Employee, Vendor, MetaLink, MerchantType, CategoryTemplate, etc. |
pricing | Pricing engine | 7 | Fare, FareSet, FareRule, Cost, Tax, TaxSet, TaxType |
allocation | Event seating | 4 | Venue, Section, Seat, Allocation |
inventory | Stock management | 8 | Inventory, PurchaseOrder, PurchaseOrderItem, InventoryTracking, InventoryTrackingType, etc. |
sale | Orders | 2 | SaleOrder, SaleOrderItem |
finance | Financial tracking | 3 | FinanceWallet, FinanceCategory, FinanceTransaction |
payment | Webhook config | 1 | WebhookConfig |
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().
// 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 deletionKiế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
| Channel | Publisher | Subscribers | Purpose |
|---|---|---|---|
PaymentSuccess | Payment / Sale | Finance | Record income transactions on successful payment |
SellerRegistered | Identity | Commerce | Initialize merchant defaults on new seller signup |
CommerceInitialized | Commerce | Finance | Create default Cash wallet for new merchant |
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.
| Package | Queue Types | Purpose |
|---|---|---|
| Commerce | 3 types | Product indexing, category sync, merchant setup |
| Finance | 2 types | PURCHASE_ORDER_RECEIVED (expense recording), transaction processing |
| Inventory | 1 type | Stock adjustment processing |
| Sale | 2 types | Order expiration scheduling, payment confirmation |
| MQ-Pay | 2 types (scheduler, confirmation) | Payment attempt expiration, IPN/webhook confirmation |
Ví dụ luồng sự kiện
Bảo mật
Xác thực và Phân quyền
| Mechanism | Location | Description |
|---|---|---|
| JWT Authentication | DefaultApplication.configureSecurity() | Token-based auth for API access |
| Basic Authentication | DefaultApplication.configureSecurity() | Username/password via IdentityNetworkService |
| bcrypt Hashing | @nx/identity | Password storage with bcrypt (^6.0.0) |
| Role-Based Access | All controllers | 5 fixed roles with numeric precedence |
Các vai trò mặc định
| Role | Code | Scope |
|---|---|---|
| SUPER_ADMIN | 999 | Full system access |
| ADMIN | 998 | Administrative operations |
| OPERATOR | 997 | Operational management |
| ORGANIZER_OWNER | 899 | Organizer-scoped access |
| EMPLOYEE | 898 | Employee-scoped access |
Mã hóa
| Mechanism | Algorithm | Usage |
|---|---|---|
| WebSocket E2E | ECDH P-256 + AES-256-GCM | Signal package -- per-client key derivation |
| Credential Storage | AES-256-GCM | CryptoUtility -- payment provider secrets |
| Password Hashing | bcrypt | Identity package -- user credentials |
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ó.
// packages/sale/src/application.ts
import { createAppConfig, DefaultApplication, MigrationRepository, PostgresCoreDataSource } from '@nx/core';
import { CoreBindings, IApplicationInfo } from '@venizia/ignis';
export const appConfig = createAppConfig();
export class Application extends DefaultApplication {
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.
// 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') },
});// 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.
// 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.SaleOrderRepository và services.SaleSocketEventService. Bạn cũng có thể viết binding key dưới dạng chuỗi thuần:
@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().
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.
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.
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
| File | Purpose | Git Tracked |
|---|---|---|
.env.example | Template with all required variables | Yes |
.env.development | Development settings | Yes |
.env.test | Test environment | Yes |
.env.local | Local overrides | No (gitignored) |
Biến môi trường phổ biến
# 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=3003
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:3001
APP_ENV_COMMERCE_SERVICE_URL=http://localhost:3002Quy trình phát triển
Lệnh build
| Command | Description |
|---|---|
make install | Install all dependencies (bun install) |
make build | Build everything in dependency order |
make build-packages | Build only packages/* |
make build-3rd | Build only third-parties/* |
make core | Build @nx/core |
make sale | Build @nx/sale |
make commerce | Build @nx/commerce |
make identity | Build @nx/identity |
make finance | Build @nx/finance |
make payment | Build @nx/payment |
make signal | Build @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
| Command | Service | Port |
|---|---|---|
make dev-sale-order | Sale service | 3003 |
make dev-commerce | Commerce service | 3002 |
make dev-identity | Identity service | 3001 |
make dev-finance | Finance service | -- |
make dev-payment | Payment service | -- |
make dev-signal | Signal (WebSocket) | -- |
Lệnh từng package
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 migrationsTest
# 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.jsLint
| Command | Scope |
|---|---|
make lint | Everything |
make lint-packages | All packages |
make lint-3rd | All third-parties |
make lint-sale-order | @nx/sale only |
make lint-finance | @nx/finance only |
make lint-payment | @nx/payment only |
make lint-signal | @nx/signal only |
Git Hook
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
| Method | Pattern | Purpose |
|---|---|---|
GET | /resources | List with filtering, pagination |
GET | /resources/:id | Get single resource |
GET | /resources/count | Count matching resources |
POST | /resources | Create resource |
PUT | /resources/:id | Full update |
PATCH | /resources/:id | Partial update |
DELETE | /resources/:id | Soft delete (sets 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
| Package | Link |
|---|---|
| @nx/core | Architecture, components, configuration, database, utilities |
| @nx/identity | Authentication, authorization, user management |
| @nx/commerce | Products, pricing, merchants |
| @nx/sale | Orders, checkout, payments |
| @nx/payment | Webhook config, payment orchestration |
| @nx/signal | WebSocket, encryption, real-time messaging |
| @nx/asset | File storage, MetaLink management |
| @nx/invoice | E-invoice generation |
| API Gateway | Gateway routing and middlewares |
Tham khảo bên ngoài
| Resource | Link |
|---|---|
| IGNIS Framework | https://venizia-ai.github.io/ignis/ |
| Hono | https://hono.dev |
| Drizzle ORM | https://orm.drizzle.team |
| Zod | https://zod.dev |
| BullMQ | https://docs.bullmq.io |
| Typesense | https://typesense.org/docs |