コンテンツにスキップ
HaneDOCSEN

アプリを作る

チュートリアル: 車両リース管理

参照アプリ「車両リース管理」を手元で動かし、Hane の上にアプリを作るときの形を、主なファイルに沿って読み解きます。

このページでは、Hane の参照アプリ「車両リース管理」を手元で動かし、どこに何が書いてあるかを順に読みます。参照アプリは、Hane の公開 API(@hane/sdk)と UI ライブラリ(@hane/ui)だけで作った顧客アプリの見本です。自分のアプリを作るときは、ここから写して始められます。

社用車のリース契約と車両の台帳を持ち、満了への対応や請求の照合を進める業務アプリです。データはすべて作りもので、実在の会社・車両・人は入っていません。

場面 使う Hane の機能
台帳(契約・車両・取引先)と値の確定 型と項目、値の状態と出典、計算の規則、CSV の取り込み
満了対応(毎朝の検知 → 案件 → 担当の Task → 方針の決定 → 見積の依頼のメール) Schedule、Workflow、割り当ての規則、承認、Communication
申込の金額による 1 段・2 段の承認 DeciderPolicy、人が行う操作と実行台帳
請求の照合 規則による照合、根拠を付けた申入れのメールの承認
文書(契約書のアップロード・検索・抜き出した値の確認) 文書サービス、抽出の定義
「Agent に頼む」チャット 会話、チャットの Agent、業務の Agent、SSE
  1. Hane を手元で起動する

    チャットの Agent と業務の Agent は Claude Code のドライバーで動くので、手元で claude auth status を確かめてから起動します。

    ターミナルウィンドウ
    HANE_DEV_PROFILE=local-claude pnpm dev

    既定の local でも画面・台帳・Workflow は動きますが、driver: claude の Agent は失敗します。

  2. データを入れる

    ターミナルウィンドウ
    pnpm dev:seed

    組織 acme、プロジェクト fleet、利用者、グループ、参照アプリのサービスアカウントと API キー、定義、作りもののデータが入ります。

  3. ログインする

    http://localhost:5174 を開き、開発用の IdP で「車両 担当」を選びます。承認は、頼んだ人とは別の「承認 部長」が行います。

  4. 頼んでみる

    「Agent に頼む」で「C-1001 の満了日を教えて」「C-1003 の再リースの見積を V-001 に頼んで」と書きます。見積の依頼のメールは承認の Task になります。「承認 部長」でログインし直して「自分の Task」で承認すると送られます(手元では emulator が受けます。http://localhost:8789)。

  • ディレクトリexamples/fleet/
    • ディレクトリdefinitions/ マニフェスト。業務の決まりはすべてここ
      • bundle.yaml
      • ディレクトリschemas/
        • …
      • ディレクトリrules/
        • …
      • ディレクトリworkflows/
        • …
      • ディレクトリschedules/
        • …
      • ディレクトリpolicies/
        • …
      • ディレクトリagents/
        • …
      • …
    • ディレクトリbff/ 画面のサーバー
      • app.ts
      • server.ts
      • worker.ts
      • ledger.ts
      • agent-chat.ts
      • agent-events.ts
      • …
    • ディレクトリapp/ 画面(React・TanStack Router)
      • src/routes.tsx
      • src/api.ts
      • src/Agents.tsx
      • src/theme.css
    • ディレクトリdata/ 作りもののデータの CSV
      • …

まず definitions/ を読みます。画面と BFF には業務の判断がなく、すべて定義にあります。

  • schemas/lease-contract.yaml は契約の型です。満了日(end_date)と申入れの期限(notice_due)は computed で、計算の規則が決めます。
  • rules/lease-end-date.yaml は、開始日と契約月数から満了日を計算する規則です。書面の満了日と計算が合わないときは、どちらが正しいか決めずに不明にします(conflict)。
  • schedules/daily-expiry-scan.yaml は、毎朝 7:00 に、申入れの期限が 90 日以内の有効な契約ごとに案件を作ります。
  • workflows/lease-expiry.yaml は満了対応の進め方です。確定していない値があれば先に確かめる Task を作り、起案の Agent を動かし、担当が方針を決めた後、承認を経て申込へ進みます。
  • agents/assistant.yaml はチャットの Agent、agents/lease-qa.yaml や agents/quote-request.yaml は業務の Agent です。quote-request は communication.send_email を持ち、approval の割り当てで承認を通します。
  • policies/ には割り当ての規則と DeciderPolicy があります。申込の総額で 1 段か 2 段の承認になる決まりはここにあります。
  • bff/app.ts の exchange が、利用者の id_token とアプリの API キーを Hane でトークン交換します。createFleetApp は /bff/* の口をまとめ、Hane のエラーを code と Problem のまま画面に返します。
  • bff/server.ts は手元の Node.js の入口で、開発用の IdP の PKCE でログインし、セッションをメモリに持ちます。アクセストークンが切れかけたら交換し直します。
  • bff/worker.ts は Cloudflare Workers の入口で、Cloudflare Access のトークンを id_token として交換します。セッションは持ちません。
  • bff/ledger.ts は台帳・案件・Task の口です。更新はレコードや Task のバージョンを ifMatch で If-Match に付け、承認の Task では画面に出した ActionRequest の digest を一緒に送ります。
  • bff/agent-chat.ts と bff/agent-events.ts は会話の口と、SSE の中継です。
  • app/src/api.ts の bff は、BFF の /bff/* だけを呼ぶ関数です。401 ならログインへ送ります。
  • app/src/routes.tsx に画面の道筋がすべてあります。一覧の絞込みは URL のクエリに持ちます。
  • app/src/Agents.tsx は、@hane/ui の AgentChat に BFF を呼ぶ ChatTransport を渡してチャットの画面を作ります。
  • app/src/theme.css は、UI ライブラリの既定のテーマ(--hane-*)を上書きして、アプリの見た目にする例です。

画面の項目名はスキーマの title から引き、アプリの辞書に持ちません。Hane から来るデータ(値・項目名・Task の題名)は訳さず、そのまま出します。

  1. definitions/ を自分の業務の型と進め方に書き換え、hanectl validate で確かめます。
  2. BFF の app.ts を残し、ログインの入口(server.ts・worker.ts)を自分の IdP に合わせます。
  3. 画面は bff() を呼ぶ形のまま、自分の業務の画面に作り替えます。