コンテンツへスキップ

システム管理者ガイド

KUKAN は2つのデプロイ方式に対応しています。手軽な Docker Compose(オンプレミス・閉域網向け)、 本番のクラウド向け AWS の順で説明します。

Docker Compose を使ったオンプレミス・閉域網デプロイに対応しています。 本番運用では最新のリリース(vX.Y.Z タグ)の利用を推奨します。

ターミナルウィンドウ
git checkout vX.Y.Z # 最新リリース
cp .env.example .env
# 認証用の秘密鍵を生成
sed -i.bak "s|^BETTER_AUTH_SECRET=.*|BETTER_AUTH_SECRET=$(openssl rand -base64 32)|" .env && rm .env.bak
cp .env.prod.example .env.prod
# .env.prod を編集
docker compose --env-file .env --env-file .env.prod --profile prod up -d --build

アップグレード前にリリースノートで破壊的変更と移行手順を確認してください。

ターミナルウィンドウ
git fetch --tags
git checkout vX.Y.Z # 新しいリリース
docker compose --env-file .env --env-file .env.prod --profile prod up -d --build

データベースのマイグレーションは Worker の起動時に自動適用されます。適用後のデータベースに旧バージョンのイメージを戻せるとは限りません。

アップデートが反映されたかは、管理画面で確認できます(動作中のバージョンの確認。出るのは Web が動かしているリリースです)。

オンプレミス構成では以下の代替サービスを使用します。

AWS サービス オンプレミス代替
S3 MinIO 互換(Compose の既定は pgsty/silo)
OpenSearch PostgreSQL 全文検索

KUKAN は CloudFront(WAF + キャッシュ)→ 内部 ALB → ECS Fargate 構成で AWS にデプロイします。 デプロイは CDK Pipelines(AWS CodePipeline)で自動化され、CodeConnections(GitHub App)をソースに、 対象ブランチへの push を起点に各環境(dev / prd 等)を CDK Stage としてデプロイします。

環境は infra/config/environments.ts で定義します(environments.example.ts をコピーして作成)。 環境はマルチサイト形状(sites 宣言)で作成します。サイトが 1 つでも sites 1 件で 始めておくと、後からのサイト追加が非破壊になります(マルチサイト運用を参照)。 sites を書かず、サイト固有の設定(ドメイン・WAF 等)を env 直下に書くシングルサイト形状は 過去互換として引き続き動作しますが、新規構築では使用しません(両形状の混在は不可)。 全パラメータの一覧は環境設定リファレンスを参照してください。

主要な AWS リソース:

  • CloudFront — CDN・WAF・TLS 終端(最前面)
  • ALB(internal) — ロードバランサー(CloudFront VPC Origin 経由でのみ到達)
  • ECS Fargate — Web アプリケーション + Pipeline Worker
  • Aurora Serverless v2 / RDS — PostgreSQL データベース(ジョブキューもここに置く)
  • S3 — ファイルストレージ
  • Cloud Map — Web が Worker に通知するための名前解決(環境に 1 つのプライベート DNS 名前空間)
  • OpenSearch — 全文検索エンジン
  • AWS Backup — 隔離バックアップ(large スケール等で有効)

環境に deployNotification: true を置くと、その環境のデプロイが終わるたびに成否が Slack に流れます。 省略した環境には通知用のリソースが 1 つも作られません。

webhook URL は Slack のアプリ管理画面 で Create New App(From scratch)→ Incoming Webhooks を有効化 → Add New Webhook to Workspace で投稿先チャンネルを選ぶと発行されます。

貼り先の箱はスタックが作ります。deployNotification: true でデプロイすると、シークレットの ARN が パイプラインスタックの出力(Notify<環境名>SlackWebhookSecretArn)に出ます:

ターミナルウィンドウ
# ARN を取得(<環境名> は environments.ts のキー。Demo のように先頭大文字)
aws cloudformation describe-stacks --stack-name KukanPipeline \
--query "Stacks[0].Outputs[?contains(OutputKey, 'Notify<環境名>SlackWebhookSecretArn')].OutputValue" \
--output text
# 取得した ARN へ webhook URL を一度だけ貼る
aws secretsmanager put-secret-value --secret-id <取得した ARN> \
--secret-string 'https://hooks.slack.com/services/...'

貼るまでの間、通知は何もしません(デプロイは失敗しません)。通知には成否・デプロイしたコミット・ 更新したサイト(domainName があればリンク)・リリースノートへのリンク(リリース時のみ)・ パイプライン実行へのリンクが入ります。

データ保護の設定は scale プリセットに統合されています:

設定 small medium large
S3 バージョニング(誤削除・上書き保護) — ✓ ✓
DB 自動バックアップ保持(任意時点復元) 7日 14日 35日
AWS Backup(隔離保管・長期世代) — — 日次35日 + 月次12ヶ月

アップロードファイルは S3 に保存され、リージョン内の複数アベイラビリティゾーンへ自動複製されます(設計耐久性 99.999999999%)。バージョニング有効時は誤削除・上書きからの復旧も可能です。AWS Backup は S3 と DB のバックアップを独立した Backup Vault に隔離保管し、リソース本体ごと失われる事故や 35 日を超える長期世代に備えます。環境ごとの調整は environments.ts の overrides.backup で行います(awsBackup の有効化には s3Versioning: true が必要)。

ストレージ内のオブジェクトは、書かれ方ごとにプレフィックスで分かれています。すべて同じバケットに 入るため、バックアップ設定は共通です。

プレフィックス そこに書かれるもの
resources/ リソースの正本。差し替えのたびに新しいオブジェクトが増える
previews/ プレビュー Parquet、検索索引用のテキスト
lake/ 行差分のカタログとデータファイル(DuckLake、リソースごと)

