diff --git a/content/docs/configure/ai.ja.mdx b/content/docs/configure/ai.ja.mdx new file mode 100644 index 0000000..4aa258e --- /dev/null +++ b/content/docs/configure/ai.ja.mdx @@ -0,0 +1,145 @@ +--- +title: AI サービス +seoTitle: "AI サービス:モデルプロバイダー、埋め込み、RAG、MCP" +description: ObjectOS の AI を設定する場所。製品内 AI ランタイムのプロバイダー設定、オープンな埋め込みとナレッジのパッケージ、そして MCP サーバー。 +editions: [community, cloud, enterprise] +translation: + source_sha: 4abd19f584761c553296b8acedc8d1af5ea11b1c06ad99a52806921cbf0a033d + guide_rev: 1 + mode: auto +--- + +ObjectOS は、オープンソースの ObjectStack フレームワークに含まれる AI の基本要素(MCP サーバー、Knowledge Protocol とそのアダプター、埋め込み)の上に、**製品内 AI ランタイム**を追加します。データに問い合わせる `ask` アシスタント、作成を支援する `build` アシスタント、そして `/api/v1/ai/*` のチャットエンドポイントです。 + +セルフマネージドのデプロイメント(ObjectOS Enterprise)では、製品内 AI を有効にするのはライセンスです。ライセンスのない単一組織のデプロイメントは Community の動作(オープンな MCP サーバー、AI は自分で用意)で実行され、ライセンスがあれば、AI Builder と「データに質問する」機能が自社のインフラストラクチャ上で有効になります。[Docker → License](/docs/deploy/docker#license) を参照してください。 + +## 何をどこで設定するか [#what-is-configured-where] + +| レイヤー | 設定する場所 | 提供元 | +|---|---|---| +| **チャットのモデルプロバイダー** | `ai` 設定名前空間:**Setup → Configuration → AI & Embedder**、または `OS_AI_*` 環境変数 | ObjectOS | +| **埋め込み** | `@objectstack/embedder-openai`、OpenAI 互換の埋め込み | オープンなフレームワーク | +| **ナレッジ / RAG** | `@objectstack/service-knowledge` とアダプターのプラグイン | オープンなフレームワーク | +| **MCP サーバー** | デフォルトで `/api/v1/mcp` で有効。`OS_MCP_SERVER_ENABLED=false` で無効になります | オープンなフレームワーク | + +## チャットのモデルプロバイダー [#chat-model-provider] + +インストールしたり登録したりする AI パッケージはありません。`@objectstack/service-ai` は 11.0 でオープンな ObjectStack のディストリビューションから外れました。それが提供する AI ランタイムは、オープンソースのフレームワークではなく ObjectOS とともに提供されます。 + +プロバイダー、モデル、認証情報は `ai` 名前空間の設定なので、ほかのすべての設定と同じように解決されます。環境変数は Setup に保存された値より優先され、その値をロックします([System Settings → Resolution order](/docs/configure/system-settings#resolution-order))。 + +| 変数 | 設定するもの | +|---|---| +| `OS_AI_PROVIDER` | プロバイダー。サポートされる値には `gateway`、`openai`、`anthropic`、`google`、`deepseek`、`dashscope`、`cloudflare`、`siliconflow`、`openrouter` が含まれます。 | +| `OS_AI_OPENAI_API_KEY` · `OS_AI_OPENAI_MODEL` · `OS_AI_OPENAI_BASE_URL` | OpenAI、または任意の OpenAI 互換 API(Azure、ローカルのゲートウェイ、サードパーティのエンドポイント)。`OS_AI_PROVIDER=openai` とともに使います。モデルのデフォルトは `gpt-4o` です。 | +| `OS_AI_ANTHROPIC_API_KEY` · `OS_AI_ANTHROPIC_MODEL` | Anthropic。`OS_AI_PROVIDER=anthropic` とともに使います。 | +| `OS_AI_GOOGLE_API_KEY` · `OS_AI_GOOGLE_MODEL` | Google。`OS_AI_PROVIDER=google` とともに使います。 | +| `OS_AI_GATEWAY_MODEL` · `OS_AI_GATEWAY_API_KEY` | Vercel AI Gateway。`OS_AI_PROVIDER=gateway` とともに使います。 | +| `OS_AI_DEEPSEEK_API_KEY`、`OS_AI_DASHSCOPE_API_KEY`…… | プリセットの OpenAI 互換プロバイダーごとに、`_API_KEY` と `_MODEL` の変数が 1 つずつあります。たとえば `OS_AI_DEEPSEEK_MODEL=deepseek-chat` です。 | + +たとえば、Setup を使わずに、デプロイメント全体でサードパーティの OpenAI 互換プロバイダーに固定するには: + +```bash +OS_AI_PROVIDER=openai +OS_AI_OPENAI_API_KEY=sk-... +OS_AI_OPENAI_MODEL=your-model +OS_AI_OPENAI_BASE_URL=https://your-provider.example.com/v1 +``` + +OpenAI 互換のベース URL には `OS_AI_OPENAI_BASE_URL`、または Setup の同じフィールドを使ってください。`OPENAI_BASE_URL` はプラットフォームレベルの変数ではありません。 + +### プロバイダーが設定されていないとき [#when-no-provider-is-set] + +ランタイムは起動時に、最初に見つかった上流の認証情報からアダプターを選びます。 + +1. `AI_GATEWAY_MODEL`(と `AI_GATEWAY_API_KEY`):Vercel AI Gateway を通じて +2. `OPENAI_API_KEY` +3. `ANTHROPIC_API_KEY` +4. `GOOGLE_GENERATIVE_AI_API_KEY` +5. どれもない場合:`MemoryLLMAdapter`。背後に実際のプロバイダーがないエコーモードです。 + +これらは上流の名前のままで、`OS_*` に改名されてはいません。`OS_AI_MODEL` は、OpenAI、Anthropic、Google を直接検出する場合のモデル ID を上書きします。起動後、ランタイムは `ai` 設定名前空間を読み取り、プロバイダーが環境変数または Setup に保存された値から来ている場合はアダプターを差し替えます。 + +### 呼び出す [#calling-it] + +製品内 AI は `/api/v1/ai/*` で提供されます。チャット(JSON またはストリーミング)、補完、環境が提供するモデル、会話です。`@objectstack/client` SDK は、その `ai` 名前空間を通じてこれにアクセスします:`ai.chat`、`ai.chatStream`、`ai.complete`、`ai.models`、`ai.conversations`。宣言的な AI(エージェント、スキル、ツール)については [エージェント](/docs/build/agents)を参照してください。 + +## 埋め込み [#embedders] + +`@objectstack/embedder-openai` は、OpenAI の `POST /v1/embeddings` の形を話す任意のエンドポイントで動作します。OpenAI、Azure OpenAI、DashScope、Zhipu BigModel、SiliconFlow、Doubao、MiniMax、Ollama、または独自のゲートウェイです。**プリセット**は既知のプロバイダーのベース URL を埋め、`baseUrl` はそれ以外の任意のエンドポイントを指します。 + +```ts +import { createOpenAIEmbedder } from '@objectstack/embedder-openai'; + +const embedder = createOpenAIEmbedder({ + preset: 'dashscope', + apiKey: process.env.DASHSCOPE_API_KEY!, + model: 'text-embedding-v3', +}); +``` + +`apiKey` は必須です。[パッケージの README](https://github.com/objectstack-ai/objectstack/tree/main/packages/plugins/embedder-openai) に、各プロバイダーのベース URL と代表的なモデルが記載されています。 + +オープンなフレームワークには、まだ埋め込みを使うナレッジアダプターはありません。`@objectstack/knowledge-memory` と `@objectstack/knowledge-ragflow` は埋め込みのオプションを取りません。 + +## ナレッジ / RAG [#knowledge--rag] + +ナレッジサービスはナレッジのソースを宣言し、返ってくるものを権限でフィルターします。検索そのものはアダプターのプラグインが行います。 + +| アダプター | バックエンド | 向いている用途 | +|---|---|---| +| `@objectstack/knowledge-memory` | プロセス内 | 開発環境とテスト。永続化がないので本番向けではありません | +| `@objectstack/knowledge-ragflow` | [RAGFlow](https://github.com/infiniflow/ragflow) | チャンク分割、埋め込み、ハイブリッド検索、リランキングを RAGFlow が行います | + +オープンなフレームワークでの組み込み方: + +```ts +import { KnowledgeServicePlugin } from '@objectstack/service-knowledge'; +import { KnowledgeRagflowPlugin } from '@objectstack/knowledge-ragflow'; + +kernel.use(new KnowledgeServicePlugin({ + sources: [{ + id: 'product_docs', + label: 'Product documentation', + adapter: 'ragflow', + source: { kind: 'http', urls: ['https://docs.example.com/sitemap.xml'] }, + adapterConfig: { datasetId: 'rgf_doc_dataset_id' }, // RAGFlow dataset to bind + }], +})); +kernel.use(new KnowledgeRagflowPlugin({ + endpoint: process.env.RAGFLOW_ENDPOINT!, // e.g. http://localhost:9380 + apiKey: process.env.RAGFLOW_API_KEY!, +})); +``` + +RAGFlow アダプターはデータセットを作成しません。RAGFlow の UI で一度作成し、そこでチャンク分割の方法、埋め込みモデル、リランクのポリシーを選びます。 + +ソースのレコードを持つすべてのヒットは、呼び出し元の権限に照らして再チェックされます。素の ObjectQL クエリをゲートするのと同じ行レベルセキュリティです。検索を `search_knowledge` ツールとして製品内のチャットに公開するのは、ObjectOS ランタイムの一部です。 + +## MCP:Model Context Protocol [#mcp--model-context-protocol] + +すべての ObjectOS デプロイメントは、すでに `/api/v1/mcp` で [Model Context Protocol](https://modelcontextprotocol.io) を提供しています。デフォルトで有効で、インストールするプラグインはありません。stdio で提供することもできます。クライアントの接続、stdio への切り替え、エージェントが得るツールについては [AI ツールを接続する(MCP)](/docs/configure/mcp)で扱っています。 + +オープンなフレームワークで MCP サーバーのプラグインを明示的に登録するには: + +```ts +import { MCPServerPlugin } from '@objectstack/mcp'; + +kernel.use(new MCPServerPlugin({ + transport: 'stdio', // or 'http' + autoStart: true, +})); +``` + +ツールはオプションごとにオプトインするものではありません。プラグインは起動時に、AI ツールのレジストリ、メタデータサービス、データエンジンを橋渡しします。すべての呼び出しは、呼び出したユーザーの権限のもとで実行されます。 + +## 次に進む [#where-to-go-next] + +- [エージェント](/docs/build/agents):宣言的なエージェント、スキル、ツール +- [AI ツールを接続する(MCP)](/docs/configure/mcp):外部のクライアントをアプリに向ける +- [システム設定](/docs/configure/system-settings):設定がどう解決され、環境変数が何をロックするか +- [セキュリティとコンプライアンス](/docs/reference/security):AI のデータの流れがどう分離されるか +- [`@objectstack/embedder-openai` のソース](https://github.com/objectstack-ai/objectstack/tree/main/packages/plugins/embedder-openai) +- [`@objectstack/service-knowledge` のソース](https://github.com/objectstack-ai/objectstack/tree/main/packages/services/service-knowledge) +- [`@objectstack/knowledge-ragflow` のソース](https://github.com/objectstack-ai/objectstack/tree/main/packages/plugins/knowledge-ragflow) +- [`@objectstack/mcp` のソース](https://github.com/objectstack-ai/objectstack/tree/main/packages/mcp) diff --git a/content/docs/configure/api-access.ja.mdx b/content/docs/configure/api-access.ja.mdx new file mode 100644 index 0000000..fc33fec --- /dev/null +++ b/content/docs/configure/api-access.ja.mdx @@ -0,0 +1,134 @@ +--- +title: API アクセス +seoTitle: "API アクセス:REST API、API キー、OAuth 2.1" +description: 生成される REST API、認証、そして連携のための API キー。 +editions: [community, cloud, enterprise] +translation: + source_sha: a72f24d7ae89d8f75070cc97fdd3cdf51529b9631945d044776aa7e84ea0283c + guide_rev: 1 + mode: auto +--- + +成果物で宣言されたすべてのオブジェクトは、生成された REST API を通じて公開されます。同じエンドポイントが UI、連携、顧客の ETL スクリプトを支えています。保守すべき別の「連携用 API」はありません。 + +## ベース URL [#base-url] + +```text +https:///api/v1 +``` + +主なエンドポイント: + +| パス | 目的 | +|---|---| +| `/api/v1/data/` | 各オブジェクトの生成された CRUD(例:`/api/v1/data/account`) | +| `/api/v1/data//{id}` | 単一のレコードの読み取り / 更新 / 削除 | +| `/api/v1/actions//` | 宣言的なアクションの呼び出し(POST) | +| `/api/v1/auth/*` | 認証(サインイン、セッション、OAuth、OIDC) | +| `/api/v1/meta/*` | 有効な場合のメタデータ API(オブジェクト、フィールド、ビュー) | +| `/api/v1/keys` | 呼び出したユーザーのために、一度だけ表示される `sys_api_key` を発行します(POST) | +| `/api/v1/batch` | オブジェクトをまたぐトランザクションのバッチ(POST)。アトミックのみで、すべての操作がオブジェクトごとにゲートされます | +| `/api/v1/mcp` | Streamable HTTP による Model Context Protocol サーバー。デフォルトで有効で、`OS_MCP_SERVER_ENABLED=false` で無効にできます | +| `/api/v1/health` | 稼働 / 準備状態のプローブ(認証なし) | + +プレフィックスのデフォルトは `/api/v1`(API の `basePath` である `/api` と `version` の `v1`)で、ObjectOS のスタックで設定できます。 + +## 公開するものを制御する [#controlling-whats-exposed] + +API の公開は、ゲートウェイではなく、成果物の中でオブジェクトごとに管理されます。 + +- オブジェクトに `apiEnabled: false` を設定すると、REST の画面から完全に外れます(そのルートは 404 になります)。 +- `apiMethods` のホワイトリスト(例:`['get', 'list']`)を設定すると、オブジェクトを読み取り専用にしたり、到達できる操作をほかの形で制限したりできます。 + +どちらも REST レイヤーで強制されます。[REST API → Restricting the API surface](/docs/reference/rest-api#restricting-the-api-surface) を参照してください。 + +同じゲートがトランザクションのバッチのルートにも適用されます(16.0)。`POST /api/v1/batch` は本文を検証し、トランザクションを開く*前に*、**すべての**操作について `apiEnabled` / `apiMethods` を強制し、更新 / 削除には ID を要求し、解決できない `{ $ref }` の親参照を拒否します。このルートはアトミックのみです。`atomic: false` は `400 BATCH_NOT_ATOMIC` で拒否されます。アトミックでない一括処理は、オブジェクトごとの `createMany` / `updateMany` エンドポイントに残ります。 + +## 認証の方法 [#authentication-options] + +呼び出し元は 4 つの方法で認証できます。 + +| 方法 | 最適な用途 | 方法の詳細 | +|---|---|---| +| セッション Cookie | ブラウザ / UI のトラフィック | `/api/v1/auth/*` でサインインします。Cookie のスコープはプロジェクトのホスト名です | +| Bearer アクセストークン | モバイル、SPA、短時間のサーバージョブ | `/api/v1/auth/sign-in/email` で認証情報を交換し、`Authorization: Bearer ` を渡します | +| API キー | サーバー間、ETL、長期間の連携 | `sys_api_key` を作成し、Bearer トークンとして渡します | +| OAuth 2.1(MCP) | サインインしたユーザーとして動作する AI エージェント / MCP クライアント | デプロイメント自身に対する、セルフサービスの認可コード + PKCE フロー | + +いずれも同じ `AuthPlugin` を通り、`SecurityPlugin` が権限とレコードアクセスに照らして評価する `sys_user` のコンテキストに解決されます。 + +## API キー [#api-keys] + +API キーは第一級の `sys_api_key` レコードです。キーの値そのものはハッシュ化して保存され、クエリできるのは `prefix` とメタデータだけなので、漏洩したキーをデータベースから復元することはできません。 + +キーは次の 2 つの方法のどちらかで発行します。 + +- **Setup**:管理者として **Setup → API Keys** にサインインし、所有するユーザーを選び、必要に応じて有効期限を設定し、表示されたシークレットを**一度だけ**コピーします。 +- **セルフサービスのエンドポイント**:`POST /api/v1/keys` は認証された呼び出し元のためにキーを発行し、生のシークレットをちょうど一度だけ返します。キーは呼び出し元自身のユーザーに固定されるので、別のアイデンティティになりすますために使うことはできません。 + + ```bash + curl -X POST https://app.example.com/api/v1/keys \ + -H "Authorization: Bearer " \ + -H "Content-Type: application/json" \ + -d '{"name": "etl-pipeline"}' + # → { "id": "...", "name": "etl-pipeline", "prefix": "os_pk_…", "key": "os_pk_live_…" } + ``` + +以降のリクエストでは、キーを Bearer トークン、`x-api-key` ヘッダー、または `Authorization: ApiKey` として渡します。REST のデータ API とメタデータ API はいずれも、MCP と同じ検証器でキーを認証し、キーの所有者の権限とレコードレベルのセキュリティのもとで処理します。 + +```bash +curl https://app.example.com/api/v1/data/account \ + -H "x-api-key: os_pk_live_…" +``` + +キーを失効させるには、対応する `sys_api_key` レコードで `revoke_api_key` アクションを実行します(Setup でも利用できます)。失効は次のリクエストから即座に有効になります。 + +### キーは組織に属する(ObjectStack 17.1) [#keys-belong-to-an-organization-objectstack-171] + +キーは呼び出し元の**アクティブな組織**に対して発行されます。`POST /api/v1/keys` は組織のパラメータを取らないので、組織をまたぐキーはなく、発行時に呼び出し元のメンバーシップが再チェックされます。単一組織のデプロイメントでは、目に見える変化は何もありません。壁で区切られたテナンシー方式(`OS_TENANCY_POSTURE`、[環境変数](/docs/reference/environment-variables#multi-organization-deployments)を参照)のもとでは、どのキーが引き続き機能するかが決まります。 + +| キー | `group` | `isolated` | +|---|---|---| +| 17.1 以降に発行され、所有者がまだその組織のメンバーである | 機能する | 機能する | +| その後、所有者がキーの組織を離れた | 拒否 | 拒否 | +| 17.1 より前に発行された(組織を持たない) | 機能する | 拒否。再発行してください | + +17.1 より前に発行されたキーに、後から組織が補完されることはありません。 + +## MCP クライアントと OAuth 2.1(ObjectStack 13+) [#mcp-clients--oauth-21-objectstack-13] + +OAuth に対応した MCP クライアント(Claude.ai のカスタムコネクタ、Claude Desktop、Claude Code)はどれも、管理者が API キーを発行しなくても**セルフサービス**で接続できます。 + +- 各デプロイメントは(組み込みの認証インスタンスに支えられた)独自の認可サーバーとして動作し、RFC 8414 / RFC 9728 の検出、動的なクライアント登録(RFC 7591)、認可コード + PKCE、`/api/v1/mcp` へのリソースのバインディングを備えます。TLS が必要です(localhost は除く)。 +- ユーザーは本人としてサインインし、ツールの呼び出しはその人自身の権限と行レベルセキュリティのもとで実行されます。 +- OAuth のスコープは厳格な権限の上限を定めます(ObjectStack 14.5):`effective_permission = scope_ceiling ∩ user_grants`。`data:read` は読み取り専用のデータアクセスを、`data:write` は完全な CRUD を付与し、機能でゲートされた業務アクションには `actions:execute` が必要です。スコープが欠けているトークンは安全側に倒れて失敗します。 + +API キーは、CI とヘッドレスのエージェントのための並行する手段として残ります。`x-api-key` と `Authorization: Bearer osk_…` は変わらず機能します。 + +## ページネーション、フィルター、並べ替え [#pagination-filtering-and-sorting] + +生成されたリストのエンドポイントは、ObjectStack の標準のクエリパラメータを受け付けます。 + +| パラメータ | 意味 | +|---|---| +| `?limit=` | ページサイズ(サーバー側の上限に従います) | +| `?offset=` または `?cursor=` | ページネーション | +| `?filter=` | ObjectQL のフィルター構文によるサーバー側のフィルター | +| `?sort=` | 並べ替えの式(例:`-created_at`) | +| `?fields=` | 一部のフィールドの選択 | + +フィルターの完全な文法はフレームワークのドキュメントを参照してください。ランタイムの文法が正です。 + +## レート制限 [#rate-limiting] + +フレームワークの `RateLimiter` プリミティブ(またはイングレス / API ゲートウェイ)を使って、IP ごととアイデンティティごとの制限を適用します。推奨される初期のバケットは[本番環境への準備](/docs/operate/production)に記載されています。 + +## CORS [#cors] + +呼び出し元が別のオリジンのブラウザで実行される場合は、イングレスまたはランタイムのミドルウェアで CORS を設定します。ワイルドカードのオリジンと認証情報付きのリクエストを組み合わせ**ないで**ください。 + +## OpenAPI / 検出 [#openapi--discovery] + +対応する機能がイメージに含まれている場合、ランタイムは生成された REST API の OpenAPI ドキュメントを提供できます。オブジェクトの名前と生成されたルートはデプロイされた成果物に従うので、顧客の連携では URL を手で組み立てるのではなく、デプロイメントごとの OpenAPI ドキュメントからクライアントを生成すべきです。 + +検出は `capabilities.transactionalBatch`(16.0)も通知するので、クライアントは `404`/`405`/`501` を探りに行く代わりに、接続時に宣言的にアトミックなバッチのルートを検出できます。 diff --git a/content/docs/configure/authentication.ja.mdx b/content/docs/configure/authentication.ja.mdx new file mode 100644 index 0000000..d1fc91f --- /dev/null +++ b/content/docs/configure/authentication.ja.mdx @@ -0,0 +1,146 @@ +--- +title: 認証 +seoTitle: "認証:OAuth、OIDC/SSO、デバイスフロー" +description: サインイン、セッション、OAuth、OIDC/SSO、デバイスフローを設定します。 +editions: [community, cloud, enterprise] +translation: + source_sha: f5ecbdd5472f71c9839f722534cf88e4aba12301b053b26ef38e7fa713fc91f3 + guide_rev: 1 + mode: auto +--- + +ObjectOS は、Better Auth を基盤とする ObjectStack の認証プラグインを使います。認証はプロジェクトごとに閉じています。各プロジェクトが独自のアイデンティティのテーブルとセッションのスコープを持ちます。 + +## サポートされるもの [#what-is-supported] + +パッケージ化されたアプリケーションと有効にした設定に応じて、ObjectOS は次のものをサポートできます。 + +- メール / パスワードによるサインイン +- セッションの管理 +- パスワードのリセットとメールアドレスの確認 +- Google、GitHub、Microsoft、Apple などのソーシャル OAuth プロバイダー +- Okta、Entra ID、Keycloak、Ping などのエンタープライズ OIDC/SSO +- 二要素認証 +- パスキー / WebAuthn +- マジックリンク +- SMS の OTP による電話番号でのサインイン(オプトイン) +- CLI / ブラウザのデバイスフロー + +## 誰がサインアップできるか(ObjectStack 17.3+) [#who-may-sign-up-objectstack-173] + +セルフ登録は**デフォルトで閉じています**。誰が自分のアカウントを作成できるかは、**Setup → Authentication → Audience** という 1 つの設定で決まります。 + +| Audience | サインアップできる人 | +|---|---| +| `invite_only`(デフォルト) | 保留中の招待を持つアドレスだけ | +| `email_domain` | 許可したドメインのアドレス。完全一致で、大文字と小文字は区別しません。サブドメインには個別のエントリが必要です | +| `open` | 誰でも | + +Audience は、セルフサービスのすべての経路を判定します。メール / パスワードによるサインアップ、ソーシャルプロバイダーによる初回サインイン、マジックリンク、OTP、電話です。拒否されたサインアップは `403 SELF_REGISTRATION_CLOSED`(`email_domain` のもとでは `403 EMAIL_DOMAIN_NOT_ALLOWED`)で応答します。登録を開くには 2 つのルールが伴います。 + +- `email_domain` と `open` のどちらにも、**セルフ登録用の権限セット**が必要です。セルフ登録した各人が受け取るセットです(`member_default` は問題ありませんが、`admin_full_access` は拒否されます)。 +- どちらもメールアドレスの確認を有効にします。`email_domain` では常に、`open` ではデプロイメント自身の設定で無効にしない限りです。 + +*Email and password* の下にある **Allow self-service registration** のトグルは Audience を上書きしません。Audience が `invite_only` なら、そのトグルがオンでもサインアップは閉じたままです。 + +自分で人を作成することは、Audience で決してゲートされません。招待、**Create User**、一括インポート、エンタープライズ SSO は、どの設定のもとでも機能します([ユーザー](/docs/configure/users#add-people)を参照)。新規インストールの一番最初のアカウントも例外です。 + +> **17.2 以前からのアップグレード:** 以前は、Audience が宣言されていなければ、メール / パスワードによるサインアップが開いていることを意味していました。今は `invite_only` を意味し、アップグレード時に何も失敗しません。開いたサインアップに頼っていたデプロイメントは、単にそれを受け付けなくなります。維持するには、(セルフ登録用の権限セットとともに)`open` を選んでください。 + +Audience は**メンバーシップのポリシー**(**Setup → Authentication → Membership**、または `OS_AUTH_MEMBERSHIP_POLICY`。[環境変数](/docs/reference/environment-variables#multi-organization-deployments)を参照)とは別の判断です。Audience は、そもそも誰かがユーザーになれる*かどうか*を決め、メンバーシップのポリシーは、新しいユーザーが*どの組織*に参加するかを決めます。 + +## 電話でのサインインと SMS(ObjectStack 14.3+) [#phone-sign-in--sms-objectstack-143] + +電話番号による認証は `auth.plugins.phoneNumber` の設定で有効にします。有効にすると: + +- `POST /sign-in/phone-number` が電話番号 + パスワードを受け付けます。 +- SMS の OTP がサインインの確認とセルフサービスのパスワードリセットをカバーします。番号ごとのクールダウン、直近 1 時間ごとの上限、IP ごとのレート制限があります。 +- `sys_user` に一意の `phone_number` と `phone_number_verified` の列が追加されます。電話番号だけのアカウントには仮のメールアドレスが付きます。 + +SMS の配信は `@objectstack/plugin-sms` が提供し、Aliyun SMS、Twilio、または開発用のログへのフォールバックを、`sms` 設定名前空間で設定します。OTP のコードを含むメッセージ本文が永続化されたりログに記録されたりすることはありません。通知も `notify(channels: ['sms'])` で `sms` チャネルを対象にできます。 + +## 管理者によるユーザー管理(ObjectStack 14.3+) [#admin-user-management-objectstack-143] + +プラットフォームの管理者は、メールの招待フローなしにアカウントをプロビジョニングできます。 + +- `POST /api/v1/auth/admin/create-user` はユーザーを直接作成します。省略可能なワンタイムパスワード(一度だけ返され、永続化されません)を付けられます。`must_change_password` フラグは初回サインイン時の変更を強制します(変更するまで 403 `PASSWORD_EXPIRED`)。 +- `POST /api/v1/auth/admin/import-users` は、行 / CSV / XLSX(1 リクエストあたり最大 500 行)を、ドライランと、メールアドレスまたは電話番号による upsert のモードで一括インポートします。既存のユーザーのパスワードがリセットされることはありません。16.0 以降、デフォルトの `passwordPolicy` は `'auto'` です。配信可能なチャネル(実在のメールアドレス + 接続済みのメールサービス、または電話番号 + SMS の招待経路)を持つ行は**招待され**、届かない行だけが一時パスワード(一度だけ返され、`must_change_password`)を受け取ります。アイデンティティだけを作る旧来のデフォルトに頼っていた呼び出し元は、今は `passwordPolicy: 'none'` を明示的に渡さなければなりません。行ごとの結果は `rows[].delivery` にあり、`summary.delivery` に内訳があります。 + +## 必要なシークレット [#required-secret] + +次を設定します。 + +```bash +OS_AUTH_SECRET=replace-with-a-strong-random-secret +``` + +ObjectOS は、この値とプロジェクトの環境 ID から、安定したプロジェクトごとのシークレットを導き出します。つまり: + +- セッションはコンテナの再起動を越えて残ります。 +- あるプロジェクトのトークンを別のプロジェクトで再利用することはできません。 +- `OS_AUTH_SECRET` をローテーションすると、セッションは無効になります。 + +旧来の `AUTH_SECRET` エイリアスを含む、認証関連の設定の完全な一覧は[環境変数](/docs/reference/environment-variables)を参照してください。 + +## セッションの分離 [#session-isolation] + +複数プロジェクトのデプロイメントでは、Cookie はプロジェクトのホスト名にスコープされます。ObjectOS は、プロジェクトのセッションにルートドメイン全体の Cookie を使うことを意図的に避けています。これにより、セッションが顧客のプロジェクトをまたいで漏れることを防ぎます。 + +## ソーシャルログイン [#social-login] + +アプリケーションのパッケージが認証の設定をどう公開しているかに応じて、プロバイダーの認証情報を環境変数またはシステム設定で構成します。 + +プロバイダーのコールバック URL は、プロバイダーの種類によって異なります。ObjectStack は 2 つの異なるコールバックのパスを公開しており、それらは相互に置き換えられ**ません**。 + +| プロバイダーの種類 | コールバックのパス | +|---|---| +| 組み込みのソーシャル(Google、GitHub、Microsoft、Apple など) | `/api/v1/auth/callback/` | +| 汎用の OIDC / OAuth2(Okta、Entra ID、Keycloak、Ping など) | `/api/v1/auth/oauth2/callback/` | + +例: + +```text +https://crm.example.com/api/v1/auth/callback/google +https://crm.example.com/api/v1/auth/callback/microsoft +https://crm.example.com/api/v1/auth/oauth2/callback/okta +https://crm.example.com/api/v1/auth/oauth2/callback/entra +``` + +ObjectOS でプロバイダーを有効にする前に、アイデンティティプロバイダーのアプリケーション登録で、対応するリダイレクト URI を設定してください。 + +## エンタープライズ OIDC/SSO [#enterprise-oidcsso] + +OIDC プロバイダーは汎用の OAuth2 プロバイダーとして登録され、`/api/v1/auth/oauth2/callback/` のパスを使います。典型的な設定には次のものが必要です。 + +| フィールド | 説明 | +|---|---| +| Provider id | `okta` や `entra` などの安定した ID(コールバック URL で使われます) | +| Display name | ユーザーに表示されるボタンのラベル | +| Discovery URL | `.well-known/openid-configuration` のエンドポイント | +| Client id | アイデンティティプロバイダーが発行したアプリケーションのクライアント ID | +| Client secret | 環境変数または暗号化された設定に保存されるシークレット | +| Scopes | 通常は `openid email profile` | + +顧客のデプロイメントでは、認可 / トークン / userinfo のエンドポイントを手で設定するよりも、OIDC の検出 URL を優先してください。 + +## プラットフォーム SSO [#platform-sso] + +クラウドに接続されたデプロイメントでは、ObjectOS はコントロールプレーンのログインをプラットフォームの SSO プロバイダーとして使えます。すでにコントロールプレーンにサインインしているビルダーは、プロジェクトローカルのアカウントを別に作成しなくても、プロジェクトのランタイムにプロビジョニングされます。 + +これには、コントロールプレーンと ObjectOS が同じ `OS_AUTH_SECRET` の基本シークレットを共有している必要があります。プラットフォーム SSO を無効にするのは、顧客がすべてのプロジェクトに完全に独立したログインの境界を持たせたい場合だけにしてください。 + +## 運用上のチェック [#operational-checks] + +本番の前に: + +- 期限切れのトークンが `401` を返すことを確認します。 +- サインアップの Audience が、アカウントを作成できるべき人と一致していることを確認します。 +- ログアウトがアクティブなセッションを失効させることを確認します。 +- ポリシーで求められている場合、パスワードのリセットがほかのセッションを失効させることを確認します。 +- コールバック URL が公開されているプロジェクトのドメインと一致していることを確認します。 +- 信頼済みのオリジンに承認済みのドメインだけが含まれていることを確認します。 +- `OS_AUTH_SECRET` がソースではなくシークレットマネージャーに保存されていることを確認します。 + +## 次のステップ [#next-steps] + +認証はユーザーが*誰か*を確立します。サインイン後に*何に*アクセスできるかを制御するには、[権限](/docs/configure/permissions)を参照してください。ブラウザ以外のクライアントとマシン間のアクセスについては、[API アクセス](/docs/configure/api-access)を参照してください。 diff --git a/content/docs/configure/data-sources.ja.mdx b/content/docs/configure/data-sources.ja.mdx new file mode 100644 index 0000000..4e9cfd7 --- /dev/null +++ b/content/docs/configure/data-sources.ja.mdx @@ -0,0 +1,206 @@ +--- +title: データソース +seoTitle: "データソース:オブジェクトを外部データベースにバインドする" +description: ObjectOS を既存の業務データベースに接続し、オブジェクトをそこにルーティングし、AI にそのデータをネイティブに問い合わせさせます。 +editions: [community, enterprise] +translation: + source_sha: decc627733034d98402da3945707ce26b5eab5e2301f74e0d58eb74b5bb81301 + guide_rev: 1 + mode: auto +--- + +**データソース**は、外部のデータストアへの名前付きの接続です。データソースを宣言することで、ObjectOS を業務ですでに稼働しているデータベース(本番の PostgreSQL、レポート用の MySQL レプリカ、MongoDB クラスター)に向け、そこにオブジェクトをバインドします。オブジェクトがバインドされると、プラットフォームのほかのすべて(REST API、権限、フロー、ダッシュボード、そして **AI エージェント**)が、行が物理的にどこにあるかを気にせず、そのデータに対して一様に動作します。 + +これは ObjectOS の最も実用的な導入経路の 1 つです。レガシーシステムを移行する代わりに、それに接続し、関心のあるテーブルをオブジェクトとしてモデル化し、データをまったくそのままの場所に置いたまま、その上で **AI ネイティブな機能**(チャット、分析、自動化)**によって拡張します**。 + +## データソースとは [#what-a-datasource-is] + +各データソースは、`DatasourceSchema` で検証されるプレーンなオブジェクトです。中核となるフィールド: + +| フィールド | 目的 | +|---|---| +| `name` | オブジェクトが参照する一意な識別子(`^[a-z_][a-z0-9_]*$`) | +| `label` | 人が読める表示名 | +| `driver` | 接続を扱うドライバー(`postgres`、`mysql`、`sqlite`、`mongodb`、`memory`、またはプラグインが提供するドライバー) | +| `config` | ドライバー固有の接続設定(ホスト、データベース、認証情報など) | +| `pool` | コネクションプールのサイズ(`min`、`max`、タイムアウト) | +| `schemaMode` | 誰がスキーマを所有するか:`managed`(デフォルト)は ObjectOS にテーブルの作成と変更を許します。`external` または `validate-only` は、ObjectOS が所有せず DDL を実行しないデータベースであることを宣言します | +| `external` | 外部データソースのフェデレーションのポリシー(書き込みのゲートと起動時の検証)と、どのデータソースも持てるシークレットストアへの参照 `credentialsRef` | +| `active` | 接続が有効かどうか | + +`readReplicas`、`capabilities`(とその `readOnly` フラグ)、`healthCheck`、`retryPolicy` は ObjectStack 17.0 で削除されました。どのランタイムの経路もそれらを読んでいなかったからです。パースはそれぞれを拒否し、実際にその動作を決める仕組みを示します。 + +提供されているドライバー: + +| ドライバーのパッケージ | `driver` | バックエンド | +|---|---|---| +| `@objectstack/driver-sql` | `postgres`、`mysql`、`sqlite` | PostgreSQL、MySQL、SQLite(knex 経由) | +| `@objectstack/driver-mongodb` | `mongodb` | MongoDB | +| `@objectstack/driver-memory` | `memory` | プロセス内、テスト用。ObjectStack 17.7 以降、起動時のストアではありません | +| `@objectstack/driver-sqlite-wasm` | `sqlite`(WASM) | WebContainers / ブラウザ内の SQLite | + +## データソースを宣言する [#declaring-datasources] + +データソースはスタックで宣言し、`defineStack` で組み立てます。各接続を `defineDatasource()` で定義し、`datasources` の下に列挙します。 + +```ts +// src/datasources/business.datasource.ts +import { defineDatasource } from '@objectstack/spec'; + +// Connect to an EXISTING production database that ObjectOS does not own. +// `external` mode: ObjectOS runs no DDL here, and writes stay off until you +// opt in. The password is never inline: it lives in the secrets store, and +// the datasource only references it. +export const BusinessDb = defineDatasource({ + name: 'business_primary', + label: 'Business System (Postgres)', + driver: 'postgres', + schemaMode: 'external', + config: { + host: 'db.internal.example.com', + port: 5432, + database: 'business', + username: 'objectos_readonly', // a database user granted SELECT only + }, + external: { + allowWrites: false, // the default: the datasource refuses writes + credentialsRef: 'secret:business_db/password', + }, + pool: { min: 1, max: 10 }, + active: true, +}); +``` + +```ts +// objectstack.config.ts +import { defineStack } from '@objectstack/spec'; +import * as objects from './src/objects/index.js'; +import { BusinessDb } from './src/datasources/business.datasource.js'; + +export default defineStack({ + manifest: { + id: 'app.example.crm-extend', + namespace: 'biz', + version: '1.0.0', + type: 'app', + name: 'CRM extension', + }, + datasources: [BusinessDb], + objects: Object.values(objects), +}); +``` + +> **`defineDatasource()` は書いた場所で検証します。** `@objectstack/spec`(と `@objectstack/spec/data`)からエクスポートされており、宣言の時点で `DatasourceSchema` の検証を実行するので、不正なフィールドはそれを含むファイルで報告されます。フレームワークの `examples/app-crm` スタックは、この方法でデータソースを宣言しています。`Datasource` 型(`@objectstack/spec/data` から)を付けたプレーンなオブジェクトも受け付けられ、スタックが組み立てられるときに検証されます。 +> +> **認証情報は決してインラインにしません。** `DatasourceSchema` は `config` 内の `password` を、環境変数から読んだものであっても拒否します。データソースは `sys_metadata` にまるごと保存されるので、インラインのシークレットはそこに平文で残ってしまいます。シークレットはシークレットストアに置き、`external.credentialsRef` でその名前を指定してください。解決されたシークレットは接続時に注入されます。 + +## オブジェクトをデータソースにバインドする [#binding-objects-to-a-datasource] + +すべてのオブジェクトは `datasource` フィールドを持ちます。デフォルトは `'default'`(プライマリデータベース)です。特定のオブジェクトを接続済みのシステムのいずれかにルーティングするには、これを設定します。 + +```ts +import { ObjectSchema, Field } from '@objectstack/spec/data'; + +export const Customer = ObjectSchema.create({ + name: 'biz_customer', + label: 'Customer', + sharingModel: 'private', + datasource: 'business_primary', // ← queries go to the business DB + external: { remoteName: 'customers' }, // the remote TABLE name + fields: { + name: Field.text({ label: 'Name', required: true }), + email: Field.text({ label: 'Email' }), + tier: Field.select({ + label: 'Tier', + options: [ + { label: 'Standard', value: 'standard' }, + { label: 'Premium', value: 'premium' }, + ], + }), + }, +}); +``` + +> **オブジェクトがバインドするデータソースは接続できなければならず、できなければ起動は失敗します。** ObjectStack 17.0 以降、到達できないデータソースは警告の行ではなく起動の失敗です。以前は、`validation.onMismatch: 'fail'` を持つ `external` データソースだけがすぐに失敗していました。`datasource: 'analytics'` を宣言してオブジェクトをそれにバインドしたアプリは、誤った URL で起動してもきれいに起動して終了コード 0 を返し、その後、それらのオブジェクトのすべての読み書きで `Datasource 'x' is not registered` となって失敗していました。データドライバーが応答しなくなると `/api/v1/ready` も **503** を報告するので、データベースがなくなったレプリカは、エラーを返し続ける代わりにローテーションから外されます。接続の試行は 10 秒で打ち切られます。[17.0 のリリースノート](https://objectstack.ai/docs/releases/v17)を参照してください。 + +### `datasourceMapping` による集中ルーティング [#centralized-routing-with-datasourcemapping] + +オブジェクトを 1 つずつバインドするのは、少数なら問題ありません。名前空間やパッケージ全体については、スタックでルーティングのルールを一度宣言します。ルールは順番に(または `priority` によって)評価され、最初に一致したものが採用されます。 + +```ts +// A second connection, for reporting. +export const AnalyticsReplica = defineDatasource({ + name: 'analytics_replica', + label: 'Analytics replica', + driver: 'postgres', + schemaMode: 'external', + config: { + host: 'replica.internal.example.com', + port: 5432, + database: 'business', + username: 'objectos_reports', + }, + external: { credentialsRef: 'secret:analytics_db/password' }, +}); + +export default defineStack({ + datasources: [BusinessDb, AnalyticsReplica], + datasourceMapping: [ + { namespace: 'biz', datasource: 'business_primary' }, + { objectPattern: 'report_*', datasource: 'analytics_replica' }, + { package: 'com.example.logs', datasource: 'default' }, + { default: true, datasource: 'default' }, + ], +}); +``` + +ルールは `namespace`、`package`、`objectPattern`(glob)、または `default` で一致し、対象の `datasource` を指定します。これにより、データレジデンシーの判断がオブジェクトのファイルに散らばらず、1 か所にまとまります。 + +## 既存のテーブルからオブジェクトを生成する [#generating-objects-from-existing-tables] + +テーブルごとにオブジェクトを手で書く必要はありません。現在、レガシーのスキーマを ObjectOS に取り込む最も手早い方法は、**コーディングエージェント(Claude Code)を使って業務テーブルをスキャンし、ソースレベルのオブジェクト定義を生成すること**です。テーブルごとに 1 つの `*.object.ts` ファイルで、フレームワークが期待するとおりの形です。 + +[`hotcrm`](https://github.com/objectstack-ai/hotcrm) リファレンスアプリは、その形の正式な例です。各テーブルは `ObjectSchema.create({ … })` と `Field.*` の定義を使う `src/objects/.object.ts` ファイルで、すべてが `defineStack` で組み立てられます。典型的な流れ: + +1. 業務データベースをデータソースとして**接続します**(上記)。 +2. **Claude Code をスキーマに向けます。** 接続したデータベース(テーブル名、列、型、外部キー)をイントロスペクトし、テーブルごとに 1 つの `ObjectSchema.create` ファイルを生成するよう頼みます。SQL の列は `Field.*` の型に、外部キーは `Field.lookup(...)` に対応付けます。各オブジェクトの `datasource` を接続に設定し(または `datasourceMapping` に任せ)、テーブル名がオブジェクト名と異なる場合は `external.remoteName` を設定します。 +3. 生成されたオブジェクトを**確認して改善します**。ラベル、フィールドのグループ、検証、権限を追加します。出力は、`hotcrm/src/objects/*.object.ts` と同じく、あなたが所有してコミットする通常のソースです。 +4. **実行します。** オブジェクトは、バインドしたデータソースを通じて既存のテーブルを読むようになります。起動時、ランタイムは各オブジェクトをそのテーブルに照らしてチェックし(`external.validation`)、デフォルトでは不一致があると起動が失敗します。書き込みは、2 つのゲート、つまりデータソースの `external.allowWrites: true` **と**オブジェクトの `external.writable: true` が両方開くまでオフのままです。 + +生成されたオブジェクトはプレーンなソースなので、完全に制御できます。合うものは残し、公開したくない列は外し、プラットフォームが所有する必要のなかったデータベースの上に ObjectOS の機能(履歴の追跡、アクティビティ、共有ルール)を重ねられます。 + +## クエリのプッシュダウン [#query-pushdown] + +何をデータベースで実行し、何をエンジンが評価するかは、データソースのメタデータではなく、各ドライバー自身が決めます。フェデレーションされたオブジェクトに対するフィルター(たとえば `?tier=premium`)は、リモートのクエリにプッシュダウンされます。 + +調整すべき `capabilities` ブロックはありません。何もそれを読んでいなかったため、ObjectStack 17.0 で削除されました。機能を宣言しても実行される経路が変わることはなく、その `readOnly` フラグが書き込みを止めることもありませんでした。読み取り専用のアクセスについては、[セキュリティに関する注意](#security-notes)を参照してください。 + +## 接続したデータに対する AI [#ai-over-connected-data] + +テーブルがオブジェクトとしてモデル化されると、**AI レイヤーは追加の手間なくそれらに対して動作します**。ObjectOS のエージェントとツール(`list_objects`、`describe_object`、`query_records`、`aggregate_data`、そしてデータチャットのエージェント)はすべて ObjectQL を通り、ObjectQL が各オブジェクトをバインドされたデータソースにルーティングします。つまり: + +- ユーザーは、レガシーの業務システムにあるデータについて**自然言語で質問でき**、答えは実際の行に対して計算されます。 +- ツールの呼び出しとクエリは**呼び出したユーザーの権限**に従います。AI が、サインインしたユーザーに許されている以上のものを見ることはありません。 +- オブジェクトがプライマリデータベースに支えられていても外部の業務システムに支えられていても、同じエージェント、フロー、ダッシュボードが動作します。 + +チャットとエージェントのレイヤーの組み込み方については [AI サービス](/docs/configure/ai)と[エージェント](/docs/build/agents)を、`default` データソースを支えるプライマリデータベースの設定については[ランタイム](/docs/configure/runtime)を参照してください。 + +## セキュリティに関する注意 [#security-notes] + +- **認証情報を決してインラインにしないでください。** 上のように、パスワードはシークレットストアに置き、`external.credentialsRef` で参照します。 +- 書き込むつもりのないシステムには**読み取り専用のデータベースユーザーを使います**。`SELECT` だけを付与してください。そうすれば、その接続を通じてデータベースに届くものは、ObjectOS の内外を問わず書き込めません。外部データソースでは、`external.allowWrites: false`(デフォルト)が ObjectOS 自身のクエリの経路でも書き込みを拒否します。`readOnly` キーはありません。以前存在したものは書き込みをゲートしたことがなく、ObjectStack 17.0 で削除されました。 +- **権限で範囲を絞ります。** オブジェクトレベルとフィールドレベルの権限は、ネイティブのオブジェクトとまったく同じように、接続したデータにも適用されます。 + +## 製品内の外部データソースのフェデレーション [#in-product-external-datasource-federation] + +上の流れ(データベースに接続し、オブジェクトをモデル化し、コーディングエージェントで生成する)は、**ターンキーのフェデレーション**の上で動きます。[ADR-0015](https://github.com/objectstack-ai/objectstack/blob/main/docs/adr/0015-external-datasource-federation.md)(ステータス:*Accepted*)で規定された `schemaMode: 'external'` は**現在提供されています**。ObjectOS が所有していないテーブルにオブジェクトをバインドし、その周りに検証のゲートを置きます。デフォルトで読み取り専用で、まだ初期段階です。成熟しているのは読み取りの経路だと考えてください。 + +これは、その機能を所有するフレームワークのドキュメントで一度だけ説明されています:[External Datasources (Federation)](https://objectstack.ai/docs/data-modeling/external-datasources)。 + +## 次に進む [#where-to-go-next] + +- [ランタイム](/docs/configure/runtime):`default` の背後にあるプライマリデータベース +- [AI サービス](/docs/configure/ai):チャット、埋め込み、RAG、MCP +- [エージェント](/docs/build/agents):オブジェクトに対する宣言的なエージェント +- [データモデル](/docs/build/data):`ObjectSchema.create` による作成のインターフェース +- [`examples/app-crm` のデータソース](https://github.com/objectstack-ai/objectstack/tree/main/examples/app-crm/src/datasources):実際のデータソース + ルーティングの例 diff --git a/content/docs/configure/email.ja.mdx b/content/docs/configure/email.ja.mdx new file mode 100644 index 0000000..d56fa39 --- /dev/null +++ b/content/docs/configure/email.ja.mdx @@ -0,0 +1,57 @@ +--- +title: メール +seoTitle: "トランザクションメール:トランスポートとテンプレート" +description: トランザクションメールの配信プロバイダーとテンプレートを設定します。 +editions: [community, cloud, enterprise] +translation: + source_sha: 1ee2df65cf5765f43f4943d79c3f093362a542e7d3fc30bc4a3e6f7789e3a43c + guide_rev: 1 + mode: auto +--- + +ObjectOS は、アプリケーションが必要とするとき(パスワードのリセット、招待、承認の通知)に、フレームワークのメールプラグインを通じてトランザクションメールを送ります。スケジュールされたレポートのメールはありません。ObjectStack 17.5 でスケジュールされたレポートの配信は削除され、代わりの機能はありません。プラグインには 3 つのトランスポートが付属しています。 + +## トランスポート [#transports] + +| プロバイダー | 使う場面 | 必要な環境変数 | +|---|---|---| +| `log` | ローカル開発。メールを送らずに標準出力にログとして出します | なし | +| `resend` | Resend による SaaS の到達性 | `OS_EMAIL_API_KEY` | +| `postmark` | Postmark による SaaS の到達性 | `OS_EMAIL_API_KEY` | + +デフォルトは `log` です。実際のプロバイダーが設定されていても API キーが指定されていない場合、ObjectOS は log トランスポートにフォールバックします。本番以外の環境が誤ってメールを送るのを防ぐのに役立ちます。 + +### SMTP はどうか [#what-about-smtp] + +ネイティブの SMTP トランスポートは、現在ランタイムに組み込まれて**いません**。環境が SMTP を必要とする場合(企業のリレー、オンプレミスのメール、エアギャップのデプロイメント)は、本番に耐える 2 つの選択肢があります。 + +1. **ObjectOS の前段で SMTP から API へのリレーを実行します。** Resend、Postmark、そしてセルフホストの代替(Postal、Cuttlefish)はいずれも SMTP の受信を受け付け、HTTP API で再送信します。ObjectOS は通常どおり HTTPS でそれらと通信します。 +2. **カスタムのメールプラグインとともにランタイムを実行します。** メールプラグインの API は小さく(`send(message)` 関数が 1 つ)、`nodemailer` をラップするプロジェクトのプラグインは `requires` リストで組み込めます。spec リポジトリの[プラグイン作成ガイド](https://github.com/objectstack-ai/spec)を参照してください。 + +ネイティブの SMTP トランスポートはロードマップにあります。進捗は [github.com/objectstack-ai/objectstack/issues](https://github.com/objectstack-ai/objectstack/issues) で追跡してください。 + +## 環境変数 [#environment-variables] + +| 変数 | 目的 | +|---|---| +| `OS_EMAIL_PROVIDER` | `log`、`resend`、または `postmark` | +| `OS_EMAIL_API_KEY` | プロバイダーの API キー(Resend または Postmark) | +| `OS_EMAIL_FROM` | デフォルトの送信元アドレス。`addr@x` と `Name ` の両方の形式をサポートします | +| `OS_EMAIL_RETRIES` | 送信失敗時のトランスポートの再試行回数(デフォルト `0`) | + +環境変数は、成果物の `email` 設定ブロックの対応する値を上書きするので、運用者は成果物を再ビルドせずに配信先を変更できます。 + +## テンプレート [#templates] + +再利用できるテンプレートは `sys_email_template` にあります。テンプレートは、フレームワークのテンプレートエンジンが評価する変数の埋め込みをサポートします。アプリケーションのコード(またはフロー)は、テンプレート ID と変数の束を指定してメールサービスを呼び出し、サービスが件名と本文を具体化して、設定されたトランスポートに渡します。 + +## 配信を確認する [#verifying-delivery] + +Resend / Postmark では、送信ドメインがプロバイダーのダッシュボードで設定されていること(SPF、DKIM、必要に応じて DMARC)を確認します。エンドツーエンドで最も手早く確認するには、Setup のメール設定ページにある **Send test email** アクションを使います。稼働中のトランスポートを使い、トランスポートのエラーをその場に表示します。 + +## 運用のガイダンス [#operational-guidance] + +- API キーはシークレットとして扱います。顧客のシークレットマネージャーに保存し、決して成果物には入れません。 +- トランスポートのエラーログを監視します。プロバイダーのレート制限、配信停止、バウンスはすべてそこに現れます。 +- 監査上重要なトランザクションメール(パスワードのリセット、MFA のチャレンジ)は、顧客のポリシーに従って保持します。保持期間はトランスポートではなく監査ログに設定してください。 +- 外向きのメールは業務トランザクションをブロックしません。送信の失敗はエラーとして表示されますが、元のレコード変更をロールバックすることはありません。 diff --git a/content/docs/configure/index.ja.mdx b/content/docs/configure/index.ja.mdx new file mode 100644 index 0000000..53076db --- /dev/null +++ b/content/docs/configure/index.ja.mdx @@ -0,0 +1,74 @@ +--- +title: 設定 +seoTitle: "設定:ユーザー、アクセス、各種設定" +description: システム管理者がユーザー、アクセス、設定、連携を管理する場所と、どのページがどのタスクに答えるか。 +editions: [community, cloud, enterprise] +translation: + source_sha: dc1a105142d4b26d331b4288248309f185672ffa2b1986e5f8d36afc521562e4 + guide_rev: 1 + mode: auto +--- + +このセクションは、ObjectOS デプロイメントの**システム管理者**向けです。ユーザーを迎え入れ、アクセスを付与し、サインイン、メール、ストレージ、連携を設定し、システムを健全に保つ人のことです。あなたは日々、人とその権限を管理します。アプリケーション、オブジェクト、権限セットそのものは、プラットフォームとインストールしたアプリパッケージとともに提供されます。 + +## Setup と Studio [#setup-and-studio] + +**権限は Studio で設計し、Setup で割り当てます。** この一文は、製品全体を貫く区分の正式な表明であり、権限だけについてのルールではありません。Setup は稼働中のデプロイメントを*運用*し、Studio はそのデプロイメントが実行するメタデータを*作成*します。どちらも `/_console/` の同じ UI の中にあり、どちらも独立した画面ではありません。 + +| | Setup | Studio | +|---|---|---| +| 答える問い | 誰がここにいて、何をしてよいか? | このアプリは何で構成されているか? | +| 場所 | `/_console/apps/setup` | `/_console/studio` | +| ゲート | `setup.access` | `studio.access` | +| 対象 | システム管理者 | 導入担当者と開発者 | + +ほとんどの管理作業は Setup から出ることはありません。Studio に入るのは、権限セットを作成するときか、explain エンジンを実行するときだけです。 + +## Setup アプリ [#the-setup-app] + +組み込みの管理アプリは **`/apps/setup`** にあり、`setup.access` 権限が必要です。左側のナビゲーションは、読み込まれている機能プラグインが実行時に提供するので、表示されるメニューはデプロイメントが実行しているものを正確に反映します。無効になっている機能は何も提供せず、そのグループは空のままです。 + +安定したナビゲーションのグループ: + +| グループ | そこにあるもの | +|---|---| +| **Overview** | System Overview ダッシュボード | +| **People & Organization** | Users、Business Units、Teams、Organizations、Invitations | +| **Access Control** | Positions、Permission Sets、Sharing Rules、Record Shares、API Keys | +| **Approvals** | 承認プロセス(承認プラグインが読み込まれている場合) | +| **Configuration** | All Settings、Branding、Authentication、Email、File Storage、AI & Embedder、Knowledge、Feature Flags | +| **Diagnostics** | Sessions、Notification Events、Audit Logs | +| **Integrations** | Webhooks | +| **Advanced** | OAuth Applications、Signing Keys (JWKS)、Identity Links、User Preferences | + +## タスクマップ [#task-map] + +| やりたいこと | 読むもの | +|---|---| +| ユーザーを追加し、組織ツリーを作り、チームを管理する | [ユーザーと組織](/docs/configure/users) | +| 入社、退社、または誰かのアクセスを変更する | [アクセスの管理](/docs/configure/permissions/managing-access) | +| アクセスモデルの全体を理解する | [権限](/docs/configure/permissions) | +| サインイン、OAuth、SSO、2FA を設定する | [認証](/docs/configure/authentication) | +| ランタイムとテナントの設定を変更する | [システム設定](/docs/configure/system-settings) | +| トランザクションメールの配信を設定する | [メール](/docs/configure/email) | +| ファイルストレージ(S3、ローカルディスク)を設定する | [ストレージ](/docs/configure/storage) | +| 外部の業務データベースに接続する | [データソース](/docs/configure/data-sources) | +| REST API と API キーを使う | [API アクセス](/docs/configure/api-access) | +| 外向きの Webhook を配信する | [Webhook](/docs/configure/webhooks) | +| AI プロバイダー、埋め込み、RAG を設定する | [AI サービス](/docs/configure/ai) | +| Claude などの MCP クライアントを接続する | [AI ツールを接続する(MCP)](/docs/configure/mcp) | +| 成果物の読み込み、データベース、キャッシュを設定する | [ランタイム設定](/docs/configure/runtime) | +| バックアップと災害復旧を計画する | [バックアップ](/docs/operate/backup) | +| 安全にアップグレードまたはロールバックする | [アップグレード](/docs/operate/upgrade) | +| 本番に向けて堅牢化する | [本番環境への準備](/docs/operate/production) | +| ログ、メトリクス、監査証跡を読む | [可観測性](/docs/operate/observability) | +| 壊れたデプロイメントを診断する | [トラブルシューティング](/docs/operate/troubleshooting) | + +## 次に進む [#where-to-go-next] + +| タスク | ページ | +|---|---| +| 最初の管理タスク:人と構造を追加する | [ユーザーと組織](/docs/configure/users) | +| 新入社員にアクセスを与える | [アクセスの管理](/docs/configure/permissions/managing-access) | +| 階層化されたアクセスモデルを学ぶ | [権限](/docs/configure/permissions) | +| 本番前のチェックリスト | [本番環境への準備](/docs/operate/production) | diff --git a/content/docs/configure/localization.ja.mdx b/content/docs/configure/localization.ja.mdx new file mode 100644 index 0000000..4c958c7 --- /dev/null +++ b/content/docs/configure/localization.ja.mdx @@ -0,0 +1,52 @@ +--- +title: ローカライズ +seoTitle: "ローカライズ:タイムゾーン、言語、書式" +description: レンダリングされるすべての値が継承する、テナント全体のタイムゾーン、言語、国、デフォルトの通貨、会計年度の開始月を設定します。 +editions: [community, cloud, enterprise] +translation: + source_sha: 85567978135b8d527209ff22f652aa15f2315e046e832736993cd3d2368a4e1c + guide_rev: 1 + mode: auto +--- + +ローカライズは、ObjectOS が時刻をどう解釈し、どのメッセージカタログを選び、日付、数値、通貨をどうレンダリングするかについての**テナントレベルのデフォルト**を設定します。これらの値はワークスペース全体のフォールバックです。個々のユーザーは [Account](/docs/use/profile) で自分の言語を上書きできますが、ここで設定したデフォルトは、上書きしていないすべての人に適用されます。 + +**Setup → Configuration → Localization** を開きます。ページは **Region** と **Finance** の 2 つのセクションに分かれています。 + +## 地域 [#region] + +Region は、ObjectOS が*意味*をどう解決するかを制御します。どのタイムゾーンを相対時間の計算の基準にするか、どのロケールで書式を決めるか、デプロイメントがどの国を本拠地として報告するかです。 + +| 設定 | デフォルト | 決めるもの | +|---|---|---| +| `Default timezone` | `UTC` | `today()` / `daysFromNow`、分析の日付バケット、レンダリングされる日時に使う IANA のゾーン | +| `Default language` | `English (US)` | メッセージカタログと数値 / 日付の書式に使う BCP-47 のロケール | +| `Default country` | `US` | ISO 3166-1 alpha-2 のコード(例:`US`、`GB`、`CN`) | + +> **タイムゾーンは見た目だけの問題ではありません。** あらゆる相対時間の式と、分析がレコードをまとめるバケットの基準です。変更すると、テナント全体で「今日」の意味がずれます。一度だけ、慎重に設定してください。 + +`Default timezone` は IANA のゾーン(`UTC`、`America/New_York`、`Asia/Shanghai` など)のドロップダウンです。`Default language` は、UI がフォールバックするメッセージカタログと書式のルールを持つロケールを選びます。`Default country` は、2 文字の ISO コードを想定した自由入力のフィールドです。 + +## 財務 [#finance] + +| 設定 | デフォルト | 決めるもの | +|---|---|---| +| `Default currency` | なし | 通貨フィールドが自身の通貨を宣言していないときに使う ISO 4217 のコード。未設定のままにすると、そのような金額は推測した記号を付けず、ただの数値としてレンダリングされます | +| `Fiscal year start` | `January` | 会計年度の最初の月。レポートで「今四半期」や「今会計年度」が何を意味するか | + +## 日付、時刻、数値は言語に従う [#dates-times-and-numbers-follow-the-language] + +独立した書式の設定はありません。日付、時刻、数値の書き表し方や、週が何曜日から始まるかは、`Default language`(またはユーザー自身の言語)に従います。ObjectStack 17.7 では、このページにかつて記載されていた 4 つの書式の設定(`date_format`、`time_format`、`number_format`、`first_day_of_week`)が廃止されました。どこからも読み取られていなかったからです。以前に保存された値は保持されますが、もう提供されません。そのいずれかを指定する `PUT /api/settings/localization` は、並んで指定された有効なキーも含めて、リクエスト全体が `400 UNKNOWN_KEY` で拒否されます。また、`OS_LOCALIZATION_*_FORMAT` と `OS_LOCALIZATION_FIRST_DAY_OF_WEEK` の変数はもう読み取られません。書式が変えるのは値の表示方法だけです。タイムスタンプと数値は、どちらにしても正規の形式で保存されます。 + +## テナントのデフォルトとユーザーの上書き [#tenant-defaults-vs-user-overrides] + +このページのすべてが**テナントのデフォルト**です。ユーザーが **Account** で自分の言語を設定すると、そのユーザーのセッションとレンダリングされる UI ではその選択が優先されます。設定を未指定のままにしたユーザーは、ここで設定した `Default language` を継承します。タイムゾーン、国、通貨、会計年度のデフォルトはテナント全体に適用されます。 + +## 次に進む [#where-to-go-next] + +| タスク | ページ | +|---|---| +| ブランディング、機能フラグ、そのほかのテナント設定を変更する | [システム設定](/docs/configure/system-settings) | +| ユーザー個人の言語の上書きを設定する | [プロフィールと設定](/docs/use/profile) | +| トランザクションメールの配信を設定する | [メール](/docs/configure/email) | +| 管理の概要に戻る | [設定](/docs/configure) | diff --git a/content/docs/configure/mcp.ja.mdx b/content/docs/configure/mcp.ja.mdx new file mode 100644 index 0000000..34196ed --- /dev/null +++ b/content/docs/configure/mcp.ja.mdx @@ -0,0 +1,235 @@ +--- +title: AI ツールを接続する(MCP) +description: Claude Code、Claude Desktop、または任意の MCP クライアントを ObjectOS アプリに向け、エージェントにあなたの権限モデルのもとでデータを扱わせます。 +editions: [community, cloud, enterprise] +translation: + source_sha: 284d38d7199dbc99e3df09c43ffc520333a1fff28e22d0681d8b885d554bf1e0 + guide_rev: 1 + mode: auto +--- + +すべての ObjectOS デプロイメントは、すでに MCP サーバーです。ランタイムは **`/api/v1/mcp`** で [Model Context Protocol](https://modelcontextprotocol.io) を提供しています。デフォルトで有効で、インストールするプラグインも設定の手順もありません。オブジェクトと公開したアクションは、定義した瞬間に型付きのツールになります。残っている作業は、クライアントを接続して動作を確かめることだけです。 + +> この機能をオフにするには `OS_MCP_SERVER_ENABLED=false` を設定します。するとエンドポイントは 404 を返し、**Setup → Connect an Agent** のページもあわせて消えます。 + +> **ObjectOS Cloud では逆です:** 各環境の MCP エンドポイントは**オーナーまたは管理者が有効にするまでオフ**で、すべてのプランにリクエストの上限があります。[ObjectOS Cloud の場合](#on-objectos-cloud)を参照してください。 + +このページは、*外部の* AI ツールをアプリに接続することについて扱います。サーバー側の AI スタック(チャットのプロバイダー、埋め込み、RAG、コードでの MCP サーバープラグインの明示的な登録)については、[AI サービス](/docs/configure/ai)を参照してください。 + +## Claude Code(コマンド 1 つ) [#claude-code-one-command] + +対話型のクライアントは OAuth を使います。各デプロイメントが独自の OAuth 2.1 認可サーバーなので、管理者が発行した認証情報を受け渡す必要はありません。最初のツールの呼び出しでブラウザのログインが開き、**あなた自身として**接続します。 + +```bash +# local dev server +claude mcp add --transport http my-app http://localhost:3000/api/v1/mcp + +# a deployed instance +claude mcp add --transport http my-app https://your-deployment.example.com/api/v1/mcp +``` + +> ローカルの開発サーバーでは、これを入力する必要すらありません。16.0 以降、`os dev` の起動時のバナーに、MCP エンドポイント、エージェントスキルの URL、そしてそのまま貼り付けられる `claude mcp add` コマンドが表示されます。 + +ヘッドレスで使う場合(CI、コンテナ)は、OAuth を使わずに代わりに [API キー](#headless-api-keys)を付けます。 + +```bash +claude mcp add --transport http my-app https://your-deployment.example.com/api/v1/mcp \ + --header "x-api-key: osk_..." +``` + +## Claude Desktop と claude.ai [#claude-desktop-and-claudeai] + +**Settings → Connectors → Add custom connector** を開き、MCP の URL(`https://your-deployment.example.com/api/v1/mcp`)を貼り付けます。初回の利用時に、同じブラウザのログインを経ます。 + +## 任意の MCP クライアント(`.mcp.json`) [#any-mcp-client-mcpjson] + +`mcpServers` マップを読むクライアントも同じように接続します。API キーを使う場合: + +```json +{ + "mcpServers": { + "objectstack": { + "type": "http", + "url": "https://your-deployment.example.com/api/v1/mcp", + "headers": { "x-api-key": "osk_..." } + } + } +} +``` + +## ヘッドレス:API キー [#headless-api-keys] + +**Setup → Connect an Agent**(クライアントごとにコピーしてすぐ使える接続のスニペットも表示されます)から、または REST でキーを発行します。 + +```bash +curl -b cookies.txt -X POST https://your-deployment.example.com/api/v1/keys +# → { "key": "osk_..." } — shown once; store it in your secret manager +``` + +すべてのリクエストで、同等な 3 つの形式のいずれかで送ります。 + +| ヘッダー | 例 | +|---|---| +| `x-api-key` | `x-api-key: osk_...` | +| `Authorization: ApiKey` | `Authorization: ApiKey osk_...` | +| `Authorization: Bearer` | `Authorization: Bearer osk_...`(`osk_` プレフィックスで認識されます) | + +> OAuth には TLS が必要です。プレーンな HTTP のデプロイメント(`localhost` を除く)は **API キーのみ**にフォールバックします。ブラウザログインの経路は、安全でない状態で動かすことを許すのではなく、無効になります。 + +長期間の連携では、キーを最小限の権限セットを持つ専用のサービスユーザーに結び付けてください。[Service accounts & API keys](/docs/configure/users#service-accounts--api-keys) を参照してください。 + +## stdio トランスポート(16.0) [#the-stdio-transport-160] + +ランタイムは HTTP のほかに、サーバーを子プロセスとして起動するホストのために、**stdio** で MCP を提供できます。16.0(ADR-0101)以降、stdio は独自のスイッチを持ち、常に実在のアイデンティティのもとで実行されます。 + +- **`OS_MCP_STDIO_ENABLED=true`** で stdio の自動起動が有効になります(デフォルトは**オフ**)。`OS_MCP_SERVER_ENABLED` が制御するのは、今は HTTP の画面だけです。`OS_MCP_SERVER_ENABLED=true` で stdio も起動していた旧来の動作は、1 リリースの間、非推奨の警告付きで引き続き機能します。 +- stdio には **`OS_MCP_STDIO_API_KEY=osk_...` が必要です**。キーは HTTP や REST と同じ検証 + 認可の連鎖で解決されるので、オブジェクトの権限、レコードアクセス、フィールドレベルのセキュリティ、テナントのスコープは、`/api/v1/mcp` とまったく同じように stdio の呼び出しにも適用されます。また、キーは読み取りのたびに再解決されるので、失効させると即座に有効になります。 +- このトランスポートは**安全側に倒れて失敗します**。解決できるキーなしに自動起動を有効にすると起動を拒否し、スコープなしのフォールバックや `system` によるすり抜けは意図的に用意されていません。完全な権限が必要なら、プラットフォーム管理者または専用のサービスアイデンティティでキーを発行してください。 + +## エージェントが得るもの [#what-the-agent-gets] + +メタデータから生成される、データ、アクション、作成の 11 個のツールです。 + +| ツール | 働き | +|---|---| +| `list_objects` / `describe_object` | どんなオブジェクトがあり、どんなフィールドを持つかを調べます | +| `query_records` / `get_record` | データを読みます(リストのクエリは、デフォルトで 1 ページあたり 50 行が上限です) | +| `validate_expression` | 数式を保存する*前に*、実際のオブジェクトのスキーマに照らして検査します(16.0)。エラー(素のフィールド参照、候補付きの不明なフィールド)、警告(型の健全性、日付の等価比較の落とし穴)、スコープ内のフィールド / 関数の一覧、推論された結果の型を返します。読み取り専用で、`data:read` のスコープで、`sys_*` では安全側に倒れて失敗します | +| `aggregate_records` | グループ化した集計(アクティブなドライバーがサポートしている場合に登録されます) | +| `create_record` / `update_record` / `delete_record` | データを書き込みます | +| `list_actions` / `run_action` | 業務アクションを名前で見つけて呼び出します | + +知っておくべき公開のルールが 2 つあります。 + +- **オブジェクトは自動的に公開されます。** ただし `sys_*` のシステムオブジェクトは、安全側に倒れてブロックされます。 +- **アクションには作成者のオプトインが必要です。** `ai: { exposed: true }` と 40 文字以上の `ai.description` を指定し、アクションが UI なしで呼び出せる(本体または登録済みのハンドラーを持つ `script`、または `flow`)必要があります。 + +## 権限の強制 [#permission-enforcement] + +- **すべての呼び出しは呼び出し元として実行されます。** MCP のブリッジは REST のリクエストと同じ実行コンテキストを解決するので、オブジェクトの権限、[レコードアクセス](/docs/configure/permissions/record-access)、[フィールドレベルのセキュリティ](/docs/configure/permissions/field-level-security)は、UI で人に適用されるのとまったく同じようにエージェントに適用されます。結果が少なかったり書き込みが拒否されたりするのは、たいていは接続が壊れているのではなく、ガバナンスが*機能している*ということです。 +- **OAuth のスコープはツールの集合を絞り込みます。** トークンは `data:read`、`data:write`、`actions:execute` のスコープを持ち、付与されたスコープの外にあるツールは、そのセッションでは登録すらされません。API キーとセッションの呼び出し元は完全な集合を得ますが、やはり呼び出しごとに権限がチェックされます。4 つ目のスコープ `metadata:write` は、デプロイメントがビルドツールを提供している場合にだけそれを提供します。ObjectOS Cloud では [エージェントで構築する](#build-with-an-agent)を参照してください。 +- **アクションの本体は、呼び出されると信頼されたアプリのコードとして実行されます**(`ai.exposed` のゲートと `requiredPermissions` は*呼び出し*時にチェックされます)。アクションを書くことはコードレビューに値する行為として扱ってください。それが本当のセキュリティの境界です。 +- アクションは `ai.requiresConfirmation` を宣言することもできます。破壊的に見えるアクションは、デフォルトでそれを必要とします。 + +## 接続を確認する [#verify-the-connection] + +稼働中のスキーマでしか答えられないことをエージェントに尋ねます。 + +```text +What objects does this app have, and what fields does the main one carry? +``` + +`list_objects` と `describe_object` が呼び出されるはずです。エージェントの自然な作業パターンは `list_objects` → `describe_object` → `query_records` → `run_action` です。4 つすべてが動けば、接続は完全に機能しています。 + +> エージェントは、アプリの**スキルファイル**があると目に見えてうまく動きます。`GET /api/v1/mcp/skill` からダウンロードするか、スキルとガイド付きの `/objectstack:connect` コマンドを同梱した[公式の Claude プラグイン](https://github.com/objectstack-ai/claude-plugin)(`claude plugin marketplace add objectstack-ai/claude-plugin`)をインストールしてください。 + +## ObjectOS Cloud の場合 [#on-objectos-cloud] + +ここまでの内容はすべて、エンドポイントが有効になった ObjectOS Cloud の環境に当てはまります。異なるのは 4 点です。スイッチ、上限、接続の詳細がある場所、そしてエージェントがアプリをドラフトとして構築できることです。 + +### AI エージェントのアクセスを有効にする [#turn-on-ai-agent-access] + +環境のデータを外部の AI クライアントに公開するのは組織の判断なので、ObjectOS Cloud ではエンドポイントは、すべてのプランで、環境ごとに**デフォルトでオフ**です([cloud#1248](https://github.com/objectstack-ai/cloud/issues/1248) で決定)。 + +1. クラウドコンソールで、環境のページとその **Settings** タブを開きます。**Access and sign-in** の下にある **AI agent access (MCP)** の行は **Now: off** と表示されています。 +2. **Enable AI Agent Access** を選び、確認します。これが表示されるのは組織のオーナーと管理者だけです。 +3. 数秒待ちます。環境は再デプロイなしに自動で変更を取り込みます。その後、行は **Now: on** と表示され、環境の **Overview** にも同じ状態が表示されます。 + +有効になると、環境自身のコンソール内に **Connect an Agent** が現れます。同じページを開く場所が 2 つあります。サインインしているすべてのユーザー向けの **Account → Developer** と、Manage Platform Settings を持つユーザー向けの **Setup → Integrations** です。そのページには、環境のエンドポイントの URL(環境のアドレスの後に `/api/v1/mcp`)、クライアントごとの接続カード、スキルファイル、API キーの発行機能が表示されます。 + +### 接続する [#connect] + +対話型のクライアントは、上で説明したブラウザのサインインを使います。するとエージェントは、あなた自身の権限、行レベルセキュリティ、フィールドアクセスの範囲内で、**あなた**として動作します。ヘッドレスのクライアント(CI、スクリプト)は、**Connect an Agent** の **API keys · headless** カードで発行した [API キー](#headless-api-keys)を使います。キーは発行した人として動作し、ほかの誰かのために発行することは決してできません。 + +### エージェントで構築する [#build-with-an-agent] + +エージェントは**アプリを構築する**こともできます。レコードだけでなく、オブジェクト、フィールド、ビュー、ページ、ダッシュボード、フロー、アクションを作成し、変更できます。構築したものはすべて、人が公開するまでは**ドラフト**です。 + +**`metadata:write` を求めます。** ビルドツールは、付与に `metadata:write` スコープを含むブラウザのサインインにだけ提供されます。環境は `data:read`、`data:write`、`actions:execute` と並べてこれを通知するので、環境が通知するスコープを求めるクライアントなら、サインインしたときにこれを得られます。クライアントがスコープを名前で求める場合は `metadata:write` を加えてください。これなしでサインインした場合は、接続し直してください。[API キー](#headless-api-keys)でビルドツールが開くことはありません。このスコープはツールを開くだけで、それ以上のことはしません。すべての呼び出しはあなたとして実行され、[AI Builder](/docs/build/ai-builder) と同じく、その環境での `manage_metadata` または `studio.access` 権限が必要です。 + +**ツールの働き。** + +| ツール | 働き | +|---|---| +| `get_authoring_rules`、`get_metadata_schema` | この環境が従う構築のルールと、メタデータの種類の形 | +| `list_metadata`、`describe_metadata`、`list_packages`、`get_package` | 環境が現在保持しているもの | +| `propose_blueprint`、`apply_blueprint` | 説明からアプリや機能を設計し、その設計全体をステージングします | +| `create_object`、`add_field`、`modify_field`、`delete_field` | オブジェクトとフィールドを変更します | +| `create_metadata`、`update_metadata`、`apply_edit` | 環境が構築する任意の種類を作成する、1 つを変更する、または既存のアプリに構造化された編集を適用します | +| `create_seed` | サンプルデータを追加します | +| `create_package` | 構築先のパッケージを作成します | +| `verify_build` | ドラフトをプラットフォームのルールに照らしてチェックし、拒否されるものを報告します | + +各呼び出しは自分のパッケージ(`packageId` または `targetApp`)を指定します。ある呼び出しから次の呼び出しへ作業中のパッケージが引き継がれることはありません。`toggle_flow` と `test_flow` はここでは提供されません。エージェントがステージングするフローは、実行されないドラフトだからです。 + +**すべての書き込みは、どの環境でもドラフトです。** 本番も含みます。公開するツールも、破棄するツールもありません。各書き込みの結果は、変更がまだ有効ではないことを伝え、ドラフトとそれらが公開される場所を示す `staged` ブロックを持ちます。 + +**公開するのは人で、Studio → Changes で行います。** Studio でパッケージとその **Changes** ビュー(環境内の `/_console/studio//data`)を開き、エージェントがステージングしたものを確認して、公開または破棄します。何かを作成したと言うエージェントは、それをドラフトにしたということです。アプリに表示されるのは公開されてからです。 + +**削除や絞り込みには `confirm: true` が必要です。** `delete_field`、`modify_field`、`apply_edit`、`update_metadata` は `confirm` 引数を取ります。フィールドを削除する、フィールドの型を変える、フローからステップを外すような呼び出しは、`confirm: true` がなければ何もステージングせず、公開すると何が失われるかを答えます。追加するだけの変更には決して必要ありません。 + +**エージェントがどれだけ構築できるか。** ビルドの呼び出しは MCP のリクエストなので、[リクエストの上限](#limits)が適用されます。さらに 2 つの上限が構築を数えます([ストレージと上限](/docs/cloud/storage-and-limits#drafts-and-authoring-writes))。 + +| | Free | Team 以上 | +|---|---|---| +| MCP 経由のビルドの書き込み(環境ごと、UTC の 1 日あたり) | 200 | 2,000 | +| 環境ごとの未公開のドラフト(作成方法を問わず) | 500 | 500 | + +読み取りと `verify_build` は書き込みとして数えられません。どちらかの上限を超えると、ツールの呼び出しは `RATE_LIMIT_EXCEEDED`、その数、そして何でリセットされるかとともに拒否されます。書き込みは UTC の翌日に、ドラフトは公開または破棄でリセットされます。 + +> **フローが拒否されるのはなぜ?** エージェントがここでは構築できないものを使っており、拒否の理由がそれを示します。Free でのスケジュールまたは相対時間のフロー、承認ワークフローがプランに含まれていない場合の承認ステップ、またはソースで構築して[パッケージ](/docs/build/packages)として公開する種類です。 + +エージェントが構築するのは、レコードの変更またはボタンで開始するフローで、レコードの作成、更新、削除、割り当て、判断、ループ、待機のステップから構成されます。スケジュールと相対時間のフローは Team 以上で、承認ステップはプランに[承認ワークフロー](/docs/cloud/plans-and-seats)が含まれている場合に構築できます。スクリプト、Webhook、API で起動するフローと画面フロー、そしてスクリプト、Webhook、API、ジョブ、メールテンプレート、翻訳、テーマ、プラグイン、エージェント、スキル、データソースの種類は、どのプランでもソースで構築します。 + +### 上限 [#limits] + +各環境のエンドポイントが受け付けるリクエストの数は決まっており、それに接続しているすべてのエージェントで共有されます([cloud#3203](https://github.com/objectstack-ai/cloud/issues/3203) で決定)。 + +| プラン | 1 分あたり | UTC の 1 日あたり | +|---|---|---| +| Free | 20 | 1,000 | +| Team 以上 | 120 | 1 日の上限なし | + +上限を超えると、エンドポイントは `Retry-After` とコード `RATE_LIMIT_EXCEEDED` とともに `429` で応答します。メッセージには、どの上限に達したか、いつリセットされるかが示されます。何がリクエストとして数えられるか、そしてそれと並ぶドラフトと作成の書き込みの上限は、[ストレージと上限](/docs/cloud/storage-and-limits#mcp-limits)にあります。スイッチはプランの変更を越えて保持されるので、ダウングレードやアップグレードによってオンやオフになることはありません。 + +### オフにする [#turn-it-off] + +同じ行の **Disable AI Agent Access** は、数秒以内に環境がエンドポイントを提供するのを止め、ブラウザのサインインと API キーのどちらも含めて、接続しているすべてのエージェントを切断します。それ以外のものは何も失効させません。 + +- **API キーは REST API では引き続き機能します。** キーそのものを廃止するには、**Account → Developer → API Keys**(自分のもの)または **Setup → Access Control → API Keys**(全員のもの、Manage Platform Settings が必要)から削除してください。 +- **ブラウザのサインインは失効しません**が、そのトークンを受け付けるのは MCP エンドポイントだけなので、オフの間は何にも届きません。 + +### ObjectOS Cloud の場合:トラブルシューティング [#on-objectos-cloud-troubleshooting] + +| 症状 | 原因 | +|---|---| +| 環境の **Settings** に **AI agent access (MCP)** の行がない | それが見えるのは組織のオーナーと管理者だけです | +| **Connect an Agent** が **Account → Developer** にも **Setup → Integrations** にもない | AI エージェントのアクセスがまだオフか、たった今オンにしたところです。再読み込みしてください | +| **Connect an Agent** が **Account → Developer** の下にしかない | その環境で Manage Platform Settings を持っていません。Account のエントリでも同じページが開きます | +| クライアントから `429` が返る | 環境のエージェントが上限を超えました。`Retry-After` の秒数だけ待ち、同じ呼び出しを繰り返しているエージェントがないか確認してください | +| 接続にビルドツールがない | サインインで `metadata:write` が付与されなかったか、クライアントが API キーを使っています。ブラウザのサインインで接続し直し、付与してください | +| ビルドツールが `PERMISSION_DENIED` を返す | その環境で `manage_metadata` と `studio.access` を持っていません | +| エージェントが構築したものがアプリに表示されない | それはドラフトです。Studio → **Changes** で公開してください | +| ビルドツールが、ビルドの書き込みまたはドラフトを示して `RATE_LIMIT_EXCEEDED` を返す | その日のビルドの書き込みまたはドラフトの上限を使い切りました。UTC の翌日まで待つか、ドラフトを公開または破棄してください | + +## トラブルシューティング [#troubleshooting] + +| 症状 | 原因 → 対処 | +|---|---| +| `/api/v1/mcp` で `404` | この機能が無効です。`OS_MCP_SERVER_ENABLED` の設定を外してください(デフォルトは有効) | +| `501 Not Implemented` | MCP プラグインがこのビルドに含まれていません。スタックのプラグインを確認してください | +| stdio を有効にすると起動が拒否される | stdio は安全側に倒れて失敗します(16.0)。`OS_MCP_STDIO_API_KEY` に解決できる `osk_` キーを設定するか、`OS_MCP_STDIO_ENABLED` をオフにしてください | +| すべての呼び出しで `401` | 匿名、または無効な認証情報です。対話型のクライアント:ブラウザのログインを完了してください。ヘッドレス:`osk_` キーとヘッダーの綴りを確認してください | +| `403 insufficient_scope` | OAuth のトークンに、そのツール群のスコープがありません(例:`data:write` なしの書き込み)。接続し直してスコープを付与してください | +| アクションが `list_actions` にない | `ai.exposed` が `true` でない、`ai.description` が 40 文字より短い、種類がヘッドレスで呼び出せない(`url` / `modal` / `form` は決して現れません)、`sys_*` オブジェクトを対象にしている、または呼び出し元が `requiredPermissions` を満たしていない | +| 読み取りの行が少ない / 書き込みが拒否される | 設計どおりの動作です。呼び出し元の権限とレコードアクセスが適用されています。UI で同じユーザーとして確認してください | + +## 次に進む [#where-to-go-next] + +| タスク | ページ | +|---|---| +| AI プロバイダー、埋め込み、MCP サーバーのプラグインを設定する | [AI サービス](/docs/configure/ai) | +| サービスユーザーと API キーを作成する | [ユーザーと組織](/docs/configure/users) | +| エージェントが何を見てよいかを理解する | [権限](/docs/configure/permissions) | +| REST API とキーの管理 | [API アクセス](/docs/configure/api-access) | +| 特定のユーザーのアクセスを確認する | [アクセスの管理](/docs/configure/permissions/managing-access) | diff --git a/content/docs/configure/notifications.ja.mdx b/content/docs/configure/notifications.ja.mdx new file mode 100644 index 0000000..2aadd89 --- /dev/null +++ b/content/docs/configure/notifications.ja.mdx @@ -0,0 +1,138 @@ +--- +title: 通知 +seoTitle: "通知のルーティング、設定、テンプレート" +description: ObjectOS がイベントをユーザーの受信トレイへどうルーティングするかを設定します。プロデューサーが通知を送る対象者、ユーザーごとの設定、レンダリングのテンプレートです。 +editions: [community, cloud, enterprise] +translation: + source_sha: acb9c57714d0c2bb4f52cb0556509fc52a0224393ac8ea0d7bde5b99663df050 + guide_rev: 1 + mode: auto +--- + +このページは通知の**管理者側**を扱います。イベントがどのようにメッセージになるか、そしてその背後にあるシステム管理の 3 つのオブジェクトです。受信者から見た受信トレイ(通知を読む、ミュートする)については、*使い方*の[通知](/docs/use/notifications)を参照してください。 + +## 通知のパイプライン [#the-notification-pipeline] + +通知は単一のレコードではありません。4 つの段階を流れます。 + +```text +emit() + explicit audience → Notification Event → recipients, filtered by Preference → Inbox Message +``` + +1. **`emit()`**:アプリケーションのコードがイベント(承認の申請、レコードの共有、招待の送信)を発生させ、**その対象者を指定します**。対象者は必須の入力で、誰に通知するかを決めるのはこれです。 +2. **Notification Event**(`sys_notification`):各 `emit()` は受け入れの行を 1 つ書き込みます。これは配信の判断が行われる前の、*何が起きたか*の診断ログです。読み方は[監査ログ](/docs/operate/audit-logs)を参照してください。 +3. **ルーティング**:各イベントについて、ObjectOS はプロデューサーが渡した対象者を受信者に展開し、各受信者がそのチャネルでそのトピックを許可しているか(**Preferences**)を確認し、受け付けられた各配信をそのチャネルに渡します。チャネルがそれをレンダリングします。チャネルが何*から*レンダリングするかはチャネルによって異なります。メールと SMS は **Notification Templates** をレンダリングし、アプリ内の受信トレイはそうしません([各チャネルが何をレンダリングするか](#what-each-channel-renders)を参照)。 +4. **Inbox Message**(`sys_inbox_message`):受信者が実際に受信トレイで目にする、具体化されたユーザーごとの結果です。 + +Preferences、Subscriptions、Templates は管理者 / システム側の設定です。Inbox Messages はユーザー側の出力です。 + +### ルーティングがどう解決されるか [#how-routing-resolves] + +1 つのイベントについて、誰が何を受け取るかを決める入力は次のとおりです。 + +| 入力 | 答える問い | +|---|---| +| `emit()` に渡される対象者 | *誰が受け取るか?* プロデューサーが受信者を指定します。リストに誰かを載せる入力はこれだけです | +| Notification Preference | *この受信者はここでそれを許可しているか?* トピックとチャネルに対するユーザーごとのミュート / 許可で、すべての(受信者 × チャネル)の組に適用されます | +| Notification Template | *どう書かれるか?* **メール**と **SMS** のチャネルでレンダリングされる件名と本文です。アプリ内の受信トレイはこれらの行を読みません。[各チャネルが何をレンダリングするか](#what-each-channel-renders)を参照してください | +| Notification Subscription | *誰が継続的な関心を宣言したか?* 管理者が作成する行で、**イベントのルーティング時には参照されません** | + +プロデューサーの対象者がその受信者に解決され、その受信者の設定がそのチャネルでそのトピックをミュートしていなければ、受信者の受信トレイに届きます。デフォルトは許可なので、設定の行を持たない受信者も通知を受け取ります。また、必須のトピック(セキュリティアラートなど)は設定を完全にすり抜けます。 + +> **警告:** Subscription の行は何もルーティングしません。サブスクリプションから受信者への展開は**配線されていません**。`emit()` は明示的な対象者を必要とし、上のパイプラインのどこにも、トピックのサブスクリプションを受信者に展開するものはありません。すべての配信はプロデューサーが渡した対象者から来ます。そのため、Setup の **Notification Subscriptions** のグリッドは管理者が作成するデータであり、稼働中のルーティングのコントロールではありません。行を一時停止しても(`enabled = false`)何も止まらず、行を追加しても何も配信されません。 + +これは、このページで説明する通知のパイプラインについての記述です。ObjectOS の上で動く機能や連携が、独自の目的でこれらの行を使って何をするかについての主張ではありません。ADR-0012 と ADR-0030 は、サブスクリプション駆動のルーティングを、現在の動作ではなく**目標とする状態**として記述しています。これらの行をルーティングに関係させるはずの展開は構築されておらず、予定もされていません。もし構築されれば、ここに記述した動作もそれとともに変わります。 + +Preferences と Templates はプラットフォームが初期投入して保守するので、それらのリストビューに表示されるのはほとんどがシステムの生成した行です。Subscription の行は管理者が Setup から作成するもので、そのためにそのグリッドがルーティングのコントロールのように見えてしまいます。 + +## Notification Preferences [#notification-preferences] + +**Setup → Configuration → Notification Preferences**(`sys_notification_preference`)にあります。 + +ユーザー × トピック × チャネルごとのトグル(ミュート / 許可)で、管理者によるグローバルなデフォルトを持ちます。設定は、ある受信者があるトピックをあるチャネルで受け取るかどうかを決めます。 + +| フィールド | 目的 | +|---|---| +| `user_id` | 設定が属するプリンシパル | +| `topic` | 通知のトピック(例:`project.digest`) | +| `channel` | 配信チャネル(アプリ内、メール……) | +| `enabled` | ブール値。そのユーザーについて、このトピック / チャネルを許可するかミュートするか | +| `digest` | そのトピックをまとめて送る周期 | +| `quiet_hours` | 配信を抑制する時間帯を表す JSON | +| `created_at` / `updated_at` | 監査用のタイムスタンプ | + +> エントリは、そのソースとなるアクション(たとえば *Submit for Approval*、*Share*、*Invite*)が最初に実行されたときに自動的に現れます。設定の行を手で作成することはまれです。リストは、管理者のデフォルトを調整したり、うるさいトピックをミュートしたりするのに使ってください。 + +## Notification Subscriptions [#notification-subscriptions] + +**Setup → Configuration → Notification Subscriptions**(`sys_notification_subscription`)にあります。 + +プリンシパルによる通知のトピックへの**継続的なサブスクリプション**です。この行は、誰かがそのトピックに関心を宣言したことを記録します。これは参照用のデータです。配信の経路のどこもこれを読まないので、サブスクリプションの行は受信者を追加することも削除することもしません([ルーティングがどう解決されるか](#how-routing-resolves)を参照)。 + +| フィールド | 目的 | +|---|---| +| `topic` | サブスクライブするトピック | +| `principal` | サブスクライバー。セレクターの文字列です。[`principal` に何を入力するか](#what-to-type-in-principal)を参照してください | +| `enabled` | ブール値。行を有効または一時停止としてマークします。どの配信もこれを参照しません | + +### `principal` に何を入力するか [#what-to-type-in-principal] + +`principal` はピッカーではなく、1 つのテキストフィールドです。値は**セレクターの文字列**で、そのプレフィックスによって、値が何と照合されるかが決まります。以下の形式は、プラットフォームの受信者リゾルバーがどのセレクターの文字列についても**受け付ける**ものです。`emit()` の対象者を書くのと同じ文法です。認識されるプレフィックスのない値は素のユーザー ID として読まれます。そのため `sales_manager`(または `Sales team`)と入力すると、意図したグループではなく、存在しないユーザーを指定することになります。 + +| 値 | 解決先 | 例 | +|---|---|---| +| `role:name` | 組織内で、組織メンバーシップの階層がその名前であるすべての人(`sys_member.role`) | `role:admin` | +| `team:id` | そのチームのすべてのメンバー。ラベルではなくチームの **ID** で照合します(`sys_team_member.team_id`) | `team:team_123` | +| `user:id` | ユーザー ID で指定した、その 1 人のユーザー | `user:usr_123` | +| `owner_of:object:id` | その 1 件のレコードの所有者。レコードが持つ最初の所有者 / 担当者のフィールドです | `owner_of:invoice:inv_123` | +| メールアドレス | メールアドレスが一致するユーザー。**どのユーザーにも一致しないアドレスは、拒否されずにそのまま**受信者 ID として保持されます | `ada@example.com` | +| `id` | 認識されるプレフィックスなし。値全体が素のユーザー ID として扱われます | `usr_123` | + +このリストはリゾルバーが受け付けるものであって、サブスクリプションの行のために設計された契約ではありません。`owner_of:` とメールの形式があるのは、すべてのセレクターの文字列が同じリゾルバーを通るからです。どちらかが継続的なサブスクリプションにふさわしいかどうかは、プラットフォームがまだ決めていない未解決の問題です。 + +> **ここでの `role:` は組織メンバーシップの階層を意味し、職務ではありません。** 階層は [`owner`、`admin`、`delegated_admin`、`member`](/docs/configure/users#organization-membership-tiers) で、ユーザーが組織の中で持つ立場です。職務は[ポジション](/docs/configure/permissions/positions)で、ポジションの名前はここでは指定できません。`role:sales_manager` は誰にも一致しません。*Role* は ObjectOS のほかのあらゆる場所で廃止された用語です(機能は権限セット、配布はポジション)。組織メンバーシップの階層が唯一の例外で、このセレクターもそれを同じように綴ります。 + +セレクターの背後にあるディレクトリの検索は、意図的にベストエフォートです。検索が外れたことでイベントが失敗することはありません。したがって、何にも一致しないセレクターは**黙ってゼロ人の受信者**に解決されます。行は有効なまま有効化されたままで、それについて何も報告されません。一致しないメールアドレスはさらに厄介です。それ自体が受信者 ID として保持されるので、入力ミスは決して届かない受信者になります。トピックが誰にも届かないときは、まずプレフィックスと値の綴りを確認してください。 + +## Notification Templates [#notification-templates] + +**Setup → Configuration → Notification Templates**(`sys_notification_template`)にあります。 + +**(トピック × チャネル × ロケール)** ごとのレンダリングのテンプレートで、**メール**と **SMS** のチャネルが読みます。テンプレートは、イベントのペイロードを、それらのチャネルが送る件名と本文に変換します。アプリ内の受信トレイはこれらの行を読みません。[各チャネルが何をレンダリングするか](#what-each-channel-renders)を参照してください。 + +| フィールド | 目的 | +|---|---| +| `topic` | このテンプレートがレンダリングするトピック | +| `channel` | レンダリングされた出力の送信先チャネル | +| `locale` | このレンダリングのロケール。受信者のものではなく、通知自身のものです | +| `version` | テンプレートのバージョン番号 | +| `subject` | レンダリングされるタイトル | +| `body` | メッセージの本文(Markdown) | +| `format` | 本文の出力形式 | +| `is_active` | ブール値。このテンプレートをレンダリングに使うかどうか | + +ロケールは受信者ではなく**通知**で照合されます。配信は、プロデューサーが `payload.locale` を設定していればそれで、そうでなければデプロイメントのデフォルトでレンダリングされます。受け取る人からロケールを解決するものは何もないので、1 回の emit は、届くすべての受信者に対して単一のロケールでレンダリングされます。あるトピックに `es` と `en` の行を作成すると、プロデューサーが選べる 2 つのレンダリングができるのであって、2 人の受信者がそれぞれ自分の言語で読めるようになるわけではありません。 + +これらのオブジェクトは**システム管理**です。行はプラットフォームと実行している機能によって初期投入されるので、作業のほとんどは、レコードを一から作成することではなく、テンプレートの内容を編集したり、`is_active`、`enabled`、設定のデフォルトを切り替えたりすることです。 + +### 各チャネルが何をレンダリングするか [#what-each-channel-renders] + +レンダリングはチャネルごとに行われ、上の行を読むのは 2 つのチャネルだけです。 + +| チャネル | レンダリングの元 | +|---|---| +| **メール** | (トピック、`email`、ロケール)に一致する Notification Template。一致する有効な行がなければ、通知自身のタイトルと本文がそのまま送られます | +| **SMS** | (トピック、`sms`、ロケール)に一致する Notification Template。同じフォールバックがあります | +| **アプリ内の受信トレイ** | **Notification Template ではありません。** 受信トレイの行は、通知自身のタイトルと本文から書かれます。プロデューサーがタイトルを設定しなかった場合はトピックです。通知が代わりにメールテンプレートを指定している場合、受信トレイはそれをレンダリングします。メールサービスを通じて(名前、ロケール)で解決される `sys_email_template` の行で、[メール](/docs/configure/email#templates)に記載されています。それをレンダリングできるメールサービスがなければ、その配信はフォールバックせずに失敗します | + +> **警告:** `inbox` は**デフォルト**のチャネルです。チャネルを指定しない通知はそこに配信され、ほかのどこにも配信されません。そのため、管理者が最も目にしやすい配信は、Notification Template を決して読まない配信です。ここでテンプレートの行を編集すると、メールと SMS が送る内容は変わりますが、アプリ内のメッセージは何も変わりません。このページは現状の配線を記述しており、受信トレイがこれらの行とつながる将来を予告するものではありません。 + +## 次に進む [#where-to-go-next] + +| タスク | ページ | +|---|---| +| 配信に使うメールチャネルを設定する | [メール](/docs/configure/email) | +| 受け入れのログと監査証跡でイベントを診断する | [監査ログ](/docs/operate/audit-logs) | +| 受信者から見た受信トレイの体験を確認する | [通知](/docs/use/notifications) | +| テンプレートが照合するロケールのデフォルトを設定する | [ローカライズ](/docs/configure/localization) | +| 管理の概要に戻る | [設定](/docs/configure) | diff --git a/content/docs/configure/runtime.ja.mdx b/content/docs/configure/runtime.ja.mdx new file mode 100644 index 0000000..23a4ca0 --- /dev/null +++ b/content/docs/configure/runtime.ja.mdx @@ -0,0 +1,67 @@ +--- +title: ランタイム設定 +seoTitle: "ランタイム設定:アプリの成果物、データベース、起動" +description: 実行中のアプリがどこから来るか、どのデータベースを使うか、そしてデプロイメントが宣言しなければならない起動時の判断。 +editions: [community, enterprise] +translation: + source_sha: f078294f4425d638d15bf1bd234afc8ecbd40c51c86182a636164d415db1a516 + guide_rev: 1 + mode: auto +--- + +ランタイム設定は 3 つの問いに答えます。 + +1. **実行中のアプリはどこから来るか?** +2. **どのデータベースを使うか?** +3. **このデプロイメントは何であることが許されているか**:接続されているか切り離されているか、組織は 1 つか複数か。 + +このページは、それらの判断の形について扱います。変数の名前とその正確な契約は[環境変数](/docs/reference/environment-variables)にあり、コピーする値はリリースとともに提供されるデプロイバンドルにあります。 + +## アプリはどこから来るか [#where-the-app-comes-from] + +有効なソースは常にちょうど 1 つで、どれであるかはデプロイメントが宣言します。 + +| モード | 使う場面 | アプリの届き方 | +|---|---|---| +| **設定で作成** | 出荷時の形:1 つのアプリ、評価、エアギャップ、ほとんどの本番デプロイメント | ランタイムは、イメージ内で作成されたメタデータと、そこにインストールされたものを提供します | +| **成果物に固定** | アプリが、ランタイムのイメージとは独立した独自の周期でリリースされる | 1 つの変数が、公開された成果物を URL で指定します。この経路では、イメージ自身の設定は読み込まれません | +| **合成** | 分離の壁の内側にある複数の組織が 1 つのデータベースを共有し、公開されたアプリを実行する | 同じ成果物の参照を、デプロイメント自身の設定から読み込むので、エンタープライズのプラグインがそれとともに読み込まれます。エアギャップライセンスでのみ可能で、それ以外では[起動時に拒否されます](/docs/deploy/air-gapped) | + +公開されたアプリのアップグレードは、成果物の参照の変更と再起動であり、イメージの再ビルドはありません。ロールバックは以前の URL で同じ操作をすることで、以前のオブジェクトが同じバイト列のまま存在している場合にだけ機能します。それはランタイムではなく公開の仕方の性質なので、このモードには 3 つのルールが伴います。 + +- **変更不可能で、バージョン名の付いたオブジェクトを公開します。** 公開済みの成果物を決して上書きせず、動く名前には決して公開しないでください。変更可能な名前では、デプロイのイベントなしに実行中のアプリが変わりうるうえ、ロールバックが不可能になり、「14:05 に何が実行されていたか」という監査上の答えが失われます。 +- **書き込みアクセスは公開パイプラインにだけ与えます。** 人が書き込める成果物ストアは、レビューのない本番デプロイの経路です。 +- **本番ではダイジェストを固定します。** 参照は省略可能な完全性の固定を持てます。それがあれば、不一致のときに**起動を拒否**し、期待したダイジェストと実際のダイジェストを示します。それがなければ、ランタイムはホストが返したものを何でも起動し、再公開された成果物と差し替えられた成果物を区別できません。 + +`file://` の参照は、成果物のホストなしで同じ経路を試せます。そのため、デプロイメントのリハーサルにはこれが適しています。本番のコマンドは、リハーサルしたものとちょうど 1 か所だけが異なることになります。 + +### 成果物の経路でのマイグレーション [#migrations-on-the-artifact-path] + +この経路での「アプリのアップグレード」は環境の変更と再起動であり、スキーマとメタデータが初めて食い違いうる瞬間に、誰もターミナルの前にいません。そのため、この経路では(そしてこの経路だけは)安全なスキーマ変更を自動的に適用し、**破壊的な変更では起動を拒否します**。その際、すべての変更と、それを解決するコマンドを示します。それ以外のすべての起動では、スキーマを決して自動的に変更しない、常設の本番ポリシーが維持されます。 + +## ランタイムが推測しない起動時の判断 [#startup-decisions-the-runtime-will-not-guess] + +一部の設定は、設定が読み込まれるときにチェックされ、機能を落として動くのではなく**拒否**されます。拒否されると、食い違っている設定を示す致命的なエラーが出力され、終了します。 + +- **ライセンスのモードとクラウドの方式は結び付いています。** 通常のライセンスはコントロールプレーンに対してオンラインで検証され、エアギャップライセンスはネットワーク通信なしにローカルで検証されます。通常のライセンスと「コントロールプレーンなし」の組み合わせは、機能を落として動くのではなく不可能であり、検証が試みられる前に拒否されます。完全な対応表は[エアギャップ](/docs/deploy/air-gapped)にあります。 +- **クラウドの方式を未設定のままにすることは「クラウドなし」ではありません。** 未設定は*公開*のコントロールプレーンに解決されます。どこにも通信しないつもりのデプロイメントは、そのことを明示しなければなりません。 +- **複数組織の方式にはライセンスが必要です。** さらに 2 つの判断が必須になります。新しいサインアップが何に参加するか、そしてどの AI エージェントをマウントするかです。どちらも、利用可能な値のいずれかを宣言すれば受け付けられますが、決めないことは受け付けられません。単一組織のデプロイメントには、どちらのチェックもありません。 +- **クラスタードライバーを使うと、共有のシークレットキーが 1 つ必須になります。** すべてのレプリカで同じものです。クラスタードライバーがなければ各レプリカが独自のキーを生成しますが、レプリカ間ではそれらが黙って食い違ってしまうので、ランタイムは代わりに起動を拒否します。 + +## コントロールプレーンに接続する [#connecting-to-a-control-plane] + +コントロールプレーンは、マーケットプレイスのカタログを提供し、通常のライセンスを検証するものです。接続は貼り付けた認証情報ではなく**バインディング**です。デプロイメントはコントロールプレーンに一度バインドされ、ランタイムは発行されたトークンを永続化して、以降のすべての呼び出しでそれを提示します。配布したり手でローテーションしたりするデプロイメントの API キーはありません。 + +バインドされ、クラウドに接続されたデプロイメントも、やはり単一環境のデプロイメントです。コントロールプレーンに接続しても、1 つのデプロイメントが複数になることはありません。 + +## データベース [#database] + +本番では、デプロイメントを**マネージド**データベースに向け、同梱のデータベースサービスをスタックから取り除きます。同梱のものは初回の実行を動かすためにあるもので、本番の構成ではなく、コンテナローカルのストレージは業務データを置く場所ではありません。 + +ドライバーは接続 URL のスキームから推測されます。明示的に上書きするのは、スキームがその情報を表せない場合だけにしてください。サポートされていない値は、推測にフォールバックせずに失敗します。 + +出荷時のスタックは、スキーマのマイグレーションを、**どのアプリケーションのレプリカが起動するよりも前に完了する一回限りのステップ**として実行するので、並行するレプリカが互いにスキーマ変更を実行し合うことはありません。ほかのオーケストレーターでは、この順序を再現しなければなりません。追加のデータソースの宣言については[データソース](/docs/configure/data-sources)を、復元の側については[バックアップ](/docs/operate/backup)を参照してください。 + +## 認証のシークレット [#authentication-secret] + +セッションは基本のシークレットから署名され、それは**すべてのレプリカで同一**でなければなりません。ローテーションすると既存のすべてのセッションが無効になり、保存されている署名キーも宙に浮きます。そのためローテーションは設定の微調整ではなく計画的な作業であり、ローテーションに必要な追加のステップ 1 つは、デプロイバンドルのテンプレートに記載されています。シークレットはシークレットマネージャーに保管し、決してイメージには入れないでください。 diff --git a/content/docs/configure/storage.ja.mdx b/content/docs/configure/storage.ja.mdx new file mode 100644 index 0000000..b2715a4 --- /dev/null +++ b/content/docs/configure/storage.ja.mdx @@ -0,0 +1,176 @@ +--- +title: ストレージ +seoTitle: "ファイルストレージ:ローカルディスク、S3、R2、MinIO、Spaces" +description: ObjectOS がファイルを置く場所。ローカルディスク、S3、R2、MinIO、Spaces。 +editions: [community, enterprise] +translation: + source_sha: 118eaaca8ed60b6085a54db822fa0487a70e083e96da8920405ffa3e1616d68d + guide_rev: 1 + mode: auto +--- + +ObjectOS のファイル(添付ファイル、アップロード、生成されたドキュメント)は**ストレージサービス**を通ります。2 つのアダプターを持つプラグイン可能な抽象化で、**ローカルファイルシステム**(デフォルト)と **S3 互換**(本番)があります。 + +このサービスは `@objectstack/service-storage` が提供し、スタンドアロンとプロジェクトの起動ではデフォルトで有効です。 + +## ユーザーがどう使うか [#how-users-interact-with-it] + +| 画面 | 動作 | +|---|---| +| UI のファイル / 画像フィールド | ブラウザが署名付き URL を使ってストレージに直接アップロードします | +| REST `/api/v1/storage/*` | プログラムからのアップロード / ダウンロードのエンドポイント | +| オブジェクトの `file` / `image` フィールド | アップロード用のウィジェットとしてレンダリングされ、メタデータは `sys_file` に永続化されます | + +ファイルは `sys_file` システムオブジェクトで追跡され、レコードに生のパスとして保存されることはありません。これにより、データモデルとストレージのバックエンドが切り離されます。 + +## ローカルファイルシステム(デフォルト) [#local-filesystem-default] + +向いている用途:開発、シングルノードのデプロイメント、デモ。 + +```ts +// objectstack.config.ts (or wherever you assemble plugins) +import { StorageServicePlugin } from '@objectstack/service-storage'; + +new StorageServicePlugin({ + adapter: 'local', + local: { + rootDir: './uploads', + baseUrl: 'http://localhost:3000', // for presigned URLs + signingSecret: process.env.OS_STORAGE_SIGNING_SECRET, // optional; auto-generated if omitted + }, + presignedTtl: 3600, // seconds — TTL for presigned URLs + sessionTtl: 86400, // seconds — TTL for chunked upload sessions +}); +``` + +スタンドアロンモード(プロジェクトなしの `os start`)では、ランタイムが `.objectstack/data/uploads/` の下にローカルストレージを自動的に設定します。ルートディレクトリは `OS_STORAGE_ROOT` 環境変数で上書きできます。 + +**本番に適しているかどうかはデプロイメントの形によります:** + +- ✅ デスクトップアプリ、シングルノードの社内ツール、エッジ / オンプレミスのアプライアンス:`uploads/` ディレクトリがファイルシステムのバックアップに含まれていれば(デスクトップアプリならユーザーが管理する同期フォルダーにあれば)、ローカルストレージで問題ありません。 +- ❌ マルチノード、マルチ AZ、またはリージョンをまたぐ耐久性が必要なもの:S3 互換ストレージを使ってください。 + +## S3 互換(本番) [#s3-compatible-production] + +向いている用途:本番、マルチノード、耐久性 + ライフサイクル管理。 + +```bash +pnpm add @aws-sdk/client-s3 @aws-sdk/s3-request-presigner +``` + +```ts +import { StorageServicePlugin } from '@objectstack/service-storage'; + +new StorageServicePlugin({ + adapter: 's3', + s3: { + bucket: 'my-bucket', + region: 'us-east-1', + // omit credentials to use the AWS SDK's default chain + // (env, ~/.aws, IAM role) + }, +}); +``` + +AWS SDK は通常の連鎖から認証情報を読み取ります。 + +| ソース | 環境変数 | +|---|---| +| 標準の環境変数 | `AWS_ACCESS_KEY_ID`、`AWS_SECRET_ACCESS_KEY`、`AWS_REGION` | +| セッショントークン | `AWS_SESSION_TOKEN` | +| 共有設定 | `~/.aws/credentials`、`AWS_PROFILE` | +| IAM ロール | EC2 / ECS / EKS / Lambda では自動。設定は不要です | + +### Cloudflare R2 [#cloudflare-r2] + +```ts +new StorageServicePlugin({ + adapter: 's3', + s3: { + bucket: 'my-bucket', + region: 'auto', + endpoint: 'https://.r2.cloudflarestorage.com', + forcePathStyle: false, + }, +}); +``` + +認証情報:R2 のアクセスキー ID + シークレット。標準の `AWS_*` 環境変数、またはシークレットマネージャーで渡します。 + +### MinIO(セルフホスト) [#minio-self-hosted] + +```ts +new StorageServicePlugin({ + adapter: 's3', + s3: { + bucket: 'my-bucket', + region: 'us-east-1', + endpoint: 'http://minio.internal:9000', + forcePathStyle: true, + }, +}); +``` + +### DigitalOcean Spaces [#digitalocean-spaces] + +```ts +new StorageServicePlugin({ + adapter: 's3', + s3: { + bucket: 'my-bucket', + region: 'nyc3', + endpoint: 'https://nyc3.digitaloceanspaces.com', + forcePathStyle: false, + }, +}); +``` + +### S3 バケットポリシー [#s3-bucket-policy] + +ストレージは署名付きの PUT/GET URL を使います。推奨されるバケットポリシー: + +- すべての公開アクセスをブロックします。 +- CORS:ObjectOS のホスト名から `PUT`/`GET` を許可します。 +- ライフサイクル:未完了のマルチパートアップロードを 1〜7 日後に期限切れにし、`temp=true` のタグが付いたオブジェクトを 24 時間後に期限切れにします。 +- バージョニング + Object Lock:省略可能。コンプライアンスが求められるデプロイメントでは推奨です。 + +## REST のエンドポイント [#rest-surface] + +これらは `@objectstack/client` が呼び出すので、通常は直接たたくことはありません。 + +| メソッド | パス | 目的 | +|---|---|---| +| POST | `/api/v1/storage/upload/presigned` | 署名付きのアップロード URL を取得します | +| POST | `/api/v1/storage/upload/complete` | 完了したアップロードを確定します | +| POST | `/api/v1/storage/upload/chunked` | 分割アップロードを開始します | +| PUT | `/api/v1/storage/upload/chunked/:uploadId/chunk/:i` | チャンクをアップロードします | +| POST | `/api/v1/storage/upload/chunked/:uploadId/complete` | 分割アップロードを完了します | +| GET | `/api/v1/storage/upload/chunked/:uploadId/progress` | 進捗をポーリングします | +| GET | `/api/v1/storage/files/:fileId/url` | 署名付きのダウンロード URL を取得します | + +ファイルごとの認可は、セキュリティプラグインの権限評価器が `sys_file` オブジェクトに対して処理するので、ストレージ層の ACL を別に用意する必要はありません。 + +## 稼働中の設定 [#live-configuration] + +設定サービスが有効な場合(デフォルトで有効です)、管理者は再起動せずに **Setup → Configuration → Storage** でストレージのアダプターを切り替えられます。 + +- アダプター、バケット、リージョン、エンドポイントを選びます。 +- 認証情報を貼り付けます(`sys_setting` に暗号化して保存されます)。 +- 保存する前に **Test connection** をクリックします。 + +変更は次のリクエストから適用されます。再起動は必要ありません。 + +## サイジング [#sizing] + +| リソース | デフォルト | 調整方法 | +|---|---|---| +| 署名付き URL の TTL | 1 時間 | プラグインオプション `presignedTtl` | +| 分割アップロードのセッションの TTL | 24 時間 | プラグインオプション `sessionTtl` | +| 単一パートのアップロードの最大サイズ | バックエンドが課す制限(S3 = 5 GB) | — | +| 分割アップロードの最大サイズ | バックエンドが課す制限(S3 = 5 TB) | — | + +## 次に進む [#where-to-go-next] + +- [システム設定](/docs/configure/system-settings):稼働中の設定と、ストレージの切り替えに使われる設定サービス +- [本番環境への準備](/docs/operate/production):オブジェクトストレージの耐久性とバックアップを含むチェックリスト +- [GitHub 上の `@objectstack/service-storage`](https://github.com/objectstack-ai/objectstack/tree/main/packages/services/service-storage):ソースとオプションの完全なリファレンス diff --git a/content/docs/configure/system-settings.ja.mdx b/content/docs/configure/system-settings.ja.mdx new file mode 100644 index 0000000..752d4c1 --- /dev/null +++ b/content/docs/configure/system-settings.ja.mdx @@ -0,0 +1,95 @@ +--- +title: システム設定 +seoTitle: "システム設定:ブランディング、機能フラグ、シークレット" +description: マニフェストと共有の K/V ストアを通じて、テナントとユーザーの設定を構成します。 +editions: [community, cloud, enterprise] +translation: + source_sha: 61207542689619b2c68ae9534fa57297ca2d5796e8075a5a304434c60891b695 + guide_rev: 1 + mode: auto +--- + +ObjectStack には、ランタイムとプラグインの設定のための設定サービスが含まれています。アプリケーションの成果物が設定機能を必要とする場合、ObjectOS はそれらの設定を Setup で公開します。 + +## 設定のモデル [#settings-model] + +設定はコードで宣言され、値として保存されます。 + +| レイヤー | 目的 | +|---|---| +| Settings Manifest | フィールド、ラベル、デフォルト、検証、表示条件、アクションを定義します | +| `sys_setting` | テナント / ユーザーの K/V の値を保存します | +| Resolver | 実効値を読み取ります | +| Console UI | 標準の設定ページをレンダリングします | + +プラグインは、通常の設定のためにその場限りの設定テーブルを作るべきではありません。設定のマニフェストを宣言し、ObjectOS に一貫した方法で値をレンダリングして保存させるべきです。 + +## 解決の順序 [#resolution-order] + +各設定はスコープ(`global`、`tenant`、`user`)を宣言します。リゾルバーは優先順位の高いものから低いものへと連鎖をたどり、最初に設定されている値が採用されます。 + +```text +Environment override (locked) +Global setting +Tenant setting +User setting +Manifest default +``` + +環境による上書きはロックされます。値が環境変数で設定されている場合、Setup はそれをホストが管理しているものとして表示し、実行時の編集を拒否します。連鎖の上位のどこかでロックされた値は実効値もロックするので、下位のスコープがそれを覆い隠すことはできません。 + +## よくある設定の領域 [#common-settings-areas] + +顧客向けの設定には、通常次のものが含まれます。 + +| 領域 | 例 | +|---|---| +| メール | SMTP ホスト、プロバイダーの API キー、送信元アドレス、テストメール | +| ブランディング | 製品名、ロゴの URL、アクセントカラー、デフォルトのテーマ | +| 機能フラグ | テナントレベルの機能スイッチ | +| ストレージ | ローカルのファイルシステム、またはオブジェクトストレージの認証情報 | +| AI プロバイダー | モデルのプロバイダー、API キー、予算の上限 | +| SSO | OIDC プロバイダーの設定と接続テスト | + +## ブランディング [#branding] + +**Setup → Configuration → Branding** にあります。これらの設定は、ワークスペースの表示上のアイデンティティ、つまり名前、ロゴ、色を制御します。 + +| 設定 | 備考 | +|---|---| +| `Workspace name` | 必須。UI 全体に表示される名前(デフォルト `ObjectStack`) | +| `Support email` | ヘルプのためにユーザーに示されるアドレス(例:`support@example.com`) | +| `Default theme` | `Match system`、`light`、または `dark` | +| `Accent colour` | ピッカー付きの 16 進数の色(デフォルト `#6366f1`) | +| `Logo URL` | ワークスペースのロゴの URL | + +## 機能フラグ [#feature-flags] + +**Setup → Configuration → Feature Flags** `[Beta]` にあります。このワークスペースの実験的な機能とベータ機能を切り替えます。**Productivity**(AI Assistant、Kanban swimlanes)と **Collaboration**(Realtime cursors、Inline comments)にグループ化されています。それぞれがテナントレベルの UI スイッチです。 + +> **ベータ機能は予告なく変更されることがあります。** 環境変数(例:`OS_FEATURE_FLAGS_AI_ENABLED=true`)でフラグを固定すると、デプロイメント全体でロックできます。環境による上書きはロックされるので、`OS_FEATURE_FLAGS_*` の変数は UI のトグルより優先されます。 + +## シークレット [#secrets] + +パスワードと認証情報のフィールドは、設定サービスで暗号化するか、環境で管理される値として提供すべきです。シークレットプロバイダーが設定されている場合、設定サービスは暗号文を `sys_secret` に保存し、`sys_setting` にはハンドルだけを保持します。シークレットを成果物、compose ファイル、Git に保存しないでください。 + +## テストアクション [#test-actions] + +設定のマニフェストは、次のような標準のアクションボタンを宣言できます。 + +- テストメールを送る +- SSO の検出をテストする +- オブジェクトストレージの認証情報を検証する +- Webhook の送信先を検証する + +運用者にまずログを調べてもらう代わりに、顧客のセットアップの流れではこれらのアクションを使ってください。 + +## 関連項目 [#related] + +いくつかの設定の領域には、専用の設定ガイドがあります。 + +- [メール](/docs/configure/email) +- [ストレージ](/docs/configure/storage) +- [AI プロバイダー](/docs/configure/ai) +- [認証と SSO](/docs/configure/authentication) +- [ランタイム](/docs/configure/runtime) diff --git a/content/docs/configure/users.ja.mdx b/content/docs/configure/users.ja.mdx new file mode 100644 index 0000000..5fe33ce --- /dev/null +++ b/content/docs/configure/users.ja.mdx @@ -0,0 +1,154 @@ +--- +title: ユーザーと組織 +description: 事業単位のツリーを作り、ユーザーを追加して招待し、メンバーシップとチームを管理し、サービスアカウントをプロビジョニングします。 +editions: [community, cloud, enterprise] +translation: + source_sha: b196256973c869eb90df98eb14987f85c2762e3ec3b5bdf578f3be8d33b5344c + guide_rev: 1 + mode: auto +--- + +デプロイメントに*誰が存在するか*に関するすべて、つまり人、その人が属する組織ツリー、共同作業するチーム、そしてその人の代わりに動作するサービスアカウントは、**Setup → People & Organization**(`/apps/setup`)で管理します。 + +基になるアイデンティティのオブジェクト(`sys_user`、`sys_organization`、`sys_member`、`sys_business_unit`、`sys_team`、`sys_invitation`、`sys_api_key` など)はプロジェクトのデータベースにあります。それぞれが何を表すかは、[アイデンティティ層の表](/docs/configure/permissions#layer-1--identity)を参照してください。 + +> **日々の管理作業の 90% は、人をポジションに割り当てることです。** ポジション、その背後にある権限セット、セキュリティのベースラインは、プラットフォームとインストールしたアプリとともに提供されます。あなたの仕事は人の側(このページで扱います)と割り当て([アクセスの管理](/docs/configure/permissions/managing-access)で扱います)です。 + +## 組織を作る(事業単位) [#build-the-organization-business-units] + +**Setup → People & Organization → Business Units。** + +事業単位のツリーは、アクセスモデルにおける*唯一の*階層です。表示範囲の深さ(`unit`、`unit_and_below`)と委任された管理の境界を決めます。導入時に作り、組織再編のときだけ見直します。 + +- デフォルトの **Org Chart** タブは、ツリーを字下げされた展開 / 折りたたみ可能なツリーグリッドとしてレンダリングします。 +- まずルート(種類 `company`)を作成し、次に **New** で子を追加して、フォームで **Parent Business Unit** を選びます。種類の `division` / `department` / `office` / `cost_center` は表示上のヒントで、ツリーはどれでも同じように機能します。 +- 再編するには、単位を **Edit** して親を変更します。ツリービューは読み取り専用の表示です。親の付け替えはドラッグ&ドロップではなく、レコードのフォームで行います。 + +似た名前の 3 つのもの、3 つの異なる役割です。混同しないでください。 + +| オブジェクト | 役割 | +|---|---| +| **事業単位**(`sys_business_unit`) | 階層。表示範囲の深さと委任された管理の境界を決めます | +| **チーム**(`sys_team`) | フラットな共同作業のグループ。チームは共有を*受け取り*ますが、機能を持つことはありません | +| **組織**(`sys_organization`) | テナントそのもの。会社のアカウントであって、その中のノードではありません | + +> ツリーは浅く、実際の構造に忠実に保ってください。組織構造によって*人がどのレコードを見られるか*に影響するべきものなら、それは事業単位です。人がレコードを共有するためのグループにすぎないなら、それはチームです。 + +## 人を追加する [#add-people] + +**Setup → People & Organization → Users。** 入口は 3 つあり、どれも第一級の方法です。 + +| 経路 | 使う場面 | 起こること | +|---|---|---| +| **Invite User**(ツールバー) | 本人に届くメールアドレスがある | 招待を送ります。本人は承諾時に自分でパスワードを設定します | +| **Create User**(ツールバー) | メールのフローを使いたくない、または電話番号だけのスタッフ | すぐにサインインできるアカウント(メールアドレスと電話番号のいずれかまたは両方)を作成します。生成された一時パスワードが**一度だけ**表示され、初回ログイン時にパスワードの変更が強制されます | +| **Import**(ツールバー) | CSV/Excel からの一括の受け入れ | 列の対応付けとドライランのプレビューを備えたウィザード。1 バッチあたり最大 500 行です。サインインのポリシーを選びます。デフォルトの **auto**(16.0)は、届くすべての行を招待し、届かない行に対してだけワンタイムの一時パスワードにフォールバックします。または明示的に選びます:パスワードなし(OTP / マジックリンク / リセットリンクで初回サインイン)、招待を送る、ワンタイムの一時パスワード | + +保留中の招待は **Setup → People & Organization → Invitations** に一覧されます。 + +セルフ登録を開かない限り、人が自分でアカウントを作成することはできません。ObjectStack 17.3 以降、サインアップの Audience のデフォルトは**招待のみ**で、人が入ってくるのはこれら 3 つの経路です。これらは Audience の設定にかかわらず機能します。人が自分でサインアップできるようにするには、[Authentication → Who may sign up](/docs/configure/authentication#who-may-sign-up-objectstack-173) を参照してください。 + +同じフローは、スクリプトによる受け入れのために REST でも利用できます(ObjectStack 14.3+)。 + +```bash +# Create a sign-in-ready account with an optional one-time password +curl -X POST https://crm.example.com/api/v1/auth/admin/create-user + +# Bulk-import rows / CSV / XLSX (max 500 rows), with dry-run and upsert modes +curl -X POST https://crm.example.com/api/v1/auth/admin/import-users +``` + +16.0 以降、インポートのデフォルトは `passwordPolicy: 'auto'` です。配信可能なチャネル(実在のメールアドレスと接続済みのメールサービス、または SMS の招待経路を持つ電話番号)を持つ行は**招待され**、届かない行だけが一時パスワード(一度だけ返され、`must_change_password`)を受け取ります。アイデンティティだけを作る旧来の動作にするには、`passwordPolicy: 'none'` を明示的に渡します。行ごとの結果は `rows[].delivery` に現れ、`summary.delivery` に内訳があります。 + +ペイロード、パスワードのポリシー、電話番号だけのアカウントについては、[Authentication → Admin user management](/docs/configure/authentication#admin-user-management-objectstack-143) で扱っています。 + +## 組織メンバーシップの階層 [#organization-membership-tiers] + +すべてのメンバーシップの行(`sys_member`)は**階層**を持ちます。ユーザーが組織の中で持つ立場です。この語彙は閉じていてプラットフォームが所有しています(ADR-0108)。次の 4 つの値だけで、アプリが何を宣言してもそれが広がることはありません。 + +| 階層 | 意味 | +|---|---| +| `owner` | 組織の最上位の立場。どの階層でも招待でき、ほかの owner を削除できる唯一の階層です | +| `admin` | 組織を管理します。`owner` 以外のどの階層でも招待できます | +| `delegated_admin` | 組織の管理者で**なくても**、組織への招待を発行できます。届く範囲はそれですべてです。階層そのものは何の権限にも解決されません。下記を参照してください | +| `member` | 通常の立場。管理上の到達範囲はありません。アクセスは、ほかの全員と同じく、ポジションと権限セットを通じて得られます | + +> **このページでは、2 つの異なるレコードが「メンバーシップ」と呼ばれています。** `sys_member` は*どの組織に、どの階層で属しているか*に答えます。`sys_business_unit_member`([次のセクション](#place-people-in-the-org-tree-memberships))は*どの事業単位に属しているか*に答えます。誰かを組織ツリーに配置しても階層は変わらず、階層を変えても誰も配置されません。 + +階層は招待(`sys_invitation.role`)で選ばれ、メンバーシップの行(`sys_member.role`)に保存されます。どちらのフィールドも同じ 4 つの値に固定された選択リストなので、アプリケーション独自の業務上のロール(`sales_manager`)をどちらにも保存することはできず、それを指定した招待は、行が書き込まれる前に拒否されます。職務は[ポジション](/docs/configure/permissions/positions)です。 + +誰がどの階層を与えられるかには 2 つのルールがあります。招待は発行者自身の階層より上の階層を与えることは決してできず、`admin` より下の発行者は `member` としてしか招待できません。 + +**階層は何に*届く*かを決める等級であり、何を*してよいか*をまとめたものでは決してありません。** `owner` と `admin` の目に見える力は、別の仕組みから来ています。この 2 つの階層のメンバーシップには、その組織にスコープされた組織管理者の権限セットが自動的に付与されます。権限を持つのはその権限セットで、階層は誰がそれを受け取るかを決めるだけです。 + +### `delegated_admin` は委任された管理ではない [#delegated_admin-is-not-delegated-administration] + +名前がほとんど同じ 2 つの仕組みです。間違ったほうを使ってしまうことを防ぐために、このセクションがあります。 + +| | `delegated_admin`(メンバーシップの階層) | [委任された管理](/docs/configure/permissions/permission-sets#delegated-administration)(権限セット) | +|---|---|---| +| 置かれる場所 | `sys_member.role` | 権限セットが持つ `adminScope` | +| 答える問い | *そもそも招待のフローに届くか?* | *実際に何を付与できるか*:どの事業単位、どの権限セットか | +| 単独での効果 | 一般のメンバーを招待できますが、誰も配置できません | 通常の割り当ての経路で管理できますが、招待は発行できません | + +この 2 つは**二重にオプトインで、互いに独立しています**。スコープ付きの委任者が、新しい人を事業単位にポジション付きで配置する招待を発行できるようになるには、誰かがメンバーシップの階層を設定し、**かつ** `adminScope` を付与しなければなりません。一方を付与しても他方を付与したことにはなりません。`delegated_admin` を持っていても、[委任された管理](/docs/configure/permissions/permission-sets#delegated-administration)に挙げられている権限は何も与えられません。 + +## 人を組織ツリーに配置する(メンバーシップ) [#place-people-in-the-org-tree-memberships] + +人を組織ツリーに配置するのは別のレコードです。**Business Unit Member** の行(`sys_business_unit_member`:ユーザー + 事業単位、1 つが*主*としてマークされます)です。深さに基づく表示範囲と `unit_and_subordinates` の共有はこのメンバーシップを通じて解決されるので、省略しないでください。メンバーシップの行を持たないユーザーは、深さに基づくルールからは見えません。 + +誰かが部署を移ったときは、その人の Business Unit Member の行を更新し、ポジションの割り当てを付け直します。[アクセスの管理](/docs/configure/permissions/managing-access)を参照してください。 + +## チーム [#teams] + +**Setup → People & Organization → Teams。** チームはフラットな共同作業のグループです。共有ルールとレコードの共有はチームを対象にできますが、チームが権限セットを持つことはありません。部署をまたぐグループが、誰の職務も組織ツリーも変えずに一連のレコードを見る必要があるときに使います。 + +## ユーザーのライフサイクル [#user-lifecycle] + +日々のライフサイクルのアクションは、各ユーザーの行のメニューとレコードのヘッダーにあります。 + +| アクション | 効果 | +|---|---| +| **Ban / Unban** | サインインを即座にブロック(または復元)します | +| **Unlock Account** | 総当たり攻撃によるロックアウトを早めに解除します | +| **Set Password** | パスワードを直接設定します。変更が強制されるワンタイムの一時パスワードも発行します | +| **Impersonate User** | サポートと確認のために、そのユーザーとしてセッションを開きます(セッションは記録されます) | + +誰かを無効にするには、まず **Ban** します。サインインは即座にブロックされます。その後、ポジションの割り当てとメンバーシップを落ち着いて削除します。退社時の完全な手順は[アクセスの管理](/docs/configure/permissions/managing-access)にあります。 + +> ユーザー自身によるセルフサービスのパスワード復旧は、設定された[メール](/docs/configure/email)または SMS の配信サービスに依存します。それが接続されるまでは、管理者による **Set Password**(一時的で、変更が必須)が確実な代替手段です。 + +## サービスアカウントと API キー [#service-accounts--api-keys] + +連携とヘッドレスのエージェントは API キー(`sys_api_key`)で認証します。**ユーザーに結び付いた**、長期間有効なプログラム用の認証情報です。キーを使ったすべての呼び出しは、そのユーザーとして、そのユーザーの権限で実行されます。 + +個人的なスクリプト以外では、専用のサービスユーザーを作成してください。 + +1. 連携のために **Create User** します(招待は不要です)。 +2. 連携が扱うオブジェクトをカバーする最小の権限セットを割り当てます。管理者のセットは決して割り当てないでください。 +3. **Setup → Connect an Agent** から、または REST で、そのユーザーの API キーを発行します。 + +```bash +curl -b cookies.txt -X POST https://crm.example.com/api/v1/keys +# → { "key": "osk_..." } — shown once; store it in your secret manager +``` + +キーの使い方、ヘッダー、ローテーションについては [API アクセス](/docs/configure/api-access)で、キーによる AI エージェントの接続については [AI ツールを接続する(MCP)](/docs/configure/mcp)で扱っています。 + +## よくある質問 [#faq] + +**新しいユーザーにほとんど何も見えません。壊れていますか?** いいえ、それはベースラインが機能しているということです。認証されたすべてのユーザーは、加算的な `member_default` のベースラインを受け取ります。本当のアクセスは、ポジションを割り当てたときに得られます。 + +**部署とチームの違いは?** 部署 = 事業単位(階層、表示範囲)。チーム = フラットな共有グループ。 + +**組み込みの権限セットを削除できますか?** いいえ。`member_default` や `organization_admin` のようなセットはプラットフォームのベースラインです。提供されたセットは上書きするか、単に割り当てずにおくことができます。 + +## 次に進む [#where-to-go-next] + +| タスク | ページ | +|---|---| +| ポジションと権限セットを割り当てる | [アクセスの管理](/docs/configure/permissions/managing-access) | +| 階層化されたアクセスモデルを理解する | [権限](/docs/configure/permissions) | +| サインイン、SSO、パスワードのポリシーを設定する | [認証](/docs/configure/authentication) | +| 招待とリセットが届くようにメールを設定する | [メール](/docs/configure/email) | +| 連携のための API キー | [API アクセス](/docs/configure/api-access) | diff --git a/content/docs/configure/webhooks.ja.mdx b/content/docs/configure/webhooks.ja.mdx new file mode 100644 index 0000000..b03dc1f --- /dev/null +++ b/content/docs/configure/webhooks.ja.mdx @@ -0,0 +1,80 @@ +--- +title: Webhook +seoTitle: "Webhook:少なくとも 1 回の配信、HMAC、再試行" +description: 永続的なアウトボックスによる ObjectOS からの外向きの Webhook。少なくとも 1 回の配信、HMAC 署名、上限付きの再試行、そして受信側が処理しなければならないこと。 +editions: [community, cloud, enterprise] +translation: + source_sha: 2ee03cd61fb199bf53a062ec6aaa901ef3542135e0616c669c40ac4d7a1c57fd + guide_rev: 1 + mode: auto +--- + +ObjectOS は、外向きの Webhook に永続的な**アウトボックス**モデルを使います。Webhook プラグインが有効なとき、業務上の変更は配信の行をキューに入れ、バックグラウンドのディスパッチャーが再試行しながらそれを配信します。そのため、遅い、または利用できない受信側が、元のトランザクションをブロックすることはありません。 + +## Webhook を有効にする [#enabling-webhooks] + +Webhook は省略可能な機能です。デプロイされる ObjectOS のイメージに `@objectstack/plugin-webhooks` が含まれていなければならず、アプリケーションの成果物は Webhook のサブスクリプションを登録しなければなりません(通常は `sys_webhook` オブジェクトのレコードとして)。 + +有効にすると、Setup に 2 つのオブジェクトが表示されます。 + +| オブジェクト | 目的 | +|---|---| +| `sys_webhook` | Webhook のサブスクリプション(送信先 URL、イベントのフィルター、シークレット、ステータス) | +| `sys_webhook_delivery` | 配信ログ(URL、レスポンスコード、試行回数、再試行のタイムスタンプ) | + +## 配信の意味 [#delivery-semantics] + +- **少なくとも 1 回。** 一時的な失敗の後、配信が再試行されることがあります。受信側は冪等でなければなりません。 +- **永続的。** 配信は業務データベースに保存されるので、ObjectOS の再起動を越えて残ります。 +- **パーティション分割。** 各ディスパッチャーのワーカーはアウトボックスのパーティションを担当するので、デプロイメントは二重配信なしにディスパッチを水平にスケールできます。 +- **上限付きの再試行。** 失敗した配信は、設定可能な上限までバックオフしながら再試行されます。上限に達した行は、調査のために `sys_webhook_delivery` に残ります。 + +## 署名 [#signing] + +すべての配信は識別用のヘッダーを持つので、受信側はそれをルーティングし、重複を排除し、検証できます。 + +```text +X-Objectstack-Event: +X-Objectstack-Delivery: +X-Objectstack-Attempt: +``` + +Webhook のサブスクリプションに `secret` がある場合、ObjectOS はすべてのリクエストに署名もします。 + +```text +X-Objectstack-Signature: sha256= +``` + +署名は、生のリクエスト本文に対して計算した `HMAC-SHA256(secret, body)` です。ペイロードを信頼する前に、受信側で検証してください。 + +```js +import { createHmac, timingSafeEqual } from 'node:crypto'; + +function verify(body, signatureHeader, secret) { + const expected = 'sha256=' + createHmac('sha256', secret).update(body).digest('hex'); + return timingSafeEqual(Buffer.from(signatureHeader), Buffer.from(expected)); +} +``` + +シークレットをローテーションするには、新しいシークレットで新しいサブスクリプションを発行し、移行期間の間は両方を動かし、その後古いものを無効にします。 + +## 受信側に期待されること [#receiver-expectations] + +- 数秒以内に `2xx` で応答します。`408`、`429`、`5xx` のレスポンス(またはタイムアウト / トランスポートのエラー)は再試行可能で、バックオフしながら再試行されます。それ以外の `4xx` は恒久的な失敗として扱われ、それ以上再試行されずに `dead` へ移されます。 +- ディスパッチャーは `2xx` を確認するまで配信を成功とマーク**しない**ので、受信側が失敗すると、調査や再配信のために行が `sys_webhook_delivery` に残ります。 +- 冪等にします。`X-Objectstack-Delivery` ヘッダー(配信 ID)か、ペイロード内の独自のイベント ID で重複を排除してください。 + +## 失敗への対処 [#failure-handling] + +何かが失敗したとき: + +1. `sys_webhook_delivery` でその行を確認します。`status`、`response_code`、`response_body`、`attempts` が記録されています。 +2. ObjectOS から受信側への外向きのネットワークアクセスを確認します。 +3. 受信側が恒久的に変更された場合は、サブスクリプションの URL を更新し、Setup からその行を再配信します。 +4. インシデントのレビューのために、監査ログ(`sys_audit_log`)はサブスクリプションの編集を記録しますが、ペイロードは記録しません。ペイロードはアウトボックスに残ります。 + +## 運用のヒント [#operational-tips] + +- Webhook の URL にシークレットを入れないでください(クエリ文字列はログに記録されます)。 +- 専用の受信側ホスト名を使うと、メインのアプリに影響を与えずに、エッジでそれをブロックして負荷を切り離せます。 +- ディスパッチャーの遅延を監視します。アウトボックスが増え続けているなら、たいていは受信側の性能が落ちています。