Constants
| Field | Detail |
|---|---|
| Source file | packages/core/src/common/constants.ts (294 lines) |
| Import | import { <ClassName> } from '@nx/core'; |
| Pattern | Static-class constants with Set-based validation |
| Total classes | 14 |
Overview
All application-wide constants are centralized in a single file (src/common/constants.ts) inside the @nx/core package. Every other package imports from @nx/core rather than defining its own magic strings.
Each constant class follows a consistent pattern:
- Static readonly fields -- the actual constant values.
SCHEME_SET/TYPE_SET-- aSetcontaining all valid values, used for O(1) membership checks.isValid()helper -- a static method that delegates to the Set.
import { <ClassName> } from '@nx/core';
// Use a constant
const schema = PostgresSchemas.PUBLIC;
// Validate input
if (!PostgresSchemas.isValid(userInput)) {
throw new Error('Invalid schema');
}1. Infrastructure
RedisModes
Redis connection mode selector. Determines whether the application connects to a single Redis instance or a Redis Cluster.
| Name | Value | Description |
|---|---|---|
SINGLE | 'single' | Single Redis instance (standalone) |
CLUSTER | 'cluster' | Redis Cluster (multi-node) |
INFO
RedisModes does not include a SCHEME_SET or isValid() helper. Validation is handled at the configuration layer.
Usage
import { RedisModes } from '@nx/core';
const redisMode = applicationEnvironment.get<string>('APP_ENV_WEBSOCKET_REDIS_MODE')
?? RedisModes.SINGLE;
if (redisMode === RedisModes.CLUSTER) {
// Initialize cluster connection
}PostgresSchemas
Identifiers for the seven PostgreSQL schemas used across the database.
| Name | Value | Description |
|---|---|---|
PUBLIC | 'public' | Users, roles, products, merchants, organizers, configurations |
PRICING | 'pricing' | Fares, pricing rules, costs, taxes |
ALLOCATION | 'allocation' | Event seating and venue layouts |
SALE | 'sale' | Sale orders and order items |
INVENTORY | 'inventory' | Stock and inventory management |
FINANCE | 'finance' | Wallets, transactions, categories |
PAYMENT | 'payment' | Webhook configurations |
Helpers
| Method | Signature | Description |
|---|---|---|
isValid | isValid(input: string): boolean | Returns true if input is a member of SCHEME_SET |
Usage
import { PostgresSchemas } from '@nx/core';
import { pgSchema } from 'drizzle-orm/pg-core';
// Define a table in the pricing schema
const pricingSchema = pgSchema(PostgresSchemas.PRICING);
const Fare = pricingSchema.table('Fare', { /* columns */ });
// Validate schema name
if (!PostgresSchemas.isValid(input)) {
throw new Error(`Unknown schema: ${input}`);
}
// Use in migration config
const schemaFilter = [
PostgresSchemas.PUBLIC,
PostgresSchemas.ALLOCATION,
PostgresSchemas.PRICING,
];2. Table / UI
TableConst
Default values for data-table and grid components used by both backend pagination and frontend UI.
| Name | Value | Description |
|---|---|---|
DEFAULT_NAME | 'System' | Default system display name |
DEFAULT_PAGINATION | { pageIndex: 0, pageSize: 50 } | Starting page and page size |
DEFAULT_ROWS_PER_PAGE_OPTIONS | [25, 50, 75, 100] | Page-size selector options |
DEFAULT_SORTING | [{ id: 'createdAt', desc: true }] | Default sort: newest first |
DEFAULT_FILTER | {} | Empty filter object |
DEFAULT_SIZE | 180 | Default column width in pixels |
INFO
TableConst does not include a SCHEME_SET or isValid() helper because it holds default configuration objects, not enumeration values.
Usage
import { TableConst } from '@nx/core';
async findAll(opts?: PaginationOptions) {
const pagination = opts?.pagination ?? TableConst.DEFAULT_PAGINATION;
const sorting = opts?.sorting ?? TableConst.DEFAULT_SORTING;
return this.find({
limit: pagination.pageSize,
offset: pagination.pageIndex * pagination.pageSize,
orderBy: sorting.map(s => ({ [s.id]: s.desc ? 'desc' : 'asc' })),
});
}TableConfigurations
Keys for storing per-user table display configurations (column visibility, ordering, sizing). Each key corresponds to one admin dashboard screen table.
| Name | Value |
|---|---|
TABLE_ORGANIZER | 'TABLE_ORGANIZER' |
TABLE_MERCHANT | 'TABLE_MERCHANT' |
TABLE_CATEGORY | 'TABLE_CATEGORY' |
TABLE_PRODUCT | 'TABLE_PRODUCT' |
TABLE_USER | 'TABLE_USER' |
TABLE_CATEGORY_TEMPLATE | 'TABLE_CATEGORY_TEMPLATE' |
TABLE_MERCHANT_TYPE | 'TABLE_MERCHANT_TYPE' |
TABLE_EMPLOYEE | 'TABLE_EMPLOYEE' |
TABLE_SALE_CHANNEL | 'TABLE_SALE_CHANNEL' |
TABLE_DEVICE | 'TABLE_DEVICE' |
TABLE_ROLE | 'TABLE_ROLE' |
TABLE_TRANSACTION | 'TABLE_TRANSACTION' |
TABLE_REVENUE_REPORT | 'TABLE_REVENUE_REPORT' |
TABLE_ORDER_REPORT | 'TABLE_ORDER_REPORT' |
TABLE_CUSTOMER | 'TABLE_CUSTOMER' |
TABLE_INVOICE | 'TABLE_INVOICE' |
TABLE_TERMINAL | 'TABLE_TERMINAL' |
TABLE_VENDOR | 'TABLE_VENDOR' |
TABLE_INVENTORY_TRACKING | 'TABLE_INVENTORY_TRACKING' |
TABLE_SALE_ORDER | 'TABLE_SALE_ORDER' |
TABLE_INVENTORY | 'TABLE_INVENTORY' |
TABLE_FINANCE_TRANSACTION | 'TABLE_FINANCE_TRANSACTION' |
TABLE_FINANCE_CATEGORY | 'TABLE_FINANCE_CATEGORY' |
TABLE_FINANCE_WALLET | 'TABLE_FINANCE_WALLET' |
TABLE_PURCHASE_ORDER | 'TABLE_PURCHASE_ORDER' |
Usage
import { TableConfigurations } from '@nx/core';
// Save user's table configuration
await configurationRepository.upsert({
userId: currentUser.id,
code: TableConfigurations.TABLE_PRODUCT,
value: JSON.stringify({ columns: ['name', 'price', 'status'], pageSize: 25 }),
});UserConfigurationCodes
Keys for storing user-level preference data.
| Name | Value | Description |
|---|---|---|
USER_PREFERENCES | 'PREFERENCES' | General user preferences (language, theme, etc.) |
Usage
import { UserConfigurationCodes } from '@nx/core';
const prefs = await configurationRepository.findOne({
where: {
userId: currentUser.id,
code: UserConfigurationCodes.USER_PREFERENCES,
},
});3. System
SystemConfigurations
Identifies system-level configuration entries stored in the Configuration database table. Currently used to store payment provider credentials.
| Name | Value | Description |
|---|---|---|
VNPAY_QR_MMS | 'VNPAY_QR_MMS' | VNPAY QR MMS provider configuration |
VNPAY_PHONE_POS | 'VNPAY_PHONE_POS' | VNPAY PhonePOS provider configuration |
Helpers
| Method | Signature | Description |
|---|---|---|
isValid | isValid(input: string): boolean | Returns true if input is a member of SCHEME_SET |
Usage
import { SystemConfigurations } from '@nx/core';
// Load payment configuration from the database
const config = await configurationRepository.findOne({
where: { code: SystemConfigurations.VNPAY_QR_MMS },
});
// Validate configuration code
if (!SystemConfigurations.isValid(configCode)) {
throw new Error(`Unknown system configuration: ${configCode}`);
}4. Business
MerchantTypes
Business type classifications that determine POS UI layout and feature set.
| Name | Value | Description |
|---|---|---|
DEFAULT | '000_DEFAULT' | Standard/general-purpose merchant |
TICKET | '100_POS_UI_TICKET' | Ticket-selling POS (events, transport) |
FNB | '200_POS_UI_FNB' | Food & Beverage POS |
THEATER | '300_POS_UI_THEATER' | Theater/cinema POS with seat allocation |
INFO
MerchantTypes does not include a SCHEME_SET or isValid() helper. Validation is performed at the service layer.
Usage
import { MerchantTypes } from '@nx/core';
// Create a merchant
await merchantRepository.create({
data: {
name: 'Cinema Central',
type: MerchantTypes.THEATER,
organizerId,
},
});
// Conditional UI rendering (frontend)
switch (merchant.type) {
case MerchantTypes.TICKET:
return <TicketPOSUI />;
case MerchantTypes.FNB:
return <FnBPOSUI />;
case MerchantTypes.THEATER:
return <TheaterPOSUI />;
default:
return <DefaultPOSUI />;
}FixedUserRoles
Predefined role identifiers with a numeric priority hierarchy. Higher priority codes grant broader access.
Role Identifiers
| Name | Value | Description |
|---|---|---|
SUPER_ADMIN | '999-super-admin' | Full system control |
ADMIN | '998-admin' | Administrative access |
OPERATOR | '997-operator' | Operational management |
ORGANIZER_OWNER | '899-organizer-owner' | Owner of an organizer entity |
EMPLOYEE | '898-employee' | Staff-level access |
Priority Codes
| Key | Code | Level |
|---|---|---|
SUPER_ADMIN | 999 | System |
ADMIN | 998 | System |
OPERATOR | 997 | System |
ORGANIZER_OWNER | 899 | Organization |
EMPLOYEE | 898 | Organization |
Special Sets
| Name | Contents | Description |
|---|---|---|
ALWAYS_ALLOW_ROLES | SUPER_ADMIN, ADMIN | Roles that bypass permission checks |
Role Hierarchy
Usage
import { FixedUserRoles } from '@nx/core';
// Check admin bypass
if (FixedUserRoles.ALWAYS_ALLOW_ROLES.has(currentRole)) {
return true; // Skip permission check
}
// Compare priority
const userPriority = FixedUserRoles.PRIORITY_CODE.ORGANIZER_OWNER; // 899
const requiredPriority = FixedUserRoles.PRIORITY_CODE.ADMIN; // 998
if (userPriority < requiredPriority) {
throw new ForbiddenError('Insufficient privileges');
}CompanyRegistrationTypes
Legal entity classifications for organizer registration. Currently only Vietnam-specific types are active; international types are defined in source but commented out for future expansion.
Active Types (Vietnam)
| Name | Value | Vietnamese Name |
|---|---|---|
VN_HOUSEHOLD_BUSINESS | '300_VN_HOUSEHOLD_BUSINESS' | Ho kinh doanh |
VN_PRIVATE_ENTERPRISE | '301_VN_PRIVATE_ENTERPRISE' | Doanh nghiep tu nhan |
VN_LIMITED_LIABILITY_ONE | '302_VN_LIMITED_LIABILITY_ONE' | Cong ty TNHH mot thanh vien |
VN_LIMITED_LIABILITY_TWO_PLUS | '303_VN_LIMITED_LIABILITY_TWO_PLUS' | Cong ty TNHH hai thanh vien tro len |
VN_JOINT_STOCK | '304_VN_JOINT_STOCK' | Cong ty co phan |
Commented-Out Types (Future Use)
The source file contains commented-out definitions for international types that may be activated in the future:
| Category | Codes | Examples |
|---|---|---|
| Individual/Personal | 001, 002 | INDIVIDUAL, SOLE_PROPRIETORSHIP |
| Partnership | 100, 101 | GENERAL_PARTNERSHIP, LIMITED_PARTNERSHIP |
| Corporation | 200, 201, 202 | PRIVATE_LIMITED_COMPANY, PUBLIC_LIMITED_COMPANY, JOINT_STOCK_COMPANY |
| Non-profit & Special | 800, 801, 802, 999 | NON_PROFIT, COOPERATIVE, GOVERNMENT_ENTITY, OTHER |
Helpers
| Method | Signature | Description |
|---|---|---|
isValid | isValid(type: string): boolean | Returns true if type is a member of TYPE_SET (active types only) |
Usage
import { CompanyRegistrationTypes } from '@nx/core';
// Validate registration type
if (!CompanyRegistrationTypes.isValid(input.registrationType)) {
throw new ValidationError('Invalid company registration type');
}
// Create organizer
await organizerRepository.create({
data: {
name: 'ABC Ltd.',
registrationType: CompanyRegistrationTypes.VN_LIMITED_LIABILITY_ONE,
},
});DeviceTypes
POS and hardware device classifications used for device registration and management.
| Name | Value | Category | Description |
|---|---|---|---|
POS_TERMINAL | '100_POS_TERMINAL' | Fixed POS | Traditional countertop POS |
POS_WORKSTATION | '101_POS_WORKSTATION' | Fixed POS | Desktop POS with full OS |
MOBILE_POS | '200_MOBILE_POS' | Mobile POS | Smartphone/tablet POS app |
TABLET | '400_TABLET' | Specialized | General tablet device |
BARCODE_SCANNER | '401_BARCODE_SCANNER' | Specialized | Standalone barcode scanner |
OTHER | '999_OTHER' | Other | Unclassified device |
Helpers
| Method | Signature | Description |
|---|---|---|
isValid | isValid(type: string): boolean | Returns true if type is a member of TYPE_SET |
Usage
import { DeviceTypes } from '@nx/core';
// Validate device type
if (!DeviceTypes.isValid(input.deviceType)) {
throw new ValidationError('Invalid device type');
}
// Create device
await deviceRepository.create({
data: {
name: 'Checkout Terminal 1',
type: DeviceTypes.POS_TERMINAL,
merchantId,
},
});5. Payment
MQPayProviders
Payment provider identifiers used by the MQ-Pay subsystem. Includes one internal provider (SYSTEM) and six third-party providers.
| Name | Value | Category | Description |
|---|---|---|---|
SYSTEM | 'SYSTEM' | Internal | Manual payments (cash, bank transfer) |
VNPAY_QR_MMS | 'VNPAY_QR_MMS' | VNPAY | Dynamic QR code payments |
VNPAY_PHONE_POS | 'VNPAY_PHONE_POS' | VNPAY | NFC card payment via PhonePOS |
VNPAY_SMART_POS | 'VNPAY_SMART_POS' | VNPAY | QR + card hybrid via SmartPOS |
MOMO | 'MOMO' | Third-party | MoMo e-wallet |
ZALOPAY | 'ZALOPAY' | Third-party | ZaloPay e-wallet |
VIETQR | 'VIETQR' | Third-party | VietQR bank transfer |
Sets
| Name | Contents | Description |
|---|---|---|
SCHEME_SET | All 7 providers | Complete provider set |
THIRD_PARTY_SCHEME_SET | All except SYSTEM | Only external payment providers |
Helpers
| Method | Signature | Description |
|---|---|---|
isValid | isValid(scheme: string): boolean | Returns true if scheme is any known provider |
isThirdPartyProvider | isThirdPartyProvider(opts: { provider: string }): boolean | Returns true if opts.provider is a third-party (non-SYSTEM) provider |
Usage
import { MQPayProviders } from '@nx/core';
// Check if provider requires external API calls
if (MQPayProviders.isThirdPartyProvider({ provider: paymentProvider })) {
// Load credentials and call external payment gateway
} else {
// Handle as manual/system payment
}
// Validate provider
if (!MQPayProviders.isValid(input.provider)) {
throw new ValidationError('Unknown payment provider');
}MQPayCredentialActions
Actions that require specific credential sets when communicating with payment providers. Each action maps to a distinct API operation.
| Name | Value | Description |
|---|---|---|
CREATE_PAYMENT | 'CREATE_PAYMENT' | Initiate a new payment transaction |
VERIFY_IPN | 'VERIFY_IPN' | Verify an Instant Payment Notification |
CHECK_TRANSACTION | 'CHECK_TRANSACTION' | Query transaction status from provider |
CANCEL_PAYMENT | 'CANCEL_PAYMENT' | Cancel an in-progress payment |
REFUND | 'REFUND' | Refund a settled payment |
Helpers
| Method | Signature | Description |
|---|---|---|
isValid | isValid(scheme: string): boolean | Returns true if scheme is a member of SCHEME_SET |
Usage
import { MQPayCredentialActions } from '@nx/core';
// Load credentials for a specific action
const credentials = await paymentConfigService.getCredentials({
provider: MQPayProviders.VNPAY_QR_MMS,
action: MQPayCredentialActions.CREATE_PAYMENT,
});MQPayCredentialTypes
Classification of credential data by direction of communication.
| Name | Value | Description |
|---|---|---|
REQUEST | 'request' | Credentials for outbound requests to the provider |
RESPONSE | 'response' | Credentials for validating provider responses |
IPN | 'ipn' | Credentials for verifying Instant Payment Notifications |
Helpers
| Method | Signature | Description |
|---|---|---|
isValid | isValid(scheme: string): boolean | Returns true if scheme is a member of SCHEME_SET |
Usage
import { MQPayCredentialTypes } from '@nx/core';
// Retrieve request-specific credentials
const requestCreds = credentials.filter(
c => c.type === MQPayCredentialTypes.REQUEST
);
// Retrieve IPN verification credentials
const ipnCreds = credentials.filter(
c => c.type === MQPayCredentialTypes.IPN
);6. Status
WebhookConfigStatuses
Lifecycle statuses for webhook configuration entries. Values are re-exported from the IGNIS framework Statuses class.
| Name | Source Constant | Value | Description |
|---|---|---|---|
ACTIVATED | Statuses.ACTIVATED | '201_ACTIVATED' | Webhook is active and will receive events |
DEACTIVATED | Statuses.DEACTIVATED | '401_DEACTIVATED' | Webhook is paused, no events dispatched |
ARCHIVED | Statuses.ARCHIVED | '405_ARCHIVED' | Webhook is archived for record keeping |
IGNIS Statuses
WebhookConfigStatuses delegates to Statuses from @venizia/ignis. For the complete status code reference, see the IGNIS Statuses documentation.
Type Export
export type TWebhookConfigStatus = TConstValue<typeof WebhookConfigStatuses>;
// Resolves to: '201_ACTIVATED' | '401_DEACTIVATED' | '405_ARCHIVED'Helpers
| Method | Signature | Description |
|---|---|---|
isValid | isValid(status: string): boolean | Returns true if status is a member of SCHEME_SET |
Usage
import { WebhookConfigStatuses } from '@nx/core';
import type { TWebhookConfigStatus } from '@nx/core';
// Create a webhook config
await webhookConfigRepository.create({
data: {
name: 'Order Notifications',
url: 'https://example.com/webhook',
eventTypes: ['order.created', 'order.completed'],
status: WebhookConfigStatuses.ACTIVATED,
},
});
// Deactivate a webhook
await webhookConfigRepository.updateById({
id: webhookId,
data: { status: WebhookConfigStatuses.DEACTIVATED },
});
// Type-safe status parameter
function setWebhookStatus(id: string, status: TWebhookConfigStatus) {
return webhookConfigRepository.updateById({ id, data: { status } });
}Best Practices
1. Always Use Constants -- Never Magic Strings
// Good -- type-safe and refactorable
if (device.type === DeviceTypes.POS_TERMINAL) { /* ... */ }
// Bad -- magic string, prone to typos
if (device.type === '100_POS_TERMINAL') { /* ... */ }2. Validate Input with isValid()
// Good -- explicit validation using the Set
if (!DeviceTypes.isValid(input.type)) {
throw new ValidationError('Invalid device type');
}
// Bad -- manual inline check
if (!['100_POS_TERMINAL', '101_POS_WORKSTATION'].includes(input.type)) { /* ... */ }3. Prefer SCHEME_SET / TYPE_SET for Bulk Checks
// Good -- O(1) lookup
if (MQPayProviders.THIRD_PARTY_SCHEME_SET.has(provider)) { /* ... */ }
// Bad -- O(n) array search
if (['VNPAY_QR_MMS', 'VNPAY_PHONE_POS', /* ... */].includes(provider)) { /* ... */ }4. Extend Constants in Downstream Packages
When a downstream package needs additional values, extend the base class rather than duplicating:
export class ExtendedDeviceTypes extends DeviceTypes {
static readonly SELF_CHECKOUT_KIOSK = '500_SELF_CHECKOUT_KIOSK';
static override TYPE_SET = new Set([
...DeviceTypes.TYPE_SET,
this.SELF_CHECKOUT_KIOSK,
]);
}