アプリを作る
チュートリアル: 車両リース管理
参照アプリ「車両リース管理」を手元で動かし、Hane の上にアプリを作るときの形を、主なファイルに沿って読み解きます。
このページでは、Hane の参照アプリ「車両リース管理」を手元で動かし、どこに何が書いてあるかを順に読みます。参照アプリは、Hane の公開 API(@hane/sdk)と UI ライブラリ(@hane/ui)だけで作った顧客アプリの見本です。自分のアプリを作るときは、ここから写して始められます。
何を見せるアプリか
Section titled “何を見せるアプリか”社用車のリース契約と車両の台帳を持ち、満了への対応や請求の照合を進める業務アプリです。データはすべて作りもので、実在の会社・車両・人は入っていません。
| 場面 | 使う Hane の機能 |
|---|---|
| 台帳(契約・車両・取引先)と値の確定 | 型と項目、値の状態と出典、計算の規則、CSV の取り込み |
| 満了対応(毎朝の検知 → 案件 → 担当の Task → 方針の決定 → 見積の依頼のメール) | Schedule、Workflow、割り当ての規則、承認、Communication |
| 申込の金額による 1 段・2 段の承認 | DeciderPolicy、人が行う操作と実行台帳 |
| 請求の照合 | 規則による照合、根拠を付けた申入れのメールの承認 |
| 文書(契約書のアップロード・検索・抜き出した値の確認) | 文書サービス、抽出の定義 |
| 「Agent に頼む」チャット | 会話、チャットの Agent、業務の Agent、SSE |
-
Hane を手元で起動する
チャットの Agent と業務の Agent は Claude Code のドライバーで動くので、手元で
claude auth statusを確かめてから起動します。ターミナルウィンドウ HANE_DEV_PROFILE=local-claude pnpm dev既定の
localでも画面・台帳・Workflow は動きますが、driver: claudeの Agent は失敗します。 -
データを入れる
ターミナルウィンドウ pnpm dev:seed組織
acme、プロジェクトfleet、利用者、グループ、参照アプリのサービスアカウントと API キー、定義、作りもののデータが入ります。 -
ログインする
http://localhost:5174 を開き、開発用の IdP で「車両 担当」を選びます。承認は、頼んだ人とは別の「承認 部長」が行います。
-
頼んでみる
「Agent に頼む」で「C-1001 の満了日を教えて」「C-1003 の再リースの見積を V-001 に頼んで」と書きます。見積の依頼のメールは承認の Task になります。「承認 部長」でログインし直して「自分の Task」で承認すると送られます(手元では emulator が受けます。http://localhost:8789)。
ファイルの構成
Section titled “ファイルの構成”ディレクトリ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 を読む
Section titled “BFF を読む”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 の題名)は訳さず、そのまま出します。
自分のアプリにするときは
Section titled “自分のアプリにするときは”definitions/を自分の業務の型と進め方に書き換え、hanectl validateで確かめます。- BFF の
app.tsを残し、ログインの入口(server.ts・worker.ts)を自分の IdP に合わせます。 - 画面は
bff()を呼ぶ形のまま、自分の業務の画面に作り替えます。