プレフィックスはオブジェクトの役割を決めません。 どれが現在の内容でどれが過去の版かは、 データベースのポインタ(resource.storage_key / resource_version.storage_key)が決めます。 オブジェクトが書かれる時点では、それが版になるかどうかまだ決まっていないためです(取得した内容が 前回と同じなら版は作られません)。

  • 現在のファイルも過去の版のファイルも resources/ にあります。 ストレージ使用量はここで 増え、差し替えの回数だけ積み上がります
  • resources/ には、まだ完了していないアップロードや、参照されなくなって回収待ちのオブジェクトも 含まれます

行差分のカタログは、リソースごとの SQLite ファイルとして lake/<リソース ID>/ に置かれます (追加の環境変数はありません)。

いずれのプレフィックスもバックアップの対象から外さないでください。 previews/ と lake/ は 正本から作り直せる派生データです。lake/ は、カタログやそれが読むファイルが欠けていれば、そのリソースの 次の取り込みや差分の表示を機に正本から作り直されます。それ以外の派生をまとめて再生成する運用手順は、 現時点では用意されていません。

CloudFront のアクセスログは、どのサイトでも常に有効です(オプトインリージョン — af-south-1 や ap-east-1 など — に置いた環境を除く。そこでは CloudFront がログを配信できないため作らず、synth で警告を出します)。サイトごとに専用のバケットへ書かれ、 cdnLogRetentionDays(省略時 90 日)が過ぎると消えます。バケット名はスタック出力の CdnLogBucketName で確かめられます。

1 行に 1 リクエストが、次のような項目とともに残ります: アクセス元の IP(c_ip)、User-Agent、 URI とクエリ文字列、ステータス、応答時間(time_taken)、キャッシュに当たったか (x_edge_result_type が Hit / Miss / RefreshHit / Error など)。Cookie は残しません (セッションのトークンを含むため)。

  • ログが届くまで、通常は数分から 1 時間ほどかかります
  • 時刻は UTC です
  • User-Agent とクエリ文字列は URL エンコードされています(Athena では url_decode で戻せます)

Athena のテーブルはサイトごとに、ワークグループは環境に 1 つ、スタックが作ります。名前はスタック 出力で確かめられます。

スタック出力 例(シングルサイト) マルチサイト
CdnLogWorkGroup kukan-prd-logs kukan-prd-logs(全サイト共通)
CdnLogTable kukan_prd_logs.cloudfront kukan_prd_<サイト>_logs.cloudfront

Athena のクエリエディタでこのワークグループを選び、テーブルをクエリします。どのサイトのログを読むかは FROM のデータベース名で決まります。クエリ結果は Athena が管理する領域に置かれるため、結果用の バケットを用意する必要はありません。

アクセスが集中した時間帯の、アクセス元とキャッシュの状態を数える例:

-- 時刻は UTC。JST 10:20〜10:25 なら 01:20〜01:25
SELECT c_ip, url_decode(cs_user_agent) AS ua, x_edge_result_type, count(*) AS n
FROM kukan_prd_logs.cloudfront
WHERE "date" = DATE '2026-01-15' AND time BETWEEN '01:20:00' AND '01:25:00'
GROUP BY 1, 2, 3
ORDER BY n DESC
LIMIT 20;

費用は S3 の料金(保存と書き込み)だけです(配信料はかかりません)。gzip で 1 リクエストあたり 数十〜百バイト程度のため、月 100 万リクエストでも数セントです。Athena は読んだ量に応じた課金 ($5 / TB)です。

CloudFront の追加メトリクス(キャッシュのヒット率など、有料)は有効にしていません。 キャッシュの状態も応答時間もアクセスログにあり、ヒット率はそこから数えられます。WAF のログは、 ルールが数えた・止めたリクエストだけを別に残します(次の「WAF のレート制限」)。

WAF を有効にしたサイト(有効化の手順は下の「セットアップ」手順 4。pipeline で管理する環境では us-east-1 の WebACL を standalone で作り、ARN を貼ります)には、閲覧者の IP ごとに 5 分間の リクエスト数を数えるルールが 2 つ入ります。全リクエスト(静的アセットを除く、既定 2000 件)と サインイン API(既定 100 件)です。既定では数えるだけで止めません。 庁内の NAT のように 1 つの出口の後ろに多くの人がいると、1 人分の上限が組織全体の上限になるためです。

数えた結果を見て、止める(block)に切り替える手順:

  1. CloudWatch(リージョン us-east-1、名前空間 AWS/WAFV2)の CountedRequests を、 Rule = kukan-waf-rate-all / kukan-waf-rate-auth ごとに見ます。0 のままなら何もしません
  2. 今超えている IP は aws wafv2 get-rate-based-statement-managed-keys --scope CLOUDFRONT --region us-east-1 --web-acl-name <名前> --web-acl-id <ID> --rule-name RateLimitAll で引けます(名前と ID は aws wafv2 list-web-acls --scope CLOUDFRONT --region us-east-1)
  3. いつ・どの IP・どの URL が当たったかは、スタック出力 WafLogBucketName のバケットのログに 残ります(数えた・止めた分だけ、Cookie は伏せてあります)
  4. その IP を、上のアクセスログ(c_ip・User-Agent・URL)と、データベースの session 表の ipAddress(その IP からサインインしている利用者がいるか)で照らします。庁内の出口など共有の IP なら waf.rateLimit.exemptIpRanges に足し、そうでなければ waf.rateLimit.mode: 'block' にします
  5. waf の変更は global スタックの standalone デプロイで反映します (npx cdk deploy -c env=prd Prd/KukanGlobalStack。webAclArn を貼った環境では、 一時的に外して流し、戻します。ARN は変わりません)

設定の書き方は環境設定リファレンスの「WAF のレート制限」を参照してください。

セットアップ(初回のみ手動。以降は push で自動デプロイ)

