interaqt 0.3.0 → 0.3.1

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 (35) hide show
  1. package/agent/.claude/agents/code-generation-handler.md +2 -0
  2. package/agent/.claude/agents/computation-generation-handler.md +1 -0
  3. package/agent/.claude/agents/implement-design-handler.md +4 -13
  4. package/agent/.claude/agents/requirements-analysis-handler.md +46 -14
  5. package/agent/agentspace/knowledge/generator/api-reference.md +3378 -0
  6. package/agent/agentspace/knowledge/generator/basic-interaction-generation.md +377 -0
  7. package/agent/agentspace/knowledge/generator/computation-analysis.md +307 -0
  8. package/agent/agentspace/knowledge/generator/computation-implementation.md +959 -0
  9. package/agent/agentspace/knowledge/generator/data-analysis.md +463 -0
  10. package/agent/agentspace/knowledge/generator/entity-relation-generation.md +395 -0
  11. package/agent/agentspace/knowledge/generator/permission-implementation.md +460 -0
  12. package/agent/agentspace/knowledge/generator/permission-test-implementation.md +870 -0
  13. package/agent/agentspace/knowledge/generator/test-implementation.md +674 -0
  14. package/agent/agentspace/knowledge/usage/00-mindset-shift.md +322 -0
  15. package/agent/agentspace/knowledge/usage/01-core-concepts.md +131 -0
  16. package/agent/agentspace/knowledge/usage/02-define-entities-properties.md +407 -0
  17. package/agent/agentspace/knowledge/usage/03-entity-relations.md +599 -0
  18. package/agent/agentspace/knowledge/usage/04-reactive-computations.md +2186 -0
  19. package/agent/agentspace/knowledge/usage/05-interactions.md +1411 -0
  20. package/agent/agentspace/knowledge/usage/06-attributive-permissions.md +10 -0
  21. package/agent/agentspace/knowledge/usage/07-payload-parameters.md +593 -0
  22. package/agent/agentspace/knowledge/usage/08-activities.md +863 -0
  23. package/agent/agentspace/knowledge/usage/09-filtered-entities.md +784 -0
  24. package/agent/agentspace/knowledge/usage/10-async-computations.md +734 -0
  25. package/agent/agentspace/knowledge/usage/11-global-dictionaries.md +942 -0
  26. package/agent/agentspace/knowledge/usage/12-data-querying.md +1033 -0
  27. package/agent/agentspace/knowledge/usage/13-testing.md +1201 -0
  28. package/agent/agentspace/knowledge/usage/14-api-reference.md +1606 -0
  29. package/agent/agentspace/knowledge/usage/15-entity-crud-patterns.md +1122 -0
  30. package/agent/agentspace/knowledge/usage/16-frontend-page-design-guide.md +485 -0
  31. package/agent/agentspace/knowledge/usage/17-performance-optimization.md +283 -0
  32. package/agent/agentspace/knowledge/usage/18-api-exports-reference.md +176 -0
  33. package/agent/agentspace/knowledge/usage/19-common-anti-patterns.md +563 -0
  34. package/agent/agentspace/knowledge/usage/README.md +148 -0
  35. package/package.json +1 -1
