ApiLogicServer 15.0.52__py3-none-any.whl → 15.0.54__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/api_logic_server_info.yaml +3 -3
- api_logic_server_cli/create_from_model/api_logic_server_utils.py +6 -0
- api_logic_server_cli/prototypes/base/.github/.copilot-instructions.md +39 -3
- api_logic_server_cli/prototypes/base/database/alembic/alembic_run.py +98 -0
- api_logic_server_cli/prototypes/base/database/alembic/readme_alembic.md +36 -0
- api_logic_server_cli/prototypes/base/docs/training/admin_app_1_context.prompt.md +40 -0
- api_logic_server_cli/prototypes/base/integration/mcp/mcp_client_executor.py +2 -2
- api_logic_server_cli/prototypes/basic_demo/_config.yml +8 -0
- api_logic_server_cli/prototypes/basic_demo/_layouts/redirect.html +15 -0
- api_logic_server_cli/prototypes/basic_demo/docs/system-creation-vibe.md +161 -0
- api_logic_server_cli/prototypes/basic_demo/logic/declarative-vs-procedural-comparison.html +110 -0
- api_logic_server_cli/prototypes/basic_demo/logic/procedural/declarative-vs-procedural-comparison.md +295 -0
- api_logic_server_cli/prototypes/manager/samples/prompts/add_email.prompt +8 -0
- api_logic_server_cli/prototypes/manager/samples/prompts/elections.prompt +3 -0
- api_logic_server_cli/prototypes/manager/samples/prompts/emp_dept.prompt +4 -0
- api_logic_server_cli/prototypes/manager/samples/prompts/genai_demo.prompt +13 -0
- api_logic_server_cli/prototypes/manager/samples/readme_samples.md +3 -1
- api_logic_server_cli/prototypes/manager/system/genai/app_templates/app_learning/Admin-App-Resource-Learning-Prompt.md +1 -1
- api_logic_server_cli/prototypes/manager/system/genai/app_templates/react-admin-template/package.json +1 -0
- api_logic_server_cli/sqlacodegen_wrapper/sqlacodegen_wrapper.py +5 -2
- {apilogicserver-15.0.52.dist-info → apilogicserver-15.0.54.dist-info}/METADATA +1 -1
- {apilogicserver-15.0.52.dist-info → apilogicserver-15.0.54.dist-info}/RECORD +27 -20
- api_logic_server_cli/prototypes/base/.devcontainer-option/.copilot-instructions.md +0 -178
- api_logic_server_cli/prototypes/base/database/alembic/readme.md +0 -18
- api_logic_server_cli/prototypes/base/database/system/SAFRSBaseX.pyZ +0 -73
- api_logic_server_cli/prototypes/basic_demo/customizations/database/system/SAFRSBaseX.py +0 -139
- {apilogicserver-15.0.52.dist-info → apilogicserver-15.0.54.dist-info}/WHEEL +0 -0
- {apilogicserver-15.0.52.dist-info → apilogicserver-15.0.54.dist-info}/entry_points.txt +0 -0
- {apilogicserver-15.0.52.dist-info → apilogicserver-15.0.54.dist-info}/licenses/LICENSE +0 -0
- {apilogicserver-15.0.52.dist-info → apilogicserver-15.0.54.dist-info}/top_level.txt +0 -0
|
@@ -12,9 +12,10 @@ ApiLogicServer CLI: given a database url, create [and run] customizable ApiLogic
|
|
|
12
12
|
Called from api_logic_server_cli.py, by instantiating the ProjectRun object.
|
|
13
13
|
'''
|
|
14
14
|
|
|
15
|
-
__version__ = "15.00.
|
|
15
|
+
__version__ = "15.00.54" # last public release: 15.00.52 (15.00.12)
|
|
16
16
|
recent_changes = \
|
|
17
17
|
f'\n\nRecent Changes:\n' +\
|
|
18
|
+
"\t07/23/2024 - 15.00.54: system vibe support \n"\
|
|
18
19
|
"\t07/20/2024 - 15.00.52: Python 3.13 compatibility fixes - psycopg2→psycopg3, SQLAlchemy 2.0+, pkg_resources→importlib.metadata. mgr dbs \n"\
|
|
19
20
|
"\t07/17/2024 - 15.00.49: venv fix+, ext bldr * fix, copilot vibe tweaks - creation, mcp logic, basic_demo autonums \n"\
|
|
20
21
|
"\t07/10/2024 - 15.00.41: copilot vibe support for logic, UI, MCP, bug[98] \n"\
|
|
@@ -390,6 +391,7 @@ def create_project_and_overlay_prototypes(project: 'ProjectRun', msg: str) -> st
|
|
|
390
391
|
joinpath('prototypes/basic_demo')
|
|
391
392
|
recursive_overwrite(nw_dir, project.project_directory)
|
|
392
393
|
create_utils.copy_md(project = project, from_doc_file = "Sample-Basic-Demo.md")
|
|
394
|
+
create_utils.copy_md(project = project, from_doc_file = "Sample-Basic-Demo-Vibe.md", to_project_file="README-VIBE.md")
|
|
393
395
|
|
|
394
396
|
|
|
395
397
|
if project.db_url == "mysql+pymysql://root:p@localhost:3306/classicmodels":
|
|
@@ -1,3 +1,3 @@
|
|
|
1
|
-
last_created_date: July
|
|
2
|
-
last_created_project_name:
|
|
3
|
-
last_created_version: 15.00.
|
|
1
|
+
last_created_date: July 23, 2025 12:12:14
|
|
2
|
+
last_created_project_name: ../../../servers/basic_demo
|
|
3
|
+
last_created_version: 15.00.53
|
|
@@ -197,6 +197,12 @@ def copy_md(project, from_doc_file: str, to_project_file: str = "README.md"):
|
|
|
197
197
|
else:
|
|
198
198
|
each_line = each_line.replace('.md', '') # hmm... todo: find out why this exists
|
|
199
199
|
pass
|
|
200
|
+
if from_doc_file == 'Sample-Basic-Demo-Vibe.md' and 'title=' in each_line:
|
|
201
|
+
# extract the quoted text after 'title=' into title
|
|
202
|
+
match = re.search(r'title\s*=\s*["\']([^"\']+)["\']', each_line)
|
|
203
|
+
if match:
|
|
204
|
+
title = match.group(1)
|
|
205
|
+
readme_lines_md.append('**' + title + ':**\n')
|
|
200
206
|
readme_lines_md.append(each_line)
|
|
201
207
|
with open(str(to_file), "w") as readme_file:
|
|
202
208
|
readme_file.writelines(readme_lines_md)
|
|
@@ -37,11 +37,14 @@ python api_logic_server_run.py
|
|
|
37
37
|
Rule.sum(derive=Customer.Balance, as_sum_of=Order.AmountTotal)
|
|
38
38
|
Rule.constraint(validate=Customer, as_condition=lambda row: row.Balance <= row.CreditLimit)
|
|
39
39
|
```
|
|
40
|
+
|
|
41
|
+
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.
|
|
42
|
+
|
|
40
43
|
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
|
|
41
44
|
1. Provide the analysis (below) showing the 44X code reduction.
|
|
42
45
|
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.
|
|
43
46
|
|
|
44
|
-
Here's the natural language logic to provide to
|
|
47
|
+
Here's the natural language logic to provide to CoPilot:
|
|
45
48
|
|
|
46
49
|
```text
|
|
47
50
|
Use case: Check Credit
|
|
@@ -126,6 +129,8 @@ Then, `npm install` and `npm start`
|
|
|
126
129
|
|
|
127
130
|
Temporary restriction: security must be disabled.
|
|
128
131
|
|
|
132
|
+
**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.
|
|
133
|
+
|
|
129
134
|
Customize using CoPilot chat, with `docs/training`.
|
|
130
135
|
|
|
131
136
|
### Security - Role-Based Access Control
|
|
@@ -164,9 +169,13 @@ def my_endpoint():
|
|
|
164
169
|
return {"message": "Custom endpoint"}
|
|
165
170
|
```
|
|
166
171
|
|
|
167
|
-
### Customize Models - Add Attributes
|
|
172
|
+
### Customize Models - Add Tables, Attributes
|
|
173
|
+
|
|
174
|
+
Update `database/model.py`, and use `database/alembic` to update the database (highly impactful - request permission). This is *generally* preferrable to updating the database directly, since some platforms may not have database CLI tools.
|
|
168
175
|
|
|
169
|
-
|
|
176
|
+
If altering `database/models.py`, be sure to follow the patterns shown in the existing models. Note they not typically contain a `__bind_key__`.
|
|
177
|
+
|
|
178
|
+
```python
|
|
170
179
|
|
|
171
180
|
### Addressing `Missing Attributes` during logic loading at project startup
|
|
172
181
|
|
|
@@ -216,6 +225,33 @@ Convert to Python values first using float(), int(), str()
|
|
|
216
225
|
Use property() function instead of @jsonapi_attr for computed properties
|
|
217
226
|
Always add error handling for type conversions
|
|
218
227
|
|
|
228
|
+
### Adding events
|
|
229
|
+
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):
|
|
230
|
+
|
|
231
|
+
```python
|
|
232
|
+
# Example: Log email activity after SysEmail is committed
|
|
233
|
+
|
|
234
|
+
def sys_email_after_commit(row: models.SysEmail, old_row: models.SysEmail, logic_row: LogicRow):
|
|
235
|
+
"""
|
|
236
|
+
After SysEmail is committed, log 'email sent'
|
|
237
|
+
unless the customer has opted out
|
|
238
|
+
"""
|
|
239
|
+
if not row.customer.email_opt_out:
|
|
240
|
+
logic_row.log(f"📧 Email sent to {row.customer.name} - Subject: {row.subject}")
|
|
241
|
+
else:
|
|
242
|
+
logic_row.log(f"🚫 Email blocked for {row.customer.name} - Customer opted out")
|
|
243
|
+
|
|
244
|
+
Rule.commit_row_event(on_class=SysEmail, calling=sys_email_after_commit)
|
|
245
|
+
```
|
|
246
|
+
|
|
247
|
+
LogicBank event types include:
|
|
248
|
+
- `Rule.commit_row_event()` - fires after transaction commits
|
|
249
|
+
- `Rule.after_insert()` - fires after row insert
|
|
250
|
+
- `Rule.after_update()` - fires after row update
|
|
251
|
+
- `Rule.after_delete()` - fires after row delete
|
|
252
|
+
|
|
253
|
+
All events receive `(row, old_row, logic_row)` parameters and should use `logic_row.log()` for logging.
|
|
254
|
+
|
|
219
255
|
## 📁 Key Directories
|
|
220
256
|
|
|
221
257
|
- `logic/` - Business rules (declarative)
|
|
@@ -0,0 +1,98 @@
|
|
|
1
|
+
import os
|
|
2
|
+
import subprocess
|
|
3
|
+
import sys
|
|
4
|
+
|
|
5
|
+
'''
|
|
6
|
+
Pushes the current database/models.py to the database.
|
|
7
|
+
python database/alembic/alembic_run.py [--non-interactive]
|
|
8
|
+
'''
|
|
9
|
+
|
|
10
|
+
def prompt(msg, non_interactive=False):
|
|
11
|
+
if non_interactive:
|
|
12
|
+
print(f"{msg}")
|
|
13
|
+
print("Running in non-interactive mode...")
|
|
14
|
+
return
|
|
15
|
+
try:
|
|
16
|
+
input(f"{msg}\nPress Enter to continue or Ctrl+C to abort...")
|
|
17
|
+
except EOFError:
|
|
18
|
+
print("Running in non-interactive mode (no stdin available)...")
|
|
19
|
+
return
|
|
20
|
+
|
|
21
|
+
def run(cmd, env=None):
|
|
22
|
+
print(f"Running: {cmd}")
|
|
23
|
+
result = subprocess.run(cmd, shell=True, env=env)
|
|
24
|
+
if result.returncode != 0:
|
|
25
|
+
print(f"Command failed: {cmd}")
|
|
26
|
+
sys.exit(result.returncode)
|
|
27
|
+
|
|
28
|
+
def main():
|
|
29
|
+
# Check for non-interactive mode more safely
|
|
30
|
+
non_interactive = "--non-interactive" in sys.argv
|
|
31
|
+
if not non_interactive:
|
|
32
|
+
try:
|
|
33
|
+
non_interactive = not sys.stdin.isatty()
|
|
34
|
+
except:
|
|
35
|
+
# If we can't check stdin, assume non-interactive
|
|
36
|
+
non_interactive = True
|
|
37
|
+
|
|
38
|
+
orig_dir = os.getcwd()
|
|
39
|
+
# Change to the database directory (parent of alembic directory) where alembic.ini is located
|
|
40
|
+
db_dir = os.path.dirname(os.path.dirname(os.path.abspath(__file__)))
|
|
41
|
+
print(f"Changing directory to {db_dir}")
|
|
42
|
+
os.chdir(db_dir)
|
|
43
|
+
|
|
44
|
+
env = os.environ.copy()
|
|
45
|
+
env["APILOGICPROJECT_NO_FLASK"] = "True" # ~ export APILOGICPROJECT_NO_FLASK=True
|
|
46
|
+
|
|
47
|
+
print("\n\nThis script will update your database schema to match models.py using Alembic.")
|
|
48
|
+
print("Steps:")
|
|
49
|
+
print("1. Set APILOGICPROJECT_NO_FLASK=True -- eg, export APILOGICPROJECT_NO_FLASK=True")
|
|
50
|
+
print("2. Run: alembic upgrade head")
|
|
51
|
+
print("3. Run: alembic revision --autogenerate -m \"message\"")
|
|
52
|
+
prompt("Ready to proceed?", non_interactive)
|
|
53
|
+
|
|
54
|
+
run("alembic upgrade head", env=env)
|
|
55
|
+
print("Database schema updated to latest migration.")
|
|
56
|
+
|
|
57
|
+
prompt("Now, a new migration will be generated to match models.py.", non_interactive)
|
|
58
|
+
if non_interactive:
|
|
59
|
+
msg = "autogenerated"
|
|
60
|
+
else:
|
|
61
|
+
try:
|
|
62
|
+
msg = input("Enter a message for the migration (default: 'autogenerated'): ") or "autogenerated"
|
|
63
|
+
except EOFError:
|
|
64
|
+
msg = "autogenerated"
|
|
65
|
+
run(f'alembic revision --autogenerate -m "{msg}"', env=env)
|
|
66
|
+
|
|
67
|
+
# Find the latest migration file
|
|
68
|
+
versions_dir = os.path.join(db_dir, "alembic", "versions")
|
|
69
|
+
migration_files = sorted(
|
|
70
|
+
[f for f in os.listdir(versions_dir) if f.endswith(".py")],
|
|
71
|
+
key=lambda x: os.path.getmtime(os.path.join(versions_dir, x)),
|
|
72
|
+
reverse=True
|
|
73
|
+
)
|
|
74
|
+
if migration_files:
|
|
75
|
+
latest_file = os.path.join(versions_dir, migration_files[0])
|
|
76
|
+
with open(latest_file, "r") as f:
|
|
77
|
+
lines = f.readlines()
|
|
78
|
+
with open(latest_file, "w") as f:
|
|
79
|
+
for line in lines:
|
|
80
|
+
f.write(line)
|
|
81
|
+
if line.strip().startswith("def downgrade"):
|
|
82
|
+
f.write(" return\n")
|
|
83
|
+
break
|
|
84
|
+
else:
|
|
85
|
+
print("No migration file found.")
|
|
86
|
+
sys.exit(1)
|
|
87
|
+
|
|
88
|
+
# Apply the newly generated migration after modifying the migration file
|
|
89
|
+
prompt(f"Migration file generated: {latest_file}\nIt is recommended to review this migration file before proceeding.", non_interactive)
|
|
90
|
+
run("alembic upgrade head", env=env)
|
|
91
|
+
|
|
92
|
+
print("Migration file updated: downgrade will do nothing.")
|
|
93
|
+
print("Consider updating ui/admin/admin.yaml to reflect schema changes.")
|
|
94
|
+
os.chdir(orig_dir)
|
|
95
|
+
print("\nSuccess! Database schema and migrations are up to date.\n\n")
|
|
96
|
+
|
|
97
|
+
if __name__ == "__main__":
|
|
98
|
+
main()
|
|
@@ -0,0 +1,36 @@
|
|
|
1
|
+
You can push changes to `database/models.py' to your database automatically, or manually.
|
|
2
|
+
|
|
3
|
+
<br>
|
|
4
|
+
|
|
5
|
+
## Automatic
|
|
6
|
+
|
|
7
|
+
Use:
|
|
8
|
+
|
|
9
|
+
```bash
|
|
10
|
+
python database/alembic/alembic_run.py [--non-interactive]
|
|
11
|
+
```
|
|
12
|
+
|
|
13
|
+
<br>
|
|
14
|
+
|
|
15
|
+
## Manual
|
|
16
|
+
|
|
17
|
+
The diagram below illustrates a path for enacting changes to the data model, and using [Alembic](https://alembic.sqlalchemy.org/en/latest/index.html) to automate the database changes:
|
|
18
|
+
|
|
19
|
+
1. Update `database/models.py` (e.g., add columns, tables)
|
|
20
|
+
2. Use alembic to compute the revisions
|
|
21
|
+
```bash
|
|
22
|
+
cd database
|
|
23
|
+
export APILOGICPROJECT_NO_FLASK=True
|
|
24
|
+
alembic revision --autogenerate -m "Added Tables and Columns"
|
|
25
|
+
```
|
|
26
|
+
3. **Edit the revision file** to signify your understanding (see below)
|
|
27
|
+
4. Activate the change
|
|
28
|
+
```bash
|
|
29
|
+
alembic upgrade head
|
|
30
|
+
unset APILOGICPROJECT_NO_FLASK
|
|
31
|
+
```
|
|
32
|
+
|
|
33
|
+

|
|
34
|
+
|
|
35
|
+
|
|
36
|
+
To update your admin app, run `rebuild-from-model`. For more information, see [Database Design Changes](https://apilogicserver.github.io/Docs/Database-Changes/).
|
|
@@ -1,3 +1,43 @@
|
|
|
1
1
|
|
|
2
2
|
Generate a full React Admin application using the following instructions.
|
|
3
3
|
The result must be a runnable React app (`npm start`) that connects to the supplied JSON:API, with fully implemented components (no placeholders or empty files).
|
|
4
|
+
|
|
5
|
+
## Critical Data Access Provider Configuration
|
|
6
|
+
|
|
7
|
+
This project uses a **pre-configured JSON:API data provider** that was built when the project was created.
|
|
8
|
+
|
|
9
|
+
### Key Requirements:
|
|
10
|
+
|
|
11
|
+
1. **Data Provider**: Use the existing `jsonapiClient` from `./rav4-jsonapi-client/ra-jsonapi-client`
|
|
12
|
+
2. **Record Context**: For custom components (like cards), ALWAYS wrap with `<RecordContextProvider value={record}>`
|
|
13
|
+
3. **List Data Access**: Use `useListContext()` to get data and loading state
|
|
14
|
+
4. **Individual Records**: Use `useRecordContext()` to access record data within providers
|
|
15
|
+
5. **API Root**: The data provider connects to `conf.api_root` (typically `http://localhost:5656/api`)
|
|
16
|
+
|
|
17
|
+
### Example Pattern for Custom List Views:
|
|
18
|
+
```javascript
|
|
19
|
+
import { useListContext, RecordContextProvider, useRecordContext } from 'react-admin';
|
|
20
|
+
|
|
21
|
+
const CustomGrid = () => {
|
|
22
|
+
const { data, isLoading } = useListContext();
|
|
23
|
+
|
|
24
|
+
return (
|
|
25
|
+
<Grid container>
|
|
26
|
+
{data?.map(record => (
|
|
27
|
+
<Grid item key={record.id}>
|
|
28
|
+
<RecordContextProvider value={record}>
|
|
29
|
+
<CustomCard />
|
|
30
|
+
</RecordContextProvider>
|
|
31
|
+
</Grid>
|
|
32
|
+
))}
|
|
33
|
+
</Grid>
|
|
34
|
+
);
|
|
35
|
+
};
|
|
36
|
+
|
|
37
|
+
const CustomCard = () => {
|
|
38
|
+
const record = useRecordContext();
|
|
39
|
+
return <Card>{record.name}</Card>;
|
|
40
|
+
};
|
|
41
|
+
```
|
|
42
|
+
|
|
43
|
+
### CRITICAL: Do NOT create new data providers or modify the existing JSON:API client configuration. The project's data flow depends on the pre-built provider.
|
|
@@ -147,12 +147,12 @@ def query_llm_with_nl(learnings_and_schema: str, nl_query: str):
|
|
|
147
147
|
else:
|
|
148
148
|
# read integration/mcp/mcp_tool_context.json
|
|
149
149
|
tool_context_file_path = os.path.join(os.path.dirname(__file__), "../../integration/mcp/examples/mcp_tool_context_response_get.json")
|
|
150
|
-
if
|
|
150
|
+
if 'send email' in nl_query:
|
|
151
151
|
tool_context_file_path = os.path.join(os.path.dirname(__file__), "../../integration/mcp/examples/mcp_tool_context_response.json")
|
|
152
152
|
try:
|
|
153
153
|
with open(tool_context_file_path, "r") as tool_context_file:
|
|
154
154
|
tool_context_str = tool_context_file.read()
|
|
155
|
-
|
|
155
|
+
log.info(f"\n\n2c. Tool context from file {tool_context_file_path}:\n" + tool_context_str)
|
|
156
156
|
except FileNotFoundError:
|
|
157
157
|
raise ConstraintException(f"Tool context file not found at {tool_context_file_path}.")
|
|
158
158
|
|
|
@@ -0,0 +1,15 @@
|
|
|
1
|
+
<!DOCTYPE html>
|
|
2
|
+
<html>
|
|
3
|
+
<head>
|
|
4
|
+
<meta charset="utf-8" />
|
|
5
|
+
<meta http-equiv="refresh" content="1;url={{ page.redirect }}" />
|
|
6
|
+
<link rel="canonical" href="{{ page.redirect }}" />
|
|
7
|
+
<script type="text/javascript">
|
|
8
|
+
window.location.href = "{{ page.redirect }}"
|
|
9
|
+
</script>
|
|
10
|
+
<title>Page Redirection</title>
|
|
11
|
+
</head>
|
|
12
|
+
<body>
|
|
13
|
+
If you are not redirected automatically, follow <a href='{{ page.redirect }}'>this link</a>.
|
|
14
|
+
</body>
|
|
15
|
+
</html>
|
|
@@ -0,0 +1,161 @@
|
|
|
1
|
+
---
|
|
2
|
+
title: Vibe MCP / Microservice
|
|
3
|
+
version: 0.23 from docsite 7/11/2025
|
|
4
|
+
---
|
|
5
|
+
<style>
|
|
6
|
+
.md-typeset h1,
|
|
7
|
+
.md-content__button {
|
|
8
|
+
display: none;
|
|
9
|
+
}
|
|
10
|
+
</style>
|
|
11
|
+
|
|
12
|
+
<< Under Construction >>
|
|
13
|
+
|
|
14
|
+
# Vibe an MCP Microservice
|
|
15
|
+
|
|
16
|
+
See the Readme for detailed walk through.
|
|
17
|
+
|
|
18
|
+
Scenario: we have an existing database (customers, order, items and product), and we require:
|
|
19
|
+
|
|
20
|
+
* An MCP-enabled API, for integration
|
|
21
|
+
* MCP client support to send emails for overdue orders
|
|
22
|
+
* Business Logic to check credit by rolling up Items and Orders.
|
|
23
|
+
|
|
24
|
+
This is a record of how we created the system using CoPilot Chat (*Vibe*).
|
|
25
|
+
|
|
26
|
+
<br>
|
|
27
|
+
|
|
28
|
+
## Initialize CoPilot
|
|
29
|
+
|
|
30
|
+
```
|
|
31
|
+
Please find and read `.github/.copilot-instructions.md`.
|
|
32
|
+
```
|
|
33
|
+
|
|
34
|
+
<br>
|
|
35
|
+
|
|
36
|
+
## Create the System
|
|
37
|
+
|
|
38
|
+
```bash title="Create a project from an existing database"
|
|
39
|
+
# in the GenAI-Logic Manager:
|
|
40
|
+
Create a database project from samples/dbs/basic_demo.sqlite
|
|
41
|
+
```
|
|
42
|
+
|
|
43
|
+
<br>
|
|
44
|
+
|
|
45
|
+
## Verify the API and Admin App
|
|
46
|
+
|
|
47
|
+
The project should automatically open a new window in VSCode. Again, open CoPilot and bootstrap it with: <br>
|
|
48
|
+
|
|
49
|
+
```bash title="Initialize CoPilot"
|
|
50
|
+
Please find and read `.github/.copilot-instructions.md`**.
|
|
51
|
+
```
|
|
52
|
+
|
|
53
|
+
Verify it as follows:
|
|
54
|
+
|
|
55
|
+
* **Click F5** to start server, open app at http://localhost:5656/
|
|
56
|
+
* **Verify API:** filtering, sorting, pagination, optimistic locking and related data access - see the Swagger
|
|
57
|
+
* **Verify Admin App:** multi-page, multi-table, automatic joins, lookups, cascade add - collaboration-ready
|
|
58
|
+
|
|
59
|
+
<br>
|
|
60
|
+
|
|
61
|
+
## Create a Custom React App
|
|
62
|
+
|
|
63
|
+
**Create Start App**
|
|
64
|
+
```bash title="Create a custom react app"
|
|
65
|
+
Create a react app.
|
|
66
|
+
```
|
|
67
|
+
|
|
68
|
+
<br>
|
|
69
|
+
|
|
70
|
+
**Customize - add cards**
|
|
71
|
+
```txt title='Customize using Natural Language'
|
|
72
|
+
In the ui/react app, update the Product list to provide users an option to see results in a list,
|
|
73
|
+
or in cards.
|
|
74
|
+
```
|
|
75
|
+
<br>
|
|
76
|
+
|
|
77
|
+
todo - diagram
|
|
78
|
+
|
|
79
|
+
**Test: verify option for cards on `http://localhost:3000`**
|
|
80
|
+
|
|
81
|
+
<br>
|
|
82
|
+
|
|
83
|
+
## MCP Client - Overdue Orders
|
|
84
|
+
|
|
85
|
+
**Stop the Server**
|
|
86
|
+
|
|
87
|
+
<br>
|
|
88
|
+
|
|
89
|
+
**Create MCP Executor: process request - invokes the LLM to obtain a series of API calls to run, and runs them**
|
|
90
|
+
``` bash title="Create an MCP Client Executor"
|
|
91
|
+
Create the mcp client executor
|
|
92
|
+
```
|
|
93
|
+
<br>
|
|
94
|
+
|
|
95
|
+
**Add a Table to Track Sent Emails**
|
|
96
|
+
``` bash title="Add a Table to Track Sent Emails"
|
|
97
|
+
Create a table SysEmail in `database/db.sqlite` as a child of customer,
|
|
98
|
+
with columns id, message, subject, customer_id and CreatedOn.
|
|
99
|
+
```
|
|
100
|
+
Follow the suggestions to update the admin app.
|
|
101
|
+
|
|
102
|
+
<br>
|
|
103
|
+
|
|
104
|
+
**Create the email service stub using SysEmail as a Request Table**
|
|
105
|
+
``` bash title="Create the email service using SysEmail as a Request Table"
|
|
106
|
+
Add an after_flush event on SysEmail to produce a log message "email sent",
|
|
107
|
+
unless the customer has opted out.
|
|
108
|
+
```
|
|
109
|
+
|
|
110
|
+
<br>
|
|
111
|
+
|
|
112
|
+
**Business Logic to Honor Email Opt-out**
|
|
113
|
+
```bash title="Business Logic to Honor Email Opt-out"
|
|
114
|
+
Add an after_flush event on SysEmail to produce a log message "email sent",
|
|
115
|
+
unless the customer has opted out.
|
|
116
|
+
```
|
|
117
|
+
|
|
118
|
+
<br>
|
|
119
|
+
|
|
120
|
+
**Test: restart the server/admin app - Click SysMCP >> Create New, and enter:**
|
|
121
|
+
```text title="Test the MCP Client: Click SysMCP >> Create New, and enter"
|
|
122
|
+
List the orders date_shipped is null and CreatedOn before 2023-07-14,
|
|
123
|
+
and send a discount email (subject: 'Discount Offer') to the customer for each one.
|
|
124
|
+
```
|
|
125
|
+
|
|
126
|
+
<br>
|
|
127
|
+
todo - diagram
|
|
128
|
+
|
|
129
|
+
**Use the Admin App to Verify the first customer has an email**
|
|
130
|
+
|
|
131
|
+
<br>
|
|
132
|
+
|
|
133
|
+
## Check Credit Business Logic
|
|
134
|
+
|
|
135
|
+
**1. Stop the Server** (Red Stop button, or Shift-F5 -- see Appendix)
|
|
136
|
+
|
|
137
|
+
**2. Add Business Logic**
|
|
138
|
+
|
|
139
|
+
```bash title="Check Credit Logic (instead of 220 lines of code)"
|
|
140
|
+
Use case: Check Credit
|
|
141
|
+
1. The Customer's balance is less than the credit limit
|
|
142
|
+
2. The Customer's balance is the sum of the Order amount_total where date_shipped is null
|
|
143
|
+
3. The Order's amount_total is the sum of the Item amount
|
|
144
|
+
4. The Item amount is the quantity * unit_price
|
|
145
|
+
5. The Item unit_price is copied from the Product unit_price
|
|
146
|
+
|
|
147
|
+
Use case: App Integration
|
|
148
|
+
1. Send the Order to Kafka topic 'order_shipping' if the date_shipped is not None.
|
|
149
|
+
```
|
|
150
|
+
|
|
151
|
+
To test the logic:
|
|
152
|
+
|
|
153
|
+
**1. Use the Admin App to access the first order for `Customer Alice`**
|
|
154
|
+
|
|
155
|
+
**2. Edit its first item to a very high quantity**
|
|
156
|
+
|
|
157
|
+
todo - diagram
|
|
158
|
+
|
|
159
|
+
The update is properly rejected because it exceeds the credit limit. Observe the rules firing in the console log - see Logic In Action, below.
|
|
160
|
+
|
|
161
|
+
<br>
|
|
@@ -0,0 +1,110 @@
|
|
|
1
|
+
<!DOCTYPE html>
|
|
2
|
+
<html lang="en">
|
|
3
|
+
<head>
|
|
4
|
+
<meta charset="utf-8">
|
|
5
|
+
<title>Page Moved - Declarative vs Procedural Comparison</title>
|
|
6
|
+
<meta http-equiv="refresh" content="3; url=https://apilogicserver.github.io/basic_demo/logic/procedural/declarative-vs-procedural-comparison.html">
|
|
7
|
+
<link rel="canonical" href="https://apilogicserver.github.io/basic_demo/logic/procedural/declarative-vs-procedural-comparison.html">
|
|
8
|
+
<style>
|
|
9
|
+
body {
|
|
10
|
+
font-family: -apple-system, BlinkMacSystemFont, 'Segoe UI', Arial, sans-serif;
|
|
11
|
+
max-width: 600px;
|
|
12
|
+
margin: 50px auto;
|
|
13
|
+
padding: 20px;
|
|
14
|
+
line-height: 1.6;
|
|
15
|
+
}
|
|
16
|
+
.redirect-box {
|
|
17
|
+
border: 2px solid #007acc;
|
|
18
|
+
padding: 30px;
|
|
19
|
+
border-radius: 8px;
|
|
20
|
+
background: linear-gradient(135deg, #f8f9fa 0%, #e9ecef 100%);
|
|
21
|
+
box-shadow: 0 4px 6px rgba(0,0,0,0.1);
|
|
22
|
+
}
|
|
23
|
+
.countdown {
|
|
24
|
+
font-weight: bold;
|
|
25
|
+
color: #007acc;
|
|
26
|
+
font-size: 1.2em;
|
|
27
|
+
}
|
|
28
|
+
.manual-link {
|
|
29
|
+
display: inline-block;
|
|
30
|
+
background: #007acc;
|
|
31
|
+
color: white;
|
|
32
|
+
padding: 12px 24px;
|
|
33
|
+
text-decoration: none;
|
|
34
|
+
border-radius: 5px;
|
|
35
|
+
margin: 10px 0;
|
|
36
|
+
font-weight: bold;
|
|
37
|
+
}
|
|
38
|
+
.manual-link:hover {
|
|
39
|
+
background: #005c99;
|
|
40
|
+
}
|
|
41
|
+
h1 { color: #333; margin-top: 0; }
|
|
42
|
+
.progress-bar {
|
|
43
|
+
width: 100%;
|
|
44
|
+
height: 6px;
|
|
45
|
+
background: #ddd;
|
|
46
|
+
border-radius: 3px;
|
|
47
|
+
margin: 15px 0;
|
|
48
|
+
overflow: hidden;
|
|
49
|
+
}
|
|
50
|
+
.progress-fill {
|
|
51
|
+
height: 100%;
|
|
52
|
+
background: #007acc;
|
|
53
|
+
width: 100%;
|
|
54
|
+
transition: width 1s linear;
|
|
55
|
+
}
|
|
56
|
+
</style>
|
|
57
|
+
<script>
|
|
58
|
+
let seconds = 3;
|
|
59
|
+
function redirect() {
|
|
60
|
+
window.location.href = "https://apilogicserver.github.io/basic_demo/logic/procedural/declarative-vs-procedural-comparison.html";
|
|
61
|
+
}
|
|
62
|
+
function updateCountdown() {
|
|
63
|
+
const countdownElement = document.getElementById('countdown');
|
|
64
|
+
const progressElement = document.getElementById('progress-fill');
|
|
65
|
+
|
|
66
|
+
if (countdownElement) {
|
|
67
|
+
countdownElement.textContent = seconds;
|
|
68
|
+
}
|
|
69
|
+
if (progressElement) {
|
|
70
|
+
progressElement.style.width = ((3-seconds)/3 * 100) + '%';
|
|
71
|
+
}
|
|
72
|
+
|
|
73
|
+
if (seconds <= 0) {
|
|
74
|
+
redirect();
|
|
75
|
+
} else {
|
|
76
|
+
seconds--;
|
|
77
|
+
setTimeout(updateCountdown, 1000);
|
|
78
|
+
}
|
|
79
|
+
}
|
|
80
|
+
window.onload = function() {
|
|
81
|
+
updateCountdown();
|
|
82
|
+
// Fallback redirect in case JavaScript fails
|
|
83
|
+
setTimeout(redirect, 3100);
|
|
84
|
+
}
|
|
85
|
+
</script>
|
|
86
|
+
</head>
|
|
87
|
+
<body>
|
|
88
|
+
<div class="redirect-box">
|
|
89
|
+
<h1>📄 Page Moved</h1>
|
|
90
|
+
<p>The <strong>Declarative vs Procedural Logic Comparison</strong> has moved to a new location.</p>
|
|
91
|
+
|
|
92
|
+
<div class="progress-bar">
|
|
93
|
+
<div id="progress-fill" class="progress-fill" style="width: 0%;"></div>
|
|
94
|
+
</div>
|
|
95
|
+
|
|
96
|
+
<p>Redirecting automatically in <span id="countdown" class="countdown">3</span> seconds...</p>
|
|
97
|
+
|
|
98
|
+
<p><strong>If you are not redirected automatically:</strong></p>
|
|
99
|
+
<a href="https://apilogicserver.github.io/basic_demo/logic/procedural/declarative-vs-procedural-comparison.html" class="manual-link">
|
|
100
|
+
👉 Go to New Location
|
|
101
|
+
</a>
|
|
102
|
+
|
|
103
|
+
<hr style="margin: 25px 0; border: none; border-top: 1px solid #ddd;">
|
|
104
|
+
<p><small>
|
|
105
|
+
<strong>New URL:</strong><br>
|
|
106
|
+
<code>https://apilogicserver.github.io/basic_demo/logic/procedural/declarative-vs-procedural-comparison.html</code>
|
|
107
|
+
</small></p>
|
|
108
|
+
</div>
|
|
109
|
+
</body>
|
|
110
|
+
</html>
|