Skip to content

Pricing Service

@nx/pricing is a standalone IGNIS service (REST API + Kafka CDC worker) that prices sellable lines: it selects the winning fare per product variant, computes compound taxes, tracks variant costs, and manages promotions. Sister services call it over HTTP and import request/response types plus a few runtime snapshot const containers from @nx/pricing/contracts — they do not mount it as a component.

1. Quick Reference

PropertyValue
Package@nx/pricing
CodeSVC-00070-PRICING
TypeMicroservice
RuntimeBun
Base ClassVerifierApplication
Locationpackages/pricing
Base Path/v1/api/pricing
Dev Port31070
Container Port3000 (external 31070)
Snowflake ID7
DB Schemapricing (9 tables)
Binding Namespace@nx/pricing
Run Modesapi (REST + Kafka CDC consumer at boot) · migrate

2. Purpose & Scope

IncludedExcluded
Fare selection per ProductVariant (default / OVERRIDE / rule-based child fares)Order persistence (owned by @nx/sale)
Compound, priority-grouped tax calculation (item + order level)Invoice / e-invoice issuance (owned by @nx/invoice)
Pricing snapshots (immutable per-line + per-order, v2)Stock / inventory mutation (owned by @nx/inventory)
Variant cost tracking with effective date rangesPayment processing (owned by @nx/mq-pay)
Promotion / PromotionMethod / Rule CRUDDiscount/fee calculation (entities exist; calculator not yet wired)
CDC seeding of FareSets from ProductVariant eventsOwning any DB schema — all schemas live in @nx/core
Two calculation pipelines: /simulation (v1) + /simulation-v2 (v2, canonical)

3. Tech Stack

External:

LibraryPurpose
@venizia/ignisIoC container, DI, BaseService, BaseController, ControllerFactory
@venizia/ignis-helpersLogger, float(x, 4) money math, Redis helper, Axios
@platformatic/kafkaKafka producer + CDC consumer (idempotent, lz4, SASL-optional)
hono + @hono/zod-openapiHTTP server + OpenAPI generation from Zod
@scalar/hono-api-referenceOpenAPI explorer at /doc
drizzle-orm / pgDB access via PostgresCoreDataSource
lodashget() for attribute-path rule evaluation

Internal:

PackagePurpose
@nx/coreAll schemas (Fare, FareSet, Tax, TaxSet, TaxType, Rule, Cost, Promotion, PromotionMethod), VerifierApplication, CDCKafkaTopics, FareTypes, RuleOperators, IdGenerator

4. Project Structure

packages/pricing/
├── src/
│   ├── application.ts              # VerifierApplication subclass
│   ├── index.ts                    # bootstrapApplication()
│   ├── migrate.ts                  # bootstrapMigration()
│   ├── common/                     # RestPaths, BindingKeys, constants, env keys
│   ├── components/kafka/           # ApplicationKafkaComponent (producer + CDC consumer)
│   ├── contracts/                  # Published types + snapshot const containers (sale imports this)
│   ├── controllers/                # 11 REST controllers
│   ├── datasources/                # PostgresCoreDataSource
│   ├── errors/                     # Domain error catalogues
│   ├── migrations/processes/       # 2 seeds (permissions, role-permissions)
│   ├── models/                     # zod request/response schemas
│   ├── repositories/               # re-exports + thin wrappers over @nx/core
│   └── services/
│       ├── core/                   # v1 calculation pipeline (/simulation)
│       ├── core-v2/                # v2 calculation + pricing-snapshot module (/simulation-v2)
│       ├── management/             # CRUD + aggregate services
│       └── pricing-worker.service.ts  # ProductVariant CDC subscriber
├── 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/pricing/doc/openapi.json (Scalar viewer at /doc, gateway portal):

ControllerBase pathCustom routes
FareController/faresPOST /groups, POST /children
FareSetController/fare-sets
CostController/costsPUT /current, GET /product-variant/{id}/current
TaxController/taxes
TaxSetController/tax-setsPATCH /{id}/aggregate
TaxTypeController/tax-types
PromotionController/promotionsPOST /aggregate, PATCH /{id}/aggregate
PromotionMethodController/promotion-methods
RuleController/rules
SimulationController/simulationPOST /calculate (v1, flat)
SimulationV2Controller/simulation-v2POST /calculate (v2, snapshot)

Async surface — full reference in API Events:

DirectionChannelCount
InboundKafka CDC (CDCKafkaTopics.PRODUCT_VARIANT)1
OutboundKafka0 (producer bound but not used by domain logic)
WebSocket out0
BullMQ jobs0 (no BullMQ / QueueComponent)

8. Components

ComponentFilePurpose
ApplicationKafkaComponentsrc/components/kafka/component.tsIdempotent lz4 producer + CDC consumer on PRODUCT_VARIANT; dispatches to PricingWorkerService
Redis cache (parent)bound at BindingKeys.APPLICATION_REDIS_CACHE via useCacheRedis()Authorization permission cache only

9. Services

ServiceFileOne-liner
PricingServicecore/pricing.service.tsv1 orchestrator — per item: select fare → calc tax → sum (concurrency 5); applies order-level taxes when merchantId present
PricingFareCalculatorServicecore/pricing-fare-calculator.service.tsLoads active FareSet, categorizes fares, picks winner (OVERRIDE first, else lowest)
PricingRuleEvaluatorServicecore/pricing-rule-evaluator.service.tsAND-logic rule evaluation via lodash get() by attribute path
PricingTaxCalculatorServicecore/pricing-tax-calculator.service.tsCompound, priority-grouped tax engine; inclusive back-calc, quantity conditions
ItemPriceCalculatorcore/item-price-calculator.service.tsPer-item price helper for the v1 pipeline
PricingV2Servicecore-v2/pricing-v2.service.tsv2 orchestrator → full pricing snapshot (per-line applied rules + by-bearer order totals)
FareCalculatorServicecore-v2/fare-calculator.service.tsv2 fare selection producing TAppliedPrice
TaxCalculatorServicecore-v2/tax-calculator.service.tsv2 tax engine producing TAppliedTax[]
BaseCalculatorServicecore-v2/base-calculator.service.tsShared money/float helpers for v2 calculators
FareServicemanagement/fare.service.tsFare / fare-group / child-fare / variant-pricing aggregate CRUD
CostServicemanagement/cost.service.tsVariant cost CRUD with date ranges (getCurrentCost hardcodes principalType:'ProductVariant')
TaxSetServicemanagement/tax-set.service.tsTaxSet + its taxes aggregate CRUD
PromotionServicemanagement/promotion.service.tsPromotion + method + rules aggregate CRUD
PricingWorkerServiceservices/pricing-worker.service.tsProductVariant CDC subscriber — seeds FareSet + default fare; seeds FBT override child fares

v1 and v2 share ~90% of fare/tax logic — fixes usually need to land in both. PromotionService CRUD exists but no discount calculator is wired into either pipeline yet.

10. Repositories

RepositoryTableSourceCustom methods
FareRepositoryFare@nx/corefindByFareId, updateChildrenCount, updateRulesCount
FareSetRepositoryFareSet@nx/core
RuleRepositoryRule@nx/corefindByFareId
TaxRepositoryTax@nx/core
TaxSetRepositoryTaxSet@nx/core
TaxTypeRepositoryTaxType@nx/core
CostRepositoryCost@nx/core
PromotionRepositoryPromotion@nx/core
PromotionMethodRepositoryPromotionMethod@nx/core
PermissionRepository, RoleRepository, PolicyDefinitionRepository, MigrationRepository@nx/coreAuthorization + migration bookkeeping

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.