ApiLogicServer 15.0.61__py3-none-any.whl → 15.0.65__py3-none-any.whl

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 (21) hide show
  1. api_logic_server_cli/api_logic_server.py +4 -3
  2. api_logic_server_cli/api_logic_server_info.yaml +2 -2
  3. api_logic_server_cli/cli.py +2 -2
  4. api_logic_server_cli/genai/{genai_admin_app.py → genai_react_app.py} +10 -2
  5. api_logic_server_cli/prototypes/base/.github/.copilot-instructions.md +297 -1
  6. api_logic_server_cli/prototypes/base/docs/training/logic_bank_api.prompt +27 -0
  7. api_logic_server_cli/prototypes/base/logic/logic_discovery/use_case.py +5 -1
  8. api_logic_server_cli/prototypes/base/test/readme_test.md +395 -0
  9. api_logic_server_cli/prototypes/basic_demo/docs/models-not-code.png +0 -0
  10. api_logic_server_cli/prototypes/basic_demo/docs/runtime engines.png +0 -0
  11. api_logic_server_cli/prototypes/basic_demo/logic/procedural/credit_service.py +204 -0
  12. api_logic_server_cli/prototypes/manager/.github/.copilot-instructions.md +1 -12
  13. api_logic_server_cli/prototypes/manager/system/Manager_workspace.code-workspace +2 -2
  14. api_logic_server_cli/prototypes/nw/test/readme_test_nw.md +224 -0
  15. {apilogicserver-15.0.61.dist-info → apilogicserver-15.0.65.dist-info}/METADATA +1 -1
  16. {apilogicserver-15.0.61.dist-info → apilogicserver-15.0.65.dist-info}/RECORD +20 -16
  17. api_logic_server_cli/prototypes/nw/test/readme_test.md +0 -13
  18. {apilogicserver-15.0.61.dist-info → apilogicserver-15.0.65.dist-info}/WHEEL +0 -0
  19. {apilogicserver-15.0.61.dist-info → apilogicserver-15.0.65.dist-info}/entry_points.txt +0 -0
  20. {apilogicserver-15.0.61.dist-info → apilogicserver-15.0.65.dist-info}/licenses/LICENSE +0 -0
  21. {apilogicserver-15.0.61.dist-info → apilogicserver-15.0.65.dist-info}/top_level.txt +0 -0
@@ -8,14 +8,15 @@ ApiLogicServer CLI: given a database url, create [and run] customizable ApiLogic
8
8
  * api/expose_api_models.py for a safrs api - using introspected models.py
9
9
  * Special provisions for NW Sample, to show customizations.
10
10
  * See end for key_module_map() quick links
11
-
11
+ ;
12
12
  Called from api_logic_server_cli.py, by instantiating the ProjectRun object.
