enterprise-patterns について
本番向け Frappe アプリの設計スキルです。CRM、Helpdesk、HRMS など複数のエンティティを扱うシステムを開発する人向けに、ワークフロー、権限、監査履歴、SLA、割り当てキュー、通知、外部連携の設計パターンを解説します。
主な機能
- 01DocType とリンクによるエンティティ設計
- 02ワークフローと状態遷移の設計
- 03ロール・行単位の権限制御
- 04活動履歴と監査ログの記録
- 05SLA とエスカレーションの実装
- 06割り当てキューと外部連携の管理
活用シーン
- 01CRM や Helpdesk のデータモデル設計
- 02ロール別のワークフロー遷移設定
- 03変更や SLA 超過の追跡
- 04レコード割り当てと外部同期の調整
インストール
コマンドをコピーしてターミナルで実行します。
$
npx skills add https:/ / github.com/ lubusin/ frappe-skills --skill enterprise-patternsインストール後、Claude Code で/enterprise-patternsを入力して読み込まれたか確認します。
同梱ファイル
SKILL.md と一緒にインストールされる参考資料やスクリプト。
references/advanced-permissions.mdenterprise-patterns.mdintegration-patterns.mdqueue-patterns.mdsla-implementation.mdworkflow-patterns.md詳細
Frappe エンタープライズパターン
本番環境向けのエンタープライズアプリケーションを構築するためのアーキテクチャパターンです。
使用する場面
- CRM、ヘルプデスク、HRMS、または同様の複数エンティティを扱うシステムを構築する場合
- SLA に基づくワークフローを設計する場合
- 割り当てとキュー管理を実装する場合
- 監査証跡とアクティビティログを構築する場合
- 外部システム(メール、テレフォニー、CRM)と連携する場合
必要な入力
- システムの種類(CRM/ヘルプデスク/カスタム)
- コアエンティティとリレーションシップ
- SLA 要件
- ワークフローの状態と遷移
- 連携ポイント
手順
0) データモデルを設計する
明確で正規化された 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) ステートマシンを実装する
オプション A:Workflow DocType
- 状態とロールベースの遷移を設定した Workflow を作成します
- 対象の DocType にリンクします
オプション B:送信フローに docstatus を使用する
| docstatus | 意味 |
|---|---|
| 0 | 下書き |
| 1 | 送信済み |
| 2 | 取消済み |
オプション C:検証付きのカスタムステータスフィールド
def validate(self):
allowed = self.get_allowed_transitions()
if self.status not in allowed:
frappe.throw(f"Cannot transition to {self.status}")
2) 権限を設定する
行レベルのフィルタリング:
- User Permissions を使用してエンティティごとに制限します
- Role Permissions と組み合わせます
RPC メソッドでは必ず再確認します:
@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) アクティビティの履歴を構築する
Activity Log またはカスタム子テーブルを使用して変更を追跡します。
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) SLA を実装する
SLA DocType:
SLA
├── entity_type (Link: DocType)
├── response_time (Duration)
├── resolution_time (Duration)
└── escalation_rules (Table: Escalation Rule)
作成時に SLA を適用する:
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()
違反を監視する(スケジュールジョブ):
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) 割り当てとキュー
ラウンドロビン方式の割り当て:
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) 通知とエスカレーション
次の通知用に Notification DocType を設定します:
- SLA 違反が迫っている場合
- 割り当てが変更された場合
- ステータスが遷移した場合
- 顧客から返信があった場合
エスカレーションチェーン:
Level 1 (0h): Notify assigned agent
Level 2 (4h): Notify team lead
Level 3 (8h): Notify manager
Level 4 (24h): Notify department head
7) 外部連携
integrations/ モジュールに集約します:
# my_app/integrations/email_connector.py
def sync_emails():
# Fetch from Email Account
# Create Communications
# Link to Tickets
同期にはバックグラウンドジョブを使用します:
frappe.enqueue(
"my_app.integrations.email_connector.sync_emails",
queue="long",
timeout=600
)
検証
- すべてのロールでワークフローの遷移が機能する
- API レベルで権限が適用される
- アクティビティログにすべての変更が記録される
- SLA の計算が正しい
- 通知が適切に送信される
- 連携の同期がエラーなく実行される
障害パターン/デバッグ
- 権限の迂回:RPC メソッドに明示的な権限チェックがあることを確認します
- SLA が適用されない:スケジュールジョブが実行されていることを確認します
- アクティビティが記録されない:
has_value_changedの使用方法を確認します - 通知が送信されない:Notification のルールとメールキューを確認します
エスカレーション
- 複雑な権限パターンについては、references/advanced-permissions.md を参照してください
- キューの最適化については、references/queue-patterns.md を参照してください
- UI/UX パターンについては、
ui-patternsを参照してください
参考資料
- references/workflow-patterns.md - ステートマシンの設計
- references/sla-implementation.md - SLA の詳細
- references/integration-patterns.md - 外部システム
ガードレール
- CRM/ヘルプデスクの UI パターンに従います:CRUD アプリでは、公式 Frappe アプリのアプリシェル、ナビゲーション、リストビュー、フォームパターンを説明している
ui-patternsスキルに従います。これにはサイドバーのレイアウト、クイックフィルター、カンバンビュー、詳細パネルが含まれます。 - フロントエンドには Frappe UI を使用します:すべてのカスタムエンタープライズフロントエンドで Frappe UI(Vue 3 + TailwindCSS)を使用します。バニラ JS や jQuery は使用しません
- ワークフローを慎重に設計します:実装前にすべての状態と遷移を整理し、ロールバック経路を考慮します
- エッジケースに対応します:ワークフローで取消済み、一時停止、例外の状態を考慮します
- 早期にパフォーマンスをテストします:大量データを扱う DocType や複雑なクエリの負荷テストを実施します
- 負荷の高い処理にはバックグラウンドジョブを使用します:実行時間の長いタスクでウェブリクエストをブロックしないでください
- 重要な処理をログに記録します:監査可能性を確保するために
frappe.log_error()とアクティビティログを使用します
よくある間違い
| 間違い | 失敗する理由 | 修正方法 |
|---|---|---|
| 複雑すぎるワークフロー | 保守が難しく、ユーザーが混乱します | 可能な限りワークフローを直線的に保ち、複雑なフローは分割します |
| インテグレーションでのエラー処理の欠如 | エラーが表面化せず、データの不整合が発生します | 外部呼び出しを try/except で囲み、エラーを記録し、再試行ロジックを実装します |
| ドキュメント更新時の競合状態 | データが破損します | ロックには frappe.db.get_value(..., for_update=True) を使用します |
| タイムゾーンを考慮しない SLA | 世界各地のユーザーに対して計算が誤ります | UTC で保存・比較し、frappe.utils.convert_utc_to_timezone を使用します |
| 一括操作でキューを使用しない | タイムアウトやメモリの問題が発生します | 多数のレコードを操作する場合は frappe.enqueue() を使用します |
| ロール名のハードコード | ロールの変更時に動作しなくなります | ロール名には定数または設定を使用します |
| 独自の UI パターン | UX に一貫性がなくなり、ユーザーが混乱します | CRM/Helpdesk のアプリシェルを調査し、それに従います |
| フロントエンドにバニラ JS/jQuery を使用 | 保守の負担が増え、エコシステムとの不整合が生じます | 必ず Vue 3 を使用した Frappe UI を使用します |
コメント
Markdown 対応