Section titled “セットアップ(初回のみ手動。以降は push で自動デプロイ)”
  1. 環境定義を用意(cp infra/config/environments.example.ts infra/config/environments.ts → environments.ts を編集)。各エントリが1環境=1パイプラインとして作られるため、単一環境なら不要なエントリ(例: dev)を削除する
  2. AWS コンソールで CodeConnections 接続を作成し、Connection ARN を environments.ts のトップレベル connectionArn(全 env 共通の export)に設定
    • CodeBuild を開く → 左メニュー下部の Settings → Connections → Create connection(「Developer Tools」共通設定。CodeBuild 経由が分かりやすい)→ GitHub を選択 → 接続名(例 kukan-github、AWS 側の識別ラベル)を入力 → Connect to GitHub → AWS Connector for GitHub アプリをインストール・認可(Only select repositories を選び、デプロイ対象のリポジトリのみに絞る。最小権限)→ ステータスが Available になったら ARN をコピー
    • GitHub App の認可はブラウザ操作が必須(CLI/CDK で作成しても PENDING になり結局ブラウザ認可が必要)
  3. cdk bootstrap(deploy の前提。各アカウント・リージョン。GlobalStack 用に us-east-1 も含める)
  4. 独自ドメイン/WAF を使う場合のみ: us-east-1 の証明書/WAF を一度 standalone で作成(npx cdk deploy -c env=prd Prd/KukanGlobalStack)し、ARN を各サイトエントリの certificateArn/webAclArn に設定
  5. environments.ts と cdk.context.json をコミット(CodeBuild の synth が checkout から読み込む)
  6. パイプラインスタックを初回デプロイ(npx cdk deploy KukanPipeline)
  7. 以降は各 env の deployBranch への push で自動デプロイ(パイプラインも自己変異で更新)

environments.ts の構造(connectionArn はトップレベル、env 個別設定は environments の中):

infra/config/environments.ts
export const connectionArn = 'arn:aws:codeconnections:...:connection/...' // 手順2の ARN(全 env 共通)
export const environments = {
// account は必須(誤デプロイ防止)。同一アカウントなら全 env に同じ ID を指定
dev: {
account: '000000000000',
scale: 'small',
githubRepo: 'owner/repo',
deployBranch: 'develop',
sites: [{ name: 'main', enableWaf: false }],
},
prd: {
account: '000000000000',
scale: 'large',
githubRepo: 'owner/repo',
deployBranch: 'main',
sites: [{ name: 'main', enableWaf: false }],
},
}

詳細・設計判断はリポジトリの docs/specs/jp/phase4-deploy.md および ADR-030(docs/adr/jp/030-cdk-pipelines-deploy.md)/ ADR-031(docs/adr/jp/031-multi-environment-deploy.md)を参照してください。

ユーザーが1人も存在しない間は自己登録が強制的に有効になり、最初に登録した ユーザーが自動的に sysadmin になります。デプロイ後、ブラウザでサインアップ ページを開いて初回ユーザーを登録してください。

ブラウザを使わずに初期化する場合や、sysadmin が全員いなくなった場合の回復には CLI を使います。

ターミナルウィンドウ
pnpm db:create-user --email admin@example.com --name admin --role sysadmin
オプション 説明 必須
--email メールアドレス Yes
--name ユーザー名(小文字英数字、ハイフン、アンダースコア、ピリオド) Yes
--role user または sysadmin(デフォルト: user) No

パスワードは実行時に入力を求められます(画面には表示されず、確認のため 2 回入力します)。 15 文字以上で推測困難なものが必要です(下記「パスワード強度ポリシー」)。 コマンドライン引数では受け付けません — シェルの履歴や ps に残るためです。 端末のない環境(スクリプトなど)では、環境変数 KUKAN_USER_PASSWORD で渡します。

サイト管理の「動作中のバージョン」に、リリースの版と Node のバージョンが出ます。

AWS・Docker Compose・開発(pnpm dev)のいずれも同じ値を表示します。設定する項目はありません。

版が見えるのはここだけです。未認証で届く応答(ページ、API、CKAN 互換 API、MCP、ヘッダー)と、worker が外部へ名乗る User-Agent には版を出しません。ページの <meta name="generator" content="KUKAN"> は製品名だけで、GENERATOR_META_ENABLED=false(AWS はサイトの generatorMeta: false)で外せます(ADR-070)。

システム管理者(sysadmin)は管理画面からユーザーを管理できます。 有効期限の切れたセッションは、worker が毎時削除します。

  • ユーザーの表示名・役割(user / sysadmin)の変更
  • 自分自身の役割降格は不可(ロックアウト防止)
  • ソフトデリート方式(state を deleted に変更)
  • 削除時に全セッション・API トークンを即時無効化
  • 監査ログ・アクティビティ履歴は保持
  • 削除済みのユーザーは「復活」できます。「完全削除」も選べますが、取り消せません(関連するアクティビティログと監査ログは匿名化されます)

新規ユーザーの自己登録は管理画面(サイト管理 → ユーザー自己登録)で 切り替えます(デフォルト: 無効)。無効の間はシステム管理者が管理画面から ユーザーを作成します。ユーザーが1人も存在しない間は、初期セットアップの ため設定に関係なく自己登録が有効になります。

一部の設定は再デプロイなしに管理画面から変更できます(サイト管理 /dashboard/admin/site と生成AI管理 /dashboard/admin/ai、システム管理者のみ)。変更は DB に保存されて監査ログに残り、反映まで最大 30 秒〜1 分ほどかかります。

