@open-mercato/core 0.4.2-canary-667ab2b715 → 0.4.2-canary-f728a6d66a

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.
Files changed (155) hide show
  1. package/dist/generated/entities/workflow_event_trigger/index.js +33 -0
  2. package/dist/generated/entities/workflow_event_trigger/index.js.map +7 -0
  3. package/dist/generated/entities.ids.generated.js +59 -58
  4. package/dist/generated/entities.ids.generated.js.map +2 -2
  5. package/dist/generated/entity-fields-registry.js +2 -0
  6. package/dist/generated/entity-fields-registry.js.map +2 -2
  7. package/dist/modules/auth/events.js +30 -0
  8. package/dist/modules/auth/events.js.map +7 -0
  9. package/dist/modules/business_rules/api/execute/[ruleId]/route.js +150 -0
  10. package/dist/modules/business_rules/api/execute/[ruleId]/route.js.map +7 -0
  11. package/dist/modules/business_rules/data/validators.js +34 -0
  12. package/dist/modules/business_rules/data/validators.js.map +2 -2
  13. package/dist/modules/business_rules/index.js +21 -1
  14. package/dist/modules/business_rules/index.js.map +2 -2
  15. package/dist/modules/business_rules/lib/rule-engine.js +182 -1
  16. package/dist/modules/business_rules/lib/rule-engine.js.map +2 -2
  17. package/dist/modules/catalog/events.js +34 -0
  18. package/dist/modules/catalog/events.js.map +7 -0
  19. package/dist/modules/customers/events.js +49 -0
  20. package/dist/modules/customers/events.js.map +7 -0
  21. package/dist/modules/directory/events.js +23 -0
  22. package/dist/modules/directory/events.js.map +7 -0
  23. package/dist/modules/sales/acl.js +1 -0
  24. package/dist/modules/sales/acl.js.map +2 -2
  25. package/dist/modules/sales/backend/sales/documents/[id]/page.js +12 -0
  26. package/dist/modules/sales/backend/sales/documents/[id]/page.js.map +2 -2
  27. package/dist/modules/sales/commands/documents.js +62 -0
  28. package/dist/modules/sales/commands/documents.js.map +2 -2
  29. package/dist/modules/sales/events.js +63 -0
  30. package/dist/modules/sales/events.js.map +7 -0
  31. package/dist/modules/sales/lib/dictionaries.js +3 -0
  32. package/dist/modules/sales/lib/dictionaries.js.map +2 -2
  33. package/dist/modules/sales/lib/frontend/documentDataEvents.js +25 -0
  34. package/dist/modules/sales/lib/frontend/documentDataEvents.js.map +7 -0
  35. package/dist/modules/workflows/acl.js +2 -0
  36. package/dist/modules/workflows/acl.js.map +2 -2
  37. package/dist/modules/workflows/api/instances/route.js +18 -6
  38. package/dist/modules/workflows/api/instances/route.js.map +2 -2
  39. package/dist/modules/workflows/api/tasks/route.js +6 -1
  40. package/dist/modules/workflows/api/tasks/route.js.map +2 -2
  41. package/dist/modules/workflows/backend/definitions/[id]/page.js +9 -1
  42. package/dist/modules/workflows/backend/definitions/[id]/page.js.map +2 -2
  43. package/dist/modules/workflows/backend/definitions/[id]/page.meta.js +1 -1
  44. package/dist/modules/workflows/backend/definitions/[id]/page.meta.js.map +2 -2
  45. package/dist/modules/workflows/backend/definitions/create/page.js +24 -15
  46. package/dist/modules/workflows/backend/definitions/create/page.js.map +2 -2
  47. package/dist/modules/workflows/backend/definitions/create/page.meta.js +1 -1
  48. package/dist/modules/workflows/backend/definitions/create/page.meta.js.map +2 -2
  49. package/dist/modules/workflows/backend/definitions/visual-editor/page.js +150 -132
  50. package/dist/modules/workflows/backend/definitions/visual-editor/page.js.map +2 -2
  51. package/dist/modules/workflows/backend/definitions/visual-editor/page.meta.js +1 -1
  52. package/dist/modules/workflows/backend/definitions/visual-editor/page.meta.js.map +2 -2
  53. package/dist/modules/workflows/backend/events/[id]/page.js +1 -1
  54. package/dist/modules/workflows/backend/events/[id]/page.js.map +2 -2
  55. package/dist/modules/workflows/backend/events/[id]/page.meta.js +2 -2
  56. package/dist/modules/workflows/backend/events/[id]/page.meta.js.map +2 -2
  57. package/dist/modules/workflows/backend/instances/[id]/page.meta.js +2 -2
  58. package/dist/modules/workflows/backend/instances/[id]/page.meta.js.map +2 -2
  59. package/dist/modules/workflows/backend/tasks/[id]/page.js +1 -1
  60. package/dist/modules/workflows/backend/tasks/[id]/page.js.map +2 -2
  61. package/dist/modules/workflows/backend/tasks/[id]/page.meta.js +2 -2
  62. package/dist/modules/workflows/backend/tasks/[id]/page.meta.js.map +2 -2
  63. package/dist/modules/workflows/backend/tasks/page.js +5 -6
  64. package/dist/modules/workflows/backend/tasks/page.js.map +2 -2
  65. package/dist/modules/workflows/cli.js +81 -3
  66. package/dist/modules/workflows/cli.js.map +3 -3
  67. package/dist/modules/workflows/components/DefinitionTriggersEditor.js +481 -0
  68. package/dist/modules/workflows/components/DefinitionTriggersEditor.js.map +7 -0
  69. package/dist/modules/workflows/components/EventTriggersEditor.js +553 -0
  70. package/dist/modules/workflows/components/EventTriggersEditor.js.map +7 -0
  71. package/dist/modules/workflows/data/entities.js +64 -1
  72. package/dist/modules/workflows/data/entities.js.map +2 -2
  73. package/dist/modules/workflows/data/validators.js +115 -0
  74. package/dist/modules/workflows/data/validators.js.map +2 -2
  75. package/dist/modules/workflows/events.js +38 -0
  76. package/dist/modules/workflows/events.js.map +7 -0
  77. package/dist/modules/workflows/examples/checkout-demo-definition.json +1 -5
  78. package/dist/modules/workflows/examples/order-approval-definition.json +257 -0
  79. package/dist/modules/workflows/examples/order-approval-guard-rules.json +32 -0
  80. package/dist/modules/workflows/lib/activity-executor.js +75 -13
  81. package/dist/modules/workflows/lib/activity-executor.js.map +2 -2
  82. package/dist/modules/workflows/lib/event-trigger-service.js +308 -0
  83. package/dist/modules/workflows/lib/event-trigger-service.js.map +7 -0
  84. package/dist/modules/workflows/lib/graph-utils.js +71 -2
  85. package/dist/modules/workflows/lib/graph-utils.js.map +2 -2
  86. package/dist/modules/workflows/lib/seeds.js +22 -5
  87. package/dist/modules/workflows/lib/seeds.js.map +2 -2
  88. package/dist/modules/workflows/lib/start-validator.js +33 -23
  89. package/dist/modules/workflows/lib/start-validator.js.map +2 -2
  90. package/dist/modules/workflows/lib/transition-handler.js +157 -45
  91. package/dist/modules/workflows/lib/transition-handler.js.map +3 -3
  92. package/dist/modules/workflows/migrations/Migration20260123143500.js +36 -0
  93. package/dist/modules/workflows/migrations/Migration20260123143500.js.map +7 -0
  94. package/dist/modules/workflows/subscribers/event-trigger.js +78 -0
  95. package/dist/modules/workflows/subscribers/event-trigger.js.map +7 -0
  96. package/dist/modules/workflows/widgets/injection/order-approval/widget.client.js +323 -0
  97. package/dist/modules/workflows/widgets/injection/order-approval/widget.client.js.map +7 -0
  98. package/dist/modules/workflows/widgets/injection/order-approval/widget.js +17 -0
  99. package/dist/modules/workflows/widgets/injection/order-approval/widget.js.map +7 -0
  100. package/dist/modules/workflows/widgets/injection-table.js +19 -0
  101. package/dist/modules/workflows/widgets/injection-table.js.map +7 -0
  102. package/generated/entities/workflow_event_trigger/index.ts +15 -0
  103. package/generated/entities.ids.generated.ts +59 -58
  104. package/generated/entity-fields-registry.ts +2 -0
  105. package/package.json +3 -5
  106. package/src/modules/auth/events.ts +39 -0
  107. package/src/modules/business_rules/api/execute/[ruleId]/route.ts +168 -0
  108. package/src/modules/business_rules/data/validators.ts +40 -0
  109. package/src/modules/business_rules/index.ts +25 -0
  110. package/src/modules/business_rules/lib/rule-engine.ts +281 -1
  111. package/src/modules/catalog/events.ts +45 -0
  112. package/src/modules/customers/events.ts +63 -0
  113. package/src/modules/directory/events.ts +31 -0
  114. package/src/modules/sales/acl.ts +1 -0
  115. package/src/modules/sales/backend/sales/documents/[id]/page.tsx +16 -0
  116. package/src/modules/sales/commands/documents.ts +74 -1
  117. package/src/modules/sales/events.ts +82 -0
  118. package/src/modules/sales/lib/dictionaries.ts +3 -0
  119. package/src/modules/sales/lib/frontend/documentDataEvents.ts +28 -0
  120. package/src/modules/workflows/acl.ts +2 -0
  121. package/src/modules/workflows/api/instances/route.ts +21 -7
  122. package/src/modules/workflows/api/tasks/route.ts +7 -1
  123. package/src/modules/workflows/backend/definitions/[id]/page.meta.ts +1 -1
  124. package/src/modules/workflows/backend/definitions/[id]/page.tsx +9 -0
  125. package/src/modules/workflows/backend/definitions/create/page.meta.ts +1 -1
  126. package/src/modules/workflows/backend/definitions/create/page.tsx +9 -0
  127. package/src/modules/workflows/backend/definitions/visual-editor/page.meta.ts +1 -1
  128. package/src/modules/workflows/backend/definitions/visual-editor/page.tsx +21 -3
  129. package/src/modules/workflows/backend/events/[id]/page.meta.ts +2 -2
  130. package/src/modules/workflows/backend/events/[id]/page.tsx +1 -1
  131. package/src/modules/workflows/backend/instances/[id]/page.meta.ts +2 -2
  132. package/src/modules/workflows/backend/tasks/[id]/page.meta.ts +2 -2
  133. package/src/modules/workflows/backend/tasks/[id]/page.tsx +1 -1
  134. package/src/modules/workflows/backend/tasks/page.tsx +5 -6
  135. package/src/modules/workflows/cli.ts +105 -0
  136. package/src/modules/workflows/components/DefinitionTriggersEditor.tsx +581 -0
  137. package/src/modules/workflows/components/EventTriggersEditor.tsx +664 -0
  138. package/src/modules/workflows/data/entities.ts +123 -0
  139. package/src/modules/workflows/data/validators.ts +138 -0
  140. package/src/modules/workflows/events.ts +49 -0
  141. package/src/modules/workflows/examples/checkout-demo-definition.json +1 -5
  142. package/src/modules/workflows/examples/order-approval-definition.json +257 -0
  143. package/src/modules/workflows/examples/order-approval-guard-rules.json +32 -0
  144. package/src/modules/workflows/i18n/en.json +71 -0
  145. package/src/modules/workflows/lib/activity-executor.ts +129 -16
  146. package/src/modules/workflows/lib/event-trigger-service.ts +557 -0
  147. package/src/modules/workflows/lib/graph-utils.ts +117 -2
  148. package/src/modules/workflows/lib/seeds.ts +34 -8
  149. package/src/modules/workflows/lib/start-validator.ts +38 -28
  150. package/src/modules/workflows/lib/transition-handler.ts +208 -55
  151. package/src/modules/workflows/migrations/Migration20260123143500.ts +38 -0
  152. package/src/modules/workflows/subscribers/event-trigger.ts +109 -0
  153. package/src/modules/workflows/widgets/injection/order-approval/widget.client.tsx +446 -0
  154. package/src/modules/workflows/widgets/injection/order-approval/widget.ts +16 -0
  155. package/src/modules/workflows/widgets/injection-table.ts +21 -0
