mcpField
A
app-development

app-development

github.com/lubusin开发69111 次安装12 周前更新
代码仓库

关于 app-development

面向 Frappe 开发者的应用构建 Skill,涵盖应用结构、钩子、后台任务和生产准备。强调将业务逻辑拆分到服务模块,并遵循 Frappe 约定。

主要功能

  1. 01应用脚手架与架构规划
  2. 02钩子配置模式
  3. 03服务层组织方式
  4. 04后台任务设置
  5. 05缓存与错误处理工具
  6. 06版本兼容指导

适用场景

  1. 01启动自定义 Frappe 应用
  2. 02将业务逻辑移出 DocType 控制器
  3. 03添加事件钩子和定时任务
  4. 04准备应用部署

安装

复制下面的命令,在终端中运行。

$npx skills add https://github.com/lubusin/frappe-skills --skill app-development

安装后在 Claude Code 中输入/app-development确认已加载。

包含的文件

除 SKILL.md 外,安装时一起下载的参考资料和脚本。

assets/mini-app-template/your_app/
api.py
hooks.py
README.md
assets/mini-app-template/your_app/background_jobs/
sample_job.py
assets/mini-app-template/your_app/dashboard/
sample_doc_dashboard.json
assets/mini-app-template/your_app/doctype/sample_doc_item/
sample_doc_item.json
assets/mini-app-template/your_app/doctype/sample_doc/
sample_doc_dynamic_link.json
sample_doc_naming_series.json
sample_doc.js
sample_doc.json
sample_doc.py
assets/mini-app-template/your_app/doctype/sample_single/
sample_single.json
assets/mini-app-template/your_app/doctype/sample_submittable/
sample_submittable.json
assets/mini-app-template/your_app/doctype/sample_tree/
sample_tree.json
assets/mini-app-template/your_app/integrations/
sample_connector.py
assets/mini-app-template/your_app/list_view/
sample_doc_list.js
assets/mini-app-template/your_app/report/sample_report/
sample_report.js
sample_report.json
sample_report.py
assets/mini-app-template/your_app/services/
sample_service.py
assets/mini-app-template/your_app/utils/
cache.py
errors.py
logging.py
permissions.py
validation.py
assets/mini-app-template/your_app/workflow/
sample_doc_workflow.json
references/
app-development.md
translations.md
version-compat.md

详细介绍

Frappe 应用开发

使用生产级模式搭建脚手架、规划结构并设计自定义 Frappe 应用。

适用场景

  • 从头开始创建新的自定义 Frappe 应用
  • 设置应用架构(模块、服务、工具函数)
  • 为事件、调度器和覆盖项配置 hooks.py
  • 实现后台任务和异步处理
  • 构建服务层和领域逻辑模式
  • 添加缓存、日志记录和错误处理工具
  • 为生产部署准备应用
  • 管理翻译、版本控制和打包

所需输入

  • 应用名称和用途
  • 目标 Frappe 版本(v13+、v15+、v16+)
  • 模块结构(涉及哪些 DocType、API 和服务)
  • 是否需要其他应用的钩子或覆盖项
  • 后台任务需求
  • 生产就绪要求

流程

0) 搭建应用脚手架
# Create the app
bench new-app my_app

# Install on site
bench --site mysite.local install-app my_app

# Verify developer mode
bench --site mysite.local console
>>> frappe.conf.developer_mode  # Must be True
1) 规划应用结构

遵循领域架构模式:保持 DocType 控制器精简,并将业务逻辑放在服务模块中:

