mcpField
A
app-development

app-development

github.com/lubusin開発69111 回インストール12 週間前に更新
リポジトリ

app-development について

Frappe 開発者向けに、アプリの構成、フック、バックグラウンドジョブ、本番環境への準備を支援するスキルです。ビジネスロジックをサービス層に分け、Frappe の規約に沿った設計を扱います。

主な機能

  1. 01アプリのひな形と設計
  2. 02フック設定のパターン
  3. 03サービス層の構成
  4. 04バックグラウンドジョブの設定
  5. 05キャッシュとエラー処理のユーティリティ
  6. 06バージョン互換性の指針

活用シーン

  1. 01カスタム Frappe アプリの開始
  2. 02DocType コントローラーからのロジック分離
  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 を確認します
  • インポートエラー:hooks 内のモジュールパスが実際の 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 を使用します:バニラ JavaScript、jQuery、カスタムフレームワークは使用しないでください。Frappe UI(Vue 3 + TailwindCSS)はエコシステムの標準です。セットアップについては frontend-development を参照してください。
  • CRUD アプリには CRM/Helpdesk のパターンに従います:公式 Frappe アプリを基にしたアプリシェル、ナビゲーション、リストビュー、フォームレイアウトには、ui-patterns スキルを使用してください。
  • 命名規則に従います:アプリ名は小文字とアンダースコアを使用し、有効な Python 識別子である必要があります。
  • 統合には hooks.py を使用します:モンキーパッチは使用せず、doc_events、scheduler_events、boot_session フックを使用してください。
  • hooks.py を簡潔に保ちます:設定のみを記述し、ロジックは含めないでください。モジュールからインポートします。
  • 後方互換性を維持します:バージョンをまたいでサポートする場合は、frappe.version によるチェックを使用してください。
  • フィクスチャを適切にエクスポートします:アプリと同期するデータには、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 にロジックを記述するテストが難しくなり、インポートエラーが発生するロジックを別のモジュールに移し、フック内でインポートします
バニラ JavaScript/jQuery でフロントエンドを構築するエコシステムとの一貫性がなくなるFrappe UI(Vue 3)を使用してください。frontend-development を参照してください
CRUD アプリにカスタムアプリシェルを使用するUX に一貫性がなくなるナビゲーションとレイアウトには CRM/Helpdesk のパターンに従います

コメント