画面 設定 内容
サイト管理 検索例クエリ 検索ボックス下に表示するクエリ例
サイト管理 サイトのメタデータ 人口や基準日のように、ブランドのコンポーネントが key で読み出す値(数値・文字列・言語別の文字列・日付)。値はすべて公開 API で読めます。読み出し方は「ブランドカスタマイズ」を参照
サイト管理 ユーザー自己登録 上記「自己登録制御」を参照
生成AI管理 AI による説明の一括生成 → 生成言語 AI による説明を書く言語(日本語 / 英語、既定は日本語)。下記「AI による説明(抄録)」を参照
生成AI管理 AI メタデータ提案 AI メタデータ提案の有効化(キルスイッチ)、生成モデル ID(空欄はプロバイダ既定)、接続テスト
生成AI管理 意味検索 → 検索の設定 意味の近い結果を検索に含めるかどうかと、含める「意味の近さ」の下限。緩めるとヒットが増える代わりにノイズも増え、厳しくすると精度重視になります(要: 埋め込みモデルが利用可能な構成)

サイト管理の「データリセット」は、すべてのデータセット・リソース・組織・グループ・タグ・パイプラインジョブと関連ファイルを完全に削除します(ユーザーアカウントは残ります)。確認のため RESET の入力を求められます。取り消せないため、本番環境では使わないでください。

「お知らせ管理」(/dashboard/admin/announcements)で、トップページに表示するお知らせ(新しい順に 5 件)を作成・編集・削除します。カテゴリーは「お知らせ」「メンテナンス」「新機能」「重要」から選びます。公開日時を空欄にすると下書き、未来の日時にすると予約公開になります。

セマンティック検索(埋め込み)と AI メタデータ提案は、AI_TYPE で選んだプロバイダを使います。

  • AWS: Bedrock(AI_TYPE=bedrock)
  • オンプレミス / 開発: Ollama(AI_TYPE=ollama)または OpenAI 互換(AI_TYPE=openai)
  • 無効: AI_TYPE=none(NoOp)— セマンティック検索はキーワード検索にフォールバックし、AI 提案は利用不可になります

AI メタデータ提案の生成モデルは管理画面(生成AI管理 → AI メタデータ提案)から再デプロイなしで切り替えられます。埋め込みモデルは管理画面からは変えられません — AI_EMBEDDING_MODEL(AWS では environments.ts の bedrock.embeddingModel)で指定し、変更には再デプロイと埋め込みベクトルの再生成が要ります。生成モデルの候補は AI_COMPLETION_MODELS 環境変数(カンマ区切り)で指定します。これはこのデプロイで利用を許可するモデルのリストで、全プロバイダ共通に管理画面ピッカーの選択肢となり、先頭エントリが既定(「プロバイダ既定」)になります。サーバー側で利用可能でも、リストに無いモデルは候補に現れません。Bedrock では CDK が environments.ts の bedrock.completionModels(IAM で InvokeModel を許可したモデル)からこの変数を注入するため、候補を増やす場合はそこに追加して再デプロイしてください。Ollama では Docker Compose の ollama-init が列挙された全モデルを起動時に pull するため、リストのモデルは自動で利用可能になります。未設定時は組み込み既定モデルのみが候補になります(Ollama: gemma4:e4b / OpenAI 互換: gpt-4o-mini)。Ollama を GPU で動かす手順は開発環境セットアップを参照してください。

AI 提案が動かないとき(Bedrock)

Section titled “AI 提案が動かないとき(Bedrock)”

生成AI管理の「AI メタデータ提案」で 接続テストを押すと、実際の生成と同じ経路(構造化出力)で 1 回だけ試行し、失敗時はエラーと対処のヒントを表示します。Bedrock 特有の典型的な原因と対処:

症状(接続テストのエラー) 原因 対処
not authorized to perform: bedrock:InvokeModel タスクロールに当該モデルの IAM 権限がない environments.ts の bedrock.completionModels に追加して再デプロイ
use case details have not been submitted Anthropic の利用ユースケースフォーム未提出 Bedrock コンソールで Anthropic の「利用ユースケース詳細」フォームを提出(アカウントに一度・約15分で有効化)
aws-marketplace:Subscribe 系の AccessDenied Marketplace 提供モデルがアカウント未サブスクライブ 下記「Marketplace モデルの初回サブスクライブ」の手順で一度 invoke して有効化。組織で SCP により制限されている場合は、管理アカウント側で aws-marketplace:Subscribe / ViewSubscriptions の許可が必要(AdministratorAccess でも SCP は上書きできません)

これらはいずれもアプリ外(AWS 側)の設定で、コンソールでの一度きりの作業です。Claude 等の Anthropic モデルはフォーム提出と Marketplace サブスクライブの両方が必要になる点に注意してください。既定の生成モデル(Claude Haiku 5.5)も Anthropic のモデルなので、モデルを指定しない配備でも必要です(Amazon Titan / Nova はどちらも不要 — 初回呼び出しで自動有効化されます)。

Marketplace モデルの初回サブスクライブ

Section titled “Marketplace モデルの初回サブスクライブ”

Cohere Embed v4 のような AWS Marketplace 提供モデルは自動有効化の対象外で、アカウント全体で使えるようにするには AWS Marketplace 権限を持つユーザーが一度だけ呼び出す必要があります。いずれかの方法で 1 回呼び出せば、以後はデプロイ済みのタスクロールからも利用できます(伝播に数分)。

  • コンソール: Bedrock → モデルカタログ(Model catalog) で対象モデルを開き、プレイグラウンド(Playground) で任意の入力を 1 回実行する。有効化済みの一覧は AWS Marketplace の「Manage subscriptions」で確認できます。

  • CLI(同じことを 1 コマンドで):

    ターミナルウィンドウ
    aws bedrock-runtime invoke-model --region ap-northeast-1 \
    --model-id cohere.embed-v4:0 --content-type application/json \
    --body '{"texts":["test"],"input_type":"search_document"}' /dev/stdout

埋め込みモデルを切り替えた場合は、既存データに反映するため埋め込みベクトルの再生成が要ります(下記「検索インデックスの再処理」)。

リソースを登録するたびに、そのファイルの内容を読んだ短い説明を AI に書かせ、リソースページに表示できます。利用者が原本を開かずに中身を判断できるようにするためのもので、同時に検索の手掛かりにもなります(リソース単位の埋め込みに入ります)。

