Skip to content

Commerce Service

@nx/commerce is the central catalog and tenant service: it owns products, variants, options, categories, merchants, organizers, sale channels, devices, receipt templates and encrypted provider integrations. It is the CDC source of truth — Debezium tails its Postgres WAL and many sister services (search, pricing, taxation, invoice, inventory) seed themselves from it. It registers a Kafka producer only and replicates products across merchants via an in-process EventBus + BullMQ queue.

1. Quick Reference

PropertyValue
Package@nx/commerce
CodeSVC-00020-COMMERCE
TypeMicroservice
RuntimeBun
Base ClassVerifierApplication (JWKS-based JWT verification)
Locationpackages/commerce
Base Path/v1/api/commerce
Dev Port31020
Container Port3000 (external 31020)
Snowflake ID2
DB Schemapublic (+ allocation) — schemas owned in @nx/core
Binding Namespace@nx/commerce
Live OpenAPI/v1/api/commerce/doc/openapi.json

2. Purpose & Scope

IncludedExcluded
Product / variant / option catalog (aggregate CRUD)Dynamic pricing — fares/rules (delegated to @nx/pricing)
Category hierarchy (SYSTEM + custom)Tax rule provisioning (@nx/taxation)
Merchant + organizer (tenant) management & onboardingStock levels / InventoryItem (delegated to @nx/inventory)
Sale-channel config + SaleChannelProduct linksOrder / checkout lifecycle (delegated to @nx/sale)
Device, receipt template, setting, discrimination typeE-invoice issuance (delegated to @nx/invoice)
Encrypted provider-integration credentials (AES-256-GCM)Search indexing engine (Typesense — synced via @nx/search CDC)
Background multi-merchant product replication (EventBus → BullMQ)Direct push to inventory (CDC-driven instead)
Merchant tax info capture (Merchant.metadata.tax) → CDC → TaxInfo
WebSocket emitter for real-time merchant events

3. Tech Stack

External:

LibraryPurpose
@venizia/ignisIoC container, DI, BaseService/Controller, ControllerFactory
@venizia/ignis-helpersLogger, KafkaProducerHelper, BullMQHelper, WebSocketEmitter, AES
@platformatic/kafkaKafka client (producer-only)
eventemitter3In-process EventBus for product aggregate events
hono + @hono/zod-openapiHTTP server + OpenAPI generation
@scalar/hono-api-referenceOpenAPI explorer at /doc
drizzle-orm + pgDB access via PostgresCoreDataSource
minioObject storage (via @nx/asset)
typesenseSearch engine client (via @nx/search)

Internal:

PackagePurpose
@nx/coreSchemas, repositories, VerifierApplication, CDCKafkaTopics, status/type enums
@nx/assetApplicationAssetComponent — Minio media + MetaLinks
@nx/searchSearch + embedding + Typesense + CDC consumer components
@nx/mq-smsDeclared dependency; not imported in src/

4. Project Structure

packages/commerce/
├── src/
│   ├── application.ts                # VerifierApplication subclass
│   ├── index.ts / migrate.ts         # bootstrap entry points
│   ├── common/
│   │   ├── constants.ts              # ApplicationRoles (api/worker)
│   │   ├── keys.ts                   # BindingKeys (Kafka/BullMQ/EventBus)
│   │   ├── event.ts                  # EVENT_EMITTER product event keys
│   │   ├── rest-paths.ts             # RestPaths
│   │   └── environments.ts           # BullMQ Redis env keys
│   ├── components/
│   │   ├── kafka/                    # ApplicationKafkaComponent (producer-only)
│   │   ├── redis/                    # BullMQ Redis connection
│   │   ├── queues/                   # SYNC_PRODUCT_QUEUE
│   │   ├── event-bus/                # EventEmitter3 bus + registry
│   │   ├── workers/                  # SyncProductWorker + WorkerComponent
│   │   └── websocket/                # CommerceSocketEventService
│   ├── controllers/                  # 18 folders → 17 registered controllers
│   ├── datasources/                  # PostgresCoreDataSource
│   ├── events/                       # emitters + product aggregate listeners
│   ├── services/                     # incl. services/product, services/allocation
│   ├── migrations/processes/         # 9 seed/backfill processes
│   └── models/                       # zod request/response schemas
├── package.json
└── tsconfig.json

5. Architecture

Detail: see Architecture.

6. Domain Snapshot

Full ERD + per-entity tables: see Domain Model.

7. Surface Summary

REST controllers — full reference rendered live from /v1/api/commerce/doc/openapi.json (Scalar viewer at /doc, gateway portal). 17 registered controllers; all authenticate via strategies: ['jwt', 'basic'].

