interaqt 0.8.2 → 0.8.4

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.
@@ -162,27 +162,41 @@ git commit -m "feat: Task 3.1.2 - Complete entity and relation implementation"
162
162
  - [ ] Ensure all payloads match the documented fields
163
163
  - [ ] **🔴 CRITICAL: For query interactions (action: GetAction):**
164
164
  - **MUST declare `data` field** - specify the Entity or Relation to query
165
- - **SHOULD declare `query` field** if there are predefined filters/fields (use Query.create with QueryItem)
166
- - Example:
165
+ - **SHOULD declare `dataPolicy` field** if there are predefined filters/fields or access restrictions
166
+ - **⚠️ IMPORTANT: Data Access Scope vs Business Rules**
167
+ - If `dataConstraints` express **data access scope restrictions** (e.g., "can only view own entities", "can only view specific fields"), use `dataPolicy` NOT `condition`
168
+ - `dataPolicy` controls what data can be accessed AFTER the operation is permitted
169
+ - `condition` controls WHETHER the operation can execute (permissions/business rules)
170
+ - Example of data policy: Restricting visible fields, filtering by ownership
171
+ - Example with dynamic data policy (user-based filtering):
172
+ ```typescript
173
+ const ViewMyOrders = Interaction.create({
174
+ name: 'ViewMyOrders',
175
+ action: GetAction,
176
+ data: Order,
177
+ dataPolicy: DataPolicy.create({
178
+ match: function(this: Controller, event: any) {
179
+ // Only show user's own orders
180
+ return MatchExp.atom({key: 'owner.id', value:['=', event.user.id]})
181
+ }
182
+ })
183
+ })
184
+ ```
185
+ - Example with combined data policy (filtering + field restrictions + pagination):
167
186
  ```typescript
168
187
  const ViewMyFollowers = Interaction.create({
169
- name: 'ViewUsers',
188
+ name: 'ViewMyFollowers',
170
189
  action: GetAction,
171
190
  data: User, // REQUIRED: specify what to query
172
- query: Query.create({ // OPTIONAL: predefined query config
173
- items: [
174
- QueryItem.create({
175
- name: 'attributeQuery',
176
- value: ['id', 'name', 'email']
177
- }),
178
- // Use function-based value to add conditional restrictions based on current context user
179
- QueryItem.create({
180
- name: 'match',
181
- value: function(this:Controller, event:any) {
182
- return MatchExp.atom({key: 'follow.id', value:['=', event.user.id]})
183
- }
184
- })
185
- ]
191
+ dataPolicy: DataPolicy.create({
192
+ // Dynamic filter: only users who follow the current user
193
+ match: function(this: Controller, event: any) {
194
+ return MatchExp.atom({key: 'following.id', value:['=', event.user.id]})
195
+ },
196
+ // Field restrictions: only expose specific fields
197
+ attributeQuery: ['id', 'name', 'email'],
198
+ // Default pagination
199
+ modifier: { limit: 20, orderBy: { name: 'asc' } }
186
200
  })
187
201
  })
188
202
  ```
@@ -1015,6 +1015,23 @@ const GetUserDonations = Interaction.create({
1015
1015
  ]
1016
1016
  })
1017
1017
  })
1018
+
1019
+ // Query interaction with dataPolicy for access control
1020
+ const GetMyDonations = Interaction.create({
1021
+ name: 'GetMyDonations',
1022
+ action: GetAction,
1023
+ data: Donation, // ✅ Entity reference
1024
+ dataPolicy: DataPolicy.create({
1025
+ // ✅ Dynamic filter: users can only see their own donations
1026
+ match: function(this: Controller, event: any) {
1027
+ return MatchExp.atom({key: 'donor.id', value: ['=', event.user.id]})
1028
+ },
1029
+ // ✅ Field restrictions: limit exposed fields
1030
+ attributeQuery: ['id', 'amount', 'createdAt', 'status'],
1031
+ // ✅ Default pagination
1032
+ modifier: { limit: 20, orderBy: { createdAt: 'desc' } }
1033
+ })
1034
+ })
1018
1035
  ```
1019
1036
 
1020
1037
  ### Pattern 5: Test Error Checking
@@ -231,7 +231,40 @@ npm run generate-frontend-api
231
231
  }
232
232
  ```
233
233
 