@@ -46,6 +46,62 @@ export type UserTaskStatus =
46
46
  | 'CANCELLED'
47
47
  | 'ESCALATED'
48
48
 
49
+ // ============================================================================
50
+ // Event Trigger Types
51
+ // ============================================================================
52
+
53
+ export type TriggerFilterOperator =
54
+ | 'eq'
55
+ | 'neq'
56
+ | 'gt'
57
+ | 'gte'
58
+ | 'lt'
59
+ | 'lte'
60
+ | 'contains'
61
+ | 'startsWith'
62
+ | 'endsWith'
63
+ | 'in'
64
+ | 'notIn'
65
+ | 'exists'
66
+ | 'notExists'
67
+ | 'regex'
68
+
69
+ export interface TriggerFilterCondition {
70
+ field: string // JSON path (e.g., "status", "metadata.type")
71
+ operator: TriggerFilterOperator
72
+ value: unknown
73
+ }
74
+
75
+ export interface TriggerContextMapping {
76
+ targetKey: string // Key in workflow initial context
77
+ sourceExpression: string // Path from event payload (supports dot notation)
78
+ defaultValue?: unknown
79
+ }
80
+
81
+ export interface WorkflowEventTriggerConfig {
82
+ filterConditions?: TriggerFilterCondition[]
83
+ contextMapping?: TriggerContextMapping[]
84
+ debounceMs?: number // Debounce rapid events
85
+ maxConcurrentInstances?: number // Limit concurrent instances
86
+ }
87
+
88
+ /**
89
+ * WorkflowDefinitionTrigger - Embedded trigger configuration
90
+ *
91
+ * Triggers are now embedded directly in the workflow definition,
92
+ * allowing users to configure event-based workflow starts during
93
+ * workflow creation in the visual editor.
94
+ */
95
+ export interface WorkflowDefinitionTrigger {
96
+ triggerId: string
97
+ name: string
98
+ description?: string | null
99
+ eventPattern: string // e.g., "sales.orders.created", "customers.*"
100
+ config?: WorkflowEventTriggerConfig | null
101
+ enabled: boolean
102
+ priority: number
103
+ }
104
+
49
105
  // ============================================================================