ControllerBase pathNotes
ProductController/products+ /aggregate create/update
ProductVariantController/product-variants+ /aggregate create/update
ProductOptionController/product-optionsoption definitions
ProductOptionValueController/product-option-valuesoption values
ProductVariantOptionController/product-variant-optionsvariant↔option selection
CategoryController/categoriesSYSTEM + custom; no CategoryService
MerchantController/merchants+ aggregate, footer-summary, deletion-policy
OrganizerController/organizers+ on-boarding (synchronous)
SaleChannelController/sale-channelsidentifier resolution
ConfigurationController/configurations+ /provider-integrations (encrypted)
DeviceController/devicesPOS device registry
DiscriminationTypeController/discrimination-typesgrouping taxonomy
ReceiptTemplateController/receipt-templatesprint templates
SettingController/settingspolymorphic settings
AllocationLayoutController/allocation-layoutsfloor plans
AllocationZoneController/allocation-zoneszones/sections
AllocationUnitController/allocation-unitstables/seats

SaleChannelInventoryLocationController + SaleChannelInventoryLocationService exist under src/ but are not registered.

Async surface — full reference in API Events:

DirectionChannelCount
OutboundCDC (Debezium)9+ tables consumed by search/pricing/taxation/invoice/inventory
InternalEventBus (eventemitter3)2 events (product.aggregate.{created,updated})
InternalBullMQ1 queue (SYNC_PRODUCT_QUEUE) × create/update jobs
OutboundWebSocketmerchant real-time emissions (emitter registered)
OutboundKafka produceproducer bound; no .send() call sites in src/

8. Components

Registered in application.ts:configureComponents() (in order):

ComponentFile / sourcePurpose
ApplicationSearchComponent@nx/searchTypesense search integration
ApplicationEmbeddingConfigurationComponent@nx/searchEmbedding config for semantic search
TypesenseSearchEngineComponent@nx/searchTypesense engine wiring
ApplicationCdcComponent@nx/searchWORKER role only — Debezium CDC → Typesense
ApplicationAssetComponent@nx/assetMinio-backed media + MetaLinks
useCacheRedis(...)core helperCache Redis (also authorization Redis)
RedisComponentcomponents/redis/Separate BullMQ Redis (single/cluster)
QueueComponentcomponents/queues/Creates SYNC_PRODUCT_QUEUE
EventBusComponentcomponents/event-bus/EventEmitter3 bus + product aggregate listeners
WorkerComponentcomponents/workers/Registers workers from APP_ENV_WORKERS
ApplicationKafkaComponentcomponents/kafka/Kafka producer initializer (no .send() in src/)
ApplicationWebSocketComponentcomponents/websocket/WebSocketEmitter for real-time events

Two Redis connections (cache + BullMQ). APPLICATION_KAFKA_CONSUMER key is declared but no consumer is wired.

9. Services

Registered in application.ts:configureServices():

ServiceOne-liner
ProductServiceProduct read + identifier resolution; delegates aggregate to create/update services
ProductCreateService / ProductUpdateServiceAggregate transaction logic; emit EventBus product events
ProductCreateSyncService / ProductUpdateSyncServicesyncToAdditionalMerchants() (BullMQ worker)
ProductVariantServiceVariant aggregate CRUD (catalog only — no pricing injection)
ProductOptionServiceOption / option-value management
MerchantServiceMerchant aggregate, tax→metadata, footer-summary cache
OrganizerServiceonBoarding() — organizer + merchant + policies + default channel
CategoryServiceSYSTEM/custom category logic
SaleChannelServiceIdentifier-based lookup
ConfigurationServiceSystem configs + encrypted provider integrations
EncryptServiceAES-256-GCM encrypt/decrypt (internal)
DeletionPolicyServicePer-merchant strict deletion enforcement
AllocationLayoutService / AllocationZoneService (+ Create/Update)Seat/zone allocation layouts
ReceiptTemplateServiceReceipt template CRUD
WebhookDispatcherServiceRe-exported from @nx/core

SaleChannelInventoryLocationService exists but is not registered.

10. Repositories

Re-exported from @nx/core and registered in configureRepositories(). Includes commerce-owned tables (Product, ProductVariant, ProductInfo, ProductIdentifier, ProductOption(Value), ProductVariantOption, ProductVariantMapping, ProductBundler, ProductCategory, Category, Merchant, Organizer, SaleChannel(Product), Configuration, Device, DiscriminationType, ReceiptTemplate, Setting, MetaLink) plus cross-package reads (SaleOrder(Item), Inventory*, Invoice, Material, Fare(Set), Tax*, FinanceAccount, TaxInfo, Permission, Role, PolicyDefinition, Notification, WebhookConfig, Customer).

Per convention, no thin wrapper repos — custom methods (e.g. MerchantRepository.markOnboardingStepComplete, SaleOrderRepository.sumWindowCompletedOrders, InventoryStockRepository.getOverview) earn their place via non-trivial logic.

11. Entry Points

FilePurpose
src/index.tsService entry → bootstrapApplication()
src/migrate.tsMigration entry → bootstrapMigration()
src/application.tsApplication extends VerifierApplication

12. Configuration

Env vars + seeded data: see Configuration.

13. Operations

Deployment + observability + security + runbook: see Operations.

Concepts — why/how:

Reference — lookup:

Features — deep dives:

Decisions:

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