@izumisy-tailor/omakase-modules 0.1.0 → 0.2.0

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.
package/README.md ADDED
@@ -0,0 +1,59 @@
1
+ # Omakase Modules
2
+
3
+ A **configurable module system** for Tailor Platform. Define reusable modules with type-safe configurations and share them across applications.
4
+
5
+ ## Motivation
6
+
7
+ When building applications on Tailor Platform, you often face these challenges:
8
+
9
+ 1. **Reusability**: You want to reuse common data models and business logic (e.g., e-commerce, inventory, orders) across multiple applications
10
+ 2. **Customizability**: While modules should be reusable, you need to customize them for application-specific requirements
11
+ 3. **Dependency Management**: Module dependencies should be explicitly defined and managed in a type-safe manner
12
+
13
+ Omakase Modules is designed to solve these challenges by providing a flexible, type-safe module system.
14
+
15
+ ## Key Features
16
+
17
+ - **Module Definition**: Define modules with `defineModule` and declare type-safe configuration schemas
18
+ - **Module Configuration**: Configure modules at the application level, injecting custom attributes and prefixes
19
+ - **Dependency Management**: Explicitly define inter-module dependencies with the `ModuleDependency` type
20
+ - **Configuration Injection**: Inject configurations into TailorDB, Resolvers, and Executors using `withModuleConfiguration`
21
+
22
+ ## Installation
23
+
24
+ ```bash
25
+ pnpm add @izumisy-tailor/omakase-modules
26
+ ```
27
+
28
+ ## Documentation
29
+
30
+ - [Using Modules](./docs/tutorials/using-modules.md) - How to use pre-built modules in your application
31
+ - [Creating Modules](./docs/tutorials/creating-modules.md) - How to create reusable modules
32
+
33
+ ## API Reference
34
+
35
+ ### `@izumisy-tailor/omakase-modules`
36
+
37
+ - `loadModules(configurator)` - Load and configure modules in your application
38
+
39
+ ### `@izumisy-tailor/omakase-modules/builder`
40
+
41
+ - `defineModule<Config, Tables>(options)` - Define a new module
42
+ - `withModuleConfiguration(module, factory)` - Access module configuration in TailorDB, Resolvers, and Executors
43
+ - `ModuleDependency<T>` - Type utility for declaring module dependencies
44
+
45
+ ### `@izumisy-tailor/omakase-modules/config/sdk`
46
+
47
+ - `getModulesReference(loadedModules)` - Generate file path references for `tailor.config.ts`
48
+
49
+ ## Project Structure
50
+
51
+ ```
52
+ examples/
53
+ commerce-core-module/ # E-commerce core module (Product, Customer, etc.)
54
+ order-module/ # Order management module
55
+ inventory-module/ # Inventory management module
56
+ basic-app/ # Application using the above modules
57
+ packages/
58
+ core/ # omakase-modules core package
59
+ ```
@@ -0,0 +1,230 @@
1
+ # Inventory Core Contract
2
+
3
+ ## Goal
4
+ Define the minimal shared layer of inventory management so industry-specific and automation modules can reuse a consistent contract. The aim is to standardise SKU- and location-level quantities, reservations, and fulfilment tasks, while coordinating downstream modules through status history.
5
+
6
+ ## Module Boundary
7
+ - Persist core metadata for SKU, location, and inventory buckets (for example on-hand, reserved).
8
+ - Publish "intent → confirmation" contracts for reservations, stock adjustments, and fulfilment tasks so callers write intents instead of mutating inventory directly.
9
+ - Provide `inventory.statusHistory` (exposed as the `inventoryStatusHistory` view where needed) so business modules append their own statuses for auditing and visibility.
10
+ - Delegate integrations with external systems (channel sync, procurement, warehouse automation, etc.) to extension modules; the core remains the source of truth for quantities and history.
11
+
12
+ ## Published Contracts
13
+
14
+ All tables implicitly include an auto-generated `id` primary key; only domain-specific columns are listed below.
15
+
16
+ ### `inventory.stock`
17
+ Represents the latest stock balance per location.
18
+
19
+ | Field | Description |
20
+ | --- | --- |
21
+ | `skuId` | Identifier of the SKU. |
22
+ | `locationId` | Identifier of the warehouse, store, or virtual location. |
23
+ | `availableQuantity` | Sellable quantity after subtracting active reservations. |
24
+ | `onHandQuantity` | Physical on-hand quantity. |
25
+ | `reservedQuantity` | Quantity locked by reservations. |
26
+ | `inboundQuantity` | Expected inbound quantity (optional). |
27
+ | `outboundQuantity` | Planned outbound quantity (optional). |
28
+ | `attributes` | JSON extension point for domain metadata (temperature band, storage condition, etc.). |
29
+ | `updatedAt` | Timestamp of the latest update. |
30
+
31
+ **Responsibilities**
32
+ - Core maintains the balance calculation and consistency; external modules must request changes via intents.
33
+ - Extension modules append industry-specific metadata (lot, serial, expiry, etc.) in `attributes`.
34
+
35
+ ### `inventory.reservationIntent`
36
+ Intent table for requesting an inventory reservation.
37
+
38
+ | Field | Description |
39
+ | --- | --- |
40
+ | `reservationIntentId` | Stable ID generated by the caller (per SKU or line item). |
41
+ | `sourceSystem` | Origin of the request (for example `order`, `procurement`, `manual`). |
42
+ | `orderId` / `sourceRef` | External reference identifier. |
43
+ | `skuId` | SKU to reserve. |
44
+ | `quantity` | Quantity requested for reservation. |
45
+ | `locationPreference` | Preferred location when stock is distributed. |
46
+ | `priority` | Reservation priority so urgent orders can be fulfilled first. |
47
+ | `requestedAt` | Timestamp when the request was issued. |
48
+ | `payload` | Arbitrary supplemental metadata. |
49
+
50
+ **Responsibilities**
51
+ - Callers insert intents to request reservation; enforce idempotency with `reservationIntentId` + `sourceSystem`.
52
+ - Intent can be updated until confirmed; after confirmation, changes require a new intent.
53
+
54
+ ### `inventory.reservation`
55
+ Confirmed record that stores the reservation outcome.
56
+
57
+ | Field | Description |
58
+ | --- | --- |
59
+ | `reservationIntentId` | Reference back to the originating intent. |
60
+ | `skuId` | SKU that was reserved. |
61
+ | `locationId` | Location assigned to fulfil the reservation. |
62
+ | `reservedQuantity` | Quantity secured; may differ from requested quantity if partially fulfilled. |
63
+ | `status` | Core-defined status such as `confirmed`, `backordered`, `cancelled`. |
64
+ | `expiresAt` | Reservation expiry timestamp (optional). |
65
+ | `payload` | Supplemental metadata (batch number, operator notes, etc.). |
66
+ | `createdAt` / `updatedAt` | Creation and update timestamps. |
67
+
68
+ **Responsibilities**
69
+ - Core finalises the intent, writes status updates to `inventory.statusHistory`, and emits CDC events.
70
+ - Callers read the outcome and handle follow-up actions such as backorders when short allocations occur.
71
+
72
+ ### `inventory.adjustmentIntent`
73
+ Intent that requests a stock increase or decrease, used for returns, cycle counts, manual corrections, etc.
74
+
75
+ | Field | Description |
76
+ | --- | --- |
77
+ | `adjustmentIntentId` | Stable ID generated by the caller. |
78
+ | `sourceSystem` | Origin of the adjustment request. |
79
+ | `skuId` | SKU being adjusted. |
80
+ | `locationId` | Location being adjusted. |
81
+ | `quantityDelta` | Quantity delta (positive for increment, negative for decrement). |
82
+ | `reasonCode` | Reason code (for example `cycle_count`, `return`, `damage`). |
83
+ | `payload` | Additional metadata (document number, operator, etc.). |
84
+ | `requestedAt` | Timestamp when the intent was created. |
85
+
86
+ ### `inventory.stockLedger`
87
+ Authoritative event log for confirmed stock movements. Centralises adjustments, inbound receipts, outbound shipments, and any other inventory change.
88
+
89
+ | Field | Description |
90
+ | --- | --- |
91
+ | `sourceType` | Origin of the event (for example `manual`, `procurement`, `fulfillment`). |
92
+ | `sourceRef` | Reference `id` (reservation, purchase order, etc.). |
93
+ | `skuId` | SKU affected. |
94
+ | `locationId` | Location affected. |
95
+ | `quantityDelta` | Quantity delta applied. |
96
+ | `reasonCode` | Reason for the event (propagated from the intent or assigned by Core). |
97
+ | `payload` | Optional extension metadata. |
98
+ | `recordedAt` | Timestamp when the event was recorded. |
99
+
100
+ `inventory.stockLedger` captures quantitative deltas only; downstream services should pair these entries with `inventory.statusHistory` to understand business context and progression.
101
+
102
+ ### `inventory.statusHistory`
103
+ Timeline of status transitions emitted by Inventory Core and its extensions.
104
+
105
+ | Field | Description |
106
+ | --- | --- |
107
+ | `entityType` | Scoped entity such as `reservation`, `fulfillmentTask`, `stock`. |
108
+ | `entityId` | Auto-generated `id` of the entity whose status changed. |
109
+ | `statusCode` | Vocabulary entry (see Inventory Status Vocabulary). |
110
+ | `payload` | Optional metadata for UI or audit trails. |
111
+ | `writtenBy` | Writer of the status (core executor, extension module, etc.). |
112
+ | `writtenAt` | Timestamp when the status was appended. |
113
+
114
+ While `inventory.stockLedger` answers "how much stock moved", `inventory.statusHistory` focuses on "what lifecycle state changed" so that UI, workflow, and auditing layers can present human-readable progress independent of quantitative adjustments.
115
+
116
+ ### `inventory.fulfillmentTask`
117
+ Executable task for picking, packing, and shipping.
118
+
119
+ | Field | Description |
120
+ | --- | --- |
121
+ | `sourceSystem` | System that generated the task (for example `order`, `channel`). |
122
+ | `reservationId` | Linked reservation; use a join table when bundling multiple reservations. |
123
+ | `skuId` / `quantity` | Item to pick and its quantity. |
124
+ | `locationId` | Location from which the item should be picked. |
125
+ | `status` | Lifecycle status such as `created`, `picking`, `packed`, `shipped`. |
126
+ | `assignee` | Human or automated assignee. |
127
+ | `payload` | Additional instructions (packing notes, carrier info, etc.). |
128
+ | `updatedAt` | Timestamp of the latest update. |
129
+
130
+ ## Core Executors
131
+
132
+ | Executor name | Trigger source | Key responsibilities | Current status |
133
+ | --- | --- | --- | --- |
134
+ | `inventory-bootstrap-product-variant` | `commerce-core.productVariant` created | Seed `inventory.stock` for the new SKU/variant with zeroed quantities and default thresholds. | Implemented (GraphQL mutation) |
135
+ | `inventory-reserve-on-order-item-created` | `order.orderItem` created (CDC) | Listen to order-side CDC, enqueue reservation intent, and emit reservation confirmation/backorder statuses without the order module calling Inventory directly. | Stubbed in code; behaviour to be completed |
136
+
137
+ > Fulfilment progression (picking → shipped) is typically handled by a warehouse extension executor such as `warehouse-fulfillment-task-progress`, which appends lifecycle statuses and ledger entries once physical operations occur.
138
+
139
+ ## Inventory Status Vocabulary
140
+
141
+ Statuses below are persisted in `inventory.statusHistory` (or projected as `inventoryStatusHistory`) and streamed via CDC to downstream consumers.
142
+
143
+ | Label | Writer | Trigger timing | Notes |
144
+ | --- | --- | --- | --- |
145
+ | `inventory:reservation_created` | Inventory core | Immediately after receiving a `reservationIntent`; signals reservation processing has started. |
146
+ | `inventory:reservation_confirmed` | Inventory core | When stock is secured; use `payload` to surface short allocations. |
147
+ | `inventory:reservation_backordered` | Inventory core | When the reservation is pending because available stock is insufficient. |
148
+ | `inventory:reservation_cancelled` | Inventory core / caller | When the reservation is cancelled. |
149
+ | `inventory:stock_adjusted` | Inventory core | When an `adjustmentIntent` is confirmed and the ledger records the delta. |
150
+ | `inventory:fulfillment_task_created` | Inventory core | When a fulfilment task is generated. |
151
+ | `inventory:picked` | Inventory core / warehouse module | When picking completes. |
152
+ | `inventory:shipped` | Inventory core / warehouse module | When the shipment is handed off. |
153
+
154
+ Industry modules follow the `inventory:*` namespace and may add codes such as `inventory:lotted_reserved` or `inventory:expiry_hold` for specialised flows.
155
+
156
+ ## Ingestion Pattern
157
+ 1. External modules (orders, procurement, manual operations, etc.) write intents to request inventory actions.
158
+ 2. Inventory Core executors validate the intents and apply them to the confirmation tables according to availability and business rules (priority, location selection).
159
+ 3. When confirmed, Core appends statuses to `inventory.statusHistory` and emits CDC events.
160
+ 4. Derived projections (for example latest stock summary, shortage report) refresh as needed.
161
+
162
+ ## Downstream Consumption
163
+ - Order and channel integration modules read `inventory.reservation` and `inventory.statusHistory` to reflect reservation outcomes and shipping progress in their UIs.
164
+ - Procurement confirms inbound receipts through `inventory.stockLedger` and reconciles stock increases.
165
+ - Analytics and forecasting modules consume `inventory.stock` alongside `inventory.stockLedger` to evaluate inventory levels and turns.
166
+
167
+ ## CDC Flow Overview
168
+ ### Scenario: Order Line to Shipped
169
+ ```mermaid
170
+ sequenceDiagram
171
+ autonumber
172
+ participant Order as Order Module
173
+ participant OrderItem as order.orderItem
174
+ participant ReserveExecutor as inventory-reserve-on-order-item-created
175
+ participant ReservationIntent as inventory.reservationIntent
176
+ participant Reservation as inventory.reservation
177
+ participant FulfillmentExecutor as warehouse-fulfillment-task-progress
178
+ participant FulfillmentTask as inventory.fulfillmentTask
179
+ participant StatusHistory as inventory.statusHistory
180
+ participant StockLedger as inventory.stockLedger
181
+ participant Stock as inventory.stock
182
+
183
+ Order->>OrderItem: persist order line
184
+ OrderItem-->>ReserveExecutor: CDC new order item event
185
+ ReserveExecutor->>ReservationIntent: create reservation intent (sourceRef = orderItem.id)
186
+ ReservationIntent-->>ReserveExecutor: CDC new intent event
187
+ ReserveExecutor->>Reservation: persist reservation
188
+ ReserveExecutor->>StatusHistory: write reservation_confirmed
189
+ ReserveExecutor->>StockLedger: hold quantity delta
190
+ StockLedger-->>Stock: CDC projection updates available/on-hand
191
+
192
+ FulfillmentExecutor->>FulfillmentTask: create task (reservationId)
193
+ FulfillmentExecutor->>StatusHistory: write fulfillment_task_created
194
+
195
+ FulfillmentExecutor->>FulfillmentTask: mark picking complete
196
+ FulfillmentExecutor->>StatusHistory: write picked
197
+
198
+ FulfillmentExecutor->>FulfillmentTask: mark shipped
199
+ FulfillmentExecutor->>StatusHistory: write shipped
200
+ FulfillmentExecutor->>StockLedger: deduct shipment quantity
201
+ StockLedger-->>Stock: CDC projection updates available/on-hand
202
+ ```
203
+
204
+ The shipping portion of this flow relies on the warehouse extension executor (`warehouse-fulfillment-task-progress`) to reflect physical operations; Inventory Core focuses on intents, reservations, ledger accuracy, and projecting those ledger deltas into `inventory.stock`.
205
+
206
+ This scenario keeps the dependency pointing from Inventory back to Order: the order module publishes its own state change (`order.orderItem` row + CDC), and Inventory Core reacts via its executor without requiring an API call from Order into Inventory.
207
+
208
+ ## Dependency Guidelines
209
+ - Inventory Core is the single source of truth for stock; only Core mutates quantities while other modules issue intents.
210
+ - Core depends on shared SKU and location masters (typically from Commerce Core) but does not create reverse dependencies.
211
+ - Industry modules extend the contracts, yet Core itself remains free of industry-specific fields or logic.
212
+
213
+ ## Versioning & Change Management
214
+ - Introduce new optional fields on intent/confirmation tables and allow consumers a migration window.
215
+ - Document naming guidelines and semantics whenever status vocabulary expands, and notify downstream modules.
216
+ - When breaking changes are unavoidable, ship a parallel contract version (for example `inventory.reservationIntent.v2`).
217
+
218
+ ## Operational Considerations
219
+ - Provide reconciliation tools (replay/rebuild) so `inventory.stock` can be regenerated from intents and the ledger.
220
+ - Define locking strategies at SKU and location granularity to minimise contention.
221
+ - Offer batch intents or aggregate APIs for high-volume updates to balance performance and consistency.
222
+ - Establish retention and archiving policies for the ledger and status history based on audit requirements.
223
+
224
+ ## Extension Points for Industry Modules
225
+ - **Lot/serial management**: Attach extension tables with foreign keys such as `lotId` / `serialId` and expose hooks within intent and ledger processing.
226
+ - **Quality inspection**: Append quality-related statuses (for example `inventory:quality_hold`) to `inventory.statusHistory` and integrate with warehouse execution modules.
227
+ - **Construction and bulky goods**: Extend location hierarchies so locations can represent job sites or delivery vehicles.
228
+ - **Healthcare and food**: Track compliance attributes (expiry date, temperature band, etc.) via `attributes` and statuses; implement expiry blocking rules in the extension module.
229
+
230
+ With this contract in place, scenario documents (channel integration, procurement, inventory reservation, etc.) can gradually migrate to reference Inventory Core. Industry modules achieve required granularity through schema extensions and additional statuses.
@@ -0,0 +1,132 @@
1
+ # Order Module Core Contract
2
+
3
+ ## Goal
4
+ Maintain the order module as a clean, channel-neutral core that accepts standardised intents, persists canonical orders, and exposes status history for downstream consumers without leaking external system concerns.
5
+
6
+ ## Module Boundary
7
+ - Own canonical order identifiers, customer references, and pricing snapshots required by internal workflows.
8
+ - Publish contracts that upstream systems write to (`order.orderIntent`) and downstream systems read (`order.order`, `orderStatusHistory`).
9
+ - Avoid dependencies on channel integrations, inventory logic, billing specifics, or storefront payload schemas.
10
+ - Surface read models through TailorDB views or projections instead of embedding module-specific fields in `order.order`.
11
+
12
+ ## Published Contracts
13
+
14
+ All tables implicitly include an auto-generated `id` primary key; only domain-specific columns are listed below.
15
+
16
+ ### `order.orderIntent`
17
+ | Field | Description |
18
+ | --- | --- |
19
+ | `orderIntentId` | Stable identifier generated by the caller; dedupe key combined with `sourceSystem`.
20
+ | `sourceSystem` | Logical system identifier (e.g., `channel.shopify`, `crm.salesforce`).
21
+ | `externalOrderId` | Optional reference for tracing back to the originating system.
22
+ | `customerRef` | Customer identity reference understood by commerce core/CRM.
23
+ | `lineItems` | Array of SKU identifiers, quantities, and pricing snapshots already mapped to internal product IDs.
24
+ | `totals` | Order-level monetary snapshot (currency, subtotal, tax, shipping, discounts).
25
+ | `submittedAt` | Timestamp from the originating system; used for sequencing when backfilling.
26
+ | `payloadHash` | Optional trace hash to support replay verification.
27
+
28
+ **Responsibilities**
29
+ - Callers (channel integration, CRM, manual tools) must write intents via the published contract and handle idempotency using `orderIntentId` + `sourceSystem`.
30
+ - Intents remain mutable only until acknowledged by the order module; mutations must create new intents.
31
+
32
+ ### `order.order`
33
+ | Field | Description |
34
+ | --- | --- |
35
+ | `customerRef` | Carried over from the intent; never rewritten by downstream modules.
36
+ | `lineItems` | Snapshot derived from the accepted intent; includes SKU, quantity, unit price, totals.
37
+ | `currency` | ISO currency code resolved via commerce core metadata.
38
+ | `createdAt` / `updatedAt` | Managed by the order module; reflect canonical lifecycle timestamps.
39
+ | `intentRef` | Foreign key back to `order.orderIntent` for traceability.
40
+ **Responsibilities**
41
+ - Remains immutable for line items and monetary values once created; adjustments require follow-up intents or dedicated adjustment commands.
42
+ - Exposes only generic fields; module-specific state must live in projections or status history.
43
+
44
+ ### `orderStatusHistory`
45
+ | Field | Description |
46
+ | --- | --- |
47
+ | `orderId` | Order identifier referencing `order.order`.
48
+ | `module` | Namespace-qualified module writing the status (e.g., `channel`, `inventory`, `billing`).
49
+ | `statusCode` | Module-defined status code (e.g., `channel:captured`, `procurement:po_confirmed`).
50
+ | `category` | Optional grouping such as `fulfillment`, `payment`, `support`.
51
+ | `severity` | Optional flag (`info`, `warning`, `blocking`) signalling operational impact.
52
+ | `payload` | JSON payload for contextual metadata (tracking number, reason codes, ETA).
53
+ | `recordedAt` | Timestamp supplied by the writer; used for chronological rendering.
54
+ | `writtenBy` | Executor/actor responsible for the entry.
55
+ | `closedAt` | Optional timestamp when the status is superseded/resolved.
56
+
57
+ **Responsibilities**
58
+ - Writers append-only; updates occur by inserting new entries instead of mutating existing ones.
59
+ - Downstream projections (latest status, blocking status, timeline views) are derived from this table.
60
+ - Status vocabularies are documented per module to avoid collisions; the order module provides write APIs but does not interpret module-specific semantics.
61
+
62
+ ## Status Model Principles
63
+ - Clean core: `order.order` keeps only canonical attributes; module-specific lifecycle stays in history/projections.
64
+ - History over flags: statuses are append-only rows, not columns on `order.order`.
65
+ - Module ownership: each module writes its own statuses; order core supplies infrastructure only.
66
+ - Read-only projections: UIs read history + module projections; modules never mutate others' tables.
67
+ - Optional composition: modules can be added/removed without schema migrations to `order.order`.
68
+
69
+ ### Order Status Vocabulary
70
+
71
+ | Label | Writer | Trigger timing | Notes |
72
+ | --- | --- | --- | --- |
73
+ | `order:submitted` | Order module | Immediately after an `orderIntent` is accepted and converted into `order.order`. | Establishes the baseline timeline entry for all downstream consumers. |
74
+ | `order:manually_adjusted` | Order module / Operator | Whenever an operator edits the order after creation (e.g., address correction, line adjustment). | Signals other modules to reconcile manual updates or rerun validation. |
75
+ | `order:cancelled` | Order module / Operator | When the order is cancelled or voided. | Downstream modules should unwind reservations, authorizations, and tasks. |
76
+
77
+ Modules must introduce additional statuses using their own namespace prefix (e.g., `inventory:*`, `billing:*`). Shared dashboards consume this vocabulary to build customer-facing timelines.
78
+
79
+ ## Projections & Queries
80
+ - Latest status per module: windowed view picking the newest entry per `(orderId, module)`.
81
+ - Blocking status detection: filter where `severity = 'blocking'` and `closedAt IS NULL` to pause fulfilment/billing.
82
+ - Timelines: list all history entries ordered by `recordedAt` for customer communications.
83
+ - Aggregations: dashboards (e.g., counts of `procurement:delayed`) without touching `order.order` schema.
84
+
85
+ ## Integration Patterns
86
+ - Inventory/Procurement: executors write `procurement:po_*`, `inventory:reservation_*`; projections decide release timing.
87
+ - Billing/Payments: append `billing:invoice_posted`, `billing:payment_failed`; UIs read history for payment lifecycle.
88
+ - Multi-entity: log `entity:*` milestones (policy snapshots, settlements) without adding entity fields to orders.
89
+ - CRM/Customer success: `crm:*` entries (case opened, loyalty awarded) live in history, not in `order.order`.
90
+ - Manual operations: operators insert `manual:*` notes for auditability.
91
+
92
+ ## Design Guidelines
93
+ 1. Naming discipline: use `module:status` to avoid collisions and simplify filtering.
94
+ 2. Idempotent writes: guard against duplicates (check last status per module where needed).
95
+ 3. Retention: define history retention/partitioning; plan for high-volume modules.
96
+ 4. Access control: modules insert/update only their own statuses; apply RBAC for manual tools.
97
+ 5. Testing: integration tests should assert history entries for key flows and respect blocking statuses.
98
+ 6. Documentation: each module documents its vocabulary and payload expectations.
99
+
100
+ ## Migration Strategy
101
+ 1. Create `orderStatusHistory` and backfill from legacy order columns if present.
102
+ 2. Update executors/modules to append history instead of mutating `order.order` columns.
103
+ 3. Deprecate legacy status columns once consumers pivot to history-driven projections.
104
+ 4. Provide transitional views so downstream systems can adopt the model gradually.
105
+
106
+ ## Ingestion Pattern
107
+ 1. External systems transform their payloads into the `order.orderIntent` schema.
108
+ 2. The order module validates intents (schema, dedupe, referenced entities), persists them, and emits a CDC event.
109
+ 3. `orderIntentIngestor` consumes the CDC stream, creates the canonical `order.order`, and records the originating mapping.
110
+ 4. Success results in a `channel:captured` (or equivalent) entry appended to `orderStatusHistory`.
111
+ 5. Failure scenarios raise rejection events so the caller can diagnose issues without introducing direct dependencies on order internals.
112
+
113
+ ## Downstream Consumption
114
+ - Inventory, procurement, billing, and CRM modules listen to `order.order` CDC events to start their workflows.
115
+ - Status dashboards query projections derived from `orderStatusHistory` to display customer timelines and operational alerts.
116
+ - Channel-specific projections (e.g., `channel.statusProjection`) remain within the owning module and reference `orderId` and `orderStatusHistory` data as needed.
117
+
118
+ ## Dependency Guidelines
119
+ - Order depends only on shared infrastructure modules (e.g., commerce core for product metadata).
120
+ - Upstream modules must depend on the order contract to write intents; downstream modules may depend on the order module for CDC schemas and read models.
121
+ - Bidirectional dependencies are avoided by using shared tables (`order.orderIntent`, `orderStatusHistory`) as integration boundaries.
122
+
123
+ ## Versioning & Change Management
124
+ - Introduce new fields in `order.orderIntent` as optional with defaults; communicate schema revisions through versioned documentation.
125
+ - Provide a deprecation window before enforcing mandatory fields so channel connectors can adopt changes.
126
+ - For breaking changes, publish a new contract version (e.g., `order.orderIntent.v2`) and run both in parallel until migration completes.
127
+
128
+ ## Operational Considerations
129
+ - Implement replay tooling to rebuild orders from intents for audit scenarios.
130
+ - Monitor dedupe metrics to detect misconfigured source systems.
131
+ - Enforce payload size limits and validation rules to prevent unbounded data ingestion.
132
+ - Retain intents for the retention period required by compliance/audit and purge only after downstream reconciliation.
@@ -0,0 +1,73 @@
1
+ # Inventory Reservation Scenario
2
+
3
+ ## Overview
4
+ This document captures a flow where the order module remains independent while an optional inventory module automates stock reservations. Back-office teams can maintain inventory manually (for example via spreadsheets or direct TailorDB edits), and when the inventory module is enabled it reacts to order events, applies reservation logic, and publishes stock projections without imposing reverse dependencies on the order module. The order contract referenced here is defined in [Order Module Core Contract](../order-module-core-contract.md).
5
+
6
+ ## Module Dependencies
7
+
8
+ | Module (package path) | Declared dependencies | Purpose |
9
+ | --- | --- | --- |
10
+ | Commerce core (`packages/commerce-core-module`) | — | Owns product and customer master data; exposes immutable definitions consumed by downstream modules. |
11
+ | Order (`packages/order-module`) | — | Publishes the `order.orderIntent` contract, stores canonical orders, and exposes status history for downstream projections. |
12
+ | Inventory (`packages/inventory-module`) | Order, Commerce core | Listens to order events to automate reservations and uses commerce metadata to resolve SKU attributes. |
13
+
14
+ ## TailorDB Tables and Views
15
+ - Uses core tables `inventory.reservation` and `inventory.stockLedger` as defined in `core/inventory-module.md`; not redefined here.
16
+ - `inventory.remainingStock`: Derived view exposing per-SKU on-hand quantities for read-only consumers (scenario-local read model).
17
+
18
+ ## Order Status
19
+
20
+ Baseline `order:*` statuses are defined in [Order Module Core Contract](../order-module-core-contract.md#order-status-vocabulary). This scenario appends the following inventory-originated statuses into `orderStatusHistory` so order consumers can see reservation outcomes without querying inventory tables directly:
21
+
22
+ | Label | Writer | Trigger timing | Notes |
23
+ | --- | --- | --- | --- |
24
+ | `inventory:reservation_created` | Inventory module | When `inventoryReservationIntake` begins reserving stock for an order. | Optional; useful for long-running reservation processes. |
25
+ | `inventory:reservation_confirmed` | Inventory module | After stock is successfully reserved. | Indicates inventory has secured the requested quantities. |
26
+ | `inventory:reservation_backordered` | Inventory module | When inventory cannot fully reserve quantities. | Marks the order as waiting on replenishment. |
27
+ | `inventory:reservation_cancelled` | Inventory module | When a reservation is released due to order change or cancellation. | Ensures support teams understand why stock was freed. |
28
+
29
+ ## Inventory Status (scenario-specific)
30
+
31
+ This scenario does not introduce additional inventory status codes beyond the core vocabulary. It emits the core `inventory:reservation_*` statuses above; other core statuses (for example `inventory:stock_adjusted`, `inventory:fulfillment_task_created`) remain available but are not invoked in this flow.
32
+
33
+ ## Executor Triggers
34
+
35
+ | Trigger table (module) | Writers (modules) | Activation timing | Target executor (module) | Responsibility |
36
+ | --- | --- | --- | --- | --- |
37
+ | `order.order` (order) | Order (owner), operators | Record creation or update (CDC) | `inventoryReservationIntake` (inventory) | Decide whether to create/update `inventory.reservation` entries based on order status; can be disabled for manual-only workflows. |
38
+ | `inventory.reservation` (inventory) | Inventory (owner), operators | Record creation or update (CDC) | `inventoryReservationProjector` (inventory) | Maintain `inventory.remainingStock` snapshots and ensure reservations propagate to the ledger when required. |
39
+ | `inventory.stockLedger` (inventory) | Inventory (owner), operators | Record creation (CDC) | `inventoryStockMetricsUpdater` (inventory) | Update analytical projections and audit views after any stock movement (manual or automated). |
40
+
41
+ ## Flow
42
+ 1. An operator or integration submits `order.orderIntent`; the order module validates and ingests it into `order.order`, emitting a CDC event. Manual edits can still be applied directly to `order.order` when policy permits.
43
+ 2. If the inventory module is enabled, `inventoryReservationIntake` reacts to the order CDC event and records reservation rows in `inventory.reservation` (and, when relevant, appends movements to `inventory.stockLedger`). If automation is disabled, operators can insert reservations or ledger entries manually without involving the executor.
44
+ 3. Inventory appends reservation outcomes (`inventory:reservation_confirmed`, `inventory:reservation_backordered`) to `orderStatusHistory` so order consumers can see automation progress without depending directly on inventory tables.
45
+ 4. CDC events on `inventory.reservation` and `inventory.stockLedger` trigger inventory-side projectors that refresh `inventory.remainingStock` and other read models.
46
+ 5. Order-facing UIs or reports can query `inventory.remainingStock` for availability and combine it with `orderStatusHistory` to display reservation timelines, while the order module itself remains oblivious to how the data originated.
47
+ 6. Commerce core continues to publish product metadata; inventory consumes this data but does not introduce reverse dependencies on order.
48
+
49
+ ```mermaid
50
+ sequenceDiagram
51
+ actor Operator
52
+ participant Order
53
+ participant Inventory
54
+ participant Commerce
55
+
56
+ Operator->>Order: submit orderIntent (manual or automated)
57
+ Order->>Order: orderIntentIngestor creates order.order
58
+ Order-->>Inventory: order.order CDC event (optional automation)
59
+ Inventory->>Inventory: inventoryReservationIntake evaluates reservation logic
60
+ Inventory->>Inventory: write inventory.reservation / inventory.stockLedger
61
+ Inventory->>Order: append inventory:* status history entries
62
+ Inventory-->>Inventory: reservation/ledger CDC refreshes remainingStock
63
+ Operator->>Inventory: manual adjustments as needed
64
+ Inventory-->>Order: remainingStock exposed via read-only view
65
+ Inventory-->>Commerce: read product metadata
66
+ ```
67
+
68
+ ## Design Considerations
69
+ - Keep order independent so manual-only workflows remain viable even without the inventory module; follow the contract in `../order-module-core-contract.md` when extending ingestion.
70
+ - Inventory automation should be idempotent and tolerant of manual edits, reconciling rather than overwriting operator input in reservation and ledger tables.
71
+ - Append reservation outcomes to `orderStatusHistory` with a documented status vocabulary (`inventory:reservation_*`) so order consumers do not query inventory tables directly.
72
+ - Downstream consumers read `inventory.remainingStock` (or similar projections) without mutating inventory-owned tables.
73
+ - Commerce core continues to act as the canonical source for SKU definitions; inventory depends on it, not the other way around.
@@ -0,0 +1,99 @@
1
+ # Multi-Storefront Order Scenario
2
+
3
+ ## Overview
4
+ This scenario covers an organisation selling through multiple storefronts (e.g., Shopify, Amazon) while sharing a single stock pool. The order module stays channel-agnostic: dedicated channel integration modules capture storefront events, translate them into core orders, and coordinate inventory reservations. Channel-specific fulfilment states and acknowledgements live outside the order schema in status history and channel projections. The shared contract for the clean order core is documented in [Order Module Core Contract](../order-module-core-contract.md).
5
+
6
+ ## Module Dependencies
7
+
8
+ | Module (package path) | Declared dependencies | Purpose |
9
+ | --- | --- | --- |
10
+ | Channel integration (`packages/channel-integration-module`) | Commerce core, Order | Pulls orders from external storefronts, maps product identifiers, and writes standardised order intents through the order module contract. |
11
+ | Order (`packages/order-module`) | — | Publishes the `orderIntent` contract, stores canonical orders, and exposes status history for downstream modules. |
12
+ | Inventory (`packages/inventory-module`) | Order, Commerce core | Manages shared stock, reservations, and warehouse operations. |
13
+ | Commerce core (`packages/commerce-core-module`) | — | Owns product catalogue, channel SKU mappings, and pricing metadata. |
14
+ | Channel sync (`packages/channel-sync-module`) | Inventory, Channel integration | Publishes stock levels and fulfilment confirmations back to the storefronts. |
15
+
16
+ ## TailorDB Tables and Views
17
+ ### Channel integration module
18
+ - `channel.orderCapture`: Raw storefront payloads kept for traceability, enrichment, and replay (shop identifier, channel order id, customer info, line allocations).
19
+ - `channel.orderMapping`: Links channel order ids to the generated `orderId` after the intent is processed; also records the originating `orderIntentId` for audits.
20
+ - `channel.statusProjection`: Channel-facing projection of statuses (acknowledged, packed, shipped) derived from history entries.
21
+
22
+ ### Inventory module
23
+ - Uses core inventory tables (`inventory.reservation`, `inventory.stock`, `inventory.fulfillmentTask`, `inventory.statusHistory`, etc.) as defined in `../core/inventory-module.md`; not redefined here.
24
+
25
+ ### Channel sync module
26
+ - `channel.stockFeed`: Snapshot of stock availability per storefront (SKU, channel SKU, available quantity, last synced at).
27
+ - `channel.fulfilmentFeed`: Outbound acknowledgements (tracking numbers, shipped quantity) queued for storefront APIs.
28
+
29
+ ## Order Status
30
+
31
+ Baseline `order:*` statuses appear in [Order Module Core Contract](../order-module-core-contract.md#order-status-vocabulary). Multi-storefront flows add the following channel and inventory signals:
32
+
33
+ | Label | Writer | Trigger timing | Notes |
34
+ | --- | --- | --- | --- |
35
+ | `channel:captured` | Order module (on behalf of channel) | Immediately after `orderIntentIngestor` creates the core order and records the channel mapping. | Confirms that the storefront intent has been accepted into the core system. |
36
+ | `inventory:reservation_confirmed` | Inventory module | When stock is successfully reserved. | Signals to channels that fulfilment can proceed. |
37
+ | `inventory:reservation_backordered` | Inventory module | When stock is insufficient and a backorder is created. | Allows channel integration to notify storefronts about delays. |
38
+ | `inventory:shipped` | Inventory module / Warehouse | After fulfilment tasks complete and goods leave the warehouse. | Provides shipment milestone prior to storefront acknowledgement. |
39
+ | `channel:reservation_confirmed` | Channel integration | When `channelReservationProjector` reflects inventory confirmation back to the storefront. | Keeps channel dashboards consistent with internal state. |
40
+ | `channel:acknowledged` | Channel integration | Once the storefront API confirms receipt of fulfilment or stock updates. | Closes the loop and highlights any outstanding acknowledgements. |
41
+
42
+ ## Executor Triggers
43
+
44
+ | Trigger table (module) | Writers (modules) | Activation timing | Target executor (module) | Responsibility |
45
+ | --- | --- | --- | --- | --- |
46
+ | `order.orderIntent` (order) | Channel integration (via contract) | Record creation (CDC) | `orderIntentIngestor` (order) | Validate intent, ensure idempotency, create `order.order`, append `channel:captured` entry to `orderStatusHistory`, and register mapping in `channel.orderMapping`. |
47
+ | `order.order` (order) | Order (owner) | Record creation (CDC) | `inventoryReservationIntake` (inventory) | Reserve shared stock for the order; write `inventory:reservation_*` statuses. |
48
+ | `inventory.reservation` (inventory) | Inventory (owner) | Record creation or update (CDC) | `channelReservationProjector` (channel integration) | Evaluate reservation results; update `channel.statusProjection` and append statuses (`channel:reservation_confirmed`, etc.). |
49
+ | `inventory.fulfilmentTask` (inventory) | Inventory (owner), warehouse systems | Record update (CDC) | `channelFulfilmentNotifier` (channel sync) | When tasks complete, enqueue shipping confirmations in `channel.fulfilmentFeed` and append `inventory:shipped` history entries. |
50
+ | `channel.fulfilmentFeed` (channel sync) | Channel sync (owner) | Record update (CDC) | `channelAckTracker` (channel integration) | Confirm storefront receipt of fulfilment data; append `channel:acknowledged` history entry when storefront confirms. |
51
+ | `inventory.stock` (inventory) | Inventory (owner) | Record update (CDC) | `channelStockPublisher` (channel sync) | Refresh `channel.stockFeed` to push near real-time stock availability to storefronts. |
52
+
53
+ ## Flow
54
+ 1. Shopify and Amazon orders are ingested by the channel integration module, stored in `channel.orderCapture` for traceability, deduped, and transformed into `order.orderIntent` records through the order contract.
55
+ 2. `orderIntentIngestor` validates each intent, creates the core `order.order`, writes the channel mapping, and inserts a `channel:captured` row in `orderStatusHistory`.
56
+ 3. The order creation triggers `inventoryReservationIntake`, which reserves stock. Depending on availability, it inserts statuses such as `inventory:reservation_confirmed` or `inventory:reservation_backordered`.
57
+ 4. Reservation outcomes trigger `channelReservationProjector`, which updates `channel.statusProjection` for each storefront and writes additional history entries so UIs can display per-channel progress.
58
+ 5. Warehouse operations progress via `inventory.fulfilmentTask`. When tasks complete, `channelFulfilmentNotifier` produces `channel.fulfilmentFeed` rows and appends `inventory:shipped` history entries.
59
+ 6. `channelStockPublisher` listens to `inventory.stock` updates and refreshes `channel.stockFeed`, ensuring storefronts receive the latest availability for overselling prevention.
60
+ 7. Storefronts acknowledge shipments and stock updates via APIs. `channelAckTracker` marks `channel.fulfilmentFeed` entries as confirmed and writes `channel:acknowledged` status history rows. Pending acknowledgements remain visible for support teams.
61
+ 8. Customer-facing applications query `orderStatusHistory` (or derived views) to render timelines, while channel dashboards rely on `channel.statusProjection` for storefront-specific messaging.
62
+
63
+ ```mermaid
64
+ sequenceDiagram
65
+ actor Shopify
66
+ actor Amazon
67
+ participant Channel as ChannelIntegration
68
+ participant Order
69
+ participant Inventory
70
+ participant Sync as ChannelSync
71
+ actor Warehouse
72
+
73
+ Shopify->>Channel: push order payload
74
+ Amazon->>Channel: push order payload
75
+ Channel->>Channel: store channel.orderCapture & dedupe
76
+ Channel->>Order: write order.orderIntent via contract
77
+ Order->>Order: orderIntentIngestor creates order + status history
78
+ Order-->>Inventory: order.order CDC event
79
+ Inventory->>Inventory: inventoryReservationIntake reserves stock
80
+ Inventory-->>Channel: reservation CDC updates status projection
81
+ Inventory->>Warehouse: emit fulfilmentTask
82
+ Warehouse-->>Inventory: complete fulfilmentTask
83
+ Inventory->>Sync: channelFulfilmentNotifier enqueues fulfilmentFeed
84
+ Sync->>Shopify: send shipment & stock update
85
+ Sync->>Amazon: send shipment & stock update
86
+ Shopify-->>Channel: ack shipment
87
+ Amazon-->>Channel: ack shipment
88
+ Channel->>Order: channelAckTracker appends status history
89
+ ```
90
+
91
+ ## Design Considerations
92
+ - Keep the order module channel-neutral; storefront-specific payloads stay in channel integration tables, while `order.orderIntent` only contains the normalised fields required by the core order schema.
93
+ - Maintain idempotent ingestion: dedupe channel payloads (channel order id + storefront id) before writing to `order.orderIntent` so order ingestion remains idempotent.
94
+ - Version the `orderIntent` contract and publish compatibility guidelines so new fields roll out without breaking existing channel connectors.
95
+ - Use `orderStatusHistory` to represent storefront and inventory milestones; avoid proliferating channel fields on the order record.
96
+ - Provide per-channel projections (`channel.statusProjection`) to avoid overloading shared history queries when storefront portals need dedicated filters.
97
+ - Stock publishing should throttle or batch updates per storefront to honour API limits while still preventing overselling.
98
+ - Errors in storefront communication should create `severity = 'blocking'` history entries so billing/fulfilment can pause until acknowledgements arrive.
99
+ - Document the vocabulary of channel statuses (e.g., `channel:captured`, `channel:acknowledged`) so downstream consumers interpret them consistently.