234
- 2. **Reference Existing Components for Patterns:**
234
+ 2. **Query Interactions Always Return Arrays:**
235
+ - Backend query-type interactions always return arrays in `response.data`
236
+ - To query a specific entity/relation, use the `match` field in the query options (2nd parameter)
237
+ - Do NOT put match criteria in the payload (1st parameter)
238
+
239
+ ```typescript
240
+ // ✅ Correct: Use match in query options
241
+ const response = await apiClient.ViewVideoGenerationStatus(
242
+ { videoGenerationRequestId: videoId }, // payload
243
+ {
244
+ attributeQuery: ['id', 'status', 'videoUrl'],
245
+ match: {
246
+ key: 'id',
247
+ value: ['=', videoId] // Match condition here
248
+ }
249
+ }
250
+ );
251
+ const item = response.data[0]; // Extract first item from array
252
+
253
+ // ❌ Wrong: Don't rely on payload for filtering
254
+ const response = await apiClient.ViewVideoGenerationStatus(
255
+ { videoGenerationRequestId: videoId } // This won't filter results
256
+ );
257
+ ```
258
+
259
+ 3. **Handling Asynchronous External System Tasks:**
260
+ - For asynchronous tasks that call external systems, backend typically does NOT implement polling unless explicitly specified in requirements
261
+ - Backend usually provides a separate API endpoint to trigger status updates
262
+ - Frontend can call this API to trigger backend status updates
263
+ - Frontend implementation options:
264
+ - **Manual trigger**: Add a button in the component for users to manually trigger the status update API
265
+ - **Automatic polling**: Implement polling in the component (on mount) until the task reaches a completion state
266
+
267
+ 4. **Reference Existing Components for Patterns:**
235
268
  - Look at `frontend/src/components/*.tsx` files
236
269
  - Follow the same patterns for API client usage
237
270
  - Check how error handling is implemented
@@ -45,6 +45,27 @@ This applies to BOTH async APIs (with task IDs) and sync APIs (immediate results
45
45
  - All integration documentation files MUST be prefixed with current module name from `.currentmodule`
46
46
  - Format: `docs/{module}.{integration-name}.integration-design.md`
47
47
 
48
+ **🔴 CRITICAL PRINCIPLE: Status Polling Strategy**
49
+
50
+ **Default Approach: Frontend Polling with Manual Query API**
51
+
52
+ Backend polling consumes significant server resources. Follow this priority order:
53
+
54
+ 1. **Default (ALWAYS implement)**: Provide manual query API for frontend
55
+ - Create API endpoint to query external status
56
+ - Frontend can poll this API at its own pace
57
+ - Even if polling is needed, frontend handles it unless explicitly stated otherwise
58
+
59
+ 2. **Backend Polling (ONLY if explicitly required)**: Implement server-side polling
60
+ - ONLY implement if user explicitly requests "backend polling" in requirements
61
+ - Use with caution due to resource consumption
62
+ - Example: volcjmeng integration (only because explicitly required)
63
+
64
+ 3. **Webhook (ONLY if both conditions met)**: Implement webhook endpoint
65
+ - ONLY if external service supports webhook registration
66
+ - AND user can register webhook themselves
67
+ - Requires exposing public endpoint for external callbacks
68
+
48
69
  # Core Concepts
49
70
 
50
71
  ## Interaqt Framework
@@ -1280,6 +1280,22 @@ git commit -m "feat: Task 1.4 - Complete data concept extraction"
1280
1280
  - Interaction IDs must be semantic names (e.g., "BorrowBook", "ViewAvailableBooks") not codes (e.g., "I001")
1281
1281
  - ❌ If a requirement has role="System", it was incorrectly created - SKIP it, do NOT create interaction
1282
1282
 
1283
+ **⚠️ IMPORTANT: Distinguishing Data Access Constraints**
1284
+
1285
+ For read-type interaction requirements with access restrictions, distinguish between:
1286
+
1287
+ 1. **Business Rules** - Constraints on whether the read operation can execute
1288
+ - Example: "Only administrators can view XXX entity"
1289
+ - Controls who can perform the action
1290
+ - Should be specified in the `conditions` field
1291
+
1292
+ 2. **Data Policy** - Constraints on the scope of data returned
1293
+ - Example: "Can only view own XXX entities" or "Can only view YYY fields of XXX entity"
1294
+ - Controls what data is accessible after the operation is permitted
1295
+ - Should be specified in the `dataConstraints` field
1296
+
1297
+ These must be separated as they are implemented differently in subsequent phases.
1298
+
1283
1299
  **⚠️ IMPORTANT: External Integration Interactions**
1284
1300
 
1285
1301
  If Task 1.4 includes API Call entities, design error handling interactions: