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,599 @@
1
+ # How to Establish Entity Relations
2
+
3
+ Relations are bridges that connect different entities, defining how entities are associated with each other. interaqt supports various types of relations, including one-to-one, one-to-many, many-to-many, and symmetric relations.
4
+
5
+ ## Important: Relation Names are Auto-Generated
6
+
7
+ When creating relations, you **DO NOT** need to specify a `name` property. The framework automatically generates the relation name based on the source and target entities. For example:
8
+ - A relation between `User` and `Post` will automatically be named `UserPost`
9
+ - A relation between `Post` and `Comment` will automatically be named `PostComment`
10
+
11
+ ```javascript
12
+ // ✅ Correct: No name specified
13
+ const UserPosts = Relation.create({
14
+ source: User,
15
+ sourceProperty: 'posts',
16
+ target: Post,
17
+ targetProperty: 'author',
18
+ type: 'n:1'
19
+ });
20
+
21
+ // ❌ Wrong: Do not specify name
22
+ const UserPosts = Relation.create({
23
+ name: 'UserPost', // DON'T do this - name is auto-generated
24
+ source: User,
25
+ sourceProperty: 'posts',
26
+ target: Post,
27
+ targetProperty: 'author',
28
+ type: 'n:1'
29
+ });
30
+ ```
31
+
32
+ ## Creating One-to-One Relations
33
+
34
+ One-to-one relations represent unique correspondences between two entities, such as the relationship between a user and their profile.
35
+
36
+ ### Basic One-to-One Relation
37
+
38
+ ```javascript
39
+ import { Entity, Property, Relation } from 'interaqt';
40
+
41
+ // Define user entity
42
+ const User = Entity.create({
43
+ name: 'User',
44
+ properties: [
45
+ Property.create({ name: 'email', type: 'string', unique: true }),
46
+ Property.create({ name: 'name', type: 'string' })
47
+ ]
48
+ });
49
+
50
+ // Define profile entity
51
+ const Profile = Entity.create({
52
+ name: 'Profile',
53
+ properties: [
54
+ Property.create({ name: 'bio', type: 'string' }),
55
+ Property.create({ name: 'avatar', type: 'string' }),
56
+ Property.create({ name: 'website', type: 'string' })
57
+ ]
58
+ });
59
+
60
+ // Create one-to-one relation
61
+ const UserProfile = Relation.create({
62
+ source: User,
63
+ sourceProperty: 'profile',
64
+ target: Profile,
65
+ targetProperty: 'user',
66
+ type: '1:1'
67
+ });
68
+ ```
69
+
70
+ ### Bidirectional Access
71
+
72
+ In one-to-one relations, you can access either end from the other:
73
+
74
+ ```javascript
75
+ // Access profile from user
76
+ const user = await controller.findOne('User', { email: 'john@example.com' });
77
+ const profile = user.profile; // Get associated profile
78
+
79
+ // Access user from profile
80
+ const profile = await controller.findOne('Profile', { id: profileId });
81
+ const user = profile.user; // Get associated user
82
+ ```
83
+
84
+ ### Creating and Managing One-to-One Relations
85
+
86
+ ```javascript
87
+ // Create user and profile, establishing the relation
88
+ const createUserWithProfile = async (userData, profileData) => {
89
+ // First create the user
90
+ const user = await controller.create('User', userData);
91
+
92
+ // Create profile and link to user
93
+ const profile = await controller.create('Profile', {
94
+ ...profileData,
95
+ user: user.id // Establish relation
96
+ });
97
+
98
+ return { user, profile };
99
+ };
100
+
101
+ // Usage example
102
+ const { user, profile } = await createUserWithProfile(
103
+ { email: 'john@example.com', name: 'John Doe' },
104
+ { bio: 'Software developer', website: 'https://johndoe.dev' }
105
+ );
106
+ ```
107
+
108
+ ## Creating One-to-Many Relations
109
+
110
+ One-to-many relations represent that one entity can be associated with multiple instances of another entity, such as the relationship between users and posts.
111
+
112
+ ### Basic One-to-Many Relation
113
+
114
+ ```javascript
115
+ // User entity (already defined)
116
+ const User = Entity.create({
117
+ name: 'User',
118
+ properties: [
119
+ Property.create({ name: 'email', type: 'string', unique: true }),
120
+ Property.create({ name: 'name', type: 'string' })
121
+ ]
122
+ });
123
+
124
+ // Post entity
125
+ const Post = Entity.create({
126
+ name: 'Post',
127
+ properties: [
128
+ Property.create({ name: 'title', type: 'string' }),
129
+ Property.create({ name: 'content', type: 'string' }),
130
+ Property.create({ name: 'createdAt', type: 'string', defaultValue: () => new Date().toISOString() })
131
+ ]
132
+ });
133
+
134
+ // Create one-to-many relation
135
+ const UserPosts = Relation.create({
136
+ source: User,
137
+ sourceProperty: 'posts',
138
+ target: Post,
139
+ targetProperty: 'author',
140
+ type: 'n:1'
141
+ });
142
+ ```
143
+
144
+ ### Accessing "Many" from "One"
145
+
146
+ ```javascript
147
+ // Get all posts for a user
148
+ const user = await controller.findOne('User', { email: 'john@example.com' });
149
+ const posts = user.posts; // Get all user's posts
150
+
151
+ // Also accessible through queries
152
+ const userPosts = await controller.find('Post', {
153
+ author: user.id
154
+ });
155
+ ```
156
+
157
+ ### Accessing "One" from "Many"
158
+
159
+ ```javascript
160
+ // Get post's author
161
+ const post = await controller.findOne('Post', { id: postId });
162
+ const author = post.author; // Get post's author
163
+ ```
164
+
165
+ ### Creating and Managing One-to-Many Relations
166
+
167
+ ```javascript
168
+ // Create new post for user
169
+ const createPost = async (userId, postData) => {
170
+ return await controller.create('Post', {
171
+ ...postData,
172
+ author: userId // Establish relation with user
173
+ });
174
+ };
175
+
176
+ // Usage example
177
+ const user = await controller.findOne('User', { email: 'john@example.com' });
178
+ const post = await createPost(user.id, {
179
+ title: 'My First Post',
180
+ content: 'This is the content of my first post.'
181
+ });
182
+
183
+ // Get all user's posts (including newly created)
184
+ const allUserPosts = await controller.find('Post', { author: user.id });
185
+ ```
186
+
187
+ ## Creating Many-to-Many Relations
188
+
189
+ Many-to-many relations represent multiple associations between two entities, such as the relationship between users and tags.
190
+
191
+ ### Basic Many-to-Many Relation
192
+
193
+ ```javascript
194
+ // Tag entity
195
+ const Tag = Entity.create({
196
+ name: 'Tag',
197
+ properties: [
198
+ Property.create({ name: 'name', type: 'string', unique: true }),
199
+ Property.create({ name: 'color', type: 'string', defaultValue: '#666666' })
200
+ ]
201
+ });
202
+
203
+ // Create many-to-many relation
204
+ const UserTags = Relation.create({
205
+ source: User,
206
+ sourceProperty: 'tags',
207
+ target: Tag,
208
+ targetProperty: 'users',
209
+ type: 'n:n'
210
+ });
211
+ ```
212
+
213
+ ### Bidirectional Access
214
+
215
+ ```javascript
216
+ // Access tags from user
217
+ const user = await controller.findOne('User', { email: 'john@example.com' });
218
+ const userTags = user.tags; // Get all user's tags
219
+
220
+ // Access users from tag
221
+ const tag = await controller.findOne('Tag', { name: 'javascript' });
222
+ const tagUsers = tag.users; // Get all users with this tag
223
+ ```
224
+
225
+ ### Managing Many-to-Many Relations
226
+
227
+ ```javascript
228
+ // Add tag to user
229
+ const addTagToUser = async (userId, tagName) => {
230
+ // Find or create tag
231
+ let tag = await controller.findOne('Tag', { name: tagName });
232
+ if (!tag) {
233
+ tag = await controller.create('Tag', { name: tagName });
234
+ }
235
+
236
+ // Establish relation (specific implementation depends on framework's relation management)
237
+ await controller.createRelation('UserTags', {
238
+ source: userId,
239
+ target: tag.id
240
+ });
241
+ };
242
+
243
+ // Remove tag from user
244
+ const removeTagFromUser = async (userId, tagId) => {
245
+ await controller.removeRelation('UserTags', {
246
+ source: userId,
247
+ target: tagId
248
+ });
249
+ };
250
+
251
+ // Usage example
252
+ const user = await controller.findOne('User', { email: 'john@example.com' });
253
+ await addTagToUser(user.id, 'javascript');
254
+ await addTagToUser(user.id, 'react');
255
+ await addTagToUser(user.id, 'nodejs');
256
+ ```
257
+
258
+ ### Adding Relation Properties
259
+
260
+ Many-to-many relations can include additional properties:
261
+
262
+ ```javascript
263
+ // User-Post like relation (including like timestamp)
264
+ const Like = Relation.create({
265
+ source: User,
266
+ sourceProperty: 'likedPosts',
267
+ target: Post,
268
+ targetProperty: 'likers',
269
+ type: 'n:n',
270
+ properties: [
271
+ Property.create({
272
+ name: 'likedAt',
273
+ type: 'string',
274
+ defaultValue: () => new Date().toISOString()
275
+ }),
276
+ Property.create({
277
+ name: 'type',
278
+ type: 'string',
279
+ defaultValue: () => 'like' // Can be 'like', 'love', 'laugh', etc.
280
+ })
281
+ ]
282
+ });
283
+
284
+ // Create relation with properties
285
+ const likePost = async (userId, postId, likeType = 'like') => {
286
+ await controller.createRelation('Like', {
287
+ source: userId,
288
+ target: postId,
289
+ properties: {
290
+ type: likeType,
291
+ likedAt: new Date().toISOString()
292
+ }
293
+ });
294
+ };
295
+ ```
296
+
297
+ ## Using Symmetric Relations
298
+
299
+ Symmetric relations are a special type of many-to-many relation where both ends are the same entity type, such as friend relationships.
300
+
301
+ ### Creating Symmetric Relations
302
+
303
+ ```javascript
304
+ // Friend relation
305
+ // Note: The system automatically detects symmetric relations when:
306
+ // source === target (both User) AND sourceProperty === targetProperty (both 'friends')
307
+ const Friendship = Relation.create({
308
+ source: User,
309
+ sourceProperty: 'friends',
310
+ target: User,
311
+ targetProperty: 'friends', // Same as sourceProperty - automatically symmetric
312
+ type: 'n:n',
313
+ properties: [
314
+ Property.create({
315
+ name: 'createdAt',
316
+ type: 'string',
317
+ defaultValue: () => new Date().toISOString()
318
+ }),
319
+ Property.create({
320
+ name: 'status',
321
+ type: 'string',
322
+ defaultValue: 'pending' // pending, accepted, blocked
323
+ })
324
+ ]
325
+ });
326
+ ```
327
+
328
+ ### Special Properties of Symmetric Relations
329
+
330
+ Symmetric relations have the following characteristics:
331
+
332
+ 1. **Automatic bidirectional sync**: When A adds B as a friend, A is automatically included in B's friend list
333
+ 2. **Single relation record**: The system stores only one relation record, but both ends can access it
334
+ 3. **Status consistency**: The relation status is consistent for both parties
335
+
336
+ ```javascript
337
+ // Send friend request
338
+ const sendFriendRequest = async (fromUserId, toUserId) => {
339
+ await controller.createRelation('Friendship', {
340
+ source: fromUserId,
341
+ target: toUserId,
342
+ properties: {
343
+ status: 'pending'
344
+ }
345
+ });
346
+ };
347
+
348
+ // Accept friend request
349
+ const acceptFriendRequest = async (userId, friendId) => {
350
+ await controller.updateRelation('Friendship', {
351
+ source: userId,
352
+ target: friendId
353
+ }, {
354
+ status: 'accepted'
355
+ });
356
+ };
357
+
358
+ // Get user's friend list
359
+ const getUserFriends = async (userId) => {
360
+ const user = await controller.findOne('User', { id: userId });
361
+ return user.friends.filter(friend => friend.status === 'accepted');
362
+ };
363
+ ```
364
+
365
+ ### Automatic Bidirectional Sync Example
366
+
367
+ ```javascript
368
+ // User A adds User B as friend
369
+ const userA = await controller.findOne('User', { email: 'alice@example.com' });
370
+ const userB = await controller.findOne('User', { email: 'bob@example.com' });
371
+
372
+ await sendFriendRequest(userA.id, userB.id);
373
+
374
+ // Now both users can see this relation
375
+ const aliceFriends = await getUserFriends(userA.id); // Contains Bob (status: pending)
376
+ const bobFriends = await getUserFriends(userB.id); // Contains Alice (status: pending)
377
+
378
+ // Bob accepts friend request
379
+ await acceptFriendRequest(userB.id, userA.id);
380
+
381
+ // Now both users have accepted friend status
382
+ const aliceFriendsAccepted = await getUserFriends(userA.id); // Bob (status: accepted)
383
+ const bobFriendsAccepted = await getUserFriends(userB.id); // Alice (status: accepted)
384
+ ```
385
+
386
+ ## Relation Queries and Optimization
387
+
388
+ ### Preloading Related Data
389
+
390
+ To avoid N+1 query problems, you can preload related data:
391
+
392
+ ```javascript
393
+ // Query users with their posts loaded
394
+ const usersWithPosts = await controller.find('User', {}, {
395
+ include: ['posts']
396
+ });
397
+
398
+ // Query posts with author and tags loaded
399
+ const postsWithDetails = await controller.find('Post', {}, {
400
+ include: ['author', 'tags']
401
+ });
402
+ ```
403
+
404
+ ### Deep Queries
405
+
406
+ You can perform multi-level relational queries:
407
+
408
+ ```javascript
409
+ // Query users, including their posts and post comments
410
+ const usersWithPostsAndComments = await controller.find('User', {}, {
411
+ include: [
412
+ {
413
+ relation: 'posts',
414
+ include: ['comments']
415
+ }
416
+ ]
417
+ });
418
+ ```
419
+
420
+ ### Conditional Queries on Relations
421
+
422
+ You can query based on related data:
423
+
424
+ ```javascript
425
+ // Find users with more than 10 posts
426
+ const activeUsers = await controller.find('User', {
427
+ 'posts.count': { $gt: 10 }
428
+ });
429
+
430
+ // Find posts liked by a specific user
431
+ const likedPosts = await controller.find('Post', {
432
+ 'likers.id': userId
433
+ });
434
+ ```
435
+
436
+ ## Relation Management Best Practices
437
+
438
+ ### 1. Design Relations with Clear Direction
439
+
440
+ ```javascript
441
+ // ✅ Good design: From owner to owned
442
+ const UserPosts = Relation.create({
443
+ source: User, // User owns posts
444
+ target: Post,
445
+ type: '1:n'
446
+ });
447
+
448
+ // ❌ Avoid: Unclear direction
449
+ const PostUser = Relation.create({
450
+ source: Post, // Post belongs to user (less intuitive direction)
451
+ target: User,
452
+ type: 'n:1'
453
+ });
454
+ ```
455
+
456
+ ### 2. Use Meaningful Property Names
457
+
458
+ ```javascript
459
+ // ✅ Clear property names
460
+ const UserPosts = Relation.create({
461
+ source: User,
462
+ sourceProperty: 'posts', // User's posts
463
+ target: Post,
464
+ targetProperty: 'author', // Post's author
465
+ type: '1:n'
466
+ });
467
+ ```
468
+
469
+ ### 3. Use Relation Properties Appropriately
470
+
471
+ ```javascript
472
+ // ✅ Add useful metadata to relations
473
+ const Membership = Relation.create({
474
+ source: User,
475
+ target: Organization,
476
+ type: 'n:n',
477
+ properties: [
478
+ Property.create({ name: 'role', type: 'string' }), // Role
479
+ Property.create({ name: 'joinedAt', type: 'string' }), // Join time
480
+ Property.create({ name: 'isActive', type: 'boolean' }) // Active status
481
+ ]
482
+ });
483
+ ```
484
+
485
+ ### 4. Consider Performance Impact
486
+
487
+ ```javascript
488
+ // Relation definition example (indexing should be configured at database level)
489
+ const UserPosts = Relation.create({
490
+ source: User,
491
+ sourceProperty: 'posts',
492
+ target: Post,
493
+ targetProperty: 'author',
494
+ type: 'n:1'
495
+ // Index configuration should be done at database level
496
+ });
497
+ ```
498
+
499
+ ## Complete Example: Blog System Relation Design
500
+
501
+ ```javascript
502
+ import { Entity, Property, Relation } from 'interaqt';
503
+
504
+ // Entity definitions
505
+ const User = Entity.create({
506
+ name: 'User',
507
+ properties: [
508
+ Property.create({ name: 'email', type: 'string', unique: true }),
509
+ Property.create({ name: 'name', type: 'string' }),
510
+ Property.create({ name: 'avatar', type: 'string' })
511
+ ]
512
+ });
513
+
514
+ const Post = Entity.create({
515
+ name: 'Post',
516
+ properties: [
517
+ Property.create({ name: 'title', type: 'string' }),
518
+ Property.create({ name: 'content', type: 'string' }),
519
+ Property.create({ name: 'status', type: 'string', defaultValue: 'draft' }),
520
+ Property.create({ name: 'createdAt', type: 'string', defaultValue: () => new Date().toISOString() })
521
+ ]
522
+ });
523
+
524
+ const Comment = Entity.create({
525
+ name: 'Comment',
526
+ properties: [
527
+ Property.create({ name: 'content', type: 'string' }),
528
+ Property.create({ name: 'createdAt', type: 'string', defaultValue: () => new Date().toISOString() })
529
+ ]
530
+ });
531
+
532
+ const Tag = Entity.create({
533
+ name: 'Tag',
534
+ properties: [
535
+ Property.create({ name: 'name', type: 'string', unique: true }),
536
+ Property.create({ name: 'color', type: 'string', defaultValue: '#666666' })
537
+ ]
538
+ });
539
+
540
+ // Relation definitions
541
+ const UserPosts = Relation.create({
542
+ source: User,
543
+ sourceProperty: 'posts',
544
+ target: Post,
545
+ targetProperty: 'author',
546
+ type: 'n:1'
547
+ });
548
+
549
+ const PostComments = Relation.create({
550
+ source: Post,
551
+ sourceProperty: 'comments',
552
+ target: Comment,
553
+ targetProperty: 'post',
554
+ type: 'n:1'
555
+ });
556
+
557
+ const UserComments = Relation.create({
558
+ source: User,
559
+ sourceProperty: 'comments',
560
+ target: Comment,
561
+ targetProperty: 'author',
562
+ type: 'n:1'
563
+ });
564
+
565
+ const PostTags = Relation.create({
566
+ source: Post,
567
+ sourceProperty: 'tags',
568
+ target: Tag,
569
+ targetProperty: 'posts',
570
+ type: 'n:n'
571
+ });
572
+
573
+ const Like = Relation.create({
574
+ source: User,
575
+ sourceProperty: 'likedPosts',
576
+ target: Post,
577
+ targetProperty: 'likers',
578
+ type: 'n:n',
579
+ properties: [
580
+ Property.create({ name: 'likedAt', type: 'string', defaultValue: () => new Date().toISOString() })
581
+ ]
582
+ });
583
+
584
+ const Follow = Relation.create({
585
+ source: User,
586
+ sourceProperty: 'following',
587
+ target: User,
588
+ targetProperty: 'followers',
589
+ type: 'n:n',
590
+ properties: [
591
+ Property.create({ name: 'followedAt', type: 'string', defaultValue: () => new Date().toISOString() })
592
+ ]
593
+ });
594
+
595
+ export {
596
+ User, Post, Comment, Tag,
597
+ UserPosts, PostComments, UserComments, PostTags, Like, Follow
598
+ };
599
+ ```