有効化は「書かせるモデルを指定する」ことだけです。 指定すると有効になり、指定しなければ何も生成されず費用もかかりません。AWS では environments.ts の bedrock.summaryModel、Docker Compose では環境変数 AI_SUMMARY_MODEL で指定します。

// AWS(infra/config/environments.ts)— CDK がここから AI_SUMMARY_MODEL を注入します
bedrock: {
completionModels: [
'jp.anthropic.claude-haiku-5-5',
'jp.anthropic.claude-sonnet-4-6',
],
summaryModel: 'jp.anthropic.claude-haiku-5-5',
}
ターミナルウィンドウ
# Docker Compose(.env)
AI_SUMMARY_MODEL=jp.anthropic.claude-haiku-5-5

抄録用のモデルには生成モデルの許可リストに含まれるものを指定します。生成言語の方はランタイム設定 ai-summary-locale(ja / en、既定 ja)です — 言語は無料、モデルは費用、という分け方です。言語は、生成AI管理の一括生成カードの「生成言語」で切り替えます(API では PUT /api/v1/admin/settings/ai-summary-locale、本文 {"value":"en"})。

言語を変えても既存の抄録は書き直されません。保存するとカードの見積もりが新しい言語で数え直されるので、書き直すには続けて「すべて作り直す」を実行します。

一括生成(生成AI管理 → AI による説明の一括生成)

Section titled “一括生成(生成AI管理 → AI による説明の一括生成)”

通常は登録時に自動で生成されるため、操作は要りません。このカードは、設定を入れる前からあるリソースや、モデル・プロンプト版・生成言語が変わって書き直しが要るものをまとめて処理するためのものです。外部 URL の再取得は行いません。

操作 対象
不足分を生成 説明がまだ無いリソースだけ
すべて作り直す 上記に加えて、別のモデル・プロンプト版・生成言語で書かれた説明も書き直す

どちらも押す前に「対象 N 件・推定 入力 X〜Y / 出力 Z トークン(概算 $低〜$高)」が表示されます。入力トークンが幅を持つのは、PDF のトークン数がページ数で決まり、ページ数はここからは見えないためです(下限 1 ページ・上限はページ上限)。

説明を書いたリソースから順に、埋め込みベクトルも作り直されます。同じ内容に対して二度実行しても、生成済みかどうかを照合するため費用は増えません。

生成AI管理の一番上の「使用量と費用」カードに、AI の呼び出しが使ったトークンと、その概算費用が出ます。設定は要りません。AI を使う構成(AI_TYPE が none 以外)なら、すべての呼び出しが自動で記録されます。

用途 呼び出し
AI による説明の生成 リソース 1 件ごとの説明の生成
メタデータ提案 AI メタデータ提案
接続テスト AI メタデータ提案カードの接続テスト
リソースの埋め込み 意味検索用の埋め込みベクトルの生成
検索クエリの埋め込み 意味検索を使う検索(MCP からの検索も含む)

カードには次の内容が出ます。

  • 今月の概算費用と月末の着地見込み。着地見込みは、今月これまでの費用を経過時間で月末まで延ばした値です。月初の 1 日が過ぎるまでは表示しません(1 回の呼び出しを 30 日分に延ばすと、実際とかけ離れた額になるため)。
  • 推移のグラフ。時間(直近 48 時間)・日(今月と先月)・月(直近 12 か月)を切り替えられます。用途・モデル・プロバイダ別に色分けし、費用とトークンも切り替えられます。日と月の区切りは環境変数 TIME_ZONE(既定 Asia/Tokyo)に従います。
  • 内訳の表。回数、入力・出力・キャッシュのトークン数、費用です。

費用は、呼び出した時点の定価による USD の概算です。消費税や割引契約は含みません。記録した時点の単価で計算した費用を記録と一緒に保存するので、単価が後で変わっても過去の月の金額は動きません。

プロバイダ 費用
Bedrock KUKAN に同梱した単価表から計算します。jp.* 推論プロファイルの 1.1 倍も含みます
Ollama 0(ローカルのモデルのため)。トークン数は記録します
OpenAI 互換 出しません(互換サーバーの多くはトークン単位で課金しないため)。トークン数は記録します

単価表に無いモデルの呼び出しは、0 円とは数えず、「単価が分からないため費用に含まれていない回数」として別に表示します。単価表は KUKAN の更新で入ります。新しいモデルを使い始めたのに単価不明の回数が増えるときは、KUKAN を更新してください。

実際の請求額と突き合わせるときは、AWS の Cost Explorer を使います。Bedrock の Claude はモデルごとに別のサービス名(例: Claude Haiku 5.5 (Amazon Bedrock Edition))で計上されます。

API でも同じ集計を取れます: GET /api/v1/admin/ai-usage?granularity=hour|day|month(システム管理者のみ、既定は day)。

索引や派生データは、それぞれの対象を扱う管理画面から作り直せます。「検索インデックスの再構築」は「インデックス管理」、「埋め込みベクトルの再生成」は「生成AI管理」の「意味検索」カード、「全リソースの再処理」は「リソースの処理状況」の画面にあります。全リソースの再処理はパイプラインを流し直す操作なので、進み具合をその画面で追えます。いずれもジョブキュー経由の非同期処理で、投入後はバックグラウンドで順次実行されます。

