@open-mercato/core 0.4.2-canary-51881f6bf3 → 0.4.2-canary-5f415b8a44

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 +145 -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 +163 -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 +111 -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 +124 -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,63 @@ 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
+ entityType?: string // Entity type for workflow instance metadata (e.g., "SalesOrder")
87
+ }
88
+
89
+ /**
90
+ * WorkflowDefinitionTrigger - Embedded trigger configuration
91
+ *
92
+ * Triggers are now embedded directly in the workflow definition,
93
+ * allowing users to configure event-based workflow starts during
94
+ * workflow creation in the visual editor.
95
+ */
96
+ export interface WorkflowDefinitionTrigger {
97
+ triggerId: string
98
+ name: string
99
+ description?: string | null
100
+ eventPattern: string // e.g., "sales.orders.created", "customers.*"
101
+ config?: WorkflowEventTriggerConfig | null
102
+ enabled: boolean
103
+ priority: number
104
+ }
105
+
49
106
  // ============================================================================
50
107
  // JSONB Structure Interfaces
51
108
  // ============================================================================
@@ -53,6 +110,7 @@ export type UserTaskStatus =
53
110
  export interface WorkflowDefinitionData {
54
111
  steps: any[] // WorkflowStep[] - will define schema in validators.ts
55
112
  transitions: any[] // WorkflowTransition[] - will define schema in validators.ts
113
+ triggers?: WorkflowDefinitionTrigger[] // Event triggers for automatic workflow start
56
114
  activities?: any[] // ActivityDefinition[] - will define schema in validators.ts
57
115
  queries?: any[]
58
116
  signals?: any[]
@@ -429,6 +487,71 @@ export class WorkflowEvent {
429
487
  organizationId!: string
430
488
  }
431
489
 
490
+ // ============================================================================
491
+ // Entity: WorkflowEventTrigger
492
+ // ============================================================================
493
+
494
+ /**
495
+ * WorkflowEventTrigger entity
496
+ *
497
+ * Maps event patterns to workflow definitions for automatic triggering.
498
+ * When a matching event is emitted, the corresponding workflow is started
499
+ * with context mapped from the event payload.
500
+ */
501
+ @Entity({ tableName: 'workflow_event_triggers' })
502
+ @Index({ name: 'workflow_event_triggers_event_pattern_idx', properties: ['eventPattern', 'enabled'] })
503
+ @Index({ name: 'workflow_event_triggers_definition_idx', properties: ['workflowDefinitionId'] })
504
+ @Index({ name: 'workflow_event_triggers_tenant_org_idx', properties: ['tenantId', 'organizationId'] })
505
+ @Index({ name: 'workflow_event_triggers_enabled_priority_idx', properties: ['enabled', 'priority'] })
506
+ export class WorkflowEventTrigger {
507
+ [OptionalProps]?: 'enabled' | 'priority' | 'createdAt' | 'updatedAt' | 'deletedAt'
508
+
509
+ @PrimaryKey({ type: 'uuid', defaultRaw: 'gen_random_uuid()' })
510
+ id!: string
511
+
512
+ @Property({ name: 'name', type: 'varchar', length: 255 })
513
+ name!: string
514
+
515
+ @Property({ name: 'description', type: 'text', nullable: true })
516
+ description?: string | null
517
+
518
+ @Property({ name: 'workflow_definition_id', type: 'uuid' })
519
+ workflowDefinitionId!: string
520
+
521
+ @Property({ name: 'event_pattern', type: 'varchar', length: 255 })
522
+ eventPattern!: string
523
+
524
+ @Property({ name: 'config', type: 'jsonb', nullable: true })
525
+ config?: WorkflowEventTriggerConfig | null
526
+
527
+ @Property({ name: 'enabled', type: 'boolean', default: true })
528
+ enabled: boolean = true
529
+
530
+ @Property({ name: 'priority', type: 'integer', default: 0 })
531
+ priority: number = 0
532
+
533
+ @Property({ name: 'tenant_id', type: 'uuid' })
534
+ tenantId!: string
535
+
536
+ @Property({ name: 'organization_id', type: 'uuid' })
537
+ organizationId!: string
538
+
539
+ @Property({ name: 'created_by', type: 'varchar', length: 255, nullable: true })
540
+ createdBy?: string | null
541
+
542
+ @Property({ name: 'updated_by', type: 'varchar', length: 255, nullable: true })
543
+ updatedBy?: string | null
544
+
545
+ @Property({ name: 'created_at', type: Date, onCreate: () => new Date() })
546
+ createdAt: Date = new Date()
547
+
548
+ @Property({ name: 'updated_at', type: Date, onUpdate: () => new Date() })
549
+ updatedAt: Date = new Date()
550
+
551
+ @Property({ name: 'deleted_at', type: Date, nullable: true })
552
+ deletedAt?: Date | null
553
+ }
554
+
432
555
  // Export all entities as default for MikroORM discovery
433
556
  export default [
434
557
  WorkflowDefinition,
@@ -436,4 +559,5 @@ export default [
436
559
  StepInstance,
437
560
  UserTask,
438
561
  WorkflowEvent,
562
+ WorkflowEventTrigger,
439
563
  ]
@@ -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
+ ]