frappe-enterprise-patterns
Compare original and translation side by side
🇺🇸
Original
English🇨🇳
Translation
ChineseFrappe Enterprise Patterns
Frappe 企业级架构模式
Architectural patterns for building production-grade enterprise applications.
用于构建生产级企业应用的架构模式。
When to use
适用场景
- Building CRM, Helpdesk, HRMS, or similar multi-entity systems
- Designing SLA-driven workflows
- Implementing assignment and queue management
- Building audit trails and activity logs
- Integrating with external systems (email, telephony, CRM)
- 构建CRM、Helpdesk、HRMS或类似的多实体系统
- 设计基于SLA的工作流
- 实现分配与队列管理
- 构建审计追踪与活动日志
- 与外部系统集成(邮件、电话、CRM)
Inputs required
所需输入
- System type (CRM/Helpdesk/custom)
- Core entities and relationships
- SLA requirements
- Workflow states and transitions
- Integration points
- 系统类型(CRM/Helpdesk/自定义)
- 核心实体及关系
- SLA要求
- 工作流状态与转换
- 集成点
Procedure
实施步骤
0) Design data model
0) 设计数据模型
Start with clear, normalized DocTypes:
Ticket (parent)
├── customer (Link: Customer)
├── assigned_to (Link: User)
├── status (Select: Open, In Progress, Resolved, Closed)
├── priority (Link: Priority)
├── sla (Link: SLA)
├── activities (Table: Ticket Activity)
└── response_by, resolution_by (Datetime)Key patterns:
- Use Link fields for relationships
- Use child tables for activities, timelines, line items
- Use Dynamic Link when target DocType varies
从清晰、规范化的DocType开始:
Ticket (parent)
├── customer (Link: Customer)
├── assigned_to (Link: User)
├── status (Select: Open, In Progress, Resolved, Closed)
├── priority (Link: Priority)
├── sla (Link: SLA)
├── activities (Table: Ticket Activity)
└── response_by, resolution_by (Datetime)关键模式:
- 使用Link字段建立关系
- 使用子表存储活动、时间线、明细项
- 当目标DocType变化时使用Dynamic Link
1) Implement state machine
1) 实现状态机
Option A: Workflow DocType
- Create Workflow with states and role-based transitions
- Link to your DocType
Option B: docstatus for submission flow
| docstatus | Meaning |
|---|---|
| 0 | Draft |
| 1 | Submitted |
| 2 | Cancelled |
Option C: Custom status field with validation
python
def validate(self):
allowed = self.get_allowed_transitions()
if self.status not in allowed:
frappe.throw(f"Cannot transition to {self.status}")选项A:Workflow DocType
- 创建包含状态和基于角色的转换规则的Workflow
- 关联到你的DocType
选项B:用docstatus处理提交流程
| docstatus | 含义 |
|---|---|
| 0 | 草稿 |
| 1 | 已提交 |
| 2 | 已取消 |
选项C:带验证的自定义状态字段
python
def validate(self):
allowed = self.get_allowed_transitions()
if self.status not in allowed:
frappe.throw(f"Cannot transition to {self.status}")2) Set up permissions
2) 设置权限
Row-level filtering:
- Use User Permissions to restrict by entity
- Combine with Role Permissions
Always re-check in RPC methods:
python
@frappe.whitelist()
def update_ticket(name, status):
doc = frappe.get_doc("Ticket", name)
if not frappe.has_permission("Ticket", "write", doc):
frappe.throw("Not permitted", frappe.PermissionError)
doc.status = status
doc.save()行级过滤:
- 使用User Permissions按实体限制访问
- 结合Role Permissions使用
始终在RPC方法中重新校验:
python
@frappe.whitelist()
def update_ticket(name, status):
doc = frappe.get_doc("Ticket", name)
if not frappe.has_permission("Ticket", "write", doc):
frappe.throw("Not permitted", frappe.PermissionError)
doc.status = status
doc.save()3) Build activity trail
3) 构建活动追踪
Track changes using Activity Log or custom child table:
python
def on_update(self):
if self.has_value_changed("status"):
self.append("activities", {
"action": "Status Change",
"old_value": self._doc_before_save.status,
"new_value": self.status,
"timestamp": frappe.utils.now()
})使用Activity Log或自定义子表追踪变更:
python
def on_update(self):
if self.has_value_changed("status"):
self.append("activities", {
"action": "Status Change",
"old_value": self._doc_before_save.status,
"new_value": self.status,
"timestamp": frappe.utils.now()
})4) Implement SLA
4) 实现SLA
SLA DocType:
SLA
├── entity_type (Link: DocType)
├── response_time (Duration)
├── resolution_time (Duration)
└── escalation_rules (Table: Escalation Rule)Apply SLA on creation:
python
def after_insert(self):
sla = get_applicable_sla(self)
if sla:
self.response_by = add_to_date(self.creation, hours=sla.response_time)
self.resolution_by = add_to_date(self.creation, hours=sla.resolution_time)
self.db_update()Monitor breaches (scheduled job):
python
def check_sla_breaches():
tickets = frappe.get_all("Ticket",
filters={"status": ["not in", ["Resolved", "Closed"]]},
fields=["name", "resolution_by"]
)
for t in tickets:
if frappe.utils.now_datetime() > t.resolution_by:
mark_sla_breached(t.name)SLA DocType:
SLA
├── entity_type (Link: DocType)
├── response_time (Duration)
├── resolution_time (Duration)
└── escalation_rules (Table: Escalation Rule)在创建时应用SLA:
python
def after_insert(self):
sla = get_applicable_sla(self)
if sla:
self.response_by = add_to_date(self.creation, hours=sla.response_time)
self.resolution_by = add_to_date(self.creation, hours=sla.resolution_time)
self.db_update()监控SLA违约(定时任务):
python
def check_sla_breaches():
tickets = frappe.get_all("Ticket",
filters={"status": ["not in", ["Resolved", "Closed"]]},
fields=["name", "resolution_by"]
)
for t in tickets:
if frappe.utils.now_datetime() > t.resolution_by:
mark_sla_breached(t.name)5) Assignment and queues
5) 分配与队列
Round-robin assignment:
python
def assign_next_agent(queue):
agents = frappe.get_all("Queue Member",
filters={"queue": queue, "available": 1},
fields=["user", "current_load"],
order_by="current_load asc"
)
if agents:
return agents[0].user
return NoneAssignment Rules DocType for automatic assignment.
轮询分配:
python
def assign_next_agent(queue):
agents = frappe.get_all("Queue Member",
filters={"queue": queue, "available": 1},
fields=["user", "current_load"],
order_by="current_load asc"
)
if agents:
return agents[0].user
return None使用Assignment Rules DocType实现自动分配。
6) Notifications and escalations
6) 通知与升级
Configure Notification DocType for:
- SLA approaching breach
- Assignment changes
- Status transitions
- Customer replies
Escalation chain:
Level 1 (0h): Notify assigned agent
Level 2 (4h): Notify team lead
Level 3 (8h): Notify manager
Level 4 (24h): Notify department head配置Notification DocType用于:
- SLA即将违约时通知
- 分配变更通知
- 状态转换通知
- 客户回复通知
升级链:
Level 1 (0h): 通知分配的坐席
Level 2 (4h): 通知团队负责人
Level 3 (8h): 通知经理
Level 4 (24h): 通知部门主管7) External integrations
7) 外部集成
Centralize in module:
integrations/python
undefined集中在模块中:
integrations/python
undefinedmy_app/integrations/email_connector.py
my_app/integrations/email_connector.py
def sync_emails():
# Fetch from Email Account
# Create Communications
# Link to Tickets
**Use background jobs for sync:**
```python
frappe.enqueue(
"my_app.integrations.email_connector.sync_emails",
queue="long",
timeout=600
)def sync_emails():
# Fetch from Email Account
# Create Communications
# Link to Tickets
**使用后台任务进行同步:**
```python
frappe.enqueue(
"my_app.integrations.email_connector.sync_emails",
queue="long",
timeout=600
)Verification
验证项
- Workflow transitions work for all roles
- Permissions enforced at API level
- Activity log captures all changes
- SLA calculation correct
- Notifications fire appropriately
- Integration sync runs without errors
- 工作流转换对所有角色生效
- API层面已强制执行权限
- 活动日志捕获所有变更
- SLA计算正确
- 通知正常触发
- 集成同步运行无错误
Failure modes / debugging
故障模式与调试
- Permission bypass: Check RPC methods have explicit permission checks
- SLA not applying: Verify scheduled job is running
- Activities not logging: Check usage
has_value_changed - Notifications not sending: Check Notification rules and email queue
- 权限绕过:检查RPC方法是否有显式的权限校验
- SLA未生效:验证定时任务是否在运行
- 活动未记录:检查的使用是否正确
has_value_changed - 通知未发送:检查Notification规则和邮件队列
Escalation
进阶指引
- For complex permission patterns, see references/advanced-permissions.md
- For queue optimization, see references/queue-patterns.md
- For UI/UX patterns →
frappe-ui-patterns
- 复杂权限模式请参考references/advanced-permissions.md
- 队列优化请参考references/queue-patterns.md
- UI/UX模式请参考
frappe-ui-patterns
References
参考资源
- references/workflow-patterns.md - State machine design
- references/sla-implementation.md - SLA details
- references/integration-patterns.md - External systems
- references/workflow-patterns.md - 状态机设计
- references/sla-implementation.md - SLA细节
- references/integration-patterns.md - 外部系统集成
Guardrails
注意事项
- Follow CRM/Helpdesk UI patterns: For CRUD apps, follow skill which documents app shell, navigation, list views, and form patterns from official Frappe apps. This includes sidebar layouts, quick filters, Kanban views, and detail panels.
frappe-ui-patterns - Use Frappe UI for frontends: All custom enterprise frontends must use Frappe UI (Vue 3 + TailwindCSS) — never vanilla JS or jQuery
- Design workflows carefully: Map all states and transitions before implementation; consider rollback paths
- Handle edge cases: Plan for cancelled, on-hold, and exception states in workflows
- Test performance early: Run load tests for high-volume DocTypes and complex queries
- Use background jobs for heavy operations: Never block web requests with long-running tasks
- Log critical operations: Use and activity logs for auditability
frappe.log_error()
- 遵循CRM/Helpdesk UI模式:对于CRUD应用,请遵循技能中记录的官方Frappe应用的应用外壳、导航、列表视图和表单模式,包括侧边栏布局、快速筛选、看板视图和详情面板。
frappe-ui-patterns - 前端使用Frappe UI:所有自定义企业级前端必须使用Frappe UI(Vue 3 + TailwindCSS)——禁止使用原生JS或jQuery
- 谨慎设计工作流:在实现前映射所有状态和转换;考虑回滚路径
- 处理边缘情况:在工作流中规划已取消、暂停和异常状态
- 尽早测试性能:对高容量DocType和复杂查询进行负载测试
- 重操作使用后台任务:永远不要用长时间运行的任务阻塞Web请求
- 记录关键操作:使用和活动日志保证可审计性
frappe.log_error()
Common Mistakes
常见错误
| Mistake | Why It Fails | Fix |
|---|---|---|
| Over-complex workflows | Hard to maintain, user confusion | Keep workflows linear when possible; split complex flows |
| Missing error handling in integrations | Silent failures, data inconsistency | Wrap external calls in try/except; log errors; retry logic |
| Race conditions in document updates | Data corruption | Use |
| SLA without timezone handling | Wrong calculations for global users | Store and compare in UTC; use |
| Not using queues for bulk operations | Timeouts, memory issues | Use |
| Hardcoded role names | Breaks on role changes | Use constants or settings for role names |
| Custom UI patterns | Inconsistent UX, user confusion | Study and follow CRM/Helpdesk app shells |
| Using vanilla JS/jQuery for frontend | Maintenance burden, ecosystem mismatch | Always use Frappe UI with Vue 3 |
| 错误 | 失败原因 | 修复方案 |
|---|---|---|
| 工作流过于复杂 | 难以维护,用户困惑 | 尽可能保持工作流线性;拆分复杂流程 |
| 集成中缺少错误处理 | 静默失败,数据不一致 | 用try/except包裹外部调用;记录错误;添加重试逻辑 |
| 文档更新中的竞争条件 | 数据损坏 | 使用 |
| SLA未处理时区 | 全球用户计算错误 | 以UTC存储和比较时间;使用 |
| 批量操作未使用队列 | 超时,内存问题 | 对多记录操作使用 |
| 硬编码角色名称 | 角色变更时失效 | 使用常量或配置存储角色名称 |
| 自定义UI模式 | UX不一致,用户困惑 | 学习并遵循CRM/Helpdesk应用外壳 |
| 前端使用原生JS/jQuery | 维护负担,生态不兼容 | 始终使用基于Vue 3的Frappe UI |