操作 作り直すもの 外部 URL の取得 実行するとき
検索インデックスの再構築 メタデータ索引。スイッチを入れると本文の索引も(解釈はやり直さない) しない 検索結果に不整合があるとき。アップグレードで検索文書の項目や本文の索引の作り方が変わったとき(解析設定の変更は下記の再解析)(POST /api/v1/admin/reindex-metadata)
全リソースの再処理 保存済みファイルのテキスト抽出・プレビュー・索引 未取得のものだけ 本文検索やプレビューが欠けているとき。リソース数に比例して時間がかかります。実行中はもう一度押せません
埋め込みベクトルの再生成 意味検索用のベクトル しない セマンティック検索を後から有効にしたとき、埋め込みモデルを変えたとき(POST /api/v1/admin/reindex-embeddings)。内容が変わっていないものはスキップされます。意味検索の対象外になっているリソースがある間は、ダッシュボードにも案内が出ます(下記)
検索インデックスの再解析 索引そのもの(解析設定ごと) しない 検索の解析設定が更新されたとき。画面に案内が出たときだけ(下記)
本文の検索インデックスの作り直し 本文の索引(以前の大きな単位で入っている分) しない 本文を読む単位が小さくなったとき。画面に案内が出たときだけ(下記)。中身は「検索インデックスの再構築」をスイッチを入れて実行するのと同じ

通常はどれも不要です。メタデータの索引はデータセットの作成・更新・削除のたびに自動で更新され、本文とプレビューはパイプラインが処理した時点で作られます。同期を取りこぼしたものも、毎時の定期再投入(と Worker 起動後の 1 回)で拾われます。

検索の解析設定(日本語の形態素解析や、形式の大文字・小文字をそろえる設定など)を更新したリリースへ上げると、ダッシュボードに再解析の案内が出ます。解析方法はインデックス作成時に決まるため、既存のインデックスは作り直さないと新しい解析が効きません。上の「再構築」は同じ索引に文書を送り直す操作で、解析方法は変わらないため、これだけは再解析でしか反映されません。

保存済みのテキストを読み替えるだけで、外部 URL の取得もファイルの再処理も行いません。更新時の一度きりの操作で、完了すると案内は表示されなくなります(POST /api/v1/admin/search/reanalyse)。

本文の検索インデックスの作り直し

Section titled “本文の検索インデックスの作り直し”

検索が本文を読む単位(チャンク)を小さくしたリリースへ上げると、ダッシュボードに本文の検索インデックスの作り直しの案内が出ます。単位は本文を索引に入れるときに決まるため、内容が変わっていないリソースは、作り直すまで以前の大きな単位のままです。そのままでも検索はできますが、本文での検索と箇所の検索が軽くなるのは、作り直したリソースからです。

案内には、以前の単位で入っているリソースの件数が出ます。「作り直す」を押すと、「インデックス管理」の「検索インデックスの再構築」を、「ファイルの本文の索引も作り直す」を入れて実行するのと同じ処理が始まります。すべてのリソースの本文を、保存済みの解釈から索引し直します。外部 URL の取得も、ファイルの解釈のやり直しもしません(解釈が今のファイルに追いついていないリソースだけは、解釈からやり直します)。

作り直しの間も、各リソースは順番が来るまで、データセットの検索には今の索引のまま出ます。箇所の検索(MCP の search_passages)には、作り直したリソースから出ます。削除済みのリソース、公開中でないデータセットのリソース、本文を索引しない形式、保存済みのファイルが無いリソースの本文は、作り直さずに索引から消します。件数は処理が進むにつれて減り、完了すると案内は表示されなくなります。進み具合は「バックグラウンド処理状況」の「本文の索引の作り直し(リソース)」で確認できます。

「バックグラウンド処理状況」(/dashboard/admin/queue)には、ジョブキューにあるジョブが並びます。データの取り込み、メタデータの検索インデックス同期、埋め込みベクトルや AI による説明の生成、削除など、裏で実行される処理はすべてジョブキューを通ります。

上の表は、処理の種類ごとに状態別の件数を数えたものです。

  • 列は処理が進む順に「予約 → 待機 → 処理中 → 打ち切り」です。「予約」は実行時刻がまだ来ていないジョブで、失敗して再試行を待っているものもここに入ります
  • 行は、何が処理を起こすかで「日常の処理」「管理者の操作・自動復旧」「システム更新時の移行」に分かれます(どれにも当たらない種類があれば「その他」)。種類は「処理(対象)」の形で表示されます(例: 「パイプラインの実行(リソース)」「版の削除(リソース)」)
  • 管理者のボタンが積んだパイプラインの実行は、「日常の処理」と分けて「管理者の操作・自動復旧」に出ます。「全リソースの再処理(リソース)」と「本文の索引の作り直し(リソース)」です
  • 件数を押すと、その種類と状態のジョブが下の一覧に出ます(開いた直後は「予約」)

画面はタブが表示されている間 5 秒ごとに更新され、更新ボタンでもすぐ読み直せます。

3 回失敗したジョブは「打ち切り」になり、30 日間残ります(毎時の見回りで消えます)。打ち切りのジョブは一覧から「再投入」(試行回数を 0 に戻して実行し直す)か「削除」ができます。削除すると対象の処理は行われませんが、処理中の版の削除と組織の完全削除は 1 時間以内に積み直されます。完全削除したデータセットの差分取り込みデータの削除を消した場合は、下記「ストレージの回収」の照合ツールで回収できます。

WORKER_WAKE_URL が設定されていないと、web が積んだジョブは worker の次の起動か毎時の見回りまで待機のままになります(下記「環境変数」)。

再処理と違い、移行のときに一度だけ実行する操作です。ダッシュボードに残件数が表示され、0 になると項目自体が消えます。

意味検索の対象になっていないリソースがある間、ダッシュボードに案内が表示されます。埋め込みはベクトルが無いと検索が失敗せずに黙ってキーワードのみへ縮退するため、気づく手立てとして案内を出しています。

出るのは主に 2 つの場合です。埋め込みの単位をリソースへ移したリリースへ上げた直後(既存のベクトルは作り直しが必要です)と、埋め込みモデルを変えたときです。通常の編集直後には出ません — 埋め込みの未反映フラグが立ってから 15 分以内のリソースは数に入れないためです。

