RELEASE NOTE
AI 連携の 土台を つくる提供元と モデルの 設定、 API キーの 2 つの 管理方式、 送信の 共通の 入口
OpenGreenTrack では、請求書の読取りや開示文の下書きなど、AI を使う機能を順に加えていく予定です。10 月 24 日の変更は、その前に整えた「土台」で、AI を使う機能そのものはまだ入っていません。機能ごとにばらばらに AI を呼ぶのではなく、鍵・送ってよいもの・回数・記録を 1 か所で守る作りにしました。
この版のポイント
- AI の提供元(Anthropic・Google・OpenAI)とモデルを、管理者が設定画面で選べる
- API キーは環境変数(方式A・既定)か、暗号化して画面から登録(方式B)。どちらの方式でもブラウザには渡らない
- AI への送信は共通の入口に一本化。用途・入力・回数・監査ログを 1 か所で確かめる
- AI を使う機能(請求書の読取りなど)は、このあと用途ごとに追加する(現時点の登録は 0 件)
01CONCEPT
考え方:設定・共通の 入口・用途の 3 層に 分ける
OpenGreenTrack はセルフホストで使うソフトウェアなので、AI も各組織が自分で契約した提供元の API キーで使います。もし機能ごとに提供元の API を直接呼ぶと、鍵の扱い・送信前の確認・回数の上限・記録の残し方が機能ごとにばらばらになり、どこか 1 つの抜けが情報漏えいや想定外の課金につながります。
入口だけを呼ぶ
- 用途
purposes.ts送ってよい入力の種類と量、回数の上限、出力の上限。例:請求書の読取り(今後追加)
決める人:開発者(プルリクエストのレビューを通す) - 共通の入口
generateStructured用途と入力の確認、鍵とモデルの解決、回数の上限、送信、結果の検証、監査ログ
決める人:OpenGreenTrack が提供 - 設定
環境変数・AI の設定鍵の方式と API キー、暗号化の鍵、使うモデルの選択
決める人:運用担当(環境変数)と管理者(画面)
組織が用意した API キーで呼ぶ
- 鍵は組織が用意する。 使ってよいのは、法人契約で、送った内容を学習に使わない設定の鍵だけです(Gemini は有料枠)。
- 送る前に見せる。 送り先と送る内容を、共通の確認ダイアログで見せてから送ります。
- AI の出力は候補にとどめる。 そのまま確定データにはせず、画面で候補として見せ、保存は人が行います。
- 何を送るかは用途ごとに決める。 用途はコードで登録し、プルリクエストのレビューを通ります。
02HOW TO
AI の 提供元と モデルを 選ぶ
対応している提供元は Anthropic(Claude)、Google(Gemini API)、OpenAI(ChatGPT)の 3 つです。どのモデルを使うかは管理者が「企業・メンバー設定」の「AI の設定」で選び、組織の全員が同じ設定を使います。メンバーは設定の内容を見るだけです。
STEPS環境変数で設定する(方式A・既定)
- 提供元の管理画面で API キーを作る
法人契約で、送った内容を学習に使わない設定の鍵を作ります。Anthropic は 1 つのワークスペースに限った鍵にしてください。
- 環境変数に 2 行を足して再起動する
.env.local(クラウドではホスティングの環境変数)にAI_PROVIDERとAI_API_KEYを書き、アプリを再起動します。 - 管理者がモデルを選んで保存する
「設定 → 企業・メンバー設定 → AI の設定」で、プルダウンからモデルを選び「モデルを保存」を押します(冒頭の画面)。画面のモデル一覧は、ダミーの鍵で撮影したため応答をダミーに差し替えています。
AI_PROVIDER=anthropic # anthropic / google / openai
AI_API_KEY=<提供元の API キー>- 1提供元からモデル一覧を取る管理者が AI の設定を開いたとき。組織ごとに 1 分 10 回まで
- 2使えるモデルに絞る画像・PDF を読めて、決まった形(JSON スキーマ)で出力できるもの。廃止予定は末尾に
- 3管理者がプルダウンで選ぶメンバーの画面では一覧を取りに行かない
- 4保存の前に一覧を取り直す選んだ ID が提供元にあるかを確かめる。同じモデルなら書き込まない
- 5組織の設定として保存するai_settings に 1 行。選んだ時点の提供元も記録し、変更を監査ログに残す
環境変数で提供元を替えると、保存済みのモデルは無効として扱い、管理者に選び直してもらう
03DESIGN
設計:API キーは、 環境変数か、 暗号化して 画面から
サーバーの環境変数を触れる人がいない組織のために、管理者が画面から API キーを登録する方式(方式B)も用意しました。画面から鍵を差し替えられるぶん攻撃の入口が増えるため、既定は方式A のままです。どちらにするかは環境変数でしか切り替えられません。ログイン中のアカウントを乗っ取った人が、自分で方式B を有効にして鍵を差し替えることはできません。
方式A(既定)
AI_PROVIDER・AI_API_KEY
鍵の差し替えは環境変数を書き換えて再起動
管理者はモデルを選ぶ
方式B(環境変数で有効にした組織だけ)
ログインパスワードで本人確認し、その鍵で提供元に接続できるかを確かめる
組織と提供元に結び付け、ブラウザからは読めないテーブルに置く
登録・差し替え・削除は管理者だけ
入力
- API キー管理者が画面で入力(平文はサーバーの中だけ)
- 暗号化の鍵環境変数 AI_ENCRYPTION_KEY(32 バイト)。DB の外に置く
- IV保存のたびに 12 バイトの乱数で作り直す
- 追加認証データai-credential:v1:〈組織 ID〉:〈提供元〉
ai_credentials(組織に 1 行)
- 暗号文・IV・認証タグ鍵そのものは保存しない
- keyId暗号化の鍵の SHA-256 の先頭 16 文字
- 末尾 4 文字・更新日時画面に出すのはここだけ
- DB やバックアップだけが漏れても暗号化の鍵が無いので読めない
- 暗号文を別の行に移しても組織と提供元が合わないので復号できない
- 暗号化の鍵を替えたらkeyId が合わず「登録し直してください」と出る
- ブラウザからはテーブルに権限を与えていないので読めない
Supabase Vault や pgcrypto を使わず、アプリのサーバーで暗号化しているのは、鍵の平文が SQL 文に乗ってデータベースのログに残るのを避けるためです。暗号化の鍵の指紋(SHA-256 の先頭 16 文字)を一緒に保存しておくので、暗号化の鍵を替えたときは、復号を試さなくても「登録し直してください」と案内できます。
# 暗号化の鍵は openssl rand -base64 32 で作る(SUPABASE_SERVICE_ROLE_KEY とは別の値)
AI_ALLOW_KEY_REGISTRATION=true
AI_ENCRYPTION_KEY=<openssl rand -base64 32 の出力>
# 任意。画面から登録してよい提供元(未設定なら 3 社すべて)
AI_ALLOWED_PROVIDERS=anthropic,openai04DESIGN
設計:AI への 送信は、 共通の 入口を 一本だけ
AI を使う機能は、共通の入口(generateStructured)だけを呼びます。入口は決まった順番で確かめ、どこかで条件を満たさなければ提供元には送りません。
請求書の読取り・開示文の下書きなど(今後追加)
共通の入口(generateStructured)
- 1用途の確認登録した用途だけが呼べる
- 2入力の確認種類・量。形式は先頭のバイト列で判定
- 3設定とモデル鍵・提供元・管理者が選んだモデル
- 4回数の上限用途ごと・組織全体
- 5提供元へ送信60 秒で打ち切る
- 6結果の検証機能が決めた形かを確かめる
- 7監査ログ鍵・送った内容・出力は残さない
ファイル保管 API は使わない
- 用途ごとに、送ってよい入力の種類(テキスト・PDF・画像)と量(既定 4MB)、回数の上限、出力の上限を決めます。登録していない用途からは、型の段階で呼べません。
- ファイルの形式は、拡張子やブラウザの申告ではなく、先頭のバイト列で判定します(PDF・PNG・JPEG・WebP)。
- 提供元に送るときはツールを渡さず、各社のファイル保管 API も使いません。OpenAI には
store: falseを付けて、応答を保存させません。
- 用途・提供元・モデル・鍵の方式
- 入力の種類と量、SHA-256
- 結果(成功・失敗の分類)とかかった時間
- API キー
- 送った内容(ファイル・文章)
- AI の出力
本文には鍵の一部が含まれることがある
- invalid_key
- billing
- rate_limited
- overloaded
- model_unavailable
- input_rejected
- timeout
- bad_response
- unknown
提供元の本文は画面にもログにも出さない
回数の上限は、監査ログの件数を数えて判定します(用途ごとの 1 分・24 時間と、組織全体の 24 時間に 500 回)。件数を数えられなかったときは、送らない側に倒します。上限は連打やスクリプトによる暴走を止めるためのもので、厳密な課金の上限ではありません。
| 提供元 | 学習への利用 | 提供元での保持 | OpenGreenTrack からの送り方 |
|---|---|---|---|
| Anthropic | 明示の許可なしには使わない | 30 日以内に削除(ポリシー違反と判定されたものは最長 2 年) | 本文に直接入れて送る(ファイル保管 API は使わない) |
| Google(Gemini API の有料枠) | 使わない | 不正利用の監視のため 55 日 | generateContent で送る。無料枠の鍵は使わない |
| OpenAI | 既定では使わない | 不正利用の監視のログは 30 日 | store: false を付けて送る(応答を保存させない) |
05ROADMAP
これから :用途ごとに AI の 機能を 加える
公式ロードマップの次の項目は、請求書の読取り(AI による活動量データの自動入力)です。機能を加えるときは、用途を登録し、共通の入口だけを通して呼びます。開発者向けの決まりは docs/architecture.md の「AI 連携」にまとめています。
- 機能の処理でログインと組織を確かめ、組織 ID はリクエストではなくログイン中のプロフィールから取る
- 利用者が入力した文は指示文に混ぜず、入力として渡す
- 出力の形を決め、値の範囲まで機能側で検証する
- AI の出力は文字として表示し、HTML として解釈しない
06CHANGELOG


