@open-mercato/core 0.6.3-develop.3810.1.ad92c339f5 → 0.6.3-develop.3811.1.be22750402

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/AGENTS.md CHANGED
@@ -2,6 +2,42 @@
2
2
 
3
3
  `@open-mercato/core` contains all core business modules (auth, catalog, customers, sales, etc.). This guide covers the full extensibility contract and module development patterns.
4
4
 
5
+ ## Always
6
+
7
+ - Preserve auto-discovery contracts for module files, API routes, pages, subscribers, workers, widgets, and generated registries.
8
+ - Export `openApi` from every API route file.
9
+ - Use `makeCrudRoute` with `indexer: { entityType }` for CRUD routes that should participate in query indexing.
10
+ - Wire custom write routes through the mutation guard contract.
11
+ - Use declarative feature guards and add new `acl.ts` features to `setup.ts` `defaultRoleFeatures`.
12
+ - Use `findWithDecryption` / `findOneWithDecryption` for encrypted entities.
13
+ - Implement domain writes through commands so audit, undo, cache, events, and indexing stay consistent.
14
+ - Run `yarn generate` after changing module files discovered by the generator.
15
+
16
+ ## Ask First
17
+
18
+ - Ask before changing any contract surface from `BACKWARD_COMPATIBILITY.md`: auto-discovery, public types, import paths, event IDs, widget spot IDs, API URLs, DB schema, DI names, ACL features, notification IDs, CLI commands, or generated file contracts.
19
+ - Ask before moving versioned generated files or changing where generated registries live.
20
+ - Ask before applying migrations with `yarn db:migrate`; normal PRs should include migration files and snapshots.
21
+
22
+ ## Never
23
+
24
+ - Never create direct ORM relationships between modules; use foreign key IDs and fetch separately.
25
+ - Never expose cross-tenant data or omit tenant/organization scoping.
26
+ - Never hand-edit generated files.
27
+ - Never import generated app bootstrap files from packages.
28
+ - Never run raw `em.find` / `em.findOne` between scalar mutations and `em.flush()` on the same `EntityManager` without `withAtomicFlush`.
29
+ - Never hand-roll AES/KMS encryption or bypass `TenantDataEncryptionService`.
30
+ - Never compare raw feature arrays with exact string checks when wildcard grants apply.
31
+
32
+ ## Validation Commands
33
+
34
+ ```bash
35
+ yarn db:generate
36
+ yarn generate
37
+ yarn workspace @open-mercato/core build
38
+ yarn workspace @open-mercato/core test
39
+ ```
40
+
5
41
  ## Core Modules
6
42
 
7
43
  | Module | Path | Description |
@@ -593,7 +629,7 @@ const crud = makeCrudRoute({
593
629
  })