my_app/
├── my_app/
│   ├── __init__.py
│   ├── hooks.py              # App hooks and configuration
│   ├── api.py                # Public API surface (RPC endpoints)
│   ├── services/             # Business logic modules
│   │   └── billing.py
│   ├── utils/                # Cross-cutting utilities
│   │   ├── cache.py
│   │   ├── errors.py
│   │   ├── logging.py
│   │   ├── permissions.py
│   │   └── validation.py
│   ├── background_jobs/      # Async job handlers
│   │   └── export_job.py
│   ├── integrations/         # External system connectors
│   │   └── payment_gateway.py
│   ├── my_module/
│   │   ├── doctype/
│   │   │   └── my_doc/
│   │   │       ├── my_doc.json
│   │   │       ├── my_doc.py
│   │   │       ├── my_doc.js
│   │   │       └── test_my_doc.py
│   │   ├── report/
│   │   └── dashboard/
│   └── translations/
│       ├── en.csv
│       └── fr.csv
├── setup.py
└── README.md

使用 assets/mini-app-template/ 中的 mini-app-template 作为初始脚手架。

2) 配置 hooks.py
# hooks.py

app_name = "my_app"
app_title = "My App"
app_publisher = "My Company"

# DocType lifecycle events
doc_events = {
    "Sales Order": {
        "on_submit": "my_app.services.billing.on_order_submit",
        "on_cancel": "my_app.services.billing.on_order_cancel",
    },
    "*": {
        "after_insert": "my_app.utils.logging.log_creation",
    }
}

# Scheduled tasks
scheduler_events = {
    "daily": [
        "my_app.background_jobs.cleanup.run_daily_cleanup"
    ],
    "cron": {
        "0 */6 * * *": [
            "my_app.background_jobs.sync.sync_external_data"
        ]
    }
}

# Client-side script injection
doctype_js = {
    "Sales Order": "public/js/sales_order.js"
}

doctype_list_js = {
    "Sales Order": "public/js/sales_order_list.js"
}

# Override another app's controller (use sparingly)
# override_doctype_class = {
#     "ToDo": "my_app.overrides.custom_todo.CustomToDo"
# }

# Extend controller without full replacement (v16+, preferred)
# extend_doctype_class = {
#     "ToDo": "my_app.overrides.todo_extension.TodoExtension"
# }

# Override whitelisted methods
# override_whitelisted_methods = {
#     "frappe.client.get_list": "my_app.overrides.custom_get_list"
# }
3) 实现服务层

保持 DocType 控制器精简,将业务逻辑委托给服务:

# my_app/services/billing.py
import frappe

def on_order_submit(doc, method):
    """Handle order submission — called via doc_events hook."""
    if doc.grand_total > 10000:
        create_approval_request(doc)
    generate_invoice(doc)

def generate_invoice(order):
    """Create invoice from submitted order."""
    invoice = frappe.get_doc({
        "doctype": "Sales Invoice",
        "customer": order.customer,
        "items": [
            {"item_code": i.item_code, "qty": i.qty, "rate": i.rate}
            for i in order.items
        ]
    })
    invoice.insert()
    invoice.submit()
    return invoice
4) 设置后台任务
# my_app/background_jobs/export_job.py
import frappe

def enqueue_export(filters):
    """Enqueue a long-running export job."""
    frappe.enqueue(
        "my_app.background_jobs.export_job.run_export",
        filters=filters,
        queue="long",
        timeout=600,
        is_async=True
    )

def run_export(filters):
    """Execute the export — runs in background worker."""
    data = frappe.get_all("Sales Order", filters=filters, fields=["*"])
    # Process data...
    frappe.publish_realtime("export_complete", {"count": len(data)})
5) 添加横切工具
# my_app/utils/cache.py
import frappe

def get_cached_settings(key):
    """Cache expensive settings lookups."""
    value = frappe.cache().get_value(f"my_app:{key}")
    if value is None:
        value = frappe.db.get_single_value("My Settings", key)
        frappe.cache().set_value(f"my_app:{key}", value)
    return value

def invalidate_cache(key):
    frappe.cache().delete_value(f"my_app:{key}")
# my_app/utils/errors.py
import frappe