50
106
  // JSONB Structure Interfaces
51
107
  // ============================================================================
@@ -53,6 +109,7 @@ export type UserTaskStatus =
53
109
  export interface WorkflowDefinitionData {
54
110
  steps: any[] // WorkflowStep[] - will define schema in validators.ts
55
111
  transitions: any[] // WorkflowTransition[] - will define schema in validators.ts
112
+ triggers?: WorkflowDefinitionTrigger[] // Event triggers for automatic workflow start
56
113
  activities?: any[] // ActivityDefinition[] - will define schema in validators.ts
57
114
  queries?: any[]
58
115
  signals?: any[]
@@ -429,6 +486,71 @@ export class WorkflowEvent {
429
486
  organizationId!: string
430
487
  }
431
488
 
489
+ // ============================================================================
490
+ // Entity: WorkflowEventTrigger
491
+ // ============================================================================
492
+
493
+ /**
494
+ * WorkflowEventTrigger entity
495
+ *
496
+ * Maps event patterns to workflow definitions for automatic triggering.
497
+ * When a matching event is emitted, the corresponding workflow is started
498
+ * with context mapped from the event payload.
499
+ */
500
+ @Entity({ tableName: 'workflow_event_triggers' })
501
+ @Index({ name: 'workflow_event_triggers_event_pattern_idx', properties: ['eventPattern', 'enabled'] })
502
+ @Index({ name: 'workflow_event_triggers_definition_idx', properties: ['workflowDefinitionId'] })
503
+ @Index({ name: 'workflow_event_triggers_tenant_org_idx', properties: ['tenantId', 'organizationId'] })
504
+ @Index({ name: 'workflow_event_triggers_enabled_priority_idx', properties: ['enabled', 'priority'] })
505
+ export class WorkflowEventTrigger {
506
+ [OptionalProps]?: 'enabled' | 'priority' | 'createdAt' | 'updatedAt' | 'deletedAt'
507
+
508
+ @PrimaryKey({ type: 'uuid', defaultRaw: 'gen_random_uuid()' })
509
+ id!: string
510
+
511
+ @Property({ name: 'name', type: 'varchar', length: 255 })
512
+ name!: string
513
+
514
+ @Property({ name: 'description', type: 'text', nullable: true })
515
+ description?: string | null
516
+
517
+ @Property({ name: 'workflow_definition_id', type: 'uuid' })
518
+ workflowDefinitionId!: string
519
+
520
+ @Property({ name: 'event_pattern', type: 'varchar', length: 255 })
521
+ eventPattern!: string
522
+
523
+ @Property({ name: 'config', type: 'jsonb', nullable: true })
524
+ config?: WorkflowEventTriggerConfig | null
525
+
526
+ @Property({ name: 'enabled', type: 'boolean', default: true })
527
+ enabled: boolean = true
528
+
529
+ @Property({ name: 'priority', type: 'integer', default: 0 })
530
+ priority: number = 0
531
+
532
+ @Property({ name: 'tenant_id', type: 'uuid' })
533
+ tenantId!: string
534
+
535
+ @Property({ name: 'organization_id', type: 'uuid' })
536
+ organizationId!: string
537
+
538
+ @Property({ name: 'created_by', type: 'varchar', length: 255, nullable: true })
539
+ createdBy?: string | null
540
+
541
+ @Property({ name: 'updated_by', type: 'varchar', length: 255, nullable: true })
542
+ updatedBy?: string | null
543
+
544
+ @Property({ name: 'created_at', type: Date, onCreate: () => new Date() })
545
+ createdAt: Date = new Date()
546
+
547
+ @Property({ name: 'updated_at', type: Date, onUpdate: () => new Date() })
548
+ updatedAt: Date = new Date()
549
+
550
+ @Property({ name: 'deleted_at', type: Date, nullable: true })
551
+ deletedAt?: Date | null
552
+ }
553
+
432
554
  // Export all entities as default for MikroORM discovery
433
555
  export default [
434
556
  WorkflowDefinition,
@@ -436,4 +558,5 @@ export default [
436
558
  StepInstance,
437
559
  UserTask,
438
560
  WorkflowEvent,
561
+ WorkflowEventTrigger,
439
562
  ]
@@ -215,10 +215,43 @@ export const workflowTransitionSchema = z.object({
215
215
  priority: z.number().int().min(0).max(9999).default(0),
216
216
  })
217
217
 
218
+ // Workflow definition trigger schema (embedded in definition)
219
+ // Note: Uses forward reference pattern since eventPatternSchema and eventTriggerConfigSchema are defined later
220
+ export const workflowDefinitionTriggerSchema = z.object({
221
+ triggerId: z.string().min(1).max(100).regex(/^[a-z0-9_-]+$/, 'Trigger ID must contain only lowercase letters, numbers, hyphens, and underscores'),
222
+ name: z.string().min(1).max(255),
223
+ description: z.string().max(2000).optional().nullable(),
224
+ eventPattern: z.string()
225
+ .min(1, 'Event pattern is required')
226
+ .max(255, 'Event pattern must be at most 255 characters')
227
+ .regex(
228
+ /^(\*|[a-z0-9_]+(\.[a-z0-9_*]+)*)$/i,
229
+ 'Event pattern must be "*" or a dot-separated pattern with optional wildcards (e.g., "customers.people.created", "sales.orders.*")'
230
+ ),
231
+ config: z.object({
232
+ filterConditions: z.array(z.object({
233
+ field: z.string().min(1).max(255),
234
+ operator: z.enum(['eq', 'neq', 'gt', 'gte', 'lt', 'lte', 'contains', 'startsWith', 'endsWith', 'in', 'notIn', 'exists', 'notExists', 'regex']),
235
+ value: z.any(),
236
+ })).max(20).optional(),
237
+ contextMapping: z.array(z.object({
238
+ targetKey: z.string().min(1).max(100),
239
+ sourceExpression: z.string().min(1).max(255),
240
+ defaultValue: z.any().optional(),
241
+ })).max(50).optional(),
242
+ debounceMs: z.number().int().min(0).max(3600000).optional(),
243
+ maxConcurrentInstances: z.number().int().min(1).max(1000).optional(),
244
+ }).optional().nullable(),
245
+ enabled: z.boolean().default(true),
246
+ priority: z.number().int().min(0).max(9999).default(0),
247
+ })
248
+ export type WorkflowDefinitionTrigger = z.infer<typeof workflowDefinitionTriggerSchema>
249
+
218
250
  // Workflow definition data (JSONB structure)
219
251
  export const workflowDefinitionDataSchema = z.object({
220
252
  steps: z.array(workflowStepSchema).min(2, 'Workflow must have at least START and END steps'),
221
253
  transitions: z.array(workflowTransitionSchema).min(1, 'Workflow must have at least one transition'),
254
+ triggers: z.array(workflowDefinitionTriggerSchema).optional(), // Event triggers for automatic workflow start
222
255
  queries: z.array(z.any()).optional(), // For Phase 7
223
256
  signals: z.array(z.any()).optional(), // For Phase 9
224
257
  timers: z.array(z.any()).optional(), // For Phase 9
@@ -488,3 +521,108 @@ export const startWorkflowInputSchema = z.object({
488
521
  })
489
522
 
490
523
  export type StartWorkflowApiInput = z.infer<typeof startWorkflowInputSchema>
524
+
525
+ // ============================================================================
526
+ // WorkflowEventTrigger Schemas
527
+ // ============================================================================
528
+
529
+ export const triggerFilterOperatorSchema = z.enum([
530
+ 'eq',
531
+ 'neq',
532
+ 'gt',
533
+ 'gte',
534
+ 'lt',
535
+ 'lte',
536
+ 'contains',
537
+ 'startsWith',
538
+ 'endsWith',
539
+ 'in',
540
+ 'notIn',
541
+ 'exists',
542
+ 'notExists',
543
+ 'regex',
544
+ ])
545
+ export type TriggerFilterOperator = z.infer<typeof triggerFilterOperatorSchema>
546
+
547
+ export const triggerFilterConditionSchema = z.object({
548
+ field: z.string().min(1).max(255, 'Field path must be at most 255 characters'),
549
+ operator: triggerFilterOperatorSchema,
550
+ value: z.any(),
551
+ })
552
+ export type TriggerFilterCondition = z.infer<typeof triggerFilterConditionSchema>
553
+
554
+ export const triggerContextMappingSchema = z.object({
555
+ targetKey: z.string().min(1).max(100, 'Target key must be at most 100 characters'),
556
+ sourceExpression: z.string().min(1).max(255, 'Source expression must be at most 255 characters'),
557
+ defaultValue: z.any().optional(),
558
+ })
559
+ export type TriggerContextMapping = z.infer<typeof triggerContextMappingSchema>
560
+
561
+ export const eventTriggerConfigSchema = z.object({
562
+ filterConditions: z.array(triggerFilterConditionSchema).max(20, 'Maximum 20 filter conditions allowed').optional(),
563
+ contextMapping: z.array(triggerContextMappingSchema).max(50, 'Maximum 50 context mappings allowed').optional(),
564
+ debounceMs: z.number().int().min(0).max(3600000, 'Debounce cannot exceed 1 hour').optional(),
565
+ maxConcurrentInstances: z.number().int().min(1).max(1000, 'Max concurrent instances must be between 1 and 1000').optional(),
566
+ })
567
+ export type EventTriggerConfig = z.infer<typeof eventTriggerConfigSchema>
568
+
569
+ export const eventPatternSchema = z.string()
570
+ .min(1, 'Event pattern is required')
571
+ .max(255, 'Event pattern must be at most 255 characters')
572
+ .regex(
573
+ /^(\*|[a-z0-9_]+(\.[a-z0-9_*]+)*)$/i,
574
+ 'Event pattern must be "*" or a dot-separated pattern with optional wildcards (e.g., "customers.people.created", "sales.orders.*")'
575
+ )
576
+
577
+ export const createEventTriggerSchema = z.object({
578
+ name: z.string().min(1).max(255),
579
+ description: z.string().max(2000).optional().nullable(),
580
+ workflowDefinitionId: uuid,
581
+ eventPattern: eventPatternSchema,
582
+ config: eventTriggerConfigSchema.optional().nullable(),
583
+ enabled: z.boolean().default(true),
584
+ priority: z.number().int().min(0).max(9999).default(0),
585
+ tenantId: uuid,
586
+ organizationId: uuid,
587
+ createdBy: z.string().max(255).optional().nullable(),
588
+ })
589
+ export type CreateEventTriggerInput = z.infer<typeof createEventTriggerSchema>
590
+
591
+ // API input schema (omits tenant fields - injected from auth context)
592
+ export const createEventTriggerInputSchema = z.object({
593
+ name: z.string().min(1).max(255),
594
+ description: z.string().max(2000).optional().nullable(),
595
+ workflowDefinitionId: uuid,
596
+ eventPattern: eventPatternSchema,
597
+ config: eventTriggerConfigSchema.optional().nullable(),
598
+ enabled: z.boolean().default(true).optional(),
599
+ priority: z.number().int().min(0).max(9999).default(0).optional(),
600
+ })
601
+ export type CreateEventTriggerApiInput = z.infer<typeof createEventTriggerInputSchema>
602
+
603
+ export const updateEventTriggerSchema = createEventTriggerSchema.partial().extend({
604
+ id: uuid,
605
+ })
606
+ export type UpdateEventTriggerInput = z.infer<typeof updateEventTriggerSchema>
607
+
608
+ // API update schema (omits tenant fields and allows partial updates)
609
+ export const updateEventTriggerInputSchema = z.object({
610
+ name: z.string().min(1).max(255).optional(),
611
+ description: z.string().max(2000).optional().nullable(),
612
+ workflowDefinitionId: uuid.optional(),
613
+ eventPattern: eventPatternSchema.optional(),
614
+ config: eventTriggerConfigSchema.optional().nullable(),
615
+ enabled: z.boolean().optional(),
616
+ priority: z.number().int().min(0).max(9999).optional(),
617
+ }).strict()
618
+ export type UpdateEventTriggerApiInput = z.infer<typeof updateEventTriggerInputSchema>
619
+
620
+ export const eventTriggerFilterSchema = z.object({
621
+ name: z.string().optional(),
622
+ workflowDefinitionId: uuid.optional(),
623
+ eventPattern: z.string().optional(),
624
+ enabled: z.boolean().optional(),
625
+ tenantId: uuid.optional(),
626
+ organizationId: uuid.optional(),
627
+ })
628
+ export type EventTriggerFilter = z.infer<typeof eventTriggerFilterSchema>
@@ -0,0 +1,49 @@
1
+ import { createModuleEvents } from '@open-mercato/shared/modules/events'
2
+
3
+ /**
4
+ * Workflows Module Events
5
+ *
6
+ * Declares all events that can be emitted by the workflows module.
7
+ */
8
+ const events = [
9
+ // Workflow Definitions
10
+ { id: 'workflows.definitions.created', label: 'Workflow Definition Created', entity: 'definitions', category: 'crud' },
11
+ { id: 'workflows.definitions.updated', label: 'Workflow Definition Updated', entity: 'definitions', category: 'crud' },
12
+ { id: 'workflows.definitions.deleted', label: 'Workflow Definition Deleted', entity: 'definitions', category: 'crud' },
13
+
14
+ // Workflow Instances
15
+ { id: 'workflows.instances.created', label: 'Workflow Instance Created', entity: 'instances', category: 'crud' },
16
+ { id: 'workflows.instances.updated', label: 'Workflow Instance Updated', entity: 'instances', category: 'crud' },
17
+ { id: 'workflows.instances.deleted', label: 'Workflow Instance Deleted', entity: 'instances', category: 'crud' },
18
+
19
+ // Workflow Lifecycle Events
20
+ { id: 'workflows.instance.started', label: 'Workflow Started', category: 'lifecycle' },
21
+ { id: 'workflows.instance.completed', label: 'Workflow Completed', category: 'lifecycle' },
22
+ { id: 'workflows.instance.failed', label: 'Workflow Failed', category: 'lifecycle' },
23
+ { id: 'workflows.instance.cancelled', label: 'Workflow Cancelled', category: 'lifecycle' },
24
+ { id: 'workflows.instance.paused', label: 'Workflow Paused', category: 'lifecycle' },
25
+ { id: 'workflows.instance.resumed', label: 'Workflow Resumed', category: 'lifecycle' },
26
+
27
+ // Activity Events
28
+ { id: 'workflows.activity.started', label: 'Activity Started', category: 'lifecycle' },
29
+ { id: 'workflows.activity.completed', label: 'Activity Completed', category: 'lifecycle' },
30
+ { id: 'workflows.activity.failed', label: 'Activity Failed', category: 'lifecycle' },
31
+
32
+ // Event Triggers
33
+ { id: 'workflows.triggers.created', label: 'Trigger Created', entity: 'triggers', category: 'crud' },
34
+ { id: 'workflows.triggers.updated', label: 'Trigger Updated', entity: 'triggers', category: 'crud' },
35
+ { id: 'workflows.triggers.deleted', label: 'Trigger Deleted', entity: 'triggers', category: 'crud' },
36
+ ] as const
37
+
38
+ export const eventsConfig = createModuleEvents({
39
+ moduleId: 'workflows',
40
+ events,
41
+ })
42
+
43
+ /** Type-safe event emitter for workflows module */
44
+ export const emitWorkflowsEvent = eventsConfig.emit
45
+
46
+ /** Event IDs that can be emitted by the workflows module */
47
+ export type WorkflowsEventId = typeof events[number]['id']
48
+
49
+ export default eventsConfig
@@ -137,11 +137,7 @@
137
137
  "priority": 100,
138
138
  "preConditions": [
139
139
  {
140
- "ruleId": "cart_not_empty",
141
- "required": true
142
- },
143
- {
144
- "ruleId": "inventory_available",
140
+ "ruleId": "workflow_checkout_cart_not_empty",
145
141
  "required": true
146
142
  }
147
143
  ],
@@ -0,0 +1,257 @@
1
+ {
2
+ "workflowId": "sales_order_approval_v1",
3
+ "workflowName": "Sales Order Approval Workflow",
4
+ "description": "Approval workflow for sales orders requiring authorization before processing",
5
+ "version": 1,
6
+ "enabled": true,
7
+ "metadata": {
8
+ "category": "Sales",
9
+ "tags": [
10
+ "sales",
11
+ "approval",
12
+ "order"
13
+ ],
14
+ "icon": "check-circle",
15
+ "entityType": "SalesOrder"
16
+ },
17
+ "definition": {
18
+ "steps": [
19
+ {
20
+ "stepId": "start",
21
+ "stepName": "Start",
22
+ "stepType": "START",
23
+ "description": "Initialize order approval workflow"
24
+ },
25
+ {
26
+ "stepId": "pending_approval",
27
+ "stepName": "Pending Approval",
28
+ "stepType": "USER_TASK",
29
+ "description": "Order awaiting approval decision",
30
+ "userTaskConfig": {
31
+ "formSchema": {
32
+ "type": "object",
33
+ "required": [
34
+ "decision"
35
+ ],
36
+ "properties": {
37
+ "comments": {
38
+ "type": "string",
39
+ "title": "Comments",
40
+ "description": "Optional comments for the decision"
41
+ },
42
+ "decision": {
43
+ "enum": [
44
+ "approve",
45
+ "reject"
46
+ ],
47
+ "type": "string",
48
+ "title": "Decision",
49
+ "description": "Approve or reject the order"
50
+ }
51
+ }
52
+ },
53
+ "slaDuration": "PT24H"
54
+ }
55
+ },
56
+ {
57
+ "stepId": "approved",
58
+ "stepName": "Approved",
59
+ "stepType": "AUTOMATED",
60
+ "description": "Order has been approved"
61
+ },
62
+ {
63
+ "stepId": "rejected",
64
+ "stepName": "Rejected",
65
+ "stepType": "AUTOMATED",
66
+ "description": "Order has been rejected"
67
+ },
68
+ {
69
+ "stepId": "end",
70
+ "stepName": "Complete",
71
+ "stepType": "END",
72
+ "description": "Workflow complete"
73
+ }
74
+ ],
75
+ "triggers": [
76
+ {
77
+ "name": "Order Approval Trigger",
78
+ "config": {
79
+ "entityType": "SalesOrder"
80
+ },
81
+ "enabled": true,
82
+ "priority": 0,
83
+ "triggerId": "order_approval_trigger",
84
+ "description": "Triggers when a new sales order is created",
85
+ "eventPattern": "sales.orders.created"
86
+ }
87
+ ],
88
+ "transitions": [
89
+ {
90
+ "transitionId": "start_to_pending",
91
+ "transitionName": "Submit for Approval",
92
+ "fromStepId": "start",
93
+ "toStepId": "pending_approval",
94
+ "trigger": "auto",
95
+ "priority": 100,
96
+ "continueOnActivityFailure": true,
97
+ "activities": [
98
+ {
99
+ "activityId": "set_pending_status",
100
+ "activityName": "Set Order to Pending Approval",
101
+ "activityType": "UPDATE_ENTITY",
102
+ "async": false,
103
+ "config": {
104
+ "commandId": "sales.orders.update",
105
+ "statusDictionary": "sales.order_status",
106
+ "input": {
107
+ "id": "{{context.id}}",
108
+ "statusValue": "pending_approval"
109
+ }
110
+ },
111
+ "retryPolicy": {
112
+ "maxAttempts": 3,
113
+ "initialIntervalMs": 1000,
114
+ "backoffCoefficient": 2,
115
+ "maxIntervalMs": 10000
116
+ }
117
+ },
118
+ {
119
+ "activityId": "emit_approval_requested",
120
+ "activityName": "Emit Approval Requested Event",
121
+ "activityType": "EMIT_EVENT",
122
+ "async": true,
123
+ "config": {
124
+ "eventName": "sales.order.approval.requested",
125
+ "payload": {
126
+ "orderId": "{{context.id}}",
127
+ "workflowInstanceId": "{{workflow.instanceId}}"
128
+ }
129
+ }
130
+ }
131
+ ]
132
+ },
133
+ {
134
+ "transitionId": "pending_approval_to_approved",
135
+ "transitionName": "Approve Order",
136
+ "fromStepId": "pending_approval",
137
+ "toStepId": "approved",
138
+ "trigger": "auto",
139
+ "priority": 100,
140
+ "preConditions": [
141
+ {
142
+ "ruleId": "workflow_order_approval_check_approved",
143
+ "required": true
144
+ }
145
+ ],
146
+ "continueOnActivityFailure": true,
147
+ "activities": [
148
+ {
149
+ "activityId": "set_approved_status",
150
+ "activityName": "Set Order to Approved",
151
+ "activityType": "UPDATE_ENTITY",
152
+ "async": false,
153
+ "config": {
154
+ "commandId": "sales.orders.update",
155
+ "statusDictionary": "sales.order_status",
156
+ "input": {
157
+ "id": "{{context.id}}",
158
+ "statusValue": "approved"
159
+ }
160
+ },
161
+ "retryPolicy": {
162
+ "maxAttempts": 3,
163
+ "initialIntervalMs": 1000,
164
+ "backoffCoefficient": 2,
165
+ "maxIntervalMs": 10000
166
+ }
167
+ },
168
+ {
169
+ "activityId": "emit_order_approved",
170
+ "activityName": "Emit Order Approved Event",
171
+ "activityType": "EMIT_EVENT",
172
+ "async": true,
173
+ "config": {
174
+ "eventName": "sales.order.approval.approved",
175
+ "payload": {
176
+ "orderId": "{{context.id}}",
177
+ "workflowInstanceId": "{{workflow.instanceId}}",
178
+ "approvedBy": "{{context.completedBy}}",
179
+ "comments": "{{context.comments}}"
180
+ }
181
+ }
182
+ }
183
+ ]
184
+ },
185
+ {
186
+ "transitionId": "pending_approval_to_rejected",
187
+ "transitionName": "Reject Order",
188
+ "fromStepId": "pending_approval",
189
+ "toStepId": "rejected",
190
+ "trigger": "auto",
191
+ "priority": 90,
192
+ "preConditions": [
193
+ {
194
+ "ruleId": "workflow_order_approval_check_rejected",
195
+ "required": true
196
+ }
197
+ ],
198
+ "continueOnActivityFailure": true,
199
+ "activities": [
200
+ {
201
+ "activityId": "set_rejected_status",
202
+ "activityName": "Set Order to Rejected",
203
+ "activityType": "UPDATE_ENTITY",
204
+ "async": false,
205
+ "config": {
206
+ "commandId": "sales.orders.update",
207
+ "statusDictionary": "sales.order_status",
208
+ "input": {
209
+ "id": "{{context.id}}",
210
+ "statusValue": "rejected"
211
+ }
212
+ },
213
+ "retryPolicy": {
214
+ "maxAttempts": 3,
215
+ "initialIntervalMs": 1000,
216
+ "backoffCoefficient": 2,
217
+ "maxIntervalMs": 10000
218
+ }
219
+ },
220
+ {
221
+ "activityId": "emit_order_rejected",
222
+ "activityName": "Emit Order Rejected Event",
223
+ "activityType": "EMIT_EVENT",
224
+ "async": true,
225
+ "config": {
226
+ "eventName": "sales.order.approval.rejected",
227
+ "payload": {
228
+ "orderId": "{{context.id}}",
229
+ "workflowInstanceId": "{{workflow.instanceId}}",
230
+ "rejectedBy": "{{context.completedBy}}",
231
+ "comments": "{{context.comments}}"
232
+ }
233
+ }
234
+ }
235
+ ]
236
+ },
237
+ {
238
+ "transitionId": "approved_to_end",
239
+ "transitionName": "Complete After Approval",
240
+ "fromStepId": "approved",
241
+ "toStepId": "end",
242
+ "trigger": "auto",
243
+ "priority": 100,
244
+ "continueOnActivityFailure": true
245
+ },
246
+ {
247
+ "transitionId": "rejected_to_end",
248
+ "transitionName": "Complete After Rejection",
249
+ "fromStepId": "rejected",
250
+ "toStepId": "end",
251
+ "trigger": "auto",
252
+ "priority": 100,
253
+ "continueOnActivityFailure": true
254
+ }
255
+ ]
256
+ }
257
+ }
@@ -0,0 +1,32 @@
1
+ [
2
+ {
3
+ "ruleId": "workflow_order_approval_check_approved",
4
+ "ruleName": "Check Decision is Approve",
5
+ "description": "Validates that the approval task decision is 'approve'",
6
+ "ruleType": "GUARD",
7
+ "entityType": "workflow:sales_order_approval_v1:transition",
8
+ "eventType": "pre_transition",
9
+ "conditionExpression": {
10
+ "field": "workflowContext.decision",
11
+ "operator": "=",
12
+ "value": "approve"
13
+ },
14
+ "enabled": true,
15
+ "priority": 100
16
+ },
17
+ {
18
+ "ruleId": "workflow_order_approval_check_rejected",
19
+ "ruleName": "Check Decision is Reject",
20
+ "description": "Validates that the approval task decision is 'reject'",
21
+ "ruleType": "GUARD",
22
+ "entityType": "workflow:sales_order_approval_v1:transition",
23
+ "eventType": "pre_transition",
24
+ "conditionExpression": {
25
+ "field": "workflowContext.decision",
26
+ "operator": "=",
27
+ "value": "reject"
28
+ },
29
+ "enabled": true,
30
+ "priority": 100
31
+ }
32
+ ]