13
13
  '''
14
14
 
15
- __version__ = "15.00.61" # last public release: 15.00.52 (15.00.12)
15
+ __version__ = "15.00.65" # last public release: 15.00.52 (15.00.12)
16
16
  recent_changes = \
17
17
  f'\n\nRecent Changes:\n' +\
18
- "\t07/27/2024 - 15.00.61: no mgr fix, confluent-kafka==2.6.0 for 3.13, system vibe support -- initial testing \n"\
18
+ "\t08/06/2024 - 15.00.65: instructions for custom API endpoints, behave testing \n"\
19
+ "\t07/30/2024 - 15.00.62: rename for clarity, no mgr fix, confluent-kafka==2.6.0 for 3.13, system vibe support -- initial testing \n"\
19
20
  "\t07/20/2024 - 15.00.52: Python 3.13 compatibility fixes - psycopg2→psycopg3, SQLAlchemy 2.0+, pkg_resources→importlib.metadata. mgr dbs \n"\
20
21
  "\t07/17/2024 - 15.00.49: venv fix+, ext bldr * fix, copilot vibe tweaks - creation, mcp logic, basic_demo autonums \n"\
21
22
  "\t07/10/2024 - 15.00.41: copilot vibe support for logic, UI, MCP, bug[98] \n"\
@@ -1,3 +1,3 @@
1
- last_created_date: July 24, 2025 19:58:07
1
+ last_created_date: August 06, 2025 17:34:43
2
2
  last_created_project_name: ../../../servers/basic_demo
3
- last_created_version: 15.00.57
3
+ last_created_version: 15.00.65
@@ -823,8 +823,8 @@ def genai_add_app(ctx, app_name: str, vibe: click.BOOL, retries: int, schema: st
823
823
  log.info(f'... Error - does not appear to be a project: {str(project.project_directory_path)}')
824
824
  log.info(f'... Typical usage - cd into project, use --project_name=. \n')
825
825
  exit (1)
826
- from api_logic_server_cli.genai.genai_admin_app import GenAIAdminApp
827
- genai_admin = GenAIAdminApp(project=project, app_name=app_name, vibe=vibe, schema=schema, retries=retries, genai_version=genai_version)
826
+ from api_logic_server_cli.genai.genai_react_app import GenAIReactApp
827
+ genai_react = GenAIReactApp(project=project, app_name=app_name, vibe=vibe, schema=schema, retries=retries, genai_version=genai_version)
828
828
  pass
829
829
  log.info("")
830
830
 
@@ -37,7 +37,15 @@ class JSResponseFormat(BaseModel): # must match system/genai/prompt_inserts/res
37
37
  code : str # generated javascript code (only)
38
38
 
39
39
 
40
- class GenAIAdminApp:
40
+ class GenAIReactApp:
41
+ """Create a react app:
42
+ 1. Clones <mgr>/system/genai/app_templates/react-admin-template
43
+ 2. For each data model class, uses creates page with list and show
44
+ * Uses ChatGpt with system/genai/app_templates/app_learning/Admin-App-Resource-Learning-Prompt.md
45
+ * Regrettably, repairs imports
46
+ 3. Creates Admin.js
47
+ * Uses ChatGpt with system/genai/app_templates/app_learning/Admin-App-js-Learning-Prompt.md
48
+ """
41
49
 
42
50
  def __init__(self, project: Project, app_name: str, vibe: bool, schema: str, genai_version: str, retries: int):
43
51
  self.start_time = time.time()
@@ -135,7 +143,7 @@ class GenAIAdminApp:
135
143
 
136
144
  def a_generate_resource_files(self):
137
145
 
138
- def fix_resource(genai_app: GenAIAdminApp, raw_source: str) -> str:
146
+ def fix_resource(genai_app: GenAIReactApp, raw_source: str) -> str:
139
147
  ''' Remove occasional begin/end code markers <br>
140
148
  And horrific override of ChatGPT refusal to generate imports AS DIRECTED!<br>
