ApiLogicServer 15.2.3__py3-none-any.whl → 15.2.10__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.
- api_logic_server_cli/api_logic_server.py +3 -1
- api_logic_server_cli/prototypes/base/.github/.copilot-instructions.md +114 -52
- api_logic_server_cli/prototypes/base/docs/training/testing.md +95 -9
- api_logic_server_cli/prototypes/base/test/api_logic_server_behave/behave_logic_report.py +19 -6
- api_logic_server_cli/prototypes/basic_demo/.github/.copilot-instructions.md +744 -0
- api_logic_server_cli/prototypes/basic_demo/customizations/logic/declare_logic.py +17 -1
- api_logic_server_cli/prototypes/basic_demo/readme.md +13 -5
- api_logic_server_cli/prototypes/basic_demo/tutor.md +1436 -0
- api_logic_server_cli/prototypes/manager/.github/.copilot-instructions.md +50 -23
- api_logic_server_cli/prototypes/manager/samples/basic_demo_sample/.github/.copilot-instructions.md +3 -0
- api_logic_server_cli/prototypes/manager/samples/basic_demo_sample/customizations/logic/declare_logic.py +17 -1
- api_logic_server_cli/prototypes/manager/samples/basic_demo_sample/docs/training/testing.md +95 -9
- api_logic_server_cli/prototypes/manager/samples/basic_demo_sample/iteration/logic/declare_logic.py +17 -1
- api_logic_server_cli/prototypes/manager/samples/basic_demo_sample/logic/declare_logic.py +38 -1
- api_logic_server_cli/prototypes/manager/samples/basic_demo_sample/test/api_logic_server_behave/features/order_processing.feature +59 -50
- api_logic_server_cli/prototypes/manager/samples/basic_demo_sample/test/api_logic_server_behave/features/steps/order_processing_steps.py +395 -248
- api_logic_server_cli/prototypes/manager/samples/basic_demo_sample/test/api_logic_server_behave/logs/behave.log +66 -62
- api_logic_server_cli/prototypes/manager/samples/basic_demo_sample/test/api_logic_server_behave/logs/scenario_logic_logs/Carbon_Neutral_Discount_A.log +51 -41
- api_logic_server_cli/prototypes/manager/samples/basic_demo_sample/test/api_logic_server_behave/logs/scenario_logic_logs/Change_Order_Customer.log +29 -0
- api_logic_server_cli/prototypes/manager/samples/basic_demo_sample/test/api_logic_server_behave/logs/scenario_logic_logs/Change_Product_in_Item.log +35 -0
- api_logic_server_cli/prototypes/manager/samples/basic_demo_sample/test/api_logic_server_behave/logs/scenario_logic_logs/Delete_Item_Reduces_Order.log +39 -19
- api_logic_server_cli/prototypes/manager/samples/basic_demo_sample/test/api_logic_server_behave/logs/scenario_logic_logs/Exceed_Credit_Limit_Rejec.log +36 -45
- api_logic_server_cli/prototypes/manager/samples/basic_demo_sample/test/api_logic_server_behave/logs/scenario_logic_logs/Good_Order_Placed_via_B2B.log +50 -40
- api_logic_server_cli/prototypes/manager/samples/basic_demo_sample/test/api_logic_server_behave/logs/scenario_logic_logs/Item_Quantity_Change.log +33 -0
- api_logic_server_cli/prototypes/manager/samples/basic_demo_sample/test/api_logic_server_behave/logs/scenario_logic_logs/Multi-Item_Order_via_B2B_.log +67 -0
- api_logic_server_cli/prototypes/manager/samples/basic_demo_sample/test/api_logic_server_behave/logs/scenario_logic_logs/Ship_Order_Excludes_from_.log +24 -14
- api_logic_server_cli/prototypes/manager/samples/basic_demo_sample/test/api_logic_server_behave/logs/scenario_logic_logs/Transaction_Processing.log +26 -17
- api_logic_server_cli/prototypes/manager/samples/basic_demo_sample/test/api_logic_server_behave/logs/scenario_logic_logs/Unship_Order_Includes_in_.log +24 -14
- api_logic_server_cli/prototypes/manager/samples/basic_demo_sample/test/api_logic_server_behave/reports/Behave Logic Report.md +361 -146
- api_logic_server_cli/prototypes/manager/system/ApiLogicServer-Internal-Dev/copilot-dev-context.md +270 -2
- {apilogicserver-15.2.3.dist-info → apilogicserver-15.2.10.dist-info}/METADATA +25 -16
- {apilogicserver-15.2.3.dist-info → apilogicserver-15.2.10.dist-info}/RECORD +36 -30
- {apilogicserver-15.2.3.dist-info → apilogicserver-15.2.10.dist-info}/WHEEL +0 -0
- {apilogicserver-15.2.3.dist-info → apilogicserver-15.2.10.dist-info}/entry_points.txt +0 -0
- {apilogicserver-15.2.3.dist-info → apilogicserver-15.2.10.dist-info}/licenses/LICENSE +0 -0
- {apilogicserver-15.2.3.dist-info → apilogicserver-15.2.10.dist-info}/top_level.txt +0 -0
|
@@ -0,0 +1,744 @@
|
|
|
1
|
+
---
|
|
2
|
+
title: Copilot Instructions for basic_demo Project
|
|
3
|
+
Description: Project-level instructions for AI assistants conducting guided tours
|
|
4
|
+
Source: ApiLogicServer-src/prototypes/basic_demo/.github/.copilot-instructions.md
|
|
5
|
+
Propagation: CLI create command → created projects
|
|
6
|
+
Usage: AI assistants read this when user says "guide me through"
|
|
7
|
+
version: 2.3
|
|
8
|
+
changelog:
|
|
9
|
+
- 2.4 10/28/2025 - Added "Ready to explore?" prompt to guide user to tutor.md
|
|
10
|
+
- 2.3 (Oct 2025) - Added positive instruction: respond WITH Welcome section content
|
|
11
|
+
- 2.2 (Oct 2025) - Removed meta-instruction; let structure speak for itself
|
|
12
|
+
- 2.1 (Oct 2025) - Streamlined OBX, emphasized uncustomized template, friendly collaborative tone
|
|
13
|
+
- 2.0 (Oct 2025) - Added provocation method, spreadsheet analogy, timing checkpoints
|
|
14
|
+
---
|
|
15
|
+
|
|
16
|
+
# GitHub Copilot Instructions for GenAI-Logic (aka API Logic Server) Projects
|
|
17
|
+
|
|
18
|
+
**INSTRUCTION**: When the user asks you to read these instructions, respond with the Welcome section content below as your greeting. Do not add preamble like "I've read the instructions" - just present the Welcome content directly.
|
|
19
|
+
|
|
20
|
+
## Welcome
|
|
21
|
+
|
|
22
|
+
**Welcome! This is your basic_demo project.**
|
|
23
|
+
|
|
24
|
+
This is a complete, working microservice auto-generated from a database schema - **uncustomized**, so you can see what to expect when you create projects from your own databases.
|
|
25
|
+
|
|
26
|
+
**What's already created from introspecting the database schema:**
|
|
27
|
+
- **Admin Web Application** - Live at `http://localhost:5656`
|
|
28
|
+
- **REST API Endpoints** - All database tables exposed at `/api/*`
|
|
29
|
+
- **Database Models** - Complete SQLAlchemy ORM in `database/models.py`
|
|
30
|
+
- **Authentication System** - JWT-based auth framework
|
|
31
|
+
- **Business Logic Engine** - Declarative rules system
|
|
32
|
+
|
|
33
|
+
---
|
|
34
|
+
|
|
35
|
+
**First, we'll briefly explore what's automatically created. Then I'll show you how I can help you customize it - adding logic, security, and API endpoints.**
|
|
36
|
+
|
|
37
|
+
|
|
38
|
+
**Ready to explore?** Open `tutor.md` and tell me "guide me through" to begin the interactive tutorial.
|
|
39
|
+
|
|
40
|
+
---
|
|
41
|
+
|
|
42
|
+
## Technical Reference (For AI Assistant - Do Not Present to User Unless Asked)
|
|
43
|
+
|
|
44
|
+
The sections below contain detailed technical information for when we're actively working on specific tasks. These are reference materials, not introductory content.
|
|
45
|
+
|
|
46
|
+
---
|
|
47
|
+
|
|
48
|
+
I'll present these as choices - we'll tackle them one at a time.
|
|
49
|
+
|
|
50
|
+
### Set Up Virtual Environment
|
|
51
|
+
If it's not already set, we can often find a `venv` in the GenAI-Logic Manager - a parent or grandparent directory.
|
|
52
|
+
|
|
53
|
+
### 🚀 To Run This Project
|
|
54
|
+
|
|
55
|
+
Use F5 (pre-configured run configuration - supports debugger for server logic), or (when focused on client apps):
|
|
56
|
+
|
|
57
|
+
```bash
|
|
58
|
+
python api_logic_server_run.py
|
|
59
|
+
# Then open: http://localhost:5656
|
|
60
|
+
```
|
|
61
|
+
|
|
62
|
+
### Adding Business Logic
|
|
63
|
+
`docs/training` explains how to translate Natural Language logic into LogicBank (Python) rules like:
|
|
64
|
+
|
|
65
|
+
```python
|
|
66
|
+
# Edit: logic/declare_logic.py
|
|
67
|
+
Rule.sum(derive=Customer.Balance, as_sum_of=Order.AmountTotal)
|
|
68
|
+
Rule.constraint(validate=Customer, as_condition=lambda row: row.Balance <= row.CreditLimit)
|
|
69
|
+
```
|
|
70
|
+
|
|
71
|
+
As described in `docs/training/logic_bank_api.prompt`, logic includes rules for sums, formulas, constraints, and more. They also include events, which are used to trigger actions like sending emails or updating related records.
|
|
72
|
+
|
|
73
|
+
For project `basic_demo`, the best place to begin is to provide CoPilot with the natural language logic below. CoPilot will then offer to translate the logic into LogicBank rules. Also
|
|
74
|
+
1. Provide the analysis (below) showing the 44X code reduction.
|
|
75
|
+
2. Stress the importance of business logic - it's half the project, and requires an underlying rules engine. Using AI alone is not sufficient - you will wind up with procedural code, with the issues noted in the analysis below.
|
|
76
|
+
|
|
77
|
+
Here's the natural language logic to provide to CoPilot:
|
|
78
|
+
|
|
79
|
+
```text
|
|
80
|
+
Use case: Check Credit
|
|
81
|
+
1. The Customer's balance is less than the credit limit
|
|
82
|
+
2. The Customer's balance is the sum of the Order amount_total where date_shipped is null
|
|
83
|
+
3. The Order's amount_total is the sum of the Item amount
|
|
84
|
+
4. The Item amount is the quantity * unit_price
|
|
85
|
+
5. The Item unit_price is copied from the Product unit_price
|
|
86
|
+
|
|
87
|
+
Use case: App Integration
|
|
88
|
+
1. Send the Order to Kafka topic 'order_shipping' if the date_shipped is not None.
|
|
89
|
+
```
|
|
90
|
+
|
|
91
|
+
**Important:** CoPilot has analyzed procedural vs declarative logic in a full app ([see it here](https://github.com/ApiLogicServer/basic_demo/blob/main/logic/declarative-vs-procedural-comparison.md)):
|
|
92
|
+
|
|
93
|
+
<analysis>
|
|
94
|
+
**LogicBank declarative rules provide a 44X reduction in code complexity** compared to traditional procedural implementations:
|
|
95
|
+
|
|
96
|
+
| Aspect | LogicBank Declarative | Procedural Code |
|
|
97
|
+
|--------|----------------------|-----------------|
|
|
98
|
+
| **Lines of Code** | 5 lines | 220+ lines |
|
|
99
|
+
| **Complexity** | Simple rule declarations | Complex event handling |
|
|
100
|
+
| **Maintenance** | Self-documenting business logic<br>Automatic Ordering | Implementation details obscure logic<br>Complex analysis to determine insert points, impacts |
|
|
101
|
+
| **Performance** | Built-in optimization & pruning | Multiple queries, N+1 problems |
|
|
102
|
+
| **Error Handling** | Automatic cascading | Manual event management |
|
|
103
|
+
| **Business Alignment** | Rules match requirements | Code doesn't reflect business intent |
|
|
104
|
+
|
|
105
|
+
**Bottom Line**: Declarative business logic eliminates complexity while providing better performance, maintainability, and business alignment.
|
|
106
|
+
|
|
107
|
+
> **Note**: The procedural implementation was generated by AI (GitHub Copilot) and still required at least 2 critical and subtle bug fixes during development, highlighting the error-prone nature of procedural approaches even when AI-assisted.
|
|
108
|
+
|
|
109
|
+
**Why the Rules Engine is a Correctness Guarantee:**
|
|
110
|
+
|
|
111
|
+
The "2 critical bugs" mentioned above were:
|
|
112
|
+
1. **Changing Order.customer_id** - procedural code failed to adjust BOTH the old and new customer balances
|
|
113
|
+
2. **Changing Item.product_id** - procedural code failed to re-copy the unit_price from the new product
|
|
114
|
+
|
|
115
|
+
These bugs illustrate why declarative rules are **mandatory, not optional**:
|
|
116
|
+
|
|
117
|
+
**Dependency Chains:** In the logic above, `Customer.balance` has transitive dependencies:
|
|
118
|
+
- Direct: `Order.amount_total`, `Order.date_shipped`
|
|
119
|
+
- Through Order: `Item.amount` (affects Order.amount_total)
|
|
120
|
+
- Through Item: `Item.quantity`, `Item.unit_price` (affect Item.amount)
|
|
121
|
+
- Through Product: `Product.unit_price` (copied to Item.unit_price)
|
|
122
|
+
|
|
123
|
+
**Automatic Completeness:** The declarative rules engine:
|
|
124
|
+
- Listens to **SQLAlchemy ORM events** at the attribute level
|
|
125
|
+
- When `Order.customer_id` changes, **automatically adjusts both old and new customer balances**
|
|
126
|
+
- When `Item.product_id` changes, **automatically re-copies from the new product**
|
|
127
|
+
- Uses **dependency ordering** to fire rules in correct sequence
|
|
128
|
+
- Applies **optimized chaining** (uses deltas, not re-aggregation)
|
|
129
|
+
|
|
130
|
+
**Why Procedural Code Fails:** Even AI-generated procedural code requires explicit handlers for EVERY possible change path. It's easy to miss:
|
|
131
|
+
- Foreign key changes affecting multiple parents
|
|
132
|
+
- Transitive dependencies through multiple tables
|
|
133
|
+
- Where clause conditions that include/exclude rows
|
|
134
|
+
|
|
135
|
+
The rules engine eliminates this entire class of bugs by automatically handling all change paths.
|
|
136
|
+
|
|
137
|
+
</analysis>
|
|
138
|
+
|
|
139
|
+
Generally CoPilot solicits Natural Language logic for translation (see logic/readme_logic.md),
|
|
140
|
+
but you can also offer to suggest rules.
|
|
141
|
+
|
|
142
|
+
### Discovery Systems
|
|
143
|
+
|
|
144
|
+
**IMPORTANT**: The project uses automated discovery systems that:
|
|
145
|
+
|
|
146
|
+
**Logic Discovery:**
|
|
147
|
+
1. **Automatically loads business logic** from `logic/logic_discovery/*.py`
|
|
148
|
+
* **CRITICAL: Always create separate files named for each use case** (e.g., `check_credit.py`, `app_integration.py`)
|
|
149
|
+
* **Never put multiple use cases in `use_case.py`** - that file is for templates/examples only
|
|
150
|
+
2. **Discovers rules at startup** via `logic/logic_discovery/auto_discovery.py`
|
|
151
|
+
3. **No manual rule loading required** - the `discover_logic()` function automatically finds and registers rules
|
|
152
|
+
|
|
153
|
+
**API Discovery:**
|
|
154
|
+
1. **Automatically loads custom APIs** from `api/api_discovery/[service_name].py`
|
|
155
|
+
2. **Discovers services at startup** via `api/api_discovery/auto_discovery.py` (called from `api/customize_api.py`)
|
|
156
|
+
3. **No manual API registration required** - services are automatically discovered and exposed
|
|
157
|
+
|
|
158
|
+
**Do NOT duplicate** by calling them manually. The discovery systems handle this automatically.
|
|
159
|
+
|
|
160
|
+
**Implementation Locations**:
|
|
161
|
+
- Business rules: `logic/logic_discovery/use_case.py`
|
|
162
|
+
- Custom APIs: `api/api_discovery/[service_name].py`
|
|
163
|
+
- System automatically discovers and loads both
|
|
164
|
+
|
|
165
|
+
**Pattern**:
|
|
166
|
+
```python
|
|
167
|
+
# logic/logic_discovery/use_case.py
|
|
168
|
+
def declare_logic():
|
|
169
|
+
"""Business logic rules for the application"""
|
|
170
|
+
Rule.sum(derive=Customer.balance, as_sum_of=Order.amount_total)
|
|
171
|
+
Rule.constraint(validate=Customer, as_condition=lambda row: row.balance <= row.credit_limit)
|
|
172
|
+
# ... other rules
|
|
173
|
+
```
|
|
174
|
+
|
|
175
|
+
**PATTERN RECOGNITION for Business Logic**:
|
|
176
|
+
When users provide natural language with multiple use cases like:
|
|
177
|
+
- "Use case: Check Credit" + "Use case: App Integration"
|
|
178
|
+
|
|
179
|
+
**ALWAYS create separate files**:
|
|
180
|
+
- `logic/logic_discovery/check_credit.py` - for credit checking rules
|
|
181
|
+
- `logic/logic_discovery/app_integration.py` - for integration rules
|
|
182
|
+
|
|
183
|
+
**NEVER put everything in `use_case.py`** - that defeats the discovery system purpose.
|
|
184
|
+
|
|
185
|
+
### Automated Testing
|
|
186
|
+
|
|
187
|
+
**CRITICAL WORKFLOW - When User Says "Create Tests":**
|
|
188
|
+
|
|
189
|
+
```
|
|
190
|
+
1. STOP ✋ - Do NOT create tests yet!
|
|
191
|
+
2. READ docs/training/testing.md FIRST (555 lines - comprehensive guide with ALL patterns)
|
|
192
|
+
3. This file contains EVERY discovered bug pattern from achieving 11/11 test success
|
|
193
|
+
4. Pay special attention to:
|
|
194
|
+
- Rule #0: Test Repeatability (timestamps for uniqueness)
|
|
195
|
+
- Rule #0.5: Behave Step Ordering (specific before general patterns)
|
|
196
|
+
- Top 5 Critical Bugs section (common AI mistakes)
|
|
197
|
+
- Filter format: filter[column]=value (NOT OData)
|
|
198
|
+
- No circular imports (test files = black box, API only)
|
|
199
|
+
- Null-safe constraints (handle None values)
|
|
200
|
+
- Fresh test data (timestamps for uniqueness)
|
|
201
|
+
5. THEN create tests following the patterns exactly
|
|
202
|
+
6. NEVER create duplicate rules - all patterns already documented
|
|
203
|
+
```
|
|
204
|
+
|
|
205
|
+
**Why This Matters:** AI-generated tests fail 80% of the time without reading this guide first. The training material documents every common mistake (circular imports, wrong filter format, null-unsafe constraints, step ordering, etc.) with exact fixes. This guide achieved 11/11 test success (100%) and contains all discovered patterns.
|
|
206
|
+
|
|
207
|
+
**`docs/training/testing.md`** explains how to create Behave tests from declarative rules, execute test suites, and generate automated documentation with complete logic traceability.
|
|
208
|
+
|
|
209
|
+
**Key capabilities:**
|
|
210
|
+
- **Create tests from rules** - Analyze declarative rules to generate appropriate test scenarios
|
|
211
|
+
- **Execute test suite** - Run all tests with one command (Launch Configuration: "Behave Run")
|
|
212
|
+
- **Generate documentation** - Auto-create wiki reports showing requirements, tests, rules used, and execution traces
|
|
213
|
+
- **Requirements traceability** - Complete chain from business requirement → test → declarative rule → execution log
|
|
214
|
+
|
|
215
|
+
**The Innovation:** Unlike traditional testing, Behave Logic Reports show **which declarative rules fired** during each test, providing complete transparency from requirement to execution. This solves the 44X advantage in testing - tests verify "what" (business rules) not "how" (procedural code).
|
|
216
|
+
|
|
217
|
+
See `test/api_logic_server_behave/` for examples and [published report](https://apilogicserver.github.io/Docs/Behave-Logic-Report/).
|
|
218
|
+
|
|
219
|
+
**Common Mistakes to Avoid (from testing.md):**
|
|
220
|
+
1. ❌ Wrong filter: `filter="name eq 'Alice'"` → ✅ Use: `filter[name]="Alice"`
|
|
221
|
+
2. ❌ Importing logic/database modules → ✅ Import only: behave, requests, test_utils
|
|
222
|
+
3. ❌ Unsafe constraints: `row.x <= row.y` → ✅ Use: `row.x is None or row.y is None or row.x <= row.y`
|
|
223
|
+
4. ❌ Step execution: `step_impl.execute_step()` → ✅ Use: `context.execute_steps('when Step')`
|
|
224
|
+
5. ❌ Reusing test data → ✅ Create fresh with: `f"{name} {int(time.time()*1000)}"`
|
|
225
|
+
|
|
226
|
+
**For detailed test creation patterns, see `docs/training/testing.md` which documents all critical rules including Rule #0.5 (Behave Step Ordering).**
|
|
227
|
+
|
|
228
|
+
#### Critical Learnings: Behave Logic Report Generation
|
|
229
|
+
|
|
230
|
+
**PROBLEM**: Reports not showing logic details for test scenarios.
|
|
231
|
+
|
|
232
|
+
**ROOT CAUSES DISCOVERED**:
|
|
233
|
+
|
|
234
|
+
1. **Empty behave.log** (Most Common Issue)
|
|
235
|
+
- ❌ Running: `python behave_run.py`
|
|
236
|
+
- ✅ Must run: `python behave_run.py --outfile=logs/behave.log`
|
|
237
|
+
- Without `--outfile`, behave.log remains empty (0 bytes) and report has no content
|
|
238
|
+
|
|
239
|
+
2. **Scenario Name Mismatch**
|
|
240
|
+
- Log files must match scenario names from .feature file
|
|
241
|
+
- ❌ Using custom names: `scenario_name = f'B2B Order - {quantity} {product_name}'`
|
|
242
|
+
- ✅ Use actual scenario: `scenario_name = context.scenario.name`
|
|
243
|
+
- Report generator truncates to 25 chars and looks for matching .log files
|
|
244
|
+
|
|
245
|
+
3. **Report Generator Logic Bug**
|
|
246
|
+
- Original code only showed logic when blank line followed "Then" step
|
|
247
|
+
- Only worked for ~30% of scenarios (those with blank lines in behave.log)
|
|
248
|
+
- ✅ Fixed: Trigger logic display when next scenario starts OR at end of file
|
|
249
|
+
|
|
250
|
+
**CORRECT PATTERN FOR WHEN STEPS**:
|
|
251
|
+
|
|
252
|
+
```python
|
|
253
|
+
@when('B2B order placed for "{customer_name}" with {quantity:d} {product_name}')
|
|
254
|
+
def step_impl(context, customer_name, quantity, product_name):
|
|
255
|
+
"""
|
|
256
|
+
Phase 2: CREATE using OrderB2B API - Tests OrderB2B integration
|
|
257
|
+
"""
|
|
258
|
+
scenario_name = context.scenario.name # ← CRITICAL: Use actual scenario name
|
|
259
|
+
test_utils.prt(f'\n{scenario_name}\n', scenario_name)
|
|
260
|
+
|
|
261
|
+
# ... test implementation ...
|
|
262
|
+
```
|
|
263
|
+
|
|
264
|
+
**WORKFLOW FOR REPORT GENERATION**:
|
|
265
|
+
|
|
266
|
+
```bash
|
|
267
|
+
# 1. Run tests WITH outfile to generate behave.log
|
|
268
|
+
python behave_run.py --outfile=logs/behave.log
|
|
269
|
+
|
|
270
|
+
# 2. Generate report (reads behave.log + scenario_logic_logs/*.log)
|
|
271
|
+
python behave_logic_report.py run
|
|
272
|
+
|
|
273
|
+
# 3. View report
|
|
274
|
+
open reports/Behave\ Logic\ Report.md
|
|
275
|
+
```
|
|
276
|
+
|
|
277
|
+
**WHAT THE REPORT SHOWS**:
|
|
278
|
+
- Each scenario gets a `<details>` section with:
|
|
279
|
+
- **Rules Used**: Which declarative rules fired (numbered list)
|
|
280
|
+
- **Logic Log**: Complete trace showing before→after values for all adjustments
|
|
281
|
+
- Demonstrates the 44X code reduction by showing rule automation
|
|
282
|
+
|
|
283
|
+
**DEBUGGING TIPS**:
|
|
284
|
+
|
|
285
|
+
```bash
|
|
286
|
+
# Check if behave.log has content
|
|
287
|
+
ls -lh logs/behave.log # Should be several KB, not 0 bytes
|
|
288
|
+
|
|
289
|
+
# Check if scenario logs exist with correct names
|
|
290
|
+
ls logs/scenario_logic_logs/ | head -10
|
|
291
|
+
|
|
292
|
+
# Count detail sections in report (should equal number of scenarios)
|
|
293
|
+
grep -c "<details markdown>" reports/Behave\ Logic\ Report.md
|
|
294
|
+
|
|
295
|
+
# View a specific scenario's log directly
|
|
296
|
+
cat logs/scenario_logic_logs/Delete_Item_Reduces_Order.log
|
|
297
|
+
```
|
|
298
|
+
|
|
299
|
+
**KEY INSIGHT**: The report generator uses a two-step process:
|
|
300
|
+
1. Reads behave.log for scenario structure (Given/When/Then steps)
|
|
301
|
+
2. Matches scenario names to .log files in scenario_logic_logs/
|
|
302
|
+
3. Injects logic details at the right location in the report
|
|
303
|
+
|
|
304
|
+
If scenario names don't match between behave.log and .log filenames, logic details won't appear!
|
|
305
|
+
|
|
306
|
+
### Adding MCP
|
|
307
|
+
|
|
308
|
+
The API is automatically MCP-enabled. The project includes a comprehensive MCP client executor at `integration/mcp/mcp_client_executor.py`, but to enable the **user interface** for MCP requests, you must run this command:
|
|
309
|
+
|
|
310
|
+
```bash
|
|
311
|
+
genai-logic genai-add-mcp-client
|
|
312
|
+
```
|
|
313
|
+
|
|
314
|
+
**CRITICAL DISTINCTION**:
|
|
315
|
+
- **`integration/mcp/mcp_client_executor.py`** = MCP processing engine (already exists)
|
|
316
|
+
- **`genai-logic genai-add-mcp-client`** = Command to add SysMcp table and UI infrastructure (must be run)
|
|
317
|
+
|
|
318
|
+
**When users ask to "Create the MCP client executor"**, they mean run the `genai-logic genai-add-mcp-client` command, NOT recreate the existing processing engine.
|
|
319
|
+
|
|
320
|
+
This command adds:
|
|
321
|
+
1. **SysMcp table** for business users to enter natural language requests
|
|
322
|
+
2. **Admin App integration** for MCP request interface
|
|
323
|
+
3. **Database infrastructure** for MCP client operations
|
|
324
|
+
|
|
325
|
+
### Configuring Admin UI
|
|
326
|
+
|
|
327
|
+
This is built when project is created - no need to add it.
|
|
328
|
+
Customize by editing the underlying yaml.
|
|
329
|
+
|
|
330
|
+
```yaml
|
|
331
|
+
# Edit: ui/admin/admin.yaml
|
|
332
|
+
resources:
|
|
333
|
+
Customer:
|
|
334
|
+
attributes:
|
|
335
|
+
- name: CompanyName
|
|
336
|
+
search: true
|
|
337
|
+
sort: true
|
|
338
|
+
```
|
|
339
|
+
|
|
340
|
+
### Create and Customize React Apps
|
|
341
|
+
|
|
342
|
+
**REQUIRED METHOD**: Complete customization is provided by generating a React Application (requires OpenAI key, Node):
|
|
343
|
+
|
|
344
|
+
**DO NOT use `create-react-app` or `npx create-react-app`**
|
|
345
|
+
**ALWAYS use this command instead:**
|
|
346
|
+
|
|
347
|
+
```bash
|
|
348
|
+
# Create: ui/admin/my-app-name
|
|
349
|
+
genai-logic genai-add-app --app-name=my-app-name --vibe
|
|
350
|
+
```
|
|
351
|
+
|
|
352
|
+
Then, `npm install` and `npm start`
|
|
353
|
+
|
|
354
|
+
Temporary restriction: security must be disabled.
|
|
355
|
+
|
|
356
|
+
**IMPORTANT**: When working with React apps, ALWAYS read `docs/training` first. This file contains critical data access provider configuration that was built when the project was created. The data provider handles JSON:API communication and record context - ignore this at your peril.
|
|
357
|
+
|
|
358
|
+
Customize using CoPilot chat, with `docs/training`.
|
|
359
|
+
|
|
360
|
+
#### React Component Development Best Practices
|
|
361
|
+
|
|
362
|
+
**Critical Pattern for List/Card Views**: When implementing custom views (like card layouts) in React Admin components:
|
|
363
|
+
|
|
364
|
+
1. **Use `useListContext()` correctly**: Access `data` as an array, not as an object with `ids`
|
|
365
|
+
```javascript
|
|
366
|
+
// CORRECT Pattern:
|
|
367
|
+
const { data, isLoading } = useListContext();
|
|
368
|
+
return (
|
|
369
|
+
<Grid container spacing={2}>
|
|
370
|
+
{data?.map(record => (
|
|
371
|
+
<Grid item key={record.id}>
|
|
372
|
+
<CustomCard record={record} />
|
|
373
|
+
</Grid>
|
|
374
|
+
))}
|
|
375
|
+
</Grid>
|
|
376
|
+
);
|
|
377
|
+
|
|
378
|
+
// AVOID: Trying to use data[id] pattern - this is for older React Admin versions
|
|
379
|
+
```
|
|
380
|
+
|
|
381
|
+
|
|
382
|
+
2. **Component Naming Consistency**: Ensure component names match their usage in JSX - mismatched names cause runtime errors.
|
|
383
|
+
|
|
384
|
+
3. **Simple Error Handling**: Use straightforward loading states rather than complex error checking:
|
|
385
|
+
```javascript
|
|
386
|
+
if (isLoading) return <div>Loading...</div>;
|
|
387
|
+
```
|
|
388
|
+
|
|
389
|
+
4. 🃏 Card View Action Links (Show, Edit, Delete) **IMPORTANT:** All card views (e.g., Product cards) must include action links or buttons for **Show**, **Edit**, and **Delete** for each record (not just the display fields), matching the functionality of the table/list view.
|
|
390
|
+
|
|
391
|
+
|
|
392
|
+
**Common Mistakes to Avoid**:
|
|
393
|
+
- Using `{ data, ids }` destructuring and trying to map over `ids` - this pattern is outdated
|
|
394
|
+
- Creating complex error handling when simple loading checks suffice
|
|
395
|
+
- Not referencing existing working implementations before creating new patterns
|
|
396
|
+
|
|
397
|
+
### Security - Role-Based Access Control
|
|
398
|
+
|
|
399
|
+
Configure:
|
|
400
|
+
```
|
|
401
|
+
als add-auth --provider-type=sql --db-url=
|
|
402
|
+
als add-auth --provider-type=sql --db_url=postgresql://postgres:p@localhost/authdb
|
|
403
|
+
|
|
404
|
+
als add-auth --provider-type=keycloak --db-url=localhost
|
|
405
|
+
als add-auth --provider-type=keycloak --db-url=hardened
|
|
406
|
+
|
|
407
|
+
als add-auth --provider-type=None # to disable
|
|
408
|
+
```
|
|
409
|
+
|
|
410
|
+
Keycloak quick start [(more information here:)](https://apilogicserver.github.io/Docs/Security-Keycloak/)
|
|
411
|
+
```bash
|
|
412
|
+
cd devops/keycloak
|
|
413
|
+
docker compose up
|
|
414
|
+
als add-auth --provider-type=keycloak --db-url=localhost
|
|
415
|
+
```
|
|
416
|
+
|
|
417
|
+
For more on KeyCloak: https://apilogicserver.github.io/Docs/Security-Keycloak/
|
|
418
|
+
|
|
419
|
+
Declaration:
|
|
420
|
+
```python
|
|
421
|
+
# Edit: security/declare_security.py
|
|
422
|
+
Grant(on_entity=Customer, to_role=sales, filter=lambda: Customer.SalesRep == current_user())
|
|
423
|
+
```
|
|
424
|
+
|
|
425
|
+
### Adding Custom API Endpoints
|
|
426
|
+
|
|
427
|
+
For simple endpoints:
|
|
428
|
+
```python
|
|
429
|
+
# Edit: api/customize_api.py
|
|
430
|
+
@app.route('/api/custom-endpoint')
|
|
431
|
+
def my_endpoint():
|
|
432
|
+
return {"message": "Custom endpoint"}
|
|
433
|
+
```
|
|
434
|
+
|
|
435
|
+
### Creating Advanced B2B Integration APIs with Natural Language
|
|
436
|
+
|
|
437
|
+
Users can create sophisticated custom API endpoints for B2B integration using natural language. The system automatically generates and discovers:
|
|
438
|
+
|
|
439
|
+
1. **Custom API Service** (`api/api_discovery/[service_name].py`) - automatically discovered by `api/api_discovery/auto_discovery.py`
|
|
440
|
+
2. **Row Dict Mapper** (`integration/row_dict_maps/[MapperName].py`)
|
|
441
|
+
|
|
442
|
+
**Example Implementation**: This project includes a working **OrderB2B API** that demonstrates the complete pattern:
|
|
443
|
+
- **API**: `api/api_discovery/order_b2b_service.py`
|
|
444
|
+
- **Mapper**: `integration/row_dict_maps/OrderB2BMapper.py`
|
|
445
|
+
- **Test Cases**: `test_requests.http` and `test_b2b_order_api.py`
|
|
446
|
+
|
|
447
|
+
**Pattern Recognition**: When users describe B2B integration scenarios involving:
|
|
448
|
+
- External partner data formats (✅ Account → Customer lookup)
|
|
449
|
+
- Field aliasing/renaming (✅ "Name" → Product.name, "QuantityOrdered" → Item.quantity)
|
|
450
|
+
- Nested data structures (✅ Items array handling)
|
|
451
|
+
- Lookups and joins (✅ Customer by name, Product by name)
|
|
452
|
+
- Data transformation (✅ External format to internal models)
|
|
453
|
+
|
|
454
|
+
Generate both the API service and corresponding Row Dict Mapper following these patterns:
|
|
455
|
+
|
|
456
|
+
**API Service Template** (`api/api_discovery/[service_name].py`) - Keep it concise:
|
|
457
|
+
```python
|
|
458
|
+
from flask import request
|
|
459
|
+
from safrs import jsonapi_rpc
|
|
460
|
+
import safrs
|
|
461
|
+
from integration.row_dict_maps.OrderB2BMapper import OrderB2BMapper
|
|
462
|
+
import logging
|
|
463
|
+
|
|
464
|
+
app_logger = logging.getLogger("api_logic_server_app")
|
|
465
|
+
|
|
466
|
+
def add_service(app, api, project_dir, swagger_host: str, PORT: str, method_decorators = []):
|
|
467
|
+
api.expose_object(OrderB2BEndPoint)
|
|
468
|
+
|
|
469
|
+
class OrderB2BEndPoint(safrs.JABase):
|
|
470
|
+
@classmethod
|
|
471
|
+
@jsonapi_rpc(http_methods=["POST"])
|
|
472
|
+
def OrderB2B(self, *args, **kwargs): # yaml comment => swagger description
|
|
473
|
+
""" # yaml creates Swagger description
|
|
474
|
+
args :
|
|
475
|
+
data:
|
|
476
|
+
Account: "Alice"
|
|
477
|
+
Notes: "Rush order for Q4 promotion"
|
|
478
|
+
Items :
|
|
479
|
+
- Name: "Widget"
|
|
480
|
+
QuantityOrdered: 5
|
|
481
|
+
- Name: "Gadget"
|
|
482
|
+
QuantityOrdered: 3
|
|
483
|
+
---
|
|
484
|
+
|
|
485
|
+
Creates B2B orders from external partner systems with automatic lookups and business logic.
|
|
486
|
+
Features automatic customer/product lookups by name, unit price copying,
|
|
487
|
+
amount calculations, customer balance updates, and credit limit validation.
|
|
488
|
+
"""
|
|
489
|
+
db = safrs.DB
|
|
490
|
+
session = db.session
|
|
491
|
+
|
|
492
|
+
try:
|
|
493
|
+
mapper_def = OrderB2BMapper()
|
|
494
|
+
request_dict_data = request.json["meta"]["args"]["data"]
|
|
495
|
+
|
|
496
|
+
app_logger.info(f"OrderB2B: Processing order for account: {request_dict_data.get('Account')}")
|
|
497
|
+
|
|
498
|
+
sql_alchemy_row = mapper_def.dict_to_row(row_dict=request_dict_data, session=session)
|
|
499
|
+
|
|
500
|
+
session.add(sql_alchemy_row)
|
|
501
|
+
session.flush() # Ensures ID is generated before accessing it
|
|
502
|
+
|
|
503
|
+
order_id = sql_alchemy_row.id
|
|
504
|
+
customer_name = sql_alchemy_row.customer.name if sql_alchemy_row.customer else "Unknown"
|
|
505
|
+
item_count = len(sql_alchemy_row.ItemList)
|
|
506
|
+
|
|
507
|
+
return {
|
|
508
|
+
"message": "B2B Order created successfully",
|
|
509
|
+
"order_id": order_id,
|
|
510
|
+
"customer": customer_name,
|
|
511
|
+
"items_count": item_count
|
|
512
|
+
}
|
|
513
|
+
|
|
514
|
+
except Exception as e:
|
|
515
|
+
app_logger.error(f"OrderB2B: Error creating order: {str(e)}")
|
|
516
|
+
session.rollback()
|
|
517
|
+
return {"error": "Failed to create B2B order", "details": str(e)}, 400
|
|
518
|
+
```
|
|
519
|
+
|
|
520
|
+
**IMPORTANT**: The project includes a working B2B integration example:
|
|
521
|
+
- **API Endpoint**: `OrderB2BEndPoint.OrderB2B` - Creates orders from external partner format
|
|
522
|
+
- **Error Handling**: Proper exception handling with session rollback for failed operations
|
|
523
|
+
- **Business Logic**: Automatic inheritance of all LogicBank rules (pricing, calculations, validation)
|
|
524
|
+
- **Testing**: Comprehensive test suite demonstrating success and error scenarios
|
|
525
|
+
- **Documentation**: Professional Swagger docs with YAML examples using real database data
|
|
526
|
+
|
|
527
|
+
When creating new B2B APIs, follow this proven pattern:
|
|
528
|
+
- Use `session.flush()` when you need generated IDs before commit
|
|
529
|
+
- Include proper error handling with try/catch and session.rollback()
|
|
530
|
+
- Provide meaningful success messages with key information (ID, customer, item count)
|
|
531
|
+
- Use YAML format in docstrings for clean Swagger documentation
|
|
532
|
+
- Always use actual database data in examples (check with sqlite3 queries)
|
|
533
|
+
|
|
534
|
+
**AI Anti-Patterns to Avoid**:
|
|
535
|
+
- **Don't assume CRUD operations**: If user asks for "create order API", only implement POST/insert (ask if they need GET/PUT/DELETE)
|
|
536
|
+
- **Don't add "enterprise" features** unless specifically requested:
|
|
537
|
+
- Detailed logging/monitoring beyond basic debugging
|
|
538
|
+
- Complex response objects with metadata
|
|
539
|
+
- Extensive documentation/comments
|
|
540
|
+
- HTTP status code handling beyond defaults
|
|
541
|
+
- **Don't import unused libraries**: Skip `logging`, `jsonify`, etc. unless actually needed
|
|
542
|
+
- **Don't over-engineer**: Simple success messages beat complex response objects
|
|
543
|
+
|
|
544
|
+
**Swagger Examples Must Use Real Data**:
|
|
545
|
+
When creating YAML docstring examples, use actual database data. Check first:
|
|
546
|
+
```bash
|
|
547
|
+
sqlite3 database/db.sqlite "SELECT name FROM customer LIMIT 3;"
|
|
548
|
+
sqlite3 database/db.sqlite "SELECT name FROM product LIMIT 3;"
|
|
549
|
+
```
|
|
550
|
+
|
|
551
|
+
**Getting Sample Data for Tests**:
|
|
552
|
+
```bash
|
|
553
|
+
# Check actual customer names
|
|
554
|
+
sqlite3 database/db.sqlite "SELECT name FROM customer LIMIT 5;"
|
|
555
|
+
|
|
556
|
+
# Check actual product names
|
|
557
|
+
sqlite3 database/db.sqlite "SELECT name FROM product LIMIT 5;"
|
|
558
|
+
```
|
|
559
|
+
Never assume data from other databases (like Northwind's "ALFKI") - always use the current project's actual data.
|
|
560
|
+
|
|
561
|
+
**Row Dict Mapper Template** (`integration/row_dict_maps/[MapperName].py`):
|
|
562
|
+
```python
|
|
563
|
+
from integration.system.RowDictMapper import RowDictMapper
|
|
564
|
+
from database import models
|
|
565
|
+
|
|
566
|
+
class OrderB2BMapper(RowDictMapper):
|
|
567
|
+
def __init__(self):
|
|
568
|
+
"""
|
|
569
|
+
B2B Order API Mapper for external partner integration.
|
|
570
|
+
|
|
571
|
+
Maps external B2B format to internal Order/Item structure:
|
|
572
|
+
- 'Account' field maps to Customer lookup by name
|
|
573
|
+
- 'Notes' field maps directly to Order notes
|
|
574
|
+
- 'Items' array with 'Name' and 'QuantityOrdered' maps to Item records
|
|
575
|
+
"""
|
|
576
|
+
mapper = super(OrderB2BMapper, self).__init__(
|
|
577
|
+
model_class=models.Order,
|
|
578
|
+
alias="Order",
|
|
579
|
+
fields=[
|
|
580
|
+
(models.Order.notes, "Notes"),
|
|
581
|
+
# customer_id will be set via parent lookup
|
|
582
|
+
# amount_total will be calculated by business logic
|
|
583
|
+
# CreatedOn will be set by business logic
|
|
584
|
+
],
|
|
585
|
+
parent_lookups=[
|
|
586
|
+
(models.Customer, [(models.Customer.name, 'Account')])
|
|
587
|
+
],
|
|
588
|
+
related=[
|
|
589
|
+
ItemB2BMapper()
|
|
590
|
+
]
|
|
591
|
+
)
|
|
592
|
+
return mapper
|
|
593
|
+
|
|
594
|
+
class ItemB2BMapper(RowDictMapper):
|
|
595
|
+
def __init__(self):
|
|
596
|
+
"""
|
|
597
|
+
B2B Item Mapper for order line items.
|
|
598
|
+
|
|
599
|
+
Maps external item format to internal Item structure:
|
|
600
|
+
- 'Name' field maps to Product lookup by name
|
|
601
|
+
- 'QuantityOrdered' maps to Item quantity
|
|
602
|
+
"""
|
|
603
|
+
mapper = super(ItemB2BMapper, self).__init__(
|
|
604
|
+
model_class=models.Item,
|
|
605
|
+
alias="Items",
|
|
606
|
+
fields=[
|
|
607
|
+
(models.Item.quantity, "QuantityOrdered"),
|
|
608
|
+
# unit_price will be copied from product by business logic
|
|
609
|
+
# amount will be calculated by business logic (quantity * unit_price)
|
|
610
|
+
],
|
|
611
|
+
parent_lookups=[
|
|
612
|
+
(models.Product, [(models.Product.name, 'Name')])
|
|
613
|
+
],
|
|
614
|
+
isParent=False
|
|
615
|
+
)
|
|
616
|
+
return mapper
|
|
617
|
+
```
|
|
618
|
+
|
|
619
|
+
**Key Components for Natural Language Processing**:
|
|
620
|
+
- **Field Aliasing**: `(models.Table.field, "ExternalName")`
|
|
621
|
+
- **Parent Lookups**: `(models.ParentTable, [(models.ParentTable.lookup_field, 'ExternalKey')])`
|
|
622
|
+
- **Related Entities**: Nested RowDictMapper instances for child records
|
|
623
|
+
- **Automatic Joins**: System handles foreign key relationships automatically
|
|
624
|
+
|
|
625
|
+
**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.
|
|
626
|
+
|
|
627
|
+
**Testing B2B APIs**: The project includes comprehensive testing infrastructure:
|
|
628
|
+
- **REST Client Tests**: `test_requests.http` - Test directly in VS Code with REST Client extension
|
|
629
|
+
- **Python Test Suite**: `test_b2b_order_api.py` - Automated testing with requests library
|
|
630
|
+
- **Swagger UI**: `http://localhost:5656/api` - Interactive API testing and documentation
|
|
631
|
+
- **Sample Requests**: `sample_b2b_request.json` - Copy-paste examples for testing
|
|
632
|
+
|
|
633
|
+
**Working Example Results**: The OrderB2B API demonstrates:
|
|
634
|
+
- ✅ External format mapping (Account → Customer, Name → Product)
|
|
635
|
+
- ✅ Automatic lookups with error handling (missing customer/product detection)
|
|
636
|
+
- ✅ Business logic inheritance (unit price copying, amount calculations, balance updates)
|
|
637
|
+
- ✅ Professional Swagger documentation with YAML examples
|
|
638
|
+
- ✅ Complete test coverage (success cases and error scenarios)
|
|
639
|
+
|
|
640
|
+
### Customize Models - Add Tables, Attributes
|
|
641
|
+
|
|
642
|
+
To add tables / columns to the database (highly impactful - request permission):
|
|
643
|
+
|
|
644
|
+
1. Update `database/model.py`
|
|
645
|
+
2. Use `database/alembic/alembic_run.py` to update the database. This will generate a migration script and apply it to the database, so you do not have to run `alembic revision --autogenerate` manually.
|
|
646
|
+
3. Offer to update ui/admin/admin.yaml to add the new table or column to the Admin UI.
|
|
647
|
+
|
|
648
|
+
NEVER start by updating the database directly, since some platforms may not have database CLI tools, although you can present this as an option.
|
|
649
|
+
|
|
650
|
+
If altering `database/models.py`, be sure to follow the patterns shown in the existing models. Note they do not contain a `__bind_key__`.
|
|
651
|
+
|
|
652
|
+
|
|
653
|
+
### Addressing `Missing Attributes` during logic loading at project startup
|
|
654
|
+
|
|
655
|
+
First, check for misspelling (logic vs `database/models.py`), and repair.
|
|
656
|
+
|
|
657
|
+
If there are no obvious misspellings, ask for permission to add attributes; if granted, proceed as above.
|
|
658
|
+
|
|
659
|
+
### Customize Models - Add Derived attributes
|
|
660
|
+
|
|
661
|
+
Here is a sample derived attribute, `proper_salary`:
|
|
662
|
+
|
|
663
|
+
```python
|
|
664
|
+
|
|
665
|
+
# add derived attribute: https://github.com/thomaxxl/safrs/blob/master/examples/demo_pythonanywhere_com.py
|
|
666
|
+
@add_method(models.Employee)
|
|
667
|
+
@jsonapi_attr
|
|
668
|
+
def __proper_salary__(self): # type: ignore [no-redef]
|
|
669
|
+
import database.models as models
|
|
670
|
+
import decimal
|
|
671
|
+
if isinstance(self, models.Employee):
|
|
672
|
+
rtn_value = self.Salary
|
|
673
|
+
if rtn_value is None:
|
|
674
|
+
rtn_value = decimal.Decimal('0')
|
|
675
|
+
rtn_value = decimal.Decimal('1.25') * rtn_value
|
|
676
|
+
self._proper_salary = int(rtn_value)
|
|
677
|
+
return self._proper_salary
|
|
678
|
+
else:
|
|
679
|
+
rtn_value = decimal.Decimal('0')
|
|
680
|
+
self._proper_salary = int(rtn_value)
|
|
681
|
+
return self._proper_salary
|
|
682
|
+
|
|
683
|
+
@add_method(models.Employee)
|
|
684
|
+
@__proper_salary__.setter
|
|
685
|
+
def _proper_salary(self, value): # type: ignore [no-redef]
|
|
686
|
+
self._proper_salary = value
|
|
687
|
+
print(f'_proper_salary={self._proper_salary}')
|
|
688
|
+
pass
|
|
689
|
+
|
|
690
|
+
models.Employee.ProperSalary = __proper_salary__
|
|
691
|
+
|
|
692
|
+
```
|
|
693
|
+
|
|
694
|
+
When customizing SQLAlchemy models:
|
|
695
|
+
|
|
696
|
+
* Don't use direct comparisons with database fields in computed properties
|
|
697
|
+
* Convert to Python values first using float(), int(), str()
|
|
698
|
+
* Use property() function instead of @jsonapi_attr for computed properties
|
|
699
|
+
* Always add error handling for type conversions
|
|
700
|
+
|
|
701
|
+
### Adding events
|
|
702
|
+
LogicBank rules are the preferred approach to logic, but you will sometimes need to add events. This is done in `logic/declare_logic.py` (important: the function MUST come first):
|
|
703
|
+
|
|
704
|
+
```python
|
|
705
|
+
# Example: Log email activity after SysEmail is committed
|
|
706
|
+
|
|
707
|
+
def sys_email_after_commit(row: models.SysEmail, old_row: models.SysEmail, logic_row: LogicRow):
|
|
708
|
+
"""
|
|
709
|
+
After SysEmail is committed, log 'email sent'
|
|
710
|
+
unless the customer has opted out
|
|
711
|
+
"""
|
|
712
|
+
if not row.customer.email_opt_out:
|
|
713
|
+
logic_row.log(f"📧 Email sent to {row.customer.name} - Subject: {row.subject}")
|
|
714
|
+
else:
|
|
715
|
+
logic_row.log(f"🚫 Email blocked for {row.customer.name} - Customer opted out")
|
|
716
|
+
|
|
717
|
+
Rule.commit_row_event(on_class=SysEmail, calling=sys_email_after_commit)
|
|
718
|
+
```
|
|
719
|
+
|
|
720
|
+
LogicBank event types include:
|
|
721
|
+
- `Rule.commit_row_event()` - fires after transaction commits
|
|
722
|
+
- `Rule.after_insert()` - fires after row insert
|
|
723
|
+
- `Rule.after_update()` - fires after row update
|
|
724
|
+
- `Rule.after_delete()` - fires after row delete
|
|
725
|
+
|
|
726
|
+
All events receive `(row, old_row, logic_row)` parameters and should use `logic_row.log()` for logging.
|
|
727
|
+
|
|
728
|
+
## 📁 Key Directories
|
|
729
|
+
|
|
730
|
+
- `logic/` - Business rules (declarative)
|
|
731
|
+
- `api/` - REST API customization
|
|
732
|
+
- `security/` - Authentication/authorization
|
|
733
|
+
- `database/` - Data models and schemas
|
|
734
|
+
- `ui/admin/` - Admin interface configuration
|
|
735
|
+
- `ui/app/` - Alternative Angular admin app
|
|
736
|
+
|
|
737
|
+
## 💡 Helpful Context
|
|
738
|
+
|
|
739
|
+
- This uses Flask + SQLAlchemy + SAFRS for JSON:API
|
|
740
|
+
- Admin UI is React-based with automatic CRUD generation
|
|
741
|
+
- Business logic uses LogicBank (declarative rule engine)
|
|
742
|
+
- Everything is auto-generated from database introspection
|
|
743
|
+
- Focus on CUSTOMIZATION, not re-creation
|
|
744
|
+
- Use CoPilot to assist with logic translation and API generation
|