Adding a service
Feature services live next to the controller in the feature folder. The module provider list exports them only when another feature is allowed to call them. Prefer a port (as stock does with StockOperationsPort) over exporting a concrete service across areas.
Pattern in this codebase
- Controller calls the service.
- The service calls
DatabaseServiceor a repository. - Multi-step writes use
prisma.$transaction. - Side effects that must survive a crash call
outboxWriter.enqueue(tx, { tenantId, eventType, aggregateId, payload })with the transaction client. - State changes call the feature’s
isValid*Transitionbefore the write.
Order command is the reference for outbox usage. Fulfillment workflow is the reference for a long status machine. Stock command is the reference for inventory mutations.
Do not EventEmitter2.emit from order command for order side effects. That rule is specific in AGENTS.md. In-process emits are used for channel, product, shipment, audit, and return events. Some of those have no listener. Prefer the outbox when another module must react after commit.
Listeners that handle outbox events belong in a module imported by WorkerModule. An API-only provider will not see them.