141
149
  '''
@@ -4,6 +4,25 @@
4
4
 
5
5
  This is a **GenAI-Logic (aka API Logic Server) project** - a complete, working microservice - auto-generated from a database schema.
6
6
 
7
+ ## 🔑 Key Technical Points
8
+
9
+ **Critical Implementation Details:**
10
+
11
+ 1. **Discovery Systems**:
12
+ - **Logic Discovery**: Business rules automatically loaded from `logic/logic_discovery/use_case.py` via `logic/logic_discovery/auto_discovery.py`
13
+ - **API Discovery**: Custom APIs automatically loaded from `api/api_discovery/[service_name].py` via `api/api_discovery/auto_discovery.py`
14
+ - Do NOT manually duplicate rule calls or API registrations
15
+
16
+ 2. **API Record ID Pattern**: When creating records via custom APIs, use `session.flush()` before accessing the ID to ensure it's generated:
17
+ ```python
18
+ session.add(sql_alchemy_row)
19
+ session.flush() # Ensures ID is generated
20
+ record_id = sql_alchemy_row.id
21
+ return {"message": "Success", "record_id": record_id}
22
+ ```
23
+
24
+ 3. **Automatic Business Logic**: All APIs (standard and custom) automatically inherit LogicBank rules without additional code.
25
+
7
26
  ## ⚠️ IMPORTANT: What's Already Built
8
27
 
9
28
  **DO NOT recreate these - they're already working:**
@@ -14,6 +33,8 @@ This is a **GenAI-Logic (aka API Logic Server) project** - a complete, working m
14
33
  4. **Authentication System** - JWT-based auth framework
15
34
  5. **Business Logic Engine** - Declarative rules system
16
35
 
36
+ > **📋 Testing:** For comprehensive testing conventions, patterns, and examples, see `test/readme_test.md`
37
+
17
38
  ## 🎯 Common Tasks
18
39
 
19
40
  If the user asks "what do I do now?", these subsections are good suggestions.
@@ -80,6 +101,37 @@ Use case: App Integration
80
101
  Generally CoPilot solicits Natural Language logic for translation (see logic/readme_logic.md),
81
102
  but you can also offer to suggest rules.
82
103
 
104
+ ### Discovery Systems
105
+
106
+ **IMPORTANT**: The project uses automated discovery systems that:
107
+
108
+ **Logic Discovery:**
109
+ 1. **Automatically loads business logic** from `logic/logic_discovery/use_case.py`
110
+ 2. **Discovers rules at startup** via `logic/logic_discovery/auto_discovery.py`
111
+ 3. **No manual rule loading required** - the `discover_logic()` function automatically finds and registers rules
112
+
113
+ **API Discovery:**
114
+ 1. **Automatically loads custom APIs** from `api/api_discovery/[service_name].py`
115
+ 2. **Discovers services at startup** via `api/api_discovery/auto_discovery.py` (called from `api/customize_api.py`)
116
+ 3. **No manual API registration required** - services are automatically discovered and exposed
117
+
118
+ **Do NOT duplicate** by calling them manually. The discovery systems handle this automatically.
119
+
120
+ **Implementation Locations**:
121
+ - Business rules: `logic/logic_discovery/use_case.py`
122
+ - Custom APIs: `api/api_discovery/[service_name].py`
123
+ - System automatically discovers and loads both
124
+
125
+ **Pattern**:
126
+ ```python
127
+ # logic/logic_discovery/use_case.py
128
+ def declare_logic():
129
+ """Business logic rules for the application"""
130
+ Rule.sum(derive=Customer.balance, as_sum_of=Order.amount_total)
131
+ Rule.constraint(validate=Customer, as_condition=lambda row: row.balance <= row.credit_limit)
132
+ # ... other rules
133
+ ```
134
+
83
135
  ### Adding MCP
84
136
 
85
137
  The API is automatically MCP-enabled. This adds the MCP Client:
@@ -105,7 +157,10 @@ resources:
105
157
 
106
158
  ### Create and Customize React Apps
107
159
 
108
- Complete customization is provided by generating a React Application (requires OpenAI key, Node):
160
+ **REQUIRED METHOD**: Complete customization is provided by generating a React Application (requires OpenAI key, Node):
161
+
162
+ **DO NOT use `create-react-app` or `npx create-react-app`**
163
+ **ALWAYS use this command instead:**
109
164
 
110
165
  ```bash
111
166
  # Create: ui/admin/my-app-name
@@ -120,6 +175,39 @@ Temporary restriction: security must be disabled.
120
175
 
121
176
  Customize using CoPilot chat, with `docs/training`.
122
177
 
178
+ #### React Component Development Best Practices
179
+
180
+ **Critical Pattern for List/Card Views**: When implementing custom views (like card layouts) in React Admin components:
181
+
182
+ 1. **Use `useListContext()` correctly**: Access `data` as an array, not as an object with `ids`
183
+ ```javascript
184
+ // CORRECT Pattern:
185
+ const { data, isLoading } = useListContext();
186
+ return (
187
+ <Grid container spacing={2}>
188
+ {data?.map(record => (
189
+ <Grid item key={record.id}>
190
+ <CustomCard record={record} />
191
+ </Grid>
192
+ ))}
193
+ </Grid>
194
+ );
195
+
196
+ // AVOID: Trying to use data[id] pattern - this is for older React Admin versions
197
+ ```
198
+
199
+ 2. **Component Naming Consistency**: Ensure component names match their usage in JSX - mismatched names cause runtime errors.
200
+
201
+ 3. **Simple Error Handling**: Use straightforward loading states rather than complex error checking:
202
+ ```javascript
203
+ if (isLoading) return <div>Loading...</div>;
204
+ ```
205
+
206
+ **Common Mistakes to Avoid**:
207
+ - Using `{ data, ids }` destructuring and trying to map over `ids` - this pattern is outdated
208
+ - Creating complex error handling when simple loading checks suffice
209
+ - Not referencing existing working implementations before creating new patterns
210
+
123
211
  ### Security - Role-Based Access Control
124
212
 
125
213
  Configure:
@@ -149,6 +237,8 @@ Grant(on_entity=Customer, to_role=sales, filter=lambda: Customer.SalesRep == cur
149
237
  ```
150
238
 
151
239
  ### Adding Custom API Endpoints
240
+
241
+ For simple endpoints:
152
242
  ```python
153
243
  # Edit: api/customize_api.py
154
244
  @app.route('/api/custom-endpoint')
@@ -156,6 +246,211 @@ def my_endpoint():
156
246
  return {"message": "Custom endpoint"}
157
247
  ```
158
248
 
249
+ ### Creating Advanced B2B Integration APIs with Natural Language
250
+
251
+ Users can create sophisticated custom API endpoints for B2B integration using natural language. The system automatically generates and discovers:
252
+
253
+ 1. **Custom API Service** (`api/api_discovery/[service_name].py`) - automatically discovered by `api/api_discovery/auto_discovery.py`
254
+ 2. **Row Dict Mapper** (`integration/row_dict_maps/[MapperName].py`)
255
+
256
+ **Example Implementation**: This project includes a working **OrderB2B API** that demonstrates the complete pattern:
257
+ - **API**: `api/api_discovery/order_b2b_service.py`
258
+ - **Mapper**: `integration/row_dict_maps/OrderB2BMapper.py`
259
+ - **Test Cases**: `test_requests.http` and `test_b2b_order_api.py`
260
+
261
+ **Pattern Recognition**: When users describe B2B integration scenarios involving:
262
+ - External partner data formats (✅ Account → Customer lookup)
263
+ - Field aliasing/renaming (✅ "Name" → Product.name, "QuantityOrdered" → Item.quantity)
264
+ - Nested data structures (✅ Items array handling)
265
+ - Lookups and joins (✅ Customer by name, Product by name)
266
+ - Data transformation (✅ External format to internal models)
267
+
268
+ Generate both the API service and corresponding Row Dict Mapper following these patterns:
269
+
270
+ **API Service Template** (`api/api_discovery/[service_name].py`) - Keep it concise:
271
+ ```python
272
+ from flask import request
273
+ from safrs import jsonapi_rpc
274
+ import safrs
275
+ from integration.row_dict_maps.OrderB2BMapper import OrderB2BMapper
276
+ import logging
277
+
278
+ app_logger = logging.getLogger("api_logic_server_app")
279
+
280
+ def add_service(app, api, project_dir, swagger_host: str, PORT: str, method_decorators = []):
281
+ api.expose_object(OrderB2BEndPoint)
282
+
283
+ class OrderB2BEndPoint(safrs.JABase):
284
+ @classmethod
285
+ @jsonapi_rpc(http_methods=["POST"])
286
+ def OrderB2B(self, *args, **kwargs): # yaml comment => swagger description
287
+ """ # yaml creates Swagger description
288
+ args :
289
+ data:
290
+ Account: "Alice"
291
+ Notes: "Rush order for Q4 promotion"
292
+ Items :
293
+ - Name: "Widget"
294
+ QuantityOrdered: 5
295
+ - Name: "Gadget"
296
+ QuantityOrdered: 3
297
+ ---
298
+
299
+ Creates B2B orders from external partner systems with automatic lookups and business logic.
300
+ Features automatic customer/product lookups by name, unit price copying,
301
+ amount calculations, customer balance updates, and credit limit validation.
302
+ """
303
+ db = safrs.DB
304
+ session = db.session
305
+
306
+ try:
307
+ mapper_def = OrderB2BMapper()
308
+ request_dict_data = request.json["meta"]["args"]["data"]
309
+
310
+ app_logger.info(f"OrderB2B: Processing order for account: {request_dict_data.get('Account')}")
311
+
312
+ sql_alchemy_row = mapper_def.dict_to_row(row_dict=request_dict_data, session=session)
313
+
314
+ session.add(sql_alchemy_row)
315
+ session.flush() # Ensures ID is generated before accessing it
316
+
317
+ order_id = sql_alchemy_row.id
318
+ customer_name = sql_alchemy_row.customer.name if sql_alchemy_row.customer else "Unknown"
319
+ item_count = len(sql_alchemy_row.ItemList)
320
+
321
+ return {
322
+ "message": "B2B Order created successfully",
323
+ "order_id": order_id,
324
+ "customer": customer_name,
325
+ "items_count": item_count
326
+ }
327
+
328
+ except Exception as e:
329
+ app_logger.error(f"OrderB2B: Error creating order: {str(e)}")
330
+ session.rollback()
331
+ return {"error": "Failed to create B2B order", "details": str(e)}, 400
332
+ ```
333
+
334
+ **IMPORTANT**: The project includes a working B2B integration example:
335
+ - **API Endpoint**: `OrderB2BEndPoint.OrderB2B` - Creates orders from external partner format
336
+ - **Error Handling**: Proper exception handling with session rollback for failed operations
337
+ - **Business Logic**: Automatic inheritance of all LogicBank rules (pricing, calculations, validation)
338
+ - **Testing**: Comprehensive test suite demonstrating success and error scenarios
339
+ - **Documentation**: Professional Swagger docs with YAML examples using real database data
340
+
341
+ When creating new B2B APIs, follow this proven pattern:
342
+ - Use `session.flush()` when you need generated IDs before commit
343
+ - Include proper error handling with try/catch and session.rollback()
344
+ - Provide meaningful success messages with key information (ID, customer, item count)
345
+ - Use YAML format in docstrings for clean Swagger documentation
346
+ - Always use actual database data in examples (check with sqlite3 queries)
347
+
348
+ **AI Anti-Patterns to Avoid**:
349
+ - **Don't assume CRUD operations**: If user asks for "create order API", only implement POST/insert (ask if they need GET/PUT/DELETE)
350
+ - **Don't add "enterprise" features** unless specifically requested:
351
+ - Detailed logging/monitoring beyond basic debugging
352
+ - Complex response objects with metadata
353
+ - Extensive documentation/comments
354
+ - HTTP status code handling beyond defaults
355
+ - **Don't import unused libraries**: Skip `logging`, `jsonify`, etc. unless actually needed
356
+ - **Don't over-engineer**: Simple success messages beat complex response objects
357
+
358
+ **Swagger Examples Must Use Real Data**:
359
+ When creating YAML docstring examples, use actual database data. Check first:
360
+ ```bash
361
+ sqlite3 database/db.sqlite "SELECT name FROM customer LIMIT 3;"
362
+ sqlite3 database/db.sqlite "SELECT name FROM product LIMIT 3;"
363
+ ```
364
+
365
+ **Getting Sample Data for Tests**:
366
+ ```bash
367
+ # Check actual customer names
368
+ sqlite3 database/db.sqlite "SELECT name FROM customer LIMIT 5;"
369
+
370
+ # Check actual product names
371
+ sqlite3 database/db.sqlite "SELECT name FROM product LIMIT 5;"
372
+ ```
373
+ Never assume data from other databases (like Northwind's "ALFKI") - always use the current project's actual data.
374
+
375
+ **Row Dict Mapper Template** (`integration/row_dict_maps/[MapperName].py`):
376
+ ```python
377
+ from integration.system.RowDictMapper import RowDictMapper
378
+ from database import models
379
+
380
+ class OrderB2BMapper(RowDictMapper):
381
+ def __init__(self):
382
+ """
383
+ B2B Order API Mapper for external partner integration.
384
+
385
+ Maps external B2B format to internal Order/Item structure:
386
+ - 'Account' field maps to Customer lookup by name
387
+ - 'Notes' field maps directly to Order notes
388
+ - 'Items' array with 'Name' and 'QuantityOrdered' maps to Item records
389
+ """
390
+ mapper = super(OrderB2BMapper, self).__init__(
391
+ model_class=models.Order,
392
+ alias="Order",
393
+ fields=[
394
+ (models.Order.notes, "Notes"),
395
+ # customer_id will be set via parent lookup
396
+ # amount_total will be calculated by business logic
397
+ # CreatedOn will be set by business logic
398
+ ],
399
+ parent_lookups=[
400
+ (models.Customer, [(models.Customer.name, 'Account')])
401
+ ],
402
+ related=[
403
+ ItemB2BMapper()
404
+ ]
405
+ )
406
+ return mapper
407
+
408
+ class ItemB2BMapper(RowDictMapper):
409
+ def __init__(self):
410
+ """
411
+ B2B Item Mapper for order line items.
412
+
413
+ Maps external item format to internal Item structure:
414
+ - 'Name' field maps to Product lookup by name
415
+ - 'QuantityOrdered' maps to Item quantity
416
+ """
417
+ mapper = super(ItemB2BMapper, self).__init__(
418
+ model_class=models.Item,
419
+ alias="Items",
420
+ fields=[
421
+ (models.Item.quantity, "QuantityOrdered"),
422
+ # unit_price will be copied from product by business logic
423
+ # amount will be calculated by business logic (quantity * unit_price)
424
+ ],
425
+ parent_lookups=[
426
+ (models.Product, [(models.Product.name, 'Name')])
427
+ ],
428
+ isParent=False
429
+ )
430
+ return mapper
431
+ ```
432
+
433
+ **Key Components for Natural Language Processing**:
434
+ - **Field Aliasing**: `(models.Table.field, "ExternalName")`
435
+ - **Parent Lookups**: `(models.ParentTable, [(models.ParentTable.lookup_field, 'ExternalKey')])`
436
+ - **Related Entities**: Nested RowDictMapper instances for child records
437
+ - **Automatic Joins**: System handles foreign key relationships automatically
438
+
439
+ **Business Logic Integration**: All generated APIs automatically inherit the full LogicBank rule engine through the discovery systems (`logic/logic_discovery/auto_discovery.py` and `api/api_discovery/auto_discovery.py`), ensuring data integrity, calculations, and constraints without additional code. Rules are automatically loaded from `logic/logic_discovery/use_case.py` and APIs from `api/api_discovery/[service_name].py` at startup.
440
+
441
+ **Testing B2B APIs**: The project includes comprehensive testing infrastructure:
442
+ - **REST Client Tests**: `test_requests.http` - Test directly in VS Code with REST Client extension
443
+ - **Python Test Suite**: `test_b2b_order_api.py` - Automated testing with requests library
444
+ - **Swagger UI**: `http://localhost:5656/api` - Interactive API testing and documentation
445
+ - **Sample Requests**: `sample_b2b_request.json` - Copy-paste examples for testing
446
+
447
+ **Working Example Results**: The OrderB2B API demonstrates:
448
+ - ✅ External format mapping (Account → Customer, Name → Product)
449
+ - ✅ Automatic lookups with error handling (missing customer/product detection)
450
+ - ✅ Business logic inheritance (unit price copying, amount calculations, balance updates)
451
+ - ✅ Professional Swagger documentation with YAML examples
452
+ - ✅ Complete test coverage (success cases and error scenarios)
453
+
159
454
  ### Customize Models - Add Tables, Attributes
160
455
 
161
456
  To add tables / columns to the database (highly impactful - request permission):
@@ -260,3 +555,4 @@ All events receive `(row, old_row, logic_row)` parameters and should use `logic_
260
555
  - Business logic uses LogicBank (declarative rule engine)
261
556
  - Everything is auto-generated from database introspection
262
557
  - Focus on CUSTOMIZATION, not re-creation
558
+ - Use CoPilot to assist with logic translation and API generation
@@ -8,6 +8,8 @@ If you create sum, count or formula LogicBank rules, you MUST create a correspon
8
8
 
9
9
  Use only the methods provided below.
10
10
 
11
+ IMPORTANT: Keep it simple! Use the built-in Rule methods with their parameters (like if_condition) rather than creating custom functions. The Rule methods are designed to handle common patterns directly.
12
+
11
13
 
12
14
  class Rule:
13
15
  """ Invoke these functions to declare rules """
@@ -131,6 +133,11 @@ class Rule:
131
133
  if_condition: any = None,
132
134
  when_condition: any = None,
133
135
  with_args: dict = None):
136
+ """
137
+ Events are triggered after database flush for integration (Kafka, etc.)
138
+
139
+ IMPORTANT: Use this simple pattern - do NOT create custom functions unless absolutely necessary.
140
+ Use if_condition parameter for conditional logic instead of writing custom event handlers.
134
141
 
135
142
  Example:
136
143
  Prompt:
@@ -146,6 +153,13 @@ class Rule:
146
153
  if_condition=lambda row: row.is_complete is True,
147
154
  with_args={"topic": "ready_to_ship"})
148
155
 
156
+ Args:
157
+ on_class: The model class to watch for changes
158
+ calling: Use kafka_producer.send_row_to_kafka for Kafka integration
159
+ if_condition: Lambda function to specify when the event should trigger
160
+ with_args: Dictionary with parameters like {"topic": "topic_name"}
161
+ """
162
+
149
163
 
150
164
  Expanded example:
151
165
 
@@ -310,5 +324,18 @@ Required (must-have) related parent constraints require an update to the data mo
310
324
  Prompt: Each Item must have a valid entry in the Product table.
311
325
  Response: product_id = Column(ForeignKey('product.id'), nullable=False)
312
326
 
327
+ CRITICAL: For event handling (Kafka integration, etc.), do NOT create custom event functions.
328
+ Use Rule.after_flush_row_event with if_condition parameter instead.
329
+
330
+ WRONG (do not do this):
331
+ def my_custom_kafka_function(row, old_row, logic_row):
332
+ # custom logic here
333
+ Rule.commit_row_event(on_class=Order, calling=my_custom_kafka_function)
334
+
335
+ RIGHT (do this instead):
336
+ Rule.after_flush_row_event(on_class=Order, calling=kafka_producer.send_row_to_kafka,
337
+ if_condition=lambda row: row.date_shipped is not None,
338
+ with_args={"topic": "order_shipping"})
339
+
313
340
  logic should create python files in logic/logic_discovery,
314
341
  and cross-check/use attribute names in database/models.py
@@ -1,5 +1,6 @@
1
1
  import datetime
2
2
  from decimal import Decimal
3
+ from integration.kafka import kafka_producer
3
4
  from logic_bank.exec_row_logic.logic_row import LogicRow
4
5
  from logic_bank.extensions.rule_extensions import RuleExtension
5
6
  from logic_bank.logic_bank import Rule
@@ -10,7 +11,10 @@ import logging
10
11
  from flask import jsonify
11
12
 
12
13
 
13
- """ Best practice: create logic files for each use case """
14
+ """
15
+ Best practice: create logic files for each use case,
16
+ named for the use case (eg, check_credit.py)
17
+ """
14
18
 
15
19
  app_logger = logging.getLogger(__name__)
16
20