594
630
  ```
595
631
 
596
- ### Key Rules
632
+ ### Response Enricher Rules
597
633
 
598
634
  - MUST implement `enrichMany()` for batch endpoints (prevents N+1 queries)
599
635
  - MUST namespace enriched fields with `_moduleName` prefix (e.g. `_example.todoCount`)
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@open-mercato/core",
3
- "version": "0.6.3-develop.3810.1.ad92c339f5",
3
+ "version": "0.6.3-develop.3811.1.be22750402",
4
4
  "type": "module",
5
5
  "main": "./dist/index.js",
6
6
  "scripts": {
@@ -243,16 +243,16 @@
243
243
  "zod": "^4.4.3"
244
244
  },
245
245
  "peerDependencies": {
246
- "@open-mercato/ai-assistant": "0.6.3-develop.3810.1.ad92c339f5",
247
- "@open-mercato/shared": "0.6.3-develop.3810.1.ad92c339f5",
248
- "@open-mercato/ui": "0.6.3-develop.3810.1.ad92c339f5",
246
+ "@open-mercato/ai-assistant": "0.6.3-develop.3811.1.be22750402",
247
+ "@open-mercato/shared": "0.6.3-develop.3811.1.be22750402",
248
+ "@open-mercato/ui": "0.6.3-develop.3811.1.be22750402",
249
249
  "react": "^19.0.0",
250
250
  "react-dom": "^19.0.0"
251
251
  },
252
252
  "devDependencies": {
253
- "@open-mercato/ai-assistant": "0.6.3-develop.3810.1.ad92c339f5",
254
- "@open-mercato/shared": "0.6.3-develop.3810.1.ad92c339f5",
255
- "@open-mercato/ui": "0.6.3-develop.3810.1.ad92c339f5",
253
+ "@open-mercato/ai-assistant": "0.6.3-develop.3811.1.be22750402",
254
+ "@open-mercato/shared": "0.6.3-develop.3811.1.be22750402",
255
+ "@open-mercato/ui": "0.6.3-develop.3811.1.be22750402",
256
256
  "@testing-library/dom": "^10.4.1",
257
257
  "@testing-library/jest-dom": "^6.9.1",
258
258
  "@testing-library/react": "^16.3.1",
@@ -2,6 +2,33 @@
2
2
 
3
3
  The auth module handles authentication, authorization, users, roles, and RBAC.
4
4
 
5
+ ## Always
6
+
7
+ 1. Hash passwords with `bcryptjs` using cost >= 10.
8
+ 2. Use `findWithDecryption` / `findOneWithDecryption` for user queries.
9
+ 3. Prefer `requireFeatures` in page/API metadata for access control.
10
+ 4. Declare every module feature in `acl.ts` and seed role grants through `setup.ts`.
11
+ 5. Use wildcard-aware helpers such as `matchFeature`, `hasFeature`, and `hasAllFeatures` when inspecting raw granted features.
12
+
13
+ ## Ask First
14
+
15
+ - Ask before changing session token format, RBAC semantics, wildcard matching, super-admin behavior, or tenant provisioning outputs.
16
+ - Ask before changing login/reset/invitation error messages because auth messages can leak account existence.
17
+
18
+ ## Never
19
+
20
+ - Never log credentials, password reset tokens, session tokens, or decrypted user secrets.
21
+ - Never reveal whether an email exists through auth error messages.
22
+ - Never check raw ACL arrays with `includes(...)`, `Set.has(...)`, or ad hoc wildcard logic.
23
+
24
+ ## Validation Commands
25
+
26
+ ```bash
27
+ yarn generate
28
+ yarn workspace @open-mercato/core build
29
+ yarn workspace @open-mercato/core test
30
+ ```
31
+
5
32
  ## Data Model
6
33
 
7
34
  - **Users** — system users with credentials, profile, preferences
@@ -2,14 +2,33 @@
2
2
 
3
3
  Use the catalog module for products, categories, pricing, variants, and offers.
4
4
 
5
- ## MUST Rules
5
+ ## Always
6
6
 
7
- 1. **MUST NOT reimplement pricing logic** — use `selectBestPrice` and the resolver pipeline from `lib/pricing.ts`
7
+ 1. **MUST use `selectBestPrice` and the resolver pipeline from `lib/pricing.ts`** for pricing logic.
8
8
  2. **MUST use the DI token `catalogPricingService`** when resolving prices — ensures overrides take effect
9
9
  3. **MUST register custom pricing resolvers** with explicit priority (`registerCatalogPricingResolver(resolver, { priority })`)
10
10
  4. **MUST declare widget injections** in `widgets/injection/` and map via `injection-table.ts`
11
11
  5. **MUST follow the standard event pattern** in `events.ts` for all CRUD and lifecycle events
12
12
 
13
+ ## Ask First
14
+
15
+ - Ask before changing price-layer precedence, resolver priority semantics, event IDs, or released widget spot IDs.
16
+ - Ask before deleting or changing option schemas that existing variants may reference.
17
+
18
+ ## Never
19
+
20
+ - Never reimplement catalog pricing inline.
21
+ - Never delete option schemas while variants reference them.
22
+ - Never bypass `prepareMutation` for catalog AI tools that mutate products, prices, or media.
23
+
24
+ ## Validation Commands
25
+
26
+ ```bash
27
+ yarn db:generate
28
+ yarn generate
29
+ yarn workspace @open-mercato/core build
30
+ ```
31
+
13
32
  ## When You Need Pricing Logic
14
33
 
15
34
  1. Resolve `catalogPricingService` from DI
@@ -2,13 +2,32 @@
2
2
 
3
3
  Use the currencies module for multi-currency support, exchange rates, and currency conversion.
4
4
 
5
- ## MUST Rules
5
+ ## Always
6
6
 
7
7
  1. **MUST store currency amounts with 4 decimal precision** — never truncate to 2 decimals internally
8
8
  2. **MUST use date-based exchange rates** — always resolve rates for the transaction date, not "current" rate
9
9
  3. **MUST record both transaction currency and base currency amounts** — dual recording is mandatory for reporting
10
10
  4. **MUST calculate realized gains/losses** on payment: `(payment rate - invoice rate) × foreign amount`
11
- 5. **MUST NOT hard-delete exchange rate records** — rates are historical reference data
11
+ 5. **MUST keep financial postings atomic** — full transaction rollback on error
12
+
13
+ ## Ask First
14
+
15
+ - Ask before changing precision, exchange-rate lookup semantics, realized gain/loss formulas, or financial reporting fields.
16
+ - Ask before changing historical exchange-rate retention behavior.
17
+
18
+ ## Never
19
+
20
+ - Never truncate internal currency amounts to 2 decimals.
21
+ - Never hard-delete exchange rate records — rates are historical reference data.
22
+ - Never delete posted transactions or audit-trail entries.
23
+
24
+ ## Validation Commands
25
+
26
+ ```bash
27
+ yarn db:generate
28
+ yarn generate
29
+ yarn workspace @open-mercato/core build
30
+ ```
12
31
 
13
32
  ## Key Files
14
33
 
@@ -2,7 +2,7 @@
2
2
 
3
3
  Customer-facing identity and portal authentication with a two-tier RBAC model. This module manages customer user accounts, sessions, roles, invitations, and the authentication flow for the customer portal. It is separate from the internal `auth` module, which handles staff authentication.
4
4
 
5
- ## MUST Rules
5
+ ## Always
6
6
 
7
7
  1. **MUST hash passwords with `bcryptjs` (cost >= 10)** — never store plaintext passwords
8
8
  2. **MUST return minimal error messages on auth endpoints** — never reveal whether an email exists (use generic "Invalid email or password")
@@ -10,11 +10,31 @@ Customer-facing identity and portal authentication with a two-tier RBAC model. T
10
10
  4. **MUST validate all inputs with zod** — schemas live in `data/validators.ts`
11
11
  5. **MUST export `openApi`** from every API route file
12
12
  6. **MUST scope all queries by `tenantId`** and filter `deletedAt: null` for soft-deleted records
13
- 7. **MUST NOT expose cross-tenant data** — session validation checks tenant match
14
- 8. **MUST use `hashForLookup` for email-based lookups** — emails are stored with a deterministic hash for indexed queries
15
- 9. **MUST use `hashToken` for storing session/verification/reset tokens** raw tokens are never persisted
16
- 10. **MUST emit events via `emitCustomerAccountsEvent`** for all state changes (login, signup, lock, password reset)
17
- 11. **MUST NOT import staff auth services** — customer auth is a fully separate identity system
13
+ 7. **MUST use `hashForLookup` for email-based lookups** — emails are stored with a deterministic hash for indexed queries
14
+ 8. **MUST use `hashToken` for storing session/verification/reset tokens** — raw tokens are never persisted
15
+ 9. **MUST emit events via `emitCustomerAccountsEvent`** for all state changes (login, signup, lock, password reset)
16
+
17
+ ## Ask First
18
+
19
+ - Ask before changing cookie names, token TTLs, JWT claim shape, rate limits, lockout thresholds, or portal RBAC semantics.
20
+ - Ask before moving customer portal navigation into a different staff IA group.
21
+ - Ask before changing CRM auto-linking behavior.
22
+
23
+ ## Never
24
+
25
+ - Never store plaintext passwords or raw tokens.
26
+ - Never reveal whether an email exists.
27
+ - Never expose cross-tenant data — session validation checks tenant match.
28
+ - Never import staff auth services; customer auth is a fully separate identity system.
29
+ - Never use exact `includes(...)` checks for portal wildcard ACL matching.
30
+
31
+ ## Validation Commands
32
+
33
+ ```bash
34
+ yarn db:generate
35
+ yarn generate
36
+ yarn workspace @open-mercato/core build
37
+ ```
18
38
 
19
39
  ## Data Model
20
40
 
@@ -2,7 +2,7 @@
2
2
 
3
3
  **This is the reference CRUD module.** When building new modules, copy patterns from here first.
4
4
 
5
- ## MUST Rules
5
+ ## Always
6
6
 
7
7
  1. **MUST use this module as the template** for new CRUD modules — copy file structure and patterns
8
8
  2. **MUST include all standard module files** — use the list below as a checklist
@@ -11,6 +11,25 @@
11
11
  5. **MUST capture custom field snapshots** in command `before`/`after` payloads for undo support
12
12
  6. **MUST use `useGuardedMutation` for non-`CrudForm` backend writes** (`POST`/`PUT`/`PATCH`/`DELETE`) and pass `retryLastMutation` in injection context
13
13
 
14
+ ## Ask First
15
+
16
+ - Ask before changing this module's reference patterns, standard module-file checklist, or AI mutation policies.
17
+ - Ask before changing customer data model relationships that downstream modules may copy.
18
+
19
+ ## Never
20
+
21
+ - Never bypass custom field normalization in CRUD create/update/read responses.
22
+ - Never omit undo snapshots for custom field mutations.
23
+ - Never write backend `POST`/`PUT`/`PATCH`/`DELETE` actions outside `CrudForm` without `useGuardedMutation`.
24
+
25
+ ## Validation Commands
26
+
27
+ ```bash
28
+ yarn db:generate
29
+ yarn generate
30
+ yarn workspace @open-mercato/core build
31
+ ```
32
+
14
33
  ## Key Reference Files — Copy From Here
15
34
 
16
35
  | When you need | Copy from |
@@ -6,6 +6,36 @@ The `data_sync` module provides a streaming data synchronization hub for import/
6
6
 
7
7
  ---
8
8
 
9
+ ## Always
10
+
11
+ - **Always scope by organizationId + tenantId** — every entity query
12
+ - **Use the queue system** — never run syncs inline in API handlers
13
+ - **New sync providers MUST support provider-owned env preconfiguration** when fresh installs need credentials or default mappings/locales/channels from deployment env
14
+ - **Persist cursor after each batch** — enables resume on failure
15
+ - **Log item-level errors** — don't stop the sync for individual item failures
16
+ - **Check for overlap** before starting a new run (same integration + entityType + direction)
17
+ - **API routes must export `openApi`** for documentation generation
18
+
19
+ ## Ask First
20
+
21
+ - Ask before changing adapter contracts, run lifecycle states, cursor semantics, queue names, or overlap detection.
22
+ - Ask before adding provider-specific logic to this generic module.
23
+ - Ask before changing progress delivery or cancellation behavior.
24
+
25
+ ## Never
26
+
27
+ - Never import from provider adapter modules — `data_sync` is generic.
28
+ - Never run syncs inline in API handlers.
29
+ - Never add frontend polling loops for sync progress beyond initial hydration or reconnect recovery.
30
+ - Never special-case provider credentials, mappings, or state in `data_sync`.
31
+
32
+ ## Validation Commands
33
+
34
+ ```bash
35
+ yarn generate
36
+ yarn workspace @open-mercato/core build
37
+ ```
38
+
9
39
  ## Module Structure
10
40
 
11
41
  ```
