@open-mercato/core 0.6.6-develop.6381.1.042df302c3 → 0.6.6-develop.6383.1.27fcc83455

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
@@ -1,104 +0,0 @@
1
- # Sales Module — Standalone App Guide
2
-
3
- Use the sales module for orders, quotes, invoices, shipments, and payments. This module has the most complex business logic in the system.
4
-
5
- ## Document Flow
6
-
7
- ```
8
- Quote → Order → Invoice
9
-
10
- Shipments + Payments
11
- ```
12
-
13
- - Quotes convert to orders — do not create orders without a source quote (unless configured)
14
- - Orders track shipments and payments independently
15
- - Each entity has its own status workflow — do not skip states
16
- - Returns create line-level adjustments and update `returned_quantity`
17
-
18
- ## Pricing Calculations
19
-
20
- Always use the sales calculation service — never inline price math:
21
-
22
- ```typescript
23
- const calcService = container.resolve('salesCalculationService')
24
- ```
25
-
26
- - Dispatches `sales.line.calculate.*` and `sales.document.calculate.*` events
27
- - For catalog pricing: use `selectBestPrice` from the catalog module
28
- - Register custom line/totals calculators or override via DI
29
-
30
- ## Channel Scoping
31
-
32
- All sales documents are scoped to channels. Channel selection affects:
33
- - Available pricing tiers
34
- - Document numbering sequences
35
- - Visibility in admin UI
36
-
37
- ## Data Model
38
-
39
- ### Core Entities
40
- | Entity | Purpose | Key Constraint |
41
- |--------|---------|---------------|
42
- | **Sales Orders** | Confirmed customer orders | MUST have a channel and at least one line |
43
- | **Sales Quotes** | Proposed orders | MUST track conversion status |
44
- | **Order/Quote Lines** | Individual items | MUST reference valid products |
45
- | **Adjustments** | Discounts/surcharges | MUST use registered `AdjustmentKind` |
46
-
47
- ### Fulfillment
48
- | Entity | Purpose |
49
- |--------|---------|
50
- | **Shipments** | Delivery tracking with status workflow |
51
- | **Payments** | Payment recording with status workflow |
52
- | **Returns** | Order returns with line selection and automatic adjustments |
53
-
54
- ### Configuration (do not modify directly)
55
- Channels, statuses, payment/shipping methods, price kinds, adjustment kinds, and document numbers — configure via admin UI or `setup.ts` hooks.
56
-
57
- ## Subscribing to Sales Events
58
-
59
- ```typescript
60
- // src/modules/<your_module>/subscribers/order-created.ts
61
- export const metadata = {
62
- event: 'sales.order.created',
63
- persistent: true,
64
- id: 'your-module-order-created',
65
- }
66
-
67
- export default async function handler(payload, ctx) {
68
- // React to new orders
69
- }
70
- ```
71
-
72
- Key events: `sales.order.created` / `updated` / `deleted`, `sales.quote.created` / `updated`, `sales.payment.created`, `sales.shipment.created`
73
-
74
- ## Extending Sales UI
75
-
76
- Widget injection spots:
77
-
78
- **Order & Quote detail page:**
79
- - `sales.document.detail.order:details` — order detail page sections
80
- - `sales.document.detail.quote:details` — quote detail page sections
81
- - `sales.document.detail.order:tabs` — order detail page tabs
82
- - `sales.document.detail.quote:tabs` — quote detail page tabs
83
- - `detail:sales.order:stage-bar` — order stage bar (empty, ready for extension)
84
- - `detail:sales.quote:stage-bar` — quote stage bar (empty, ready for extension)
85
- - `detail:sales.order:closure` — order closure section (empty, ready for extension)
86
- - `detail:sales.quote:closure` — quote closure section (empty, ready for extension)
87
-
88
- **Order list:**
89
- - `data-table:sales.orders:columns` — order list columns
90
- - `data-table:sales.orders:row-actions` — order row actions
91
-
92
- **Order form:**
93
- - `crud-form:sales.sales_order:fields` — order detail form
94
-
95
- **Payments:**
96
- - `data-table:sales.payments:columns` — payment list columns
97
-
98
- **Payment methods:**
99
- - `crud-form:sales.payment_method:fields` — payment method form fields
100
- - `crud-form:sales.sales_payment_method:fields` — sales payment method form fields
101
-
102
- ## Frontend Pages
103
-
104
- - `frontend/quote/` — public-facing quote view for customer acceptance
@@ -1,152 +0,0 @@
1
- # Workflows Module — Standalone App Guide
2
-
3
- Use the workflows module for business process automation: defining step-based workflows, executing instances, handling user tasks, and triggering workflows from domain events.
4
-
5
- ## Using Workflows in Your App
6
-
7
- The workflow engine is provided by `@open-mercato/core`. Your standalone app can:
8
-
9
- 1. **Create workflow definitions** via the visual editor at `/backend/workflows`
10
- 2. **Trigger workflows** from domain events emitted by your modules
11
- 3. **Subscribe to workflow events** for side effects in your modules
12
- 4. **Inject UI widgets** into workflow pages or inject workflow widgets into your pages
13
- 5. **Define user tasks** that require human approval or data entry
14
-
15
- ## Starting Workflows Programmatically
16
-
17
- Resolve the workflow executor via DI — never import lib functions directly:
18
-
19
- ```typescript
20
- // In your module's DI-aware context (API route, subscriber, worker)
21
- const executor = container.resolve('workflowExecutor')
22
-
23
- await executor.startWorkflow({
24
- workflowId: 'order-approval', // matches a WorkflowDefinition.workflowId
25
- context: {
26
- orderId: order.id,
27
- orderTotal: order.totalGross,
28
- customerName: order.customerName,
29
- },
30
- organizationId,
31
- tenantId,
32
- })
33
- ```
34
-
35
- ## Event Triggers
36
-
37
- Configure automatic workflow starts from your module's domain events:
38
-
39
- 1. Create a workflow definition with a `triggers[]` entry in the visual editor or via API
40
- 2. The workflow engine's wildcard subscriber evaluates all non-internal events
41
- 3. Use `filterConditions` to narrow which events match (e.g., only orders above a threshold)
42
- 4. Use `contextMapping` to extract event payload fields into workflow context variables
43
- 5. Use `debounceMs` and `maxConcurrentInstances` to prevent trigger storms
44
-
45
- Excluded event prefixes (never trigger workflows): `query_index`, `search`, `workflows`, `cache`, `queue`.
46
-
47
- ## Subscribing to Workflow Events
48
-
49
- React to workflow lifecycle events in your module:
50
-
51
- ```typescript
52
- // src/modules/<your_module>/subscribers/workflow-completed.ts
53
- export const metadata = {
54
- event: 'workflows.instance.completed',
55
- persistent: true,
56
- id: 'your-module-workflow-completed',
57
- }
58
-
59
- export default async function handler(payload, ctx) {
60
- // payload.resourceId = instance ID
61
- // payload.workflowId = definition ID
62
- // payload.context = workflow context variables
63
- }
64
- ```
65
-
66
- Key workflow events your module can subscribe to:
67
-
68
- | Event | When it fires |
69
- |-------|--------------|
70
- | `workflows.instance.created` | New workflow instance started |
71
- | `workflows.instance.completed` | Workflow finished successfully |
72
- | `workflows.instance.failed` | Workflow failed |
73
- | `workflows.instance.cancelled` | Workflow was cancelled |
74
- | `workflows.task.created` | User task assigned |
75
- | `workflows.task.completed` | User task completed |
76
- | `workflows.step.completed` | Individual step finished |
77
-
78
- ## Step Types
79
-
80
- | Step type | Use case |
81
- |-----------|----------|
82
- | `START` | Entry point — every definition has exactly one |
83
- | `END` | Terminal step — marks workflow as COMPLETED |
84
- | `USER_TASK` | Human approval or data entry — pauses until task completion |
85
- | `AUTOMATED` | Executes transition activities immediately and advances |
86
- | `SUB_WORKFLOW` | Invokes a nested workflow definition |
87
- | `WAIT_FOR_SIGNAL` | Pauses for an external signal (e.g., payment confirmed) |
88
- | `WAIT_FOR_TIMER` | Pauses for a configured duration |
89
- | `PARALLEL_FORK` / `PARALLEL_JOIN` | Splits/merges parallel execution paths |
90
-
91
- ## Activity Types
92
-
93
- Activities execute on transitions between steps:
94
-
95
- | Activity type | Use case |
96
- |---------------|----------|
97
- | `SEND_EMAIL` | Send templated email |
98
- | `CALL_API` | Call an internal API endpoint |
99
- | `CALL_WEBHOOK` | Call an external HTTP endpoint |
100
- | `UPDATE_ENTITY` | Mutate an entity via the command bus |
101
- | `EMIT_EVENT` | Emit a domain event |
102
- | `EXECUTE_FUNCTION` | Run a registered custom function |
103
- | `WAIT` | Delay execution for a configured duration |
104
-
105
- Use `{{context.*}}`, `{{workflow.*}}`, `{{env.*}}`, `{{now}}` for variable interpolation in activity config — never hardcode values.
106
-
107
- ## Sending Signals
108
-
109
- Resume a workflow waiting for an external signal:
110
-
111
- ```typescript
112
- const executor = container.resolve('workflowExecutor')
113
-
114
- await executor.sendSignal({
115
- instanceId: workflowInstanceId,
116
- signalName: 'payment_confirmed',
117
- payload: { transactionId: '...' },
118
- organizationId,
119
- tenantId,
120
- })
121
- ```
122
-
123
- ## Widget Injection
124
-
125
- Inject workflow-related UI into your module's pages, or inject your module's widgets into workflow pages:
126
-
127
- ```typescript
128
- // src/modules/<your_module>/widgets/injection-table.ts
129
- export const widgetInjections = {
130
- // Inject into workflow task detail page
131
- 'workflows.task.detail:after': {
132
- widgetId: 'your-module-task-context',
133
- priority: 50,
134
- },
135
- }
136
- ```
137
-
138
- ## Compensation (Saga Pattern)
139
-
140
- When a workflow step fails, compensation activities execute in reverse order to undo previous steps. This follows the saga pattern:
141
-
142
- - **Sync activities** execute inline and advance immediately
143
- - **Async activities** enqueue to the `workflow-activities` queue; workflow pauses until completion
144
- - On failure, compensation runs in reverse — keep activity handlers **idempotent** (check state before mutating)
145
-
146
- ## Key Rules
147
-
148
- - MUST resolve services via DI (`container.resolve('workflowExecutor')`) — never import lib functions directly
149
- - MUST use `workflowExecutor.startWorkflow()` to create instances — never insert rows directly
150
- - MUST keep activity handlers idempotent — they may be retried on failure
151
- - MUST scope all queries by `organization_id` — workflow data is tenant-scoped
152
- - MUST NOT couple your module to workflow internals — use event triggers and signals for integration