@@ -0,0 +1,1411 @@
1
+ # How to Define and Execute Interactions
2
+
3
+ Interactions are the only way users interact with the system in interaqt, and the source of all data changes in the system. By defining interactions, you can describe what operations users can perform and how these operations affect data in the system.
4
+
5
+ ## Important Note: About User Identity
6
+
7
+ **interaqt focuses on reactive processing of business logic and does not include user authentication functionality.**
8
+
9
+ When using this framework, please note:
10
+ - The system assumes user identity has already been authenticated through other means (such as JWT, Session, etc.)
11
+ - All interactions start from a state where "user identity already exists"
12
+ - You don't need to define authentication-related interactions like user registration, login, logout
13
+ - User context should be provided to the framework by external systems
14
+
15
+ For example, when executing interactions, user information is passed as a parameter:
16
+ ```javascript
17
+ // User identity provided by external system
18
+ const result = await controller.callInteraction('CreatePost', {
19
+ user: { id: 'user123', name: 'John', role: 'author' }, // Already authenticated user
20
+ payload: { /* ... */ }
21
+ });
22
+ ```
23
+
24
+ ## Basic Concepts of Interactions
25
+
26
+ ### What is an Interaction
27
+
28
+ An interaction represents an operation that a user can perform, such as:
29
+ - Creating a blog post
30
+ - Liking a post
31
+ - Submitting an order
32
+ - Approving a request
33
+
34
+ Each interaction contains:
35
+ - **Name**: Identifier for the interaction
36
+ - **Action**: Identifier for the interaction type (⚠️ Note: Action is just an identifier and contains no operational logic)
37
+ - **Payload**: Parameters needed for the interaction
38
+ - **Permission control**: Who can execute this interaction
39
+
40
+ ## ⚠️ Important Concept Clarification: Action is not "Operation"
41
+
42
+ Many developers misunderstand the concept of Action. **Action is just a name given to the interaction type, like an event type tag, and it contains no operational logic.**
43
+
44
+ ```javascript
45
+ // ❌ Wrong understanding: Thinking Action contains operational logic
46
+ const CreatePost = Action.create({
47
+ name: 'createPost',
48
+ execute: async (payload) => { // ❌ Action has no execute method!
49
+ // Trying to write operational logic here...
50
+ }
51
+ });
52
+
53
+ // ✅ Correct understanding: Action is just an identifier
54
+ const CreatePost = Action.create({
55
+ name: 'createPost' // That's it! Just like naming an event
56
+ });
57
+ ```
58
+
59
+ **All data change logic is implemented through reactive computations (Transform, Count, Every, Any, etc.), not in Actions.**
60
+
61
+ ### Interactions vs Traditional APIs
62
+
63
+ ```javascript
64
+ // Traditional API approach
65
+ app.post('/api/posts', async (req, res) => {
66
+ const { title, content, authorId } = req.body;
67
+
68
+ // Manual data validation
69
+ if (!title || !content || !authorId) {
70
+ return res.status(400).json({ error: 'Missing required fields' });
71
+ }
72
+
73
+ // Manual permission checking
74
+ if (!await checkPermission(req.user, 'create_post')) {
75
+ return res.status(403).json({ error: 'Permission denied' });
76
+ }
77
+
78
+ // Manual data operations
79
+ const post = await db.posts.create({ title, content, authorId });
80
+
81
+ // Manual related data updates
82
+ await db.users.update(authorId, {
83
+ postCount: { $inc: 1 }
84
+ });
85
+
86
+ res.json(post);
87
+ });
88
+
89
+ // interaqt interaction approach
90
+ const CreatePost = Interaction.create({
91
+ name: 'CreatePost',
92
+ action: Action.create({
93
+ name: 'createPost'
94
+ // Action only contains name, no operational logic
95
+ }),
96
+ payload: Payload.create({
97
+ items: [
98
+ PayloadItem.create({ name: 'title', required: true }),
99
+ PayloadItem.create({ name: 'content', required: true }),
100
+ PayloadItem.create({ name: 'authorId', base: User, isRef: true })
101
+ ]
102
+ })
103
+ // Data changes are declaratively defined through Relation or Property computation
104
+ });
105
+ ```
106
+
107
+ ## Creating Basic Interactions
108
+
109
+ ### Simplest Interaction
110
+
111
+ ```javascript
112
+ import { Interaction, Action, Payload, PayloadItem } from 'interaqt';
113
+
114
+ const SayHello = Interaction.create({
115
+ name: 'SayHello',
116
+ action: Action.create({
117
+ name: 'sayHello'
118
+ // Action is just an identifier, contains no specific operations
119
+ })
120
+ });
121
+ ```
122
+
123
+ ### Interaction for Creating Entities
124
+
125
+ In interaqt, interactions don't directly operate on data. Data creation, updating, and deletion are all implemented through reactive computations.
126
+
127
+ ```javascript
128
+ // 1. Define interaction
129
+ const CreateArticle = Interaction.create({
130
+ name: 'CreateArticle',
131
+ action: Action.create({
132
+ name: 'createArticle'
133
+ }),
134
+ payload: Payload.create({
135
+ items: [
136
+ PayloadItem.create({
137
+ name: 'title',
138
+ required: true
139
+ }),
140
+ PayloadItem.create({
141
+ name: 'content',
142
+ required: true
143
+ }),
144
+ PayloadItem.create({
145
+ name: 'categoryId',
146
+ base: Category,
147
+ isRef: true
148
+ })
149
+ ]
150
+ })
151
+ });
152
+
153
+ // 2. Use Transform to listen to interaction events and create entities
154
+ import { Transform, InteractionEventEntity } from 'interaqt';
155
+
156
+ // When defining Article entity, use Transform in computation to create entities reactively
157
+ const Article = Entity.create({
158
+ name: 'Article',
159
+ properties: [
160
+ Property.create({ name: 'title', type: 'string' }),
161
+ Property.create({ name: 'content', type: 'string' }),
162
+ Property.create({ name: 'status', type: 'string', defaultValue: () => 'draft' }),
163
+ Property.create({ name: 'createdAt', type: 'string' })
164
+ ],
165
+ // Transform in Entity's computation creates entities from interactions
166
+ computation: Transform.create({
167
+ record: InteractionEventEntity,
168
+ callback: function(event) {
169
+ if (event.interactionName === 'CreateArticle') {
170
+ // Return Article data to be created
171
+ return {
172
+ title: event.payload.title,
173
+ content: event.payload.content,
174
+ category: {id:event.payload.categoryId}, // Relation will be created automatically
175
+ status: 'draft',
176
+ createdAt: new Date().toISOString()
177
+ };
178
+ }
179
+ return null;
180
+ }
181
+ })
182
+ });
183
+ ```
184
+
185
+ ### Interaction for Updating Entities
186
+
187
+ ```javascript
188
+ // 1. Define update interaction
189
+ // Note: This is for logged-in users updating their own profile, user identity passed through context
190
+ const UpdateUserProfile = Interaction.create({
191
+ name: 'UpdateUserProfile',
192
+ action: Action.create({
193
+ name: 'updateProfile'
194
+ }),
195
+ payload: Payload.create({
196
+ items: [
197
+ PayloadItem.create({
198
+ name: 'userId',
199
+ base: User,
200
+ isRef: true,
201
+ required: true
202
+ }),
203
+ PayloadItem.create({ name: 'name' }),
204
+ PayloadItem.create({ name: 'bio' }),
205
+ PayloadItem.create({ name: 'avatar' })
206
+ ]
207
+ })
208
+ });
209
+
210
+ // 2. Use Transform or StateMachine to respond to interactions and update data
211
+ // This is usually defined in Property's computation
212
+ ```
213
+
214
+ ## Defining Interaction Parameters (Payload)
215
+
216
+ ### Basic Parameter Types
217
+
218
+ ```javascript
219
+ const CreatePost = Interaction.create({
220
+ name: 'CreatePost',
221
+ payload: Payload.create({
222
+ items: [
223
+ // String parameter
224
+ PayloadItem.create({
225
+ name: 'title',
226
+ required: true
227
+ }),
228
+
229
+ // Number parameter
230
+ PayloadItem.create({
231
+ name: 'priority'
232
+ }),
233
+
234
+ // Boolean parameter
235
+ PayloadItem.create({
236
+ name: 'isDraft'
237
+ }),
238
+
239
+ // Object parameter
240
+ PayloadItem.create({
241
+ name: 'metadata',
242
+ required: false
243
+ }),
244
+
245
+ // Array parameter
246
+ PayloadItem.create({
247
+ name: 'tags',
248
+ isCollection: true
249
+ })
250
+ ]
251
+ })
252
+ // ... action definition
253
+ });
254
+ ```
255
+
256
+ ### Referencing Other Entities (isRef)
257
+
258
+ ```javascript
259
+ const CreateComment = Interaction.create({
260
+ name: 'CreateComment',
261
+ payload: Payload.create({
262
+ items: [
263
+ PayloadItem.create({
264
+ name: 'content',
265
+ required: true
266
+ }),
267
+ // Reference to post entity
268
+ PayloadItem.create({
269
+ name: 'postId',
270
+ base: Post,
271
+ isRef: true,
272
+ required: true
273
+ }),
274
+ // Reference to user entity
275
+ PayloadItem.create({
276
+ name: 'authorId',
277
+ base: User,
278
+ isRef: true,
279
+ required: true
280
+ })
281
+ ]
282
+ }),
283
+ action: Action.create({
284
+ name: 'createComment'
285
+ })
286
+ });
287
+
288
+ // Comment entity with Transform in computation for reactive creation
289
+ const Comment = Entity.create({
290
+ name: 'Comment',
291
+ properties: [
292
+ Property.create({ name: 'content', type: 'string' }),
293
+ Property.create({ name: 'createdAt', type: 'string' })
294
+ ],
295
+ computation: Transform.create({
296
+ record: InteractionEventEntity,
297
+ callback: function(event) {
298
+ if (event.interactionName === 'CreateComment') {
299
+ return {
300
+ content: event.payload.content,
301
+ createdAt: new Date().toISOString(),
302
+ author: {id:event.payload.authorId}, // Relation created automatically
303
+ post: {id:event.payload.postId } // Relation created automatically
304
+ };
305
+ }
306
+ return null;
307
+ }
308
+ })
309
+ });
310
+
311
+ // Relations are defined normally without computation for creation
312
+ const CommentAuthorRelation = Relation.create({
313
+ source: Comment,
314
+ sourceProperty: 'author',
315
+ target: User,
316
+ targetProperty: 'comments',
317
+ type: 'n:1'
318
+ });
319
+
320
+ const CommentPostRelation = Relation.create({
321
+ source: Comment,
322
+ sourceProperty: 'post',
323
+ target: Post,
324
+ targetProperty: 'comments',
325
+ type: 'n:1'
326
+ });
327
+ ```
328
+
329
+ ### Parameter Validation
330
+
331
+ The framework's PayloadItem supports basic required field validation, but doesn't support complex validation rules like length limits, regular expressions, etc. These validations should be implemented in business logic:
332
+
333
+ ```javascript
334
+ const CreateProduct = Interaction.create({
335
+ name: 'CreateProduct',
336
+ action: Action.create({ name: 'createProduct' }),
337
+ payload: Payload.create({
338
+ items: [
339
+ PayloadItem.create({
340
+ name: 'name',
341
+ type: 'string',
342
+ required: true
343
+ // Complex validation logic should be implemented in interaction handling
344
+ }),
345
+ PayloadItem.create({
346
+ name: 'price',
347
+ type: 'number',
348
+ required: true
349
+ // Price range validation should be handled in business logic
350
+ }),
351
+ PayloadItem.create({
352
+ name: 'email'
353
+ // Email format validation should be handled in business logic
354
+ }),
355
+ PayloadItem.create({
356
+ name: 'category'
357
+ // Enum validation should be handled in business logic
358
+ })
359
+ ]
360
+ })
361
+ });
362
+ ```
363
+
364
+ ### Conditional Parameters
365
+
366
+ The framework itself doesn't support dynamic required conditions and complex validation functions. These logics should be implemented in interaction handling:
367
+
368
+ ```javascript
369
+ const CreateOrder = Interaction.create({
370
+ name: 'CreateOrder',
371
+ action: Action.create({ name: 'createOrder' }),
372
+ payload: Payload.create({
373
+ items: [
374
+ PayloadItem.create({
375
+ name: 'items',
376
+ isCollection: true,
377
+ required: true
378
+ }),
379
+ PayloadItem.create({
380
+ name: 'shippingAddress'
381
+ // Conditional required logic should be checked in interaction handling
382
+ }),
383
+ PayloadItem.create({
384
+ name: 'couponCode'
385
+ // Coupon validation should be implemented in business logic
386
+ })
387
+ ]
388
+ })
389
+ });
390
+
391
+ // Validation logic should be implemented in Transform or Attributive
392
+ const orderValidation = Transform.create({
393
+ record: InteractionEventEntity,
394
+ callback: function(event) {
395
+ if (event.interactionName === 'CreateOrder') {
396
+ // Implement complex validation logic here
397
+ const { payload } = event;
398
+ if (payload.totalAmount < 100 && !payload.shippingAddress) {
399
+ throw new Error('Shipping address is required for orders under $100');
400
+ }
401
+ // Coupon validation etc.
402
+ }
403
+ }
404
+ });
405
+ ```
406
+
407
+ ## Implementing Data Change Logic
408
+
409
+ ⚠️ **Important: In interaqt, never try to "operate" data in interactions!**
410
+
411
+ Interactions only declare "what users can do" and contain no data operation logic. All data changes are **inherent properties** of data, automatically maintained through reactive computations.
412
+
413
+ ### Mindset Shift: From "Operating Data" to "Declaring Data Essence"
414
+
415
+ ❌ **Wrong mindset: Trying to operate data in interactions**
416
+ ```javascript
417
+ // Wrong: Thinking you need to write "create post" logic somewhere
418
+ const CreatePost = Interaction.create({
419
+ name: 'CreatePost',
420
+ action: Action.create({
421
+ name: 'createPost',
422
+ // ❌ Wrong: Trying to write creation logic here
423
+ handler: async (payload) => {
424
+ const post = await db.create('Post', payload);
425
+ await updateUserPostCount(payload.authorId);
426
+ return post;
427
+ }
428
+ })
429
+ });
430
+ ```
431
+
432
+ ✅ **Correct mindset: Declare what data is**
433
+ ```javascript
434
+ // 1. Interaction only declares that users can create posts
435
+ const CreatePost = Interaction.create({
436
+ name: 'CreatePost',
437
+ action: Action.create({ name: 'createPost' }), // Just an identifier
438
+ payload: Payload.create({
439
+ items: [
440
+ PayloadItem.create({ name: 'title', required: true }),
441
+ PayloadItem.create({ name: 'content', required: true })
442
+ ]
443
+ })
444
+ });
445
+
446
+ // 2. Post existence "is" a response to the create post interaction
447
+ const UserPostRelation = Relation.create({
448
+ source: User,
449
+ target: Post,
450
+ computation: Transform.create({
451
+ record: InteractionEventEntity, // Listen to all interaction events
452
+ callback: (event) => {
453
+ if (event.interactionName === 'CreatePost') {
454
+ // Return post data that should exist
455
+ return {
456
+ source: event.user.id,
457
+ target: {
458
+ title: event.payload.title,
459
+ content: event.payload.content,
460
+ createdAt: new Date().toISOString()
461
+ }
462
+ };
463
+ }
464
+ }
465
+ })
466
+ });
467
+
468
+ // 3. User post count "is" the count of user-post relations
469
+ const User = Entity.create({
470
+ properties: [
471
+ Property.create({
472
+ name: 'postCount',
473
+ computation: Count.create({
474
+ record: UserPostRelation
475
+ })
476
+ })
477
+ ]
478
+ });
479
+ ```
480
+
481
+ ### Correct Ways of Data Changes
482
+
483
+ Data changes are **declared** (not operated) through the following methods:
484
+
485
+ 1. **Transform**: Declare "when a certain event occurs, certain data should exist"
486
+ 2. **Count/Every/Any**: Declare "certain data is the computed result of other data"
487
+ 3. **StateMachine**: Declare "how states transition based on events"
488
+
489
+ ### Creating Entities - Reactive Way
490
+
491
+ ```javascript
492
+ // 1. Define blog creation interaction
493
+ const CreateBlogPost = Interaction.create({
494
+ name: 'CreateBlogPost',
495
+ action: Action.create({
496
+ name: 'createBlogPost'
497
+ }),
498
+ payload: Payload.create({
499
+ items: [
500
+ PayloadItem.create({ name: 'title', required: true }),
501
+ PayloadItem.create({ name: 'content', required: true }),
502
+ PayloadItem.create({ name: 'authorId', base: User, isRef: true })
503
+ ]
504
+ })
505
+ });
506
+
507
+ // 2. Create blog posts through Entity's computation
508
+ const Post = Entity.create({
509
+ name: 'Post',
510
+ properties: [
511
+ Property.create({ name: 'title', type: 'string' }),
512
+ Property.create({ name: 'content', type: 'string' }),
513
+ Property.create({ name: 'status', type: 'string', defaultValue: () => 'draft' }),
514
+ Property.create({ name: 'createdAt', type: 'string' }),
515
+ Property.create({ name: 'slug', type: 'string' })
516
+ ],
517
+ computation: Transform.create({
518
+ record: InteractionEventEntity,
519
+ callback: function(event) {
520
+ if (event.interactionName === 'CreateBlogPost') {
521
+ // Return entity data with relation reference
522
+ return {
523
+ title: event.payload.title,
524
+ content: event.payload.content,
525
+ status: 'draft',
526
+ createdAt: new Date().toISOString(),
527
+ slug: event.payload.title.toLowerCase().replace(/\s+/g, '-'),
528
+ author: {id:event.payload.authorId} // Relation will be created automatically
529
+ };
530
+ }
531
+ return null;
532
+ }
533
+ })
534
+ });
535
+
536
+ // 3. Define relation (no computation needed for creation)
537
+ const UserPostRelation = Relation.create({
538
+ source: Post,
539
+ sourceProperty: 'author',
540
+ target: User,
541
+ targetProperty: 'posts',
542
+ type: 'n:1'
543
+ });
544
+
545
+ // 4. User's postCount property will automatically update
546
+ const User = Entity.create({
547
+ name: 'User',
548
+ properties: [
549
+ Property.create({
550
+ name: 'postCount',
551
+ type: 'number',
552
+ computation: Count.create({
553
+ record: UserPostRelation,
554
+ direction: 'target'
555
+ })
556
+ })
557
+ ]
558
+ });
559
+ ```
560
+
561
+ ### Updating Entities - Reactive Way
562
+
563
+ ```javascript
564
+ // 1. Define profile update interaction
565
+ const UpdateUserProfile = Interaction.create({
566
+ name: 'UpdateUserProfile',
567
+ action: Action.create({ name: 'updateProfile' }),
568
+ payload: Payload.create({
569
+ items: [
570
+ PayloadItem.create({ name: 'userId', base: User, isRef: true }),
571
+ PayloadItem.create({ name: 'name' }),
572
+ PayloadItem.create({ name: 'bio' }),
573
+ PayloadItem.create({ name: 'avatar' })
574
+ ]
575
+ })
576
+ });
577
+
578
+ // 2. User properties respond to update interactions
579
+ // First declare state nodes for tracking updates
580
+ const NameUpdatedState = StateNode.create({
581
+ name: 'nameUpdated',
582
+ computeValue: function(lastValue, context) {
583
+ // When entering this state due to UpdateUserProfile, return the new name
584
+ return context.event.payload.name || lastValue;
585
+ }
586
+ });
587
+
588
+ const BioUpdatedState = StateNode.create({
589
+ name: 'bioUpdated',
590
+ computeValue: function(lastValue, context) {
591
+ // When entering this state due to UpdateUserProfile, return the new bio
592
+ return context.event.payload.bio || lastValue;
593
+ }
594
+ });
595
+
596
+ const User = Entity.create({
597
+ name: 'User',
598
+ properties: [
599
+ Property.create({
600
+ name: 'name',
601
+ type: 'string',
602
+ computation: StateMachine.create({
603
+ states: [NameUpdatedState],
604
+ transfers: [
605
+ StateTransfer.create({
606
+ current: NameUpdatedState,
607
+ next: NameUpdatedState,
608
+ trigger: UpdateUserProfile,
609
+ computeTarget: (event) => ({ id: event.payload.userId })
610
+ })
611
+ ],
612
+ defaultState: NameUpdatedState
613
+ })
614
+ }),
615
+ Property.create({
616
+ name: 'bio',
617
+ type: 'string',
618
+ computation: StateMachine.create({
619
+ states: [BioUpdatedState],
620
+ transfers: [
621
+ StateTransfer.create({
622
+ current: BioUpdatedState,
623
+ next: BioUpdatedState,
624
+ trigger: UpdateUserProfile,
625
+ computeTarget: (event) => ({ id: event.payload.userId })
626
+ })
627
+ ],
628
+ defaultState: BioUpdatedState
629
+ })
630
+ })
631
+ ]
632
+ });
633
+ ```
634
+
635
+ ### Deleting Entities - Through State Management
636
+
637
+ ```javascript
638
+ // 1. Define soft delete interaction
639
+ const DeletePost = Interaction.create({
640
+ name: 'DeletePost',
641
+ action: Action.create({ name: 'deletePost' }),
642
+ payload: Payload.create({
643
+ items: [
644
+ PayloadItem.create({ name: 'postId', base: Post, isRef: true })
645
+ ]
646
+ })
647
+ });
648
+
649
+ // Define PublishPost interaction
650
+ const PublishPost = Interaction.create({
651
+ name: 'PublishPost',
652
+ action: Action.create({ name: 'publishPost' }),
653
+ payload: Payload.create({
654
+ items: [
655
+ PayloadItem.create({ name: 'postId', base: Post, isRef: true })
656
+ ]
657
+ })
658
+ });
659
+
660
+ // 2. Declare state nodes for Post status
661
+ const draftState = StateNode.create({ name: 'draft' });
662
+ const publishedState = StateNode.create({ name: 'published' });
663
+ const deletedState = StateNode.create({ name: 'deleted' });
664
+
665
+ // 3. Use StateMachine to manage post status
666
+ const Post = Entity.create({
667
+ name: 'Post',
668
+ properties: [
669
+ Property.create({ name: 'title', type: 'string' }),
670
+ Property.create({ name: 'content', type: 'string' }),
671
+ Property.create({
672
+ name: 'status',
673
+ type: 'string',
674
+ defaultValue: () => 'draft',
675
+ computation: StateMachine.create({
676
+ name: 'PostStatus',
677
+ states: [draftState, publishedState, deletedState],
678
+ defaultState: draftState,
679
+ transfers: [
680
+ StateTransfer.create({
681
+ current: draftState,
682
+ next: publishedState,
683
+ trigger: PublishPost,
684
+ computeTarget: (event) => ({ id: event.payload.postId })
685
+ }),
686
+ StateTransfer.create({
687
+ current: publishedState,
688
+ next: deletedState,
689
+ trigger: DeletePost,
690
+ computeTarget: (event) => ({ id: event.payload.postId })
691
+ }),
692
+ StateTransfer.create({
693
+ current: draftState,
694
+ next: deletedState,
695
+ trigger: DeletePost,
696
+ computeTarget: (event) => ({ id: event.payload.postId })
697
+ })
698
+ ]
699
+ })
700
+ })
701
+ ]
702
+ });
703
+
704
+ // 4. Filter active posts (exclude deleted ones)
705
+ const ActivePosts = FilteredEntity.create({
706
+ name: 'ActivePosts',
707
+ baseEntity: Post,
708
+ filter: function(record) {
709
+ return record.status !== 'deleted';
710
+ }
711
+ });
712
+ ```
713
+
714
+ ## Complex Interaction Examples
715
+
716
+ ### Multi-Step Business Process
717
+
718
+ ```javascript
719
+ // Define order status interactions
720
+ const ConfirmPayment = Interaction.create({
721
+ name: 'ConfirmPayment',
722
+ action: Action.create({ name: 'confirmPayment' }),
723
+ payload: Payload.create({
724
+ items: [
725
+ PayloadItem.create({ name: 'orderId', base: Order, isRef: true })
726
+ ]
727
+ })
728
+ });
729
+
730
+ const ShipOrder = Interaction.create({
731
+ name: 'ShipOrder',
732
+ action: Action.create({ name: 'shipOrder' }),
733
+ payload: Payload.create({
734
+ items: [
735
+ PayloadItem.create({ name: 'orderId', base: Order, isRef: true })
736
+ ]
737
+ })
738
+ });
739
+
740
+ const ConfirmDelivery = Interaction.create({
741
+ name: 'ConfirmDelivery',
742
+ action: Action.create({ name: 'confirmDelivery' }),
743
+ payload: Payload.create({
744
+ items: [
745
+ PayloadItem.create({ name: 'orderId', base: Order, isRef: true })
746
+ ]
747
+ })
748
+ });
749
+
750
+ const CancelOrder = Interaction.create({
751
+ name: 'CancelOrder',
752
+ action: Action.create({ name: 'cancelOrder' }),
753
+ payload: Payload.create({
754
+ items: [
755
+ PayloadItem.create({ name: 'orderId', base: Order, isRef: true })
756
+ ]
757
+ })
758
+ });
759
+
760
+ // Order submission process with multiple steps
761
+ const SubmitOrder = Interaction.create({
762
+ name: 'SubmitOrder',
763
+ action: Action.create({ name: 'submitOrder' }),
764
+ payload: Payload.create({
765
+ items: [
766
+ PayloadItem.create({ name: 'items', isCollection: true, required: true }),
767
+ PayloadItem.create({ name: 'shippingAddress', required: true }),
768
+ PayloadItem.create({ name: 'paymentMethod', required: true }),
769
+ PayloadItem.create({ name: 'couponCode' })
770
+ ]
771
+ })
772
+ });
773
+
774
+ // Declare order state nodes
775
+ const pendingState = StateNode.create({ name: 'pending' });
776
+ const confirmedState = StateNode.create({ name: 'confirmed' });
777
+ const shippedState = StateNode.create({ name: 'shipped' });
778
+ const deliveredState = StateNode.create({ name: 'delivered' });
779
+ const cancelledState = StateNode.create({ name: 'cancelled' });
780
+
781
+ // Order entity with computed properties responding to submission
782
+ const Order = Entity.create({
783
+ name: 'Order',
784
+ properties: [
785
+ Property.create({ name: 'items', type: 'object', collection: true }),
786
+ Property.create({ name: 'shippingAddress', type: 'object' }),
787
+ Property.create({ name: 'paymentMethod', type: 'string' }),
788
+ Property.create({ name: 'couponCode', type: 'string' }),
789
+ Property.create({
790
+ name: 'status',
791
+ type: 'string',
792
+ computation: StateMachine.create({
793
+ name: 'OrderStatus',
794
+ states: [pendingState, confirmedState, shippedState, deliveredState, cancelledState],
795
+ defaultState: pendingState,
796
+ transfers: [
797
+ StateTransfer.create({
798
+ current: pendingState,
799
+ next: confirmedState,
800
+ trigger: ConfirmPayment,
801
+ computeTarget: (event) => ({ id: event.payload.orderId })
802
+ }),
803
+ StateTransfer.create({
804
+ current: confirmedState,
805
+ next: shippedState,
806
+ trigger: ShipOrder,
807
+ computeTarget: (event) => ({ id: event.payload.orderId })
808
+ }),
809
+ StateTransfer.create({
810
+ current: shippedState,
811
+ next: deliveredState,
812
+ trigger: ConfirmDelivery,
813
+ computeTarget: (event) => ({ id: event.payload.orderId })
814
+ }),
815
+ StateTransfer.create({
816
+ current: pendingState,
817
+ next: cancelledState,
818
+ trigger: CancelOrder,
819
+ computeTarget: (event) => ({ id: event.payload.orderId })
820
+ })
821
+ ]
822
+ })
823
+ }),
824
+ Property.create({
825
+ name: 'totalAmount',
826
+ type: 'number',
827
+ // Calculate from order items
828
+ computed: function(order) {
829
+ const items = order.items || [];
830
+ return items.reduce((total, item) => total + (item.price * item.quantity), 0);
831
+ }
832
+ })
833
+ ],
834
+ computation: Transform.create({
835
+ record: InteractionEventEntity,
836
+ callback: function(event) {
837
+ if (event.interactionName === 'SubmitOrder') {
838
+ return {
839
+ items: event.payload.items,
840
+ shippingAddress: event.payload.shippingAddress,
841
+ paymentMethod: event.payload.paymentMethod,
842
+ couponCode: event.payload.couponCode,
843
+ userId: event.user.id,
844
+ createdAt: new Date().toISOString()
845
+ };
846
+ }
847
+ return null;
848
+ }
849
+ })
850
+ });
851
+ ```
852
+
853
+ ### Conditional Business Logic
854
+
855
+ ```javascript
856
+ // Product review with approval workflow
857
+ const SubmitReview = Interaction.create({
858
+ name: 'SubmitReview',
859
+ action: Action.create({ name: 'submitReview' }),
860
+ payload: Payload.create({
861
+ items: [
862
+ PayloadItem.create({ name: 'productId', base: Product, isRef: true }),
863
+ PayloadItem.create({ name: 'rating', required: true }),
864
+ PayloadItem.create({ name: 'content', required: true })
865
+ ]
866
+ })
867
+ });
868
+
869
+ const Review = Entity.create({
870
+ name: 'Review',
871
+ properties: [
872
+ Property.create({ name: 'productId', type: 'string' }),
873
+ Property.create({ name: 'rating', type: 'number' }),
874
+ Property.create({ name: 'content', type: 'string' }),
875
+ Property.create({ name: 'userId', type: 'string' }),
876
+ Property.create({ name: 'createdAt', type: 'string' }),
877
+ Property.create({
878
+ name: 'status',
879
+ type: 'string',
880
+ defaultValue: () => 'pending'
881
+ })
882
+ ],
883
+ computation: Transform.create({
884
+ record: InteractionEventEntity,
885
+ dataDeps: {
886
+ users: {
887
+ type: 'records',
888
+ source: User,
889
+ attributeQuery: ['id', 'trustLevel']
890
+ }
891
+ },
892
+ callback: function(event, dataDeps) {
893
+ if (event.interactionName === 'SubmitReview') {
894
+ const user = dataDeps.users?.find(u => u.id === event.user.id);
895
+ const userTrustLevel = user?.trustLevel || 0;
896
+
897
+ // Determine initial status based on trust level and rating
898
+ let initialStatus = 'pending';
899
+
900
+ // Auto-approve reviews from trusted users
901
+ if (userTrustLevel >= 80) {
902
+ initialStatus = 'approved';
903
+ }
904
+ // Reviews with low ratings require manual approval
905
+ else if (event.payload.rating <= 2) {
906
+ initialStatus = 'pending_review';
907
+ }
908
+
909
+ return {
910
+ productId: event.payload.productId,
911
+ rating: event.payload.rating,
912
+ content: event.payload.content,
913
+ userId: event.user.id,
914
+ createdAt: new Date().toISOString(),
915
+ status: initialStatus
916
+ };
917
+ }
918
+ return null;
919
+ }
920
+ })
921
+ });
922
+ ```
923
+
924
+ ## Permission Control and Security
925
+
926
+ ### Basic Permission Checks
927
+
928
+ ```javascript
929
+ // Interaction with permission requirements
930
+ const DeletePost = Interaction.create({
931
+ name: 'DeletePost',
932
+ action: Action.create({ name: 'deletePost' }),
933
+ payload: Payload.create({
934
+ items: [
935
+ PayloadItem.create({ name: 'postId', base: Post, isRef: true })
936
+ ]
937
+ }),
938
+ // Permission logic should be implemented through Attributive
939
+ });
940
+
941
+ // Use Attributive for permission control
942
+ const DeletePostPermission = Attributive.create({
943
+ name: 'canDeletePost',
944
+ type: 'boolean',
945
+ record: InteractionEventEntity,
946
+ computation: function(interactionEvent) {
947
+ if (interactionEvent.interactionName === 'DeletePost') {
948
+ const user = interactionEvent.user;
949
+ const postId = interactionEvent.payload.postId;
950
+
951
+ // Admin can delete any post
952
+ if (user.role === 'admin') {
953
+ return true;
954
+ }
955
+
956
+ // Author can delete their own post
957
+ // This would need to be checked against the actual post data
958
+ return false; // Simplified for example
959
+ }
960
+ return true;
961
+ }
962
+ });
963
+ ```
964
+
965
+ ### Role-Based Permission Control
966
+
967
+ ```javascript
968
+ // Content moderation interaction
969
+ const ModerateContent = Interaction.create({
970
+ name: 'ModerateContent',
971
+ action: Action.create({ name: 'moderateContent' }),
972
+ payload: Payload.create({
973
+ items: [
974
+ PayloadItem.create({ name: 'contentId', required: true }),
975
+ PayloadItem.create({ name: 'action', required: true }), // approve, reject, flag
976
+ PayloadItem.create({ name: 'reason' })
977
+ ]
978
+ })
979
+ });
980
+
981
+ // Permission check through Attributive
982
+ const ModerationPermission = Attributive.create({
983
+ name: 'canModerateContent',
984
+ type: 'boolean',
985
+ record: InteractionEventEntity,
986
+ computation: function(interactionEvent) {
987
+ if (interactionEvent.interactionName === 'ModerateContent') {
988
+ const user = interactionEvent.user;
989
+
990
+ // Only moderators and admins can moderate content
991
+ return ['moderator', 'admin'].includes(user.role);
992
+ }
993
+ return true;
994
+ }
995
+ });
996
+ ```
997
+
998
+ ## Using Transform to Listen to Interactions and Create Data
999
+
1000
+ Transform is a core concept in interaqt, used to listen to events in the system (such as interaction events) and reactively create or update data.
1001
+
1002
+ ### Listening to Interaction Events to Create Relations
1003
+
1004
+ ```javascript
1005
+ // 1. Define like post interaction
1006
+ const LikePost = Interaction.create({
1007
+ name: 'LikePost',
1008
+ action: Action.create({ name: 'likePost' }),
1009
+ payload: Payload.create({
1010
+ items: [
1011
+ PayloadItem.create({ name: 'userId', base: User, isRef: true }),
1012
+ PayloadItem.create({ name: 'postId', base: Post, isRef: true })
1013
+ ]
1014
+ })
1015
+ });
1016
+
1017
+ // 2. Define like relation, using Transform to listen to interaction events
1018
+ const LikeRelation = Relation.create({
1019
+ source: User,
1020
+ sourceProperty: 'likedPosts',
1021
+ target: Post,
1022
+ targetProperty: 'likedBy',
1023
+ type: 'n:n',
1024
+ properties: [
1025
+ Property.create({
1026
+ name: 'likedAt',
1027
+ type: 'string'
1028
+ })
1029
+ ],
1030
+ computation: Transform.create({
1031
+ record: InteractionEventEntity,
1032
+ callback: function(event) {
1033
+ if (event.interactionName === 'LikePost') {
1034
+ return {
1035
+ source: event.payload.userId,
1036
+ target: event.payload.postId,
1037
+ likedAt: new Date().toISOString()
1038
+ };
1039
+ }
1040
+ return null;
1041
+ }
1042
+ })
1043
+ });
1044
+
1045
+ // 3. Post's like count will be automatically calculated
1046
+ const Post = Entity.create({
1047
+ name: 'Post',
1048
+ properties: [
1049
+ Property.create({
1050
+ name: 'likeCount',
1051
+ type: 'number',
1052
+ computation: Count.create({
1053
+ relation: LikeRelation,
1054
+ relationDirection: 'target'
1055
+ })
1056
+ })
1057
+ ]
1058
+ });
1059
+ ```
1060
+
1061
+ ## Using StateMachine for State Management
1062
+
1063
+ StateMachine is used to manage entity state changes and can automatically transition states based on interaction events.
1064
+
1065
+ ### Basic State Machine Example
1066
+
1067
+ ```javascript
1068
+ import { StateMachine, StateNode } from 'interaqt';
1069
+
1070
+ // 1. Define state-related interactions
1071
+ const PayOrder = Interaction.create({
1072
+ name: 'PayOrder',
1073
+ action: Action.create({ name: 'payOrder' }),
1074
+ payload: Payload.create({
1075
+ items: [
1076
+ PayloadItem.create({ name: 'orderId', type: 'string', isRef: true, base: Order }),
1077
+ PayloadItem.create({ name: 'paymentMethod', type: 'string' }),
1078
+ PayloadItem.create({ name: 'amount', type: 'number' })
1079
+ ]
1080
+ })
1081
+ });
1082
+
1083
+ const ShipOrder = Interaction.create({
1084
+ name: 'ShipOrder',
1085
+ action: Action.create({ name: 'shipOrder' }),
1086
+ payload: Payload.create({
1087
+ items: [
1088
+ PayloadItem.create({ name: 'orderId', type: 'string', isRef: true, base: Order }),
1089
+ PayloadItem.create({ name: 'trackingNumber', type: 'string' })
1090
+ ]
1091
+ })
1092
+ });
1093
+
1094
+ // 2. Define state nodes
1095
+ const PendingState = StateNode.create({ name: 'pending' });
1096
+ const PaidState = StateNode.create({ name: 'paid' });
1097
+ const ShippedState = StateNode.create({ name: 'shipped' });
1098
+ const DeliveredState = StateNode.create({ name: 'delivered' });
1099
+
1100
+ // 3. Create order state machine
1101
+ const OrderStateMachine = StateMachine.create({
1102
+ name: 'OrderStatus',
1103
+ states: [PendingState, PaidState, ShippedState, DeliveredState],
1104
+ defaultState: PendingState,
1105
+ transfers: [
1106
+ StateTransfer.create({
1107
+ current: PendingState,
1108
+ next: PaidState,
1109
+ trigger: PayOrder,
1110
+ computeTarget: (event) => ({ id: event.payload.orderId })
1111
+ }),
1112
+ StateTransfer.create({
1113
+ current: PaidState,
1114
+ next: ShippedState,
1115
+ trigger: ShipOrder,
1116
+ computeTarget: (event) => ({ id: event.payload.orderId })
1117
+ })
1118
+ ]
1119
+ });
1120
+
1121
+ // 4. Use state machine in order entity
1122
+ const Order = Entity.create({
1123
+ name: 'Order',
1124
+ properties: [
1125
+ Property.create({
1126
+ name: 'status',
1127
+ type: 'string',
1128
+ computation: OrderStateMachine
1129
+ }),
1130
+ // Calculate other properties based on state
1131
+ Property.create({
1132
+ name: 'canCancel',
1133
+ type: 'boolean',
1134
+ computed: function(order) {
1135
+ return order.status === 'pending' || order.status === 'paid';
1136
+ }
1137
+ }),
1138
+ // Payment info is stored in separate Payment entity
1139
+ ]
1140
+ });
1141
+
1142
+ // Create Payment entity to record payment history
1143
+ const Payment = Entity.create({
1144
+ name: 'Payment',
1145
+ properties: [
1146
+ Property.create({ name: 'orderId', type: 'string' }),
1147
+ Property.create({ name: 'method', type: 'string' }),
1148
+ Property.create({ name: 'amount', type: 'number' }),
1149
+ Property.create({ name: 'paidAt', type: 'string' })
1150
+ ],
1151
+ computation: Transform.create({
1152
+ record: InteractionEventEntity,
1153
+ callback: function(event) {
1154
+ if (event.interactionName === 'PayOrder') {
1155
+ return {
1156
+ orderId: event.payload.orderId,
1157
+ method: event.payload.paymentMethod,
1158
+ amount: event.payload.amount,
1159
+ paidAt: new Date().toISOString()
1160
+ };
1161
+ }
1162
+ return null;
1163
+ }
1164
+ })
1165
+ });
1166
+ ```
1167
+
1168
+ ## Executing Interactions
1169
+
1170
+ ### Basic Execution
1171
+
1172
+ ```javascript
1173
+ // Use controller.callInteraction to execute interactions
1174
+ const result = await controller.callInteraction('CreatePost', {
1175
+ user: { id: 'user123', name: 'John' }, // User context
1176
+ payload: {
1177
+ title: 'My First Post',
1178
+ content: 'This is the content of my first post.',
1179
+ authorId: 'user123'
1180
+ }
1181
+ });
1182
+
1183
+ console.log('Interaction result:', result);
1184
+ ```
1185
+
1186
+ ### Finding and Executing Interactions
1187
+
1188
+ ```javascript
1189
+ // Find interaction by name
1190
+ const createPostInteraction = Interaction.instances.find(i => i.name === 'CreatePost');
1191
+
1192
+ if (createPostInteraction) {
1193
+ const result = await controller.callInteraction(createPostInteraction.name, {
1194
+ user: { id: 'user123' },
1195
+ payload: {
1196
+ title: 'Another Post',
1197
+ content: 'More content',
1198
+ authorId: 'user123'
1199
+ }
1200
+ });
1201
+ }
1202
+ ```
1203
+
1204
+ ### Executing Interactions in Activities
1205
+
1206
+ ```javascript
1207
+ // Execute interaction as part of an activity
1208
+ const result = await controller.callActivityInteraction(
1209
+ 'OrderProcess', // activity name
1210
+ 'processPayment', // interaction name
1211
+ 'activity-instance-id',// activity instance ID
1212
+ {
1213
+ user: { id: 'user123' },
1214
+ payload: { /* ... */ }
1215
+ }
1216
+ );
1217
+ ```
1218
+
1219
+ ## Error Handling
1220
+
1221
+ > **Important**: The interaqt framework automatically catches and handles all errors, never throwing uncaught exceptions. All errors are returned through the `error` field in the return value of `callInteraction` or `callActivityInteraction`. Therefore, **DO NOT use try-catch to test error cases**, instead check the `error` field in the return value.
1222
+
1223
+ ### Parameter Validation Errors
1224
+
1225
+ ```javascript
1226
+ // ✅ Correct error handling approach
1227
+ const result = await controller.callInteraction('CreatePost', {
1228
+ user: { id: 'user123' },
1229
+ payload: {
1230
+ title: '', // Empty title will trigger validation error
1231
+ // content missing
1232
+ authorId: 'invalid-user-id'
1233
+ }
1234
+ });
1235
+
1236
+ if (result.error) {
1237
+ console.log('Error type:', result.error.type);
1238
+ console.log('Error message:', result.error.message);
1239
+ }
1240
+
1241
+ // ❌ Wrong approach: DO NOT use try-catch
1242
+ // try {
1243
+ // const result = await controller.callInteraction('CreatePost', {...});
1244
+ // } catch (e) {
1245
+ // // This code will never execute as the framework doesn't throw exceptions
1246
+ // }
1247
+ ```
1248
+
1249
+ ### Permission Errors
1250
+
1251
+ ```javascript
1252
+ const result = await controller.callInteraction('DeletePost', {
1253
+ user: { id: 'user456' }, // Not the author
1254
+ payload: {
1255
+ postId: 'post123'
1256
+ }
1257
+ });
1258
+
1259
+ if (result.error) {
1260
+ console.log('Permission denied:', result.error);
1261
+ }
1262
+ ```
1263
+
1264
+ ### Business Logic Errors
1265
+
1266
+ In reactive systems, business logic errors are usually prevented through computed properties and conditions:
1267
+
1268
+ ```javascript
1269
+ // Use Every to ensure sufficient inventory
1270
+ const Order = Entity.create({
1271
+ name: 'Order',
1272
+ properties: [
1273
+ Property.create({
1274
+ name: 'isValid',
1275
+ type: 'boolean',
1276
+ computation: Every.create({
1277
+ record: OrderItemRelation,
1278
+ relationDirection: 'source',
1279
+ callback: function(orderItem) {
1280
+ // Check if each order item has sufficient product inventory
1281
+ return orderItem.product.stock >= orderItem.quantity;
1282
+ }
1283
+ })
1284
+ })
1285
+ ]
1286
+ });
1287
+ ```
1288
+
1289
+ ## Best Practices for Interactions
1290
+
1291
+ ### 1. Design Appropriate Interaction Granularity
1292
+
1293
+ ```javascript
1294
+ // ✅ Good design: Atomic operations
1295
+ const LikePost = Interaction.create({
1296
+ name: 'LikePost',
1297
+ action: Action.create({ name: 'likePost' }),
1298
+ payload: Payload.create({
1299
+ items: [
1300
+ PayloadItem.create({ name: 'userId', base: User, isRef: true }),
1301
+ PayloadItem.create({ name: 'postId', base: Post, isRef: true })
1302
+ ]
1303
+ })
1304
+ });
1305
+
1306
+ const UnlikePost = Interaction.create({
1307
+ name: 'UnlikePost',
1308
+ action: Action.create({ name: 'unlikePost' }),
1309
+ payload: Payload.create({
1310
+ items: [
1311
+ PayloadItem.create({ name: 'userId', base: User, isRef: true }),
1312
+ PayloadItem.create({ name: 'postId', base: Post, isRef: true })
1313
+ ]
1314
+ })
1315
+ });
1316
+
1317
+ // ❌ Avoid: Overly complex interactions
1318
+ const ManagePostLike = Interaction.create({
1319
+ name: 'ManagePostLike',
1320
+ action: Action.create({ name: 'managePostLike' }),
1321
+ payload: Payload.create({
1322
+ items: [
1323
+ PayloadItem.create({ name: 'action' }),
1324
+ // One interaction handling multiple operations increases complexity
1325
+ PayloadItem.create({ name: 'userId', base: User, isRef: true }),
1326
+ PayloadItem.create({ name: 'postId', base: Post, isRef: true })
1327
+ ]
1328
+ })
1329
+ });
1330
+ ```
1331
+
1332
+ ### 2. Use Meaningful Naming
1333
+
1334
+ ```javascript
1335
+ // ✅ Clear naming
1336
+ const SubmitLeaveRequest = Interaction.create({
1337
+ name: 'SubmitLeaveRequest',
1338
+ action: Action.create({ name: 'submitLeaveRequest' })
1339
+ });
1340
+ const ApproveLeaveRequest = Interaction.create({
1341
+ name: 'ApproveLeaveRequest',
1342
+ action: Action.create({ name: 'approveLeaveRequest' })
1343
+ });
1344
+ const PublishBlogPost = Interaction.create({
1345
+ name: 'PublishBlogPost',
1346
+ action: Action.create({ name: 'publishBlogPost' })
1347
+ });
1348
+
1349
+ // ❌ Vague naming
1350
+ const DoAction = Interaction.create({
1351
+ name: 'DoAction',
1352
+ action: Action.create({ name: 'doAction' })
1353
+ });
1354
+ const ProcessData = Interaction.create({
1355
+ name: 'ProcessData',
1356
+ action: Action.create({ name: 'processData' })
1357
+ });
1358
+ const HandleRequest = Interaction.create({
1359
+ name: 'HandleRequest',
1360
+ action: Action.create({ name: 'handleRequest' })
1361
+ });
1362
+ ```
1363
+
1364
+ ### 3. Leverage Reactive Features
1365
+
1366
+ ```javascript
1367
+ // ✅ Fully leverage reactive computations
1368
+ // Define simple interactions
1369
+ const CreatePost = Interaction.create({
1370
+ name: 'CreatePost',
1371
+ action: Action.create({ name: 'createPost' }),
1372
+ payload: Payload.create({
1373
+ items: [
1374
+ PayloadItem.create({ name: 'title', required: true }),
1375
+ PayloadItem.create({ name: 'content', required: true }),
1376
+ PayloadItem.create({ name: 'authorId', base: User, isRef: true })
1377
+ ]
1378
+ })
1379
+ });
1380
+
1381
+ // Data changes automatically handled through reactive definitions
1382
+ const UserPostRelation = Relation.create({
1383
+ // ... relation definition
1384
+ computation: Transform.create({
1385
+ record: InteractionEventEntity,
1386
+ callback: function(event) {
1387
+ if (event.interactionName === 'CreatePost') {
1388
+ // Automatically create relations and entities
1389
+ return { /* ... */ };
1390
+ }
1391
+ }
1392
+ })
1393
+ });
1394
+
1395
+ // User's postCount automatically updates
1396
+ const User = Entity.create({
1397
+ name: 'User',
1398
+ properties: [
1399
+ Property.create({
1400
+ name: 'postCount',
1401
+ type: 'number',
1402
+ computation: Count.create({
1403
+ relation: UserPostRelation,
1404
+ relationDirection: 'target'
1405
+ })
1406
+ })
1407
+ ]
1408
+ });
1409
+ ```
1410
+
1411
+ Interactions are the bridge connecting user operations and data changes in interaqt. By properly designing interactions and combining them with the framework's reactive features, you can create business logic systems that are both easy to understand and efficiently executed. Remember: interactions only define "what to do", while the specific "how to do it" is implemented through reactive computations.