@@ -152,14 +182,3 @@ Data sync providers can leverage the **Unified Module Extension System (UMES)**
152
182
  - Use helpers from `@open-mercato/core/modules/core/__integration__/helpers/*`
153
183
  - Tests must create prerequisites via API and clean up in `finally`
154
184
  - Avoid hard dependency on late-phase modules; keep tests scoped to implemented contracts
155
-
156
- ## MUST Rules
157
-
158
- - **Always scope by organizationId + tenantId** — every entity query
159
- - **Never import from provider adapter modules** — data_sync is generic
160
- - **Use the queue system** — never run syncs inline in API handlers
161
- - **New sync providers MUST support provider-owned env preconfiguration** when fresh installs need credentials or default mappings/locales/channels from deployment env
162
- - **Persist cursor after each batch** — enables resume on failure
163
- - **Log item-level errors** — don't stop the sync for individual item failures
164
- - **Check for overlap** before starting a new run (same integration + entityType + direction)
165
- - **API routes must export `openApi`** for documentation generation
@@ -6,6 +6,37 @@ The `integrations` module is the foundation layer for all external connectors (p
6
6
 
7
7
  ---
8
8
 
9
+ ## Always
10
+
11
+ - **Always scope by organizationId + tenantId** — every entity query and service call
12
+ - **Use `findWithDecryption`/`findOneWithDecryption`** for credential reads
13
+ - **New providers MUST support provider-owned env preconfiguration** when credentials/settings are deployment-managed; implement it in the provider package, not in core
14
+ - **Health check services** must be registered in DI by the provider module, not by integrations
15
+ - **API routes must export `openApi`** for documentation generation
16
+ - **All user-facing strings** via i18n keys in `i18n/en.json`
17
+ - **Keep ACL default export shape** consistent: `export const features = [...]; export default features`
18
+ - **Registry/type contracts** live in `@open-mercato/shared/modules/integrations/types`
19
+
20
+ ## Ask First
21
+
22
+ - Ask before changing credential resolution order, registry type contracts, canonical API routes, or compatibility surfaces.
23
+ - Ask before moving provider-specific logic into this module.
24
+ - Ask before changing health-check timeouts, log retention semantics, or credential redaction behavior.
25
+
26
+ ## Never
27
+
28
+ - Never import from provider modules — integrations module is generic; providers import from integrations, not vice versa.
29
+ - Never log credential values — log service strips secret fields from payload.
30
+ - Never special-case provider env presets, credentials, mappings, or enabled state in core.
31
+ - Never remove legacy `integrations.detail:tabs` fallback without a compatibility plan.
32
+
33
+ ## Validation Commands
34
+
35
+ ```bash
36
+ yarn generate
37
+ yarn workspace @open-mercato/core build
38
+ ```
39
+
9
40
  ## Module Structure
10
41
 
11
42
  ```
@@ -192,16 +223,3 @@ The integrations module itself uses UMES to inject external ID displays on any e
192
223
  - Module-local integration tests go under `__integration__/`
193
224
  - Use helpers from `@open-mercato/core/modules/core/__integration__/helpers/*`
194
225
  - Tests must create prerequisites via API and clean up in `finally`
195
-
196
- ## MUST Rules
197
-
198
- - **Never import from provider modules** — integrations module is generic; providers import from integrations, not vice versa
199
- - **Always scope by organizationId + tenantId** — every entity query and service call
200
- - **Use `findWithDecryption`/`findOneWithDecryption`** for credential reads
201
- - **New providers MUST support provider-owned env preconfiguration** when credentials/settings are deployment-managed; implement it in the provider package, not in core
202
- - **Never log credential values** — log service strips secret fields from payload
203
- - **Health check services** must be registered in DI by the provider module, not by integrations
204
- - **API routes must export `openApi`** for documentation generation
205
- - **All user-facing strings** via i18n keys in `i18n/en.json`
206
- - **Keep ACL default export shape** consistent: `export const features = [...]; export default features`
207
- - **Registry/type contracts** live in `@open-mercato/shared/modules/integrations/types`
@@ -2,7 +2,7 @@
2
2
 
3
3
  Use the progress module for every user-visible bulk operation and every long-running operation. Keep `ProgressTopBar` the single shared progress surface.
4
4
 
5
- ## MUST Rules
5
+ ## Always
6
6
 
7
7
  1. **MUST create `ProgressJob` for durable work** — imports, exports, bulk mutations, reindexing, external sync, and queued work must persist progress server-side.
8
8
  2. **MUST return `progressJobId` to the UI** — DataTable bulk actions and start-operation APIs must expose the job id so the top bar can track it.
@@ -11,7 +11,25 @@ Use the progress module for every user-visible bulk operation and every long-run
11
11
  5. **MUST use queue workers for durable work** — use `@open-mercato/queue`; do not implement custom queues, timers, or page polling loops.
12
12
  6. **MUST run mutations through commands** — workers must use `commandBus.execute(...)` for domain writes so audit, undo, cache, events, and index invalidation stay intact.
13
13
  7. **MUST use client-local progress only for browser-bound loops** — local `client:*` progress events are best-effort and must not represent work that should survive navigation.
14
- 8. **MUST NOT build per-module progress bars for global operations** — use `ProgressTopBar` and shared progress hooks.
14
+
15
+ ## Ask First
16
+
17
+ - Ask before adding a new progress mode, changing job terminal states, or changing cancellation semantics.
18
+ - Ask before creating a module-specific progress UI for work that could use the shared top bar.
19
+
20
+ ## Never
21
+
22
+ - Never leave running jobs without heartbeat/progress updates.
23
+ - Never implement custom queues, timers, or page polling loops for durable work.
24
+ - Never represent durable server work with client-local `client:*` progress events.
25
+ - Never build per-module progress bars for global operations — use `ProgressTopBar` and shared progress hooks.
26
+
27
+ ## Validation Commands
28
+
29
+ ```bash
30
+ yarn generate
31
+ yarn workspace @open-mercato/core build
32
+ ```
15
33
 
16
34
  ## Choosing Progress Mode
17
35
 
@@ -2,13 +2,32 @@
2
2
 
3
3
  Use the sales module for orders, quotes, invoices, shipments, and payments. This module has the most complex business logic in the system.
4
4
 
5
- ## MUST Rules
5
+ ## Always
6
6
 
7
- 1. **MUST NOT reimplement document math inline** — use `salesCalculationService` from DI
7
+ 1. **MUST use `salesCalculationService` from DI** for document math.
8
8
  2. **MUST follow document flow**: Quote → Order → Invoice — no skipping steps
9
- 3. **MUST NOT modify configuration entities directly** (statuses, methods, channels) — use the admin UI or setup hooks
10
- 4. **MUST use `selectBestPrice`** from catalog pricing helpersnever inline price calculations
11
- 5. **MUST scope all documents to a channel** — channel selection affects pricing, numbering, and visibility
9
+ 3. **MUST use `selectBestPrice`** from catalog pricing helpers.
10
+ 4. **MUST scope all documents to a channel**channel selection affects pricing, numbering, and visibility
11
+
12
+ ## Ask First
13
+
14
+ - Ask before changing the Quote → Order → Invoice flow, workflow states, numbering rules, or channel scoping behavior.
15
+ - Ask before changing configuration entity semantics for statuses, methods, channels, price kinds, adjustment kinds, or document numbers.
16
+
17
+ ## Never
18
+
19
+ - Never reimplement document math inline.
20
+ - Never skip configured document workflow states.
21
+ - Never modify configuration entities directly; use the admin UI or setup hooks.
22
+ - Never inline price calculations.
23
+
24
+ ## Validation Commands
25
+
26
+ ```bash
27
+ yarn db:generate
28
+ yarn generate
29
+ yarn workspace @open-mercato/core build
30
+ ```
12
31
 
13
32
  ## Document Flow
14
33
 
@@ -2,19 +2,41 @@
2
2
 
3
3
  Use the workflows module for business process automation: defining step-based workflows, executing instances, handling user tasks, processing async activities, and triggering workflows from domain events.
4
4
 
5
- ## MUST Rules
5
+ ## Always
6
6
 
7
7
  1. **MUST resolve services via DI** — use `container.resolve('workflowExecutor')`, never import and call lib functions directly
8
- 2. **MUST NOT skip the execution loop** — always use `workflowExecutor.startWorkflow()` to create and run instances; never insert `WorkflowInstance` rows directly
8
+ 2. **MUST use `workflowExecutor.startWorkflow()`** to create and run instances.
9
9
  3. **MUST follow the step state machine** — steps transition `PENDING → ACTIVE → COMPLETED|FAILED|SKIPPED|CANCELLED`; never set status out of order
10
10
  4. **MUST follow the instance state machine** — instances transition `RUNNING → COMPLETED|FAILED|CANCELLED`; intermediate states include `PAUSED`, `WAITING_FOR_ACTIVITIES`, `COMPENSATING`
11
11
  5. **MUST keep activity handlers idempotent** — check state before mutating; activities may be retried on failure
12
12
  6. **MUST use event sourcing** — log all workflow events via `eventLogger.logWorkflowEvent()`; never mutate instance state without a corresponding event
13
13
  7. **MUST use variable interpolation** for dynamic activity config — use `{{context.*}}`, `{{workflow.*}}`, `{{env.*}}`, `{{now}}`; never hardcode values
14
- 8. **MUST NOT couple other modules to workflow internals** — use event triggers and signals for cross-module integration; widget injection for UI
14
+ 8. **MUST use event triggers, signals, and widget injection** for cross-module integration.
15
15
  9. **MUST declare new events in `events.ts`** with `as const` — undeclared events trigger TypeScript errors and runtime warnings
16
16
  10. **MUST scope all queries by `organization_id`** — workflow data is tenant-scoped; never expose cross-tenant instances or tasks
17
17
 
18
+ ## Ask First
19
+
20
+ - Ask before changing workflow, step, or activity state machines.
21
+ - Ask before changing SSRF guard behavior, private URL allowances, compensation semantics, or trigger storm controls.
22
+ - Ask before coupling another module directly to workflow internals.
23
+
24
+ ## Never
25
+
26
+ - Never import and call workflow lib functions directly instead of resolving DI services.
27
+ - Never skip the execution loop or insert `WorkflowInstance` rows directly.
28
+ - Never mutate instance state without a corresponding workflow event.
29
+ - Never expose cross-tenant workflow instances or tasks.
30
+ - Never leave `OM_WORKFLOWS_ALLOW_PRIVATE_URLS` enabled in production.
31
+
32
+ ## Validation Commands
33
+
34
+ ```bash
35
+ yarn db:generate
36
+ yarn generate
37
+ yarn workspace @open-mercato/core build
38
+ ```
39
+
18
40
  ## Execution Architecture
19
41
 
20
42
  ```