案内から実行する処理は、上の表の「埋め込みベクトルの再生成」と同じものです。

バージョン管理より前からあるリソースには版が付いていません。ダッシュボードの「バージョンの補完」を実行すると、各リソースの現在のファイルを v1 として記録し、表形式のものを差分表示に取り込みます。再取得も再インデックスも行いません(GET /api/v1/admin/version-backfill-status / POST /api/v1/admin/backfill-versions)。以前のリリースで取り込んだ行差分を、リソースごとのカタログへ移す処理も兼ねます。

層ごとの内訳と、旧方式の巻き戻しの変換についてはデータ管理者ガイドを参照してください。

OData 配信(利用者ガイド)より前に作られたプレビューには、1 回に読み出す行のまとまり(行グループ)に何行入っているかが記録されていません。この値が無いと、配信は安全側に倒して 1 ページを小さく切るため、列の多い表や文字数の多い表が「配信できない」と断られることがあります。

残件がある間、ダッシュボードに「BI ツールへの配信を整える」が出ます。実行すると、保存済みのプレビューを読んで行数を記録します。公開元からの再取得は行いません(GET /api/v1/admin/row-group-status / POST /api/v1/admin/record-row-groups)。

古い設定で作られた一部のプレビューは、記録だけでは足りず作り直しになります。これも保存済みのファイルから行うため再取得は発生せず、対象の件数は実行前にダッシュボードに出ます。

急ぐ操作ではありません。実行しなくても配信そのものは動きます — 断られる表が実力より多いだけです。

外部 URL リソースの死活監視を自動で行います。

  • 定期的なスケジューラーによる自動チェック(既定では 5 分ごとに、24 時間以上確認していない外部 URL を HEAD で確認。変更を検知したものは取り込み直し、変更を判定できないものも 168 時間ごとに取り込み直す)
  • 管理画面(ヘルスチェック)からヘルスチェック結果の確認
  • エラーリソースの特定と対応

間隔は HEALTH_CHECK_CRON / HEALTH_CHECK_STALENESS_HOURS / HEALTH_CHECK_FULL_FETCH_INTERVAL_HOURS で変えられます(下記「環境変数」)。

差し替えなどで参照されなくなったオブジェクトは台帳に記録され、毎時のスイープが保持期間の経過後に 削除します。削除の直前にもう一度「まだ誰か指しているか」を確認するため、通常の運用で操作は要りません。

台帳が導入されたのはバージョン管理と同じリリースです。それ以前に処理の中断で取り残された オブジェクトは、どの記録にもポインタにも名前がありません。 該当するのはこのリリースより前から 運用していた環境だけで、回収するにはバケットを一覧する必要があるため、手動のツールを用意しています。 データセットの完全削除の後片付けのジョブが失われたときの lake/ も、同じツールで回収します。

デプロイ済みのコンテナ内(本番のデータベースとバケットに届く場所)で実行します。

ターミナルウィンドウ
node apps/worker/dist/reconcile-orphans.js # 報告のみ
node apps/worker/dist/reconcile-orphans.js --commit # 台帳へ登録

チェックアウトからは次のように実行します。

ターミナルウィンドウ
pnpm --filter @kukan/worker reconcile-orphans
pnpm --filter @kukan/worker reconcile-orphans -- --commit
  • 既定は報告のみです。対象の鍵が一覧で出るので、--commit の前に目を通してください
  • --commit も削除はしません。 台帳に登録するだけで、実際に消すのは毎時のスイープです。 スイープは削除の直前に参照を確認し直すので、一覧を取った後にポインタが着いたオブジェクトは 残ります。判断を誤っても失うのは台帳の行であってファイルではありません
  • 24 時間以内に書かれたオブジェクトは対象外です。書き込み途中のオブジェクトは、一覧からは 取り残しと区別が付かないためで、これらは tooRecent として報告されます
  • 報告の nominated と tooRecent が両方 0 になるまで繰り返します。 一度で終わるとは限りません
  • 対象は resources/、previews/、lake/ です。lake/ は、リソースがもう存在しない lake/<リソース ID>/ だけを対象にします(データセットの完全削除の後片付けのジョブが、実行される前に 失われたとき)。存在するリソースの中は書き込みのたびに片付けられ、lake/main/(以前の形式)は 対象外です

Excel・Word・PowerPoint の原本は、既定では ibisOffice が閲覧者の ブラウザの中で描きます。サーバーでも外部のサービスでも文書を開かないので、閉域網や非公開のデータ セットでも原本が表示できます。worker の処理や既存のデータには関係しないので、再処理は要りません。

OFFICE_PREVIEW_VIEWER(AWS はサイトの officePreviewViewer)で切り替えます。

値 原本を描くもの 表示できるもの
ibis-office(既定) ibisOffice(ブラウザの中) XLSX・XLS・DOCX・PPTX・PPT。非公開・下書きを含む。DOC は抽出テキストのみ
office-online Microsoft の Office Online Viewer 公開のデータセットで 10 MB 以下。DOC を含む。Microsoft のサーバーがファイルを取りに来るので、アップロードしたファイルは、IP 制限や Basic 認証のあるサイト、閉域網では表示できない(外部 URL のリソースは、その URL が公開なら表示できる)
  • ビルド: web のビルドが、ibisOffice の Web 版を上流の GitHub リリースから取って SHA-256 を照合します (apps/web/vendor/ibis-office/manifest.json に版と SHA-256)。動いているサービスは GitHub に行きません。 GitHub に届かない閉域網でビルドするときは、同じ版の ibisOffice-<版>-Web.zip を先に apps/web/vendor/ibis-office/ に置いてください
  • 閲覧者の環境: WebGPU か WebGL2 が要ります。ブラウザのタブは 1 文書で数百 MB から 1 GB を使います。 描けないときや重すぎるときは、抽出テキストへ案内します
  • イメージ: web のイメージが約 65 MB 大きくなります
  • 切り替えの反映: CloudFront にキャッシュされたページは最大 5 分、切り替える前の CSP のままです
  • アクセス制御: IP 制限と Basic 認証は /vendor/ibis-office/ にはかかりません。隔離した iframe は認証情報を 付けずに読み込むためです。配っているのは公開の配布物と起動ページだけです
  • ライセンス: ibisOffice は AGPL-3.0 で、画面に「Powered by ibisOffice」とリンクを表示します。 対応するソースの案内は /vendor/ibis-office/<版>/SOURCE にあります