def api_error(message, status_code=400, exc=None):
    """Consistent error response for API endpoints."""
    frappe.local.response["http_status_code"] = status_code
    frappe.throw(message, exc or frappe.ValidationError)
6) 处理翻译
# In Python code
frappe._("Hello World")   # Mark string for translation

# In JavaScript
__("Hello World")         # Mark string for translation
# Translation CSV files go in my_app/translations/
# e.g., my_app/translations/fr.csv:
# Hello World,Bonjour le monde
7) 版本兼容性
功能最低版本
extend_doctype_classFrappe v16+
REST API v2 (/api/v2/)Frappe v15+
基于令牌的身份验证Frappe v11.0.3+

面向多个版本时,请为特定版本的功能添加保护:

import frappe

if hasattr(frappe, 'extend_doctype_class'):
    # v16+ pattern
    pass
else:
    # Fallback for older versions
    pass

验证

  • 应用安装无错误:bench --site <site> install-app my_app
  • 钩子正常触发(检查调度器日志和文档事件)
  • 后台任务成功入队并完成
  • bench --site <site> migrate 成功
  • 测试通过:bench --site <site> run-tests --app my_app

故障模式 / 调试

  • 找不到应用:检查 apps.txt 和 sites/<site>/site_config.json
  • 钩子未触发:检查 hooks.py 语法;重启 bench
  • 后台任务卡住:使用 bench doctor 检查工作进程状态;检查 Redis
  • 导入错误:确保钩子中的模块路径与实际 Python 路径一致
  • 开发者模式已关闭:DocType 更改不会导出到文件

升级处理

  • 有关 DocType 创建详情 → doctype-development
  • 有关 API 端点模式 → api-development
  • 有关 Desk UI 自定义 → desk-customization
  • 有关 Frappe UI 前端 → frontend-development
  • 有关打印格式和 Jinja → printing-templates
  • 有关报表 → reports
  • 有关网页表单 → web-forms
  • 有关测试 → testing
  • 有关企业架构 → enterprise-patterns
  • 有关 Docker/FM 环境 → frappe-manager

参考资料

交叉引用(由专用技能维护)

防护规则

  • 自定义前端使用 Frappe UI:绝不使用原生 JS、jQuery 或自定义框架。Frappe UI(Vue 3 + TailwindCSS)是生态标准。设置请参阅 frontend-development。
  • CRUD 应用遵循 CRM/Helpdesk 模式:遵循 ui-patterns 技能中的应用外壳、导航、列表视图和表单布局,这些模式源自官方 Frappe 应用。
  • 遵循命名规范:应用名称必须全部小写并使用下划线,且是有效的 Python 标识符
  • 使用 hooks.py 进行集成:绝不使用猴子补丁;使用 doc_events、scheduler_events、boot_session 钩子
  • 保持 hooks.py 简洁:仅放置配置,不包含逻辑;从模块导入
  • 保持向后兼容性:使用 frappe.version 检查以支持不同版本
  • 正确导出 fixtures:对于应与应用同步的数据,在 hooks.py 中使用 fixtures

常见错误

错误失败原因修复方法
应用不在 installed_apps 中应用代码未加载运行 bench --site <site> install-app my_app
hooks 中的模块路径错误事件不会触发确认路径与实际的 my_app/module/file.py 结构一致
重复注册钩子事件会多次触发检查 hooks.py 中是否有重复项;使用列表,不要重复键
编辑 hooks.py 后未重启更改不会生效修改 hooks.py 后运行 bench restart
缺少 __init__.py 文件模块导入错误确保每个目录都有 __init__.py
在 hooks.py 中编写逻辑难以测试,且可能导致导入错误将逻辑移至独立模块,并在 hooks 中导入
使用原生 JS/jQuery 构建前端与生态不一致使用 Frappe UI(Vue 3);参阅 frontend-development
为 CRUD 应用构建自定义应用外壳用户体验不一致遵循 CRM/Helpdesk 的导航和布局模式

评论

支持 Markdown