コンテンツにスキップ
HaneDOCSEN

アプリを作る

アプリの構成

Hane の上に作るアプリを、画面・BFF・SDK・定義のディレクトリに分け、何を Hane に置き何をアプリに置くかを説明します。

このページでは、Hane の上に作る業務アプリの基本の形を説明します。参照アプリ(車両リース管理)と同じく、画面・BFF・定義の 3 つに分け、業務データと業務の決まりを Hane に置きます。

ブラウザ(画面)
│ /bff/* だけを呼ぶ。cookie のセッション
▼
BFF(アプリのサーバー)
│ @hane/sdk で公開 API を呼ぶ。利用者のアクセストークン
▼
Hane の公開 API(入口)
│
├─ 業務データ・Workflow・Task・Agent・文書・監査
└─ 定義(hanectl apply → ReleaseBundle)
  • 画面 は BFF の口だけを呼びます。Hane を直接呼ばず、API キーもアクセストークンも持ちません。
  • BFF は、利用者のログインとセッションを持ち、Hane でトークン交換して得たアクセストークンで公開 API を呼びます。
  • 定義 は Git に置くマニフェストで、hanectl で Hane に入れます。業務の決まり(計算・進め方・割り当て・Agent)はここに書きます。

参照アプリは次のように分けています。自分のアプリも同じ形で始めると、BFF の書き方や定義の置き方をそのまま写せます。

  • ディレクトリmy-app/
    • ディレクトリapp/ 画面(React と Vite など)
      • ディレクトリsrc/
        • api.ts BFF を呼ぶ口
        • routes.tsx
    • ディレクトリbff/ アプリのサーバー
      • app.ts 口(Hono など)。動かす場所によらない
      • server.ts 手元の Node.js の起動とログイン
      • worker.ts Cloudflare Workers の入口
    • ディレクトリdefinitions/ マニフェスト
      • bundle.yaml ReleaseBundle に束ねる範囲
      • ディレクトリschemas/
        • …
      • ディレクトリrules/
        • …
      • ディレクトリworkflows/
        • …
      • ディレクトリagents/
        • …
      • ディレクトリpolicies/
        • …
    • package.json

BFF の口(app.ts)は動かす場所に依存させず、ログインとセッションの持ち方だけを server.ts や worker.ts で替えます。手元では開発用の IdP の PKCE とメモリのセッション、Cloudflare Workers では Cloudflare Access のトークンを使う、という分け方です。

BFF は、利用者の IdP の id_token と、このアプリのサービスアカウントの API キーを Hane に渡して、アクセストークンに交換します。こうすると、利用者が元の主体、アプリが実行主体として記録され、Task を決めた人や値を確かめた人が利用者として残ります。

import { createHaneClient, unwrap } from "@hane/sdk";
export async function exchange(idToken: string) {
const anon = createHaneClient({ baseUrl: process.env.HANE_API!, token: () => null });
return unwrap(
anon.POST("/v1/auth/token", {
body: {
grant_type: "urn:ietf:params:oauth:grant-type:token-exchange",
subject_token: idToken,
subject_token_type: "urn:ietf:params:oauth:token-type:id_token",
actor_token: process.env.HANE_API_KEY!,
actor_token_type: "urn:hane:params:token-type:api_key",
organization: "acme",
project: "fleet",
environment: "dev",
},
}),
);
}

交換したアクセストークンは 15 分で切れます。期限が近づいたら同じ id_token で交換し直し、id_token も切れかけていたらログインし直させます。要求ごとに、そのセッションのアクセストークンでクライアントを作ります。

const hane = (session: { accessToken: string }) =>
createHaneClient({ baseUrl: process.env.HANE_API!, token: () => session.accessToken });

詳しくは 認証 を見てください。

何を Hane に置き、何をアプリに置くか

Section titled “何を Hane に置き、何をアプリに置くか”
Hane に置く アプリに置く
業務データ(レコード・値の状態・出典・関係)の正本 画面と画面の道筋
計算の規則、Workflow、スケジュール、割り当ての規則、Agent の定義 顧客の台帳の列から Hane の項目への変換(取り込みの前処理)
Task、承認、外への操作の記録、監査 ログインとセッション(IdP との連携)
会話、AgentRun、文書と検索の索引 画面の文言と見た目のテーマ
  • API キーとアクセストークンは BFF だけが持ち、ブラウザには渡しません。ブラウザとの間は httpOnly の cookie のセッションにします。
  • 画面に出す項目名は、型の定義の title から引きます(GET /v1/data/types)。アプリの辞書に同じ名前を持ちません。
  • Hane のエラーは、BFF で code と Problem をそのまま画面に返すと、項目ごとの誤りを画面で示せます。
  • 画面の CSP は BFF が応答に付けます。外の origin から読むものを足したら CSP にも足します。