主要な環境変数の一覧です。詳細は .env.example を参照してください。

変数名 説明 デフォルト
POSTGRES_HOST PostgreSQL ホスト localhost
POSTGRES_PORT PostgreSQL ポート 5432
POSTGRES_DB データベース名 kukan
POSTGRES_USER データベースユーザー kukan
POSTGRES_PASSWORD データベースパスワード kukan
POSTGRES_SSLMODE DB 接続の TLS(disable / require / verify-full)。verify-full は証明書も検証する(AWS では CDK が設定) disable
POSTGRES_SSLROOTCERT verify-full で照合する CA バンドルのパス。未設定なら Node の信頼ストア。AWS では CDK が /etc/ssl/rds-ca.crt を設定 -
S3_BUCKET S3 バケット名 kukan-dev
S3_ENDPOINT S3 エンドポイント(MinIO: http://localhost:9000、AWS: 省略) -
S3_ACCESS_KEY / S3_SECRET_KEY MinIO の認証情報(AWS では省略し IAM ロールを使う) -
SEARCH_TYPE 検索エンジン(opensearch / postgres) opensearch
OPENSEARCH_URL OpenSearch エンドポイント http://localhost:9200
WORKER_WAKE_URL web がジョブ投入を worker に知らせる先(worker の /wake)。未設定だと、ジョブは worker の次の起動か毎時の見回りまで待つ 開発時は http://localhost:8080/wake、それ以外はなし
WORKER_DB_POOL_MAX worker の DB 接続プールの上限。並行数の既定値もここから決まる 5
WORKER_CONCURRENCY worker が同時に処理するジョブの数。未設定なら WORKER_DB_POOL_MAX − 2(最大 4)。メモリに余裕がある環境で増やす 未設定(5 なら 3)
WEB_DB_POOL_MAX web の DB 接続プールの上限 5
BETTER_AUTH_SECRET 認証セッション秘密鍵(必須、32 文字以上。openssl rand -base64 32 で生成) -
BETTER_AUTH_URL 公開 URL http://localhost:3000
PASSWORD_MIN_SCORE パスワード強度の下限(zxcvbn スコア 0〜4)— 下記 3
CLIENT_IP_HEADER ログイン試行の回数制限と、クエリ・OData の呼び出し元ごとの上限がクライアントの IP を読むヘッダー。x-kukan-client-ip は CloudFront の後ろでのみ x-forwarded-for
AI_TYPE AI プロバイダ(none / bedrock / openai / ollama) none
AI_EMBEDDING_MODEL 埋め込みモデル。変えたら埋め込みベクトルの再生成が要る プロバイダ既定(Bedrock: Titan Text Embeddings v2 / Ollama: bge-m3 / OpenAI 互換: text-embedding-3-small)
AI_EMBEDDING_DIMENSIONS 埋め込みの次元数 プロバイダ既定
OPENAI_BASE_URL OpenAI 互換エンドポイントの URL(AI_TYPE=openai) -
OLLAMA_URL Ollama の URL(AI_TYPE=ollama) http://localhost:11435
AI_COMPLETION_MODELS 生成モデルの許可リスト(カンマ区切り)。管理画面ピッカーの選択肢、先頭が既定 -
AI_SUMMARY_MODEL AI による説明を書くモデル。未設定で機能オフ(費用も発生しない)— 上記参照 -
HEALTH_CHECK_ENABLED 外部 URL のヘルスチェックを行うか true
HEALTH_CHECK_CRON ヘルスチェックの実行間隔(cron 式) */5 * * * *
HEALTH_CHECK_STALENESS_HOURS 最後の確認からこの時間が過ぎた外部 URL を確認し直す 24
HEALTH_CHECK_FULL_FETCH_INTERVAL_HOURS 変更を判定できない外部 URL を取り込み直す間隔(時間) 168
LOG_LEVEL ログレベル(trace〜fatal) info
TIME_ZONE 日時を事前描画するタイムゾーン(IANA 名)。ブラウザ側で閲覧者のゾーンに置き換わる Asia/Tokyo
USER_AGENT_URL 外部へ名乗る連絡先。公開サイトのみ(AWS はサイトの nameSiteInUserAgent) -
GENERATOR_META_ENABLED ページに <meta name="generator" content="KUKAN"> を出すか。バージョンは出さない(AWS はサイトの generatorMeta) true
OFFICE_PREVIEW_VIEWER Office 文書の原本を描くもの(ibis-office / office-online)。Office 文書の原本(AWS はサイトの officePreviewViewer) ibis-office
CSP_MODE ページの Content-Security-Policy の出し方(report-only / enforce)。report-only は違反をブラウザのコンソールに出すだけで何も止めない。enforce は止める。どちらでも Office プレビューの frame-src は強制(ADR-071、AWS はサイトの cspMode) report-only

パスワードを設定するすべての経路 — サインアップ、利用者自身による変更、管理画面での ユーザー作成、pnpm db:create-user — に同じ条件が適用されます。

  • 15 文字以上(変更不可)
  • zxcvbn スコアが PASSWORD_MIN_SCORE 以上(既定値 3 =「安全に推測困難」)

PASSWORD_MIN_SCORE を下げると、よく使われる単語の並びやキーボード上の並びが通るように なります。0 では推測困難性の判定そのものが無効になります。