codymaster 4.6.0 → 5.2.0
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.
- package/CHANGELOG.md +74 -8
- package/README.md +192 -95
- package/dist/advisory-handoff.js +89 -0
- package/dist/advisory-report.js +105 -0
- package/dist/browse-server.js +251 -0
- package/dist/cli/command-registry.js +34 -0
- package/dist/cli/commands/agent.js +120 -0
- package/dist/cli/commands/bench.js +69 -0
- package/dist/cli/commands/brain.js +108 -0
- package/dist/cli/commands/dashboard.js +93 -0
- package/dist/cli/commands/design-studio.js +111 -0
- package/dist/cli/commands/distro.js +25 -0
- package/dist/cli/commands/engineering.js +596 -0
- package/dist/cli/commands/evolve.js +123 -0
- package/dist/cli/commands/mcp-serve.js +104 -0
- package/dist/cli/commands/project.js +324 -0
- package/dist/cli/commands/skill-chain.js +269 -0
- package/dist/cli/commands/system.js +89 -0
- package/dist/cli/commands/task.js +254 -0
- package/dist/cli/update-check.js +83 -0
- package/dist/cm-config.js +92 -0
- package/dist/cm-suggest.js +77 -0
- package/dist/codybench/judges/automated.js +31 -0
- package/dist/codybench/runners/claude-code.js +32 -0
- package/dist/codybench/suites/memory-retention.js +85 -0
- package/dist/codybench/suites/tdd-regression.js +35 -0
- package/dist/codybench/suites/token-efficiency.js +55 -0
- package/dist/codybench/types.js +2 -0
- package/dist/context-db.js +157 -0
- package/dist/continuity.js +2 -6
- package/dist/distro-validate.js +54 -0
- package/dist/execution-analyzer.js +138 -0
- package/dist/guardian-core.js +74 -0
- package/dist/index.js +36 -2759
- package/dist/indexer/skills-lib.js +533 -0
- package/dist/indexer/skills-map.js +1374 -0
- package/dist/indexer/skills.js +16 -0
- package/dist/learning-promoter.js +246 -0
- package/dist/mcp-context-server.js +289 -1
- package/dist/mcp-skills-tools.js +81 -0
- package/dist/retro-summary.js +70 -0
- package/dist/second-opinion-providers.js +79 -0
- package/dist/skill-chain.js +63 -1
- package/dist/skill-evolver.js +456 -0
- package/dist/skill-execution-cache.js +254 -0
- package/dist/smart-brain-router.js +184 -0
- package/dist/sprint-pipeline.js +228 -0
- package/dist/storage-backend.js +14 -67
- package/dist/token-budget.js +88 -0
- package/dist/utils/cli-utils.js +76 -0
- package/dist/utils/skill-utils.js +32 -0
- package/package.json +17 -7
- package/scripts/build-skills.mjs +51 -0
- package/scripts/gate-0-repo-hygiene.js +75 -0
- package/scripts/postinstall.js +34 -28
- package/scripts/security-scan.js +1 -1
- package/scripts/validate-skills.mjs +42 -0
- package/skills/CLAUDE.md +2 -7
- package/skills/_shared/helpers.md +2 -8
- package/skills/cm-ads-tracker/SKILL.md +3 -6
- package/skills/cm-browse/SKILL.md +34 -0
- package/skills/cm-conductor-worktrees/SKILL.md +28 -0
- package/skills/cm-content-factory/SKILL.md +1 -1
- package/skills/cm-content-factory/landing/docs/content/changelog.md +36 -0
- package/skills/cm-content-factory/landing/docs/content/deployment.md +46 -0
- package/skills/cm-content-factory/landing/docs/content/execution-flow.md +67 -0
- package/skills/cm-content-factory/landing/docs/content/memory-system.md +38 -0
- package/skills/cm-content-factory/landing/docs/content/openspace.md +27 -0
- package/skills/cm-content-factory/landing/docs/content/use-cases.md +26 -0
- package/skills/cm-content-factory/landing/docs/content/v5-intro.md +28 -0
- package/skills/cm-content-factory/landing/docs/index.html +240 -0
- package/skills/cm-content-factory/landing/index.html +100 -100
- package/skills/cm-content-factory/landing/script.js +42 -0
- package/skills/cm-content-factory/landing/translations.js +400 -400
- package/skills/cm-continuity/SKILL.md +32 -33
- package/skills/cm-design-studio/SKILL.md +34 -0
- package/skills/cm-ecosystem-roadmap/SKILL.md +15 -0
- package/skills/cm-engineering-meta/SKILL.md +73 -0
- package/skills/cm-growth-hacking/SKILL.md +1 -12
- package/skills/cm-guardian-runtime/SKILL.md +26 -0
- package/skills/cm-mcp-engineering/SKILL.md +22 -0
- package/skills/cm-notebooklm/SKILL.md +1 -17
- package/skills/cm-post-deploy-canary/SKILL.md +22 -0
- package/skills/cm-project-bootstrap/SKILL.md +11 -0
- package/skills/cm-qa-visual-cli/SKILL.md +22 -0
- package/skills/cm-retro-cli/SKILL.md +23 -0
- package/skills/cm-second-opinion-cli/SKILL.md +23 -0
- package/skills/cm-secret-shield/SKILL.md +2 -2
- package/skills/cm-security-gate/SKILL.md +1 -0
- package/skills/cm-skill-chain/SKILL.md +25 -4
- package/skills/cm-skill-evolution/SKILL.md +83 -0
- package/skills/cm-skill-health/SKILL.md +83 -0
- package/skills/cm-skill-index/SKILL.md +11 -3
- package/skills/cm-skill-search/SKILL.md +49 -0
- package/skills/cm-skill-share/SKILL.md +58 -0
- package/skills/cm-sprint-bus/SKILL.md +33 -0
- package/skills/cm-start/SKILL.md +0 -10
- package/skills/cm-tdd/SKILL.md +59 -72
- package/skills/profiles/README.md +21 -0
- package/skills/profiles/core.txt +23 -0
- package/skills/profiles/design.txt +6 -0
- package/skills/profiles/full.txt +62 -0
- package/skills/profiles/growth.txt +10 -0
- package/skills/profiles/knowledge.txt +7 -0
- package/install.sh +0 -901
- package/scripts/test-gemini.js +0 -13
- package/skills/cm-frappe-agent/SKILL.md +0 -134
- package/skills/cm-frappe-agent/agents/doctype-architect.md +0 -596
- package/skills/cm-frappe-agent/agents/erpnext-customizer.md +0 -643
- package/skills/cm-frappe-agent/agents/frappe-backend.md +0 -814
- package/skills/cm-frappe-agent/agents/frappe-custom-frontend.md +0 -557
- package/skills/cm-frappe-agent/agents/frappe-debugger.md +0 -625
- package/skills/cm-frappe-agent/agents/frappe-fixer.md +0 -275
- package/skills/cm-frappe-agent/agents/frappe-frontend.md +0 -660
- package/skills/cm-frappe-agent/agents/frappe-installer.md +0 -158
- package/skills/cm-frappe-agent/agents/frappe-performance.md +0 -307
- package/skills/cm-frappe-agent/agents/frappe-planner.md +0 -419
- package/skills/cm-frappe-agent/agents/frappe-remote-ops.md +0 -153
- package/skills/cm-frappe-agent/agents/github-workflow.md +0 -286
- package/skills/cm-frappe-agent/commands/frappe-app.md +0 -351
- package/skills/cm-frappe-agent/commands/frappe-backend.md +0 -162
- package/skills/cm-frappe-agent/commands/frappe-bench.md +0 -254
- package/skills/cm-frappe-agent/commands/frappe-debug.md +0 -263
- package/skills/cm-frappe-agent/commands/frappe-doctype-create.md +0 -272
- package/skills/cm-frappe-agent/commands/frappe-doctype-field.md +0 -310
- package/skills/cm-frappe-agent/commands/frappe-erpnext.md +0 -210
- package/skills/cm-frappe-agent/commands/frappe-fix.md +0 -59
- package/skills/cm-frappe-agent/commands/frappe-frontend.md +0 -210
- package/skills/cm-frappe-agent/commands/frappe-fullstack.md +0 -243
- package/skills/cm-frappe-agent/commands/frappe-github.md +0 -57
- package/skills/cm-frappe-agent/commands/frappe-install.md +0 -52
- package/skills/cm-frappe-agent/commands/frappe-plan.md +0 -442
- package/skills/cm-frappe-agent/commands/frappe-remote.md +0 -58
- package/skills/cm-frappe-agent/commands/frappe-test.md +0 -356
- package/skills/cm-frappe-agent/docs/README.md +0 -51
- package/skills/cm-frappe-agent/docs/agents-catalog.md +0 -113
- package/skills/cm-frappe-agent/docs/architecture.md +0 -149
- package/skills/cm-frappe-agent/docs/commands-catalog.md +0 -82
- package/skills/cm-frappe-agent/docs/resources-catalog.md +0 -66
- package/skills/cm-frappe-agent/docs/sitemap-urls.txt +0 -52
- package/skills/cm-frappe-agent/docs/sitemap.md +0 -81
- package/skills/cm-frappe-agent/docs/sop/user-guide.md +0 -178
- package/skills/cm-frappe-agent/docs/sop/vibe-coding-guide.md +0 -122
- package/skills/cm-frappe-agent/resources/7-layer-architecture.md +0 -985
- package/skills/cm-frappe-agent/resources/bench_commands.md +0 -73
- package/skills/cm-frappe-agent/resources/code-patterns-guide.md +0 -948
- package/skills/cm-frappe-agent/resources/common_pitfalls.md +0 -266
- package/skills/cm-frappe-agent/resources/doctype-registry.md +0 -158
- package/skills/cm-frappe-agent/resources/installation-guide.md +0 -289
- package/skills/cm-frappe-agent/resources/rest-api-patterns.md +0 -182
- package/skills/cm-frappe-agent/resources/scaffold_checklist.md +0 -82
- package/skills/cm-frappe-agent/resources/upgrade_patterns.md +0 -113
- package/skills/cm-frappe-agent/resources/web-form-patterns.md +0 -252
- package/skills/cm-frappe-agent/skills/bench-commands/SKILL.md +0 -621
- package/skills/cm-frappe-agent/skills/client-scripts/SKILL.md +0 -642
- package/skills/cm-frappe-agent/skills/doctype-patterns/SKILL.md +0 -576
- package/skills/cm-frappe-agent/skills/frappe-api/SKILL.md +0 -740
- package/skills/cm-frappe-agent/skills/remote-operations/SKILL.md +0 -47
- package/skills/cm-frappe-agent/skills/server-scripts/SKILL.md +0 -608
- package/skills/cm-frappe-agent/skills/web-forms/SKILL.md +0 -46
- package/skills/frappe-app-builder.zip +0 -0
|
@@ -1,182 +0,0 @@
|
|
|
1
|
-
# Frappe REST API Patterns
|
|
2
|
-
|
|
3
|
-
> Reference for interacting with remote Frappe/ERPNext sites via REST API.
|
|
4
|
-
|
|
5
|
-
## Authentication
|
|
6
|
-
|
|
7
|
-
All requests require API key header:
|
|
8
|
-
```
|
|
9
|
-
Authorization: token <api_key>:<api_secret>
|
|
10
|
-
```
|
|
11
|
-
|
|
12
|
-
### Test Authentication
|
|
13
|
-
```bash
|
|
14
|
-
curl -sS "https://{site}/api/method/frappe.auth.get_logged_user" \
|
|
15
|
-
-H "Authorization: token {key}:{secret}"
|
|
16
|
-
```
|
|
17
|
-
|
|
18
|
-
### Security Rules
|
|
19
|
-
- **NEVER** reveal API keys or secrets in output
|
|
20
|
-
- **NEVER** expose internal file paths or server configs
|
|
21
|
-
- **ALWAYS** confirm before destructive operations (DELETE, bulk updates)
|
|
22
|
-
- **NEVER** fabricate document data or fake API responses
|
|
23
|
-
- Store credentials in `.env` file, never in code
|
|
24
|
-
|
|
25
|
-
---
|
|
26
|
-
|
|
27
|
-
## CRUD Operations
|
|
28
|
-
|
|
29
|
-
### Get Single Document
|
|
30
|
-
```bash
|
|
31
|
-
curl -sS "https://{site}/api/resource/{DocType}/{name}" \
|
|
32
|
-
-H "Authorization: token {key}:{secret}"
|
|
33
|
-
```
|
|
34
|
-
|
|
35
|
-
### List Documents (with filters)
|
|
36
|
-
```bash
|
|
37
|
-
curl -sS "https://{site}/api/resource/{DocType}" \
|
|
38
|
-
-G --data-urlencode 'filters=[["field","=","value"]]' \
|
|
39
|
-
--data-urlencode 'fields=["name","field1","field2"]' \
|
|
40
|
-
--data-urlencode 'limit_page_length=20' \
|
|
41
|
-
-H "Authorization: token {key}:{secret}"
|
|
42
|
-
```
|
|
43
|
-
|
|
44
|
-
**Fallback for blocked fields** (e.g., `is_single`, `istable`):
|
|
45
|
-
```bash
|
|
46
|
-
curl -sS "https://{site}/api/method/frappe.client.get_list" \
|
|
47
|
-
-H "Authorization: token {key}:{secret}" \
|
|
48
|
-
-H "Content-Type: application/json" \
|
|
49
|
-
-d '{"doctype":"DocType","fields":["name","module"],"limit_page_length":0}'
|
|
50
|
-
```
|
|
51
|
-
|
|
52
|
-
### Create Document
|
|
53
|
-
```bash
|
|
54
|
-
curl -sS -X POST "https://{site}/api/resource/{DocType}" \
|
|
55
|
-
-H "Authorization: token {key}:{secret}" \
|
|
56
|
-
-H "Content-Type: application/json" \
|
|
57
|
-
-d '{"field1":"value1","field2":"value2"}'
|
|
58
|
-
```
|
|
59
|
-
|
|
60
|
-
### Update Document
|
|
61
|
-
```bash
|
|
62
|
-
curl -sS -X PUT "https://{site}/api/resource/{DocType}/{name}" \
|
|
63
|
-
-H "Authorization: token {key}:{secret}" \
|
|
64
|
-
-H "Content-Type: application/json" \
|
|
65
|
-
-d '{"field_to_update":"new_value"}'
|
|
66
|
-
```
|
|
67
|
-
|
|
68
|
-
### Delete Document
|
|
69
|
-
```bash
|
|
70
|
-
curl -sS -X DELETE "https://{site}/api/resource/{DocType}/{name}" \
|
|
71
|
-
-H "Authorization: token {key}:{secret}"
|
|
72
|
-
```
|
|
73
|
-
|
|
74
|
-
---
|
|
75
|
-
|
|
76
|
-
## RPC (Server Method Calls)
|
|
77
|
-
|
|
78
|
-
### Run Server Method
|
|
79
|
-
```bash
|
|
80
|
-
curl -sS "https://{site}/api/method/{dotted.method.path}" \
|
|
81
|
-
-H "Authorization: token {key}:{secret}" \
|
|
82
|
-
-H "Content-Type: application/json" \
|
|
83
|
-
-d '{"arg1":"value1"}'
|
|
84
|
-
```
|
|
85
|
-
|
|
86
|
-
### Get Value (Shortcut)
|
|
87
|
-
```bash
|
|
88
|
-
curl -sS "https://{site}/api/method/frappe.client.get_value" \
|
|
89
|
-
-H "Authorization: token {key}:{secret}" \
|
|
90
|
-
-H "Content-Type: application/json" \
|
|
91
|
-
-d '{"doctype":"Employee","filters":{"user_id":"user@example.com"},"fieldname":["name","employee_name"]}'
|
|
92
|
-
```
|
|
93
|
-
|
|
94
|
-
### Get Count
|
|
95
|
-
```bash
|
|
96
|
-
curl -sS "https://{site}/api/method/frappe.client.get_count" \
|
|
97
|
-
-H "Authorization: token {key}:{secret}" \
|
|
98
|
-
-H "Content-Type: application/json" \
|
|
99
|
-
-d '{"doctype":"Employee","filters":{"status":"Active"}}'
|
|
100
|
-
```
|
|
101
|
-
|
|
102
|
-
### Run Report
|
|
103
|
-
```bash
|
|
104
|
-
curl -sS "https://{site}/api/method/frappe.desk.query_report.run" \
|
|
105
|
-
-H "Authorization: token {key}:{secret}" \
|
|
106
|
-
-H "Content-Type: application/json" \
|
|
107
|
-
-d '{"report_name":"Employee Leave Balance","filters":{"company":"My Company"}}'
|
|
108
|
-
```
|
|
109
|
-
|
|
110
|
-
---
|
|
111
|
-
|
|
112
|
-
## Batch Operations
|
|
113
|
-
|
|
114
|
-
### Bulk Update (via RPC)
|
|
115
|
-
```bash
|
|
116
|
-
curl -sS -X POST "https://{site}/api/method/frappe.client.bulk_update" \
|
|
117
|
-
-H "Authorization: token {key}:{secret}" \
|
|
118
|
-
-H "Content-Type: application/json" \
|
|
119
|
-
-d '{
|
|
120
|
-
"docs": [
|
|
121
|
-
{"doctype":"ToDo","name":"TODO-001","status":"Closed"},
|
|
122
|
-
{"doctype":"ToDo","name":"TODO-002","status":"Closed"}
|
|
123
|
-
]
|
|
124
|
-
}'
|
|
125
|
-
```
|
|
126
|
-
|
|
127
|
-
### File Upload
|
|
128
|
-
```bash
|
|
129
|
-
curl -sS -X POST "https://{site}/api/method/upload_file" \
|
|
130
|
-
-H "Authorization: token {key}:{secret}" \
|
|
131
|
-
-F "file=@/path/to/file.pdf" \
|
|
132
|
-
-F "doctype=File" \
|
|
133
|
-
-F "docname=Home"
|
|
134
|
-
```
|
|
135
|
-
|
|
136
|
-
---
|
|
137
|
-
|
|
138
|
-
## Web Form Operations
|
|
139
|
-
|
|
140
|
-
### Get Web Form Config
|
|
141
|
-
```bash
|
|
142
|
-
curl -sS "https://{site}/api/resource/Web%20Form" \
|
|
143
|
-
-G --data-urlencode 'filters=[["route","=","my-form"]]' \
|
|
144
|
-
--data-urlencode 'fields=["name","title","custom_css","client_script"]' \
|
|
145
|
-
-H "Authorization: token {key}:{secret}"
|
|
146
|
-
```
|
|
147
|
-
|
|
148
|
-
### Update Web Form
|
|
149
|
-
```bash
|
|
150
|
-
curl -sS -X PUT "https://{site}/api/resource/Web%20Form/{name}" \
|
|
151
|
-
-H "Authorization: token {key}:{secret}" \
|
|
152
|
-
-H "Content-Type: application/json" \
|
|
153
|
-
-d '{"custom_css":"...","client_script":"..."}'
|
|
154
|
-
```
|
|
155
|
-
|
|
156
|
-
---
|
|
157
|
-
|
|
158
|
-
## Response Format
|
|
159
|
-
|
|
160
|
-
| Type | Format |
|
|
161
|
-
|------|--------|
|
|
162
|
-
| Success | `{"data": {...}}` or `{"message": ...}` |
|
|
163
|
-
| Error | `{"exception": "...", "exc_type": "...", "exc": "..."}` |
|
|
164
|
-
|
|
165
|
-
---
|
|
166
|
-
|
|
167
|
-
## Error Handling Patterns
|
|
168
|
-
|
|
169
|
-
| Error | Cause | Solution |
|
|
170
|
-
|-------|-------|----------|
|
|
171
|
-
| `DataError: Field not allowed` | Blocked field in resource API | Use `frappe.client.get_list` RPC fallback |
|
|
172
|
-
| `403 Forbidden` | Insufficient API key permissions | Check User > API Access settings |
|
|
173
|
-
| `404 Not Found` | DocType/document doesn't exist | Verify name spelling, check module |
|
|
174
|
-
| `417 Expectation Failed` | Validation error on create/update | Check required fields, valid values |
|
|
175
|
-
| `409 Conflict` | Duplicate name or concurrent edit | Use unique naming, add `If-Match` header |
|
|
176
|
-
|
|
177
|
-
## URL Encoding Tips
|
|
178
|
-
|
|
179
|
-
- Use `--data-urlencode` for filters/fields with special characters
|
|
180
|
-
- DocType names with Unicode: URL-encode the name (e.g., `Web%20Form`)
|
|
181
|
-
- Use `-G` flag with `--data-urlencode` for GET requests with encoded params
|
|
182
|
-
- Always use `jq` for JSON parsing: `| jq '.data'`
|
|
@@ -1,82 +0,0 @@
|
|
|
1
|
-
# Frappe App Scaffold Checklist
|
|
2
|
-
|
|
3
|
-
Use this checklist when creating a new Frappe custom app from scratch.
|
|
4
|
-
|
|
5
|
-
## Phase 1: Foundation
|
|
6
|
-
|
|
7
|
-
- [ ] `bench new-app my_app` — scaffold the app
|
|
8
|
-
- [ ] Create folder structure:
|
|
9
|
-
```
|
|
10
|
-
mkdir -p my_app/{engines,api,tasks,setup,tests,scripts,fixtures}
|
|
11
|
-
mkdir -p my_app/public/js
|
|
12
|
-
touch my_app/{engines,api,tasks,setup,tests}/__init__.py
|
|
13
|
-
```
|
|
14
|
-
- [ ] `bench --site mysite install-app my_app`
|
|
15
|
-
- [ ] `bench --site mysite set-config developer_mode 1`
|
|
16
|
-
|
|
17
|
-
## Phase 2: Data Model
|
|
18
|
-
|
|
19
|
-
- [ ] Design DocTypes on paper first (fields, links, workflows)
|
|
20
|
-
- [ ] Identify which DocTypes are Submittable (need approval flow)
|
|
21
|
-
- [ ] Identify Master DocTypes (config, types, rules)
|
|
22
|
-
- [ ] Create DocTypes via Frappe UI or JSON files
|
|
23
|
-
- [ ] Add `module` property to all DocTypes
|
|
24
|
-
|
|
25
|
-
## Phase 3: Hooks & Setup
|
|
26
|
-
|
|
27
|
-
- [ ] Configure `hooks.py`:
|
|
28
|
-
- [ ] `app_name`, `app_title`, `required_apps`
|
|
29
|
-
- [ ] `app_include_js` for shared client JS
|
|
30
|
-
- [ ] `after_install`, `after_migrate`
|
|
31
|
-
- [ ] `doc_events` for submit/cancel/insert hooks
|
|
32
|
-
- [ ] `fixtures` for Roles, Custom Fields, Workflows
|
|
33
|
-
- [ ] `scheduler_events` for daily/weekly/monthly tasks
|
|
34
|
-
- [ ] `permission_query_conditions` for row-level security
|
|
35
|
-
- [ ] Write `setup/install.py` (idempotent role/field/state creation)
|
|
36
|
-
|
|
37
|
-
## Phase 4: Business Logic
|
|
38
|
-
|
|
39
|
-
- [ ] Create `engines/` with pure-logic functions (no Frappe imports)
|
|
40
|
-
- [ ] Create config cascade functions (with Frappe DB)
|
|
41
|
-
- [ ] Create main pipeline function (aggregates everything)
|
|
42
|
-
- [ ] Write doc-event hook functions (on_submit, on_cancel, after_insert)
|
|
43
|
-
|
|
44
|
-
## Phase 5: APIs
|
|
45
|
-
|
|
46
|
-
- [ ] Create external API (`api/external.py`) for webhook/integration
|
|
47
|
-
- [ ] Create internal API (`api/internal.py`) for UI-facing calls
|
|
48
|
-
- [ ] Add permission checks (`frappe.has_permission()`)
|
|
49
|
-
- [ ] Add permission query functions for row-level security
|
|
50
|
-
|
|
51
|
-
## Phase 6: Scheduler Tasks
|
|
52
|
-
|
|
53
|
-
- [ ] `tasks/daily.py` — aggregation, reminders
|
|
54
|
-
- [ ] `tasks/weekly.py` — weekly calculations
|
|
55
|
-
- [ ] `tasks/monthly.py` — monthly calculations, benefit checks
|
|
56
|
-
- [ ] Register all in `hooks.py` → `scheduler_events`
|
|
57
|
-
|
|
58
|
-
## Phase 7: Client Side
|
|
59
|
-
|
|
60
|
-
- [ ] Create `public/js/my_app.js` with shared utilities
|
|
61
|
-
- [ ] Write DocType `.js` files (refresh, field triggers, custom buttons)
|
|
62
|
-
- [ ] Add list view settings with workflow color indicators
|
|
63
|
-
|
|
64
|
-
## Phase 8: Reports
|
|
65
|
-
|
|
66
|
-
- [ ] Create Script Reports with `execute()`, `get_columns()`, `get_data()`
|
|
67
|
-
- [ ] Add charts via `get_chart()` (bar, line, pie)
|
|
68
|
-
- [ ] Add summary cards via `get_report_summary()`
|
|
69
|
-
- [ ] Create `.js` filter definitions
|
|
70
|
-
|
|
71
|
-
## Phase 9: Testing
|
|
72
|
-
|
|
73
|
-
- [ ] Write standalone tests for pure-logic functions
|
|
74
|
-
- [ ] Run: `python -m pytest my_app/tests/ -v`
|
|
75
|
-
|
|
76
|
-
## Phase 10: Deploy
|
|
77
|
-
|
|
78
|
-
- [ ] `bench --site mysite migrate`
|
|
79
|
-
- [ ] `bench build --app my_app`
|
|
80
|
-
- [ ] Export fixtures: `bench --site mysite export-fixtures --app my_app`
|
|
81
|
-
- [ ] Test on staging before production
|
|
82
|
-
- [ ] Push to git
|
|
@@ -1,113 +0,0 @@
|
|
|
1
|
-
# Frappe App Upgrade & Migration Patterns
|
|
2
|
-
|
|
3
|
-
## Adding New DocTypes to Existing App
|
|
4
|
-
|
|
5
|
-
1. Create DocType JSON via Frappe UI
|
|
6
|
-
2. Write controller (`.py`) following existing patterns
|
|
7
|
-
3. Add doc_events in `hooks.py` if needed
|
|
8
|
-
4. Add to fixtures list if it has workflow
|
|
9
|
-
5. Update `setup/install.py` if new roles/states needed
|
|
10
|
-
6. `bench --site mysite migrate && bench build --app my_app`
|
|
11
|
-
|
|
12
|
-
## Adding Fields to Existing DocType
|
|
13
|
-
|
|
14
|
-
```bash
|
|
15
|
-
# 1. Modify DocType JSON (via UI or directly)
|
|
16
|
-
# 2. Run migration
|
|
17
|
-
bench --site mysite migrate
|
|
18
|
-
|
|
19
|
-
# 3. If adding Custom Fields to core DocTypes (Employee, etc.)
|
|
20
|
-
# Add to setup/install.py → _create_custom_fields()
|
|
21
|
-
# Add to hooks.py → fixtures → Custom Field filter
|
|
22
|
-
```
|
|
23
|
-
|
|
24
|
-
## Upgrading Engine Logic
|
|
25
|
-
|
|
26
|
-
1. Modify pure-logic functions in `engines/`
|
|
27
|
-
2. Update tests to cover new behavior
|
|
28
|
-
3. Run `python -m pytest my_app/tests/ -v`
|
|
29
|
-
4. No migration needed — pure Python changes
|
|
30
|
-
|
|
31
|
-
## Adding New API Endpoint
|
|
32
|
-
|
|
33
|
-
```python
|
|
34
|
-
# 1. Add function in api/my_module.py
|
|
35
|
-
@frappe.whitelist()
|
|
36
|
-
def new_endpoint(param1, param2):
|
|
37
|
-
if not frappe.has_permission("My DocType", "read"):
|
|
38
|
-
frappe.throw(_("Permission denied"), frappe.PermissionError)
|
|
39
|
-
return engine.process(param1, param2)
|
|
40
|
-
```
|
|
41
|
-
|
|
42
|
-
No hooks.py changes needed — Frappe auto-discovers whitelisted methods.
|
|
43
|
-
|
|
44
|
-
## Adding New Scheduler Task
|
|
45
|
-
|
|
46
|
-
```python
|
|
47
|
-
# 1. Add function in tasks/daily.py (or new file)
|
|
48
|
-
def my_new_task():
|
|
49
|
-
# ... logic
|
|
50
|
-
frappe.db.commit()
|
|
51
|
-
|
|
52
|
-
# 2. Register in hooks.py
|
|
53
|
-
scheduler_events = {
|
|
54
|
-
"daily": [
|
|
55
|
-
"my_app.tasks.daily.my_new_task", # Add here
|
|
56
|
-
],
|
|
57
|
-
}
|
|
58
|
-
```
|
|
59
|
-
|
|
60
|
-
## Changing Workflow States
|
|
61
|
-
|
|
62
|
-
⚠️ **CONFIRM before doing this — affects existing records!**
|
|
63
|
-
|
|
64
|
-
1. Update Workflow JSON
|
|
65
|
-
2. Add new states to `setup/install.py` → `_create_workflow_states()`
|
|
66
|
-
3. Add new states to `hooks.py` → fixtures → Workflow State filter
|
|
67
|
-
4. `bench --site mysite migrate`
|
|
68
|
-
5. Check existing records are not in broken state
|
|
69
|
-
|
|
70
|
-
## Adding New Reports
|
|
71
|
-
|
|
72
|
-
```bash
|
|
73
|
-
# 1. Create report folder
|
|
74
|
-
mkdir -p my_app/my_app/report/new_report/
|
|
75
|
-
touch my_app/my_app/report/new_report/__init__.py
|
|
76
|
-
|
|
77
|
-
# 2. Create report files
|
|
78
|
-
# new_report.py — execute(), get_columns(), get_data(), get_chart()
|
|
79
|
-
# new_report.js — filters definition
|
|
80
|
-
# new_report.json — report metadata
|
|
81
|
-
|
|
82
|
-
# 3. Build
|
|
83
|
-
bench build --app my_app
|
|
84
|
-
```
|
|
85
|
-
|
|
86
|
-
## Data Migration Script
|
|
87
|
-
|
|
88
|
-
```python
|
|
89
|
-
"""
|
|
90
|
-
scripts/migrate_data.py
|
|
91
|
-
Run: bench --site mysite execute my_app.scripts.migrate_data.run
|
|
92
|
-
|
|
93
|
-
⚠️ ALWAYS backup before running migration scripts!
|
|
94
|
-
"""
|
|
95
|
-
import frappe
|
|
96
|
-
|
|
97
|
-
def run():
|
|
98
|
-
frappe.logger("my_app").info("Starting data migration...")
|
|
99
|
-
|
|
100
|
-
# Process in batches of 100
|
|
101
|
-
records = frappe.get_all("Old DocType", fields=["*"], limit=100)
|
|
102
|
-
for rec in records:
|
|
103
|
-
try:
|
|
104
|
-
frappe.get_doc({
|
|
105
|
-
"doctype": "New DocType",
|
|
106
|
-
"field1": rec.old_field,
|
|
107
|
-
}).insert(ignore_permissions=True)
|
|
108
|
-
except Exception as exc:
|
|
109
|
-
frappe.log_error(str(exc), "Migration error")
|
|
110
|
-
|
|
111
|
-
frappe.db.commit()
|
|
112
|
-
frappe.logger("my_app").info("Migration complete")
|
|
113
|
-
```
|
|
@@ -1,252 +0,0 @@
|
|
|
1
|
-
# Web Form Development Patterns
|
|
2
|
-
|
|
3
|
-
> Patterns for building Frappe Web Forms (portal pages) — client scripts, CSS, and gotchas.
|
|
4
|
-
|
|
5
|
-
---
|
|
6
|
-
|
|
7
|
-
## Key Differences: Web Form vs Desk Form
|
|
8
|
-
|
|
9
|
-
| Aspect | Desk Form (`.js`) | Web Form (Client Script) |
|
|
10
|
-
|--------|-------------------|--------------------------|
|
|
11
|
-
| API | `frappe.ui.form.Form` | `frappe.web_form` (extends FieldGroup) |
|
|
12
|
-
| Set values | `frm.set_value()` | `frappe.web_form.set_values({...})` ← **PLURAL** |
|
|
13
|
-
| Ready event | `refresh(frm)` | `frappe.ready(function() { ... })` |
|
|
14
|
-
| Context | `cur_frm` | `frappe.web_form` |
|
|
15
|
-
| Field access | `frm.fields_dict.fieldname` | `frappe.web_form.fields_dict.fieldname` |
|
|
16
|
-
|
|
17
|
-
> [!WARNING]
|
|
18
|
-
> The most common mistake: using `set_value()` (singular) instead of `set_values()` (plural) in Web Forms. WebForm extends FieldGroup, NOT Form.
|
|
19
|
-
|
|
20
|
-
---
|
|
21
|
-
|
|
22
|
-
## Client Script Patterns
|
|
23
|
-
|
|
24
|
-
### Basic Structure
|
|
25
|
-
```javascript
|
|
26
|
-
frappe.ready(function() {
|
|
27
|
-
// All Web Form code goes inside frappe.ready()
|
|
28
|
-
// This ensures the form is fully loaded before running
|
|
29
|
-
|
|
30
|
-
// Set initial values
|
|
31
|
-
frappe.web_form.set_values({
|
|
32
|
-
date: frappe.datetime.get_today(),
|
|
33
|
-
status: 'Open'
|
|
34
|
-
});
|
|
35
|
-
|
|
36
|
-
// Listen for field changes
|
|
37
|
-
frappe.web_form.on('change', function(field, value) {
|
|
38
|
-
if (field === 'category') {
|
|
39
|
-
handle_category_change(value);
|
|
40
|
-
}
|
|
41
|
-
});
|
|
42
|
-
});
|
|
43
|
-
```
|
|
44
|
-
|
|
45
|
-
### Set Read-Only Fields
|
|
46
|
-
```javascript
|
|
47
|
-
frappe.ready(function() {
|
|
48
|
-
// Read-only fields CAN still be set via set_values()
|
|
49
|
-
frappe.web_form.set_values({
|
|
50
|
-
employee_name: frappe.session.user_fullname,
|
|
51
|
-
submit_date: frappe.datetime.get_today()
|
|
52
|
-
});
|
|
53
|
-
});
|
|
54
|
-
```
|
|
55
|
-
|
|
56
|
-
### Conditional Field Visibility
|
|
57
|
-
```javascript
|
|
58
|
-
frappe.ready(function() {
|
|
59
|
-
frappe.web_form.on('change', function(field, value) {
|
|
60
|
-
if (field === 'request_type') {
|
|
61
|
-
// Show/hide fields based on selection
|
|
62
|
-
let show_urgency = (value === 'Emergency');
|
|
63
|
-
frappe.web_form.fields_dict.urgency_level.$wrapper.toggle(show_urgency);
|
|
64
|
-
frappe.web_form.fields_dict.emergency_contact.$wrapper.toggle(show_urgency);
|
|
65
|
-
}
|
|
66
|
-
});
|
|
67
|
-
});
|
|
68
|
-
```
|
|
69
|
-
|
|
70
|
-
### Custom Validation Before Submit
|
|
71
|
-
```javascript
|
|
72
|
-
frappe.ready(function() {
|
|
73
|
-
frappe.web_form.validate = function() {
|
|
74
|
-
let values = frappe.web_form.get_values();
|
|
75
|
-
|
|
76
|
-
if (!values.email || !values.email.includes('@')) {
|
|
77
|
-
frappe.msgprint(__('Please enter a valid email address'));
|
|
78
|
-
return false; // Prevents submission
|
|
79
|
-
}
|
|
80
|
-
|
|
81
|
-
if (values.start_date > values.end_date) {
|
|
82
|
-
frappe.msgprint(__('End date must be after start date'));
|
|
83
|
-
return false;
|
|
84
|
-
}
|
|
85
|
-
|
|
86
|
-
return true; // Allow submission
|
|
87
|
-
};
|
|
88
|
-
});
|
|
89
|
-
```
|
|
90
|
-
|
|
91
|
-
### Call Server Methods
|
|
92
|
-
```javascript
|
|
93
|
-
frappe.ready(function() {
|
|
94
|
-
frappe.web_form.on('change', function(field, value) {
|
|
95
|
-
if (field === 'employee_id') {
|
|
96
|
-
frappe.call({
|
|
97
|
-
method: 'my_app.api.get_employee_details',
|
|
98
|
-
args: { employee_id: value },
|
|
99
|
-
callback: function(r) {
|
|
100
|
-
if (r.message) {
|
|
101
|
-
frappe.web_form.set_values({
|
|
102
|
-
employee_name: r.message.employee_name,
|
|
103
|
-
department: r.message.department
|
|
104
|
-
});
|
|
105
|
-
}
|
|
106
|
-
}
|
|
107
|
-
});
|
|
108
|
-
}
|
|
109
|
-
});
|
|
110
|
-
});
|
|
111
|
-
```
|
|
112
|
-
|
|
113
|
-
### After Load / After Save
|
|
114
|
-
```javascript
|
|
115
|
-
frappe.ready(function() {
|
|
116
|
-
// After form loads
|
|
117
|
-
frappe.web_form.after_load = function() {
|
|
118
|
-
console.log('Form loaded with data:', frappe.web_form.doc);
|
|
119
|
-
};
|
|
120
|
-
|
|
121
|
-
// After form saves
|
|
122
|
-
frappe.web_form.after_save = function() {
|
|
123
|
-
frappe.msgprint(__('Thank you! Your submission has been recorded.'));
|
|
124
|
-
};
|
|
125
|
-
});
|
|
126
|
-
```
|
|
127
|
-
|
|
128
|
-
---
|
|
129
|
-
|
|
130
|
-
## Custom CSS Patterns
|
|
131
|
-
|
|
132
|
-
### Professional Form Styling
|
|
133
|
-
```css
|
|
134
|
-
/* Card-style form container */
|
|
135
|
-
.web-form-container {
|
|
136
|
-
max-width: 800px;
|
|
137
|
-
margin: 0 auto;
|
|
138
|
-
padding: 2rem;
|
|
139
|
-
}
|
|
140
|
-
|
|
141
|
-
/* Section headings */
|
|
142
|
-
.web-form-container .section-head {
|
|
143
|
-
font-size: 1.25rem;
|
|
144
|
-
font-weight: 600;
|
|
145
|
-
color: var(--text-color);
|
|
146
|
-
border-bottom: 2px solid var(--primary);
|
|
147
|
-
padding-bottom: 0.5rem;
|
|
148
|
-
margin-bottom: 1.5rem;
|
|
149
|
-
}
|
|
150
|
-
|
|
151
|
-
/* Success message styling */
|
|
152
|
-
.web-form-container .success-page {
|
|
153
|
-
text-align: center;
|
|
154
|
-
padding: 3rem 1rem;
|
|
155
|
-
}
|
|
156
|
-
|
|
157
|
-
/* Hide specific fields */
|
|
158
|
-
.frappe-control[data-fieldname="internal_notes"] {
|
|
159
|
-
display: none;
|
|
160
|
-
}
|
|
161
|
-
|
|
162
|
-
/* Custom button styling */
|
|
163
|
-
.web-form-container .btn-primary-dark {
|
|
164
|
-
background: var(--primary);
|
|
165
|
-
border: none;
|
|
166
|
-
padding: 0.75rem 2rem;
|
|
167
|
-
font-size: 1rem;
|
|
168
|
-
border-radius: 8px;
|
|
169
|
-
}
|
|
170
|
-
```
|
|
171
|
-
|
|
172
|
-
### Responsive Layout
|
|
173
|
-
```css
|
|
174
|
-
@media (max-width: 768px) {
|
|
175
|
-
.web-form-container {
|
|
176
|
-
padding: 1rem;
|
|
177
|
-
}
|
|
178
|
-
|
|
179
|
-
.web-form-container .form-group {
|
|
180
|
-
margin-bottom: 1rem;
|
|
181
|
-
}
|
|
182
|
-
}
|
|
183
|
-
```
|
|
184
|
-
|
|
185
|
-
---
|
|
186
|
-
|
|
187
|
-
## Common Gotchas
|
|
188
|
-
|
|
189
|
-
### 1. Timing Issues
|
|
190
|
-
```javascript
|
|
191
|
-
// ❌ WRONG: Code runs before form is ready
|
|
192
|
-
frappe.web_form.set_values({ field: 'value' });
|
|
193
|
-
|
|
194
|
-
// ✅ CORRECT: Always wrap in frappe.ready()
|
|
195
|
-
frappe.ready(function() {
|
|
196
|
-
frappe.web_form.set_values({ field: 'value' });
|
|
197
|
-
});
|
|
198
|
-
```
|
|
199
|
-
|
|
200
|
-
### 2. set_value vs set_values
|
|
201
|
-
```javascript
|
|
202
|
-
// ❌ WRONG: set_value doesn't exist on WebForm
|
|
203
|
-
frappe.web_form.set_value('field', 'value');
|
|
204
|
-
|
|
205
|
-
// ✅ CORRECT: Use set_values (plural) with object
|
|
206
|
-
frappe.web_form.set_values({ field: 'value' });
|
|
207
|
-
```
|
|
208
|
-
|
|
209
|
-
### 3. Guest Access
|
|
210
|
-
```javascript
|
|
211
|
-
// For forms allowing guest submissions, check login state:
|
|
212
|
-
frappe.ready(function() {
|
|
213
|
-
if (frappe.session.user === 'Guest') {
|
|
214
|
-
// Show limited fields
|
|
215
|
-
frappe.web_form.fields_dict.internal_field.$wrapper.hide();
|
|
216
|
-
}
|
|
217
|
-
});
|
|
218
|
-
```
|
|
219
|
-
|
|
220
|
-
### 4. File Uploads in Web Forms
|
|
221
|
-
```javascript
|
|
222
|
-
// Web Forms handle file uploads differently
|
|
223
|
-
// Use the Attach field type in DocType, Web Form will auto-create upload widget
|
|
224
|
-
// For custom upload handling:
|
|
225
|
-
frappe.ready(function() {
|
|
226
|
-
frappe.web_form.on('change', function(field, value) {
|
|
227
|
-
if (field === 'attachment' && value) {
|
|
228
|
-
console.log('File uploaded:', value);
|
|
229
|
-
}
|
|
230
|
-
});
|
|
231
|
-
});
|
|
232
|
-
```
|
|
233
|
-
|
|
234
|
-
---
|
|
235
|
-
|
|
236
|
-
## Managing Web Forms via REST API
|
|
237
|
-
|
|
238
|
-
### Get Web Form Configuration
|
|
239
|
-
```bash
|
|
240
|
-
curl -sS "https://{site}/api/resource/Web%20Form" \
|
|
241
|
-
-G --data-urlencode 'filters=[["route","=","my-form"]]' \
|
|
242
|
-
--data-urlencode 'fields=["name","title","custom_css","client_script"]' \
|
|
243
|
-
-H "Authorization: token {key}:{secret}"
|
|
244
|
-
```
|
|
245
|
-
|
|
246
|
-
### Update Web Form Client Script
|
|
247
|
-
```bash
|
|
248
|
-
curl -sS -X PUT "https://{site}/api/resource/Web%20Form/{name}" \
|
|
249
|
-
-H "Authorization: token {key}:{secret}" \
|
|
250
|
-
-H "Content-Type: application/json" \
|
|
251
|
-
-d '{"client_script":"frappe.ready(function() { ... })"}'
|
|
252
|
-
```
|