From 4c93e10cba561edee321f0dfb6a5f8a0c0210fdc Mon Sep 17 00:00:00 2001 From: Steedos Date: Thu, 29 Oct 2026 10:17:59 +0000 Subject: [PATCH 01/22] docs(i18n): translate the entry path into ja (index, why, start, editions, use) Phase 1 of the other-locale plan. Adds ja translations of the 19 entry-path pages (index, why, start/*, editions/*, use/*) and the ja sidebar labels for start/ and editions/. Every heading keeps its English id, fences match the English byte for byte, terms follow the glossary's ja column, and each page carries a --stamp. check-translations: ja 0 stale, 79 missing (was 98). Fixes #386 Claude-Session: https://claude.ai/code/session_01QsR2jRsjbApbf83iyTDDXm Co-Authored-By: Claude --- content/docs/editions/compare.ja.mdx | 62 ++++ content/docs/editions/license.ja.mdx | 118 ++++++++ content/docs/editions/meta.ja.json | 5 + content/docs/editions/public-preview.ja.mdx | 26 ++ content/docs/index.ja.mdx | 87 ++++++ content/docs/start/cloud.ja.mdx | 45 +++ content/docs/start/community.ja.mdx | 296 ++++++++++++++++++++ content/docs/start/enterprise.ja.mdx | 30 ++ content/docs/start/meta.ja.json | 5 + content/docs/use/approvals.ja.mdx | 76 +++++ content/docs/use/collaboration.ja.mdx | 122 ++++++++ content/docs/use/dashboards.ja.mdx | 71 +++++ content/docs/use/files.ja.mdx | 94 +++++++ content/docs/use/import.ja.mdx | 125 +++++++++ content/docs/use/index.ja.mdx | 94 +++++++ content/docs/use/notifications.ja.mdx | 68 +++++ content/docs/use/profile.ja.mdx | 78 ++++++ content/docs/use/records.ja.mdx | 85 ++++++ content/docs/use/search.ja.mdx | 102 +++++++ content/docs/use/views.ja.mdx | 90 ++++++ content/docs/why.ja.mdx | 124 ++++++++ 21 files changed, 1803 insertions(+) create mode 100644 content/docs/editions/compare.ja.mdx create mode 100644 content/docs/editions/license.ja.mdx create mode 100644 content/docs/editions/meta.ja.json create mode 100644 content/docs/editions/public-preview.ja.mdx create mode 100644 content/docs/index.ja.mdx create mode 100644 content/docs/start/cloud.ja.mdx create mode 100644 content/docs/start/community.ja.mdx create mode 100644 content/docs/start/enterprise.ja.mdx create mode 100644 content/docs/start/meta.ja.json create mode 100644 content/docs/use/approvals.ja.mdx create mode 100644 content/docs/use/collaboration.ja.mdx create mode 100644 content/docs/use/dashboards.ja.mdx create mode 100644 content/docs/use/files.ja.mdx create mode 100644 content/docs/use/import.ja.mdx create mode 100644 content/docs/use/index.ja.mdx create mode 100644 content/docs/use/notifications.ja.mdx create mode 100644 content/docs/use/profile.ja.mdx create mode 100644 content/docs/use/records.ja.mdx create mode 100644 content/docs/use/search.ja.mdx create mode 100644 content/docs/use/views.ja.mdx create mode 100644 content/docs/why.ja.mdx diff --git a/content/docs/editions/compare.ja.mdx b/content/docs/editions/compare.ja.mdx new file mode 100644 index 00000000..bfcf0726 --- /dev/null +++ b/content/docs/editions/compare.ja.mdx @@ -0,0 +1,62 @@ +--- +title: エディションの比較 +seoTitle: "ObjectOS エディションの比較:Community、Free、Team、Enterprise" +description: ObjectOS の各エディションとプランに含まれるものを 1 行ずつ。Community、Cloud Free、Cloud Team、Enterprise、そして各違いがどこで強制されるか。 +editions: [community, cloud, enterprise] +translation: + source_sha: 453d01cdf9083450d82f8221495bfac52b798f6ccb9ac8ffbbc5796920086128 + guide_rev: 1 + mode: auto +--- + +ObjectOS は 3 つのエディションを持つひとつの製品です。**ObjectOS Community** は自分で実行するオープンソースのランタイムです。**ObjectOS Cloud** は同じ製品をあなたのためにホストしたもので、**Free** と **Team** のプランがあります。**ObjectOS Enterprise** は自社のインフラストラクチャ上で実行するライセンス制の製品で、**Business** と**Business Self-Managed** はその下の契約オプションです。料金と契約は[ライセンスと料金](/docs/editions/license)にあります。このページは、それぞれが何を違う形で行うかを説明します。 + +このドキュメントのすべてのページは、タイトルの下にエディションバッジの行を持ち、適用されるエディションを示します。サイドバーは、すべてのエディション向けではないページとグループに同じアイコンで印を付けます。 + +## 比較表 [#the-matrix] + +| | **Community** | **Cloud Free** | **Cloud Team** | **Enterprise** | +|---|---|---|---|---| +| 提供形態 | セルフマネージド | ホスト型 | ホスト型 | セルフマネージド | +| 料金 | 無料(Apache-2.0) | 無料 | $24 / AI シート / 月 | 契約による | +| ファイルストレージ | 自前([ストレージ](/docs/configure/storage)) | 環境ごとに 1 GB | 環境ごとに 20 GB | 自前([ストレージ](/docs/configure/storage)) | +| 開発環境 | デプロイした数だけ | —(本番のみ) | 2 つ、さらに AI シートごとに 1 つ | デプロイした数だけ | +| MCP リクエスト | デプロイで設定 | 20 / 分、1,000 / 日 | 120 / 分、1 日の上限なし | デプロイで設定 | +| カスタムドメイン | 自前のホスト | — | ✓ | 自前のホスト | +| レコードレベルおよびフィールドレベルのセキュリティ | ✓ | — | ✓ | ✓ | +| UI 内の AI(AI Builder、「データに質問する」) | MCP のみ:モデルは持ち込み | お試し | ✓ | ✓ | +| AI ガバナンス(アクションの監査、ガードレール、権限のスコープ設定) | — | — | — | ✓ | +| 自社の ID プロバイダーによるシングルサインオン | ✓([認証](/docs/configure/authentication)) | — | — | ✓ | +| SCIM | — | — | — | ✓ | +| クラスタリング / 高可用性 | — | — | — | ✓ | +| ひとつのデプロイ上の複数の組織 | — | — | — | ✓ | +| エアギャップ運用 | — | — | — | ✓ | +| サポート | コミュニティ | コミュニティ | スタンダード | SLA + 専任 | + +ObjectOS Cloud では、シングルサインオンと AI ガバナンスは **Business**、すなわちホスト型サービス上の ObjectOS Enterprise の契約オプションに含まれます。セルフマネージドのデプロイでは、Community と Enterprise は同じランタイムを実行します。Community 列にあるものはすべて Enterprise 列にもあります。 + +## 各違いがどこで強制されるか [#where-each-difference-is-enforced] + +比較表には、製品が強制する違いだけを載せています。以下は、このドキュメントですでに詳しく説明しているものです。 + +- **ライセンスが、セルフマネージドのデプロイが何であるかを決めます。** ライセンスがない場合、単一組織のデプロイは Community の動作で実行されます。オープンな MCP サーバーで、AI は持ち込みです。ライセンスがある場合、AI Builder と「データに質問する」が自社のインフラストラクチャ上で利用可能になります。[AI サービス](/docs/configure/ai)を参照してください。 +- **ひとつのデプロイ上の複数の組織にはライセンスが必要です。** ライセンスなしのマルチ組織の体制は起動時に拒否され、ランタイムはトラフィックを処理しません。[ランタイム設定](/docs/configure/runtime)と[トラブルシューティング](/docs/operate/troubleshooting)を参照してください。 +- **エアギャップ運用はライセンスモードです。** 通常のライセンスはコントロールプレーンに対してオンラインで検証されます。エアギャップライセンスはローカルで検証され、デプロイはコントロールプレーンがないことも宣言しなければなりません。機能し得ない組み合わせは起動時に拒否されます。[エアギャップデプロイ](/docs/deploy/air-gapped)を参照してください。 +- **ObjectOS Cloud では、プランは環境ごとに強制されます。** 開発環境は Free では拒否されます(`403 DEV_ENV_PLAN_LOCKED`)。容量が満杯の環境は添付ファイルのアップロードと一括インポートを拒否しますが、単一レコードの書き込み、読み取り、エクスポートは決して拒否しません(`403 STORAGE_LIMIT_REACHED`、80% から警告)。MCP エンドポイントはプランのリクエスト上限を超えると `429` を返します。[環境](/docs/cloud/environments)と[ストレージと上限](/docs/cloud/storage-and-limits)を参照してください。 +- **ライセンスが失効してもランタイムは決して停止しません。** Business Self-Managed は有料機能をオフにし、データとランタイムは動作し続けます。フルの Enterprise デプロイは最後に支払ったバージョンを維持します。[ライセンスと料金](/docs/editions/license#faq)を参照してください。 + +## このページはどのエディション向けか [#which-edition-is-this-page-for] + +| バッジ | 意味 | +|---|---| +| Community | ObjectOS Community を自分で実行する場合に当てはまる | +| Cloud | ObjectOS Cloud の Free および Team プランで当てはまる | +| Enterprise | ライセンスを受けたセルフマネージドの ObjectOS Enterprise デプロイで当てはまる | + +デプロイと運用は、2 つのセルフマネージドのエディション、Community と Enterprise 向けです。ObjectOS Cloud では、私たちがデプロイを運用します。 + +## 次へ [#next] + +- [開始](/docs/start/cloud):3 つの入り口。Cloud、Community、Enterprise。 +- [ライセンスと料金](/docs/editions/license):料金、契約、オープンソースライセンス。 +- [パブリックプレビュー](/docs/editions/public-preview):ObjectOS Cloud の現在の段階が、データと連携にとって何を意味するか。 diff --git a/content/docs/editions/license.ja.mdx b/content/docs/editions/license.ja.mdx new file mode 100644 index 00000000..7cb56e42 --- /dev/null +++ b/content/docs/editions/license.ja.mdx @@ -0,0 +1,118 @@ +--- +title: ライセンスと料金 +description: ObjectOS は 3 つのエディションを持つひとつの製品です。Community(オープンソース、無料)、Cloud、Enterprise。それぞれのライセンス形態と、ObjectStack フレームワークとの関係を説明します。 +editions: [community, cloud, enterprise] +translation: + source_sha: 8214fa1bad828f1ed43938ca72f4a791acb69e4bdb82a1e015eec4e78d2d1128 + guide_rev: 1 + mode: auto +--- + +## ひとつの製品、3 つのエディション [#one-product-three-editions] + +ObjectOS は **ObjectStack アプリケーションの公式ランタイム環境**で、3 つのエディションがあります。**ObjectOS Community**(オープンソース、セルフホスト、無料)、**ObjectOS Cloud**(私たちが運用)、**ObjectOS Enterprise**(商用ライセンスのもとであなたが運用)です。ObjectStack は、3 つのエディションが実行するプロトコル、SDK、CLI、フレームワークの名前です。 + +{/* + Naming, decided under #79 and re-confirmed on #107: "Console UI" here and in + the Apache-2.0 list further down names the *component* — the shipped browser + bundle, the `@objectstack/console` package, the same spelling architecture.mdx + and configure/system-settings.mdx were deliberately kept at. #79 retired + "Console" as the name of the end-user surface (a reader opens ObjectOS, not + "the Console") but kept the names of things the product ships, and a license + enumerates artifacts rather than surfaces. Both occurrences on this page are + therefore deliberate — do not rewrite them to "the UI" or to "ObjectOS". +*/} + +オープンソースの部分には 2 つの名前と 1 つのライセンスがあります。**[ObjectStack フレームワーク](https://github.com/objectstack-ai/objectstack)**(Apache-2.0)はプロトコル、カーネル、SDK、CLI です。**ObjectOS Community** はそこから構築されたオープンソースのランタイムと Console UI です。本番用のランタイムイメージ、MCP サーバー、権限と共有、監査、あらゆるプロトコル機能など、**独自のアプリケーションを構築、実行、セルフホスト**するために必要なものすべてが無料で、開発と本番の間に機能の制限はありません。そのコードは同じ objectstack リポジトリにあります。ObjectOS Cloud と ObjectOS Enterprise は、その仕組みの上に**組み込みの AI** と**公式に運用 / サポートされる**プラットフォームが欲しいときに購入するものです。 + +## エディション [#editions] + +ObjectOS Community は無料です。2 つの商用エディションには、ひとつの料金表と 2 つの提供形態があり、**AI シート**が唯一の課金単位です。 + +| | **Community** | **Free** | **Team** | **Enterprise** | +|---|---|---|---|---| +| エディション | ObjectOS Community | ObjectOS Cloud | ObjectOS Cloud | ObjectOS Enterprise | +| 提供形態 | **セルフマネージド** | クラウド | クラウド | **セルフマネージド(プライベートデプロイ)** | +| 料金 | **無料**(Apache-2.0) | **無料** | **$24** / AI シート / 月 | 個別見積もり(ボリューム):[営業にお問い合わせください](mailto:sales@objectstack.ai) | +| UI 内の AI(AI Builder +「データに質問する」) | MCP のみ(モデルは持ち込み) | お試し | ✓ | ✓ | +| AI ガバナンス(アクションの監査、ガードレール、権限のスコープ設定) | — | — | — | ✓ | +| クラスタリング / HA、マルチ組織のセルフホスト、エアギャップ、SCIM | — | — | — | ✓ | +| サポート | コミュニティ | コミュニティ | スタンダード | SLA + 専任 | + +Team とフルのプライベートデプロイの間には、**ObjectOS Enterprise の下の 2 つの契約オプション**があり、料金はこれまでどおりです。**Business**(ObjectOS Cloud 上の SSO と AI ガバナンス、**$54** / AI シート / 月、年額払いでは $45 / AI シート / 月。優先サポート)と **Business Self-Managed**(シングルノードのエントリーオプション、**$540** / AI シート / 年)です。どちらも契約により販売されます。[営業にお問い合わせください](mailto:sales@objectstack.ai)。 + +**無料で**セルフホストしたいですか?それが **ObjectOS Community** です(MCP のみの AI:モデルは持ち込み)。下の [ObjectOS Community](#objectos-community) を参照してください。 + +**オープンな仕組み、クローズドなインテリジェンス。** データをモデル化しアプリを実行するために必要なものはすべてオープンソースです(ObjectStack フレームワーク上の ObjectOS Community)。Cloud と Enterprise は、その上に*組み込みのインテリジェンス*(製品内の AI Builder と「データに質問する」アシスタント。ガバナンスと監査付き)を重ね、さらに運用のスケールと公式サポートを加えます。 + +**支払うのは AI シートだけです。** 課金されるシートは **AI シート**だけです。閲覧者、AI を使わないアプリユーザー、MCP 上で構築する開発者は無料で、ユーザーごとのシート課金はありません(ユーザーあたり $150〜300 の既存製品とは明確に対照的です)。 + +## クラウドかセルフマネージドか [#cloud-or-self-managed] + +セルフマネージドの ObjectOS は、**ObjectOS Community**(無料)または **ObjectOS Enterprise**(ライセンス制)です。Cloud は Free と Team で、Team より上はすべて Enterprise の契約です。 + +- **Cloud(Free / Team)**:フルホスト型、セルフサービス。料金にはホスティングと十分な月間 AI 利用枠が含まれます(モデルは私たちが実行します)。 +- **Enterprise**:契約により販売されるライセンス制の ObjectOS で、3 つの形があります。 + - **Business**:ObjectOS Cloud 上の契約オプション。ホスト型サービス上の SSO / SAML と AI ガバナンス(アクションの監査、ガードレール、権限のスコープ設定)、$54 / AI シート / 月、または年額払いで $45 / AI シート / 月、優先サポート。 + - **Business Self-Managed**:シングルノードのエントリーオプション。Business プランを **10〜25 AI シート**向けの**シングルノード Docker ライセンス**として提供します($540/AI シート/年、年額)。自社のインフラストラクチャ上で UI 内の AI と AI ガバナンスを利用でき、**モデル / キーは持ち込み**です(LLM のコストは自分で支払います。プラットフォームの AI 請求や従量課金はありません)。カード払い、スタンダードサポート。ライセンスが失効しても、ランタイムは動作し続け、データはそのまま残ります。有料機能がオフになるだけです(使えなくなることは決してありません)。 + - **フルのプライベートデプロイ**:それを超えるすべてのもの。クラスタリング / HA / マルチノード、マルチ組織のセルフホスト、データレジデンシーと**エアギャップ**運用、SCIM と ID ライフサイクル、コンプライアンスの証明、SLA と専任サポート、オフライン / 請求書払い。複数年の価格固定オプション付きの**年間ライセンス**として販売されます。更新しない場合、デプロイは**最後に支払ったバージョンを永続的に維持**します(失うのはアップデートとサポートであり、システムやデータではありません)。料金はボリュームベースです。[営業にお問い合わせください](mailto:sales@objectstack.ai)。 + +**ノードごとの課金はありません**。クラスタリング / スケールは Enterprise に含まれます。 + +## それぞれが適するとき [#when-you-might-want-each] + +| シナリオ | 選ぶもの | +|---|---| +| プラットフォームを**ホストして運用してほしい** | ObjectOS Cloud(Free → Team) | +| ホスト型サービスで **SSO と AI ガバナンス**が必要 | **Business**、ObjectOS Cloud 上の ObjectOS Enterprise の契約オプション | +| **自社のシングルノード**で実行しなければならず、製品内の AI が欲しい、25 AI シート以下 | **Business Self-Managed**、ObjectOS Enterprise の契約オプション(シングルノードのエントリー) | +| **クラスタリング / HA**、**マルチ組織**、**エアギャップ**、**SCIM**、コンプライアンスの証明、SLA、オフライン払いが必要 | **ObjectOS Enterprise**、フルのプライベートデプロイ | +| ObjectOS Community をセルフホストしているが、**商用契約付きのサポートされたディストリビューション**(SLA、セキュリティパッチの優先対応、指名エスカレーション)が必要 | **ObjectOS Runtime Subscription**:[営業にお問い合わせください](mailto:sales@objectstack.ai) | +| **無料のセルフホスト**で、MCP 経由で AI を持ち込みたい | **ObjectOS Community**(オープンソース) | +| ObjectOS または ObjectStack の名前で **OEM / 再配布**の権利が必要 | 商用契約:[営業にお問い合わせください](mailto:sales@objectstack.ai) | + +## ObjectOS Community [#objectos-community] + +**ObjectOS Community**(ランタイムイメージと Console UI)と、その土台である **ObjectStack フレームワーク**は、[Apache License, Version 2.0](https://www.apache.org/licenses/LICENSE-2.0) のもとでライセンスされています。コピーレフトなし、明示的な特許許諾、永久に無料。シートも、利用ティアも、ライセンスサーバーも、キーも、テレメトリもありません。ノート PC、自社のサーバー、顧客のサーバー、1000 ポッドのクラスターのどこで実行しても、ライセンスは同じです。そこでの AI の経路はオープンな **MCP サーバー**です。自分の Claude Code(または任意の MCP クライアント)をデプロイに向ければ、自分のモデルでデータをクエリし操作できます。 + +Apache-2.0 であるもの(objectstack リポジトリ内):ランタイムイメージ、すべての`@objectstack/*` npm パッケージ(ランタイム、プラグイン、サービス、ドライバー、アダプター、CLI、クライアント SDK)、templates リポジトリ、そして Console UI(それが提供する Account アプリを含む)。ドキュメントは CC-BY-4.0 です。 + +全文:[LICENSE](https://github.com/objectstack-ai/objectstack/blob/main/LICENSE) + +## 商標 [#trademarks] + +「ObjectOS」と ObjectOS のロゴは**商標**であり、どのコードライセンスの対象でもありません。自社の製品が ObjectOS / ObjectStack の*上に構築されている*、または*互換性がある*と事実に即して述べることはできます。自社の製品名、会社名、ドメイン名にこれらの名前やロゴを使うには書面による許可が必要です。[TRADEMARK.md](https://github.com/objectstack-ai/docs.objectos.ai/blob/main/TRADEMARK.md) を参照してください。 + +## サードパーティのコンポーネント [#third-party-components] + +ObjectOS は ObjectStack フレームワークと、いくつかの上流のオープンソースプロジェクト(Node.js、Hono、Zod、Better Auth、AI SDK など)の上に構築されています。それぞれに独自のライセンスが付属し、すべて商用利用と互換性のある Apache-2.0、MIT、BSD 系の寛容なライセンスです。完全な一覧は、各リリースとともに公開される SBOM を参照してください。 + +## よくある質問 [#faq] + +### ObjectOS はオープンソースですか? [#is-objectos-open-source] + +**ObjectOS Community** はオープンソースです。ランタイムと Console は Apache-2.0 で無料、そのもととなる ObjectStack フレームワークと並んで [objectstack リポジトリ](https://github.com/objectstack-ai/objectstack)でオープンに開発されています。**ObjectOS Cloud**と **ObjectOS Enterprise** は商用エディションで、同じ仕組みの上に組み込みの AI、ホスティングと運用、SSO、サポートを加えたものです。 + +### 顧客に販売するクローズドソースの SaaS で ObjectStack を使えますか? [#can-i-use-objectstack-in-a-closed-source-saas-i-sell-to-my-customers] + +はい。Apache-2.0 にはコピーレフトもロイヤリティもありません。コードを共有する必要はなく、製品が利益を上げても支払うものはありません。 + +### 支払いなしで ObjectOS をセルフホストできますか? [#can-i-self-host-objectos-without-paying] + +はい。それが **ObjectOS Community** です。同じオープンな仕組みをセルフホストし、AI は MCP のみ(モデルは持ち込み)です。*ライセンス制*のセルフマネージドエディションは ObjectOS Enterprise で、その 2 つのオプション(シングルノードの Business Self-Managed、またはフルの Enterprise デプロイ)はどちらも、製品内の AI、AI ガバナンス、商用サポートを追加します。 + +### 更新しないとソフトウェアは動かなくなりますか? [#does-the-software-stop-working-if-i-dont-renew] + +使えなくなることは決してありません。Business Self-Managed は無料の仕組みの動作に戻ります(有料機能はオフになり、データとランタイムは動作し続けます)。フルの Enterprise デプロイは**最後に支払ったバージョンを永続的に**維持します。失うのはアップデート、新しい AI 機能、サポートであり、システムではありません。 + +### ObjectOS は外部に通信しますか? [#does-objectos-phone-home] + +ObjectOS Enterprise はライセンスをオンラインで検証します。エアギャップの Enterprise ライセンスはオフラインで検証します。ObjectOS Community にはテレメトリも、ライセンスチェックも、アップデートの確認通信もありません。 + +### ObjectOS Community に契約上の保証が欲しい場合は? [#what-if-i-want-a-contractual-warranty-on-objectos-community] + +それが **ObjectOS Runtime Subscription** です。ObjectOS Community に対するサポート契約(公式ディストリビューション、SLA、セキュリティパッチの優先対応)で、機能の違いはまったくありません。[sales@objectstack.ai](mailto:sales@objectstack.ai) にお問い合わせください。 + +### ObjectOS Community とフレームワークはずっと無料ですか? [#will-objectos-community-and-the-framework-always-be-free] + +はい。Apache-2.0 の許諾は取り消し不能であり、すでにリリースされたものはすべてリリース時のライセンスのままです。 diff --git a/content/docs/editions/meta.ja.json b/content/docs/editions/meta.ja.json new file mode 100644 index 00000000..df73148b --- /dev/null +++ b/content/docs/editions/meta.ja.json @@ -0,0 +1,5 @@ +{ + "title": "エディション", + "defaultOpen": false, + "pages": ["compare", "license", "public-preview"] +} diff --git a/content/docs/editions/public-preview.ja.mdx b/content/docs/editions/public-preview.ja.mdx new file mode 100644 index 00000000..60043f4d --- /dev/null +++ b/content/docs/editions/public-preview.ja.mdx @@ -0,0 +1,26 @@ +--- +title: パブリックプレビュー +seoTitle: "ObjectOS Cloud パブリックプレビュー:その意味" +description: ObjectOS Cloud はパブリックプレビュー段階です。データは保持され、API はまだ変更される可能性があり、SLA はまだありません。 +editions: [cloud] +translation: + source_sha: cd4762a38174841caa9a60deee0bb14fead010fe52bcf440543efe070cb2bcb2 + guide_rev: 1 + mode: auto +--- + +ObjectOS Cloud は**パブリックプレビュー**段階です。今日からサインアップし、実際のアプリを構築して実行できます。この段階の間は、次の 3 つが当てはまります。 + +| | パブリックプレビュー中 | +|---|---| +| **データ** | 永続的です。構築したものと保存したレコードは保持されます。プレビューは消去されるサンドボックスではありません。 | +| **API** | 変更される可能性があります。一般提供の前に、エンドポイント、パラメーター、レスポンスの形がリリース間で変わることがあります。 | +| **サービスレベル** | SLA はまだありません。公開されるまで、稼働率の約束もサービスクレジットもありません。 | + +## それがあなたにとって意味すること [#what-that-means-for-you] + +- **その上に構築してください。** アプリとそのデータは引き継がれます。プレビューが終わっても最初からやり直すことはありません。 +- **連携するものは固定してください。** 他のシステムが [REST API](/docs/reference/rest-api) や [MCP](/docs/configure/mcp) 経由で ObjectOS Cloud を呼び出す場合は、API が変わったときにその連携を見直すことを想定し、[変更履歴](/docs/resources/changelog)を確認してください。 +- **今すぐ SLA が必要ですか?** ObjectOS を自分で実行してください。**ObjectOS Enterprise** には契約のもとで SLA と専任サポートが付きます。[エディションの比較](/docs/editions/compare)と[ライセンスと料金](/docs/editions/license)を参照してください。 + +パブリックプレビューは ObjectOS Cloud だけの段階です。自分でデプロイして[アップグレード](/docs/operate/upgrade)する ObjectOS Community や ObjectOS Enterprise については何も意味しません。 diff --git a/content/docs/index.ja.mdx b/content/docs/index.ja.mdx new file mode 100644 index 00000000..baaf9d33 --- /dev/null +++ b/content/docs/index.ja.mdx @@ -0,0 +1,87 @@ +--- +title: はじめに +seoTitle: "ドキュメント:開始、構築、デプロイ、運用" +description: "ObjectOS は ObjectStack 上に構築された商用ランタイム環境で、ホスト型(ObjectOS Cloud)またはセルフマネージド(ObjectOS Enterprise)で動作します。オントロジーはあなたのものです。" +editions: [community, cloud, enterprise] +translation: + source_sha: 0347fa621f4342212be72ecb78497ccea72ca3490d850f45dc5b91549d81cf22 + guide_rev: 1 + mode: auto +--- + +オントロジーこそがソフトウェアです。実行可能なひとつのビジネスオントロジー。AI が書き、ランタイムが実行し、エージェントが操作し、あなたが所有します。同じループをブラウザ上のホスト型で、何もインストールせずに使いたいですか?それが ObjectOS、ObjectStack 上に構築された商用ランタイム環境です。ObjectOS は、何もインストールせずにブラウザ上のホスト型で動作するか(ObjectOS Cloud)、あなた自身のインフラストラクチャ上でセルフマネージドで動作し(ObjectOS Enterprise)、どちらのエディションでもオントロジーをエクスポートして、オープンソースの ObjectStack ランタイムで実行できます。 + +ビジネスに必要なもの(ヘルプデスク、承認フロー、CRM)を組み込みの [AI Builder](/docs/build/ai-builder) に説明するか、テンプレートをインストールすると、それが書いたオントロジーは即座に稼働します。REST API、生成された画面、認証、RBAC、監査ログ、ファイルストレージ、バックグラウンドジョブ、Webhook、そしてエージェントが呼び出せる MCP ツールとして公開されたすべてのオブジェクトです。各変更は小さく読みやすい差分で、実行前に人が承認します。 + +オープンソース(Apache-2.0)の [ObjectStack](https://github.com/objectstack-ai/objectstack) スタック、すなわちプロトコル、カーネル、CLI、本番ランタイムは、オントロジーを実行するものであり、ObjectOS の土台です。ObjectOS 上で構築したものはすべて通常の ObjectStack メタデータなので、構造上、そのランタイムへ移植できます。 + +## 開始 [#start] + +| やりたいこと | すること | +|---|---| +| ObjectOS を、何もインストールせずに | **ObjectOS Cloud**、あなたのためのホスト型です。最初のアプリを構築するには Free プランで十分です。[ObjectOS Cloud で始める](/docs/start/cloud)を参照してください | +| ObjectOS を、自社のインフラストラクチャ上でライセンスを受けて | **ObjectOS Enterprise** は、シングルノードの Business Self-Managed オプション以上で、ライセンスされた Enterprise イメージをあなたのサーバー上で実行します。[ObjectOS Enterprise で始める](/docs/start/enterprise)を参照してください | +| ObjectOS を、自分のマシン上で無料で | **ObjectOS Community** はオープンソースのランタイムです。`npm i -g @objectstack/cli && os start` で SQLite データベースとともに設定なしで起動します。[ObjectOS Community をローカルで実行する](/docs/start/community)を参照してください | + +その後、ObjectOS Cloud と ObjectOS Enterprise は同じ場所へ導きます。サインインして、次のことができます。 + +- **AI Builder と対話する**:*「サポートチケットを優先度と担当者付きで管理したい」*。AI Builder があなたの[オントロジー](/docs/ontology)、つまりオブジェクトとそのフィールドを、あなたが承認する小さな差分として書くのを見届けます。[構築 → AI Builder](/docs/build/ai-builder) を参照してください。 +- **組み込みのマーケットプレイスからテンプレートをインストールする**(Todo、Contracts、Helpdesk など)と、ワンクリックで本物のアプリが手に入ります。 +- **[テンプレート](/docs/build/templates)をフォークする**と、TypeScript ソースを自分の管理下に置けます。同じメタデータを、自分のリポジトリでコーディングエージェントとともに作成します。 + +## なぜ …… ではなく ObjectOS なのか [#why-objectos-instead-of-] + +| 今使っているもの | 課題 | ObjectOS が提供するもの | +|---|---|---| +| **Retool / Appsmith** | UI ビルダーは優れているが、データは彼らのクラウドにあり、料金はユーザー数に比例して増える | ホスト型(ObjectOS Cloud)またはあなたのネットワーク内(ObjectOS Enterprise)。オープンソースの ObjectStack(Apache-2.0)上に構築されているため、オントロジーは自由にエクスポートできます。シート課金なし、AI シートのみ | +| **Supabase / Firebase** | BaaS は速いがベンダーロックイン。設計上マルチテナント SaaS | 同じ開発体験(自動 API、認証、ストレージ)ですが、定義はあなたのものです。エクスポートしてオープンな ObjectStack ランタイムで実行するか、自社のデータベース上で ObjectOS Enterprise を実行します | +| **Salesforce / NetSuite** | 強力なプラットフォームだが、カスタマイズは苦痛で、シート単価は目が飛び出るほど高い | 馴染みのある語彙(オブジェクト、フィールド、権限セット、共有ルール)ですが、定義は AI が書き、エージェントが操作し、Apache-2.0 ランタイムへエクスポートできるオープンなオントロジーです。ホスト型でもセルフマネージドでも、シート課金なし。閲覧者と AI を使わないユーザーは無料です | +| **自前で構築(Next + Prisma + NextAuth)** | RBAC、監査、ファイルアップロード、設定、Webhook、ジョブを毎回作り直す | 本来のビジネスロジックを出荷できます。プラットフォームの配管はすでに揃っています | + +## 標準で得られるもの [#what-you-get-out-of-the-box] + +| サーフェス | 内容 | +|---|---| +| **自動 REST API** | 宣言したすべてのオブジェクトに、フィルター/ソート/ページネーション付きの `/api/v1/data/` が用意されます | +| **UI**(`/_console/`) | 生成された画面:レコードの閲覧と編集、そしてユーザー/ロール/権限セットの管理、監査ログ、セッション、API キー、設定の確認を行う **Setup** | +| **Account**([UI 内](/docs/resources/glossary#surface)) | ログイン、登録、パスワードリセット、OAuth、OIDC/SSO、パスキー、2FA | +| **MCP サーバー**(`/api/v1/mcp`) | デフォルトで有効:すべてのオブジェクトがツールであり、AI に公開したすべてのアクションもツールです。エージェントはユーザーとして、そのユーザーの権限のもとで接続します。[AI ツールを接続する(MCP)](/docs/configure/mcp)を参照してください | +| **20 以上のプラグイン** | RBAC + 行レベルセキュリティ、監査、ファイルストレージ、キュー、ジョブ、メール、AI、Webhook。宣言的で、必要に応じて有効化 | + +## あなたの手元に残るもの [#what-stays-yours] + +どちらのエディションでも、オントロジーはあなたのものです。オブジェクト、フィールド、リレーション、アクション、権限、フロー、エージェント定義は通常の ObjectStack メタデータであり、エクスポートしてオープンソースの ObjectStack ランタイムで実行できます。**ObjectOS Enterprise** では、それ以外のものもすべてあなたの手元に残ります。[データレジデンシー](/docs/reference/security#data-residency)には、データの各分類について、どこに保存され、ネットワークの外に出るかどうかが記載されています。 + +セルフマネージドの ObjectOS はライセンスをオンラインで検証します。Enterprise のエアギャップライセンスはオフラインで検証します。したがって、インターネットにアクセスできないネットワークは Enterprise の正式なデプロイ先です。[エアギャップ](/docs/deploy/air-gapped)を参照してください。 + +## ドキュメントを探す [#find-your-docs] + +このドキュメントは 4 種類の読者を対象としています。ObjectOS の使い方に合ったセクションから始めてください。 + +| あなたは …… | やりたいこと | ここから | +|---|---|---| +| **日常的なユーザー** | アプリで作業する:レコード、ビュー、ダッシュボード、承認 | [使い方](/docs/use) | +| **ビルダー** | アプリを作成する:データモデル、インターフェース、自動化、AI エージェント | [構築](/docs/build) | +| **管理者** | プラットフォームを運用する:ユーザー、権限、設定、デプロイ | [設定](/docs/configure)、[デプロイ](/docs/deploy)、[運用](/docs/operate/production) | +| **エージェント、またはそれを接続する人** | MCP 経由でアプリを操作する:レコードの読み書き、AI に公開されたアクションの実行。ユーザーの権限のもとで | [AI ツールを接続する(MCP)](/docs/configure/mcp) | + +## 次に進む [#where-to-go-next] + +| やりたいこと | 読むもの | +|---|---| +| 何もインストールせずに始める | [ObjectOS Cloud で始める](/docs/start/cloud) | +| 実際に動くところを見る | [ObjectOS Community をローカルで実行する](/docs/start/community) | +| 各エディションに含まれるものを比較する | [エディションの比較](/docs/editions/compare) | +| 中身を理解する | [アーキテクチャ](/docs/architecture) | +| Docker で実行する | [Docker](/docs/deploy/docker) | +| Kubernetes にデプロイする | [Kubernetes](/docs/deploy/kubernetes) | +| Postgres / 自社の DB に接続する | [ランタイム設定](/docs/configure/runtime) | +| SSO を設定する | [認証](/docs/configure/authentication) | +| 誰が何を見られるかを制限する | [権限](/docs/configure/permissions) | +| 別のサービスから呼び出す | [API アクセス](/docs/configure/api-access) | +| 他のシステムにイベントを送る | [Webhook](/docs/configure/webhooks) | +| 本番に移行する | [本番環境への準備](/docs/operate/production) | + +## ライセンスと料金 [#license--pricing] + +ObjectOS は **3 つのエディションを持つひとつの製品**です。**ObjectOS Community**、すなわち Apache-2.0 の **[ObjectStack フレームワーク](https://github.com/objectstack-ai/objectstack)** 上に構築されたオープンソースのランタイムと Console は、商用製品での利用、組み込み、セルフホストが無料で、シート単価もライセンスサーバーもありません。**ObjectOS Cloud** と **ObjectOS Enterprise** は、UI に組み込まれた AI、ガバナンス、公式の運用を追加し、料金は **AI シートのみ**です(閲覧者と AI を使わないユーザーは無料)。「年額 5 万ドルから」はありません。[ライセンスと料金](/docs/editions/license)を参照してください。 diff --git a/content/docs/start/cloud.ja.mdx b/content/docs/start/cloud.ja.mdx new file mode 100644 index 00000000..7086f29a --- /dev/null +++ b/content/docs/start/cloud.ja.mdx @@ -0,0 +1,45 @@ +--- +title: ObjectOS Cloud で始める +seoTitle: "ObjectOS Cloud で始める:サインアップして最初のアプリを構築する" +description: あなたのためにホストされる ObjectOS、インストールするものは何もありません。サインアップし、組織に名前を付け、その本番環境を作成し、最初のアプリを構築してチームを招待します。 +editions: [cloud] +translation: + source_sha: f83df72638808eeefa3a77e192b7ec0158e83be9e366f36a3d9c7fd74b8fedf5 + guide_rev: 1 + mode: auto +--- + +**ObjectOS Cloud** は、あなたのためにホストされ運用される ObjectOS です。作業はブラウザで行い、インストールやデプロイするものは何もありません。**Free** プランで最初のアプリを構築するには十分です。ObjectOS Cloud は[パブリックプレビュー](/docs/editions/public-preview)段階です。 + +自分のマシン上で使いたいですか?それは [ObjectOS Community](/docs/start/community) です。自社のインフラストラクチャ上で、ライセンスを受けて使いたいなら、[ObjectOS Enterprise](/docs/start/enterprise) です。 + +## 1. サインアップする [#1-sign-up] + +[www.objectos.ai](https://www.objectos.ai) から始めて、アカウントを作成します。 + +## 2. 組織を作成する [#2-create-your-organization] + +組織は、チームが共有するワークスペースです。そのアプリ、そのデータ、そのメンバーです。名前と **slug**(ObjectOS が組織を指すのに使う短い識別子)を付けます。 + +## 3. 本番環境を作成する [#3-create-the-production-environment] + +組織はアプリを環境の中で実行します。組織の**本番環境**を作成してください。最初のアプリはそこに置かれます。Free プランでは、本番が唯一の環境です。[環境](/docs/cloud/environments)を参照してください。 + +## 4. 最初のアプリを構築する [#4-build-your-first-app] + +方法は 2 つあり、両方を使えます。 + +- **[AI Builder](/docs/build/ai-builder) に説明する**:*「サポートチケットを優先度と担当者付きで管理したい」*。AI Builder はオブジェクト、フィールド、ビューを、実行前にあなたが承認する変更として提案します。 +- **[テンプレート](/docs/build/templates)をインストールして**、動作するアプリから始めます。 + +開発者にはさらに 2 つの道があります。ソースで構築して[パッケージ](/docs/build/packages#two-developer-routes-on-objectos-cloud)を公開するか、自分のエージェントに [MCP](/docs/configure/mcp#build-with-an-agent) 経由で、人が公開するドラフトとして構築させます。どちらの場合も、結果は通常の ObjectStack メタデータです。REST API、生成された画面、権限、監査がそれに付いてきます。次に追加できるものすべては[構築](/docs/build)を参照してください。 + +## 5. チームを招待する [#5-invite-your-team] + +アプリを使う人を招待します。課金されるのは **AI シート**だけです。閲覧者と、製品内の AI を使わずにアプリを使う人は無料です。招待とロールについては[組織とメンバー](/docs/cloud/organization)、環境内のアクセスについては[ユーザー](/docs/configure/users)、誰が何を見られるかについては[権限](/docs/configure/permissions)を参照してください。 + +## 次へ [#next] + +- [ObjectOS を使う](/docs/use):チームがサインインしたときに目にするもの。 +- [AI ツールを接続する(MCP)](/docs/configure/mcp):エージェントにユーザーの権限のもとでアプリを操作させます。 +- [エディションの比較](/docs/editions/compare):Free と Team それぞれに含まれるもの。 diff --git a/content/docs/start/community.ja.mdx b/content/docs/start/community.ja.mdx new file mode 100644 index 00000000..450a8c0d --- /dev/null +++ b/content/docs/start/community.ja.mdx @@ -0,0 +1,296 @@ +--- +title: ObjectOS Community をローカルで実行する +seoTitle: "os start または os init で ObjectOS Community をローカルで実行する" +description: "オープンソースのランタイムである ObjectOS Community で、ゼロから動作するアプリまで。ひとつの CLI、ひとつのコマンドで、アカウントも Docker も不要です。" +editions: [community] +translation: + source_sha: 830910eec853d34ebcd2357928eec4e753013766473391a72b60214c2479ce9e + guide_rev: 1 + mode: auto +--- + +**ObjectOS Community** は ObjectOS のオープンソースエディションです。ランタイムとその UI で、Apache-2.0 の ObjectStack フレームワーク上に構築され、どこでも無料で実行できます。このページでは、ひとつの CLI とひとつのコマンドで自分のマシン上に起動します。ここではアカウントもライセンスも Docker も必要ありません。 + +他の 2 つの入り口にはそれぞれ専用のページがあります。何もインストールせずにホスト型で使いたいなら [ObjectOS Cloud で始める](/docs/start/cloud)、自社のインフラストラクチャ上でライセンス制のエディションを使うなら [ObjectOS Enterprise で始める](/docs/start/enterprise)を参照してください。ここで構築したものは通常の ObjectStack メタデータなので、すべてのエディションで動作します。 + +オープンなランタイムを起動する方法は、何をしているかによって 2 つあります。 + +| あなたは …… | ここから | +|---|---| +| オープンなランタイムを初めて試す、または本番で実行する | [パス A:`os start`](#path-a--os-start-operator--first-time-evaluator) | +| コードでアプリを構築またはカスタマイズする | [パス B:`os init`](#path-b--os-init-developer) | + +どちらも UI 付きの稼働中のサーバーを生成します。アカウントのサインイン、登録、セルフサービスはその UI 内のルートであり、別のサーフェスではありません。違いは、ソースファイルをスキャフォールドするかどうかです。 + +## 前提条件 [#prerequisites] + +- **Node.js 22 以降**:`node --version` +- ターミナル + +それだけです。Docker も、データベースも、アカウント登録も不要です。 + +--- + +## パス A:`os start`(運用担当者 / 初めての評価者) [#path-a--os-start-operator--first-time-evaluator] + +CLI をグローバルにインストールしてから実行します。 + +```bash +npm i -g @objectstack/cli +os start +``` + +次のように表示されます。 + +```text +◆ ObjectStack +──────────────────────────────────────── +🏠 Home: ~/.objectstack +📦 Artifact: none (empty kernel — install apps via the Console marketplace) +🗄️ Database: file:~/.objectstack/data/objectstack.db +🎯 Environment: env_local + → Starting server... + + ✓ Server is ready + + ➜ API: http://localhost:3000/ + ➜ Console: http://localhost:3000/_console/ + ➜ MCP: http://localhost:3000/api/v1/mcp + connect an AI client (Claude Code, Cursor, …) · skill: http://localhost:3000/api/v1/mcp/skill + + Mode: production + Driver: SqlDriver(better-sqlite3) → ~/.objectstack/data/objectstack.db + Tenancy: single + Plugins: 32 loaded + + Press Ctrl+C to stop +``` + +それだけです。オープンソースのランタイムである ObjectOS Community が動作しています。ObjectOS Cloud と ObjectOS Enterprise がその上に何を追加するかは、[エディションの比較](/docs/editions/compare)を参照してください。 + +上のブロックは、`@objectstack/cli` 17.7.0 が空のカーネルを起動したときの出力を書き写したものです。ホームパスは `~/…` と表示していますが、CLI は展開したパスを表示します。実際の起動では、サーバーの起動前に `No objectstack.config.ts or artifact found` の行も表示され、さらに起動時の注意事項(ローカルストレージドライバー、開発用の暗号鍵、起動診断)と読み込まれたプラグイン名の完全な一覧も表示されます。どちらも環境によって異なります。 + +### 何が動いているか [#whats-running] + +| URL | 内容 | +|---|---| +| http://localhost:3000/_console/register | 最初のアカウントを作成する | +| http://localhost:3000/_console/ | 生成された UI と **アプリマーケットプレイス** | +| http://localhost:3000/_console/apps/setup | **Setup**:ユーザー、ロール、監査ログ、設定 | +| http://localhost:3000/api/v1/health | Liveness:プロセスが起動しているか | +| http://localhost:3000/api/v1/ready | Readiness:起動していて、**かつ**データを提供しているか | + +ランタイムは**空のカーネル**で起動します。オブジェクトもアプリもなく、マーケットプレイスが公開されているので、出来合いのアプリを数秒でインストールできます。 + +ここではどちらのプローブも 200 を返し、ローカルではそれをつなぐ先もありません。しかし両者は交換可能ではないので、デプロイする前にどちらがどちらかを知っておく価値があります。Liveness はプロセスが実行中であることだけを報告するため、データベースが停止している間もずっと正常のままです。Readiness は、データドライバーが応答しなくなった時点で **503** を返します。どのプローブをどこに使うかは [Docker](/docs/deploy/docker) と [Kubernetes](/docs/deploy/kubernetes)で説明しています。 + +### チャットで構築する:AI Builder [#build-by-chat--the-ai-builder] + +製品内の AI Builder は ObjectOS のものです。ObjectOS Cloud と ObjectOS Enterprise に含まれ、今起動したオープンなランタイムには含まれません。オープンなランタイムの AI 経路は、バナーに表示された MCP エンドポイント(`http://localhost:3000/api/v1/mcp`。Claude Code や任意の MCP クライアントをそこに向けます)です。ObjectOS では、サインインしたら AI アシスタント(右上のきらめきアイコン)を開き、必要なものを説明します。 + +> *「顧客サポートのチケットを管理したい。各チケットには件名、説明、優先度(low/medium/high/urgent)、ステータス、担当者がある。ステータスでグループ化したカンバンビューを追加して。」* + +AI が計画を提案し、あなたが承認すると、メタデータが稼働します。REST エンドポイント、生成されたビュー、監査ログのエントリ、権限によるゲートです。ファイルの編集も再起動もありません。語彙の全体は [構築 → AI Builder](/docs/build/ai-builder)を参照してください。 + +> **IDE で手書きしていますか?** `npx skills add objectstack-ai/objectstack/skills`を実行すると、Claude Code / Cursor / Copilot / Codex に、ObjectStack メタデータ(ObjectOS が実行するオントロジー)を実際の Zod スキーマに沿って作成する方法を教えられます。[構築 → IDE スキル](/docs/build/ai-skills)を参照してください。 + +### マーケットプレイスからアプリをインストールする [#install-an-app-from-the-marketplace] + +**http://localhost:3000/_console/** を開き、サインインして、アプリを選びます。 + +| アプリ | 得られるもの | +|---|---| +| Todo | 汎用のタスク & プロジェクト管理 | +| Contracts | AI による抽出付きの契約ライフサイクル | +| Procurement | ベンダー、発注書、3 点照合 | +| Compliance | SOC 2 / ISO 27001 の統制 + 証跡 | +| Helpdesk | AI ファーストのカスタマーサポート | +| Content | 編集カレンダー + チャネル ROI | +| HR | 名簿、組織図、休暇 | + +インストール → 再読み込み → そこにあります。オブジェクト、ビュー、権限、シードデータ付きです。再起動は不要です。 + +### よく使うフラグ [#common-flags] + +```bash +os start --port 3200 # different port +os start --database postgres://... # external database +os start --auth-secret "$(openssl rand -hex 32)" # enable auth in /api/v1/auth/* +os start --home /var/lib/objectos # persistent home (production) +``` + +すべてのオプションは[ランタイム設定](/docs/configure/runtime)を、本番向けの構成は [Docker](/docs/deploy/docker) を参照してください。 + +--- + +## パス B:`os init`(開発者) [#path-b--os-init-developer] + +独自のデータモデル、ビュー、フローを定義するために TypeScript を書くときに使います。 + +```bash +npx @objectstack/cli init my-app -t app --install +cd my-app +pnpm dev +``` + +次のように表示されます。 + +```text +◆ Development Mode +──────────────────────────────────────── +📂 Config: my-app/objectstack.config.ts + → Compiling objectstack.config.ts → dist/objectstack.json... + +◆ Compile +──────────────────────────────────────── + ✓ Build complete (312ms) + + Data: 1 Objects 3 Fields + UI: 0 Apps + Logic: 0 Flows + Security: 0 Positions 0 Permissions + Runtime: 0 plugins + + Artifact: my-app/dist/objectstack.json (2.2 KB) + + → Starting dev server (local mode)... +🎯 Environment ID: env_local +📦 Artifact: dist/objectstack.json +🗄️ Database: file:my-app/.objectstack/data/objectstack.db + 👁 watching objectstack.config.ts, src — rebuild + restart on change + + ✓ Server is ready + + ➜ API: http://localhost:3000/ + ➜ Console: http://localhost:3000/_console/ + ➜ MCP: http://localhost:3000/api/v1/mcp + connect an AI client (Claude Code, Cursor, …) · skill: http://localhost:3000/api/v1/mcp/skill + + 🔑 Dev admin: admin@objectos.ai / admin123 + seeded on empty DB · dev only — do not use in production + platform admin — Setup, Studio and every record, but NO app-declared capability, so + an app that gates navigation on requiredPermissions may show it an empty menu; grant + it a permission set under Setup → Users, or sign in as an account your app seeds + + Artifact: dist/objectstack.json + Mode: development + Driver: SqlDriver(better-sqlite3) → my-app/.objectstack/data/objectstack.db + Tenancy: single + Plugins: 38 loaded + + Press Ctrl+C to stop +``` + +上のブロックは、`@objectstack/cli` 17.7.0 で作成したスキャフォールド上で `pnpm dev` を実行したときの出力を書き写したものです。プロジェクトパスは `my-app/…` と表示していますが、CLI は展開したパスを表示します。また `Build complete` の時間は書き写したマシンが計測した値なので、あなたの環境では異なります。実際の実行では、ブロックの上に pnpm のスクリプトヘッダー、ステップごとのコンパイル進捗、起動時の注意事項(設定の読み込み、開発用のシークレットフィールド暗号化)、読み込まれたプラグイン名の完全な一覧、起動診断、MCP 接続の末尾メッセージも表示されます。その末尾メッセージは別のプロセスが出力するため、通常はバナーの途中に入り込み、しばしば 1 行ずつ交互に混ざります。 + +開発サーバーはポート **3000** を要求することに注意してください。これは `os start` と同じポートです。そのポートが使用中の場合は、次の空きポートにバインドし、そのことを表示します。`↪ server bound to port 3001 (requested 3000)`。 + +### 独自のオブジェクトを追加する [#add-your-own-object] + +追加するすべてのオブジェクトは、プロジェクトの名前空間を持ちます。`os init` はそれをプロジェクト名から導出し(`my-app` → `my_app`)、`objectstack.config.ts` に `manifest.namespace` として書き込んだので、タスクオブジェクトは`my_app_task` です。コンパイルは素の `task` を`Rename it to 'my_app_task' (namespace = 'my_app')` で拒否し、次のルールを示します。``Every object.name must be `${manifest.namespace}_${shortName}`.`` + +`src/objects/task.object.ts` を作成します。 + +```ts +// src/objects/task.object.ts +import { ObjectSchema, Field } from '@objectstack/spec/data'; + +const task = ObjectSchema.create({ + name: 'my_app_task', + label: 'Task', + fields: { + subject: Field.text({ label: 'Subject', required: true, maxLength: 200 }), + done: Field.boolean({ label: 'Done', defaultValue: false }), + due: Field.date({ label: 'Due' }), + assignee: Field.lookup('sys_user', { label: 'Assignee' }), + }, + // Org-wide default: who sees records they don't own. Required — the + // compile refuses an object that declares none. + sharingModel: 'private', +}); + +export default task; +``` + +次に、それを `src/objects/index.ts` からエクスポートします。`objectstack.config.ts` は各ディレクトリをその `index.ts` バレル経由で読み込むため、バレルがエクスポートしないファイルは読み込まれません。サンプルオブジェクトの行の下に次の行を追加します。`export { default as task } from './task.object';` + +`npx objectstack generate object task` は、ファイルのスタブと同じバレルの行を書き込みます。 + +保存します。開発サーバーは再コンパイルし、`✚ new object(s): my_app_task — table & seeds sync on restart` を表示して、新しいビルドで自分自身を再起動します。書くべきマイグレーションも、実行すべき再起動もありません。`✗ compile failed` だけが表示された場合は、`pnpm build` を実行して原因を確認してください。これで次のものが手に入ります。 + +- **`/api/v1/data/my_app_task`**:作成、読み取り、更新、削除を、フィルター、ソート、ページネーション付きで([REST API](/docs/reference/rest-api))。サインインした呼び出し元にのみ応答するので、まず開発用管理者としてサインインしてください(下記)。 +- **生成された一覧、フォーム、レコードページ**:スキャフォールドはまだアプリを宣言していないため、Console 内にそれらへのリンクはありません。`http://localhost:3000/_console/apps/setup/my_app_task` を開いてください。 +- **権限セットエディターの Task 行**:Setup → Permission Sets でセットを開き、*Design in Studio* を選びます。そのセットに対する作成、読み取り、編集、削除です。 +- **監査ログのエントリ**:作成、更新、削除のそれぞれが、Setup → Audit Logs に一覧表示されます。 + +```bash +curl -c cookies.txt -H 'Content-Type: application/json' \ + -d '{"email":"admin@objectos.ai","password":"admin123"}' \ + http://localhost:3000/api/v1/auth/sign-in/email +curl -b cookies.txt -H 'Content-Type: application/json' \ + -d '{"subject":"Try the API"}' \ + http://localhost:3000/api/v1/data/my_app_task +curl -b cookies.txt http://localhost:3000/api/v1/data/my_app_task +``` + +### プロジェクトの構成 [#project-layout] + +```text +my-app/ +├── objectstack.config.ts # defineStack(): manifest + one key per barrel +├── src/ # one index.ts barrel per directory +│ ├── actions/ +│ ├── apps/ +│ ├── dashboards/ +│ ├── flows/ +│ ├── objects/ # index.ts + my_app_item.object.ts, the sample object +│ ├── picklists/ +│ ├── skills/ +│ └── views/ +├── dist/ +│ └── objectstack.json # Compiled artifact (regenerated on save) +├── .objectstack/ # Local SQLite databases (pnpm dev creates them) +├── package.json +├── pnpm-workspace.yaml +└── tsconfig.json +``` + +`os init` は `.gitignore` とインストーラーのロックファイルも書き込みます。 + +`dist/objectstack.json` が本番に出荷するものです。これをランタイム(オープンな ObjectStack イメージ、または ObjectOS Enterprise のデプロイ)にマウントすると、それがあなたのアプリになります。 + +### テンプレートから始める [#or-start-from-a-template] + +本番向けのスターターは [github.com/objectstack-ai/templates](https://github.com/objectstack-ai/templates) にあります。 + +```bash +git clone https://github.com/objectstack-ai/templates.git +cd templates/packages/todo +pnpm install +pnpm dev # http://localhost:4002 +``` + +各テンプレートは 2500 行未満で、一度に読み通せ、単体で動作します。 + +--- + +## 標準で読み込まれるもの [#whats-loaded-out-of-the-box] + +どちらのパスでも、次のプラグインが自動的に読み込まれます。 + +> HTTP サーバー、REST API、Dispatcher、MCP サーバー、Auth、Security(RBAC + RLS + FLS)、Audit、Sharing、プラットフォームオブジェクト、Metadata、ObjectQL、デフォルトのデータソースと外部データソースおよびデータソース管理のサービス、Queue、Jobs、Cache、Settings、Email、SMS、Messaging、Storage、Analytics、外部検証、Marketplace、パッケージ管理、マイグレーションの復旧、Setup と Account のアプリ、そして Console UI。 + +パス B では、スキャフォールドの `objectstack.config.ts` が`requires: ['automation', 'triggers']` を宣言しているため、自動化サービスに加えて、レコード変更、スケジュール、相対時間、受信 HTTP/Webhook のフロートリガーも読み込まれます。また、`pnpm dev` が開発モードで実行されるため、専用のテレメトリデータソース(データベースの隣にある 2 つ目の SQLite ファイル)も開きます。 + +どれもインポートしたり配線したりする必要はありません。上の一覧は何も宣言していなくても読み込まれ、自動化サービスとフロートリガーは何かがそれを必要と宣言すると有効になり、開発モードはテレメトリデータソースを追加します。 + +## 次のステップ [#next-steps] + +| 次にすること | 読むもの | +|---|---| +| Docker で実行する(本番向けの構成) | [Docker](/docs/deploy/docker) | +| SQLite の代わりに Postgres を使う | [ランタイム設定](/docs/configure/runtime) | +| Google / Okta / Entra のログインを追加する | [認証](/docs/configure/authentication) | +| 誰が何をできるかを制限する | [権限](/docs/configure/permissions) | +| Slack / Zapier / 自社のサービスにイベントを送る | [Webhook](/docs/configure/webhooks) | +| 本番にデプロイする | [本番環境への準備](/docs/operate/production) | diff --git a/content/docs/start/enterprise.ja.mdx b/content/docs/start/enterprise.ja.mdx new file mode 100644 index 00000000..f8538773 --- /dev/null +++ b/content/docs/start/enterprise.ja.mdx @@ -0,0 +1,30 @@ +--- +title: ObjectOS Enterprise で始める +seoTitle: "ObjectOS Enterprise で始める:ライセンス制、セルフマネージド" +description: ObjectOS Enterprise は、自社のインフラストラクチャ上で実行するライセンス制のエディションです。ライセンスの入手方法と、デプロイガイドの出発点を説明します。 +editions: [enterprise] +translation: + source_sha: 65aa2affdd32ca612f967daaffd1275dc3cb60a61e72bd88b99c97ee9c0f11f2 + guide_rev: 1 + mode: auto +--- + +**ObjectOS Enterprise** は、商用ライセンスのもとで、あなたが運用するインフラストラクチャ上で動作する ObjectOS です。製品内の AI、AI ガバナンス、公式のサポートを自社のサーバー上で利用でき、フルのプライベートデプロイでは、クラスタリング、ひとつのデプロイ上の複数の組織、SCIM、エアギャップ運用も利用できます。完全な一覧は[エディションの比較](/docs/editions/compare)を、シングルノードの **Business Self-Managed** 以上の契約オプションは[ライセンスと料金](/docs/editions/license)を参照してください。 + +## 1. ライセンスを入手する [#1-get-a-license] + +ObjectOS Enterprise は契約により販売されます。[営業にお問い合わせください](mailto:sales@objectstack.ai)。ライセンスにはライセンスされた Enterprise イメージのレジストリ認証情報が付属し、各リリースのリリースノートには実行すべき正確なイメージダイジェストが記載されています。 + +## 2. デプロイする [#2-deploy] + +デプロイガイドは[デプロイ](/docs/deploy)から始まり、すべてのデプロイが行う 3 つの判断を順に説明します。その後、構成を選びます。 + +- [Docker](/docs/deploy/docker):サポートされる構成。プル、検証、ライセンス、実行、スケール、アップグレード。 +- [Kubernetes](/docs/deploy/kubernetes):どのオーケストレーターも保持しなければならない特性。 +- [エアギャップ](/docs/deploy/air-gapped):ライセンスモードとしてのエアギャップと、起動時に拒否される組み合わせ。 + +## 3. 運用する [#3-operate] + +[本番環境への準備](/docs/operate/production)は、本番稼働前のチェックリストです。そこから先のバックアップ、アップグレード、可観測性、監査ログは[運用](/docs/operate)で扱います。 + +購入前に評価したいですか?[ObjectOS Community](/docs/start/community) は同じランタイムを無料で実行し、その上で構築したものは通常の ObjectStack メタデータなので、そのまま Enterprise に移行できます。 diff --git a/content/docs/start/meta.ja.json b/content/docs/start/meta.ja.json new file mode 100644 index 00000000..5c8508c5 --- /dev/null +++ b/content/docs/start/meta.ja.json @@ -0,0 +1,5 @@ +{ + "title": "開始", + "defaultOpen": false, + "pages": ["cloud", "community", "enterprise"] +} diff --git a/content/docs/use/approvals.ja.mdx b/content/docs/use/approvals.ja.mdx new file mode 100644 index 00000000..bf28ea37 --- /dev/null +++ b/content/docs/use/approvals.ja.mdx @@ -0,0 +1,76 @@ +--- +title: 承認 +seoTitle: "承認の受信トレイ:申請、レビュー、リクエストの追跡" +description: レコードを承認に回し、自分に割り当てられたリクエストに対応し、すべての承認の状況を常に把握します。 +editions: [community, cloud, enterprise] +translation: + source_sha: 2e66606b534686f5a7d8944dc432440b441ef36a02de56101bfa89b2627a1ce3 + guide_rev: 1 + mode: auto +--- + +一部のレコードは、先に進む前に承認が必要です。上限を超える経費、値引き、休暇申請などです。そのような場合、ObjectOS は**承認リクエスト**を作成します。これはシステムが管理する稼働中のレコードで、その 1 回の申請を、送信された瞬間から誰かが承認または却下するまで追跡します。これらの追跡用レコードを自分で作成したり編集したりすることはありません。判断が下されるたびに、システムが最新の状態に保ちます。 + +このページでは、プロセスの両側を扱います。何かを承認に回すことと、自分を待っているリクエストに対応することです。 + +## 承認の受信トレイ [#your-approval-inbox] + +承認に関するものはすべて、ひとつの場所にあります:**Account → Inbox → Approvals**。**Account** アプリを開き(全員が利用できます)、左のサイドバーで **Inbox** を展開して、**Approvals** を選びます。 + +リストの上部にはビューのタブがあり、同じ受信トレイを 4 つの切り口で見られます。 + +| ビューのタブ | 表示内容 | +|---|---| +| **My Pending** | *あなた*の判断を待っているリクエスト。これがあなたの ToDo リストです。 | +| **I Submitted** | あなたが承認に回したリクエスト。自分の申請の状況はここで確認します。 | +| **Completed** | 判断が下された(承認または却下された)リクエスト。 | +| **All** | あなたが見られるすべての承認リクエスト。どれが見られるかは下で説明します。 | + +あなたを待っているものが何もないとき、**My Pending** には空の状態 *"No pending approvals — You're all caught up."* が表示されます。一日の終わりに見たい画面です。 + +**見えるのは、自分が関わっているリクエストです。** リクエストが見えるのは、それを申請した人、現在それが待っている相手(直接、または保持しているポジションを通じて)、そしてすでに判断またはコメントした人です。管理者はすべてのリクエストを見られます。レコードを開けるだけでは不十分です。レコードを読み取れても承認に関わっていない同僚には、そのリクエスト、コメント、添付ファイルは見えません。 + +> **ヒント:** Approvals の受信トレイをブックマークするか、ホームページの **Needs your attention** の一覧をちらっと見てください。保留中の承認はそこにも、待っている時間とともに表示されます。 + +## 承認リクエストとは [#what-an-approval-request-is] + +| これは…… | これではない…… | +|---|---| +| 申請ごとに追跡される稼働中のインスタンス。承認に回したレコード 1 件につきリクエスト 1 件 | レコード自体のコピー | +| システム管理。判断が下されるにつれて自動的に作成、更新、クローズされる | 手で編集するもの | +| 監査証跡。誰が申請し、誰が割り当てられ、何がいつ決まったか | 消えてしまう一度きりの通知 | + +各申請がそれぞれのリクエストを持つため、却下後にレコードを再申請すると、新しいリクエストが始まります。古いリクエストは履歴として **Completed** に残ります。 + +## リクエストに対応する [#acting-on-a-request] + +リクエストがあなたに回されると、2 つのことが起こります。 + +1. **通知が届きます**:トップバーのベルに未読のバッジが表示され、その項目がホームページの **Needs your attention** と **Account → Inbox → Notifications** に表示されます。 +2. **レコードにあなた向けの承認アクションが表示されます**:該当するレコードを開くと、レコードアクションとして **Approve** と **Reject** が表示されます。これらのボタンは割り当てられた承認者にだけ表示され、レコードを見ている他の人には表示されません。 + +| するには | 方法 | +|---|---| +| 自分を待っているものを確認する | **Account → Inbox → Approvals** → **My Pending**、またはベル / **Needs your attention** | +| 詳細を確認する | リクエストからレコードを開き、他のレコードと同じようにハイライトとフィールドセクションを読みます | +| 判断する | **Approve** または **Reject** のレコードアクションを使います | +| 処理されたことを確認する | リクエストが **Completed** に移り、申請者に通知されます | + +> **ヒント:** リクエストだけでなく、レコードを読んでください。承認リクエストは、何かに判断が必要だという*こと*を伝えます。承認す*べきかどうか*を伝えるのはレコード自体です。 + +## 保留中にロックされるレコード [#records-locked-while-pending] + +承認の設定によっては、リクエストが保留中の間、レコードが**ロック**されることがあります。判断が下されるまでフィールドを編集できません。これは承認者を守るためです。承認するものは申請されたものとまったく同じで、その間にこっそり編集されることはありません。ロックされたレコードを変更する必要がある場合は、承認者に却下してもらい(またはアプリが許す場合は取り下げ)、変更を加えてから再申請してください。 + +## アプリが提供するレビューキュー [#app-provided-review-queues] + +一部のアプリは、独自に整理した**レビューキューのページ**を追加します。たとえば、アプリのナビゲーションにある「Approvals」ページで、そのチームに関係する項目だけを、あらかじめフィルターした状態で処理できるように表示します。あればそれを使ってください。中身は同じリクエストで、より使いやすい見せ方にすぎません。**Account → Inbox → Approvals** の受信トレイは、常にすべてがひとつの場所にある完全なビューです。 + +## 次に進む [#where-to-go-next] + +| 次にすること | 読むもの | +|---|---| +| 日常的なユーザーとして ObjectOS を見て回る | [ObjectOS を使う](/docs/use) | +| 承認するレコードを操作する | [レコード](/docs/use/records) | +| 自分に回されたその他すべてを把握する | [通知](/docs/use/notifications) | +| 承認者と同じようにリストを切り分ける | [ビュー](/docs/use/views) | diff --git a/content/docs/use/collaboration.ja.mdx b/content/docs/use/collaboration.ja.mdx new file mode 100644 index 00000000..ae83fe16 --- /dev/null +++ b/content/docs/use/collaboration.ja.mdx @@ -0,0 +1,122 @@ +--- +title: レコードでのコラボレーション +seoTitle: "レコードのディスカッション、@メンション、履歴、共有リンク、公開フォーム" +description: チームとレコードについて話し合い、人を @メンションし、何が誰によって変更されたかを確認します。そして共有リンクと公開フォームが外部の人に何を開くかを説明します。 +editions: [community, cloud, enterprise] +translation: + source_sha: 6f006fa86f045c560def736d420ace4826af5c3751a280f581b2c7d8bbc2d102 + guide_rev: 1 + mode: auto +--- + +{/* + Platform checklist items this page documents (objectstack + docs/qa/platform-checklist/areas/records-forms.json and access-security.json): + records-forms.record-discussion-mentions, + records-forms.comment-reactions-and-edit-stamps, + records-forms.field-history-tracking, + access-security.share-link-capability-tokens, + access-security.share-link-landing-page, + access-security.share-link-combined-gates, + access-security.public-form-intake, + access-security.public-form-withdrawal-layers. +*/} + +レコードに関する作業がひとりで完結することはめったにありません。すべてのレコードページは、そのレコードについての会話と、何が変わったかの記録を持てます。さらにアプリがそのように設定されていれば、サインインしない人にレコードを見せたり、その人からデータを集めたりする方法も持てます。 + +## ディスカッション [#the-discussion] + +レコードページのタブの下には **Discussion** があります。コメントとレコードのアクティビティがひとつのフィードに古い順で並びます(ビルダーがディスカッションを有効にしたオブジェクトに表示されます)。 + +| できること | 方法 | +|---|---| +| コメントする | **Write a comment…** に入力し、**Send** を押すか `Ctrl+Enter` を押します。太字、斜体、リスト、インラインコードはツールバーにあり、**Preview** もあります | +| 誰かをメンションする | `@` を入力し、候補から人を選びます(または **Mention someone**) | +| 返信する | コメントの下に返信して、スレッドをまとめます | +| リアクションする | コメントに絵文字のリアクションを追加します | +| 編集または削除する | 自分のコメントのみ。編集されたコメントには **(edited)** の印が付きます。この印はサーバーが付けるので、隠すことはできません | +| レコードをフォローする | **Subscribe to notifications** で、このレコードの更新を受け取ります | + +コメントは送信した瞬間に表示され、その後、重複することなく保存されたコピーに置き換わります。 + +### フィードを絞り込む [#filtering-the-feed] + +フィードには、コメントとレコードのアクティビティが混在しています。フィルターで絞り込めます。 + +| フィルター | 表示内容 | +|---|---| +| **All Activity** | すべて | +| **Comments Only** | コメントと返信 | +| **Field Changes** | レコードのフィールドへの編集 | +| **Tasks Only** | タスクのエントリ | + +フィルターの結果が空なら、レコードにその種類のものがまだないというだけです。 + +## @メンション [#mentions] + +誰かを `@mention` すると、その人のベルに、コメントのプレビューとレコードへの直接リンク付きの通知が届きます。 + +メンションがディスカッション自体より遠くに届くことはありません。通知されるのは、その人がレコードとコメントを読み取れる場合だけです。誰かをメンションしても、その人にアクセス権が**与えられるわけではありません**。コメントの作成者は自分自身のメンションについて通知されず、メンションされていない人も通知されません。 + +## 何が変わり、誰が変えたか [#what-changed-and-who-changed-it] + +| 場所 | 表示内容 | +|---|---| +| ディスカッションのフィード | アプリのビルダーが追跡対象に選んだフィールドについて、**Industry: Technology → Finance** のような行。フォームで見るラベルを使います | +| **History** タブ | レコードの完全な変更履歴。ビルダーが履歴の追跡を有効にしたオブジェクトに表示されます | + +追跡されていないフィールドへの変更には、フィードで変更前後の行が表示されません。 + +## チームとレコードを共有する [#sharing-a-record-with-your-team] + +レコードの `⋯` メニューにある **Share** は、レコードのアドレスをコピーします(またはデバイスの共有シートを開きます)。何かを許可するわけではありません。それを開く人には、引き続きレコードへのアクセス権が必要です。[権限](/docs/configure/permissions)を参照してください。 + +## 共有リンク:リンクを知っている全員 [#share-links-anyone-with-the-link] + +アプリのビルダーが公開共有を有効にしたオブジェクトでは、レコードは**共有リンク**も持てます。アカウントを持たない人や、アカウントはあってもレコードへのアクセス権がない人に、その 1 件のレコードを見せるリンクです。 + +共有リンクは、そのレコードを見られる人が API(`POST /api/v1/share-links`)を通じて 1 件のレコードに対して作成します。各リンクは独自の制限を持てます。 + +| 制限 | 効果 | +|---|---| +| **パスワード** | ページがそれを求めます:**Password required**、正しく入力するまで **Wrong password.** | +| **サインインしたユーザーのみ** | セッションのない訪問者には **Sign in required** と、同じページに戻る **Sign in** リンクが表示されます | +| **メールの許可リスト** | 一覧にあるメールアドレスでサインインした人だけがレコードを見られます | +| **有効期限** | リンクはその日に機能しなくなります | +| **非表示のフィールド** | リンクが表示する内容から除外されるフィールド。オブジェクトが常に共有リンクから隠すフィールドに加えて適用されます | + +リンクを開いた人には、アプリの外にあるページが表示されます。メニューはなく、リンクが求めない限りサインインもありません。レコードのフィールドが読み取り専用で表示されます。フィールドが非表示にされている場合、ページには **Some fields are hidden by the owner** と表示され、それらの名前が示されます。 + +### 失効、そしてリンクが決して公開しないもの [#revoking-and-what-a-link-never-exposes] + +- リンクを**失効**させる(`DELETE /api/v1/share-links/…`)と、即座に機能しなくなります。ページには **This link has expired or was revoked.** と表示されます。有効期限を過ぎたリンクも同様です。 +- **レコードを削除**すると、それへのすべてのリンクは **This link is invalid or no longer available.** と答えます。でっち上げたリンクと同じ答えなので、リンクがレコードの存在を確認させることはありません。 +- **非表示のフィールドはサーバー上で取り除かれます。** 画面からだけでなく、訪問者のブラウザに届くこともありません。 +- **1 件のレコードのみ。** リンクが開くのは、作成対象のレコードだけです。関連レコードやリストの残りは決して開きません。 +- **パスワードはサーバーに残ります。** ハッシュ化して保存され、どのレスポンスもそれを返しません。 +- **何もキャッシュされません。** リンク経由で提供されるページは、ブラウザとプロキシにコピーを保持しないよう指示するため、共有コンピューターの次の人がパスワードで保護されたレコードを見ることはできません。 +- **見えるのは自分のリンクだけです。** リンクを一覧表示すると、自分が作成したものが返され、他の人のものは返されません。 + +アプリのビルダーがオブジェクトの公開共有をオフにすると、そのオブジェクトのすべてのリンクは、再びオンにされるまで機能しなくなります。 + +## 公開フォーム:外部からデータを集める [#public-forms-collecting-data-from-outside] + +**公開フォーム**は、アプリのビルダーが `/forms/contact-us` のようなリンクで公開した、サインインしていない人向けのフォームです。お問い合わせフォーム、Web からのリード獲得、サポートリクエストなどです。訪問者はそれを記入し、フォームの確認表示(たとえばお礼のメッセージ)を見ます。各送信はレコードになり、チームは他のレコードと同じようにそれに対応します。 + +公開フォームが決して開かないもの: + +- **一覧にあるフィールドのみ。** 訪問者が見て記入できるのは、フォームが表示するフィールドだけです。オブジェクトの残りではありません。 +- **検索はできません。** フォームが何を宣言していても、公開フォームにはレコードを検索するフィールド(参照ピッカーやユーザーピッカー)はありません。 +- **所有者の偽装はできません。** 訪問者は、レコードの所有者、所属する組織、ステータスなどのフィールドを設定できません。それらに送られた値は破棄され、サーバーが設定します。 + +公開フォームを**閉じる**には、ビルダーが公開を取り消すか、匿名アクセスをオフにします。するとリンクはフォームが存在しないかのように答え、送信は即座に止まります。 + +## 次に進む [#where-to-go-next] + +| やりたいこと | 読むもの | +|---|---| +| レコードにファイルを添付する | [ファイルと添付ファイル](/docs/use/files) | +| どの通知を受け取るかを制御する | [通知](/docs/use/notifications) | +| 誰がレコードを見られるかを理解する | [権限](/docs/configure/permissions) | +| 公開フォームを構築する | [ビュー → 公開フォーム](/docs/build/interface/views#public-forms) | +| ツアーに戻る | [ObjectOS を使う](/docs/use) | diff --git a/content/docs/use/dashboards.ja.mdx b/content/docs/use/dashboards.ja.mdx new file mode 100644 index 00000000..b997288c --- /dev/null +++ b/content/docs/use/dashboards.ja.mdx @@ -0,0 +1,71 @@ +--- +title: ダッシュボード +seoTitle: "ダッシュボードを読む:KPI、グラフ、日付フィルター" +description: チームの KPI、グラフ、表をひと目で読み、日付やフィルターで 2 クリックで絞り込みます。 +editions: [community, cloud, enterprise] +translation: + source_sha: 2d541eab18014e7c9f5272fff044d83422a7760bfb23362d8270006188c6f864 + guide_rev: 1 + mode: auto +--- + +**ダッシュボード**は、レコードを数値とグラフに変えます。未完了のタスクがいくつあるか、作業がどう推移しているか、誰が負荷を担っているか。ここではダッシュボードを構築するのではなく読みます。ダッシュボードはレコードの変化に合わせて自動的に更新されます。 + +## ダッシュボードの場所 [#where-dashboards-live] + +ダッシュボードはアプリの**ナビゲーションサイドバー**の項目で、通常は **Analytics** のようなグループの中にあります。クリックすると、他のページと同じように開きます。 + +## ダッシュボードのヘッダー [#the-dashboard-header] + +すべてのダッシュボードの上部には次のものがあります。 + +| 要素 | 機能 | +|---|---| +| **タイトルと説明** | このダッシュボードが何を、なぜ測定するか | +| **期間のプリセット** | **Last 90 days** のようなドロップダウン。すべてのウィジェットの期間を一度に変更します | +| **ダッシュボードのフィルター** | **Task Status: All** のようなドロップダウン。すべてのウィジェットを一部分に絞り込みます(例:*In Progress* のみ) | + +> **ヒント:** 数値がおかしく見える場合は、まず期間とフィルターを確認してください。**Task Status: Done** での「Last 90 days」は、全期間、全ステータスとはまったく違う姿を見せます。 + +期間とフィルターは**ダッシュボード全体**に適用されるため、すべてのウィジェットがデータの同じ部分について同じ問いに答えます。2 つのグラフが別のものを数えているのではと悩む必要はありません。 + +## ウィジェットの種類 [#widget-types] + +ダッシュボードは**ウィジェット**のグリッドです。3 種類のウィジェットがあります。 + +| ウィジェット | 見た目 | 適した用途 | +|---|---|---| +| **KPI 統計タイル** | ラベル付きの大きな数値ひとつ | 見出しとなる数値:*Open Tasks: 42* | +| **グラフ** | 棒グラフ、円グラフなどの視覚表現 | グループの比較や傾向の発見 | +| **表** | 行と列 | 数値の裏にある詳細:上位の項目、最近のレコード | + +典型的なレイアウトでは、上部に統計タイルの行(見出し)、中央にグラフ(データの形)、下部に表(裏付け)を置きます。その順に読めば、1 分足らずで全体像がつかめます。 + +## ダッシュボードとビュー [#dashboards-vs-views] + +どちらもレコードを表示しますが、高さが異なります。 + +| サーフェス | 表示内容 | 使うとき | +|---|---|---| +| **ダッシュボード** | 集計:件数、合計、傾向 | 全体像が欲しいとき | +| **ビュー** | 個々のレコードを 1 行ずつ | リストを処理したいとき。[ビューを使う](/docs/use/views)を参照してください | + +## 空の状態 [#empty-states] + +表示するものがないウィジェットは、そのことをはっきり示します。たとえば表には **No rows** と表示されます。これはエラーではありません。現在の期間とフィルターでは、一致するレコードがないということです。期間を広げるかフィルターをリセットすれば、たいていデータは再び表示されます。 + +## 数値からレコードへ [#from-number-to-records] + +ダッシュボードはレコードを要約し、一部のウィジェットではそのレコードへ**ドリルスルー**できます。タイル、グラフの区分、表の行がクリック可能な場合、一致するレコードが開き、数値が示していることに対応できます。そこから先は通常のリストです。[ビューを使う](/docs/use/views)を参照してください。 + +> **ヒント:** ダッシュボードを読むことはループです。おかしな数値を見つけ、フィルターで絞り込み、レコードへドリルスルーし、直すべきものを直します。 + +## 次に進む [#where-to-go-next] + +| やりたいこと | 読むもの | +|---|---| +| 数値の裏にあるレコードを操作する | [レコードを操作する](/docs/use/records) | +| 自分でリストをフィルターしグループ化する | [ビューを使う](/docs/use/views) | +| 自分を待っている申請に対応する | [承認](/docs/use/approvals) | +| どの通知を受け取るかを管理する | [通知](/docs/use/notifications) | +| ツアーに戻る | [ObjectOS を使う](/docs/use) | diff --git a/content/docs/use/files.ja.mdx b/content/docs/use/files.ja.mdx new file mode 100644 index 00000000..52b5d13d --- /dev/null +++ b/content/docs/use/files.ja.mdx @@ -0,0 +1,94 @@ +--- +title: ファイルと添付ファイル +seoTitle: "ファイルと添付ファイル:アップロード、ダウンロード、権限" +description: レコードにファイルを添付するか、ファイルフィールドにアップロードします。誰がそれを見て、追加し、削除できるか、そして削除されたファイルがどのくらい保持されるかを説明します。 +editions: [community, cloud, enterprise] +translation: + source_sha: 3bb89abc1ac77bc14428766ab10e45b3a10ceef5d201d4d588c672c0a4072b9f + guide_rev: 1 + mode: auto +--- + +{/* + Platform checklist items this page documents (objectstack + docs/qa/platform-checklist/areas/attachments-storage.json): + attachments-storage.presigned-upload-roundtrip, + attachments-storage.download-authz-both-sides, + attachments-storage.read-inherits-parent-rls, + attachments-storage.attach-requires-parent-edit, + attachments-storage.sys-file-status-pipeline, + attachments-storage.orphan-tombstone-reap, + attachments-storage.inline-grid-receipt-cells, + attachments-storage.field-accept-maxsize-server-enforced, + attachments-storage.upload-limits-scope-and-ownership. +*/} + +ファイルがレコードに届く方法は 2 つあります。 + +| 方法 | 見た目 | 用途 | +|---|---|---| +| **添付ファイル** | レコードページの **Attachments** タブ。任意の数のファイルを一覧表示します | 契約書、写真、やり取り。レコードに属するあらゆるもの | +| **ファイルフィールドと画像フィールド** | フォーム内のアップロードコントロール。明細テーブルの各行にあることもあります | レコードが必要とする特定の書類。経費明細ごとの領収書、製品写真 | + +どちらもファイル自体はストレージに保管し、レコードはそれを指します。そのため、誰がそれを開けるかは同じルールで決まります。 + +## Attachments タブ [#the-attachments-tab] + +ビルダーが添付ファイルを有効にしたオブジェクトでは、すべてのレコードページに **Attachments** タブが表示されます。 + +| コントロール | 機能 | +|---|---| +| **Upload** | コンピューターから 1 つ以上のファイルを選びます | +| ファイル一覧 | このレコードに添付されたすべてのファイル | +| **Download** | ファイルを開きます | +| **Delete attachment** | 確認後、このレコードからファイルを削除します | + +何も添付されていないレコードには **No attachments yet. Upload a file to get started.** と表示されます。 + +## 誰が何をできるか [#who-can-do-what] + +添付ファイルは、それが属するレコードに従います。 + +| するには | 必要なもの | +|---|---| +| 添付ファイルを見てダウンロードする | レコードの読み取りアクセス | +| 添付ファイルをアップロードする | レコードの**編集**アクセス。読み取りだけでは不十分です | +| 添付ファイルを削除する | それをアップロードした本人であるか、レコードの編集アクセス | + +ファイルをアップロードした人は、常にそれをダウンロードし削除できます。 + +レコードを読み取れない場合、その添付ファイルはあなたにとって存在しません。どのリストにも件数にも表示されません。何かが拒否されると、*You don't have access to attach files to this record.* や *Only the uploader or someone who can edit this record may delete this attachment.* のような平易なメッセージが表示されます。 + +## ファイルフィールドと画像フィールド [#file-and-image-fields] + +ファイルフィールドや画像フィールドは、フォームにアップロードコントロールを表示します。ファイルを選ぶとすぐにアップロードされ、ファイル名付きのチップとして表示されます。保存前ならそれを削除できます。明細テーブル(たとえば請求書の明細行)では、各行に独自のアップロードセルがあります。 + +フィールドは、受け付けるファイルの種類とファイルの最大サイズを制限できます。サーバーは保存時にその制限をもう一度確認します。制限に違反するファイルはフィールド名を示すメッセージとともに拒否され、何も保存されません。 + +## ダウンロードは短時間だけ有効なリンク [#downloads-are-short-lived-links] + +**Download** は、数分間(デフォルトでは 5 分)有効なリンクをサーバーに要求します。そのリンクをコピーして後で開くと、期限切れになっています。レコードからもう一度ダウンロードしてください。レコードへのアクセス権がない人は、有効なリンクをまったく取得できません。 + +## サイズの上限 [#size-limits] + +管理者が別の上限(ストレージ設定の **Limits** にある **Max upload size (MB)**)を設定していない限り、1 つのファイルは **100 MB** までです。上限を超えるファイルは、一部でも保存される前に拒否されます。 + +## 削除されたファイルはどうなるか [#what-happens-to-removed-files] + +添付ファイルを削除すると、**そのレコード**から外れます。ファイル自体は段階的に片付けられるため、間違えてもその場でデータが失われることはありません。 + +| 状態 | 何が起こるか | +|---|---| +| 別のレコードにも添付されている | いずれかのレコードがまだ保持している限り残ります | +| どこにも添付されていない | **30 日間**保持され、その後ストレージが回収されます | +| 開始されたが完了しなかったアップロード | **7 日**後に削除されます | + +## 次に進む [#where-to-go-next] + +| やりたいこと | 読むもの | +|---|---| +| ファイルが属するレコードを開いて編集する | [レコードを操作する](/docs/use/records) | +| チームとレコードについて話し合う | [レコードでのコラボレーション](/docs/use/collaboration) | +| スプレッドシートから多数のレコードを取り込む | [データのインポート](/docs/use/import) | +| ファイルの保存場所を設定する | [ストレージ](/docs/configure/storage) | +| ツアーに戻る | [ObjectOS を使う](/docs/use) | diff --git a/content/docs/use/import.ja.mdx b/content/docs/use/import.ja.mdx new file mode 100644 index 00000000..cf10487c --- /dev/null +++ b/content/docs/use/import.ja.mdx @@ -0,0 +1,125 @@ +--- +title: データのインポート +seoTitle: "インポートウィザード:CSV と Excel のインポート、マッピング、取り消し" +description: CSV や Excel ファイルからレコードを取り込みます。列をマッピングし、何かが保存される前にエラーを修正し、うまくいかなかったインポートを取り消します。 +editions: [community, cloud, enterprise] +translation: + source_sha: 47a5d626f6c1bbf30e5d32d5604cf1ecf5a2d4285086b433ec1cbad75d838a2f + guide_rev: 1 + mode: auto +--- + +{/* + Platform checklist items this page documents (objectstack + docs/qa/platform-checklist/areas/records-forms.json): + records-forms.import-wizard-encoding-and-hints, + records-forms.named-import-mapping, + records-forms.import-job-undo-cancel, + records-forms.import-transform-matrix. +*/} + +顧客リストや昨年のプロジェクトなど、スプレッドシートにレコードがある場合、**インポートウィザード**が 3 つのステップでそれをレコードに変えます:**Upload**、**Mapping**、**Preview**。最後に **Import** を押すまで、何も保存されません。 + +## ウィザードを開く [#opening-the-wizard] + +オブジェクトのリストで、リストヘッダーの **Import** をクリックします。オブジェクトによっては、ヘッダーの `⋯` オーバーフローメニューの中にあります。 + +表示されるのは、オブジェクトがインポートに対して開かれていて、そのレコードの作成を許可されている場合だけです。インポートはレコードを作成するので、**+ New** と同じ権限が必要です。 + +## ステップ 1:Upload [#step-1--upload] + +ファイルをウィザードにドラッグするか、**Browse Files** をクリックするか、Excel や Google Sheets からコピーした行をそのまま貼り付けます(`Ctrl/⌘+V`)。 + +| ファイル | サポート | +|---|---| +| CSV、TSV | はい | +| Excel `.xlsx` | はい | +| 古い Excel `.xls` | いいえ。開いて先に `.xlsx` として保存してください | + +最初の行は列見出しでなければならず、データ行が少なくとも 1 行必要です。 + +**どの列を使えばよいかわからない場合は?** **Download template** をクリックすると、インポートできるすべての列を一覧にし、必須の列に `*` を付け、記入方法を説明した Excel ファイルが手に入ります。 + +> **ヒント:** 中国語版の Excel で保存したファイル(「CSV として保存」)は、UTF-8 ではなく GBK でエンコードされていることがよくあります。変換する必要はありません。ウィザードがエンコーディングを検出するので、中国語の見出しと値はそのまま取り込まれます。 + +## ステップ 2:Mapping [#step-2--mapping] + +ウィザードは名前によって列をオブジェクトのフィールドに対応付け、その確度(**High**、**Medium**、**Low confidence**)を示します。対応付けを確認し、間違っているものを変更します。 + +| 選択肢 | 効果 | +|---|---| +| フィールド | 列の値がそのフィールドに入ります | +| **— Skip —** | 列は無視されます | + +値がフィールドの型らしく見えない列には印が付きます(たとえば *Looks like Date*)。 + +**必須フィールドはマッピングしなければなりません。** マッピングされていない場合、**Next** は無効のままで、ウィザードは不足しているフィールドを示します。その列をファイルに追加するか、それを含むファイルをアップロードしてください。 + +**マッピングの再利用。** **Mapping template** の下にある **Save current** は、この列とフィールドの対応をブラウザに保存するので、同じファイルレイアウトの次のインポートはワンクリックで済みます。アプリのビルダーがこの種のファイル向けに**保存されたマッピング**を設定している場合は、代わりにそれを選びます。その場合、サーバーが列の名前を変更し、値を変換し、独自のルールを適用し、列のマッピングは読み取り専用で表示されます。 + +## ステップ 3:Preview [#step-3--preview] + +プレビューは、インポートされるとおりに行を表示します。問題のある行は強調表示されます。強調表示されたセルをクリックすると、その場で値を修正できます。**Validate data** をクリックすると、何かが書き込まれる前に、すべての行をサーバーに照らして確認します。有効な行の数と、どの行にエラーがあるかが表示されます。検証に合格した行は、インポートが受け入れる行です。 + +よくあるエラー: + +| メッセージ | 意味 | +|---|---| +| *This field is required* | 必須の値が空です | +| *"abc" is not a valid number*(または date、time、true/false) | 値をフィールドの型として読み取れません | +| *"Gold" is not one of the allowed options* | 選択フィールドに、提供されていない値が入りました | +| *No matching record for "Acme"* | 別のレコードを指す列が、存在しないレコードを指定しました | +| *"Acme" matches more than one record* | その名前は一意ではありません。一意の値かレコード ID を使ってください | + +### インポートのオプション [#import-options] + +| オプション | 機能 | +|---|---| +| **When a row matches an existing record** | **Always create new**、**Update existing (skip if no match)**、**Update if matched, else create** | +| **Match on** | 既存のレコードを見つけるために使うフィールド。メールアドレス、コード、外部 ID など | +| **Keep unknown option values** | フィールドが提供していない選択肢の値を、行を拒否する代わりにそのまま保存します | +| **Skip rows with a blank match value** | 照合に使う値がない行を除外します | +| **Import in the background** | インポートを、後で取り消せるジョブとして実行します | + +照合フィールドで更新すると、インポートを安全に繰り返せます。同じファイルをもう一度実行すると、重複を作る代わりに、作成したレコードを更新します。 + +## 結果 [#the-result] + +インポートが完了すると、**作成**、**更新**、**スキップ**されたレコードの数と、行のエラーが表示されます。**Download failed rows** は、取り込めなかった行だけを渡すので、修正してもう一度インポートできます。 + +## バックグラウンドインポート、キャンセル、取り消し [#background-imports-cancel-and-undo] + +**5,000 行**を超えるファイルは常にバックグラウンドでインポートされます。それより小さいファイルは、**Import in the background** にチェックを入れた場合にそうなります。バックグラウンドインポートは進捗を表示し、その間も作業を続けられます。 + +| 操作 | 何が起こるか | +|---|---| +| **Cancel import** | ジョブを停止します。すでに書き込まれた行は残ります。行は完全に保存されるか、まったく保存されないかのどちらかで、半分だけ書き込まれることはありません。 | +| **History** | このオブジェクトのバックグラウンドインポートを新しい順に、ステータス、行数、結果とともに一覧表示します | +| **Undo import** | インポートが作成したレコードを削除し、更新したレコードを以前の値に戻します。それ以外には何も触れません。 | + +取り消せない行がある場合、ウィザードはその数を示します。**Undo import** をもう一度選ぶと、それらだけを再試行します。 + +> **ヒント:** 大きなファイルを初めてインポートしますか?**Import in the background** にチェックを入れてください。結果が期待どおりでなければ、**Undo import** 一回で元に戻せます。 + +## アプリビルダー向け:保存されたマッピング [#for-app-builders-saved-mappings] + +保存されたマッピングは、パッケージ内の `mapping` メタデータです。外部の見出しをフィールドに名前変更し("Full Name" → `name`)、再インポートが重複ではなく更新になるようにするキーを設定し、取り込み時に値を変換できます。 + +| 変換 | 機能 | +|---|---| +| `map` | コードを値に変換します(`'Webform'` → `web`)。エントリのない値はそのまま通ります | +| `constant` | 列を無視して固定値を書き込みます | +| `lookup` | 名前を関連レコードの ID に解決します | +| `split` | ひとつの列を複数のフィールドに分割します | +| `join` | 複数の列をひとつのフィールドに結合し、空の部分はスキップします | + +`javascript` 変換を指定したマッピングは、行が書き込まれる前に拒否されます。それを実行するサーバー側のサンドボックスがないためです。別の形式向けに宣言されたマッピングでファイルをインポートする(JSON を CSV マッピングで)と、両方の形式を示して拒否されます。Excel ファイルは CSV マッピングを通ります。存在しないマッピングを指定したインポートは、位置による列の照合にフォールバックするのではなく拒否されます。 + +## 次に進む [#where-to-go-next] + +| やりたいこと | 読むもの | +|---|---| +| インポートしたレコードを編集する | [レコードを操作する](/docs/use/records) | +| インポートしたばかりのレコードを見つける | [検索](/docs/use/search) | +| インポートしたものだけにリストを絞り込む | [ビューを使う](/docs/use/views) | +| ツアーに戻る | [ObjectOS を使う](/docs/use) | diff --git a/content/docs/use/index.ja.mdx b/content/docs/use/index.ja.mdx new file mode 100644 index 00000000..17dd42e1 --- /dev/null +++ b/content/docs/use/index.ja.mdx @@ -0,0 +1,94 @@ +--- +title: ObjectOS を使う +seoTitle: "ユーザーガイド:サインイン、アプリ、検索、ナビゲーション" +description: 一度サインインすれば、チームが共有するすべてのアプリ、レコード、通知が見つかります。5 分で回る ObjectOS のツアーです。 +editions: [community, cloud, enterprise] +translation: + source_sha: 6cc63a43afd4f93986a9af7c841417befd0918cb6efbc5b38f583fe46cc826c1 + guide_rev: 1 + mode: auto +--- + +ObjectOS は、プロジェクト、タスク、承認、ダッシュボードなど、チームの業務アプリが置かれる場所です。一度サインインすれば、アクセスできるすべてのアプリをひとつの場所で、ひとつの検索ボックスとともに見られます。 + +このセクションは**日常的なユーザー**向けです。アプリを構築する人やシステムを管理する人は、代わりに[構築](/docs/build)または[設定](/docs/configure)に進んでください。 + +## サインイン [#signing-in] + +チームから伝えられた URL を開き、**メールアドレスとパスワード**でサインインします。セッションは記憶されるので、アバターメニューからログアウトするまで、そのブラウザではサインインしたままです。 + +## ホームページ [#the-home-page] + +サインインすると、ホームページに移動します。上から順に次のものがあります。 + +| 領域 | 表示内容 | +|---|---| +| **あいさつ** | 個人宛てのあいさつ("Good afternoon, Ada") | +| **あなたのアプリ** | タイルのグリッド。アクセスできるアプリごとに 1 枚です。タイルをクリックするとアプリが開きます。 | +| **Needs your attention**(対応が必要) | 保留中の通知と承認、それぞれが届いてからの経過時間 | +| **Recently Accessed**(最近のアクセス) | 最近開いたオブジェクトとレコード。昨日の作業に戻る最速の方法です | +| **アクティビティフィード** | ワークスペース全体の最近のアクティビティ | + +> **ヒント:** **Needs your attention** を朝の受信トレイとして使いましょう。どのアプリを開く前でも、あなたを待っている承認が表示されます。 + +## アプリを切り替える [#switching-between-apps] + +左上の**パンくずリスト**は、常に現在地を示します:*アプリ → オブジェクト → レコード*。最初の部分は**アプリスイッチャー**です。クリックするとアプリの一覧がドロップダウンで表示され、ホームに戻らずにアプリ間を移動できます。 + +どのインストールにも、チーム向けに構築された業務アプリと並んで、次のものがあります。 + +| アプリ | 誰が見られるか | 用途 | +|---|---|---| +| **Account** | 全員 | 個人用のスペース:プロフィール、通知の受信トレイ、承認、セキュリティ | +| **Setup** | 管理者のみ | システム管理 | + +## アプリのナビゲーションサイドバー [#the-app-navigation-sidebar] + +アプリ内では、左のサイドバーがそのアプリのメニューです。フラットな項目と**折りたたみ可能なグループ**(たとえば *Workspace* や *Analytics*)が含まれます。各項目は次の 3 つのいずれかを開きます。 + +| 項目の種類 | クリックで開くもの | +|---|---| +| オブジェクト(例:*Tasks*) | そのリストビュー。[ビュー](/docs/use/views)を参照してください | +| ページ | アプリ向けに構築されたカスタムページ | +| ダッシュボード | グラフと KPI。[ダッシュボード](/docs/use/dashboards)を参照してください | + +アクティブな項目の横には**ピンアイコン**が表示され、よく使う場所をピン留めできます。 + +## グローバル検索 [#global-search] + +`⌘K`(Mac)または `Ctrl-K`(Windows/Linux)を押すか、トップバーの **Search…**(検索)をクリックします。**すべてのオブジェクトにわたるレコード**を検索するダイアログが開きます。タスク名、プロジェクト、顧客の数文字を入力すれば、すぐにそこへ移動できます。 + +## トップバー [#the-top-bar] + +トップバーはすべての画面に表示されます。 + +| コントロール | 機能 | +|---|---| +| **Search…** | グローバル検索を開く(`⌘K` / `Ctrl-K`) | +| **ベル** | 通知。赤いバッジが未読数を示します。受信トレイ全体は **Account → Inbox → Notifications** にあります。 | +| **?** | ヘルプ | +| **アバター** | アカウントメニュー(下記) | + +**アバターメニュー**には名前とメールアドレスが表示され、次の項目があります。 + +| 項目 | 機能 | +|---|---| +| **Profile**(プロフィール) | Account アプリでプロフィールを開く | +| **Preferences → Theme**(設定 → テーマ) | ライトとダークを切り替える | +| **Preferences → Language**(設定 → 言語) | インターフェースの言語を変更する | +| **Log out**(ログアウト) | セッションを終了する | + +> **ヒント:** テーマと言語は**アバターメニュー → Preferences** にあり、プロフィールページにはありません。最初に探しがちな場所です。 + +## 次に進む [#where-to-go-next] + +| やりたいこと | 読むもの | +|---|---| +| レコードを開く、作成する、編集する | [レコードを操作する](/docs/use/records) | +| グリッド、カンバン、カレンダーなどを切り替える | [ビューを使う](/docs/use/views) | +| グラフと KPI を読む | [ダッシュボード](/docs/use/dashboards) | +| 申請を承認または却下する | [承認](/docs/use/approvals) | +| 通知を管理する | [通知](/docs/use/notifications) | +| 名前、写真、パスワードを更新する | [プロフィールとセキュリティ](/docs/use/profile) | +| アプリを構築またはカスタマイズする | [構築](/docs/build) | +| システムを管理する | [設定](/docs/configure) | diff --git a/content/docs/use/notifications.ja.mdx b/content/docs/use/notifications.ja.mdx new file mode 100644 index 00000000..ef803520 --- /dev/null +++ b/content/docs/use/notifications.ja.mdx @@ -0,0 +1,68 @@ +--- +title: 通知 +seoTitle: "通知の受信トレイ:承認、ダイジェスト、ミュート" +description: 承認、ダイジェスト、更新など、自分に回されたすべてを、受信トレイに張り付くことなく受け取ります。 +editions: [community, cloud, enterprise] +translation: + source_sha: c72a596060c2df31c53b93bddabfdc1a02e1594e20f9a31483a08d200e07673a + guide_rev: 1 + mode: auto +--- + +ObjectOS は、何かがあなたを必要とするときに知らせます。承認があなたの手元に届いたとき、スケジュールされたダイジェストがプロジェクトを要約したとき、フォローしているレコードが変わったときです。それらのメッセージは、ひと目で確認できるものから完全な履歴まで、3 つの場所に表示されます。 + +| サーフェス | 場所 | 最適な用途 | +|---|---|---| +| **ベル** | すべての画面のトップバー | 「何か新しいものは?」の素早い確認。赤いバッジが未読数を示します | +| **Needs your attention** | ホームページ | 朝の仕分け。最近の項目を、待っている時間とともに | +| **完全な受信トレイ** | **Account → Inbox → Notifications** | すべてを読み、検索し、処理する | + +## ベルとホームページ [#the-bell-and-the-home-page] + +**ベルアイコン**は、ObjectOS のどこにいてもトップバーにあります。その上の赤いバッジは未読の通知を数えています。クリックすると、今の画面を離れずに新着を確認できます。 + +ホームページには **Needs your attention** の一覧が加わります。保留中の通知と承認が、それぞれの経過時間とともに表示されるので、どれが最新でどれが最も長く待っているかがひと目でわかります。 + +> **ヒント:** 一日をホームページから始めましょう。作業に取りかかる前の仕分けは、たいてい **Needs your attention** と **Recently Accessed** で十分です。 + +## 完全な受信トレイ [#the-full-inbox] + +全体像を見るには、**Account → Inbox → Notifications** を開きます。アプリスイッチャーの **Account** アプリを開き、サイドバーの **Inbox** を選びます。デフォルトのビューは、自分の通知をリストとして表示します。 + +| 列 | わかること | +|---|---| +| **Title** | 何が起こったかを 1 行で | +| **Topic** | どのような種類のメッセージか。たとえばプロジェクトのダイジェストか承認か | +| **Severity** | どれだけ緊急か(Info 以上) | +| **Created At** | いつ届いたか | + +これは通常のリストビューなので、リストについて知っていることはすべて当てはまります。フィルター、ソート、その中での検索ができます。 + +## 通知の発生元 [#where-notifications-come-from] + +これらを設定する必要はありません。アプリ内の何かが、あなたが知るべきだと判断したので通知が届きます。 + +| 発生元 | 例 | +|---|---| +| **自動化** | 毎朝、未完了のプロジェクトタスクを要約するスケジュールされたダイジェスト | +| **承認** | 判断すべきリクエストがあなたに割り当てられた、または自分の申請が承認または却下された | +| **購読** | フォローしているオブジェクトやレコードが変わった | + +## うるさいオブジェクトをミュートする [#muting-a-noisy-object] + +あるオブジェクトが有益な情報よりも雑音を多く生むなら、ミュートしましょう。そのオブジェクトのリストを開き、リストヘッダーの**ベルオフのトグル**をクリックします。そのオブジェクトの通知は届かなくなります。もう一度クリックするとミュートが解除されます。ミュートはオブジェクトごとで、影響するのは*あなた*だけです。チームメイトは引き続き通知を受け取ります。 + +> **ヒント:** 無視するのではなくミュートしましょう。ミュートしたオブジェクトは完全に使えるままで、それについて呼び出されなくなるだけです。そして未読バッジが再び意味を持つようになります。 + +## デスクトップ通知 [#desktop-notifications] + +ObjectOS のデスクトップアプリを使っている場合、アプリ内の通知をオペレーティングシステムのネイティブ通知に反映できます。他のデスクトップアプリと同じバナーと通知センターのエントリです。ObjectOS のウィンドウがバックグラウンドにあっても新しい項目が表示され、クリックするとすぐにそこへ移動します。 + +## 次に進む [#where-to-go-next] + +| 次にすること | 読むもの | +|---|---| +| 通知が指す承認に対応する | [承認](/docs/use/approvals) | +| 受信トレイを他のリストと同じようにフィルターしソートする | [ビュー](/docs/use/views) | +| 個人設定を調整する | [プロフィールと設定](/docs/use/profile) | +| 日常的なユーザーとして ObjectOS を見て回る | [ObjectOS を使う](/docs/use) | diff --git a/content/docs/use/profile.ja.mdx b/content/docs/use/profile.ja.mdx new file mode 100644 index 00000000..c8a66a72 --- /dev/null +++ b/content/docs/use/profile.ja.mdx @@ -0,0 +1,78 @@ +--- +title: プロフィールと設定 +description: ObjectOS を自分のものにします。名前とアバター、テーマと言語、そしてサインイン中のすべてのセッションの管理です。 +editions: [community, cloud, enterprise] +translation: + source_sha: d7531547c07b1a8ee043f6832b30aa22e33e8da23e59bb4d2b3ebea8bc9693f3 + guide_rev: 1 + mode: auto +--- + +個人的なものはすべて 2 つの場所にあります。右上の**アバターメニュー**(すべての画面で使える手早い設定)と、**Account** アプリ(プロフィール、セキュリティ、受信トレイ)です。ここでの変更が他の人に影響することはありません。これらはあなたのアカウントの、あなたの設定です。 + +| やりたいこと | 移動先 | +|---|---| +| 名前やアバターを変更する | **Account → Profile** | +| パスワードを変更する | **Account → Profile** → Change Password | +| ライト/ダークモードや言語を切り替える | アバターメニュー → Preferences | +| 他のセッションを確認する、またはサインアウトさせる | **Account → Security** → Active Sessions | +| どのサインインプロバイダーが連携されているか確認する | **Account → Security** → Linked Accounts | +| サインアウトする | アバターメニュー → **Log out** | + +## プロフィール [#your-profile] + +**Account → Profile** を開きます。アプリスイッチャーの **Account** アプリからでも、アバターメニューの **Profile** からでも開けます。 + +| 設定 | 変更できるか | +|---|---| +| **アバター** | はい。**Upload** をクリックして画像を選びます。チームメイトは、割り当て、アクティビティフィード、承認など、あなたが表示されるあらゆる場所でそれを目にします。 | +| **名前** | はい。Personal Information カードで編集します。 | +| **メールアドレス** | いいえ。メールアドレスはアカウントを識別するもので、ここでは変更できません。 | +| **ロール** | 読み取り専用。管理者があなたに割り当てたものを表示します。 | + +**Save Changes** をクリックして編集を適用します。 + +Personal Information の下には **Change Password** カードがあります。現在のパスワードと新しいパスワードを入力すれば完了です。他のデバイスは、セッションが終わるまでサインインしたままです。すべて一掃したい場合は、**Active Sessions** からそれらをサインアウトさせてください。 + +## 設定:テーマと言語 [#preferences-theme-and-language] + +右上のアバターをクリックします。名前とメールアドレスと並んで、Preferences があります。 + +| 設定 | 選択肢 | +|---|---| +| **Theme** | ライトまたはダーク。UI 全体がすぐに切り替わります。 | +| **Language** | UI の表示言語を選びます。 | + +どちらもその場で反映されます。保存ボタンも再読み込みもありません。 + +## セキュリティ [#security] + +**Account → Security** を開くと、ときどき確認する価値のある 2 つのものがあります。 + +| セクション | 用途 | +|---|---| +| **Linked Accounts** | アカウントに連携されたソーシャルまたは会社のサインインプロバイダー(SSO)。何が連携されているかをひと目で確認できます。 | +| **Active Sessions** | 現在あなたとしてサインインしているすべてのデバイスとブラウザ。一覧を確認し、見覚えのないセッションやもう使っていないセッションを**サインアウト**させます。 | + +> **ヒント:** 共有のマシンや借りたマシンでサインインしたまま、ログアウトし忘れましたか?そのマシンは必要ありません。どのデバイスからでも **Active Sessions** でそのセッションを失効させられます。 + +## Account アプリのその他の項目 [#also-in-the-account-app] + +| セクション | 用途 | +|---|---| +| **Inbox → My Organizations** | アカウントが所属する組織。 | +| **Inbox → Notifications / Approvals** | 個人の受信トレイ。[通知](/docs/use/notifications)と[承認](/docs/use/approvals)で説明しています。 | +| **Developer → API Keys, OAuth Applications** | 外部ツールを ObjectOS に接続するための認証情報。**ほとんどのユーザーはこのセクションを必要としません**。必要かどうかわからないなら、必要ありません。 | + +## ログアウト [#logging-out] + +アバターメニューを開き、**Log out** をクリックします。これで使っているデバイスのセッションが終了します。他のデバイスは、**Active Sessions** からサインアウトさせるまで、それぞれのセッションを保持します。 + +## 次に進む [#where-to-go-next] + +| 次にすること | 読むもの | +|---|---| +| 受信トレイを管理下に置く | [通知](/docs/use/notifications) | +| 自分に回されたリクエストに対応する | [承認](/docs/use/approvals) | +| データを使って生産的に作業する | [レコード](/docs/use/records) | +| 日常的なユーザーとして ObjectOS を見て回る | [ObjectOS を使う](/docs/use) | diff --git a/content/docs/use/records.ja.mdx b/content/docs/use/records.ja.mdx new file mode 100644 index 00000000..84c6df65 --- /dev/null +++ b/content/docs/use/records.ja.mdx @@ -0,0 +1,85 @@ +--- +title: レコードを操作する +description: 日々の作業の裏にあるレコード(タスク、プロジェクト、顧客、何でも)を開き、読み、作成し、編集します。 +editions: [community, cloud, enterprise] +translation: + source_sha: 18dd6c9ea408b3c20cbbdf3ace75fbfc3830ea0ae649a3066878122a22934d97 + guide_rev: 1 + mode: auto +--- + +ObjectOS のすべては**レコード**です。タスク、プロジェクト、顧客、請求書。このページでは、レコードを開き、そのページを読み、新しいレコードを作成し、多数のレコードを一度に編集する方法を説明します。 + +## レコードを開く [#opening-a-record] + +どのリストでも、**レコードのタイトルはリンク**です。クリックするとレコードページが開きます。戻るには、レコード上部の戻るリンク(たとえば **< All Tasks**)か、左上のパンくずリストを使います。 + +## レコードページの構成 [#anatomy-of-a-record-page] + +レコードページには、上から順に次のものが表示されます。 + +| 要素 | 内容 | +|---|---| +| **戻るリンク** | 元のリストに戻ります(例:**< All Tasks**) | +| **状態パイプラインバー** | ワークフローを持つオブジェクトのみ。レコードがプロセスのどこにあるかを示す山形のステージ | +| **ハイライト帯** | レコードの主要フィールドの概要(例:Project、Assignee、Priority、Due Date、Progress) | +| **アクションボタン** | このレコードに定義されたアクション。たとえば **Log Time** | +| **フィールドセクション** | 残りのフィールドをカードにまとめたもの(例:Overview、Schedule、Details) | +| **Show N empty fields** | セクションの末尾にあるトグル。ページを短く保つため、空のフィールドはデフォルトで折りたたまれています | + +### 状態パイプラインを読む [#reading-the-state-pipeline] + +オブジェクトにワークフローがある場合、上部のバーはすべてのステージを山形で表示します。完了したステージにはチェックマークが付き(✓ Backlog → ✓ To Do → ✓ In Progress)、**現在のステージは強調表示**されます。ひと目でレコードの進み具合がわかります。 + +> **ヒント:** レコードの項目が少なく見える場合は、**Show N empty fields** をクリックしてください。フィールドは存在していて、まだ値がないだけです。 + +## レコードを作成する [#creating-a-record] + +任意のリストの上部にある **+ New** をクリックします。モーダルが開きます(たとえば *"Create Task — Add a new Task to your database"*)。フォームの中には次のものがあります。 + +| 表示されるもの | 動作 | +|---|---| +| `*` の付いたフィールド | 必須です。入力しないと保存できません | +| **Select…** ピッカー | 別のレコード(Project、User)を指す参照フィールド。入力して検索するか、テーブル閲覧ボタンで完全な一覧から選びます。 | +| ドロップダウン | Status や Priority のような選択フィールド。値をひとつ選びます | +| 日付ピッカー | 日付フィールドをクリックし、カレンダーから日を選びます | + +**Create** で完了するか、**Cancel** で破棄します。 + +## レコードをインラインで編集する [#editing-records-inline] + +変更するたびにレコードを開く必要はありません。グリッドビューで、ツールバーの **Edit inline** トグルをオンにすると、セルが編集可能になり、ステータスの修正、タスクの再割り当て、日付の更新をリスト上でスプレッドシートのように直接行えます。 + +## 行ごとのアクションメニュー [#the-per-row-actions-menu] + +グリッドのすべての行の末尾には `⋮` **Actions** メニューがあります。そのレコード 1 件に使えるアクションがまとまっており、先にレコードを開く代わりの手早い方法です。 + +## 多数のレコードを一度に選択する [#selecting-many-records-at-once] + +グリッドの各行は**チェックボックス**で始まります。 + +1. 対象の行にチェックを入れます(ページ全体ならヘッダーのチェックボックス)。 +2. オブジェクトの**一括アクション**(リスト上部の **Reassign…** のようなボタン)が、選択したものすべてに適用されるようになります。 + +> **ヒント:** 一括アクションはオブジェクトごとに異なります。リストヘッダーの **+ New** と **Import** の隣にあるボタンです。 + +## リストヘッダーの全体 [#the-list-header-in-full] + +すべてのリストの上には次のものがあります。 + +| ボタン | 機能 | +|---|---| +| **+ New** | レコードを作成する(上で説明したモーダル) | +| **Import** | 1 件ずつ入力する代わりに、ファイルからレコードを取り込む | +| カスタムの一括アクション | **Reassign…** のようなオブジェクト固有の操作を、選択したものに適用する | +| ベルオフのトグル | このオブジェクトの通知をミュートする。[通知](/docs/use/notifications)を参照してください | + +## 次に進む [#where-to-go-next] + +| やりたいこと | 読むもの | +|---|---| +| リスト自体の見た目を変える:フィルター、グループ化、カンバンへの切り替え | [ビューを使う](/docs/use/views) | +| 行ではなく合計と傾向を見る | [ダッシュボード](/docs/use/dashboards) | +| 自分を待っているレコードを承認する | [承認](/docs/use/approvals) | +| どの更新を受け取るかを制御する | [通知](/docs/use/notifications) | +| ツアーに戻る | [ObjectOS を使う](/docs/use) | diff --git a/content/docs/use/search.ja.mdx b/content/docs/use/search.ja.mdx new file mode 100644 index 00000000..e1a7596d --- /dev/null +++ b/content/docs/use/search.ja.mdx @@ -0,0 +1,102 @@ +--- +title: 検索 +seoTitle: "検索とコマンドパレット:あらゆるレコードを見つける" +description: レコードの一部を入力するだけで見つけられます。⌘K パレット、リストの検索ボックス、参照ピッカーから。そしてアプリ内のどこへでも移動できます。 +editions: [community, cloud, enterprise] +translation: + source_sha: 78801613cbafc2e8b4473a6057341caba6dbfad1ba128189df982d69710f578b + guide_rev: 1 + mode: auto +--- + +{/* + Platform checklist items this page documents (objectstack + docs/qa/platform-checklist/areas/search.json): search.cross-field-object-search, + search.field-scoped-narrowing, search.rls-both-personas, + search.pinyin-flag-both-sides, search.freshness-and-empty, + search.console-global-search, search.command-palette-navigation, + search.global-search-skips-unreadable. +*/} + +名前、メールアドレス、ステータス、都市名の一部を入力すると、ObjectOS はそれを含むレコードを見つけます。同じ検索が 3 つの場所で動作します。 + +| 場所 | 検索対象 | +|---|---| +| **グローバル検索**:`⌘K`(Mac) / `Ctrl-K`(Windows/Linux)、またはトップバーの **Search…** | 読み取れるすべてのオブジェクトにわたるレコードと、アプリ自体のメニュー | +| **リスト検索**:ビューのツールバーの虫眼鏡 | 今いるリストのレコード | +| **参照ピッカー**:別のレコードを指すフィールドの **Select…** ボックス | 選択できるレコード | + +3 つとも入力した語をサーバーに送り、同じ答えを受け取ります。そのため、ひとつの場所で見つかるレコードは他の場所でも見つかります。 + +## 一致の仕組み [#how-matching-works] + +| 入力 | 見つかるもの | +|---|---| +| 単語の一部:`retail` | 検索対象のフィールドのどこかに `retail` を含むすべてのレコード:*Acme Retail*、または業種が *Retail* の取引先 | +| 大文字小文字は問わない:`Retail`、`RETAIL` | 同じレコード。検索は大文字と小文字を区別しません | +| 複数の語:`retail northwind` | **すべての**語が同じレコードのいずれかのフィールドに一致するレコード | +| 選択肢のラベル:`In Progress` | ステータス(または他の選択フィールド)がその選択肢を持つレコード。保存されている値が異なっていても見つかります | + +どのフィールドを検索するかは、アプリを構築した人がオブジェクトごとに設定します。選んでいない場合、検索はレコードの名前またはタイトル、テキストフィールド(メール、電話、URL、長いテキストを含む)、選択フィールドを対象にします。数値、日付、はい/いいえのフィールド、ファイル、他のレコードへのリンクは対象外です。 + +> **ヒント:** 語を増やすと結果が絞り込まれます。`acme invoice` は Acme の請求書を見つけます。Acme のすべてのレコードとすべての請求書ではありません。 + +## 見つかるのは読み取れるものだけ [#you-only-find-what-you-can-read] + +検索は、リストを開くときと同じく、あなたの権限で実行されます。 + +- 読み取れないレコードは決して返されず、合計件数にも数えられません。 +- アクセス権のないオブジェクトは静かにスキップされます。検索は読み取れるオブジェクトから引き続き答えます。 +- あなたから隠されているフィールドは検索されないため、ヒットからその中身が明らかになることはありません。 + +2 人が同じ語を入力しても、異なる結果になることがあります。それは正しい動作です。それぞれが見ることを許された一致を見ています。 + +## 常に最新 [#always-up-to-date] + +待つべきインデックスはありません。作成したばかりのレコードはすぐに見つかります。名前を変更すると、新しい名前が一致し、古い名前は一致しなくなります。削除したレコードは結果から即座に消えます。 + +何も一致しない場合は **No results found** と表示されます。エラーではありません。語を減らすか、短くしてみてください。 + +## 中国語の名前とピンイン [#chinese-names-and-pinyin] + +アプリが中国語をサポートしている場合、検索はピンインで入力された中国語の名前にも一致します。完全な綴り(`zhangwei`)または頭文字(`zw`)で **张伟** が見つかり、漢字も入力したとおりに一致し続けます。ピンインはレコードの名前フィールドに適用されます。 + +ピンイン検索は、アプリの言語に中国語が含まれている場合に有効になります。管理者は `OS_SEARCH_PINYIN_ENABLED` の設定で、デプロイ全体に対してオンまたはオフにできます。 + +## コマンドパレット [#the-command-palette] + +`⌘K` / `Ctrl-K` を押す(または **Search…** をクリックする)とパレットが開きます。検索ボックスとナビゲーターを兼ねています。 + +| 表示されるもの | 機能 | +|---|---| +| **Recently viewed** | ボックスが空の間に表示されます。最近開いたレコードに 1 クリックで移動できます | +| オブジェクト名の下にグループ化されたレコード | **2 文字以上**入力すると、*Accounts* や *Contacts* などの見出しの下に一致が表示されます。**Enter** で強調表示されたレコードを開きます | +| **Objects**、**Dashboards**、**Pages**、**Reports** | 名前が一致する現在のアプリのメニュー項目。メニューグループ内の項目も含みます | +| **Switch App** | 他のアプリ。現在のアプリには **Current** の印が付きます | +| **Preferences** | **Light Theme**、**Dark Theme**、**System Theme**。即座に適用されます | +| **Open Full Search Page** | 検索ページ(下記)を開きます | + +パレットが提示するのは、いずれにせよたどり着けるものだけです。サイドバーで隠されているメニュー項目はここでも隠され、非アクティブなアプリは **Switch App** に表示されません。 + +> **ヒント:** キーボードから手を離さずに:`⌘K`、入力、矢印キー、**Enter**。もう一度 `⌘K` を押すとパレットが閉じます。 + +## 検索ページ [#the-search-page] + +**Open Full Search Page** は、同じ検索の全画面表示に移動します。一致するアプリのオブジェクト、ダッシュボード、ページ、レポートと、オブジェクトごとにグループ化されたレコードの一致が表示されます。ボックスに入力して絞り込みます。 + +## リスト内を検索する [#searching-inside-a-list] + +ビューのツールバーの虫眼鏡は、今いるリストを絞り込みます。ビューのフィルター、グループ化、ソートと組み合わせて動作します。[ビューを使う](/docs/use/views)を参照してください。*どの*リストかわかっているときに使い、わからないときは `⌘K` を使います。 + +## アプリビルダー向け [#for-app-builders] + +オブジェクトの `searchableFields` は、検索がスキャンするフィールドを設定します。省略すると、上で説明した名前、テキスト、選択フィールドになります。ビューや API 呼び出しはスキャンをそれらのうちの少ないフィールドに絞り込めますが、広げることは決してできません。セット外のフィールドを要求すると、無視されるのではなく拒否されます。計算される `formula` フィールドは保存されないため検索できません。値を保存されるテキストフィールドにコピーして、そちらを検索してください。 + +## 次に進む [#where-to-go-next] + +| やりたいこと | 読むもの | +|---|---| +| リストをフィルター、グループ化、ソートする | [ビューを使う](/docs/use/views) | +| 見つけたレコードを開いて編集する | [レコードを操作する](/docs/use/records) | +| 誰がどのレコードを見られるかを理解する | [権限](/docs/configure/permissions) | +| ツアーに戻る | [ObjectOS を使う](/docs/use) | diff --git a/content/docs/use/views.ja.mdx b/content/docs/use/views.ja.mdx new file mode 100644 index 00000000..30d2ca3a --- /dev/null +++ b/content/docs/use/views.ja.mdx @@ -0,0 +1,90 @@ +--- +title: ビューを使う +seoTitle: "ビューを使う:グリッド、ボード、カレンダー、タイムライン" +description: 同じレコードをグリッド、ボード、カレンダー、タイムラインとして表示し、自分の方法でフィルター、グループ化、ソートします。 +editions: [community, cloud, enterprise] +translation: + source_sha: ed314bea3937ef6fc74e2f3459c058566342cca16afa870864575be9d8550c86 + guide_rev: 1 + mode: auto +--- + +**ビュー**は、オブジェクトのレコードを見るための保存された方法です。同じタスクを、スプレッドシートのようなグリッド、カンバンボード、カレンダーとして表示できます。自由に切り替えられ、データは何も変わりません。 + +## ビューのタブ [#view-tabs] + +すべてのリストの上部には、オブジェクトのビューがタブとして表示されます。たとえば次のとおりです。 + +**All Tasks ★ | In Progress | Urgent | Done | … 9 more | +** + +| タブの要素 | 意味 | +|---|---| +| **★** | デフォルトのビュー。最初に開くものです | +| 名前付きのタブ(*In Progress*、*Urgent*) | チーム向けに設定された、あらかじめフィルターされたビュー。タブの小さな漏斗のバッジは、組み込みのフィルターがあることを示します。 | +| **… 9 more** | ビューが収まりきらないときのオーバーフローメニュー | +| **+** | 自分の**個人ビュー**を作成します。自分のフィルター、自分の列を、自分専用に保存します | + +> **ヒント:** 毎朝同じフィルターを適用し直す代わりに、**+** を一度クリックして個人ビューとして保存しましょう。 + +## ビューの種類を切り替える [#switching-view-types] + +右側のツールバーには、現在のビューの種類(例:**Grid**)が表示されます。クリックすると、同じレコードを見る 6 つの方法を切り替えられます。 + +| 種類 | 最適な用途 | +|---|---| +| **Grid** | 日常的な表。多数のレコードの一覧、ソート、編集 | +| **Kanban** | 進行中の作業。ボード上でステージを移動するカード | +| **Gallery** | 画像が重要なレコード。製品、デザイン、人 | +| **Calendar** | 日付を持つもの。締め切り、イベント、予約を月または週ごとに | +| **Timeline** | 時間に沿ったレコードの時系列フィード | +| **Gantt** | プロジェクト計画。開始、終了、期間を示すバー | + +## ビューのツールバー [#the-view-toolbar] + +ビューの種類の切り替えの隣には、次のものがあります。 + +| コントロール | 機能 | +|---|---| +| **Edit inline** | グリッドでスプレッドシートのようなセル編集を切り替えます。[レコードを操作する](/docs/use/records)を参照してください | +| **Filter** | 選んだ条件に一致するレコードだけを表示します | +| **Group** | 行を見出しの下にまとめます(例:Project や Assignee ごと) | +| **Sort** | レコードを並べ替えます。バッジは有効なソートルールの数を示します | +| 列の設定 | どの列をどの順序で表示するかを選びます | +| 虫眼鏡 | **ビュー内検索**。入力して現在のリストを絞り込みます | + +> **ヒント:** ビュー内検索は今いるリストを絞り込みます。`⌘K` / `Ctrl-K` はすべてのオブジェクトにわたってレコードを検索します。*どの*リストかわかっているときは虫眼鏡を、わからないときは `⌘K` を使いましょう。 + +## グリッドを読む [#reading-a-grid] + +グリッドのセルには追加の情報が詰め込まれています。 + +| 表示されるもの | 意味 | +|---|---| +| 行のチェックボックスと `#` 番号 | 一括アクションのために行を選択し、行数をひと目で数えます | +| 色付きのピル | Status や Priority のような選択フィールドの値。色は値に従います | +| 赤い日付("Overdue 6d") | 日付が過ぎています。その日数だけ期限切れです | +| 進捗バー | 完了率のフィールドをバーで表示したもの | +| 行末の `⋮` | 行ごとのアクションメニュー | +| フッターの件数("10 records") | 現在のビューに含まれるレコードの数 | + +## カンバンボード [#kanban-boards] + +**Kanban** に切り替えると、レコードは**列の中のカード**になります。列はオブジェクトの選択フィールドのひとつから作られます。タスクの場合は通常 Status なので、*Backlog*、*To Do*、*In Progress*、*In Review* などになります。 + +| ボードの要素 | 表示内容 | +|---|---| +| 列ヘッダー | ステージ名と、その列のカードの**件数** | +| カード | レコードのタイトルと主要な詳細。担当者、優先度のピル | +| ツールバー | グリッドと同じ **Filter / Group / Sort** のコントロール | + +カンバンは「各ステージにどれだけの作業があるか」にひと目で答えます。列の件数がボトルネックの検出器です。 + +## 次に進む [#where-to-go-next] + +| やりたいこと | 読むもの | +|---|---| +| ビューの裏にあるレコードを開いて編集する | [レコードを操作する](/docs/use/records) | +| 行ではなく集計された数値を見る | [ダッシュボード](/docs/use/dashboards) | +| 承認リクエストに対応する | [承認](/docs/use/approvals) | +| ベルが知らせる内容を調整する | [通知](/docs/use/notifications) | +| ツアーに戻る | [ObjectOS を使う](/docs/use) | diff --git a/content/docs/why.ja.mdx b/content/docs/why.ja.mdx new file mode 100644 index 00000000..ababb27b --- /dev/null +++ b/content/docs/why.ja.mdx @@ -0,0 +1,124 @@ +--- +title: なぜ ObjectOS なのか +seoTitle: "なぜ ObjectOS なのか:使うべきときと、使うべきでないとき" +description: 率直な説明。使うべきとき、使うべきでないとき、そして何が違うのか。 +editions: [community, cloud, enterprise] +translation: + source_sha: 5f5a99346059a4eebaab08952d7d63a45e80b1fef6b6aaf390b849f7de2d5808 + guide_rev: 1 + mode: auto +--- + +このページは、ObjectOS があなたに合っているかを判断するために、他のすべてのドキュメントの行間を読まなくても済むように存在します。 + +## 賭けの形 [#the-shape-of-the-bet] + +**オントロジーこそがソフトウェアです。** 実行可能なひとつのビジネスオントロジー。AI が書き、ランタイムが実行し、エージェントが操作し、あなたが所有します。4 つの約束です。そして ObjectOS は、何もインストールせずにブラウザ上のホスト型で(**ObjectOS Cloud**)、あなた自身のインフラストラクチャ上でセルフマネージドで(**ObjectOS Enterprise**)、あるいは自分のマシン上で無料で(**ObjectOS Community**、オープンソースのランタイム)、その約束を守ります。 + +- **実行可能。** オブジェクト、フィールド、リレーション、アクション、権限、フロー、エージェント定義は、ランタイムが実行する、型付きでバージョン管理されたひとつの定義です。REST エンドポイント、生成された画面、RBAC、監査ログ、MCP ツールはすべてそこから導出されます。コード生成のステップも、「説明した」と「稼働した」の間のデプロイパイプラインもありません。 +- **AI が書ける。** その定義をファイルごとに手で書く必要はありません。ビジネスに必要なものを組み込みの [AI Builder](/docs/build/ai-builder) に説明してください。AI Builder は少数の監査済みツールを呼び出し、すべての変更は人の承認を待つキューに入り、結果は実際に読める小さな差分になります。 +- **エージェントが操作できる。** すべてのオブジェクトと公開されたすべてのアクションは MCP ツールを兼ねるため、エージェントは人と同じ権限、行レベルセキュリティ、監査のもとで稼働中のアプリを操作します。生の SQL も、スクレイピングした UI も使いません。 +- **あなたが所有する。** オントロジーは通常の [ObjectStack](https://github.com/objectstack-ai/objectstack) メタデータで、Apache-2.0 です。どちらのエディションでもエクスポートして、そのオープンソースのランタイムで実行できます。ObjectOS Enterprise では、ランタイムとデータベースもあなたのインフラストラクチャ上に置かれます。 + +説明は以上です。このページの残りは、それが誰に合い、誰に合わないかです。 + +## 次に当てはまるなら ObjectOS を使ってください [#use-objectos-if-you-] + +- 社内ツール、管理パネル、バックオフィスアプリが必要で、**かつ** +- それを使う人(またはその人の代わりに動く AI エージェント)が、チケットを起票せずにそれを*拡張*できるようにしたく、**かつ** +- ホスト型で運用してほしい(ObjectOS Cloud)、あるいは自社の境界内で実行しなければならない(ObjectOS Enterprise)、**かつ** +- 認証 + RBAC + 監査 + ファイルアップロード + ジョブ + Webhook を 10 回目に作り直したくない。 + +適しているよくあるシナリオ: + +| シナリオ | うまくいく理由 | +|---|---| +| セキュリティレビューでデータ主権が問題になったため、Retool / Appsmith アプリを置き換える | ObjectOS Enterprise はあなたの VPC 内で動作し、データは外に出ません | +| 規制業種向けにコンプライアンス / リスク / ベンダー管理ツールを構築する | 監査ログ、RBAC、フィールドセキュリティ、行レベルの分離が正式な機能です。そして AI による変更はそれ自体が監査エントリになります | +| SaaS 製品の社内管理画面を立ち上げる | ひとつの Node プロセスで、既存のサービスの隣に収まります。あるいは何も実行しなくてよい Cloud テナントです | +| エンタープライズ顧客向けのエアギャップまたはオンプレミスのデプロイ | ObjectOS Enterprise の正式なターゲットです。エアギャップライセンスはオフラインで検証され、AI サービスはローカルモデルを指せます | +| マルチテナントの社内ポータル(複数の組織、ひとつのデプロイ) | 隔離型のテナンシー体制が、ランタイム内で強制される組織ごとの分離の壁を立てます。これは Enterprise の機能です。[ライセンスと料金](/docs/editions/license)を参照してください。分離されるのは組織のデータとメンバーシップであり、スキーマではありません。組織はひとつのデータベースとひとつのメタデータセットを共有します | +| ユーザーが変更を説明するだけで、安全にアプリを拡張できるようにしたい | AI Builder + HITL 承認キュー + 監査ログこそが要点です | +| 基幹 ERP の周りにあるロングテールの部門アプリ:ベンダーのオンボーディング、点検、社内申請 | それぞれが、メールで回されるスプレッドシートではなく、頻繁に変わる小さな型付きの定義になります | +| 初日からエージェントが操作するバックオフィス | すべてのデプロイはデフォルトで有効な MCP サーバーです。エージェントは人と同じ権限と監査を通じて動作します | + +## 次に当てはまるなら ObjectOS を使わないでください [#dont-use-objectos-if-you-] + +- 大企業の基幹 ERP や財務システムを置き換える必要がある → 総勘定元帳、連結、税務、給与には規制が伴い、パッケージシステムがすでにそれを組み込んでいます。その中核の代わりではなく、周りに構築してください。 +- 価値の大部分が多数の既存システムの統合から生まれる → すでに運用しているデータベースへの接続は[デフォルトで読み取り専用で、まだ初期段階](/docs/build/extend-existing-systems)です。それらのシステムの上に載るレイヤーのほうが適しています。 +- データレイク上の分析が必要 → ダッシュボードはアプリ自身のオブジェクト上で動作します。レイクをクエリするようには作られていません。 +- 価格設定やスケジューリングのような、アルゴリズム中心の領域で作業している → オントロジーは何ができるかを宣言するものであり、最適化エンジンではありません。アルゴリズムを[アクション](/docs/build/interface/actions)としてラップすれば、権限、監査、エージェントアクセスが他のものと同様に適用されます。 +- それ自体が認証を受けたプラットフォーム上で実行しなければならない → ObjectOS はそうではありません。認証は稼働中のデプロイに対して行われ、あなたのデプロイの認証はあなたが担う作業です。[セキュリティとコンプライアンス](/docs/reference/security#compliance-frameworks)を参照してください。 +- 高トラフィックのコンシューマー製品を構築している → 従来の Web フレームワークを使ってください。より多くを制御できます。 +- エンドユーザー向けにピクセル単位で作り込んだ独自 UI が必要 → 生成される UI は管理/社内用途向けです。REST 経由で独自のフロントエンドと組み合わせてください。 +- エンジニア以外の人向けのドラッグ&ドロップのキャンバスが欲しい → Retool、Bubble、Airtable を使ってください。ObjectOS は UI をオントロジーから生成します。ビルダーは AI とそれが提案する差分であり、キャンバスではありません。 +- リアルタイムの共同編集(Figma のような)が必要 → それは realtime プラグインが解決するものではありません。 + +最初の 5 つの理由は、ObjectOS の土台であるオープンなランタイムについて、[ObjectStack を使うべきとき](https://objectstack.ai/docs/concepts/when-to-use)に説明されています。 + +## おそらく今使っているものとの比較 [#compared-to-what-youre-probably-using] + +### Retool / Appsmith / 社内開発との比較 [#vs-retool--appsmith--internal] + +| | Retool | ObjectOS | +|---|---|---| +| データの場所 | 彼らのクラウド(上位プランではセルフホストも可) | ObjectOS Cloud、または ObjectOS Enterprise ではあなたのネットワーク | +| UI ビルダー | ドラッグ&ドロップ、非常に洗練されている | メタデータ駆動で生成。カスタマイズ性は低い | +| 料金 | ユーザー単位で、増えると苦しい | AI シートのみ。閲覧者は無料。無料のセルフホストはオープンソースの ObjectStack ランタイム | +| ワークフロー / トリガー | 彼らのワークフローエンジン | 宣言的なフロー + プラグイン | +| バックエンドロジック | 彼らのクエリエディターに限られる | 完全な TypeScript、Node エコシステム全体 | +| 最適な用途 | 既存の API の上に作る手早いダッシュボード | 定義を自分で所有するアプリ | + +### Supabase / Firebase との比較 [#vs-supabase--firebase] + +| | Supabase | ObjectOS | +|---|---|---| +| セットアップ時間 | 約 30 秒 | 約 30 秒 | +| データベース | Postgres、彼らのもの(セルフホストも可) | ObjectOS Cloud ではマネージド。ObjectOS Enterprise では任意の Postgres / MySQL / SQLite / Turso / Mongo、**あなたのもの** | +| 認証 | 組み込み | 組み込み | +| 生成される API | PostgREST | ObjectQL が生成する REST | +| 管理 UI | Console(基本的) | Setup + Account | +| RBAC | Postgres RLS による行レベル | RBAC + 行レベル + フィールドレベル、宣言的 | +| 監査ログ | 自作 | 正式な機能 | +| ベンダーロックイン | 彼らの認証 + 彼らのストレージ + 彼らのリアルタイム | オントロジーはオープンソースの ObjectStack ランタイムへエクスポートでき、すべてのレイヤーがプラグイン | +| 最適な用途 | BaaS が欲しい新規アプリ | 定義を所有する必要があるアプリ。Enterprise ではランタイムも | + +### Salesforce / NetSuite / ServiceNow との比較 [#vs-salesforce--netsuite--servicenow] + +| | Salesforce | ObjectOS | +|---|---|---| +| データモデル | オブジェクト + フィールド + リレーションシップ、プラットフォーム内で設定 | オブジェクト、フィールド、リレーションをひとつのオープンなオントロジーに。エクスポート可能で、Apache-2.0 の ObjectStack ランタイムで実行可能 | +| 権限 | プロファイル + 権限セット + 共有ルール + FLS | 馴染みのある語彙(権限セット、ポジション、共有ルール、FLS)をオントロジーで宣言し、すべての REST 呼び出し、UI クリック、エージェントのツール呼び出しで強制 | +| ユーザーあたりのコスト | $150-300/ユーザー/月 | 閲覧者と AI を使わないユーザーは無料。支払うのは AI シートのみ | +| カスタマイズ | Apex + Lightning + フロー | TypeScript + フロー | +| 実行場所 | 彼らのクラウドのみ | ObjectOS Cloud、またはあなたのインフラストラクチャ(ObjectOS Enterprise) | +| 「自分たちのもの」になるまでの時間 | コンサルタント作業で数か月 | 午後ひとつ | +| 最適な用途 | エコシステムにお金を払う営業主導の企業 | 税金なしでモデルを手に入れたいチーム | + +### 自前で構築する場合(Next.js + Prisma + NextAuth)との比較 [#vs-rolling-your-own-nextjs--prisma--nextauth] + +| | 自作 | ObjectOS | +|---|---|---| +| 最初の REST エンドポイント | 数時間 | 60 秒 | +| 認証(メール + OAuth + OIDC + パスキー + 2FA) | 数週間 | 含まれる | +| すべてのオブジェクトの管理 UI | オブジェクトごとに構築 | 生成される | +| 監査ログ | 自作 | プラグイン、宣言的 | +| 権限付きの S3 へのファイルアップロード | 自作 | プラグイン | +| バックグラウンドジョブ + リトライ + デッドレター | 自作 | プラグイン | +| マルチテナンシー | 自作(そして 2 回は間違える) | 組み込み | +| 最適な用途 | 独自の UX を持つ公開アプリ | スピードが勝る社内ツール | + +## 率直なトレードオフ [#the-honest-tradeoffs] + +- **Retool より UI の自由度は低い。** UI はメタデータから生成されます。独自のフロントエンドと組み合わせることはできます(REST API は UI が使うものと同じです)が、手作りでピクセル単位まで作り込んだ UI が必要なら、自分で構築して ObjectOS をバックエンドとして使ってください。 +- **TypeScript ファースト。** エンジニア以外の人がリポジトリで直接オブジェクトを作成することはありません。Salesforce の管理者は UI ビルダーをクリックして進むことに慣れていますが、ここでは AI Builder の差分か `git` です。 +- **Salesforce より新しい。** Salesforce には 25 年分のエッジケースが文書化されています。私たちには数百です。プロトコルは安定しています。エコシステムは成長中です。 +- **オープンソースの基盤、3 つのエディション。** 土台となる ObjectStack スタックは Apache-2.0 です。商用製品で使い、組み込み、非公開で改変でき、コピーレフトの驚きはありません。**ObjectOS Community**、すなわちそこから構築されたオープンソースのランタイムと Console は、同じライセンスのもとで無料です。**ObjectOS Cloud** と **ObjectOS Enterprise** は商用エディションで、ホスティングと運用、AI Builder、SSO、サポートを追加します。 + +## 現実の確認 [#reality-check] + +最小の ObjectOS は ObjectOS Cloud 上の Free テナントです。最小のセルフマネージド構成は SQLite を使うシングルノードのコンテナです。現在本番で最大のものは、Postgres + S3 + Redis を使い、複数のリージョンにまたがって数万人の社内ユーザーにサービスを提供しています。そのすべてが同じソフトウェアを実行しています。 + +[ObjectOS Cloud](https://www.objectos.ai) で始めるか、ObjectOS Community で`npm create objectstack@latest my-app` を使ってプロジェクトをスキャフォールドし、5 分で判断してください。合わなければ、失ったのは 5 分です。 + +[**ObjectOS Community をローカルで実行する →**](/docs/start/community) From 408661e56dc5acb4811c7f496e85f0b3d76e1d4c Mon Sep 17 00:00:00 2001 From: Steedos Date: Thu, 29 Oct 2026 10:46:47 +0000 Subject: [PATCH 02/22] docs(i18n): translate build/ and build/data/ into ja (#388, PR 1 of 7) Phase 2 of the other-locale plan, first batch: ja for the build/ top level (index, agents, ai-builder, ai-skills, extend-existing-systems, marketplace, packages, reports, templates) and build/data/ (index, relationships, formulas, validation-rules). Same rules as #386: English heading ids, fences byte for byte, glossary ja column, UI labels in English, one line per paragraph, each page stamped. check-translations: ja 0 stale, 66 missing (was 79). Refs #388 Claude-Session: https://claude.ai/code/session_01QsR2jRsjbApbf83iyTDDXm Co-Authored-By: Claude --- content/docs/build/agents.ja.mdx | 162 +++++++++ content/docs/build/ai-builder.ja.mdx | 160 +++++++++ content/docs/build/ai-skills.ja.mdx | 91 +++++ content/docs/build/data/formulas.ja.mdx | 208 ++++++++++++ content/docs/build/data/index.ja.mdx | 310 ++++++++++++++++++ content/docs/build/data/relationships.ja.mdx | 180 ++++++++++ .../docs/build/data/validation-rules.ja.mdx | 237 +++++++++++++ .../docs/build/extend-existing-systems.ja.mdx | 62 ++++ content/docs/build/index.ja.mdx | 53 +++ content/docs/build/marketplace.ja.mdx | 140 ++++++++ content/docs/build/packages.ja.mdx | 164 +++++++++ content/docs/build/reports.ja.mdx | 164 +++++++++ content/docs/build/templates.ja.mdx | 93 ++++++ 13 files changed, 2024 insertions(+) create mode 100644 content/docs/build/agents.ja.mdx create mode 100644 content/docs/build/ai-builder.ja.mdx create mode 100644 content/docs/build/ai-skills.ja.mdx create mode 100644 content/docs/build/data/formulas.ja.mdx create mode 100644 content/docs/build/data/index.ja.mdx create mode 100644 content/docs/build/data/relationships.ja.mdx create mode 100644 content/docs/build/data/validation-rules.ja.mdx create mode 100644 content/docs/build/extend-existing-systems.ja.mdx create mode 100644 content/docs/build/index.ja.mdx create mode 100644 content/docs/build/marketplace.ja.mdx create mode 100644 content/docs/build/packages.ja.mdx create mode 100644 content/docs/build/reports.ja.mdx create mode 100644 content/docs/build/templates.ja.mdx diff --git a/content/docs/build/agents.ja.mdx b/content/docs/build/agents.ja.mdx new file mode 100644 index 00000000..05a53cc9 --- /dev/null +++ b/content/docs/build/agents.ja.mdx @@ -0,0 +1,162 @@ +--- +title: エージェント +seoTitle: "AI エージェント:エージェント、スキル、ツールを定義する" +description: エンドユーザー向けの AI アシスタント。Agent → Skill → Tool の構成で、データとアクションから組み立てます。 +editions: [community, cloud, enterprise] +translation: + source_sha: a79f76287f957b73a7b772cee68ed44718d9d50857f83da882622e1206d1122a + guide_rev: 1 + mode: auto +--- + +エージェントは、**エンドユーザー**がチャットする AI アシスタントです。ヘルプデスクのコパイロット、営業の BDR、社内 HR の Q&A ボットなどです。エージェントはすでに定義したデータとアクションの上に載ります。新しいコードは書かず、既存のプリミティブを組み合わせてペルソナを作ります。 + +Salesforce Agentforce、Microsoft Copilot Studio、ServiceNow Now Assist にそろえた 3 層のアーキテクチャです。 + +```text +Agent ──→ Skill ──→ Tool +(persona) (capability) (callable function) +``` + +| 層 | 内容 | 例 | +|---|---|---| +| **Tool** | 呼び出し可能な関数ひとつ(アクション、クエリ、ナレッジ検索、MCP メソッド) | `create_ticket`、`get_order_status`、`search_kb` | +| **Skill** | 関連するツールを、共通の LLM 指示とともにまとめた名前付きの束 | `ticket_management` = 作成 + 更新 + クローズ + エスカレーション | +| **Agent** | 役割、システムプロンプト、付属するスキルを持つペルソナ | `tier1_support` = 共感的で、本人確認を行い、`ticket_management` + `kb_search` を持つ | + +## エージェントを定義する(ファイル 1 つ) [#define-an-agent-one-file] + +```ts +// src/agents/tier1_support.agent.ts +import { defineAgent } from '@objectstack/spec/ai'; + +export const tier1Support = defineAgent({ + name: 'tier1_support', + label: 'First Line Support', + role: 'Help Desk Assistant', + instructions: ` + You are a friendly first-line support agent. + Always verify the user's identity before discussing account specifics. + Search the FAQ and the policy articles before you answer a how-to question. + Escalate to tier 2 if the issue involves billing or security. + `, + skills: ['ticket_management', 'knowledge_search'], + model: { provider: 'openai', model: 'gpt-4o', temperature: 0.3 }, + memory: { longTerm: { enabled: true, maxEntries: 50 }, reflectionInterval: 10 }, +}); +``` + +エージェントには `knowledge` ブロックはありません。`search_knowledge` ツールがどのソースを読めるかは、ナレッジサービスでソースごとに制限されます。エージェントがどのソースに基づいて答えるべきかは `instructions` に書いてください。 + +UI からは:**Studio → Agents → New Agent**。 + +あるいは、そしてこれが要点ですが、AI Builder にこう伝えます。 + +> *「チケット管理を担当し、FAQ を検索する Tier 1 サポートエージェントを作って。アカウントの詳細について話す前に本人確認をすること。」* + +## スキルを定義する [#define-a-skill] + +```ts +// src/skills/ticket_management.skill.ts +import { defineSkill } from '@objectstack/spec/ai'; + +export const ticketManagement = defineSkill({ + name: 'ticket_management', + label: 'Ticket Management', + instructions: ` + Always confirm the ticket subject and priority before creating one. + Use 'urgent' priority sparingly — only for outages or security incidents. + `, + tools: [ + 'create_ticket', + 'update_ticket', + 'close_ticket', + 'escalate_ticket', + 'action_*', // wildcard: every action the app exposes to AI (`ai.exposed`) + ], +}); +``` + +スキルは**再利用に適した単位**です。ひとつのスキルが多くのエージェントで機能します。 + +## ツールは宣言したメタデータから生まれる [#tools-come-from-your-declared-metadata] + +アクションは、**作成者がそれを AI に公開したとき**(40 文字以上の `ai.description` を伴う `ai: { exposed: true }`)、かつその種類が UI なしで実行される(`script`、`flow`、`api`)場合に、`action_` ツールになります。それ以外に配線は不要です。`support_ticket` オブジェクトの `escalate_ticket` が公開されていれば、AI Builder もあなたのエージェントもそれを呼び出せます。公開されていないアクションはエージェントからは見えず、呼び出し元がどのような権限を持っていても、呼び出されれば拒否されます。 + +呼び出しは**ユーザーとして**チェックされます。アクションの `requiredPermissions` が実行してよいかを決め、アクションはそのユーザーとしてレコードを読み込みます。その後 `script` の本体は信頼されたアプリコードとして実行されるので、それらのチェックを通過する誰に対しても本体を安全に実行できる場合にだけ、アクションを公開してください。[アクション](/docs/build/interface/actions#permissions)を参照してください。 + +次のものも公開できます。 + +| ツールの種類 | ソース | +|---|---| +| **アクション** | インストールされた任意のパッケージで、AI に公開された(`ai.exposed`)任意のアクション | +| **フロー** | 公開された `type: 'flow'` のアクション。エージェントがアクションを呼び出し、アクションがフローを開始します | +| **クエリ** | 保存された ObjectQL クエリ(`*.query.ts`) | +| **ナレッジ検索** | ユーザーが読めるソースを対象とする `search_knowledge` ツール | +| **MCP メソッド** | 接続された MCP サーバーが公開するもの | +| **組み込みのメタデータツール** | `create_object`、`add_field` など。ただし管理者向けエージェントのみ | + +## アンビエントアシスタントのパターン [#ambient-assistant-pattern] + +ユーザーにエージェントを選ばせる代わりに、**アプリ全体でひとつのチャットボックス**(Claude Code / Agentforce のスタイル)が欲しい場合は、App メタデータで `defaultAgent` を宣言し、アプリのコンテキストを付けてアンビエントチャットのエンドポイントを呼び出します。 + +```text +POST /api/v1/ai/chat { context: { appName: 'crm' }, ... } +``` + +`context.appName` が `defaultAgent` を宣言しているアプリに解決されると、ランタイムはそのエージェントを自動的に選択します。ユーザーが一覧から選ぶことはありません。組み込みの AI パネルはこの仕組みを使っています。ランタイムは次のものを解決します。 + +1. アクティブなアプリの**デフォルトエージェント**(アプリの `defaultAgent`)、またはユーザーがアクセスできる最初のエージェント。 +2. **アクティブなスキル**:Skill Registry から読み込まれたエージェントの `skills:` の一覧を、ユーザーの権限セットと現在のオブジェクト/レコードのコンテキストでフィルターしたもの。 + +どのエージェントをどこに表示するかを配線する必要はありません。アプリを宣言し、その `defaultAgent` を設定すれば表示されます。 + +## 権限 [#permissions] + +| 機能 | 権限 | +|---|---| +| エージェントとチャットする | `ai:chat`(とエージェントのスキルのツールへのアクセス) | +| メタデータの変更を承認する | `ai:approve` | +| エージェントとスキルを定義 / 編集する | `ai:author`(通常は Setup Administrator) | +| AI の会話を読む(監査) | `ai:read` | + +会話はユーザーにスコープされます。委任された許可がない限り、あるユーザーが別のユーザーのチャット履歴を見ることはできません。 + +## メモリと会話の状態 [#memory-and-conversation-state] + +エージェントの `memory` ブロックは長期メモリを設定します。各ユーザーについて抽出され、セッションをまたいで引き継がれるメモです。 + +| フィールド | 機能 | +|---|---| +| `longTerm.enabled` | セッションをまたいでメモを保持する(デフォルト `false`) | +| `longTerm.maxEntries` | ユーザーごとに保持するメモの数。新しいものから想起されます。`enabled` が true の場合は必須 | +| `reflectionInterval` | 振り返りの間に何回のやり取りがあるか。メモを書くのは振り返りです。`enabled` が true の場合は必須 | + +短期メモリのブロックはありません。1 回のリクエストのコンテキストウィンドウはトークン予算で制限されます。メモをどこに保存するかはプラットフォームが選ぶことであり、エージェントのメタデータではありません。 + +稼働中のコンテキストウィンドウの刈り込みは、会話のトークン予算の戦略で制御されます。`sliding_window`(デフォルト)、`fifo`、`importance`、`semantic`、`summary` です。 + +会話の行は `ai_conversations` に保存されます。ツール呼び出しの結果と保留中のアクションは、監査のために元の会話を相互参照します。 + +## 可観測性 [#observability] + +エージェントの実行はすべて次のものを出力します。 + +- `audit:ai:chat` イベント(ターンごと) +- `audit:ai:tool` イベント(ツール呼び出しごと、入力と出力付き) +- `audit:ai:pending_action` イベント(変更がキューに入ったとき) +- チャージバックのための、監査ログへのトークン数のメトリクス(モデルごと、プロバイダーごと) + +これらは普段使っている可観測性スタックにつなげられます。[可観測性](/docs/operate/observability)を参照してください。 + +## マルチテナントに関する注意 [#multi-tenant-note] + +エージェントは環境ごとです。テナント A の `tier1_support` エージェントがテナント B のデータ、会話、ナレッジを見ることは決してありません。同じエージェント定義をマーケットプレイスのパッケージで配布していても同じです。 + +## 次に進む [#where-to-go-next] + +- [AI Builder](/docs/build/ai-builder):構築時のアシスタント +- [IDE スキル](/docs/build/ai-skills):`npx skills add objectstack-ai/objectstack/skills` で、IDE のエージェントがメタデータを正しく作成できるようにする +- [アクション](/docs/build/interface/actions):エージェントが使うツールを宣言する +- [AI サービス](/docs/configure/ai):プロバイダー、エンベッダー、MCP の設定 +- [`@objectstack/spec/ai`](https://github.com/objectstack-ai/objectstack/tree/main/packages/spec/src/ai):完全なスキーマ diff --git a/content/docs/build/ai-builder.ja.mdx b/content/docs/build/ai-builder.ja.mdx new file mode 100644 index 00000000..b5f9612a --- /dev/null +++ b/content/docs/build/ai-builder.ja.mdx @@ -0,0 +1,160 @@ +--- +title: AI Builder +seoTitle: "AI Builder:平易な言葉のチャットからアプリを構築する" +description: 平易な言葉の要件を稼働するメタデータに変える組み込みのチャットと、データについての質問に答えるアシスタント。それぞれの仕組み、呼び出すツール、変更の承認方法を説明します。 +editions: [cloud, enterprise] +translation: + source_sha: 3dc30df8f6289a706b6eb8101c4160ba800617f579063fc3b62f98518b34fad2 + guide_rev: 1 + mode: auto +--- + +AI Builder は、**顧客が ObjectOS を拡張する主要な方法**です。ObjectOS を開き、必要なものを平易な言葉で説明すると、オブジェクト、フィールド、ビュー、ダッシュボード、フロー、アプリ全体といったメタデータを構築してくれます。計画を承認するまでは何も構築されず、構築されるものはすべて、読み、変更し、パッケージ化できる通常の ObjectStack メタデータです。 + +## 2 つのエージェント:Builder と Assistant [#two-agents-the-builder-and-the-assistant] + +ObjectOS には 2 つの AI エージェントが付属します。どちらかを選ぶ必要はありません。**どこで尋ねるか**で、どちらが答えるかが決まります。 + +| | **Builder**(`build`) | **Assistant**(`ask`) | +|---|---|---| +| 場所 | アプリ構築のサーフェスにある AI Builder | データコンソールで、レコードの横にあるチャット | +| 何をするか | **アプリ**を設計し変更する:オブジェクト、フィールド、ビュー、ダッシュボード、フロー | **データ**についての質問に答え、グラフを描き、アプリが公開するアクションを実行する | +| 決してしないこと | — | アプリケーションを変更すること。構築のリクエストが届くと断り、Builder を案内します。黙って振り替えることは決してありません | + +どちらも**サインインしている人として**実行されます。すべてのツール呼び出しはその人の権限、レコードアクセス、フィールドレベルセキュリティに照らしてチェックされるので、AI がその人自身にできる以上のものを見たり変更したりすることは決してありません。 + +**Builder を使える人。** AI シートだけでは不十分です。Builder はアプリのメタデータを変更するので、`manage_metadata` または `studio.access` の権限も必要です。どちらも持たないメンバーには Assistant だけが表示され、Builder への直接のリクエストは `403 PERMISSION_DENIED` で拒否され、すべての構築ツールは実行時に権限をもう一度チェックします。 + +## 試してみる [#try-it] + +``` +You: I need to track customer support tickets. + Each ticket has a subject, description, priority (low/medium/high/urgent), + status (new/open/pending/resolved/closed), and assignee. + +AI: Here's the plan: + • Object `support_ticket` with 5 fields + • A kanban view grouped by status + • A dashboard of open tickets by priority + • A few sample tickets to try it with + + Shall I build it? + +You: Yes + +AI: ✓ Object created + ✓ Kanban view and dashboard created + ✓ Sample data added + Published — open Support Tickets to try it. +``` + +これで動作するチケット管理アプリができました。REST エンドポイント、生成されたビュー、監査ログのエントリ、権限のチェックポイントなど、すべてそろっています。ファイルは編集されず、再起動も起きていません。 + +## 構築の流れ [#how-a-build-runs] + +1. **計画。** 単一の変更より大きなもの(「採用管理システムを作って」)については、Builder はまず**ブループリント**を提案します。作成しようとしているオブジェクト、フィールド、リレーションシップ、ビュー、ダッシュボード、サンプルデータと、その前提です。このステップでは何も作成されません。 +2. **承認。** チャットで答えます。承認するか、変更を求めて修正された計画を受け取ります。Builder は、その会話であなたが承認した後にのみ変更を加えます。 +3. **ドラフトとして構築。** 承認された変更は**ドラフト**として書き込まれます。ステージングされた状態で、まだ稼働していません。 +4. **検証。** Builder はドラフトをプラットフォームのルールに照らしてチェックし、何かが稼働する前に直せるものを直します。 +5. **公開。** ドラフトは構築している環境に公開され、アプリがサンプルデータとともにそこに現れます。ステータスパネルが実際に公開されたものを表示します。Builder は、出荷されていない変更を出荷済みと報告することは決してありません。 + +既存のアプリを拡張するには、そう伝えます。*「サポートアプリに満足度アンケートを追加して」*。すると Builder は、別のアプリを構築する代わりに、新しい部品をそのアプリのオブジェクトにリンクするよう設計し、ナビゲーションに追加します。 + +## 依頼できること [#what-you-can-ask-for] + +| 目的 | プロンプト | +|---|---| +| 新しいオブジェクト | *"Create a `product` object with name, sku, price, category."* | +| フィールドの追加 | *"Add a `discount` decimal field to `order`, max 50."* | +| 選択リストの変更 | *"On `task.status`, add 'blocked' between 'open' and 'done'."* | +| リレーションシップ | *"Make `order_line` master-detail to `order`."* | +| 検証 | *"On `invoice`, the discount can't exceed the subtotal."* | +| フロー | *"When a high-priority ticket sits in 'new' for 30 minutes, notify the manager."* | +| アクション | *"Create an action `approve_invoice` that sets status to approved."* | +| 権限セット | *"Create `agent` permission set with read/create/edit on support_ticket and read on customer."* | +| 翻訳 | *"Translate the support_ticket labels and picklists to Spanish."* | + +AI にできないことなら、そう言って手作業の方法を案内します。 + +## エージェントが呼び出すツール [#the-tools-the-agents-call] + +エージェントの能力はそのツールです。環境のライブカタログは `GET /api/v1/ai/tools` で確認できます。 + +**Builder の作成ツール**は[パッケージ](/docs/build/packages)とそのメタデータを扱い、`@objectstack/spec` に照らして検証されます。 + +| 領域 | ツール | +|---|---| +| 計画 | `propose_blueprint`、`apply_blueprint` | +| パッケージ | `create_package`、`list_packages`、`get_package`、`get_active_package`、`set_active_package` | +| オブジェクト | `create_object`、`list_objects`、`describe_object` | +| フィールド | `add_field`、`modify_field`、`delete_field` | + +**Assistant のデータツール**はレコードを読み取り、それに対して動作します。 + +| ツール | 機能 | +|---|---| +| `query_records` | フィルター、フィールドの選択、ソート、ページングを指定してオブジェクトをクエリします。各レコードは `id` 付きで返されるので、回答は言及したレコードにリンクできます。 | +| `get_record` | id で 1 件のレコードを取得します。 | +| `aggregate_data` | サーバー側の `count`、`sum`、`avg`、`min`、`max`、`count_distinct`。必要に応じてグループ化とフィルターができます。 | +| `query_data` | 平易な言葉のリクエストに答えます。関連するオブジェクトを見つけ、クエリを書き、実行し、レコードを返します。 | +| `visualize_data` | グラフを描く唯一のツールです。オブジェクトをひとつのディメンションで 1 つ以上のメジャーにわたって集計し、棒、縦棒、横棒、折れ線、面、円、ドーナツ、レーダー、散布図のグラフをチャットに描きます。軸には表示値(選択肢のラベル、レコード名)がチャットの言語で表示されます。環境の分析サービスが必要です。 | +| `search_knowledge` | 登録されたナレッジソース(レコードのスナップショット、ファイル、URL)を検索します。結果はその人が見られるものにすでにフィルターされています。ナレッジサービスが設定されている場合に存在します。 | +| `action_` | AI に公開された、アプリの業務アクションのひとつを実行します(下記)。 | + +`aggregate_data` は製品内の AI の一部です。外部から [MCP](/docs/configure/mcp) で接続したエージェントは独自のツールセットを受け取り、それはそちらで説明しています。 + +## ツールとしてのアクション [#actions-as-tools] + +アクションは、作成者がそれを **AI に公開した**とき(40 文字以上の `ai.description` を伴う `ai: { exposed: true }`、UI なしで実行される種類(`script`、`flow`、`api`)で)、`action_` という名前のツールになります。公開されると、AI は呼び出し元の権限のもとで、組み込みのツールと同じようにそれを呼び出せます。公開されていないアクションがツールになることはありません。[アクション](/docs/build/interface/actions#from-an-ai-agent)を参照してください。 + +**アクションの実行前の承認。** `ai.requiresConfirmation: true` を宣言している、または別の宣言なしに破壊的に見えるアクションは、すぐには実行されません。AI はそれを**保留中のアクション**として登録し、承認されたときにだけ実行されます。 + +| エンドポイント | 目的 | +|---|---| +| `GET /api/v1/ai/pending-actions` | 自分の保留中のアクションを一覧表示する(ステータスでフィルター) | +| `GET /api/v1/ai/pending-actions/:id` | 自分の保留中のアクションの 1 件 | +| `POST /api/v1/ai/pending-actions/:id/approve` | 承認して実行する | +| `POST /api/v1/ai/pending-actions/:id/reject` | 却下する。理由は任意 | + +保留中のアクションは、それを提案した会話の持ち主に属します。読み取り、承認、却下ができるのはその人だけです。それ以外の人は、管理者であっても、存在しないかのような答えを受け取ります。 + +## API 経由でチャットする [#chatting-through-the-api] + +会話をエージェントに名前(`ask` または `build`)で送ります。 + +```bash +curl -X POST https://your-environment-host/api/v1/ai/agents/ask/chat \ + -H "Authorization: Bearer $TOKEN" \ + -H "Content-Type: application/json" \ + -d '{ + "messages": [{ "role": "user", "content": "How many open opportunities over $50k?" }], + "context": { "appName": "crm", "objectName": "opportunity" } + }' +``` + +- **`messages`**:これまでの会話。クライアントから受け付けるのは `user` と `assistant` のターンだけです。 +- **`context`**:その人がどこにいるか。`appName`、`objectName`、`viewName`、`recordId`。スキルはこれを使って何が関連するかを判断します。 +- **`conversationId`**(任意):既存の会話を続けます。 + +回答はデフォルトで Server-Sent Events として**ストリーミング**されます(Vercel AI のデータストリームプロトコル、`x-vercel-ai-ui-message-stream: v1`)。グラフはストリームの中で `data-chart` パートとして届きます。代わりに単一の JSON の回答が欲しい場合は `"stream": false` を送ります。 + +会話は `/api/v1/ai/conversations` の下に保存され、各人は自分のものだけを見られます。 + +## 制限 [#limits] + +- **データアクセスはその人自身の権限に従います。** 読み取りでもアクションでも同じです。 +- **システムパッケージは対象外です。** システムパッケージ(`sys_*`)の変更を AI に依頼すると拒否されます。 +- **大きな構築は段階を踏むほうがうまくいきます。** 「完全な HR アプリを作って」も機能しますが、それぞれがひとつの領域を仕上げる小さな会話の連続のほうがレビューしやすくなります。 +- **ObjectOS Cloud では**、AI は環境の [AI 利用枠](/docs/cloud/ai-credits-and-limits)を消費し、環境が保持できる未公開のドラフトは最大 500 件です([ストレージと上限](/docs/cloud/storage-and-limits#drafts-and-authoring-writes))。セルフマネージドの Enterprise デプロイでは、モデルは自分のもので、[AI サービス](/docs/configure/ai)で設定します。 + +## 構築時の AI の先へ [#going-beyond-build-time-ai] + +同じ AI の仕組みが、エンドユーザー向けの**ランタイムエージェント**(サポートアシスタント、営業のコパイロット、社内の Q&A ボット)も動かしています。同じ Agent → Skill → Tool のアーキテクチャで構築されます。[エージェント](/docs/build/agents)を参照してください。 + +## 次に進む [#where-to-go-next] + +- [エージェント](/docs/build/agents):データの上に載るエンドユーザー向けアシスタント +- [データモデル](/docs/build/data):AI が実際に生成しているもの +- [アクション](/docs/build/interface/actions):AI がランタイムのツールとして公開する単位 +- [AI クレジットと上限](/docs/cloud/ai-credits-and-limits):ObjectOS Cloud の AI 利用枠 +- [AI サービス](/docs/configure/ai):プロバイダーの設定(OpenAI / Anthropic / Google / DeepSeek / …) diff --git a/content/docs/build/ai-skills.ja.mdx b/content/docs/build/ai-skills.ja.mdx new file mode 100644 index 00000000..1747dcf5 --- /dev/null +++ b/content/docs/build/ai-skills.ja.mdx @@ -0,0 +1,91 @@ +--- +title: IDE スキル(Claude Code / Cursor / Copilot) +description: ObjectStack のスキルをインストールすると、Claude Code、Cursor、Copilot、Codex などのコーディングエージェントが、正しい ObjectStack メタデータ(ObjectOS が実行するオントロジー)を作成できるようになります。 +editions: [community, cloud, enterprise] +translation: + source_sha: 1c4b67992500eaa86e4fac4a8e9f8065f54259b7f639e19d1346d5d317b5fc1f + guide_rev: 1 + mode: auto +--- + +[AI Builder](./ai-builder) は ObjectOS の中にあり、テナントのデータベースと対話します。しかし、`*.object.ts` を手で編集しているとき、フローを設計しているとき、Cursor に CEL の述語を書かせるときなど、同じドメイン知識を IDE の中で使いたいこともあります。 + +ObjectStack には、コーディングアシスタントにあらゆる種類の ObjectStack メタデータ(ObjectOS が実行するオントロジー)の作成方法を教える **9 つのファーストパーティのエージェントスキル**が付属します。これらはオープンな [`skills`](https://www.npmjs.com/package/skills) エコシステム(Vercel Labs)を通じて配布され、**Claude Code、Cursor、Copilot、Codex、Gemini CLI、Windsurf、Cline、Continue、Roo、Goose、Kiro、opencode** をはじめとする約 50 のエージェントで動作します。 + +## インストール [#install] + +`@objectstack/*` パッケージを使う任意のプロジェクトで: + +```bash +npx skills add objectstack-ai/objectstack/skills +``` + +CLI は設定済みのエージェント(`.claude/`、`.cursor/`、`.github/copilot/`、`AGENTS.md` など)を検出し、スキルを適切な場所に書き込みます。いつでも再実行して最新バージョンを取得できます。 + +> `package.json` の変更もグローバルインストールも不要です。スキルはリポジトリにコミットされる普通の Markdown ファイルなので、チーム全体と CI のエージェントが同じ指示を共有します。 + +## 得られるもの [#what-you-get] + +| スキル | 読み込むのは、次の作業をしているとき | +|:------|:-----------------------------| +| `objectstack-platform` | `defineStack`、ドライバー、アダプター、プラグイン、サービス、`os` CLI、デプロイ | +| `objectstack-data` | `*.object.ts`、`*.seed.ts`、フィールド、リレーションシップ、検証、インデックス、ライフサイクルフック、RLS | +| `objectstack-query` | ObjectQL:フィルター、ソート、ページネーション、集計、結合、ウィンドウ関数、全文検索 | +| `objectstack-ui` | ビュー、アプリ、ページ、ダッシュボード、レポート、グラフ、アクション | +| `objectstack-automation` | フロー、ワークフロー、トリガー、承認、スケジュール、Webhook | +| `objectstack-ai` | エージェント、ツール、スキル、会話、モデルレジストリ、MCP | +| `objectstack-api` | REST エンドポイント、認証プロバイダー、リアルタイムチャネル、エラーエンベロープ、バッチ/バージョニングの契約 | +| `objectstack-i18n` | 翻訳バンドル、ロケールのフォールバック、カバレッジ | +| `objectstack-formula` | CEL 式:数式フィールド、検証/共有/表示の述語、条件 | + +各スキルは**スコープを認識**しています。いつ自分を読み込み、いつ兄弟スキルに任せるべきかをエージェントに伝えるので、Claude がプラットフォームのスキルでオブジェクトをモデル化しようとしたり、データのスキルで CEL 式を書こうとしたりすることはありません。 + +## 仕組み [#how-it-works] + +各スキルは[フレームワークのリポジトリ](https://github.com/objectstack-ai/objectstack/tree/main/skills)の `skills/` の下にあるフォルダーです。 + +``` +skills/objectstack-data/ +├── SKILL.md # YAML frontmatter + prose guide +├── references/ +│ └── _index.md # pointers into @objectstack/spec Zod sources +└── rules/ # optional deep-dive rules +``` + +`SKILL.md` のフロントマターは、`skills add` がスキルを適切なエージェントのサーフェスに振り分けるために読むものです。 + +```yaml +--- +name: objectstack-data +description: Design ObjectStack data schemas — objects, fields, ... +license: Apache-2.0 +compatibility: Requires @objectstack/spec Zod schemas (v4+) +metadata: + domain: data + tags: object, field, validation, relationship, hook, permission, rls +--- +``` + +すべてのスキルに共通する中核のルールは、**`@objectstack/spec` の Zod スキーマが真実である**ということです。スキルは意図を与え、エージェントは正確なフィールドの形を `node_modules/@objectstack/spec/src/**/*.zod.ts` のスキーマから読み取ります。スキルをインストールすると、でっち上げのフィールドが事実上なくなるのはこのためです。 + +## スキルと AI Builder の比較 [#skills-vs-ai-builder] + +| | [AI Builder](./ai-builder) | IDE スキル | +|:--|:--|:--| +| 実行場所 | ブラウザ | IDE / コーディングエージェント | +| 変更するもの | テナント内の稼働中のメタデータ | リポジトリ内のファイル | +| 誰の代わりに動くか | エンドユーザー / 管理者 | 開発者 | +| 承認モデル | HITL キュー(`ai:approve`) | プルリクエストのレビュー | +| 最適な用途 | 日々の拡張、ノーコードのユーザー | テンプレート、パッケージ、複雑なフロー、ライブラリのコード | + +両者は補完し合います。ほとんどのチームは、テナントのカスタマイズには AI Builder を、**公開するつもりのパッケージ**の作業には IDE スキルを使います([テンプレート](./templates)と[マーケットプレイス](./marketplace)を参照してください)。 + +## 更新 [#updating] + +スキルは `@objectstack/spec` のバージョンに従います。spec パッケージをアップグレードした後は `npx skills add objectstack-ai/objectstack/skills` を再実行し、エージェントを最新の Zod スキーマ、CEL ヘルパー、メタデータの語彙に合わせてください。 + +## 関連 [#related] + +- [AI Builder](./ai-builder):ブラウザ内の対になるもの +- [エージェント](./agents):ObjectOS の*中で*実行されるサーバー側のエージェントを宣言する +- [テンプレート](./templates):公式テンプレートはすべて、これらのスキルを読み込んで構築されています diff --git a/content/docs/build/data/formulas.ja.mdx b/content/docs/build/data/formulas.ja.mdx new file mode 100644 index 00000000..744e03f5 --- /dev/null +++ b/content/docs/build/data/formulas.ja.mdx @@ -0,0 +1,208 @@ +--- +title: 数式 +seoTitle: "数式フィールド、動的デフォルト、CEL のロジック" +description: 計算フィールド、動的デフォルト、条件付きロジック。メタデータが考える必要のあるあらゆる場所で、ひとつの CEL 式言語を使います。 +editions: [community, cloud, enterprise] +translation: + source_sha: 4c94691d64eaae42bb49bfe69035aae77414eb5038b32c992efce1b2768c0aa1 + guide_rev: 1 + mode: auto +--- + +**ひとつの式言語を、あらゆるサーフェスで。** メタデータが値を計算したり条件を評価したりする必要がある場所では、ObjectOS は [CEL](/docs/reference/cel)(Google の Common Expression Language)を使います。数式フィールド、動的デフォルト、条件付きの表示、検証の条件、フローの判断です。構文を一度覚えれば、どこでも使えます。 + +| サーフェス | そこで CEL がすること | +|---|---| +| **数式フィールド**(`type: 'formula'`) | 他のフィールドから読み取り時の値を計算する | +| **動的デフォルト**(``defaultValue: cel`...` ``) | コンパイル時ではなく挿入時に評価する | +| **フィールドの述語**(`visibleWhen`、`readonlyWhen`、`requiredWhen`) | 条件に応じてフィールドを表示 / ロック / 必須にする | +| **[検証ルール](/docs/build/data/validation-rules)**(`condition`) | 無効なレコードに印を付ける | +| **[ビュー](/docs/build/interface/views)**(`visibleOn`、`conditionalFormatting`) | 条件付きのセクションと行のスタイル | +| **[フロー](/docs/build/automation/flows)**(判断、フックの条件) | レコードの状態で分岐する | + +このページでは、ビルダーが数式を*使う*方法を扱います。演算子、標準ライブラリ、`Expression` エンベロープなどの言語全体は [CEL リファレンス](/docs/reference/cel)にあります。 + +## 数式フィールド [#formula-fields] + +数式フィールドは、CEL 式から読み取り時に値を計算します。読み取り専用で、直接書き込むことはできません。 + +```ts +import { F } from '@objectstack/spec'; +import { ObjectSchema, Field } from '@objectstack/spec/data'; + +export const Invoice = ObjectSchema.create({ + name: 'invoice', + fields: { + subtotal: Field.currency({ label: 'Subtotal' }), + tax_rate: Field.number({ label: 'Tax Rate', scale: 4 }), + + total: Field.formula({ + label: 'Total', + returnType: 'number', + expression: F`record.subtotal + record.subtotal * record.tax_rate`, + }), + }, +}); +``` + +重要なキーは 2 つです。 + +| キー | 機能 | +|---|---| +| `expression` | CEL のソース。ランタイムが評価する**唯一の**キーです | +| `returnType` | 数式が返すもの:`'number'`、`'text'`、`'boolean'`、`'date'`。ダッシュボードと書式設定が読み取ります | + +> **警告:** 数式フィールドの `type` は常に `formula` です。`Field.formula` に `type: 'currency'` や `type: 'number'` を**渡さないでください**。`type: 'formula'` を上書きしてしまい、フィールドは黙って一度も計算されなくなります。値の型は代わりに `returnType` で宣言してください。 + +### よく使うパターン [#everyday-patterns] + +```ts +// Tiered label +Field.formula({ + label: 'Discount Tier', + returnType: 'text', + expression: ` + record.amount > 1000000 ? "Platinum" : + record.amount > 500000 ? "Gold" : + record.amount > 100000 ? "Silver" : "Bronze" + `, +}) + +// Days until close +Field.formula({ + label: 'Days to Close', + returnType: 'number', + expression: 'daysBetween(record.close_date, today())', +}) + +// Full name — joinNonEmpty skips blank parts +Field.formula({ + label: 'Full Name', + returnType: 'text', + expression: F`joinNonEmpty([record.salutation, record.first_name, record.last_name], ' ')`, +}) + +// Gross margin with 2 decimal places +Field.formula({ + label: 'Gross Margin %', + returnType: 'number', + expression: 'record.revenue > 0 ? ((record.revenue - record.cost) / record.revenue) * 100 : 0', + scale: 2, +}) +``` + +> **ヒント:** CEL は `null + string` で例外を投げるので、連結するときは null になりうるオペランドを `coalesce(record.x, '')` で包んでください。あるいは `joinNonEmpty` を使えば手間が省けます。 + +### 16.0 の新機能 [#new-in-160] + +- **日付と数値の演算はビルド時のエラーです。** `record.end_date - record.start_date + 1` や `today() + 30` のような式は、実行時に常に失敗していました(黙って null に評価されていました)。現在はビルドがそれらを拒否し、期間には `daysBetween(a, b)` を、ずらすには `daysFromNow(n)` / `addDays(d, n)` / `addMonths(d, n)` を案内するエラーを出します。 +- **null ガードの三項演算子がコンパイルできます。** `cond ? value : null`(例:`record.end_date != null ? daysBetween(record.start_date, record.end_date) + 1 : null`)は、入力がそろうまで数式を空白に保つための推奨される方法です。 +- **`floor(x)` / `ceil(x)` が登録されました。** これらは −∞ / +∞ の方向に丸めます(つまり `floor(-1.2) == -2`)。整数除算のようにゼロの方向ではありません。 +- **`today()` との日付の等価比較が一致するようになりました。** 時間の値は比較の前に型変換されるので、`record.due_date == today()` も `daysBetween(today(), record.due_date) == 0` も期待どおりに動作します。 + +### レコードのタイトルとしての数式 [#formula-as-record-title] + +ADR-0079 以降、レコードのタイトルは `nameField` で指定されたフィールドです。複合的なタイトルにはテキストの数式を使います。 + +```ts +ObjectSchema.create({ + name: 'invoice', + nameField: 'display_title', + fields: { + display_title: Field.formula({ + returnType: 'text', + expression: F`"Invoice " + string(record.invoice_no) + " – " + record.customer.name`, + }), + }, +}); +``` + +## 動的デフォルト [#dynamic-defaults] + +`` cel`...` `` で包んだ `defaultValue` は**挿入時**に評価されます。あなたのノート PC ではなく、ユーザーの時刻と ID で評価されます。 + +```ts +import { cel } from '@objectstack/spec'; + +issued_date: Field.date({ + defaultValue: cel`today()`, +}), +due_date: Field.date({ + defaultValue: cel`daysFromNow(30)`, +}), +``` + +同じ手法はシードデータにも使えます。``close_date: cel`daysFromNow(45)` `` を持つシードレコードはパッケージのインストール時に解決されるので、デモデータはコンパイル時のタイムスタンプを運ぶのではなく、常に新しいものになります。 + +## 条件付きのフィールドの動作 [#conditional-field-behavior] + +述語を使うと、フィールドがレコードの他の部分に反応します。 + +```ts +import { P } from '@objectstack/spec'; + +po_number: Field.text({ + label: 'PO Number', + requiredWhen: P`record.amount > 10000`, +}), +rating: Field.select({ + label: 'Rating', + options: [ + { label: 'Hot', value: 'hot' }, + { label: 'Cold', value: 'cold' }, + ], + visibleWhen: P`record.status == 'qualified'`, +}), +notes: Field.textarea({ + readonlyWhen: P`record.status == 'approved'`, +}), +``` + +`F`(formula)、`P`(predicate)、`cel` のタグ付きテンプレートのヘルパーは交換可能です。呼び出し箇所で最も読みやすいものを選んでください。 + +## 30 秒でわかる CEL [#cel-in-30-seconds] + +| 概念 | 構文 | +|---|---| +| 現在のレコードのフィールド | `record.amount` | +| 更新前の値 | `previous.status` | +| 等価 / 論理 | `==` `!=` `&&` `\|\|` `!` | +| 条件 | `cond ? then : else` | +| 包含 | `record.region in ['us', 'eu']` | +| 空白のチェック | `isBlank(record.phone)` | +| 日付 | `today()`、`now()`、`daysBetween(a, b)`、`addDays(d, n)` | +| 文字列 | `upper`、`lower`、`trim`、`contains`、`matches` | + +演算子の完全な表と標準ライブラリ:[CEL リファレンス](/docs/reference/cel)。 + +> **警告:** 述語は素の CEL です。フィールドの参照を決して波括弧で包まないでください。`{record.rating} >= 4` は**マップリテラル**で、解析エラーになります。`record.rating >= 4` と書いてください。波括弧が使われるのは `{{ … }}` のテキストテンプレートだけです。不正な式はビルドに失敗し、実行時には例外を投げます。黙って `false` に評価されることはありません。 + +> **ヒント:** `has(record.x)` は、キーが存在すれば値が `null` でも真になります。「空白でない」ことをチェックするには、`isBlank(...)` か `record.x != null` を使ってください。 + +## ベストプラクティス [#best-practices] + +| すること | しないこと | +|---|---| +| 数式をシンプルで読みやすく保つ | 循環参照を作る | +| エッジケース(null、ゼロ、空)をテストする | 三項演算子を 5 段も入れ子にする | +| `coalesce` / `isBlank` で null を扱う | 頻繁に変わるデータに数式を使う | +| すべての数式で `returnType` を宣言する | 検証ルールが担うべきロジックを作り直す | + +## チャットで構築する [#build-by-chat] + +数式を手で書くことはめったにありません。[AI Builder](/docs/build/ai-builder) にこう伝えます。 + +> *「opportunity に Days to Close の数式を追加して。close_date と今日の間の日数。」* + +AI Builder は CEL を出力し、`returnType` を推論して付け、式は出荷前に検証されます。無効な数式は、位置付きのエラーでビルドに失敗します。 + +## 次に進む [#where-to-go-next] + +| ページ | 理由 | +|---|---| +| [CEL リファレンス](/docs/reference/cel) | 言語全体:演算子、標準ライブラリ、式のエンベロープ | +| [データモデル](/docs/build/data) | 数式フィールドが置かれる場所 | +| [検証ルール](/docs/build/data/validation-rules) | 不正な書き込みをブロックする CEL の条件 | +| [ビュー](/docs/build/interface/views) | `visibleOn` と `conditionalFormatting` の CEL | +| [フロー](/docs/build/automation/flows) | 判断とフックの条件の CEL | +| [フィールドの種類](/docs/reference/field-types) | `formula`、`summary`、`autonumber` など | diff --git a/content/docs/build/data/index.ja.mdx b/content/docs/build/data/index.ja.mdx new file mode 100644 index 00000000..6db56f35 --- /dev/null +++ b/content/docs/build/data/index.ja.mdx @@ -0,0 +1,310 @@ +--- +title: データモデル +seoTitle: "データモデル:オブジェクト、フィールド、リレーションシップ" +description: オブジェクト、フィールド、リレーションシップ、検証、インデックス。AI に説明するか、TypeScript で書きます。 +editions: [community, cloud, enterprise] +translation: + source_sha: dfc4b470748f9d65a343db5a45ca7627a0b01485644546deff2adcd36ffb7430 + guide_rev: 1 + mode: auto +--- + +データモデルは、アプリの唯一の信頼できる情報源です。オブジェクトが存在すれば、ObjectOS は REST API、生成されたビュー、RBAC のチェックポイント、監査ログのエントリ、AI ツールとしての公開を無償で提供します。 + +**ほとんどの顧客はスキーマを手で書くことはありません。** [AI Builder](/docs/build/ai-builder) で必要なものを説明すると、プラットフォームがオブジェクト、フィールド、インデックス、翻訳を作成します。このページでは、その土台となる形を説明します。AI が何を生成しているかを理解し、必要なときに直接編集できるようにするためです。 + +## 作成の道 [#authoring-paths] + +| 道 | 見た目 | +|---|---| +| **AI Builder**(主要) | *"Create a `support_ticket` object with subject, description, priority, status, assignee."* | +| **クリックで構築** | **Studio → Objects → New Object** → フォーム | +| **TypeScript(`*.object.ts`)** | 下に示す TS。通常はフォークした[テンプレート](/docs/build/templates)の中 | + +3 つとも同じスキーマを生成します。スキーマが正規のものであり、それ以外はすべて導出されたものです。 + +## オブジェクトの構造 [#anatomy-of-an-object] + +```ts +// src/objects/task.ts +import { ObjectSchema, Field } from '@objectstack/spec/data'; + +export const Task = ObjectSchema.create({ + name: 'todo_task', + label: 'Task', + pluralLabel: 'Tasks', + icon: 'check-square', + description: 'A single unit of work.', + + fields: { + subject: Field.text({ label: 'Subject', required: true, maxLength: 200 }), + description: Field.markdown({ label: 'Description' }), + status: Field.select({ + label: 'Status', + options: [ + { label: 'To Do', value: 'todo', default: true }, + { label: 'In Progress', value: 'in_progress' }, + { label: 'Done', value: 'done' }, + ], + }), + due: Field.date({ label: 'Due' }), + assignee: Field.lookup('sys_user', { label: 'Assignee' }), + }, + + enable: { + trackHistory: true, // record field changes in audit log + apiEnabled: true, // expose REST endpoints (default true) + feeds: true, // chatter / comments / @mentions + }, +}); +``` + +スタックに登録します。 + +```ts +// objectstack.config.ts +import { defineStack } from '@objectstack/spec'; +import * as objects from './src/objects'; + +export default defineStack({ + manifest: { id: 'my.app', namespace: 'todo', version: '0.1.0', type: 'app', name: 'My App' }, + objects: Object.values(objects), +}); +``` + +すべてのオブジェクト名は、スタックの `namespace` とアンダースコアで始まります。`todo` 名前空間では `todo_task` です。必要なのはそれだけです。`os dev` が再コンパイルし、`/api/v1/data/todo_task`、生成された Task ビュー、その権限の行がすべて現れます。 + +## フィールドの種類 [#field-types] + +ObjectStack には約 25 種類のフィールドが付属します。最もよく使われるもの: + +### スカラー [#scalars] + +| 種類 | 保存するもの | ヘルパー | +|---|---|---| +| `text` | 短い文字列 | `Field.text({ maxLength, required })` | +| `textarea` | 長い文字列 | `Field.textarea(...)` | +| `markdown` | Markdown 付きのリッチテキスト | `Field.markdown(...)` | +| `number` | 数値。`scale` で小数点以下の桁数を設定 | `Field.number({ min, max, scale })` | +| `currency` | 金額 | `Field.currency(...)` | +| `boolean` | 真/偽 | `Field.boolean({ defaultValue })` | +| `date` | 暦日 | `Field.date(...)` | +| `datetime` | タイムスタンプ | `Field.datetime(...)` | +| `email` | 検証されたメールアドレス | `Field.email(...)` | +| `url` | 検証された URL | `Field.url(...)` | +| `phone` | 検証された電話番号 | `Field.phone(...)` | +| `json` | 任意の JSON | `Field.json(...)` | + +### 選択肢 [#choices] + +| 種類 | 用途 | +|---|---| +| `select` | 単一の選択(列挙) | +| `multiselect` | 複数の選択 | + +### リレーションシップ [#relationships] + +| 種類 | カーディナリティ | ヘルパー | +|---|---|---| +| `lookup` | 1 対多(外部キー) | `Field.lookup('sys_user', { label })` | +| `master_detail` | カスケード削除付きの 1 対多 | `Field.masterDetail('order', { label })` | + +### ファイルとメディア [#files--media] + +| 種類 | 保存するもの | +|---|---| +| `file` | ストレージサービス経由のファイル 1 つ | +| `image` | プレビュー付きの画像ファイル | + +### 計算 / 導出 [#computed--derived] + +| 種類 | 動作 | +|---|---| +| `formula` | CEL 式から読み取り時に計算 | +| `summary` | 関連レコードの集計(sum/count/avg) | +| `autonumber` | 連番(`INV-{000001}`) | +| `created`、`lastModified` | システムが管理するタイムスタンプ | +| `createdBy`、`lastModifiedBy` | システムが管理するユーザー参照 | + +## 必須 / 一意 / デフォルト [#required--unique--default] + +すべてのスカラーフィールドに共通する修飾子: + +```ts +Field.text({ + label: 'Code', + required: true, + unique: true, // unique constraint enforced at DB level + defaultValue: '', + inlineHelpText: 'Internal short code', +}) +``` + +## 検証 [#validation] + +インライン: + +```ts +Field.number({ label: 'Quantity', min: 1, max: 9999 }) +Field.text({ label: 'SKU', minLength: 8, maxLength: 8 }) +``` + +オブジェクトレベルのルール:フィールドをまたぐルールと、パターンのための `format` ルールです。ルールの `condition` は無効なレコードを記述します。それが真のとき、書き込みは拒否されます。 + +```ts +ObjectSchema.create({ + name: 'order', + fields: { + sku: Field.text({ label: 'SKU' }), + discount: Field.currency({ label: 'Discount' }), + total: Field.currency({ label: 'Total' }), + }, + validations: [ + { + type: 'cross_field', + name: 'discount_lt_total', + message: 'Discount cannot exceed total', + fields: ['discount', 'total'], + condition: 'record.discount > record.total', + }, + { + type: 'format', + name: 'sku_format', + message: 'SKU looks like ABC-1234', + field: 'sku', + regex: '^[A-Z]{3}-[0-9]{4}$', + }, + ], +}); +``` + +検証は REST、UI、ObjectQL のすべての書き込みで実行されるので、「裏口」はありません。 + +## インデックスとパフォーマンス [#indexes--performance] + +```ts +ObjectSchema.create({ + name: 'order', + fields: { /* ... */ }, + indexes: [ + { fields: ['status', 'created_at'] }, + { fields: ['account', 'created_at'], unique: false }, + ], +}); +``` + +ドライバーはスキーマの同期時に実際の DB インデックスを作成します。 + +## フィールドグループ [#field-groups] + +長いフォームでは、フィールドをグループ化します。 + +```ts +ObjectSchema.create({ + name: 'task', + fieldGroups: [ + { key: 'core', label: 'Task', icon: 'check-square' }, + { key: 'planning', label: 'Planning', icon: 'calendar' }, + { key: 'meta', label: 'Metadata', icon: 'info', defaultExpanded: false }, + ], + fields: { + subject: Field.text({ label: 'Subject', group: 'core' }), + due: Field.date({ label: 'Due', group: 'planning' }), + }, +}); +``` + +## 機能フラグと所有権 [#capability-flags--ownership] + +```ts +ObjectSchema.create({ + name: 'task', + fields: { subject: Field.text({ label: 'Subject' }) }, + ownership: 'user', // 'user' (default) | 'business_unit' | 'org' | 'none' + sharingModel: 'private', // OWD — custom objects default to private (v13) + enable: { + apiEnabled: true, // generated REST endpoints (default true) + searchable: true, // index records for global search (default true) + trackHistory: true, // History tab + field-level diffs (opt-in, default false) + feeds: true, // sys_comment / @mentions (default true) + activities: true, // mirror CRUD to sys_activity timeline (default true) + files: false, // Attachments panel (opt-in, default false) + clone: true, // record deep cloning (default true) + }, +}); +``` + +`enable` は**閉じた語彙**です。このブロックは厳格なので、認識されないフラグ(`feedEnabled` のようなタイプミスや、かつて存在したキー)は、黙って捨てられる設定ではなく、そのキーを示す解析エラーになります。上の 7 つのフラグがそのすべてで、さらにキーがもう 1 つあります。 + +```ts +// Keys of an object; its name and fields are omitted. +enable: { + apiMethods: ['get', 'list', 'create', 'update'], // no delete over the API +} +``` + +`apiMethods` は、オブジェクトが公開する API の操作をホワイトリストで指定します。作成できる語彙はちょうど 6 つのプリミティブ、`get`、`list`、`create`、`update`、`delete`、`bulk` です。制限のないアクセスにはキーを省略します。`[]` はすべて拒否を意味します。8 つのレガシーな値(`upsert`、`import`、`export`、`aggregate`、`search`、`history`、`restore`、`purge`)は、宣言するものではなく*導出される*実効的な操作です。保存されているものはまだ解析されますが、置き換え先を示す警告とともに取り除かれます(`upsert` → `create` + `update`、`export`/`aggregate`/`search` → `list`、`history` → `get`。`restore` と `purge` は何からも導出されず、単に削除されます)。ひとつの落とし穴に注意してください。レガシーな値*だけ*のホワイトリストは `[]` に取り除かれ、オブジェクトの API を広げるのではなく閉じてしまいます。 + +> **ソフトデリートはありません。`enable.trash` は削除されました。** 以前のドキュメントは、廃止されたオブジェクトレベルの `softDelete` プロパティの代わりとして `enable: { trash: true }` を案内していました。これは、はっきり述べておく価値のある形で誤りでした。`trash` にはランタイムの利用者が一度もありませんでした。削除は常にハードデリートだったので、ごみ箱を約束するデフォルト true のフラグは偽りのアフォーダンスでした。作成者は、実行されたことのないソフトデリートを無効にしているつもりで `trash: false` を書いていました。このキー(と隣の `enable.mru`)は現在、無視されるのではなく、ガイダンス付きで**解析時に拒否**されます。ソースから削除するか、`os migrate meta --from 16` を実行して書き換えてください。 +> +> 復元可能性のためには、フィールドごとの `trackHistory`(何が変わったかの監査証跡)か [`lifecycle`](#data-lifecycle-retention) ポリシーを使ってください。本物のごみ箱は現時点で提供されている機能ではありません。 + +> **オブジェクトのサーフェスから削除されたものは他にもあります:** `softDelete`、`versioning`、`search`(トップレベルの `searchableFields` を使ってください)、`recordName`(autonumber フィールドを `nameField` として使ってください)、`keyPrefix`、`tags`、`active`、`abstract`。これらのいずれかを渡すと、`ObjectSchema.create` は置き換え先を示す位置付きのエラーを投げます。 + +ObjectStack 14 以降、`enable.*` のフラグは助言ではなく**強制**されます。`feeds: false` はコメントの作成を 403 `FEEDS_DISABLED` で拒否し、`sys_attachment` の行を作成するには `files` をオプトインする必要があり(そうでなければ 403 `FILES_DISABLED`)、`activities` / `trackHistory` はタイムラインと History タブを制御します。コンプライアンスのための `sys_audit_log` の行は、フラグにかかわらず常に書き込まれます。 + +## データのライフサイクル(保持) [#data-lifecycle-retention] + +大量のデータを持つオブジェクトは `lifecycle` ブロックを宣言でき、プラットフォームがその増加を抑えます(ObjectStack 14.4、ADR-0057)。 + +```ts +ObjectSchema.create({ + name: 'my_event', + fields: { payload: Field.json({ label: 'Payload' }) }, + lifecycle: { + class: 'event', // 'record' | 'audit' | 'telemetry' | 'transient' | 'event' + retention: { maxAge: '14d' }, // reaper deletes rows past the window + // time-sharded table: 2 shards of 1 week + storage: { strategy: 'rotation', shards: 2, unit: 'week' }, + }, +}); +``` + +組み込みの LifecycleService(`OS_LIFECYCLE_DISABLED=1` で無効化)は、期限切れの行を刈り取り、時間でシャーディングされたテーブルをローテーションし、監査クラスのオブジェクトをアーカイブします。`sys_activity`(14 日)や `sys_audit_log`(90 日間ホット、その後アーカイブ)のようなプラットフォームのオブジェクトにはライフサイクルの宣言が付属し、`lifecycle.retention_overrides` 設定で環境ごとに調整できます。 + +## システムオブジェクト(すべてのプロジェクトに無償で付属) [#system-objects-free-with-every-project] + +これらを宣言する必要はありません。常に存在します。 + +| オブジェクト | 内容 | +|---|---| +| `sys_user` | ユーザーアカウント | +| `sys_org` | 組織 / テナント | +| `sys_member` | 組織のメンバーシップ | +| `sys_position`、`sys_permission_set` | RBAC のプリミティブ | +| `sys_audit_log` | 監査証跡(監査機能が読み込まれている場合) | +| `sys_file`、`sys_attachment` | ファイルのメタデータ(ストレージが読み込まれている場合) | +| `sys_comment`、`sys_activity` | フィード / チャター(フィードが読み込まれている場合) | +| `sys_session`、`sys_api_key` | 認証の成果物 | +| `sys_webhook`、`sys_webhook_delivery` | Webhook の購読(有効な場合) | + +`lookup` フィールドでは名前で参照します。例:`Field.lookup('sys_user', { label: 'Owner' })`。 + +## ポリモーフィックなプラットフォーム機能 [#polymorphic-platform-features] + +`feeds: true` と `trackHistory: true` を有効にすると、オブジェクトは自動的に次のものに参加します。 + +- `sys_comment`(thread_id = `:`) +- `sys_attachment`(parent_object = ``、parent_id = ``) +- `sys_activity`(タイムライン) +- `sys_audit_log`(フィールドレベルの差分) + +これらをオブジェクトごとに配線する必要はありません。プラットフォーム上でポリモーフィックに動作します。 + +## 次に進む [#where-to-go-next] + +- [権限](/docs/configure/permissions):オブジェクトへのアクセスを制御する +- [フロー / 自動化](/docs/build/automation/flows):レコードの変更に反応する +- [API アクセス](/docs/configure/api-access):生成された REST を呼び出す +- [`os explain`](/docs/reference/cli):レンダリングされたスキーマを出力する +- [`@objectstack/spec` のソース](https://github.com/objectstack-ai/objectstack/tree/main/packages/spec):スキーマが契約です。ここにあるものはすべてそこから導出されています diff --git a/content/docs/build/data/relationships.ja.mdx b/content/docs/build/data/relationships.ja.mdx new file mode 100644 index 00000000..1b1d8256 --- /dev/null +++ b/content/docs/build/data/relationships.ja.mdx @@ -0,0 +1,180 @@ +--- +title: リレーションシップ +seoTitle: "リレーションシップ:参照、主従、ロールアップ" +description: 参照と主従でオブジェクトをつなぎます。カスケードのルール、フィルター付きのピッカー、階層、中間オブジェクト、ロールアップ。 +editions: [community, cloud, enterprise] +translation: + source_sha: 05bc53d30e7cc26ead447169d0a7c3ba0beb76be6a457d9843593253d11f0469 + guide_rev: 1 + mode: auto +--- + +**リレーションシップは単なるフィールドです。** `lookup` または `masterDetail` フィールドを別のオブジェクトに向けると、ObjectOS がその上のすべてを配線します。外部キーの整合性、レコードピッカー、親ページの関連リスト、クエリの `expand` です。 + +| 種類 | カーディナリティ | 削除のデフォルト | 用途 | +|---|---|---|---| +| `lookup` | 多対 1 | `set_null` | 緩やかな参照(チケット → 担当者) | +| `master_detail` | 多対 1、所有される | `cascade` | 親子の所有関係(注文 → 明細行) | +| `tree` | 自己参照 | — | 階層(カテゴリ、組織図) | +| `user` | 多対 1 | `set_null` | 人のピッカー。`sys_user` に特化した参照 | +| `summary` | 親へのロールアップ | — | 子の集計(sum、count、avg) | + +## 参照(多対 1) [#lookup-many-to-one] + +主力です。別のオブジェクトのレコードを参照します。 + +```ts +import { ObjectSchema, Field } from '@objectstack/spec/data'; + +export const Contact = ObjectSchema.create({ + name: 'contact', + fields: { + account: Field.lookup('account', { + label: 'Account', + required: true, + }), + }, +}); +``` + +プラットフォームは参照されたレコードが存在することを検証します。外部キーの整合性はすべての書き込みで強制されます。 + +> **ヒント:** フィールドには、指す先のオブジェクトの名前を付けてください。`account_id` ではなく `account` です。関連リスト、`expand`、AI Builder のすべてが、そのほうが読みやすくなります。 + +### 親が削除されたときに起こること [#what-happens-when-the-parent-is-deleted] + +カスケードの動作は `deleteBehavior` で制御します。 + +| 値 | 親の削除時 | +|---|---| +| `set_null` | 子の参照がクリアされます(参照のデフォルト) | +| `cascade` | 子のレコードも削除されます | +| `restrict` | 子が存在する間は削除がブロックされます | + +## フィルター付きの参照 [#filtered-lookups] + +ピッカーが提示するレコードを制限します。静的な条件には `lookupFilters` を、同じレコードの別のフィールドで候補を絞り込むには `dependsOn` を使います。 + +```ts +contact: Field.lookup('contact', { + label: 'Contact', + dependsOn: ['account'], // only contacts of the chosen account + lookupFilters: [ + { field: 'is_active', operator: 'eq', value: true }, + ], +}) +``` + +> **警告:** レガシーな `referenceFilters: string[]` プロパティ(例:`['is_active = true']`)は **16.0 で削除されました**。解析時に取り除かれ、削除される前でさえレコードピッカーの UI はそれを読んでいなかったので、何もフィルターしていませんでした。上に示した構造化された `lookupFilters` + `dependsOn` が、サポートされる唯一の形です。 + +## 主従(所有される子) [#master-detail-owned-children] + +`masterDetail` は所有のセマンティクスを持つ参照です。子は親に属し、デフォルトでは親とともにカスケード削除され、親のフォームで明細行としてインライン編集できます。 + +```ts +export const OrderLine = ObjectSchema.create({ + name: 'order_line', + fields: { + order: Field.masterDetail('order', { label: 'Order' }), + product: Field.lookup('product', { label: 'Product' }), + quantity: Field.number({ label: 'Quantity', min: 1 }), + }, +}); +``` + +| 観点 | 動作 | +|---|---| +| 削除 | `deleteBehavior: 'restrict'` でない限り、実行時に子へカスケードします | +| 所有 | 子のレコードは親のレコードが所有します | +| 編集 | 親のフォームでの明細行のインライン編集(任意) | +| ロールアップ | `summary` フィールドは主(親)の側でのみ有効です | + +参照が任意または共有されるものなら `lookup` を、子のレコードが親なしでは意味をなさないなら `masterDetail` を選んでください。 + +## 自己参照の参照とツリー [#self-referencing-lookups--trees] + +参照は自分自身のオブジェクトを指して階層を構築できます。 + +```ts +parent_account: Field.lookup('account', { + label: 'Parent Account', + description: 'Parent company in hierarchy', +}) +``` + +専用の階層(カテゴリ、組織図)には `tree` フィールドの種類を使います。`lookup` と同じように保存され展開される自己参照の参照です。エンジンは書き込み時に循環のチェックを**行わない**ため、自分自身に戻ってくる連鎖が自動的に拒否されることはありません。 + +> **ヒント:** `tree` / 自己参照のフィールドを[ツリーリストビュー](/docs/build/interface/views)と組み合わせると、階層を入れ子の行として表示できます。 + +## 関連リスト [#related-lists] + +これは無償で得られます。参照が親を指していれば、子のレコードは親の詳細ページに関連リストとして自動的に表示されます。 + +- Contact が `account: Field.lookup('account')` を持つ +- → Account の詳細ページに **Contacts** の関連リストが表示される + +追加の設定は不要です。 + +## 多対多:中間オブジェクト [#many-to-many-junction-objects] + +ObjectOS には直接の多対多フィールドはありません。**中間オブジェクト**としてモデル化します。両側それぞれへのリレーションシップフィールドを 2 つ持つオブジェクトです。 + +```ts +// Student ↔ Course, joined by Enrollment +export const Enrollment = ObjectSchema.create({ + name: 'enrollment', + fields: { + student: Field.masterDetail('student', { label: 'Student' }), + course: Field.masterDetail('course', { label: 'Course' }), + grade: Field.select({ + label: 'Grade', + options: [ + { label: 'Pass', value: 'pass' }, + { label: 'Fail', value: 'fail' }, + ], + }), + }, + indexes: [ + { fields: ['student', 'course'], unique: true }, // one enrollment per pair + ], +}); +``` + +どちらの側も中間レコードを関連リストとして見られます。そして中間オブジェクト自体が、組み合わせの属性(成績、役割、参加日)の自然な置き場所になります。 + +## ロールアップ(`summary` フィールド) [#roll-ups-summary-fields] + +`summary` フィールドで子のレコードを親に集計します。主オブジェクト、つまり主従の親の側でのみ有効です。 + +```ts +// Fields of an object — this one belongs on the Order object. +total_lines: { + type: 'summary', + label: 'Line Count', + summaryOperations: { + object: 'order_line', // child object to aggregate + field: 'quantity', // field to aggregate + function: 'sum', // count | sum | min | max | avg + filter: { status: 'active' }, // new in 16.0: aggregate only matching children + }, +} +``` + +サマリーフィールドは読み取り専用で、子から計算されます。直接書き込むことはありません。 + +**16.0 の新機能:** 任意の `filter` はクエリ形式の `where` 述語です。それに一致する子の行だけが集計され(例:`status == 'active'` の子だけを数える)、子が述語の内外に移ると、ロールアップは再集計されます。また、複数のサマリーが*同じ*子オブジェクトを別々の合計にロールアップできるようになります。 + +## リレーションシップをまたいでクエリする [#querying-across-relationships] + +`expand` を使うと、関連レコードを 1 回の呼び出しで読み込めます。クエリ API は参照フィールドをたどり、参照先のレコードをインライン化するので、クライアントから N+1 のリクエストを発生させずに済みます。 + +## 次に進む [#where-to-go-next] + +| ページ | 理由 | +|---|---| +| [データモデル](/docs/build/data) | オブジェクト、フィールド、これらのリレーションシップが存在するスキーマ | +| [数式](/docs/build/data/formulas) | CEL でレコード全体の値を計算する | +| [検証ルール](/docs/build/data/validation-rules) | フィールドをまたぐルールと一意制約 | +| [ビュー](/docs/build/interface/views) | ツリービュー、カンバン、関連リストのサーフェス | +| [フィールドの種類](/docs/reference/field-types) | `lookup`、`master_detail`、`tree`、`summary` の完全なリファレンス | +| [AI Builder](/docs/build/ai-builder) | チャットでリレーションシップを説明し、プラットフォームに配線させる | diff --git a/content/docs/build/data/validation-rules.ja.mdx b/content/docs/build/data/validation-rules.ja.mdx new file mode 100644 index 00000000..2c0defeb --- /dev/null +++ b/content/docs/build/data/validation-rules.ja.mdx @@ -0,0 +1,237 @@ +--- +title: 検証ルール +seoTitle: "検証ルール:必須、一意、CEL のルール" +description: 必須フィールド、一意制約、そして CEL によるルールで、プラットフォームのレベルで不正なデータを止めます。エラーメッセージは自分で制御できます。 +editions: [community, cloud, enterprise] +translation: + source_sha: 1f582742d9d1e87e240b1d6d773f281c8036338f52226387f84a0549f02bc5c1 + guide_rev: 1 + mode: auto +--- + +**検証はすべての書き込み経路で実行されます。** REST、フォーム、ObjectQL のどこでも同じルールが発動するので、不正なデータのための裏口はありません。16.0 以降は複数行の更新も含まれます。一括更新は、一致した行ごとにルールを 1 回評価します。検証ルールは、単一のレコードに対する決定的で同期的な副作用のない述語です。入ってくる書き込み(更新時には以前のレコードも)から I/O なしで判定できます。 + +検証は層になっています。ルールを表現できる最も低い層を使ってください。 + +| 層 | 表現するもの | 例 | +|---|---|---| +| **フィールドの修飾子** | 存在、一意性 | `required: true`、`unique: true` | +| **フィールドの制約** | フィールドごとの形 | `min`、`max`、`maxLength`、`format` | +| **条件付きの修飾子** | 文脈に依存する存在 | ``requiredWhen: P`record.amount > 10000` `` | +| **オブジェクトの検証ルール** | フィールドをまたぐビジネスロジック | 「値引きは合計を超えられない」 | +| **一意インデックス** | 複合 / スコープ付きの一意性 | `{ fields: ['code', 'organization'], unique: true }` | +| **ライフサイクルフック** | 任意の検証コード、削除のガード | `beforeInsert` / `beforeUpdate` / `beforeDelete` | + +## フィールドレベル:必須、一意、制約 [#field-level-required-unique-constraints] + +汎用の修飾子は、すべてのフィールドの種類で動作します。 + +```ts +// Fields of an object; the object around them is omitted. +import { ObjectSchema, Field } from '@objectstack/spec/data'; + +fields: { + email: Field.email({ label: 'Contact Email', required: true, unique: true }), + quantity: Field.number({ label: 'Quantity', min: 1, max: 9999 }), + code: Field.text({ label: 'Code', minLength: 3, maxLength: 20 }), +} +``` + +| 修飾子 | 動作 | +|---|---| +| `required: true` | 実行時に `null` / `undefined` を拒否します | +| `unique: true` | データベースレベルの一意制約。競合しやすいアプリケーション側のチェックではありません | +| `min` / `max` | 数値の範囲(number、currency、percent、rating、slider など) | +| `minLength` / `maxLength` | テキストの種類の文字数の範囲 | +| `format` | 組み込みの形のチェック。`email`、`url`、`phone` のフィールドの種類はデフォルトでそれを持ちます | +| `readonly: true` | 挿入時と更新時にサーバーで強制されます。システム以外によるそのフィールドへの書き込みは捨てられ、レスポンスの `droppedFields` で報告されます。書き込みが `strictReadonlyWrites` オプションを渡した場合は完全に拒否されます。作成時に読み取り専用フィールドへ初期値を入れるには、システムとして書き込みます。シード、システムフック、または `runAs: 'system'` のフローです | + +フィールドの種類も無償で自分自身を検証します。`email` は `local@domain` の形をチェックし、`url` はプロトコルを必要とし、`select` の値は選択肢に一致しなければならず、`lookup` は参照先のレコードが存在することを強制し、`json` は解析できなければなりません。すべてのデフォルトは[フィールドの種類のリファレンス](/docs/reference/field-types)を参照してください。 + +### 条件付きの必須 / 読み取り専用 / 表示 [#conditional-required--read-only--visible] + +存在の要否は、CEL の述語でレコードの他の部分に依存させられます。 + +```ts +import { P } from '@objectstack/spec'; + +po_number: Field.text({ + label: 'PO Number', + requiredWhen: P`record.amount > 10000`, +}), +``` + +`visibleWhen`、`readonlyWhen`、`requiredWhen` はすべて CEL の述語を取ります。[数式](/docs/build/data/formulas)を参照してください。これらはレコード自身のフィールドだけを読みます。評価できない `requiredWhen` や `readonlyWhen`(綴りを間違えたフィールド、`null` に対する大小比較、`record.account.tier` のような参照をたどる読み取り)は、書き込みを通すのではなく `VALIDATION_FAILED` で拒否します。関連レコードを読む必要があるチェックは[検証ルール](#reading-a-related-record)に置いてください。 + +## オブジェクトレベルの検証ルール [#object-level-validation-rules] + +フィールドをまたぐビジネスロジックは、オブジェクトの `validations` 配列に置きます。 + +```ts +export const Order = ObjectSchema.create({ + name: 'order', + fields: { + amount: Field.currency({ label: 'Amount', required: true }), + status: Field.select({ + label: 'Status', + options: [ + { label: 'Draft', value: 'draft' }, + { label: 'Submitted', value: 'submitted' }, + ], + }), + }, + + validations: [ + { + name: 'amount_positive', + type: 'script', + severity: 'error', + message: 'Amount must be greater than zero', + // CEL predicate — TRUE means the record is INVALID. + condition: 'record.amount <= 0', + events: ['insert', 'update'], + }, + ], +}); +``` + +> **警告:** `script` ルールの `condition` は**失敗の**述語です。それが TRUE に評価されると検証は失敗します。*不正な*状態のテストを書いてください。`record.amount <= 0` は正でない金額を拒否します。 + +### 共通のプロパティ [#common-properties] + +すべてのルールの種類は、次の基本の形を共有します。 + +| プロパティ | 必須 | 説明 | +|---|---|---| +| `name` | はい | 一意のルール名(`snake_case`) | +| `message` | はい | ユーザー向けのエラーメッセージ | +| `type` | はい | `script`、`state_machine`、`format`、`cross_field`、`json_schema`、`conditional` | +| `severity` | いいえ | `error`(保存をブロック、デフォルト)、`warning`(保存を許可)、`info` | +| `events` | いいえ | `insert`、`update`。デフォルトは `['insert', 'update']`。`delete` イベントは 16.0 で削除されました。評価器は削除時に一度も実行されず(削除はレコードのペイロードを持たない)、黙って何もしていなかったためです。削除は `beforeDelete` フックでガードしてください | +| `priority` | いいえ | 0〜9999、小さいほど先に実行(デフォルト 100) | +| `active` | いいえ | 削除せずに切り替える(デフォルト `true`) | + +### 6 種類のルール [#the-six-rule-types] + +| 種類 | チェックするもの | 主な設定 | +|---|---|---| +| `script` | 任意の CEL 述語 | `condition`(TRUE = 無効) | +| `state_machine` | 許可されたステータスの遷移 | `field`、`transitions` のマップ、任意の `initialStates` | +| `format` | 1 つのフィールドを正規表現または組み込みの形式に照らす | `field`、`regex` または `format: 'email' \| 'url' \| 'phone' \| 'json'` | +| `cross_field` | フィールド間の関係 | `fields`、`condition` | +| `json_schema` | JSON フィールドを JSON Schema に照らす | `field`、`schema` | +| `conditional` | 述語が成り立つときだけ入れ子のルールを適用する | `when`、`then`、任意の `otherwise` | + +いつも使うことになる 2 つのルール: + +```ts +// Two validation rules, entries of the object's `validations` array. + +// State machine — enforce the status flow +{ + name: 'order_status_transitions', + type: 'state_machine', + severity: 'error', + message: 'Invalid status transition', + field: 'status', + transitions: { + draft: ['submitted', 'cancelled'], + submitted: ['approved', 'rejected', 'cancelled'], + approved: ['completed'], + rejected: ['draft'], + cancelled: [], + completed: [], + }, + initialStates: ['draft'], // new in 16.0: states a record may be CREATED in + events: ['insert', 'update'], // include 'insert' so initialStates is checked +} + +// Cross-field — dates in order +{ + name: 'date_range_valid', + type: 'cross_field', + severity: 'error', + message: 'End date must be after start date', + fields: ['start_date', 'end_date'], + condition: 'record.end_date <= record.start_date', + events: ['insert', 'update'], +} +``` + +**16.0 の新機能:** `state_machine` ルールは `initialStates`、つまりレコードを*作成*できる状態を宣言できます。状態フィールドが一覧外の値を持つ挿入は拒否されます(`invalid_initial_state`)。`transitions` は更新だけを制御し、`select` フィールドは宣言された任意の選択肢を初期値として許すので、`initialStates` がないとレコードはフローの途中で生まれることがあります(例:最初から `approved` で作成される)。省略するとレガシーな動作(挿入時に初期状態をチェックしない)のままです。チェックを実行するには、ルールの `events` に `insert` が含まれていなければなりません。 + +更新時の条件では、`previous` が変更前のスナップショットを保持します。`record.stage != previous.stage` で変更を検出できます。 + +### 関連レコードを読む [#reading-a-related-record] + +ObjectStack 17.5 以降、`script` または `cross_field` ルールは、`lookup`、`master_detail`、`user`、`tree` のフィールドを通じて **1 ホップ**だけ読めます。 + +```ts +// One validation rule, an entry of the object's `validations` +{ + name: 'partner_deal_cap', + type: 'script', + severity: 'error', + message: 'Partner deals over 10,000 need a direct contract', + condition: "record.account.type == 'partner' && record.amount > 10000", + events: ['insert', 'update'], +} +``` + +エンジンは、条件が名前を挙げた関連フィールドだけを、参照フィールドごとに 1 回のまとめた読み取りで読み込み、たどるルールがなければ何も読みません。2 ホップ目(`record.account.owner.email`)は拒否され、たどりながら参照の ID を比較することも拒否されます。フィールドレベルの述語と行レベルセキュリティは、レコード自身のフィールドにとどまります。 + +ルールが見るのは `record` と `previous` だけで、それ以外は見えません。誰が保存しているかを尋ねることはできません。`current_user.can(...)` に答えるのは別の場所で([CEL → 権限チェック](/docs/reference/cel#permission-checks)を参照)、検証ルールの中では評価できないため、そのルールは実行されるすべての書き込みを拒否します。 + +## 一意性:ルールではなくインデックスを使う [#uniqueness-use-an-index-not-a-rule] + +`uniqueness` という検証の種類は**ありません**。意図的です。SELECT してから INSERT するチェックは本質的に競合します(TOCTOU)。データベースの一意制約はそうではありません。一意性はデータ層で強制してください。 + +```ts +// Keys of an object; its name and its other fields are omitted. +fields: { + // Field-level + email: Field.email({ label: 'Contact Email', unique: true }), +}, + +// Composite / scoped via indexes +indexes: [ + { fields: ['code', 'organization'], unique: true }, + // add `partial` for a scoped/conditional constraint +], +``` + +同じ理屈で、非同期/リモートの検証(クライアントのフォームの関心事であり、書き込み経路での SSRF/レイテンシーの危険)とカスタムハンドラーも除外されています。任意の検証コードは `beforeInsert` / `beforeUpdate` のライフサイクルフックに、削除時のガードは `beforeDelete` フックに置きます。 + +## カスタムのエラーメッセージ [#custom-error-messages] + +`message` は、ルールが発動したときにユーザーが目にするものです。フォームでも API のエラーレスポンスでも表示されます。行動につながるものにしてください。 + +| 弱い | 強い | +|---|---| +| "Invalid input" | "Close date is required for closed deals" | +| "Validation failed" | "Phone must match format: +1-XXX-XXX-XXXX" | +| "Error" | "Discount cannot exceed total" | + +`severity` で調整します。`error` は保存をブロックし、`warning` はメッセージを表示しつつ保存を通し、`info` は純粋に情報提供です。 + +> **警告:** 述語を評価できないルール(解析エラー、綴りを間違えたフィールド、比較できない値)は**安全側に失敗**します。書き込みは `VALIDATION_FAILED` で拒否され、ルールをスキップして保存されることは決してありません。新しいルールは、公開する前に実際のレコードでテストしてください。 + +## ベストプラクティス [#best-practices] + +| すること | しないこと | +|---|---| +| できるだけ低い層で検証する(フィールド → ルール → フック) | フィールドの修飾子で表現できることにフックを使う | +| 明確で行動につながるメッセージを書く | 同じチェックを複数の層で重複させる | +| `priority` を使って安価な形式チェックを先に実行する | 複雑すぎる条件を作る | +| 実際のデータでルールをテストする | 正当なエッジケースをブロックする | + +## 次に進む [#where-to-go-next] + +| ページ | 理由 | +|---|---| +| [データモデル](/docs/build/data) | これらのルールが守るオブジェクトとフィールド | +| [数式](/docs/build/data/formulas) | `condition` と `requiredWhen` の背後にある CEL 言語 | +| [リレーションシップ](/docs/build/data/relationships) | オブジェクトをまたぐ参照整合性 | +| [CEL リファレンス](/docs/reference/cel) | 条件のための演算子と標準ライブラリの完全なリファレンス | +| [フィールドの種類](/docs/reference/field-types) | フィールドの種類ごとの組み込みの検証のデフォルト | +| [フロー](/docs/build/automation/flows) | (有効な)レコードの変更に自動化で反応する | diff --git a/content/docs/build/extend-existing-systems.ja.mdx b/content/docs/build/extend-existing-systems.ja.mdx new file mode 100644 index 00000000..649b53f9 --- /dev/null +++ b/content/docs/build/extend-existing-systems.ja.mdx @@ -0,0 +1,62 @@ +--- +title: 既存システムの拡張 +description: すでに運用しているデータベースを外部データソースとして ObjectOS にフェデレーションし(デフォルトで読み取り専用、まだ初期段階)、マイグレーションなしでそのテーブルをオブジェクトとしてモデル化します。 +editions: [community, cloud, enterprise] +translation: + source_sha: f2aed087dbf4f5abe0d1db987fa124702e063509e62d3f866137fa20c45c87c5 + guide_rev: 1 + mode: auto +--- + +ObjectOS を評価しているチームの多くは、すでに記録システムを持っています。CRM、ERP、チケット管理ツール、本番の SQL や MongoDB データベース上で動く自社製のバックオフィスなどです。問われるのは「捨てて作り直すべきか?」であることはまれです。「危険なマイグレーションなしで、すでにあるものと一緒に使えるか?」です。 + +まずひとつの境界を示します。このページが約束できる範囲を決めるものだからです。ObjectOS が実行するオントロジーは**既存システムの上に載るセマンティックレイヤーではありません**。それ自体がシステムであり、データベース、API、UI、エージェントのツールはそこから導出されます。すでに運用しているシステムに対して提供できるものはそれより狭く、[ObjectStack](https://github.com/objectstack-ai/objectstack) の README が述べるとおりに表現すると、**外部データソースのフェデレーションはデフォルトで読み取り専用で、まだ初期段階です。** データベースをデータソースとして接続し、関心のあるテーブルをオブジェクトとしてモデル化すると、ObjectOS は他のすべてと同じ権限モデルを通じてそれを読み取ります。記録システムは記録システムのままです。 + +## 移行の形 [#the-shape-of-the-move] + +業務システムを置き換えるのではありません。ObjectOS をその*隣に*置き、同じデータベースに向けます。 + +1. 既存のデータベースを外部[データソース](/docs/configure/data-sources)として**接続**します(`schemaMode: 'external'`)。ObjectOS はそれに対して DDL を実行せず、オプトインするまで書き込みはオフのままです。パスワードはシークレットストアに保存され、データソースには決して置かれません。読み取りしかできないデータベースユーザーで接続し、書き込みは意図して有効にしてください。 +2. テーブルをオブジェクトとして**モデル化**します。手で行うか、コーディングエージェントにスキーマをスキャンさせ、ソースレベルのオブジェクトファイルを生成させます。 +3. 各オブジェクトをデータソースに**バインド**します(オブジェクトごと、または名前空間全体のルーティングルールで)。 +4. **読み取り**ます。テーブルがオブジェクトになった瞬間から、すべてのビュー、ダッシュボード、フロー、エージェントのツールがそれを読み取れ、正しいデータベースに自動的にルーティングされ、同じ権限で制御されます。 + +レガシーアプリケーションは何も変わりません。行は元の場所にとどまり、レガシーアプリケーションはそれを書き込み続けます。 + +## 書き直しなしで機能する理由 [#why-this-works-without-a-rewrite] + +| 懸念 | ObjectOS の対応 | +|---|---| +| 「データを移動できない」 | データは決して移動しません。ObjectOS はデータベースにその場で接続します。 | +| 「本番への書き込みのリスクは取れない」 | フェデレーションはデフォルトで読み取り専用です。書き込みには、データソースでのオプトイン(`external.allowWrites: true`)**と**各オブジェクトでのオプトイン(`external.writable: true`)が必要です。`SELECT` だけを許可されたデータベースユーザーは、ObjectOS の内外を問わず、すべての経路でそのとおりに保たれます。 | +| 「すべてのテーブルのモデル化には何週間もかかる」 | コーディングエージェントがスキーマをスキャンし、テーブルごとにオブジェクトファイルを 1 つ生成します。あなたは確認して仕上げるだけで、手で打ち込む必要はありません。 | +| 「AI にデータを任せられない」 | エージェントは**サインインしたユーザー**として実行され、オブジェクトレベル、レコードレベル、フィールドレベルの権限に従います。背後にいる人以上のものを見ることはありません。 | +| 「データをネットワークの外に出せない」 | ObjectOS Enterprise では、ObjectOS はあなたの環境で動作します。業務データとプロンプトは境界の内側にとどまります。 | + +## コーディングエージェントでオブジェクトを生成する [#generating-objects-with-a-coding-agent] + +既存のスキーマを取り込む最速の方法は、コーディングエージェント(Claude Code など)を使って**業務テーブルをスキャンし、ソースレベルのオブジェクト定義を生成する**ことです。テーブルごとに `*.object.ts` ファイルを 1 つ作ります。 + +[`hotcrm`](https://github.com/objectstack-ai/hotcrm) リファレンスアプリは、その出力が取るべき正確な形を示しています。各テーブルは `src/objects/.object.ts` になり、型付きの `Field.*` 定義と外部キー用の `Field.lookup(...)` を使った `ObjectSchema.create({ … })` で表され、`defineStack` で組み立てられます。エージェントは接続されたデータベースをイントロスペクトし、列をフィールドの型に対応付け、あなたが所有しコミットするオブジェクトを書きます。合うものは残し、公開したくない列は削除し、その上にラベル、検証、権限を追加します。 + +完全な手順の作成ガイドは[データソース](/docs/configure/data-sources)を参照してください。 + +## 初日から得られるもの [#what-you-get-on-day-one] + +テーブルが既存のデータベースにバインドされたオブジェクトとしてモデル化されると、次のものが得られます。 + +- **自然言語による分析。** ユーザーは実際のレコードについて質問します。「今四半期に遅れた商談はどれで、担当者は誰か?」。答えは ObjectQL を通じてライブデータに対して計算されます。 +- **ガバナンスの効いた自動化。** フローとアクションは同じデータを読み取り、書き込みを有効にしている場合は書き込みます。すべてのステップが監査されます。 +- **生成された API と UI。** REST エンドポイントと管理画面は同じメタデータから生まれます。 +- **ひとつの権限モデル。** 人に適用される境界が、AI のトラフィックにもまったく同じように適用されます。 + +## まだできないこと [#what-it-is-not-yet] + +フェデレーションは初期段階です。成熟しているのは読み取りの経路だと考え、各データソースプロトコルが現在何をサポートしているかは、[データソース](/docs/configure/data-sources)とフレームワーク自身の [External Datasources](https://objectstack.ai/docs/data-modeling/external-datasources) ガイドで確認してください。多くのシステムを、そのどれも実行せずに*記述する*セマンティックレイヤーが必要なら、それは別の種類の製品です。 + +## ここから始める [#start-here] + +- [データソース](/docs/configure/data-sources):データベースを接続し、オブジェクトをバインドし、クエリをルーティングする +- [AI エージェント](/docs/build/agents):オブジェクトの上の宣言的なエージェント +- [権限](/docs/configure/permissions):AI が継承するモデル +- [ObjectOS Community をローカルで実行する](/docs/start/community):オープンなランタイムを数分で立ち上げる diff --git a/content/docs/build/index.ja.mdx b/content/docs/build/index.ja.mdx new file mode 100644 index 00000000..ac3638f6 --- /dev/null +++ b/content/docs/build/index.ja.mdx @@ -0,0 +1,53 @@ +--- +title: 構築 +seoTitle: "アプリを構築する:AI チャット、Studio のフォーム、テンプレート" +description: ObjectOS でアプリが形になる方法。AI とのチャット、Studio のフォームをクリックして進める方法、テンプレートのフォーク。 +editions: [community, cloud, enterprise] +translation: + source_sha: a4c1dc21dbbfcf386995724063bb871474f3f5487259af000a7779e9e21c4916 + guide_rev: 1 + mode: auto +--- + +ObjectOS で構築するとは、[オントロジー](/docs/ontology)を作成することです。その中核(オブジェクトとフィールド、リレーション、アクション、権限、フロー、エージェント)と、人がそれを見るための投影(ビュー、ダッシュボード、アプリ)です。ほとんどの人はそのメタデータを手で書きません。**欲しいものを説明すると、AI Builder がそれを書きます。** 道は 3 つあり、実際に多くの人がプラットフォームを使う順に並べると次のとおりです。 + +| 道 | 対象 | 成果物 | +|---|---|---| +| **[AI Builder](/docs/build/ai-builder)**(主要) | 業務ユーザー、プロダクトオーナー、誰でも | テナント内の稼働中のメタデータ。承認待ちのキューに入ります | +| **クリックで構築**(代替) | Studio のフォームを好む管理者 | 同じ稼働中のメタデータ | +| **[テンプレートのフォーク](/docs/build/templates)**(開発者向け) | コードをソース管理下に置きたいエンジニア | マーケットプレイス経由で配布される TypeScript パッケージ | + +3 つの道はすべて**同じオントロジー**を作成します。同じオブジェクト、フィールド、リレーション、アクション、権限、フローと、同じ投影です。そしてどの道も、何かが実行される前に同じ検証ゲートを通ります。`@objectstack/spec` のスキーマと `os validate` が実行する作成ルールで、ランタイムは AI Builder や Studio からのすべてのメタデータ書き込みにもそれを適用します。ObjectStack のドキュメントの [Validating Metadata](https://objectstack.ai/docs/deployment/validating-metadata) を参照してください。 + +## プラットフォームの語彙 [#the-platform-vocabulary] + +すべてのアプリは同じプリミティブから組み立てられます。一度覚えれば十分です。 + +| 概念 | 内容 | ドキュメント | +|---|---|---| +| **[パッケージ](/docs/build/packages)** | 組織化の単位。`com.acme.crm` のように、バージョン付きでインストール可能 | パッケージ | +| **[データモデル](/docs/build/data)** | オブジェクト + フィールド + リレーションシップ + ステートマシン | データモデル | +| **[インターフェース](/docs/build/interface)** | アプリ、ビュー、フォーム、ダッシュボード、ページ。ユーザーが目にするもの | インターフェース | +| **[アクション](/docs/build/interface/actions)** | 名前付きの操作。REST やボタンから呼び出せ、公開すれば AI エージェントからも呼び出せます。フローを開始することもできます | アクション | +| **[権限](/docs/configure/permissions)** | 誰が何を読み取り、作成し、編集し、削除できるか。権限セット、レコードアクセス、フィールドレベルセキュリティ | 権限 | +| **[フロー](/docs/build/automation/flows)** | 宣言的なビジネスロジック(自動起動 / スケジュール / 手動) | フロー | +| **[エージェント](/docs/build/agents)** | エンドユーザー向けの AI アシスタント。Agent → Skill → Tool | エージェント | +| **[マーケットプレイス](/docs/build/marketplace)** | 誰でもワンクリックでインストールできる出来合いのパッケージ | マーケットプレイス | + +## どこから始めるか [#where-to-start] + +1. **まずは試してみたい?** → ObjectOS を開き、[AI Builder](/docs/build/ai-builder) を起動して、*「サポートチケットを優先度、ステータス、担当者付きで管理したい」* と伝えます。30 秒足らずで動作するオブジェクトができます。 + +2. **その上で本物の製品を構築する?** → [パッケージ](/docs/build/packages)と[データモデル](/docs/build/data)を読んで、AI が何を生成しているかを理解してください。AI で下書きし、手またはチャットで仕上げ、結果をコミットします。 + +3. **Salesforce/Retool のアプリを置き換える?** → 最も近い[マーケットプレイスのテンプレート](/docs/build/marketplace)をフォークし、不要なものを取り除き、足りない部分を AI に埋めてもらいます。 + +## 決してしなくてよいこと [#what-youll-never-have-to-do] + +- REST エンドポイントを書く。プラットフォームがオブジェクトごとに生成します。 +- Studio のフォームを配線する。フォームはスキーマからレンダリングされます。 +- RBAC のチェックを書く。権限はコードではなく宣言です。 +- 管理 UI を構築する。Setup と Account がシステム管理とサインインを担います。 +- 型を生成する。`@objectstack/spec` がスキーマから導出します。 + +ObjectOS はこの点について意図的にこだわりを持っています。**メタデータが存在すれば、あらゆるサーフェス(REST、UI、ObjectQL、監査、AI ツール)が無償で現れます。** だからこそ AI Builder は機能します。メタデータを生成するだけでよく、残りはプラットフォームが処理します。 diff --git a/content/docs/build/marketplace.ja.mdx b/content/docs/build/marketplace.ja.mdx new file mode 100644 index 00000000..1c70423d --- /dev/null +++ b/content/docs/build/marketplace.ja.mdx @@ -0,0 +1,140 @@ +--- +title: マーケットプレイス +seoTitle: "マーケットプレイス:出来合いのアプリをインストールし、公開する" +description: コードを書かずに、稼働中の ObjectOS に出来合いのアプリをインストールします。 +editions: [community, cloud, enterprise] +translation: + source_sha: 5fb581df2aa59854381bb78c50049fa3203dd3c3ded12d2e39d88d4997ff7e68 + guide_rev: 1 + mode: auto +--- + +ObjectOS のマーケットプレイスを使うと、構築済みのアプリを稼働中のランタイムにインストールできます。ビルドのステップも、再起動も、ソースのチェックアウトもありません。初日から本物のソフトウェアをユーザーの前に置く最速の方法です。 + +## 仕組み [#how-it-works] + +マーケットプレイスのクライアントは、オープンソースの `@objectstack/cloud-connection` パッケージです。クラウド管理の環境とセルフホストの ObjectOS イメージには、最初から配線された状態で付属します。自分で組み立てるスタックでは、数行の設定で有効にします。 + +```ts +import { + MarketplaceProxyPlugin, + MarketplaceInstallLocalPlugin, + RuntimeConfigPlugin, + resolveCloudUrl, +} from '@objectstack/cloud-connection'; + +const catalogUrl = resolveCloudUrl(); // OS_CLOUD_URL; 'off' disables + +plugins: [ + ...(catalogUrl ? [ + new MarketplaceProxyPlugin({ controlPlaneUrl: catalogUrl }), + new MarketplaceInstallLocalPlugin({ controlPlaneUrl: catalogUrl }), + ] : []), + new RuntimeConfigPlugin({ controlPlaneUrl: '', singleEnvironment: true, installLocal: true }), +] +``` + +閲覧とインストールの*仕組み*はオープンです。カタログの*サービス*(組織のカタログ、レビュー、有料配布)は、`OS_CLOUD_URL` が指すコントロールプレーンが提供します。アプリはインストールされるとランタイム自身のカーネルに置かれ、実行時に何もカタログへの到達性に依存しません。 + +ObjectOS(`/_console/`)を開くと、マーケットプレイスのタブが設定されたアプリカタログを問い合わせ、インストール可能なアプリを表示します。 + +```text +You ─→ ObjectOS ─→ Marketplace tab ─→ pick app ─→ Install + ↓ + Artifact merged into kernel + ↓ + The page re-renders with new + objects / views / permissions + ↓ + Done — no restart +``` + +## カタログ [#catalogs] + +| カタログ | ソース | 使うとき | +|---|---|---| +| **Default** | ObjectOS のランタイムイメージにあらかじめ同梱 | 初めての評価、デモ、オフライン | +| **ObjectStack 公開カタログ** | 公開のアプリレジストリ | 最新のコミュニティ製とファーストパーティのアプリ | +| **プライベートカタログ** | 自分で公開した成果物 | 公開したくない社内アプリ | +| **Local** | ランタイムにマウントしたファイル | エアギャップ、カスタムビルド | + +カタログのソースは、マーケットプレイスのプラグインまたは環境変数で設定します。[ランタイム設定](/docs/configure/runtime)を参照してください。 + +## デフォルトカタログの内容 [#whats-in-the-default-catalog] + +次のアプリはワンクリックでインストールできます。 + +| アプリ | 得られるもの | +|---|---| +| **Todo** | 汎用のタスクとプロジェクトの管理 | +| **Contracts** | AI による条項抽出付きの契約ライフサイクル管理(CLM) | +| **Procurement** | ベンダー、発注書、3 点照合 | +| **Compliance** | SOC 2 / ISO 27001 の統制 + 証跡の収集 | +| **Helpdesk** | AI ファーストのカスタマーサポートのチケット管理 | +| **Content** | 編集カレンダー + チャネル ROI | +| **HR** | 名簿、組織図、休暇 | +| **Project** | プロジェクト / タスク / マイルストーンの管理 | + +ソースは [github.com/objectstack-ai/templates](https://github.com/objectstack-ai/templates) にあります。どれでもクローンして、カスタムアプリの出発点にできます。 + +## インストールの流れ [#install-flow] + +1. **ObjectOS を開きます**:http://localhost:3000/_console/ +2. **サインインします**:まだアカウントがない場合は `/_console/register` で登録します +3. **マーケットプレイスのタブに移動します** +4. **アプリを選び、Install をクリックします** +5. **ページを再読み込みします**:新しいアプリのオブジェクト、ビュー、フローが表示されます + +裏では、マーケットプレイスがアプリのコンパイル済み成果物を取得し、稼働中のカーネルにマージし、そのオブジェクトを ObjectQL に登録します。シードデータは(アプリが定義していれば)最初のインストール時に挿入されます。 + +## アンインストール [#uninstall] + +**Marketplace → インストール済みのアプリ → Uninstall** から行います。アプリのオブジェクトはカーネルから削除され、テーブルはクリーンアップの対象として印が付けられます(データはデフォルトで保持され、テーブルを削除するかどうかは選べます)。 + +## 自分のアプリを公開する [#publishing-your-own-app] + +`os init` で構築したものは、どれでもマーケットプレイスのアプリにできます。 + +```bash +os init my-app -t app --install +cd my-app +# ... write objects, views, etc. ... +os compile # → dist/objectstack.json +os package publish # publish to a catalog +``` + +公開カタログに公開するには、レジストリのアカウントが必要です(`os login`)。プライベートカタログに公開するには、`OS_PACKAGE_REGISTRY` を自分のものに向けます。 + +## バージョニング [#versioning] + +公開されたアプリはすべて不変です。更新すると新しいバージョンができます。ランタイムはアプリごとに、インストール済みのバージョンと利用可能な更新を追跡します。追跡しているカタログに新しいバージョンが公開されると、ユーザーには「Update available」のバッジが表示されます。 + +## CLI からインストールする [#installing-from-the-cli] + +マーケットプレイスのタブが主要なインストールのサーフェスですが、同じ install-local エンドポイントは CI やエアギャップ運用のためにスクリプトから使えます。 + +```bash +# Catalog mode — the runtime resolves the package from its configured catalog +os package install com.acme.crm --runtime http://localhost:3000 \ + --email admin@example.com --password … + +# Air-gapped mode — send a compiled artifact inline, no catalog round-trip +os package install ./dist/objectstack.json --runtime http://localhost:3000 \ + --email admin@example.com --password … +``` + +認証情報は**対象のランタイム**のアカウントです(クラウドのログインではありません)。アプリ内のインストールが使うのと同じ認可です。 + +## 権限 [#permissions] + +アプリのインストールには `manage_marketplace` システム権限が必要です。デフォルトでは **Setup Administrator** 権限セットのメンバーだけがそれを持ちます。通常のユーザーにはマーケットプレイスは読み取り専用で表示されます。 + +## エアギャップのマーケットプレイス [#air-gapped-marketplaces] + +インターネットへの出口がないデプロイでは、ネットワーク内でローカルのカタログサーバーを実行し、ObjectOS をそこに向けます。構成は[エアギャップ](/docs/deploy/air-gapped)を参照してください。 + +## マーケットプレイスではないもの [#what-the-marketplace-is-not] + +- **コードの配布チャネルではありません。** 公開されたアプリはコンパイル済みの成果物で、データ + UI + フローを宣言的に記述します。任意の JavaScript は含みません。 +- **サンドボックスではありません。** インストールされたアプリは、カーネル内の他のものと同じようにデータベースにアクセスできます。信頼できないソースのアプリをインストールする前に、成果物を確認してください。 +- **決済プラットフォームではありません**(今のところ)。公開カタログのアプリは無料の Apache-2.0 です。商用 / 有料の配布はロードマップにあります。 diff --git a/content/docs/build/packages.ja.mdx b/content/docs/build/packages.ja.mdx new file mode 100644 index 00000000..65a825f4 --- /dev/null +++ b/content/docs/build/packages.ja.mdx @@ -0,0 +1,164 @@ +--- +title: パッケージ +seoTitle: "パッケージ:作成、バージョン管理、公開、インストール" +description: ObjectOS における組織化の単位。バージョン付きで、インストール可能で、共有できます。 +editions: [community, cloud, enterprise] +translation: + source_sha: d23055ede31061fdd880d75901375cee4b7968fd7ac57a3a993feae4c88d955c + guide_rev: 1 + mode: auto +--- + +ObjectOS で構築するものはすべて**パッケージ**に置かれます。パッケージは、バージョン付きで自己完結したメタデータの束です。パッケージは、AI Builder が作業する単位であり、マーケットプレイスが配布する単位であり、ObjectOS が更新を追跡する単位です。 + +## パッケージの中身 [#whats-in-a-package] + +```text +com.acme.crm@1.2.0 +├── manifest id, version, namespace, dependencies +├── objects/ *.object.ts, *.state.ts, *.hook.ts +├── views/ *.view.ts, *.page.ts, *.form.ts +├── actions/ *.action.ts +├── flows/ *.flow.ts, *.approval.ts +├── agents/ *.agent.ts, *.skill.ts +├── permissions/ *.permission.ts +├── sharing/ *.sharing.ts +├── translations/ en.ts, zh-CN.ts, ... +├── apps/ *.app.ts (navigation) +└── data/ defineDataset(...) seed +``` + +すべてのメタデータの成果物(オブジェクト、アクション、フローなど)は、ちょうどひとつのパッケージに属します。パッケージ ID は**逆 DNS 形式**(`com.acme.crm`、`org.mycompany.helpdesk`)で、名前空間のプレフィックス(`crm_`、`hd_`)は、同じテナントにインストールされた複数のパッケージ間でテーブル名やオブジェクト名が衝突するのを防ぎます。 + +## パッケージを作成する [#creating-a-package] + +### AI Builder から [#from-the-ai-builder] + +> *「社内 CRM 用の新しいパッケージを、名前空間 `crm` で始めて。」* + +AI は `create_package` と `set_active_package` を呼び出します。それ以降、説明するすべてのオブジェクト / フィールド / アクションは `crm` に置かれます。 + +### CLI から [#from-the-cli] + +```bash +os init my-crm -t app +cd my-crm +# manifest lives in the `manifest:` block of ./objectstack.config.ts +pnpm dev +``` + +### UI から [#from-the-ui] + +**Studio → Packages → New Package**:名前、ID、バージョン、名前空間を指定します。 + +## アクティブなパッケージ [#active-package] + +AI Builder では、会話が**アクティブなパッケージ**を持ちます。新しいメタデータのデフォルトの入れ物です。*「`com.acme.helpdesk` に切り替えて」* のように言うと、AI は `set_active_package` ツールでそれを設定します。CLI では、アクティブなパッケージは単純にプロジェクトの `objectstack.config.ts`(`manifest:` ブロック)で宣言されたものです。 + +## バージョニング [#versioning] + +パッケージは **semver** です。ルールはランタイムと同じです。[変更履歴とバージョニング](/docs/resources/changelog)を参照してください。 + +バージョンを上げても、公開するまでは何も変わりません。ランタイムはテナントごと、パッケージごとに `installed_version` を追跡し、カタログに新しいバージョンがあると、マーケットプレイスに *"Update available"* のバッジが表示されます。 + +## 依存関係 [#dependencies] + +パッケージは他のパッケージに依存できます。 + +```json +{ + "id": "com.acme.helpdesk", + "version": "0.3.0", + "dependencies": { + "com.acme.crm": "^1.0.0", + "sys.feeds": "*" + } +} +``` + +ランタイムはインストール時に依存関係を解決します。`com.acme.crm` がインストールされていない場合、helpdesk のインストールは明確なエラーで失敗します。 + +システムパッケージ(`sys.*`)は常に存在します。フィード、添付ファイル、監査、ID などです。 + +## 公開 [#publishing] + +```bash +os cloud login # once: stores a cloud token in ~/.objectstack/cloud.json +os compile # → dist/objectstack.json +os package publish # → ObjectStack cloud catalog +``` + +`os package publish` は、コンパイル済みのマニフェストを `OS_CLOUD_URL` が指すカタログにアップロードします。認証は `os cloud login`(対話型)か、CI では `OS_CLOUD_API_KEY` の Bearer トークンから得られます。プライベート / エアギャップの配布では、公開を省略し、コンパイル済みの `dist/objectstack.json` を対象のインストールに直接渡します(下の「インストール」を参照)。[マーケットプレイス](/docs/build/marketplace)を参照してください。 + +> **この 2 つの変数は、ビルドマシンの公開用 ID を設定するものです**。パッケージカタログに対する CLI の認証情報です。*デプロイ*がコントロールプレーンに接続する方法ではありません。稼働中のデプロイは、バインドされたときに発行されたトークンで認証し、設定すべき API キーはありません。どちらかの名前をデプロイの設定にコピーする前に、[環境変数](/docs/reference/environment-variables)を確認してください。 + +## ObjectOS Cloud での 2 つの開発者向けの道 [#two-developer-routes-on-objectos-cloud] + +開発者がホスト型の環境に変更を入れる方法は 2 つあります。 + +| | パッケージの公開 | MCP での構築 | +|---|---|---| +| 方法 | ソースで構築し、`os package publish` してから **Marketplace** でインストールする | `metadata:write` スコープで [MCP](/docs/configure/mcp#build-with-an-agent) 経由で接続した自分のエージェントが、環境内で構築する | +| 届くもの | **バージョン付き**のパッケージ。丸ごとインストールされる | 環境内の**ドラフト**。人が Studio → **Changes** で公開する | +| 構築できるもの | 環境が実行するすべてのもの。スクリプト、Webhook、API でトリガーされるフローを含む | 環境の AI 構築が提供するもの:データモデル、インターフェース、サンプルデータ、アプリの外枠、レコードやボタンで開始するフロー、ノーコードのアクション | +| 最適な用途 | リリース:複数の環境での同じバージョン、リポジトリでのレビュー、Marketplace | 反復:ひとつの環境で変更を試し、アプリで確認する | + +アプリを素早く形にするには MCP での構築を使い、バージョンが必要になったらパッケージにします。別の環境や組織に出荷するとき、リポジトリで保持するとき、MCP での構築が提供しないメタデータを運ぶときです。 + +## インストール [#installing] + +インストールは**環境内の**操作で、公開とは別のものです。パッケージは(カタログに)一度公開し、その後、対象の環境の*中から*インストールします。インストールはその環境へのログインによって確認され、認可されます。インストールするのに環境 ID を知る必要はありません。 + +| 方法 | 手順 | +|---|---| +| UI で(推奨) | 環境にサインイン → **Marketplace** → パッケージを選択 → **Install**。現在の環境にインストールされます。 | +| CLI → 稼働中のランタイム | `os package install com.acme.crm --runtime `:ランタイムが設定されたカタログからパッケージを解決し、自身のカーネルにマージします | +| CLI でエアギャップ | `os package install ./dist/objectstack.json --runtime `:コンパイル済みの成果物をインラインで送り、カタログとの往復はありません | +| REST | `POST /api/v1/marketplace/install-local`(ボディ:`{ packageId, versionId? }` または `{ manifest }`) | +| エアギャップ(起動時) | コンパイル済みの `dist/objectstack.json` 成果物をマウントします([エアギャップ](/docs/deploy/air-gapped)を参照) | + +インストールコマンドのパッケージ ID は、安定したマニフェストの ID(`com.acme.crm`)です。内部の `pkg_…` の行 ID は必要ありません。 + +> **CI のショートカット。** *既知の*環境にデプロイするパイプラインは、公開とインストールを 1 ステップで行えます:`os package publish --env --install [--seed-sample-data]`。これは自動化のための便宜であり、人が使う方法ではありません。対話的なインストールは環境の Marketplace で行います。このステップは全部か無かです。インストールが拒否されると何も公開されず、バージョンは保存されず、コマンドはゼロ以外で終了するので、パイプラインは失敗を検知できます。 + +インストールはパッケージのメタデータを稼働中のカーネルにマージし、そのオブジェクトを ObjectQL に登録し、最初のインストール時に初期データを投入します。再起動は不要です。キャッシュされたインストールは次回の起動時に再登録されるので、プロセスの再起動後も残ります。 + +## アンインストール [#uninstalling] + +アンインストールすると、パッケージのキャッシュされたマニフェストが削除され、次回の起動時に再登録されなくなります。オブジェクトの登録は追加的なので、すでに稼働しているパッケージのオブジェクトを完全にアンロードするには**カーネルの再起動**が必要です。データはデフォルトで**保持**されるので、再インストールして再開できます。 + +## パッケージ間の規約 [#cross-package-conventions] + +多くのパッケージが共存するときの衝突を防ぐために: + +| 成果物 | 規約 | +|---|---| +| オブジェクト名 | 常にプレフィックス付き:`crm_account`、`hd_ticket` | +| アクション名 | プレフィックス付き:`crm_assign_owner`、`hd_close_ticket` | +| フロー名 | プレフィックス付き:`hd_overdue_alert` | +| 翻訳キー | 名前空間の下にスコープ:`crm.account.label` | +| シードの `externalId` | `:`、例:`crm:demo-account-1` | +| システム名 | 予約済み:`sys_*`(カスタムパッケージでは決して使わない) | + +CLI と AI Builder はどちらも、作成時にこれを強制します。 + +## システムパッケージ [#system-packages] + +ランタイムには、ポリモーフィックなサービスを提供する、常に存在する少数のパッケージが付属します。 + +| パッケージ | 提供するもの | +|---|---| +| `sys.identity` | `sys_user`、`sys_organization`、`sys_member`、セッション、API キー | +| `sys.feeds` | `sys_comment`、`sys_activity`、`sys_attachment` | +| `sys.audit` | `sys_audit_log` | +| `sys.files` | `sys_file` | +| `sys.ai` | `ai_conversations`、`ai_pending_actions` | +| `sys.settings` | `sys_setting` | + +オブジェクトで `enable: { feeds: true, trackHistory: true, … }` を指定して有効にします。[データモデル](/docs/build/data)を参照してください。 + +## 次に進む [#where-to-go-next] + +- [マーケットプレイス](/docs/build/marketplace):パッケージを他のテナントに配布する +- [データモデル](/docs/build/data):パッケージの中に入るもの +- [`os package` コマンド](/docs/reference/cli):完全な CLI リファレンス diff --git a/content/docs/build/reports.ja.mdx b/content/docs/build/reports.ja.mdx new file mode 100644 index 00000000..efb7965c --- /dev/null +++ b/content/docs/build/reports.ja.mdx @@ -0,0 +1,164 @@ +--- +title: レポート +seoTitle: "レポートを構築する:データセット上のサマリー、マトリックス、結合レポート" +description: ダッシュボードと同じデータセットにバインドされた、グループ化レポートとクロス集計レポート。任意のグラフと、すべての数値の裏にあるレコードへのドリルスルー付きです。 +editions: [community, cloud, enterprise] +translation: + source_sha: b9e6f81d52e7e18ec7dd039e188135dbeea353e30700f37dbc327be0018f9a52 + guide_rev: 1 + mode: auto +--- + +{/* + Platform checklist items this page documents (objectstack + docs/qa/platform-checklist/areas/dashboards.json): + dashboards.dataset-report-authoring, dashboards.drill-through-range, + dashboards.analytics-exposure-gate-and-measure-aggregate. + + Deliberately not written: saved personal reports and scheduled report + delivery. dashboards.saved-report-ownership and + dashboards.report-schedule-dispatch-delivery are retired — the saved-report + stack was removed (objectstack #20102), and `subscription` / `schedule` on a + report are refused because nothing delivers a report on a timetable. The + report `dateRange` and `exportOptions` keys (objectstack #26548) are not + documented yet either: the spec accepts them, but the report page does not + render them. +*/} + +**レポートは、データセットにバインドされた数値の表です。** データセットのメジャーをディメンションでグループ化し(行方向に、マトリックスでは列方向にも)、同じ数値のグラフを表の上に描くことができます。レポートはデータセットからメジャーを*名前で*選ぶので、レポートの「売上」は[ダッシュボード](/docs/build/interface/dashboards)が表示するのと同じ売上です。 + +## データセットから始める [#start-from-a-dataset] + +レポートとダッシュボードは、ひとつのセマンティックレイヤーを共有します。**データセット**が、ベースのオブジェクト、結合するリレーションシップ、グループ化に使えるディメンション、表示できるメジャーを持ちます。一度定義すれば([ダッシュボード → まずデータセット](/docs/build/interface/dashboards#datasets-first)を参照)、好きなだけのレポートとウィジェットをそれにバインドできます。 + +データセットが届かないものには、レポートも届きません。 + +- API がオフになっているオブジェクトはデータセットのベースにできません。クエリは拒否されます。 +- 内部フィールドは、ディメンション、メジャー、フィルターとして使えません。管理者でも同じです。 +- すべてのクエリは閲覧者の権限で実行されるため、レポートが閲覧者の開けないレコードを数えることはありません。 + +## レポートの種類 [#report-types] + +| `type` | 表示内容 | 選択するもの | +|---|---|---| +| `summary` | グループごとに 1 行、列にメジャー | `rows`(ディメンション)と `values`(メジャー) | +| `matrix` | クロス集計:ひとつのディメンションを縦に、別のものを横に、セルにメジャー | `rows`、`columns`、`values` | +| `joined` | 複数のサブレポートを 1 ページに積み重ね、それぞれを表として描画 | `blocks` の各エントリが独自に選択 | + +レコードの単純な一覧はレポートではありません。代わりにオブジェクトのリスト[ビュー](/docs/build/interface/views)として構築してください。 + +```ts +import { defineReport } from '@objectstack/spec/ui' + +// Estimated hours by task status. +export const hoursByStatus = defineReport({ + name: 'hours_by_status', + label: 'Hours by Status', + type: 'summary', + dataset: 'task_metrics', + rows: ['status'], + values: ['est_hours'], +}) + +// Status down, priority across. +export const statusByPriority = defineReport({ + name: 'status_by_priority', + label: 'Status × Priority', + type: 'matrix', + dataset: 'task_metrics', + rows: ['status'], + columns: ['priority'], + values: ['est_hours'], +}) +``` + +`summary` または `matrix` のレポートには、`dataset` と、`values` に少なくとも 1 つのメジャーが必要です。`rows`、`columns`、`values` が指すのはデータセットのディメンションとメジャーであり、オブジェクトの生のフィールドではありません。 + +### 結合レポート [#joined-reports] + +結合レポートは、独立した複数のサブレポートを 1 ページに置きます。たとえば「未完了の作業」の上に「完了した作業」を置くようなものです。各ブロックは独自のデータセットにバインドし、独自の行、列、値を選び、独自の `runtimeFilter` を持ちます。コンテナ自体は何も選択しません。結合レポートの `dataset`、`rows`、`columns`、`values`、`order`、`chart` は拒否され、`dataset` のないブロックは名前を示して拒否されます。ブロックの中に別の結合レポートを入れ子にすることはできません。 + +```ts +import { defineReport } from '@objectstack/spec/ui' + +export const taskOverview = defineReport({ + name: 'task_overview', + label: 'Task Overview', + type: 'joined', + blocks: [ + { name: 'open_block', label: 'Open Tasks', type: 'summary', + dataset: 'task_metrics', rows: ['status'], values: ['est_hours'], + runtimeFilter: { done: false } }, + { name: 'done_block', label: 'Completed Tasks', type: 'summary', + dataset: 'task_metrics', rows: ['status'], values: ['task_count'], + runtimeFilter: { done: true } }, + ], +}) +``` + +コンテナレベルの `runtimeFilter` はすべてのブロックに AND で結合されるので、「今四半期」のようなスコープは一度書くだけで済みます。 + +## フィルターと並べ替え [#filtering-and-ordering] + +- **`runtimeFilter`** は、データセット自身のフィルターに加えて、レポートが集計する行を絞り込みます。 +- **`order`** は結果を並べ替えます。最も重要なキーが先です。各キーはレポートが選択するディメンションまたはメジャーを指し、選択していないキーは作成時のエラーです。並べ替えはサーバー上で結果全体に対して行われます。日付のディメンションはすでに時系列順で返されるので、`order` が必要なのは、メジャーで並べ替えるとき(「大きい順」)、新しいものを先にするとき、または別のディメンションを並べるときだけです。 + +## グラフを追加する [#adding-a-chart] + +`summary` または `matrix` のレポートは、表の上(`columns` を持つマトリックスでは下)にグラフを描けます。グラフの軸は同じデータセットのディメンションとメジャーを指します。 + +```ts +import { defineReport } from '@objectstack/spec/ui' + +export const hoursByStatusChart = defineReport({ + name: 'hours_by_status_chart', + label: 'Hours by Status (Chart)', + type: 'summary', + dataset: 'task_metrics', + rows: ['status'], + values: ['est_hours'], + chart: { type: 'bar', xAxis: 'status', yAxis: 'est_hours' }, +}) +``` + +グラフは表が示すのと同じ数値をプロットします。結合レポートは表だけを描きます。 + +## ドリルスルー [#drill-through] + +集計されたすべての行やセルはクリックできます。その数値の裏にあるレコードを一覧表示するサイドドロワーが開き、グループに正確にスコープされます。日付のディメンションではそのバケットの期間、マトリックスのセルでは行と列の両方です。ドロワーからレコードをクリックして開くか、**Open in list →** でオブジェクトの完全なリストに進みます。`drilldown: false` でオフにできます。 + +一致するデータがないレポートは、壊れた表ではなく空の状態を表示します。 + +## レポートを人の前に出す [#putting-a-report-in-front-of-people] + +[アプリ](/docs/build/interface/apps)のナビゲーションに `report` 項目を追加します。 + +```ts +// One navigation item of an app. +{ id: 'nav_hours_by_status', type: 'report', label: 'Hours by Status', + reportName: 'hours_by_status', icon: 'sigma' } +``` + +レポートページには、レポートのラベルと説明、そしてレポートが表示されます。レポートは `⌘K` コマンドパレットの **Reports** の下にも一覧表示されます。[検索](/docs/use/search)を参照してください。 + +管理者にはレポートページに **Edit** ボタンが表示されます。サイドパネルでレポートの設定が開きます。変更はドラフトとして保存され、公開されるまで他の人には見えません。 + +ドラフトは不完全でもかまいません。まだ存在しないデータセット、メジャー、ディメンションを指していても許されます。公開時にそれらの参照がチェックされ、存在しないものを指すレポートは拒否されるので、公開されたレポートがエラーなしに空白で表示されることはありません。 + +## ダッシュボードかレポートか [#dashboards-or-reports] + +| 使うもの | とき | +|---|---| +| [ダッシュボード](/docs/build/interface/dashboards) | 複数の数値とグラフをひと目で、ダッシュボード全体の日付とフィルターのコントロール付きで | +| レポート | ひとつの問いへの完全な答え。1 行ずつ読むグループ化された表またはクロス集計と、そのグラフ | + +どちらも同じデータセットにバインドし、同じ方法でドリルスルーするので、数値はそれらの間を意味を変えずに行き来します。ダッシュボード全体の期間とグローバルフィルターは、[ダッシュボード → グローバルな期間とフィルター](/docs/build/interface/dashboards#global-date-range-and-filters)で説明しています。 + +## 次に進む [#where-to-go-next] + +| ページ | 理由 | +|:--|:--| +| [ダッシュボード](/docs/build/interface/dashboards) | データセット、ウィジェット、グローバルフィルター | +| [ビュー](/docs/build/interface/views) | 単純なレコードの一覧と、リスト内のグラフ | +| [アプリ](/docs/build/interface/apps) | レポートをナビゲーションに置く | +| [権限](/docs/configure/permissions) | すべてのレポートクエリが適用する行レベルセキュリティ | diff --git a/content/docs/build/templates.ja.mdx b/content/docs/build/templates.ja.mdx new file mode 100644 index 00000000..98510551 --- /dev/null +++ b/content/docs/build/templates.ja.mdx @@ -0,0 +1,93 @@ +--- +title: テンプレート +seoTitle: "アプリテンプレート:フォークできる Helpdesk、Contracts、Todo" +description: フォークできるスターターパッケージ。`todo`、`contracts`、`procurement`、`helpdesk` など。 +editions: [community, cloud, enterprise] +translation: + source_sha: 463d4f0100a6c89aa409bc10e01a61663dd4d3c6937fe19376fbc7a0e24145f8 + guide_rev: 1 + mode: auto +--- + +テンプレートは**フォークできるスターターパッケージ**です。それぞれが本物の形を持ったアプリで、マーケットプレイスからワンクリックでインストールすることも、CLI でクローンして拡張用の TypeScript のコードベースを手に入れることもできます。 + +テンプレートが存在する理由は 2 つあります。 + +1. **説明するより見せる**:動作する複数オブジェクトのアプリは、ドキュメントより速く読めます。 +2. **エンジニアリングチームに出発点を与える**:データベース内の AI 生成メタデータだけでなく、コードをソース管理下に置きたいときのためです。 + +## デフォルトカタログに含まれるもの [#what-ships-in-the-default-catalog] + +| テンプレート | 領域 | フォークして作れるもの | +|---|---|---| +| **`todo`** | タスクとプロジェクト | 「何らかの形でグループ化されたやること」のツール全般 | +| **`contracts`** | AI による条項抽出付きの CLM | 承認 + ドキュメント AI | +| **`procurement`** | ベンダー、発注書、3 点照合 | 承認チェーン + 受領 | +| **`compliance`** | SOC 2 / ISO 27001 の統制 | 証跡収集のワークフロー | +| **`helpdesk`** | AI ファーストのカスタマーサポート | チケット + SLA + AI コパイロット | +| **`content`** | 編集カレンダー + チャネル ROI | ライフサイクル + メトリクス | +| **`hr`** | 名簿、組織図、休暇 | 人を中心としたアプリ | +| **`project`** | プロジェクト / タスク / マイルストーンの管理 | プロジェクト管理ツール | + +ソース:[github.com/objectstack-ai/templates](https://github.com/objectstack-ai/templates)。Apache-2.0 です。断りなくフォークしてください。 + +## 30 秒でインストール(コードなし) [#install-in-30-seconds-zero-code] + +ObjectOS で: + +1. **Marketplace** を開き → テンプレートを検索します。 +2. **Install** をクリックします。 +3. 更新します。新しいアプリがナビゲーションに表示されます。 + +完了です。レコード、ビュー、フロー、権限がすべて稼働します。 + +## コードベースとしてフォークする(エンジニア向け) [#fork-as-a-codebase-for-engineers] + +```bash +npm create objectstack@latest my-app +cd my-app +pnpm install +pnpm dev +``` + +スキャフォールダーはすべてのプロジェクトを `blank` テンプレートから始めます。コンテンツのテンプレートを名前で取得することはもうありません。ObjectStack 17.7 では、`--template todo` は廃止済みとして拒否されます。 + +プロジェクトは自己完結した pnpm パッケージです。編集、lint、テスト、コミットできる `*.object.ts`、`*.view.ts`、`*.flow.ts` ファイルです。満足したら: + +```bash +pnpm build +os package publish # → your marketplace +``` + +あなたのフォークをインストールする顧客は、**あなたの**ブランドと**あなたの**変更を受け取ります。 + +## テンプレート憲章(社会契約) [#template-charter-the-social-contract] + +すべてのテンプレートには、スコープと厳格な上限を宣言する `CHARTER.md` が付属します。典型的には、業務オブジェクトは 6 つ以下、`src/` 以下は 2,500 行以下、アプリは 1 つ、デフォルトロケールは 1 つです。憲章は、テンプレートが中途半端な製品ではなく**テンプレート**であり続けるために存在します。フォークがこれらの上限を超えて大きくなったら、既存のものを肥大化させず、新しいテンプレートとして出荷してください。 + +ファイルの接尾辞のプロトコル(`*.object.ts`、`*.state.ts`、`*.hook.ts` など)、作成の順序(オブジェクト → 状態 → フック → ビュー → フロー → …)、作り直す代わりに再利用すべきポリモーフィックなプラットフォームサービス(`sys_comment`、`sys_attachment`、`sys_audit_log`)については、上流の [TEMPLATE_GUIDE.md](https://github.com/objectstack-ai/templates/blob/main/TEMPLATE_GUIDE.md) を参照してください。 + +## 出発点を選ぶ [#pick-a-starting-point] + +| 構築しているもの | フォークするもの | 理由 | +|---|---|---| +| 「もの」を追跡する社内ツール全般 | `todo` | すべてのプリミティブを示す最小で最もきれいな例 | +| 承認チェーンのあるもの全般 | `procurement` または `contracts` | 本物の承認プロセスが配線済み | +| AI を使う顧客向けのもの全般 | `helpdesk` | エージェント + チケットのコパイロットのパターン | +| 規制業種のワークフロー | `compliance` | 監査 + 証跡 + 統制のマッピング | +| 人 / 組織図のアプリ | `hr` | 名簿 + レポートライン | + +## AI Builder とテンプレートを一緒に使う [#ai-builder--templates-together] + +テンプレートをフォークしても、その上で**引き続き** AI Builder を使えます。`helpdesk` をインストールしてから、こう伝えます。 + +> *「`hd_ticket` に、範囲 1〜5 の整数フィールド `csat_score` を追加して、クローズ時に入力を求めて。」* + +AI はインストールされたパッケージをその場で拡張します。変更はデプロイ内の稼働中のメタデータで、他の AI Builder の変更と同じように承認されます。それ自体でテンプレートのソースリポジトリに戻ることはありません。 + +## 次に進む [#where-to-go-next] + +- [AI Builder](/docs/build/ai-builder):任意のテンプレートをチャットで拡張する +- [パッケージ](/docs/build/packages):テンプレートの実体 +- [マーケットプレイス](/docs/build/marketplace):フォークを配布する +- [ObjectOS Community をローカルで実行する](/docs/start/community):開発者向けの道の端から端まで From 38384aa6999ebbd4de99bfe830150606f9e2b431 Mon Sep 17 00:00:00 2001 From: Steedos Date: Thu, 29 Oct 2026 11:01:47 +0000 Subject: [PATCH 03/22] docs(i18n): translate build/automation/ and build/interface/ into ja (#388, PR 2 of 7) Adds ja translations for the 11 automation and interface pages: build/automation/{index,flows,workflows,approvals} and build/interface/{index,apps,views,forms,dashboards,pages,actions}. Both sections' meta.ja.json already match the English pages list. Refs #388 Claude-Session: https://claude.ai/code/session_01QsR2jRsjbApbf83iyTDDXm Co-Authored-By: Claude --- .../docs/build/automation/approvals.ja.mdx | 279 ++++++++++++ content/docs/build/automation/flows.ja.mdx | 404 ++++++++++++++++++ content/docs/build/automation/index.ja.mdx | 43 ++ .../docs/build/automation/workflows.ja.mdx | 181 ++++++++ content/docs/build/interface/actions.ja.mdx | 208 +++++++++ content/docs/build/interface/apps.ja.mdx | 137 ++++++ .../docs/build/interface/dashboards.ja.mdx | 201 +++++++++ content/docs/build/interface/forms.ja.mdx | 175 ++++++++ content/docs/build/interface/index.ja.mdx | 49 +++ content/docs/build/interface/pages.ja.mdx | 166 +++++++ content/docs/build/interface/views.ja.mdx | 294 +++++++++++++ 11 files changed, 2137 insertions(+) create mode 100644 content/docs/build/automation/approvals.ja.mdx create mode 100644 content/docs/build/automation/flows.ja.mdx create mode 100644 content/docs/build/automation/index.ja.mdx create mode 100644 content/docs/build/automation/workflows.ja.mdx create mode 100644 content/docs/build/interface/actions.ja.mdx create mode 100644 content/docs/build/interface/apps.ja.mdx create mode 100644 content/docs/build/interface/dashboards.ja.mdx create mode 100644 content/docs/build/interface/forms.ja.mdx create mode 100644 content/docs/build/interface/index.ja.mdx create mode 100644 content/docs/build/interface/pages.ja.mdx create mode 100644 content/docs/build/interface/views.ja.mdx diff --git a/content/docs/build/automation/approvals.ja.mdx b/content/docs/build/automation/approvals.ja.mdx new file mode 100644 index 00000000..c0d4b0ef --- /dev/null +++ b/content/docs/build/automation/approvals.ja.mdx @@ -0,0 +1,279 @@ +--- +title: 承認 +seoTitle: "承認フロー:レコードを人による承認へ回す" +description: レコードを人による承認へ回します。自動化が行レベルセキュリティを黙ってすり抜けることはさせません。 +editions: [community, cloud, enterprise] +translation: + source_sha: e03dd11f32910f971d7514f12aab8e3c2ac1eceb25966b2b4162185eb062a521 + guide_rev: 1 + mode: auto +--- + +**承認とは、承認ノードを持つ[フロー](/docs/build/automation/flows)です。フローは人が承認または却下するまで一時停止し、その後、対応する分岐に沿って再開します。** 新たに覚えるべき独立した承認エンジンはありません。トリガー、分岐、エラー処理は、ほかのフローとまったく同じように動作します。このページが加えるのは承認ノードそのものと、ルーティングと同じくらい重要な 2 つのアクセスの判断です。 + +## 誰が何をするか [#who-does-what] + +意図的に分けられた 3 つのロールです。 + +| ロール | できること | 必要なもの | +|---|---|---| +| **ビルダー** | 承認フローを作成、編集する | `manage_metadata`(通常は Studio のユーザー) | +| **申請者** | フローに入るレコードを申請する | 通常のレコードアクセス。自動化の設定は不要 | +| **承認者** | 承認依頼に対応する(承認 / 却下) | 権限セットで付与された機能 | + +エンドユーザーはレコードを申請し、依頼に対応します。自動化を編集することはありません。自動化の設定画面は、利用者向けのアプリに含めないでください。 + +## 誰として実行するか:安全上の判断 [#as-whom-does-it-run--the-safety-decision] + +フローは `runAs` を宣言します。承認にとって、これはフローが行レベルセキュリティを黙ってすり抜けないようにするための判断です。 + +| `runAs` | データ操作を実行する主体 | 使う場面 | +|---|---|---| +| `'user'`(デフォルト) | **申請者**。その RLS に従います | フローが、申請者がすでに見られるレコードにだけ触れる場合 | +| `'system'` | **昇格**。RLS をすり抜けます | 申請者が見られないレコードをフローが読み書きしなければならない場合(元帳への記帳、申請者が見られない行を所有する承認者への通知) | + +昇格は、偶然ではなく見える形にするために**明示的に**宣言します。デフォルトが `'user'` なので、承認フローが申請者に、テナントや所有者をまたぐ到達範囲を黙って与えることはできません。昇格はオプトインで、監査できます。 + +> **ヒント:** スケジュールで起動するエスカレーションには起動したユーザーがいないので、そもそも動作させるには `runAs: 'system'` でなければなりません。これが昇格の正当なケースです。「動かすためにどこでも `system`」はアンチパターンです。 + +## 承認ノード [#the-approval-node] + +ノードは**誰が承認するか**と、その判断をどう集約するかを宣言します。 + +```ts +// One flow node; the flow around it is omitted (see the complete flow below). +{ + id: 'manager_approval', + type: 'approval', + label: 'Manager Approval', + config: { + approvers: [{ type: 'field', value: 'owner_manager_id' }], + behavior: 'unanimous', + approvalStatusField: 'approval_status', + lockRecord: true, + }, +} +``` + +| 設定 | 働き | +|---|---| +| `approvers` | 誰が判断しなければならないか。下記の承認者の種類を参照 | +| `behavior` | 複数の承認者をどう集約するか:`'first_response'`(デフォルト)、`'unanimous'`、`'quorum'`、`'per_group'` | +| `minApprovals` | 必要な承認数。`quorum` では合計(N 人中 M 人)、`per_group` ではグループごと(デフォルト 1) | +| `onEmptyApprovers` | 承認者の解決結果が誰もいなかったときの動作:`'admin_rescue'`(デフォルト)、`'fail'`、`'auto_approve'` | +| `decisionOutputs` | 判断が構造化された出力としてフローに持ち帰れるキー | +| `approvalStatusField` | プラグインが依頼のステータスを反映する、省略可能なレコードのフィールド | +| `lockRecord` | 依頼が保留中の間、レコードを編集からロックします | + +`approvers` の各エントリは `type` と `value` を指定します。 + +| `type` | 解決先 | +|---|---| +| `manager` | 申請者のマネージャー(`sys_user.manager_id`)。value は取りません | +| `position` | 組織のポジションの保持者 | +| `department` | 事業単位**とそのすべての下位単位**のメンバー | +| `team` | フラットなコラボレーションチームのメンバー | +| `field` | 起動したレコードのフィールドが保持するユーザー ID | +| `user` | 名前で指定した 1 人のユーザー ID | +| `org_membership_level` | [組織メンバーシップの階層](/docs/configure/users#organization-membership-tiers)(`owner` / `admin` / `delegated_admin` / `member`) | +| `expression` | ノードに入るときに解決される CEL 式。下記を参照 | + +文字どおりの `user` ID よりも、間接的なバインディング(`manager`、`position`、`department`、`team`)を優先してください。本人がチームを移ったり退職したりしても機能し続けますが、ハードコードされた ID は、もう承認を見るべきではない人に黙って承認を回してしまいます。 + +> **警告:`position` とメンバーシップの階層。** `{ type: 'position', value: 'finance_manager' }` はポジション(`sys_user_position`)の保持者に回します。[組織メンバーシップの階層](/docs/configure/users#organization-membership-tiers)(`sys_member.role`:`owner`/`admin`/`delegated_admin`/`member`)は 16.0 以降 `type: 'org_membership_level'` で指定します。旧来の表記 `role` は **1 リリースの間だけの非推奨エイリアス**で、警告付きで今も同じように読み込まれて解決されますが、次のメジャーで削除されます。メンバーシップ階層の種類として書かれたポジション名は誰にも一致せず、依頼は止まってしまいます。`os lint` は両方のケースを指摘します(`approval-approver-not-membership-tier`、`approval-approver-type-deprecated`)。value が組織のポジションを指している場合、修正は `type: 'position'` です。 + +### クォーラムとグループごとの承認(16.0) [#quorum-and-per-group-sign-off-160] + +`first_response` と `unanimous` に加えて、16.0 では 2 つの集約モードが追加されました。**クォーラム**は N 人中 M 人の承認で確定します。 + +```ts +// The `config` of an `approval` node; the node around it is omitted. +config: { + approvers: [ + { type: 'user', value: 'director_a' }, + { type: 'user', value: 'director_b' }, + { type: 'user', value: 'director_c' }, + ], + behavior: 'quorum', + minApprovals: 2, // any 2 of the 3 approve +} +``` + +**グループごと**は、ラベル付けされた*各*グループからの承認(会签)を必要とします。承認者に `group` でラベルを付けると、すべてのグループが `minApprovals` 件の承認(デフォルトはグループごとに 1)を得たときにだけノードが先に進みます。 + +```ts +// The `config` of an `approval` node; the node around it is omitted. +config: { + approvers: [ + { type: 'position', value: 'legal_counsel', group: 'legal' }, + { type: 'position', value: 'finance_manager', group: 'finance' }, + ], + behavior: 'per_group', // one sign-off from legal AND one from finance +} +``` + +すべてのモードに共通する意味: + +- 承認者の集合は、不在時の代理を含む**依頼開始時のスナップショット**に照らして集計されます。誰が応答しなければならないかは依頼が開始されたときに確定し、不在の承認者は依頼を止めるのではなく代理に置き換えられます。 +- **1 件の却下はやはり拒否権です**。どのモードでも、ノードを `rejected` として確定させます。 +- しきい値は実行時に、解決できる承認者の数に**切り詰められる**ので、誤設定された `minApprovals` が依頼をデッドロックさせることはありません。 +- `group` ラベルのない承認者はそれぞれが独自のグループになるので、ラベルなしの承認者リストでも `per_group` のもとで妥当に動作します。 + +### 動的なルーティング:承認者が次の承認者を選ぶ(17.0) [#dynamic-routing-an-approver-picks-the-next-approver-170] + +17.0 で追加された 3 つの機能により、ノードは固定の宣言からではなく、実行がそれまでに生み出したものから承認者を決められます。 + +**`expression` 承認者**は、ノードに入るときに、3 つの明示的なルートに対して CEL 式を解決します。`current.*`(レコードの現在の状態)、`trigger.*`(申請時のスナップショット)、`vars.*`(上流ノードの出力を含むフロー変数)です。結果が承認者の顔ぶれになります。 + +```ts +// The `config` of an `approval` node; the node around it is omitted. +config: { + approvers: [ + { + type: 'expression', + value: 'vars.legal_review.picked_departments', + resolveAs: 'department', // each value is a department id, fanned out to its members + }, + ], +} +``` + +`resolveAs` は `expression` 承認者自身のキー(デフォルトは `'user'`、または `'department'` / `'position'` / `'team'`)で、式が返した ID の種類を示し、静的な承認者の種類と同じグラフ検索で各 ID を展開します。`behavior: 'per_group'` のもとでは、返された各値が独自のグループになり、返された部署ごとに 1 件の承認が必要になります。 + +`record` と素のフィールド名は意図的に**使えません**。プラットフォームのほかのすべての場面で `record` は「イベント時点のレコード」を意味しており、ここで再利用すると 2 つの時点のどちらかを黙って指してしまうからです。 + +上のような式に値を供給するのが **`decisionOutputs`** です。判断が持ち帰れるキーは*作成者*が宣言し、承認者は値を埋めるだけです。受け付けられた出力は `.` というフロー変数として実行を再開させます。素の名前には決してならないので、承認者が作成者の変数を覆い隠すことはできません。 + +```ts +// One flow node; the flow around it is omitted. +{ + id: 'legal_review', + type: 'approval', + label: 'Legal Review', + config: { + approvers: [{ type: 'position', value: 'legal_counsel' }], + decisionOutputs: [ + { key: 'picked_departments', type: 'department', multiple: true }, + ], + }, +} +``` + +エントリは、素のキー(判断の UI ではプレーンなテキスト入力としてレンダリングされます)か、型付きの宣言 `{ key, type, multiple }` のいずれかです。型付きの宣言は、判断の UI に代わりにレコードピッカーをレンダリングさせます。`user` / `department` / `position` / `team` はそれぞれ対応するシステムオブジェクトのピッカーになり、`multiple: true` は ID の配列を集めます。宣言されていないキーを持つ判断は拒否されます。`decision` と `requestId` は予約されています。 + +**`onEmptyApprovers`** は、解決結果に具体的な人が 1 人もいないとき(式の結果が空、ポジションに人がいない、複数選択フィールドが空)の動作を決めます。 + +| 値 | 動作 | +|---|---| +| `'admin_rescue'`(デフォルト) | とにかく依頼を開始し、大きく警告します。特権を持つ管理者が Reassign で引き継げます。レコードを素通りさせることも、実行を止めることもしない唯一の選択肢です | +| `'fail'` | ノードが失敗します(fault エッジ / 実行の失敗)。顔ぶれが空なら設定のバグとしか考えられない場合に選びます | +| `'auto_approve'` | 依頼をスキップし、`output.autoApproved = true` とともに `approve` エッジに沿って続行します。レコードを黙って素通りさせるので、オプトインです | + +このデフォルトは意図的なものです。承認の役目は門番なので、空の顔ぶれが黙って通ることがあってはなりません。 + +## 完全な承認フロー [#a-complete-approval-flow] + +大型の提案を所有者のマネージャーに回し、その判断で分岐します。 + +```ts +export const opportunityApproval = defineFlow({ + name: 'opportunity_approval', + label: 'Opportunity Approval', + type: 'record_change', + status: 'active', + runAs: 'user', // submitter's RLS unless a step genuinely needs more + nodes: [ + { + id: 'start', + type: 'start', + label: 'Proposal over 50,000', + config: { + triggerType: 'record-after-update', + objectName: 'opportunity', + condition: "record.amount >= 50000 && record.stage == 'proposal'", + }, + }, + { + id: 'manager_approval', + type: 'approval', + label: 'Manager Approval', + config: { + approvers: [{ type: 'field', value: 'owner_manager_id' }], + behavior: 'unanimous', + approvalStatusField: 'approval_status', + lockRecord: true, + }, + }, + { + id: 'mark_approved', + type: 'update_record', + label: 'Mark Approved', + config: { + objectName: 'opportunity', + filter: { id: '{record.id}' }, + fields: { stage: 'negotiation' }, + }, + }, + { + id: 'mark_rejected', + type: 'update_record', + label: 'Mark Rejected', + config: { + objectName: 'opportunity', + filter: { id: '{record.id}' }, + fields: { stage: 'closed_lost' }, + }, + }, + { id: 'end', type: 'end', label: 'End' }, + ], + edges: [ + { id: 'e1', source: 'start', target: 'manager_approval' }, + { id: 'approved', source: 'manager_approval', target: 'mark_approved', label: 'approve' }, + { id: 'rejected', source: 'manager_approval', target: 'mark_rejected', label: 'reject' }, + { id: 'e4', source: 'mark_approved', target: 'end' }, + { id: 'e5', source: 'mark_rejected', target: 'end' }, + ], +}); +``` + +ラベル付きのエッジに注目してください。`approve` と `reject` が判断後の分岐に名前を付けています。却下の経路は必ずモデル化してください。承認の分岐しかないフローでは、却下されたレコードが行き場を失います。 + +**多段階の承認:** 複数の `approval` ノードをつなぎます。**並行承認:** [フロー](/docs/build/automation/flows)の集約ノードのパターンを参照してください。 + +## 承認者が体験すること [#what-the-approver-experiences] + +永続的な承認の状態は `@objectstack/plugin-approvals` パッケージが管理します。依頼が保留中の間: + +1. プラグインは依頼(`sys_approval_request`)と、それに対して行われたすべての判断(`sys_approval_action`)を永続化します。承認の履歴はクエリできるデータです。 +2. `lockRecord: true` の場合、判断が下るまでレコードは編集からロックされます。 +3. `approvalStatusField` を設定すると、レコード自身のフィールドが依頼のステータスを反映するので、ビューやレポートでそれを使ってフィルターできます。 +4. 承認者が承認または却下すると、プラグインは一時停止していたフローを対応するエッジに沿って再開します。16.0 以降、判断には**添付ファイル**を付けられます(`sys_approval_action.attachments` に永続化され、decide/comment のルートとクライアント SDK を通じて受け渡されます)。署名済みの PDF や証拠は判断とともに保管されます。 +5. 依頼はサーバーで計算された **`decision_progress`** を公開します。`unanimous`/`quorum` では得た承認数と必要な承認数、`per_group` ではグループごとの内訳です。そのため受信トレイや独自の UI は、集計を再実装せずに進捗をレンダリングできます。 + +**依頼を見られるのは誰か(17.0)。** 依頼はレコードのスナップショット、判断の履歴全体、添付ファイルを持つので、読めるのはその参加者だけです。申請者、現在の承認者(依頼が待っているポジションの保持者を含む)、そしてすでに対応またはコメントした人です。プラットフォームと組織の管理者はすべての依頼を見られます。それ以外の人には何も見えず、レコードを読めるかどうかはそれを変えません。承認者で依頼リストをフィルターするのはフィルターであって付与ではありません。それを省くと、テナント全体ではなく、自分が参加している依頼だけが返されます。見える依頼の中でも、スナップショットからは、読み手がそのレコードで読めないフィールドがすべて取り除かれます。17.6 以降は、マスクされた状態でしか読めないフィールドもすべて取り除かれます。 + +**判断は宣言されたアクションです(16.0)。** 判断の全体(承認、却下、再割り当て、修正のための差し戻し(`/revise`)、情報の依頼、リマインド、取り消し、再申請)は、`sys_approval_request` 上の `type: 'api'` アクションとして宣言されており、型付きのパラメータ、保留中のときだけ表示するゲート、申請者か承認者かの述語(例:`record.submitter_id == ctx.user.id`)を持ちます。承認の受信トレイは、手書きのボタンではなく、これらの宣言されたアクションをレンダリングします。そのため新しい判断機能はメタデータとして出荷され、クライアントのリリースは必要ありません。 + +承認すること自体がゲート付きのアクションです。「承認してよい」は、承認者の権限セットで付与される機能(例:`approve_invoice`)としてモデル化し、承認アクションの `requiredPermissions` をそれでゲートします。そうすればゲートは画面から隠されるだけでなく、UI とサーバーの**両方**で強制されます。 + +## ベストプラクティス [#best-practices] + +| すること | しないこと | +|---|---| +| 明確な開始条件を定義する | 承認ステップを作りすぎる | +| 妥当なタイムアウト期間を設定する | 承認を複雑にしすぎる | +| 適切な場合は取り消しを許す | 却下の経路を忘れる | +| すべての関係者に通知する | 承認者をハードコードする | +| 承認の履歴を追跡する | 「承認」を UI でだけゲートする | +| デフォルトは `runAs: 'user'` にし、1 ステップずつ昇格する | 「動かすために」どこでも `runAs: 'system'` を設定する | + +## 次に進む [#where-to-go-next] + +| ページ | 理由 | +|---|---| +| [フロー](/docs/build/automation/flows) | このページの土台となるフローのリファレンス:トリガー、ステップ、エラー処理 | +| [ワークフロー](/docs/build/automation/workflows) | 承認が置かれるライフサイクルを制約する | +| [アクション](/docs/build/interface/actions) | 申請と承認をインターフェースのボタンとして表示する | +| [CEL 式](/docs/reference/cel) | 開始条件の背後にある言語 | +| [メール](/docs/configure/email) | 承認者と関係者に通知する | +| [自動化の概要](/docs/build/automation) | 選び方:フロー、ワークフロー、承認 | diff --git a/content/docs/build/automation/flows.ja.mdx b/content/docs/build/automation/flows.ja.mdx new file mode 100644 index 00000000..46a7b726 --- /dev/null +++ b/content/docs/build/automation/flows.ja.mdx @@ -0,0 +1,404 @@ +--- +title: フローと自動化 +description: 宣言的なビジネスロジック。AI に説明しても TypeScript で書いても、ランタイムはどちらの場合も同じ成果物を実行します。 +editions: [community, cloud, enterprise] +translation: + source_sha: 011506676f1192c1d884573299f8404d1cf906edfc56cb81b122979ba8410d43 + guide_rev: 1 + mode: auto +--- + +フローは、サーバーを書かずにビジネスロジックを表現する方法です。すべてのフローは、ランタイムが実行する宣言的なメタデータであり、オブジェクトやビューと同じです。そのため、フローは `os diff`、監査ログ、Studio のフロービルダー、そして [AI Builder](/docs/build/ai-builder) のすべてに同時に現れます。 + +ほとんどのお客様は、AI に頼んでフローを作成します。 + +> *「優先度の高いチケットが 'new' のまま 30 分経ったら、Slack でマネージャーに通知して」* + +AI はこのページで説明する形でフローのメタデータを生成するので、読んで編集できます。 + +フローはグラフです。`nodes` が作業を行い、`edges` がそれらをつなぎ、`start` ノードがフローを起動するものを示します。この形は ObjectStack の `FlowSchema` で、ObjectStack の [Flow metadata](https://objectstack.ai/docs/automation/flows) に完全に記載されています。 + +スタックでこの機能を有効にします。 + +```ts +export default defineStack({ + // ... + requires: ['automation', 'triggers'], // the flow engine, and the triggers that start flows +}); +``` + +両方のトークンが必要です。レコードの変更、スケジュール、API 呼び出しで開始するフローがあるのに `requires` にどちらかが欠けているスタックを、`defineStack` は拒否します。そのようなフローは登録されても決して実行されないからです。 + +## フローの種類 [#flow-types] + +| `type` | 起動するもの | 用途 | +|---|---|---| +| `record_change` | レコードの挿入、更新、削除。開始ノードで結び付けます | 「チケットが作成されたら担当者にメールする」 | +| `schedule` | 開始ノード上の cron スケジュール | 「毎晩午前 2 時に古いタスクをマークする」 | +| `schedule`、相対時間 *(16.0)* | 日付フィールドと今日との近さ。毎日のスイープで判定 | 「契約終了の 60 日前に通知する」 | +| `autolaunched` | アクションボタン、別のフロー、または API 呼び出し | 「請求書を承認」アクション | +| `screen` | ユーザー。1 つ以上の画面を通じて | ガイド付きのデータ入力 | +| `api` | 開始ノードの `config.secret` で署名された HTTP リクエスト | 外部システム向けのエンドポイント | + +## レコード変更:レコードの変更に反応する [#record-change-react-to-a-record-change] + +```ts +// src/flows/ticket_assigned_email.ts +import { defineFlow } from '@objectstack/spec'; + +export const ticketAssignedEmail = defineFlow({ + name: 'ticket_assigned_email', + label: 'Email the assignee of a new ticket', + type: 'record_change', + status: 'active', + nodes: [ + { + id: 'start', + type: 'start', + label: 'Ticket created', + config: { objectName: 'support_ticket', triggerType: 'record-after-create' }, + }, + { + id: 'email_assignee', + type: 'notify', + label: 'Email the assignee', + config: { + recipients: '{record.assignee}', + title: 'New ticket: {record.subject}', + message: 'You have been assigned {record.subject}, priority {record.priority}.', + channels: ['email'], + }, + }, + { id: 'end', type: 'end', label: 'End' }, + ], + edges: [ + { id: 'e1', source: 'start', target: 'email_assignee' }, + { id: 'e2', source: 'email_assignee', target: 'end' }, + ], +}); +``` + +メールは `notify` ノードを通じて送られます。独立したメールノードの種類はありません。`channels: ['email']` は、[メール](/docs/configure/email)で設定されたトランスポートを通じて、メールチャネルで通知を送ります。`channels` がなければ、通知はアプリ内の受信トレイにだけ届きます。インラインのテキストの代わりに保存済みのメールテンプレートを送るには、`title` と `message` の代わりに `template`(`sys_email_template` の名前)を設定します。 + +ノードの `config` 内のフィールド値と通知テキストはテンプレートです。`{record.}` は起動したレコードを、`{}` はフロー変数を、`{$User.Id}` は現在のユーザーを読み、`{NOW()}` / `{TODAY()}` は日付マクロです。条件は波括弧なしの素の CEL です。[条件と分岐](#conditions-and-branches)を参照してください。 + +開始ノードの `triggerType` がイベントを選び、省略可能な `condition` がそれを絞り込みます。たとえば `condition: "record.priority == 'high'"` です。 + +| `triggerType` | 発動するタイミング | +|---|---| +| `record-after-create` | 挿入の後 | +| `record-after-update` | 更新の後 | +| `record-after-delete` | 削除の後 | +| `record-after-write` | 挿入**または**更新の後 | +| `record-before-create` | 挿入の前 | +| `record-before-update` | 更新の前 | +| `record-before-delete` | 削除の前 | +| `record-before-write` | 挿入**または**更新の前 | + +更新では、`previous` が変更前のレコードを保持します:`condition: 'record.stage != previous.stage'`。同じ書き込みの中で、保存される前に保留中のレコードを変更するには、フローではなく before フックを使います。フローは保存の副作用のためのものです。レコードの作成、通知、HTTP 呼び出し、承認の依頼などです(ObjectStack の [Hooks vs flows](https://objectstack.ai/docs/automation/hooks#hooks-vs-flows))。 + +## スケジュール:時刻に従って実行する [#scheduled-run-on-a-clock] + +```ts +export const nightlyCleanup = defineFlow({ + name: 'nightly_cleanup', + label: 'Mark overdue tasks', + type: 'schedule', + status: 'active', + runAs: 'system', // a scheduled run has no user, so its data operations need an explicit identity + nodes: [ + { + id: 'start', + type: 'start', + label: 'Every night at 2am', + config: { + triggerType: 'schedule', + schedule: { type: 'cron', expression: '0 2 * * *', timezone: 'America/New_York' }, + }, + }, + { + id: 'mark_overdue', + type: 'update_record', + label: 'Mark open tasks past due', + config: { + objectName: 'task', + filter: { status: 'open', due_date: { $lt: '{TODAY()}' } }, + fields: { status: 'overdue' }, + multi: true, // update every match; without it, a filter that is not a single id is refused + }, + }, + { id: 'end', type: 'end', label: 'End' }, + ], + edges: [ + { id: 'e1', source: 'start', target: 'mark_overdue' }, + { id: 'e2', source: 'mark_overdue', target: 'end' }, + ], +}); +``` + +`@objectstack/service-job` 機能に支えられています。[ランタイム機能](/docs/reference/runtime-capabilities)を参照してください。時間で起動するフローには組織を引き継ぐ呼び出し元がいません。開始ノードで `organization` を使って組織を宣言しなければならない場合については、ObjectStack の [Flow metadata](https://objectstack.ai/docs/automation/flows#the-acting-organization) に記載されています。 + +> **スケジュールされた処理は、デプロイメントが有効にするまでオフです。** ObjectStack 17.5 以降、時間で起動するフロー(`schedule` の周期、または下記の相対時間スイープ)とパッケージ化された `defineJob` の cron ジョブは、デプロイメントが `OS_AUTOMATION_SCHEDULED_WORK_ENABLED` を `true`(または `1`、`on`、`yes`)に設定したときにだけ有効になります。未設定なら何も有効にならず、そのようなフローはそれぞれエラーではなく *disabled by deployment policy* として報告されます。オフは ObjectStack ランタイムのデフォルトです。お使いの ObjectOS イメージやそのデプロイバンドルのテンプレートがこの変数を設定してくれるかどうかは、このページでは約束できません。アプリがスケジュールフローに依存するときは明示的に設定し、実効値を表示する `os doctor` で確認してください。[環境変数](/docs/reference/environment-variables#runtime-services)を参照してください。プラットフォーム自身のスケジュール処理(承認のエスカレーション、保持期間、メッセージの配信)には影響しません。`isolated` テナンシー方式では、開始ノードで `organization` を宣言していないスケジュールフローは、スイッチがオンでも有効になりません。 + +## 相対時間:日付フィールドを基準に発動する(16.0) [#time-relative-fire-relative-to-a-date-field-160] + +「契約終了の 60 日前に通知する」は、かつては `record.end_date == daysFromNow(60)` を条件とするレコード変更フローとして作成されていました。この述語はレコードが*たまたま変更された*ときにしか評価されないので、放っておくとほとんど発動しません。そのようには書かないでください。代わりに**相対時間トリガー**を宣言します。フローの開始ノードが `config.timeRelative` 記述子を持ち、ランタイムがスケジュールに従ってオブジェクトをスイープし、**一致したレコードごとに 1 回**フローを起動します。 + +```ts +export const renewalReminder = defineFlow({ + name: 'contract_renewal_reminder', + label: 'Contract renewal reminder', + type: 'schedule', + status: 'active', + runAs: 'system', // a sweep has no user to act as + nodes: [ + { + id: 'start', + type: 'start', + label: 'Start', + config: { + timeRelative: { + object: 'contracts', + dateField: 'end_date', + offsetDays: [60, 30, 7], // T-minus thresholds + filter: { status: 'active' }, // AND-ed with the date window + }, + // Optional sweep cadence — defaults to daily at 08:00 UTC. + schedule: { type: 'cron', expression: '0 8 * * *' }, + }, + }, + { + id: 'notify_owner', + type: 'notify', + label: 'Notify Owner', + config: { recipients: '{record.owner}', title: 'Contract {record.name} ends on {record.end_date}' }, + }, + { id: 'end', type: 'end', label: 'End' }, + ], + edges: [ + { id: 'e1', source: 'start', target: 'notify_owner' }, + { id: 'e2', source: 'notify_owner', target: 'end' }, + ], +}); +``` + +| キー | 宣言するもの | +|---|---| +| `object` | スイープがレコードを問い合わせるオブジェクト(マシン名) | +| `dateField` | 今日を基準に評価される `date` / `datetime` フィールド(日単位) | +| `offsetDays` | **オフセットモード**:`dateField` がちょうど今日 + 列挙した各オフセットのときに発動します(`[60, 30, 7]`。負の値は過去で、たとえば `[-1]` は翌日) | +| `withinDays` | **範囲モード**:`dateField` が今日から N 日以内である日には毎日発動します。正の値は今後(「まもなく期限切れ」)、負の値は範囲を区切った期限超過の遡り、`0` は今日が期限 | +| `filter` | 計算された日付の範囲と AND 結合される、省略可能な ObjectQL の where マップ(例:`{ status: 'active' }`) | +| `maxRecords` | 1 回のスイープで起動するレコード数の上限(デフォルト 1000。上限で切り詰めるとスイープがログに記録します) | + +`offsetDays` と `withinDays` のどちらか**一方だけ**を設定しなければなりません。ほかによくある 2 つの形です。 + +```ts +// Two variants of the start node's config.timeRelative; the rest of the flow is as above. + +// "Expiring soon" — fires every day a document is within 30 days of expiry. +timeRelative: { object: 'hr_document', dateField: 'expires_on', withinDays: 30 } + +// Overdue sweep — fires for POs up to 14 days past due (bounded lookback). +timeRelative: { object: 'purchase_order', dateField: 'due_date', + withinDays: -14, filter: { status: 'open' } } +``` + +各起動は一致したレコードを自動化コンテキストに置くので、開始ノードの `condition` と `{record.}` の埋め込みは、レコード変更フローとまったく同じように動作します。検出のクエリはシステムとして実行され、レコードごとに障害が分離されます。`os validate` には準備状況のチェックが加わり、`timeRelative.object` がスタックで定義されていないオブジェクトを指しているとき、および自動起動のフローが `draft` ステータスのまま残っているときに警告します。 + +> **同じ日のチェックは、今は問題なく使えます(#3183)。** 16.0 では `record.due_date == today()` が一致します。エンジンが時間型の `==` / `!=` 比較を変換するので、日付フィールドが `today()` と正しく比較されます。本当に「今日が期限」という条件にはこれを使い、「日付の N 日前/後」という形のものには `timeRelative` を使ってください。 + +## 手動で開始:アクションと API 呼び出し [#started-by-hand-actions-and-api-calls] + +```ts +export const approveInvoice = defineFlow({ + name: 'approve_invoice', + label: 'Approve invoice', + type: 'autolaunched', + status: 'active', + variables: [ + { name: 'invoice_id', type: 'text', isInput: true }, + ], + nodes: [ + { id: 'start', type: 'start', label: 'Start' }, + { + id: 'approve', + type: 'update_record', + label: 'Approve the invoice', + config: { + objectName: 'invoice', + filter: { id: '{invoice_id}' }, + fields: { status: 'approved', approved_by: '{$User.Id}' }, + }, + }, + { id: 'end', type: 'end', label: 'End' }, + ], + edges: [ + { id: 'e1', source: 'start', target: 'approve' }, + { id: 'e2', source: 'approve', target: 'end' }, + ], +}); +``` + +請求書のビューで、種類が `flow` の[アクション](/docs/build/interface/actions)を使ってボタンとして表示するか、REST で呼び出します。 + +```bash +curl -X POST https://app.example.com/api/v1/automation/approve_invoice/trigger \ + -H 'Authorization: Bearer ' \ + -H 'Content-Type: application/json' \ + -d '{"params": {"invoice_id": "inv_123"}}' +``` + +入力は `isInput: true` で宣言したフロー変数で、同じ名前で `params` に入れて送ります。宣言された入力だけがバインドされます。呼び出し元のアイデンティティが実行に引き渡されるので、更新は呼び出し元の権限のもとで実行されます。 + +このルートは何が起きたかを示す HTTP ステータスで応答するので、本文の `success` フラグではなくステータスで分岐してください。ディスパッチされた実行(完了、一時停止、または[拒否](#ending-a-run-completed-or-refused))には `200`、不明なフローには `404`、オフに切り替えられたフローには `409 FLOW_DISABLED`、開始ノードのない定義には `422 FLOW_NO_START_NODE`、ディスパッチされて失敗した実行には `400 FLOW_FAILED` です。種類が `flow` のアクションも同じように応答します。[REST API → Flow status table](/docs/reference/rest-api#flow-status-table) を参照してください。 + +## ノードの種類 [#node-types] + +| ノードの `type` | 目的 | +|---|---| +| `get_record` | ObjectQL でレコードを読みます。1 件、または `limit` が 1 より大きいときはリスト | +| `create_record` / `update_record` / `delete_record` | オブジェクトに書き込みます(`multi: true` で一致したすべてを更新または削除) | +| `notify` | 通知を送ります。デフォルトはアプリ内の受信トレイ、`channels: ['email']` でメール | +| `http` | HTTP エンドポイントを呼び出します | +| `connector_action` | インストール済みのコネクタ(Slack など)でアクションを実行します | +| `script` | `config.function` で名前を指定した登録済みの関数を呼び出します | +| `decision` | エッジの条件で分岐します | +| `assignment` | フロー変数を設定します | +| `loop` | コレクションの各項目について本体の領域を 1 回ずつ実行します | +| `parallel` | 分岐の領域を並行して実行します | +| `try_catch` | 領域内の失敗を捕捉し、必要に応じて再試行します | +| `wait` | タイマーまたは名前付きシグナルまで一時停止します | +| `screen` | ユーザーの入力を待って一時停止します | +| `subflow` | 別のフローを呼び出します | +| `approval` | 承認者が判断するまでブロックします(`@objectstack/plugin-approvals` が必要) | +| `end` | 実行を終了します。デフォルトは `completed`、または理由付きの `refused`(下記) | + +### 実行の終了:完了または拒否 [#ending-a-run-completed-or-refused] + +ObjectStack 17.4 以降、`end` ノードは実行の**結果**を宣言します。断らなければならないフロー(重複、上限を超える金額など)は、失敗したり、断ったことを伝えるだけの画面を表示したりする代わりに、拒否の `end` で終わります。 + +```ts +// One flow node; the flow around it is omitted. +{ + id: 'refuse_duplicate', + type: 'end', + label: 'Refused: duplicate', + config: { + outcome: 'refused', // 'completed' (the default) | 'refused' + message: 'Refused: {record.name} is already registered.', + }, +} +``` + +拒否された実行は失敗した実行ではありません。何も例外を投げていないからです。実行は `refused` ステータスで終わり、トリガーのルートはそのステータスとともに `200` で応答し、レンダリングされた `message` は `refusalMessage` として返され、その横に `successMessage` はありません。`outcome` が `refused` のときは `message` が必須で、完了の end では拒否されます。そこでは誰の目にも触れないからです。拒否の `end` には `decision` の分岐から到達させ、すべての書き込みは拒否が通らない分岐に置いてください。 + +## 条件と分岐 [#conditions-and-branches] + +```ts +export const expenseRouting = defineFlow({ + name: 'expense_routing', + label: 'Route new expenses', + type: 'record_change', + status: 'active', + nodes: [ + { + id: 'start', + type: 'start', + label: 'Expense submitted', + config: { objectName: 'expense', triggerType: 'record-after-create' }, + }, + { id: 'check_amount', type: 'decision', label: 'Over 10,000?' }, + { + id: 'ask_approver', + type: 'notify', + label: 'Ask the approver', + config: { recipients: '{record.approver}', title: 'Expense over 10,000: {record.name}' }, + }, + { + id: 'auto_approve', + type: 'update_record', + label: 'Auto-approve', + config: { objectName: 'expense', filter: { id: '{record.id}' }, fields: { status: 'auto_approved' } }, + }, + { id: 'end', type: 'end', label: 'End' }, + ], + edges: [ + { id: 'e1', source: 'start', target: 'check_amount' }, + { id: 'e_large', source: 'check_amount', target: 'ask_approver', condition: 'record.amount > 10000' }, + { id: 'e_other', source: 'check_amount', target: 'auto_approve', isDefault: true }, + { id: 'e2', source: 'ask_approver', target: 'end' }, + { id: 'e3', source: 'auto_approve', target: 'end' }, + ], +}); +``` + +`decision` ノードは出力エッジで分岐します。エッジは `edges` に並んだ順に評価され、`condition` が成り立つ最初のものが実行され、どれも成り立たないときは `isDefault` のエッジが実行されます。`isDefault` がない場合、条件のないエッジは、一致した分岐と並んで毎回実行されます。条件が成り立つ*すべての*分岐を実行するには、decision に `config: { mode: 'inclusive' }` を宣言します。最初の一致を採用するのは ObjectStack 17.5 からのルールです。それ以前は真になったすべての分岐が実行されていました。データベースに保存された decision(Studio から保存されたもの)は、書き換えられることなく、アップグレード時に新しい意味になりました。 + +## エラー処理 [#error-handling] + +```ts +// Keys of a record_change flow on `invoice`. The nodes are omitted: `charge_card` is an +// `http` node, `mark_paid` an `update_record`, and `flag_for_review` a `notify`. +edges: [ + { id: 'e_ok', source: 'charge_card', target: 'mark_paid' }, + { id: 'e_fault', source: 'charge_card', target: 'flag_for_review', type: 'fault' }, +], +errorHandling: { strategy: 'retry', maxRetries: 3, backoffMs: 1000, backoffMultiplier: 2 }, +``` + +どちらの仕組みもなければ、ノードの失敗で実行は終了します。これらは 2 つの範囲で働きます。 + +| | 範囲 | 失敗時 | +|---|---|---| +| `fault` エッジ | 1 つのノード | 実行はハンドラーから続行し、完了します | +| `errorHandling: { strategy: 'retry', maxRetries }` | フロー全体 | フローは最初から再実行されます。最大で `maxRetries` 回まで | + +`strategy` は `'fail'`(デフォルト)、`'retry'`、`'continue'` のいずれかです。再試行は、すでに成功したすべてのノードを再生します。2 通目のメール、2 件目の作成レコードが生まれるので、失敗が局所的な場合は fault エッジを優先してください。fault エッジが処理した失敗はフローの失敗ではなく、再試行を消費せず、失敗したステップは実行のトレースに残ります。 + +## 数式と式(CEL) [#formulas-and-expressions-cel] + +条件(開始ノードの `condition`、エッジの `condition`)は **CEL**(Common Expression Language)で書きます。安全な式評価のための Google の言語です。 + +```ts +'record.amount > 10000 && record.tier == "enterprise"' +'record.stage != previous.stage' +'!isBlank(record.notes)' +``` + +`record` と `previous` は宣言されたすべてのフィールドを持ち、値のないフィールドは `null` として読まれます。そのため `has(record.notes)` が示すのはフィールドが宣言されていることで、値があることではありません。値の有無は `record.notes != null` または `isBlank(record.notes)` で確かめてください。 + +CEL はサンドボックス化されており(副作用なし、I/O なし)、サーバー側で評価され、フロービルダーで監査できます。 + +## ビジュアルビルダー [#visual-builder] + +ObjectOS には、宣言的なメタデータと相互に変換できるビジュアルフロービルダーが付属しています。エンジニアでなくてもフローを編集でき、編集結果は手で書く TypeScript と同じ形にシリアライズされます。これは Studio の **Automations** の柱です。 + +Studio から保存したフローは、インストール済みのパッケージが提供するフローと並んで、デプロイメントに保存されます。そこから 2 つのルールが導かれます。どちらも ObjectStack 17.6 からです。 + +- **パッケージ化されたフローがその名前を取ります。** パッケージ化されたフローと同じ名前を持つ保存済みのフローは隠され、実行されません。起動ログに警告が出ます。パッケージ化されたフローをカスタマイズするには、新しい名前で複製してください。 +- **保存済みのフローは `status` で切り替えます。** オン/オフのトグルが切り替えるのはパッケージ化されたフローだけです。デプロイメント内で作成したフローは、`status: 'obsolete'` で保存するとオフになり、`status: 'active'` で保存するとオンに戻ります。 + +## フローのテスト [#testing-flows] + +```bash +os test qa/ticket-email.test.json # run a Quality Protocol test suite against a running server +``` + +`os test` は、JSON のテストスイートとして書かれた Quality Protocol のシナリオを、実行中のサーバーに対して実行します。`--tags` はタグでシナリオを選びます。[CLI リファレンス](/docs/reference/cli)を参照してください。 + +## 制限とベストプラクティス [#limits--best-practices] + +- **before フックは小さく保ちます。** 書き込みトランザクションをブロックするからです。 +- **長時間実行のステップの代わりに `wait` ノードを使います。** 実行を永続的に待機させ、タイマーまたは名前付きシグナルで再開します。 +- **独立した作業には `parallel` ブロックを使います。** 分岐を並行して実行し、フローが続行する前に合流させます。 +- **冪等性が重要です。** フローレベルの再試行は、すでに成功したノードを再実行します。外部への副作用は重複を排除すべきです(フローの実行 ID をキーとして使います)。 +- **監査上重要なアクション。** 権限を変更したりレコードを削除したりするフローは、それ自体が `sys_audit_log` にログを書くべきです。 + +## 次に進む [#where-to-go-next] + +- [Webhook](/docs/configure/webhooks):外向きの通知。フローから起動されることが多いもの +- [メール](/docs/configure/email):`notify` ノードの `email` チャネルの背後にあるトランスポート +- [通知](/docs/configure/notifications):受信者、チャネル、テンプレートがどう解決されるか +- [API アクセス](/docs/configure/api-access):外部システムからフローを呼び出す +- [@objectstack/service-automation](https://github.com/objectstack-ai/objectstack/tree/main/packages/services/service-automation):実行エンジンのソース diff --git a/content/docs/build/automation/index.ja.mdx b/content/docs/build/automation/index.ja.mdx new file mode 100644 index 00000000..e9db7348 --- /dev/null +++ b/content/docs/build/automation/index.ja.mdx @@ -0,0 +1,43 @@ +--- +title: 自動化 +seoTitle: "自動化:フロー、ワークフロー、承認" +description: 用途に合ったツールを選びます。手順にはフロー、状態にはワークフロー、人による承認には承認を使います。 +editions: [community, cloud, enterprise] +translation: + source_sha: e39ead174c229520946d302d63cc2c7e6903c12d87048df02a15aed0b5ab0a84 + guide_rev: 1 + mode: auto +--- + +**自動化は、ビジネスロジックをアプリケーションコードに散らばらせるのではなく、ランタイムが実行するメタデータとして、データモデルに宣言的に結び付けます。** 3 つのツールがその範囲をカバーしており、最初に正しいものを選べば、後で作り直す手間が省けます。 + +## どれが必要か [#which-one-do-i-need] + +| 必要なもの | 使うもの | 読むもの | +|---|---|---| +| 「X が起きたら Y をする」:レコードの変更、スケジュール、ボタンのクリックで実行される手順 | **フロー** | [フロー](/docs/build/automation/flows) | +| 「このレコードはこれらの状態だけを通って進める」:管理されたライフサイクル | **ワークフロー**(ステートマシン) | [ワークフロー](/docs/build/automation/workflows) | +| 「先に進む前に人が承認しなければならない」:ルーティングされる人の判断 | **承認** | [承認](/docs/build/automation/approvals) | + +目安:**状態**はワークフローで、**手順**はフローでモデル化します。承認は別のエンジンではありません。承認とは、人が判断するまで承認ノードで一時停止するフローです。 + +## どう組み合わせるか [#how-they-combine] + +3 つは競合せず、組み合わせて使います。 + +- **ワークフロー**は、そもそもどのライフサイクル遷移が有効かを制約します。状態とその間の移動だけで、それ以外は扱いません。 +- **フロー**は、それらの遷移の前後で副作用を実行します。メールを送る、レコードを更新する、外部サービスを呼び出す、待機する、分岐する、などです。 +- フロー内の**承認ノード**は、承認者が操作するまで実行を止め、その後、承認または却下の分岐に沿って再開します。 + +つまり「ケースが new → assigned → resolved と進む」はワークフローであり、「エスカレーションされたらマネージャーに通知する」はフローであり、「5 万ドルを超える値引きには財務マネージャーの承認が必要」は承認ノードを持つフローです。 + +> **ヒント:** 要求が「X が起きたら Y をする」と読めるならフローです。「このレコードは決して状態を飛ばしてはならない」と読めるならワークフローです。ここから始めれば、選択を誤ることはほとんどありません。 + +## 次に進む [#where-to-go-next] + +| ページ | 理由 | +|---|---| +| [フロー](/docs/build/automation/flows) | フローの完全なリファレンス:トリガー、ステップの種類、エラー処理、CEL | +| [ワークフロー](/docs/build/automation/workflows) | 厳密なライフサイクルのための、状態とその許可された遷移 | +| [承認](/docs/build/automation/approvals) | 承認ノード、実行アイデンティティ、承認者の体験 | +| [CEL 式](/docs/reference/cel) | 条件と検証ルールで使われる式言語 | diff --git a/content/docs/build/automation/workflows.ja.mdx b/content/docs/build/automation/workflows.ja.mdx new file mode 100644 index 00000000..00fbe406 --- /dev/null +++ b/content/docs/build/automation/workflows.ja.mdx @@ -0,0 +1,181 @@ +--- +title: ワークフロー +seoTitle: "ワークフロー:ステートマシンとしてのレコードのライフサイクル" +description: レコードのライフサイクルをステートマシンとしてモデル化します。レコードが取りうる状態、その間で許される移動、そしてフローの方がうまくできることは何も含めません。 +editions: [community, cloud, enterprise] +translation: + source_sha: 7ec55c7f19bcf4f40b34dc0d852ea4cf3534169ad263dbdff0f1ed34fbb0c600 + guide_rev: 1 + mode: auto +--- + +**ワークフローは、レコードのライフサイクルを有限ステートマシンとしてモデル化します。レコードが取りうる状態と、その間で許される移動です。** オブジェクト上の `state_machine` 検証ルールとして宣言し、状態フィールドへのすべての書き込みがそれに照らしてチェックされます。中心となる要件が「このオブジェクトはこれらの状態だけを通って進める」であるときに使います。 + +Salesforce 風の独立した Workflow Rule という作成タイプはありません。かつての「ワークフロー」の概念は、きれいに 2 つに分かれます。 + +- **`state_machine` 検証ルール**:厳密なライフサイクル遷移のため。このページです。 +- **[フロー](/docs/build/automation/flows)**:イベントで起動する、またはスケジュールされた自動化のため。[承認](/docs/build/automation/approvals)による一時停止も含みます。 + +## ワークフローとフロー [#workflows-vs-flows] + +| | ワークフロー(ステートマシン) | フロー | +|---|---|---| +| モデル化するもの | *状態*:レコードがライフサイクルのどこにあるか | *手順*:何かが起きたときに何が起こるか | +| 答える問い | 「この遷移は今許されるか?」 | 「それについて何をするか?」 | +| 形 | 状態フィールドと、許される移動の表 | ノードとエッジ:トリガー、アクション、分岐 | +| 副作用 | なし。制約するだけです | すべて:メール、更新、HTTP、待機 | + +両者は組み合わせて使います。ステートマシンが遷移を制約し、通知、レコード更新、外部呼び出しが必要なときには、フローがその前後で副作用を実行します。 + +## ステートマシンを定義する [#define-a-state-machine] + +`new → assigned → resolved` と進まなければならず、エスカレーションの経路を持つサポートケースです。ステートマシンはオブジェクトの `validations` のひとつです。 + +```ts +import { P } from '@objectstack/spec'; +import { ObjectSchema, Field } from '@objectstack/spec/data'; + +export const SupportCase = ObjectSchema.create({ + name: 'support_case', + label: 'Support Case', + fields: { + status: Field.select({ + label: 'Status', + required: true, + options: [ + { label: 'New', value: 'new', default: true }, + { label: 'Assigned', value: 'assigned' }, + { label: 'Escalated', value: 'escalated' }, + { label: 'Resolved', value: 'resolved' }, + ], + }), + resolution: Field.textarea({ + label: 'Resolution', + requiredWhen: P`record.status == 'resolved'`, // no resolved case without one + }), + }, + validations: [ + { + type: 'state_machine', + name: 'case_lifecycle', + field: 'status', + message: 'This status change is not allowed.', + initialStates: ['new'], + transitions: { + new: ['assigned'], + assigned: ['resolved', 'escalated'], + escalated: ['resolved'], + resolved: [], + }, + }, + ], +}); +``` + +これを契約として読みます。ケースは `new` として作成され、`new` のケースは担当割り当てしかできません。`assigned` のケースは解決またはエスカレーションでき、エスカレーションされたケースは解決できます。`resolved` には何も列挙されていないので、それ以上は何も移動させられません。ステータスが `resolved` のときは `resolution` が必須なので、それなしでケースを解決する書き込みは拒否されます。 + +## 構成 [#anatomy] + +| キー | 宣言するもの | +|---|---| +| `type: 'state_machine'` | この検証ルールがステートマシンであること | +| `name` | ルールの識別子(snake_case) | +| `field` | ルールが管理する状態フィールド | +| `transitions` | 各状態 → 移動できる状態のマップ。レコードの更新時にチェックされます | +| `initialStates` | レコードを作成できる状態。挿入時にチェックされます | +| `message` | 拒否された書き込みが返すエラー | + +このルールは、すべての検証ルールに共通するキー `severity`、`events`、`active`、`priority` も受け付けます。 + +### 最終状態 [#final-states] + +リストが空の状態は最終状態で、そこから出るすべての移動が拒否されます。キーがまったくない状態は最終状態ではありません。そこではチェックに判断材料がなく、書き込みを通してしまうので、「最終」を意味するときは `[]` を宣言してください。 + +### 遷移の条件 [#conditions-on-a-transition] + +`state_machine` ルールには遷移ごとのガードがありません。移動を条件付きにするには、プラットフォームが強制する場所に条件を置きます。 + +- **ある状態に必要な値**:上の `resolution` のように、そのフィールドに `requiredWhen` を付けます。値なしでその状態に入る書き込みを拒否し、ルールより前から存在する行には手を付けません。 +- **それ以外すべて**:同じ `validations` 配列に、兄弟の `script` または `conditional` 検証ルール(CEL の述語)を置きます。 + +### イベントではなく書き込み [#writes-not-events] + +マシンは状態フィールドへの書き込み時にチェックされます。`status` を現在の値の下に列挙されていない値に変える更新は拒否され、`initialStates` 以外での挿入も同様です。宣言すべき名前付きイベントはありません。正当な移動の表がマシンのすべてです。 + +> **ヒント:** マシンは最小限に保ちます。状態とその間の移動だけです。「そしてメールを送る」と言いたくなった瞬間、ワークフローの領域を離れています。その副作用は、遷移に反応する[フロー](/docs/build/automation/flows)に置いてください。 + +## 副作用はフローに置く [#side-effects-belong-in-flows] + +ステートマシンは有効な遷移を記述するだけで、それ以外は何もしません。遷移で何かを*する*必要があるとき(営業に通知する、クローズ日を記録する、外部システムを呼び出す)は、マシンとレコード変更で起動するフローを組み合わせます。 + +```ts +export const dealClosedWon = defineFlow({ + name: 'deal_closed_won', + label: 'Deal closed won', + type: 'record_change', + status: 'active', + nodes: [ + { + id: 'start', + type: 'start', + label: 'Stage moved to closed won', + config: { + triggerType: 'record-after-update', + objectName: 'opportunity', + condition: "record.stage == 'closed_won' && previous.stage != 'closed_won'", + }, + }, + { + id: 'set_closed_date', + type: 'update_record', + label: 'Set Closed Date', + config: { + objectName: 'opportunity', + filter: { id: '{record.id}' }, + fields: { closed_date: '{TODAY()}' }, + }, + }, + { + id: 'notify_sales', + type: 'notify', + label: 'Notify Sales', + config: { recipients: '{record.owner}', title: 'Deal won: {record.name}' }, + }, + { id: 'end', type: 'end', label: 'End' }, + ], + edges: [ + { id: 'e1', source: 'start', target: 'set_closed_date' }, + { id: 'e2', source: 'set_closed_date', target: 'notify_sales' }, + { id: 'e3', source: 'notify_sales', target: 'end' }, + ], +}); +``` + +マシンは商談が正当に `closed_won` へ*到達した*ことを保証し、フローはその後に起こることを処理します。上のような条件は CEL 式です。[CEL](/docs/reference/cel) を参照してください。 + +## ワークフロールールからの移行 [#migrating-from-workflow-rules] + +Workflow Rules を持つプラットフォームから来た場合の対応は次のとおりです。 + +| 旧来の概念 | 現在の対応するもの | +|---|---| +| Workflow Rule | フロー | +| 時間トリガー(「日付の N 日前/後」) | 相対時間トリガー:フローの開始ノードの `config.timeRelative`(16.0、[フロー](/docs/build/automation/flows)を参照) | +| 時間トリガー(固定時刻) | スケジュールフロー | +| 項目自動更新アクション | `update_record` ノード | +| メールアラート | `notify` ノード | +| HTTP 呼び出し | `http` ノード | +| 承認プロセス | 1 つ以上の `approval` ノードを持つフロー | + +判断の基準:旧ルールが「X が起きたら Y をする」なら、小さなフローとしてモデル化します。「日付フィールドの N 日前/後に Y をする」なら、相対時間トリガーを宣言します。レコード変更フローに日付が等しいという条件を付けてはいけません。それはレコードがたまたま変更されたときにしか評価されないからです。「このレコードは管理された状態を通って進まなければならない」なら、`state_machine` 検証ルールを宣言し、副作用にはフローを使います。 + +## 次に進む [#where-to-go-next] + +| ページ | 理由 | +|---|---| +| [フロー](/docs/build/automation/flows) | 遷移の前後の副作用:トリガー、ステップ、エラー処理 | +| [承認](/docs/build/automation/approvals) | フロー内の一時停止としての、人による承認 | +| [検証ルール](/docs/build/data/validation-rules) | ステートマシンが属するルールの系統 | +| [CEL 式](/docs/reference/cel) | `requiredWhen`、検証ルール、フロー条件の背後にある言語 | +| [データモデリング](/docs/build/data) | ライフサイクルを制約するオブジェクト | +| [自動化の概要](/docs/build/automation) | 選び方:フロー、ワークフロー、承認 | diff --git a/content/docs/build/interface/actions.ja.mdx b/content/docs/build/interface/actions.ja.mdx new file mode 100644 index 00000000..c89a8f0a --- /dev/null +++ b/content/docs/build/interface/actions.ja.mdx @@ -0,0 +1,208 @@ +--- +title: アクション +seoTitle: "アクション:REST エンドポイント、ボタン、AI ツール" +description: プラットフォームが 1 つの宣言から REST エンドポイント、ボタン、AI ツールとして公開する、名前付きの操作。 +editions: [community, cloud, enterprise] +translation: + source_sha: 85e291bd4a1a724fe1ba2fbbf181d61ab30004d9389a19eaee2e9ae3175b1096 + guide_rev: 1 + mode: auto +--- + +**アクション**は、オブジェクトに対する名前付きの操作です。一度宣言すると、次のものとして現れます。 + +- `/api/v1/actions//` の **REST エンドポイント** +- レコード詳細ページの**ボタン** +- エージェントと AI Builder 向けの **AI ツール**(`action_`)。AI に公開したとき(`ai.exposed`、[下記](#from-an-ai-agent))に限ります + +3 つの画面で同じことを繰り返す必要はありません。1 つの宣言で、3 通りの呼び出し方ができます。作業が 1 ステップで終わらないときは、アクションから[フロー](/docs/build/automation/flows)を開始することもできます(`type: 'flow'`)。 + +## アクションを宣言する [#declare-an-action] + +```ts +// src/actions/approve_invoice.action.ts +import { Action } from '@objectstack/spec/ui'; + +export const approveInvoice = Action.create({ + name: 'approve_invoice', // lowercase snake_case (machine id) + label: 'Approve Invoice', + objectName: 'invoice', // attaches to the invoice object + icon: 'check', + variant: 'primary', + locations: ['record_header'], // where the button shows + description: 'Approve this invoice?', // shown in the param dialog + successMessage: 'Invoice approved', + refreshAfter: true, + + // collect input before running + params: [ + { name: 'note', label: 'Approval note', type: 'textarea' }, + ], + + // only show the button when the record is still pending + visible: 'record.status == "pending"', + + // expose it to agents and the AI Builder as `action_approve_invoice` + ai: { + exposed: true, + description: 'Approve a pending invoice, recording the approver and an optional note.', + }, + + // what it does — a sandboxed script body. `input` is the params bag; + // `ctx.record` is a read-only snapshot, so the write goes through `ctx.api`, + // which needs the `api.write` capability + type: 'script', + body: { + language: 'js', + capabilities: ['api.write'], + source: ` + await ctx.api.object('invoice').update({ + id: ctx.recordId, + status: 'approved', + approved_by: ctx.user.id, + approved_at: new Date().toISOString(), + approval_note: input.note, + }); + `, + }, +}); +``` + +`os dev` が再コンパイルした後: + +- `POST /api/v1/actions/invoice/approve_invoice` が動作します +- 請求書のレコードページに **Approve Invoice** ボタンが表示されます +- AI アシスタントは、スキルが許可していれば `action_approve_invoice` を呼び出せます。AI に公開されているからです + +## アクションの種類 [#action-types] + +`type` フィールドが、アクションが何をするかを決めます。 + +| `type` | 実行されるもの | 用途 | +|---|---|---| +| `script` | `body`:L1 の数式、またはサンドボックス化された L2 の JavaScript | ほとんどの場合。サーバー側のロジックで、監査でき、公開すれば AI から呼び出せます | +| `api` | `target` エンドポイントへの HTTP 呼び出し(`method`、`bodyExtra`) | データ API やプラットフォームのエンドポイントの再利用 | +| `flow` | `target` で名前を指定したフローを実行します | 多段階のビジネスプロセス | +| `url` | `target` の URL に移動します | ディープリンク、リダイレクト型のアクション | +| `modal` | `target` で名前を指定したページ / モーダルを開きます | カスタムのダイアログ | +| `form` | `target` で名前を指定した FormView を開きます | ガイド付きのデータ入力 | + +```ts +// api type — reuse a data-API endpoint +Action.create({ + name: 'archive_order', + objectName: 'order', + label: 'Archive', + locations: ['list_item'], + type: 'api', + method: 'PATCH', + target: '/api/v1/data/order/{id}', + bodyExtra: { archived: true }, +}); +``` + +`script` 以外の種類には `target` が必要です。どの種類でも 1 つの宣言ですが、`url`、`modal`、`form` のアクションは UI でしか実行されないので、AI ツールになることはありません。 + +## アクションを呼び出す [#calling-an-action] + +### REST [#rest] + +```bash +# the record id can go in the body, or in the path +curl -X POST https://app.example.com/api/v1/actions/invoice/approve_invoice/inv_123 \ + -H 'Authorization: Bearer ' \ + -H 'Content-Type: application/json' \ + -d '{"note": "LGTM"}' +``` + +パラメータはリクエスト本文にフラットに入れて送ります。レコード ID は、末尾のパスセグメント(`.../approve_invoice/:recordId`)としても本文の中でも指定できます。レスポンスは、スクリプト本体の戻り値です(`api` の種類のアクションでは呼び出しの結果)。 + +### UI から [#from-the-ui] + +ボタンをどこに表示するかはアクション自身で宣言します。`locations`(`record_header`、`record_more`、`list_item`、`list_toolbar` など)と `order` です。その後、`visible` の述語がレコードごとにレンダリングするかどうかを決めます。リストビューでも、各行と行の選択に対するアクションを名前で指定できます。 + +```ts +// One list view; the container and `data` are omitted (see Views). +{ + type: 'grid', + columns: ['number', 'customer', 'amount', 'status'], + rowActions: ['approve_invoice', 'reject_invoice'], + bulkActions: ['send_to_customer'], +} +``` + +### フローとともに [#with-a-flow] + +アクションを呼び出すフローのノードはありません。逆向きにしてください。多段階のロジックをフローに置き、`type: 'flow'` と、`target` にフローの名前を指定したアクションからそれを開始します。 + +```ts +// flow type — start a flow by name +Action.create({ + name: 'run_invoice_approval', + objectName: 'invoice', + label: 'Run approval', + locations: ['record_more'], + type: 'flow', + target: 'approve_invoice', +}); +``` + +### AI エージェントから [#from-an-ai-agent] + +アクションがエージェントに届くのは、作成者が AI に公開したときだけです。上の例のように、UI なしで実行される種類(`script`、`flow`、`api`)で、`ai: { exposed: true }` と 40 文字以上の `ai.description` を指定します。公開されたアクションは、ObjectOS 自身のエージェントと AI Builder では `action_` ツールになり、[MCP クライアント](/docs/configure/mcp)では `run_action` になります。公開されていなければ、エージェントからは見えず、呼び出されても拒否されます。 + +`approve_invoice` が公開されていて、エージェントが持つスキルに含まれていれば、LLM はそれを呼び出せます。入力は会話から得られ、ユーザーがボタンを押した場合と同じ呼び出し時のチェックが適用されます。 + +> *「請求書 INV-2042 を、メモ『電話で確認済み』を付けて承認して。」* + +## 権限 [#permissions] + +誰がアクションを実行できるかは、呼び出されたときに、呼び出し元としてチェックされます。REST からでも、ボタンからでも、エージェントからでも同じです。 + +1. **`requiredPermissions`**:呼び出し元の[権限セット](/docs/configure/permissions/permission-sets)が持っていなければならない機能です。1 つでも欠けている呼び出し元は `403` を受け取ります。 +2. **対象のレコード**:呼び出し元として読み込まれます。呼び出し元が読めないレコードは、見つからないものとして応答されます。 +3. **AI への公開**:エージェントが届くのは、AI に公開されたアクションだけです。 +4. **UI のゲート**:`visible` と `disabled` の述語(CEL。`record`、`os.user`、パラメータに対して評価されます)が、ボタンをレンダリングするか、グレーアウトするかを制御します。 + +その後アクションが行うことは、信頼されたアプリのコードです。`script` 本体の読み書きはアプリの権限で実行され、レコードアクセスとフィールドレベルのセキュリティはそれを制限**しません**。`flow` アクションはフローの `runAs` に従います。そのため、機密性のあるものには `requiredPermissions` を宣言し、アクションを書くことはコードレビューに値する行為として扱ってください。 + +## 組み込みのアクション [#built-in-actions] + +すべてのオブジェクトには、これらが無償で用意されます。 + +| アクション | 働き | +|---|---| +| `create` | レコードを挿入します | +| `update` | レコードを更新します | +| `delete` | レコードを削除(またはソフト削除)します | +| `restore` | ソフト削除を取り消します | +| `clone` | レコードをディープコピーします | +| `share` | ユーザー、チーム、ポジション、事業単位、または単位とその配下に直接共有します | + +これらを再宣言しないでください。オブジェクトの[ライフサイクルと機能のフラグ](/docs/build/data)に従います。 + +## 監査 [#auditing] + +プラットフォームのイベントは、変更不可能な証跡である `sys_audit_log` に記録されます。次のようなフィールドがあります。 + +- `user_id`:操作を起こしたユーザー +- `action`:アクションの名前 +- `object_name` と `record_id`:何に触れたか +- `old_value` / `new_value`:変更内容 +- `ip_address` / `user_agent`:リクエストの発信元 +- `created_at`:いつ起きたか + +*「誰がボタンを押したのか?」* という質問には、まずここを見てください。 + +## AI Builder でアクションを生成する [#generating-actions-with-the-ai-builder] + +> *「`support_ticket` に `escalate_ticket` というアクションを作って。優先度を urgent に設定し、オンコールのエンジニアに割り当てるもの。」* + +[AI Builder](/docs/build/ai-builder) はアクションのメタデータを生成し、変更を承認待ちのキューに入れます。承認後、アクションは REST、UI、そして再帰的に AI 自身から呼び出せるようになります。 + +## 次に進む [#where-to-go-next] + +- [フロー](/docs/build/automation/flows):`type: 'flow'` のアクションが開始する多段階のロジック +- [エージェント](/docs/build/agents):アクションを AI ツールとして公開する +- [API アクセス](/docs/configure/api-access):外部システムからアクションを呼び出す +- [権限](/docs/configure/permissions):誰が何を呼び出せるかをゲートする diff --git a/content/docs/build/interface/apps.ja.mdx b/content/docs/build/interface/apps.ja.mdx new file mode 100644 index 00000000..d11da2d9 --- /dev/null +++ b/content/docs/build/interface/apps.ja.mdx @@ -0,0 +1,137 @@ +--- +title: アプリ +seoTitle: "アプリ:ナビゲーション、ブランディング、対象者のゲート" +description: オブジェクト、ビュー、ページ、ダッシュボードを、ブランド付きでナビゲーションできる外枠にまとめ、誰が何を見るかを正確にゲートします。 +editions: [community, cloud, enterprise] +translation: + source_sha: 92a61a2c5ecd3b085a106339e991600fa0fc1dc9db0194a67c257c4946b4f080 + guide_rev: 1 + mode: auto +--- + +**アプリ**は、オブジェクト、ビュー、ページ、ダッシュボードをひとつのまとまった体験にまとめる論理的なコンテナです。ナビゲーションツリー、ブランディング、そして決定的に重要な、誰が入れるかを定義します。 + +```ts +import { App } from '@objectstack/spec/ui' + +export const CrmApp = App.create({ + name: 'crm_app', + label: 'CRM', + icon: 'briefcase', + branding: { primaryColor: '#2563EB' }, + navigation: [ + { id: 'group_sales', type: 'group', label: 'Sales', icon: 'briefcase', children: [ + { id: 'nav_leads', type: 'object', objectName: 'crm_lead', label: 'Leads', icon: 'funnel' }, + { id: 'nav_accounts', type: 'object', objectName: 'crm_account', label: 'Accounts', icon: 'building' }, + ]}, + ], + requiredPermissions: ['crm_access'], +}) +``` + +## アプリのプロパティ [#app-properties] + +| プロパティ | 型 | 必須 | 説明 | +|:--|:--|:--|:--| +| `name` | `string` | はい | マシン名(`snake_case`) | +| `label` | `string` | はい | 表示名 | +| `icon` | `string` | — | アプリのアイコン(Lucide) | +| `description` / `version` | `string` | — | 一覧表示用のメタデータ | +| `active` | `boolean` | — | アプリが有効かどうか(デフォルト `true`) | +| `isDefault` | `boolean` | — | これがデフォルトのアプリかどうか | +| `navigation` | `NavigationItem[]` | — | ナビゲーションツリー | +| `branding` | `AppBranding` | — | `primaryColor`、`logo`、`favicon` | +| `requiredPermissions` | `string[]` | — | そもそも誰がアプリを開けるか | +| `homePageId` | `string` | — | ランディングページとして使うナビゲーション項目の `id` | + +## ナビゲーション項目 [#navigation-items] + +ナビゲーションツリーは 8 種類の項目をサポートします。よく使う 5 つは `object`、`dashboard`、`page`、`url`、`group` で、仕様ではほかに `report`、`action`、`component` の項目も定義されています。 + +| `type` | 着地先 | 主な設定 | +|:--|:--|:--| +| `object` | オブジェクトのリストビュー | `objectName`、および省略可能なターゲット指定(下記) | +| `dashboard` | ダッシュボード | `dashboardName` | +| `page` | カスタムページ | `pageName`、省略可能な `params` | +| `url` | 外部の URL | `url`、`target: '_blank'` | +| `group` | 折りたたみ可能なセクション | `children`、`expanded` | + +すべての項目は一意な `id`(小文字の `snake_case`)を宣言**しなければなりません**。`homePageId` が参照するのはこれです。共通のプロパティ:`label`、`icon`、`order`、`badge`、そして下記の 3 つのゲートです。 + +### オブジェクトのエントリのターゲット指定 [#targeting-an-object-entry] + +3 つの省略可能なフィールドで `object` エントリの着地先を絞り込めます。優先順位は `recordId` → `filters` → `viewName` です。 + +- `viewName`:エントリを名前付きのリストビューに固定します。 +- `recordId`:単一のレコードへのディープリンク(「マイプロフィール」)。`{current_user_id}` / `{current_org_id}` のテンプレート変数をサポートします。 +- `filters`:一回限りのパラメータ付きの切り出しです。エントリは素のデータ画面に着地し、各条件は削除できる URL のフィルターチップになります。ビューを作成せずに「自分に割り当てられたもの」のリンクを作るのに最適です。セキュリティ機能ではありません。何を表示するかは、引き続き行レベルの権限が決めます。 + +```ts +// One navigation item of an app. +{ id: 'nav_my_open', type: 'object', label: 'My Open Deals', objectName: 'opportunity', + filters: { owner_id: '{current_user_id}', status: 'open' }, icon: 'user-check' } +``` + +### モバイルのナビゲーション [#mobile-navigation] + +モバイル専用のナビゲーションブロックはありません。`mobileNavigation` は、どのレンダラーも読み取っていなかったため、ObjectStack 17.0 で削除されました。 + +## 対象者によるアプリのゲート [#gating-apps-by-audience] + +同じデータが、まったく異なる 2 つの対象者に役立ちます。スキーマを設計する**ビルダー**と、データを入力して読むだけの**エンドユーザー**です。これらの画面はデフォルトで分けてください。各管理者が手で隠すことに頼ってはいけません。 + +| 対象者 | 画面 | ゲートするもの | +|:--|:--|:--| +| エンドユーザー(利用者) | 厳選されたアプリ → `page` / `view` のエントリ | `App.requiredPermissions`、ナビゲーション項目のゲート | +| ビルダー / 管理者 | Setup / Studio、素のオブジェクトテーブル | 機能:`setup.access`、`studio.access`、`manage_metadata` | + +組み込みの権限セットはすでにこの区分を表しています。`member_default` と `viewer_readonly` は `studio.access` / `manage_metadata` を持た**ない**ので、これらの権限セットのユーザーにはビルダー向けの画面が見えません。`admin_full_access` と `organization_admin` は持っています。 + +各ナビゲーション項目は、独立した 3 つのゲートをサポートします。 + +| ゲート | 型 | 次の場合を除き項目を隠す…… | +|:--|:--|:--| +| `requiredPermissions` | `string[]` | ユーザーが RBAC の機能(例:`manage_metadata`)を持っている | +| `visible` | CEL 式 | 述語が真と評価される(例:`'org_admin' in current_user.positions`) | +| `requiresObject` / `requiresService` | `string` | 指定したオブジェクト / カーネルサービスがインストールされている | + +```ts +// Keys of an app; its other keys are omitted. +navigation: [ + { id: 'nav_contacts', type: 'object', label: 'Contacts', objectName: 'showcase_contact' }, + // Builder-only entry — consumers never render it: + { id: 'nav_designer', type: 'component', label: 'Object Designer', + componentRef: 'metadata:resource', params: { type: 'object' }, + requiredPermissions: ['manage_metadata'] }, +] +``` + +> **無効化せず、隠します。** 無効化されていても見えているビルダー向けのエントリは、やはりノイズです。ゲートされたナビゲーション項目は、その機能を持たないユーザーには*レンダリングされません*。エンドユーザーを混乱させるグレーアウトした部品はありません。 + +利用者向けの画面をすっきり保つ習慣がさらに 2 つあります。 + +- **エンドユーザーには素のテーブルではなくページを渡します。** `page` エントリなら、公開するものを正確に厳選できます。選んだ列、固定された可視化、有効にしたフィルターとアクションだけです。`object` エントリは制限の緩いグリッドを与えます。切り替え可能なビュー、個人用ビュー、完全なツールバーです。 +- **データ画面そのものを厳選します。** 素のオブジェクトの読み取り権限を与えて 40 列のグリッドにユーザーを放り込むよりも、[厳選したビュー](/docs/build/interface/views)を優先してください。 + +アクションのゲートは両面です。UI がボタンを隠すか無効にし、**かつ**サーバーが呼び出しを拒否します。「UI ではゲートされているがサーバーでは開いている」という落とし穴はありません。[アクション](/docs/build/interface/actions)を参照してください。 + +## Setup アプリ:組み込みの例 [#the-setup-app--a-built-in-example] + +プラットフォーム自身の管理 UI である **Setup アプリ**も、同じアプリのメタデータプロトコルからレンダリングされています。ナビゲーション、ページ、ゲートはデータとして宣言され、あなたのアプリと同じレンダラーが描画します。そのゲートは、あなたのビルダー向け画面がそうあるべきとおりのものです。利用者向けの権限セットが持たない `setup.access` 機能の背後にあります。メタデータとしてのアプリがスケールする証拠が欲しいなら、すでにそれを使っています。 + +## アンチパターン [#anti-patterns] + +- **すべてのエンドユーザーをビルダー並みの共同作業者にして**、タブを 1 つずつ隠すこと。利用者とビルダーの区分をデフォルトにしてください。 +- **ビルダー向けのエントリを隠さずに無効化すること。** 見えているのに動かない部品は、やはり混乱を招きます。 +- 厳選したページでエンドユーザーに必要なものを正確に公開できるのに、**素のオブジェクトの読み取り権限を与えること**。 + +## 次に進む [#where-to-go-next] + +| ページ | 理由 | +|:--|:--| +| [ビュー](/docs/build/interface/views) | `object` のナビゲーションエントリの着地先 | +| [ページ](/docs/build/interface/pages) | エンドユーザー向けの厳選された `page` エントリ | +| [ダッシュボード](/docs/build/interface/dashboards) | `dashboard` エントリがレンダリングするもの | +| [アクション](/docs/build/interface/actions) | ボタンとその両面のゲート | +| [権限](/docs/configure/permissions) | `requiredPermissions` の背後にある権限セット | +| [インターフェースの概要](/docs/build/interface) | すべての部品がどう組み合わさるか | diff --git a/content/docs/build/interface/dashboards.ja.mdx b/content/docs/build/interface/dashboards.ja.mdx new file mode 100644 index 00000000..04155fc1 --- /dev/null +++ b/content/docs/build/interface/dashboards.ja.mdx @@ -0,0 +1,201 @@ +--- +title: ダッシュボード +seoTitle: "ダッシュボードの構築:データセット、ウィジェット、ドリルダウン" +description: 名前付きデータセットにバインドされたチャートウィジェットで構築する分析ページ。グローバルフィルター、自動更新、元のレコードへのドリルスルーを備えます。 +editions: [community, cloud, enterprise] +translation: + source_sha: c67b6877ef40bb832312c2b13597c8aa27a0351ad3ce7bd72469323bdef0ddc6 + guide_rev: 1 + mode: auto +--- + +**ダッシュボードはウィジェットのグリッドであり、すべてのウィジェットはデータセットにバインドします。** データセットはセマンティックレイヤーで、基になるオブジェクト、結合、ディメンション、メジャーを持ちます。ウィジェットはそれらを名前で選ぶので、「売上」は、それを使うすべてのダッシュボードとレポートで同じ意味になります。 + +```ts +// One dashboard, bound to the `sales` dataset defined below. +const salesDashboard = { + name: 'sales_overview', + label: 'Sales Overview', + description: 'Key sales metrics and pipeline analysis', + refreshIntervalSeconds: 300, // auto-refresh every 5 minutes + + dateRange: { + field: 'close_date', + defaultRange: 'this_quarter', + allowCustomRange: true, + }, + + widgets: [ + { id: 'total_revenue', title: 'Total Revenue', type: 'metric', + dataset: 'sales', values: ['revenue'], + layout: { x: 0, y: 0, w: 3, h: 2 } }, + { id: 'revenue_by_region', title: 'Revenue by Region', type: 'bar', + dataset: 'sales', dimensions: ['region'], values: ['revenue'], + layout: { x: 3, y: 0, w: 6, h: 4 } }, + { id: 'deals_by_month', title: 'Deals by Month', type: 'pie', + dataset: 'sales', dimensions: ['close_month'], values: ['deal_count'], + layout: { x: 9, y: 0, w: 3, h: 4 } }, + ], +} +``` + +## ダッシュボードのプロパティ [#dashboard-properties] + +| プロパティ | 型 | 必須 | 説明 | +|:--|:--|:--|:--| +| `name` | `string` | はい | マシン名(`snake_case`) | +| `label` | `string` | はい | 表示ラベル | +| `description` | `string` | — | ダッシュボードの説明 | +| `widgets` | `DashboardWidget[]` | はい | チャートと指標のウィジェット | +| `refreshIntervalSeconds` | `number` | — | 自動更新の間隔(秒) | +| `dateRange` | `object` | — | グローバルな日付範囲のフィルター | +| `globalFilters` | `GlobalFilter[]` | — | 対話的なフィルターコントロール | + +## まずデータセット [#datasets-first] + +データセットを一度定義し、すべてのウィジェットをそれにバインドします。 + +```ts +import { defineDataset } from '@objectstack/spec/ui' + +export const salesDataset = defineDataset({ + name: 'sales', + label: 'Sales', + object: 'opportunity', + include: ['account'], + dimensions: [ + { name: 'region', field: 'account.region', type: 'string' }, + { name: 'close_month', field: 'close_date', type: 'date', dateGranularity: 'month' }, + ], + measures: [ + { name: 'revenue', field: 'amount', aggregate: 'sum' }, + { name: 'deal_count', aggregate: 'count' }, + ], +}) +``` + +集計はウィジェットではなく、データセットのメジャー(`aggregate`)に置かれます:`count`、`sum`、`avg`、`min`、`max`、`count_distinct`、`array_agg`、`string_agg`。ウィジェットの `dimensions` と `values` は、バインドしたデータセットで宣言された名前を参照しなければなりません。 + +実行時、データセットのクエリは分析サービスを通じて実行され、基になるオブジェクトと結合したオブジェクトに、呼び出し元の行レベルセキュリティの範囲が自動的に適用されます。ダッシュボードが、ユーザーの[権限](/docs/configure/permissions)では見られないレコードを見せることはありません。 + +> 16.0 以降、ウィジェットのスキーマは**厳格**です。宣言されていないトップレベルのキー(入力ミス、ハルシネーションによるキー、削除されたインラインクエリのキー(`object` + `categoryField` + `valueField` + `aggregate`、ピボットの `rowField` / `columnField`))は、**問題のキーを名指しするパースエラー**になり、データセットの形を示します。何もレンダリングしないウィジェットへと黙って取り除かれることは、もうありません。データセットを定義してウィジェットをそれにバインドしてください。`options` は、レンダラー固有の追加設定のための自由形式の逃げ道として残っています。 + +## ウィジェット [#widgets] + +| プロパティ | 型 | 必須 | 説明 | +|:--|:--|:--|:--| +| `id` | `string` | はい | 一意なウィジェット ID(`snake_case`) | +| `dataset` | `string` | はい | バインドするデータセットの名前 | +| `values` | `string[]` | はい | メジャーの名前(少なくとも 1 つ) | +| `dimensions` | `string[]` | — | ディメンションの名前:X / グループ / 分割 | +| `type` | `ChartType` | — | 可視化の種類(デフォルト `metric`) | +| `title` / `description` | `string` | — | 表示用のタイトルとサブタイトル | +| `filter` | `FilterCondition` | — | 表示範囲のフィルター | +| `layout` | `object` | — | グリッド上の位置(省略時は自動配置) | +| `colorVariant` | `enum` | — | KPI / カードのアクセントカラー | +| `compareTo` | `enum \| object` | — | 期間比較のウィンドウ | +| `filterBindings` | `object` | — | ウィジェットごとのグローバルフィルターの対応付け(下記) | + +### チャートの種類 [#chart-types] + +| 種類 | 最適な用途 | +|:--|:--| +| `metric` *(デフォルト)* | 単一の数値の KPI:売上、件数、割合 | +| `bar` / `horizontal-bar` / `column` | カテゴリーの比較 | +| `line` | 時間の経過による傾向 | +| `pie` / `donut` | 分布 | +| `area` | 時間の経過による量 | +| `scatter` | 相関 | +| `radar` | 多次元の比較 | +| `funnel` | コンバージョンの段階 | +| `gauge` / `solid-gauge` / `bullet` / `kpi` | 目標に対する進捗 | +| `treemap` / `sankey` | 階層の比率 / 流れ | +| `table` | 詳細なレコード:**ドリルスルー** | +| `pivot` | クロス集計:**ドリルスルー** | + +### レイアウト [#layout] + +ウィジェットは 12 列のグリッドに配置されます。 + +```ts +// Keys of a dashboard widget; its other keys are omitted. +layout: { + x: 0, // column position (0-11) + y: 0, // row position + w: 6, // width in columns (1-12) + h: 4, // height in rows +} +``` + +## ドリルダウン [#drill-down] + +`table` と `pivot` のウィジェットは**ドリルスルー**できます。集計された行やセルをクリックすると、そのグループの背後にある*元のレコード*を一覧するサイドドロワーが開きます。データセットは生のグループキーを保持しているので、ドロワーのフィルターは正確なレコードに一致します。ラベルから ID を推測することはありません。ドロワー内の任意の行をクリックすると、そのレコードの詳細が開きます。**グループ → レコード一覧 → レコード**という一連の流れです。 + +ドロワーには **"Open in list →"** という逃げ道もあり、同じドリルのフィルターで範囲を絞ったまま、のぞき見をオブジェクトの完全なリストページ(並べ替え、一括選択、エクスポート、共有できる URL)に格上げします。 + +チャートのウィジェットも同じようにドリルできます。棒、点、扇形をクリックすると、ドロワーにそのバケットのレコードが一覧されます。日付のディメンションなら、そのバケットの日付範囲ぴったりです。データセットが基になるオブジェクトを公開し、ウィジェットが少なくとも 1 つのディメンションでグループ化していれば、ドリルスルーは自動的に働き、ウィジェットごとの設定は不要です。`metric` のタイルは集計値だけを表示します。[レポート](/docs/build/reports)も同じようにドリルスルーできます。 + +## グローバルな日付範囲とフィルター [#global-date-range-and-filters] + +グローバルな時間のフィルターはすべてのウィジェットに適用されます。 + +```ts +// Keys of a dashboard; its other keys are omitted. +dateRange: { field: 'created_at', defaultRange: 'this_month', allowCustomRange: true } +``` + +プリセットの範囲:`today`、`yesterday`、`this_week`、`last_week`、`this_month`、`last_month`、`this_quarter`、`last_quarter`、`this_year`、`last_year`、`last_7_days`、`last_30_days`、`last_90_days`、`custom`。 + +対話的なグローバルフィルターも同じように働きます。 + +```ts +// Keys of a dashboard; its other keys are omitted. +globalFilters: [ + { name: 'region', field: 'region', label: 'Region', type: 'select' }, + { field: 'owner', label: 'Sales Rep', type: 'lookup' }, +] +``` + +各フィルターの `name`(デフォルトは `field`)がその安定した識別子です。ウィジェットが `filterBindings` で参照するキーであり、ウィジェットの式の中で `page.` として読めるダッシュボードレベルの変数です。`dateRange` という名前は組み込みの日付範囲のために予約されています。 + +### ウィジェットごとのフィルターのバインディング [#per-widget-filter-bindings] + +デフォルトでは、フィルターはすべてのウィジェットで自身の `field` に適用されます。ウィジェットがその概念を別のフィールドに保持している場合、またはフィルターを無視すべき場合は、`filterBindings` を宣言します。 + +```ts +// Keys of a dashboard; each widget's dataset, values and title are omitted (`/* … */`). +widgets: [ + // Default binding: dateRange → created_at, region → region. + { id: 'invoices_by_status', /* … */ }, + // This widget's fields differ — map each filter explicitly. + { id: 'accounts_signed', + filterBindings: { dateRange: 'signed_at', region: 'sales_region' }, /* … */ }, + // Opt out of a filter with `false`. + { id: 'total_invoices', filterBindings: { region: false }, /* … */ }, +] +``` + +> 優先順位:明示的な `filterBindings` のエントリ(文字列による上書き、または `false` によるオプトアウト)→ フィルターの旧来の `targetWidgets` 許可リスト → フィルター自身の `field`。 + +## ダッシュボードを表示する [#surfacing-a-dashboard] + +[アプリ](/docs/build/interface/apps)に `dashboard` のナビゲーションエントリを追加します。 + +```ts +// One navigation item of an app. +{ id: 'nav_analytics', type: 'dashboard', label: 'Analytics', + dashboardName: 'sales_overview', icon: 'bar-chart' } +``` + +あるいは [AI Builder](/docs/build/ai-builder) に説明します(*「地域別の売上と月次の商談の推移を含む営業概要ダッシュボード」*)。そして承認する前に、生成されたデータセット + ダッシュボードのメタデータを確認します。 + +## 次に進む [#where-to-go-next] + +| ページ | 理由 | +|:--|:--| +| [レポート](/docs/build/reports) | 同じデータセットに対するグループ化レポートとクロス集計レポート | +| [アプリ](/docs/build/interface/apps) | ダッシュボードをナビゲーションに置く | +| [ビュー](/docs/build/interface/views) | 同じデータセットに対するインラインの `chart` リストビュー | +| [ページ](/docs/build/interface/pages) | ウィジェットのグリッドでは足りないときの自由形式のレイアウト | +| [データモデル](/docs/build/data) | データセットが集計するオブジェクト | +| [権限](/docs/configure/permissions) | ダッシュボードが継承する行レベルセキュリティ | diff --git a/content/docs/build/interface/forms.ja.mdx b/content/docs/build/interface/forms.ja.mdx new file mode 100644 index 00000000..3e5be655 --- /dev/null +++ b/content/docs/build/interface/forms.ja.mdx @@ -0,0 +1,175 @@ +--- +title: フォーム +seoTitle: "フォーム:作成と編集、セクション、送信後" +description: 作成フォームと編集フォームを 1 つのフラットなフィールドの集合から導き出し、ずれを生まずにフィールドをセクションにまとめ、送信後に起こることを制御します。 +editions: [community, cloud, enterprise] +translation: + source_sha: 7b91231facd6607664e7ec8baee9af1949872ed91a12abe14e7b20eb2d0c96e2 + guide_rev: 1 + mode: auto +--- + +**フォームはオブジェクトのフィールドの投影であり、2 つ目のフィールドリストではありません。** フィールドはオブジェクトで一度だけ宣言し、フォームは*どのフィールドをどこに*置くかを選びます。データの意味(型、検証、デフォルト、フィールドレベルのセキュリティ)がフォームに置かれることはないので、フォームがずれてデータについて偽ることはありません。 + +フォームビューの*種類*(`simple`、`tabbed`、`wizard`、`modal` など)と公開フォームの REST の契約は、[ビュー](/docs/build/interface/views)で扱っています。このページはレイアウトの問題、つまり作成と編集、グループ化、順序についてです。 + +## 作成フォーム ≠ 編集フォーム [#create-form--edit-form] + +新規レコードのフォームはいくつかの必須項目だけを尋ね、編集フォームはレコード全体をセクションに分けて表示するべきです。**2 つのフォームを作成しないでください。** 作成フォームのサブセットは、各フィールドにすでにある意図から*導き出せます*。 + +| フィールドの手がかり | 作成フォームへの影響 | +|:--|:--| +| `required: true` | 作成時に表示**しなければなりません** | +| `readonly` / 数式 / ロールアップ / 自動採番 / システムが記録するもの | 作成時には**決して**表示しません。設定できないからです | +| `defaultValue` がある | **省略できます**。自動で埋まるからです | +| `hidden` | デフォルトではどこにも表示しません | +| `group` | フィールドが属するセクション | +| *宣言の順序* | これがデフォルトの表示順序**です**。`field.order` はありません | + +そのため、妥当な作成フォーム(*編集可能で、必須または中核のフィールドを、宣言の順序で*)は、何も作成しなくてもオブジェクトから自然に導かれます。省略が正解です。余分なものを何も出力しなくても、完全で正しいフォームが得られます。完全な編集フォームも導き出され、各 `field.group` がセクションとして具体化されます。 + +### 作成フォームを手で整えるのは、レイアウトや流れが異なる場合だけ [#hand-shape-the-create-form-only-when-layout-or-flow-diverges] + +逃げ道は、作成のエントリポイントにバインドした名前付きのフォームビューです。これは**疎な上書き**として作成します。ほとんどはフィールド名のリストです。 + +```ts +import { defineView } from '@objectstack/spec' + +const data = { provider: 'object' as const, object: 'showcase_contact' } + +export const ContactViews = defineView({ + list: { + type: 'grid', data, + columns: [{ field: 'name' }, { field: 'email' }, { field: 'company' }, { field: 'stage' }], + // Bind the "+ Add record" entry point to the slim create form: + addRecord: { enabled: true, mode: 'form', formView: 'create' }, + }, + + // Full edit form — grouped by field.group; bare strings inherit field defs. + form: { + type: 'simple', data, + sections: [ + { name: 'contact', label: 'Contact', columns: 2, fields: ['name', 'email', 'phone'] }, + { name: 'work', label: 'Work', columns: 2, fields: ['company', 'title'] }, + { name: 'status', label: 'Status', columns: 2, fields: ['stage', 'lead_score'] }, + ], + }, + + formViews: { + // Sparse create override: only the core fields, one section. + create: { + type: 'simple', data, title: 'New contact', + sections: [ + { label: 'Who is this?', columns: 1, fields: ['name', 'email', 'phone', 'company'] }, + ], + }, + }, +}) +``` + +バインディングは `addRecord.mode: 'form'` + `addRecord.formView: 'create'` です。`formViews.create` がなければ、作成のエントリはデフォルトを導き出します。あれば、作成時にはそれが優先されます。 + +| 本当に必要なこと | 使うもの | +|:--|:--| +| 作成時に尋ねるフィールドを減らす(必須 + いくつかの中核) | **純粋な導出**。手で書かないでください | +| 作成時のグループ化が異なるが、小さなサブセットにすぎない | たいていはやはり導出 | +| 作成がウィザード / 多段階、作成専用の文言、条件付きの表示を持つ | **`formViews.create` を手で書く** | + +> 目安:*フィールドのサブセットが異なる* → 導出する。*レイアウトや流れが異なる* → 上書きする。フィールドを減らすためだけに完全な作成フォームを書くと、2 つの成果物がずれる罠にまっすぐはまります。必須フィールドを追加し、作成フォームのことを忘れ、作成時に実行時の「必須フィールドがありません」が出る、という具合です。 + +作成のフィールドは編集のフィールドの*同じ順序とグループの*サブセットなので、「4 つのフィールドでクイック作成 → 保存 → 完全なレコードに着地」が視覚的に途切れません。導出はそれを無償で保ちます。 + +## フィールドのグループ化と順序 [#field-grouping-and-order] + +モデルはフラットなフィールドの集合です。グリッドはフラットな列を表示します。フォームにはセクションが必要です。これは矛盾ではありません。1 つのフラットな集合を、異なるレンズを通して見ているのです。 + +| レンズ | フィールドの形 | 理由 | +|:--|:--|:--| +| オブジェクトの定義 | フラット | モデルは*どんなデータが存在するか*を記述します | +| テーブル / グリッド | フラットな列 | グリッドはレコード × フィールドの行列です | +| フォーム / レコードページ | グループ化されたセクション | 1 件のレコードを読む人間には区切りが必要です | + +グループ化の概念は **2 つ**あります。区別しておいてください。 + +**1. 意味上のグループ化:`field.group`(オブジェクト上)。** フィールドの論理的な居場所です。モデルとともに移動し、自動生成されるフォームの*デフォルトの*セクション分けの元になります。 + +```ts +// Fields of an object; the object around them is omitted. +fields: { + name: Field.text({ label: 'Full name', group: 'contact' }), + email: Field.email({ label: 'Email', group: 'contact' }), + stage: Field.select({ + label: 'Stage', + group: 'status', + options: [ + { label: 'Lead', value: 'lead' }, + { label: 'Customer', value: 'customer' }, + ], + }), +} +``` + +**2. レイアウト上のグループ化:フォームの `sections`(ビュー上)。** 特定のフォームの明示的な配置です。どのフィールドを、どのセクションに、何列(`columns`)で置くか、折りたたみ可能か。`field.group` をデフォルトとして継承し、必要に応じてフォームごとに上書きします。 + +```ts +// Keys of a view container; `data` and its other keys are omitted. +form: { + type: 'simple', + sections: [ + { name: 'contact', label: 'Contact', columns: 2, fields: ['name', 'email', 'phone'] }, + { name: 'status', label: 'Status', columns: 2, fields: ['stage'] }, + ], +} +``` + +**順序は作成した順序です。** `field.order` はありません。オブジェクト上のフィールドの宣言の順序が、どこでもデフォルトの表示順序であり、`sections`(とその中のフィールド)は順序付きのリストです。 + +> **「グループ」の罠。** グリッドビューの `groupByField` は、フィールドの*値*で **レコード(行)** をグループ化します。`stage = qualified` の行がすべてまとまります。フォームのセクションは **フィールド(列)** を視覚的にグループ化します。同じ言葉で、無関係な 2 つの軸です。グリッドのグループがフォームをセクションに分けることは決してありません。 + +## 送信後に起こること [#what-happens-after-submit] + +送信後の体験を制御するには、フォームビューに `submitBehavior` を追加します。 + +```ts +// Keys of a form view; its other keys are omitted. +submitBehavior: { + kind: 'thank-you', + title: 'Thanks!', + message: 'A specialist will reach out within 24 hours.', +} +``` + +| `kind` | 動作 | +|:--|:--| +| `thank-you` *(デフォルト)* | フォームを確認パネル(`title`、`message`)に置き換えます | +| `redirect` | `delayMs`(デフォルト 0)の後に `url` へ移動します。マーケティングページに最適です | +| `continue` | 次の回答のためにフォームをリセットします。キオスク、一括入力向けです | +| `next-record` | キュー内の次のレコードに進みます(内部モード) | + +公開フォームと内部フォームのどちらも、`?prefill_=` という URL パラメータに従います。メールのリンクやキャンペーンページからフォームに値を入れておけます。事前入力は UX の近道であって、権限のすり抜けではありません。値はやはり検証と、(公開フォームの場合は)サーバー側のフィールドのホワイトリストを通ります。 + +``` +/console/f/contact-us?prefill_company=Acme&prefill_email=ada@example.com +/console/forms/quick_create?prefill_lead_source=event_booth_2026 +``` + +## レコードの詳細はフォームのバインディングではなくロールで決まる [#record-detail-is-driven-by-roles-not-a-form-binding] + +フォームビューをレコード詳細画面に固定するオブジェクトレベルのキーはありません。詳細のレンダリングは、オブジェクトの画面をまたぐ**意味上のロール**から導き出されます。`nameField`(表示名)、`highlightFields`(最も重要なフィールドの帯)、`stageField`(ライフサイクルの進捗ステッパー)、そして `fieldGroups` + `Field.group`(フォーム、モーダル、詳細ページで共有されるセクション分け)です。ロールから導き出せる以上の特注のレイアウトがレコードページに必要なときは、そのオブジェクトにカスタムの[ページ](/docs/build/interface/pages)を割り当てます。 + +## アンチパターン [#anti-patterns] + +- **手で作成した 2 つの完全なフィールドリスト**(`contact_create_form` + `contact_edit_form`)。ずれることが確実です。 +- **フィールドの型 / 検証 / 選択肢をフォームで書き直すこと。** データの意味はオブジェクトにだけ置きます。 +- **すべてのフォームでグループ化を打ち直すこと。** `field.group` を一度宣言し、本当に異なる場合だけ上書きします。 +- **フォームを満たすためにデータモデルに構造的な入れ子を加えること。** モデルはフラットのままにし、フォームがグループ化します。 + +## 次に進む [#where-to-go-next] + +| ページ | 理由 | +|:--|:--| +| [ビュー](/docs/build/interface/views) | フォームビューの種類、公開フォームの共有、ビューの完全なスキーマ | +| [データモデル](/docs/build/data) | フィールドとその意図が宣言される場所 | +| [アクション](/docs/build/interface/actions) | フォームビューを開く `type: 'form'` のアクション | +| [ページ](/docs/build/interface/pages) | 導出されたレイアウトを超えるカスタムのレコードページ | +| [権限](/docs/configure/permissions) | フォームが従うフィールドレベルのセキュリティ | diff --git a/content/docs/build/interface/index.ja.mdx b/content/docs/build/interface/index.ja.mdx new file mode 100644 index 00000000..dc6217f8 --- /dev/null +++ b/content/docs/build/interface/index.ja.mdx @@ -0,0 +1,49 @@ +--- +title: インターフェース +seoTitle: "インターフェース:アプリ、ビュー、フォーム、ダッシュボード、ページ" +description: アプリ、ビュー、フォーム、ダッシュボード、ページ、アクション。ユーザーが目にするすべての画面をメタデータとして宣言し、ObjectOS がレンダリングします。 +editions: [community, cloud, enterprise] +translation: + source_sha: b5a75aba85c279c1de7f1e2e11254b300b51906392cfaa0a5f4e1f50a803e61c + guide_rev: 1 + mode: auto +--- + +**ユーザーが目にするものはすべてメタデータです。** インターフェースはデータとして宣言し、オブジェクトと同じライフサイクルを持ちます。バージョン管理し、パッケージで出荷し、AI Builder に生成させることができ、準拠したレンダラーならどれでも描画できます。 + +各部品は上から下へと組み合わさります。 + +1. **アプリ**は外枠です。ナビゲーション、ブランディング、対象者のゲートを持ちます。 +2. その**ナビゲーション**は、オブジェクト、ダッシュボード、ページ、URL を指します。 +3. オブジェクトのエントリは**ビュー**に着地します。グリッド、カンバン、カレンダーなどです。 +4. レコードを開いたり作成したりすると**フォーム**がレンダリングされます。セクションはフィールドのメタデータから導き出され、モードごとに上書きできます。 +5. **ダッシュボード**は同じデータを、名前付きデータセットにバインドされたチャートウィジェットに集約します。 +6. **ページ**はオブジェクトの枠から完全に抜け出します。コンポーネントとリージョンで構成する自由形式のレイアウトです。 +7. **アクション**は上記のすべてにボタンを置きます。1 つの宣言で、UI、REST、フロー、AI エージェントから呼び出せます。 + +## 概念 [#the-concepts] + +| 概念 | 宣言するもの | ページ | +|:--|:--|:--| +| アプリ | ナビゲーションの外枠、ブランディング、対象者のゲート | [アプリ](/docs/build/interface/apps) | +| ビュー | レコードのレンダリング方法:グリッド、カンバン、カレンダー、ガント…… | [ビュー](/docs/build/interface/views) | +| フォーム | 作成 / 編集のレイアウト、セクション、フィールドのグループ化 | [フォーム](/docs/build/interface/forms) | +| ダッシュボード | チャートウィジェット、グローバルフィルター、ドリルダウン | [ダッシュボード](/docs/build/interface/dashboards) | +| ページ | 自由形式のコンポーネントレイアウト。パッケージ化されたドキュメントページ | [ページ](/docs/build/interface/pages) | +| アクション | あらゆる場所にボタンとして表示される名前付きの操作 | [アクション](/docs/build/interface/actions) | + +UI はデータなので、表示するレコードと同じ[権限](/docs/configure/permissions)に従います。また [AI Builder](/docs/build/ai-builder) は、同じ型付きのインターフェースを通じて、そのどれでも生成または変更できます。欲しいインターフェースを説明し、差分を確認して、承認します。 + +> まずデータから始めてください。ビューとフォームは[オブジェクトの定義](/docs/build/data)から妥当なデフォルトを導き出すので、インターフェースのメタデータを書くのは、デフォルトが望みどおりでない箇所だけです。 + +## 次に進む [#where-to-go-next] + +| ページ | 理由 | +|:--|:--| +| [アプリ](/docs/build/interface/apps) | オブジェクトをナビゲーションできる外枠で包む | +| [ビュー](/docs/build/interface/views) | レコードのレンダリング方法を選ぶ | +| [フォーム](/docs/build/interface/forms) | 作成と編集の体験を形作る | +| [ダッシュボード](/docs/build/interface/dashboards) | 分析ウィジェットを追加する | +| [ページ](/docs/build/interface/pages) | 自由形式のレイアウトを構成する | +| [アクション](/docs/build/interface/actions) | 操作をボタンの背後に置く | +| [データモデル](/docs/build/data) | すべての画面が読み取るオブジェクト | diff --git a/content/docs/build/interface/pages.ja.mdx b/content/docs/build/interface/pages.ja.mdx new file mode 100644 index 00000000..f46decbb --- /dev/null +++ b/content/docs/build/interface/pages.ja.mdx @@ -0,0 +1,166 @@ +--- +title: ページ +seoTitle: "自由形式のページ:リージョン、コンポーネント、ドキュメントページ" +description: リージョン、コンポーネント、ローカル状態で構成する自由形式のレイアウト。さらに、パッケージの中に同梱して出荷する Markdown のドキュメントページ。 +editions: [community, cloud, enterprise] +translation: + source_sha: 4a88c0ee1ee387d77d686cf62b3d5270e2d183f2d362cd66274326205db8a3d4 + guide_rev: 1 + mode: auto +--- + +**ページは自由形式のコンテナです。** 単一のオブジェクトにバインドされる[ビュー](/docs/build/interface/views)とは異なり、ページは複数のコンポーネントを組み合わせ、ビューを埋め込み、ローカル状態を管理します。ホーム画面、カスタムのレコードレイアウト、ユーティリティパネルなどです。 + +```ts +// One page. +const homePage = { + name: 'sales_home', + label: 'Sales Home', + type: 'home', + regions: [ + { name: 'header', width: 'full', components: [ + { type: 'metric_card', id: 'total_revenue', label: 'Total Revenue', + properties: { dataset: 'sales', values: ['revenue'], format: 'currency' } }, + ]}, + { name: 'main', width: 'large', components: [ + { type: 'list_view', id: 'recent_deals', label: 'Recent Deals', + properties: { object: 'opportunity', view: 'recent_open', limit: 10 } }, + ]}, + ], +} +``` + +## ページのプロパティ [#page-properties] + +| プロパティ | 型 | 必須 | 説明 | +|:--|:--|:--|:--| +| `name` | `string` | はい | マシン名(`snake_case`) | +| `label` | `string` | はい | 表示ラベル | +| `type` | `enum` | — | ページの種類(デフォルト `'record'`、下記を参照) | +| `object` | `string` | — | 関連するオブジェクト(`record` の種類の場合) | +| `template` | `string` | — | レイアウトテンプレートの名前(デフォルト `'default'`) | +| `regions` | `PageRegion[]` | — | コンポーネントを含むレイアウトの区画 | +| `variables` | `PageVariable[]` | — | ローカル状態の変数 | +| `isDefault` | `boolean` | — | その種類のデフォルトのページかどうか | +| `assignedProfiles` | `string[]` | — | このページにアクセスできるプロファイル | + +### ページの種類 [#page-types] + +| 種類 | 用途 | +|:--|:--| +| `record` | 1 つのオブジェクトのレコードに結び付いたカスタムの詳細ページ | +| `home` | アプリのランディング / 入口 | +| `app` | 一般的なアプリケーションのレイアウト | +| `utility` | ツール、設定、ウィザード | +| `list` | データ駆動のインターフェース画面 | + +有効なのはこの 5 つの種類だけです。レンダラーが出荷されなかった以前のロードマップ上の種類は、スキーマから削除されました。 + +## リージョン [#regions] + +リージョンはレイアウトの区画で、それぞれがコンポーネントを保持します。 + +```ts +// Keys of a page; its other keys, and the regions' components, are omitted. +regions: [ + { name: 'sidebar', width: 'small', components: [/* … */] }, + { name: 'content', width: 'large', components: [/* … */] }, +] +``` + +`width` には `'small'`、`'medium'`、`'large'`、`'full'` を指定できます。 + +## コンポーネント [#components] + +コンポーネントはリージョンの中の構成要素です。 + +```ts +// One page component; the page and region around it are omitted. +{ + type: 'chart', + id: 'revenue_chart', + label: 'Revenue Trend', + properties: { chartType: 'line', dataset: 'sales', + dimensions: ['close_month'], values: ['revenue'] }, + events: { onClick: "navigate_to('opportunity_detail', { id: $event.id })" }, + visibleWhen: "'sales_manager' in os.user.positions", +} +``` + +分析を扱うコンポーネント(`chart`、`metric_card`)は名前付きの**データセット**にバインドし、その `dimensions` + `values` を名前で選びます。これは[ダッシュボード](/docs/build/interface/dashboards)のウィジェットと同じ ADR-0021 の形であり、Studio が出力する唯一の形です。削除されたインライン分析の形(コンポーネント上の `object` + `categoryField` + `valueField` + `aggregate`)は、16.0 以降はパースエラーになり、黙って無視される何もしない設定ではありません。 + +| プロパティ | 型 | 説明 | +|:--|:--|:--| +| `type` | `string` | 標準のコンポーネントの種類、またはカスタムの文字列 | +| `id` | `string` | 一意なコンポーネントインスタンスの ID | +| `properties` | `object` | コンポーネント固有の設定 | +| `events` | `object` | イベントハンドラー(アクションの式) | +| `visibleWhen` | `string` | CEL の表示条件の述語。TRUE のときだけコンポーネントがレンダリングされます(`visibility` は非推奨のエイリアスで、今も受け付けられ、`visibleWhen` に正規化されます) | +| `style` / `className` | — | その場限りの CSS | +| `responsiveStyles` | `object` | **推奨される**スタイル指定の手段:デスクトップ優先のブレークポイントごとのスタイルマップ(`large` を基準に、`medium` / `small` / `xsmall` で上書き)。スコープ付きの CSS にコンパイルされます。`var(--space-8)` のようなデザイントークンを優先してください | + +標準の、名前空間付きのコンポーネントの種類: + +| 名前空間 | 種類 | +|:--|:--| +| 構造 | `page:header`、`page:footer`、`page:sidebar`、`page:tabs`、`page:accordion`、`page:card`、`page:section` | +| レコードのコンテキスト | `record:details`、`record:highlights`、`record:related_list`、`record:activity`、`record:chatter`、`record:path`、`record:alert`、`record:quick_actions`、`record:reference_rail`、`record:history` | +| ナビゲーション | `app:launcher`、`nav:menu`、`nav:breadcrumb` | +| ユーティリティ | `global:search`、`global:notifications`、`user:profile` | +| AI | `ai:chat_window`、`ai:suggestion` | +| 要素 | `element:text`、`element:number`、`element:image`、`element:divider`、`element:button`、`element:filter`、`element:form`、`element:record_picker`、`element:text_input` | + +コンポーネントは、`dataSource`(複数オブジェクトのページ向けの、要素ごとのオブジェクトのバインディング)、`responsive`、`aria` の設定を持つこともできます。プロジェクト固有のウィジェットには、カスタムの文字列の種類も受け付けられます。 + +## 変数 [#variables] + +ページは、コンポーネントの間で共有されるローカル状態を保持します。 + +```ts +// Keys of a page; its other keys are omitted. +variables: [ + { name: 'selected_tab', type: 'string', defaultValue: 'overview' }, + { name: 'date_range', type: 'object', defaultValue: { start: null, end: null } }, +] +``` + +`type` には `'string'`(デフォルト)、`'number'`、`'boolean'`、`'object'`、`'array'`、`'record_id'` を指定できます。 + +> `record` の種類のページは、特注のレコードレイアウトのためにサポートされている方法です。ロールから導き出される詳細ページ([フォーム](/docs/build/interface/forms)を参照)では足りないときに使います。全幅のヘッダーに `record:highlights` を、サイドバーに `record:details` と `record:activity` を、メインのリージョンに `record:related_list` のコンポーネントを配置します。 + +[アプリ](/docs/build/interface/apps)から `page` のナビゲーションエントリでページを表示するか、`homePageId` でアプリのランディングページにします。 + +## ドキュメントページ [#doc-pages] + +**ドキュメント**はパッケージのドキュメントのページです。フラットな `src/docs/` ディレクトリに置いたプレーンな Markdown ファイルで、パッケージの成果物にコンパイルされ、UI の `/docs/` でレンダリングされます。ドキュメントは、AI アシスタントがパッケージについての質問に答えるときの根拠にもなります。 + +``` +src/docs/ + crm_index.md → doc name "crm_index" + crm_user_guide.md → doc name "crm_user_guide" +``` + +ファイル名の語幹がドキュメントの `name` になります。ディレクトリによる分類も、順序のファイルもありません。フラットな配置により相互参照が安定します。リンクはパスではなく、常にベース名で解決されます。 + +| ルール | 詳細 | +|:--|:--| +| 命名 | `snake_case`。ビルドの lint は**名前空間のプレフィックス**を要求します(`user_guide` ではなく `crm_user_guide`) | +| フロントマター | 省略可能。`title` と `description` が読み取られます。タイトルはフロントマター → 最初の `#` 見出し → ドキュメント名の順に解決されます | +| 相互参照 | プレーンな相対リンク(`[overview](./crm_index.md)`)。UI では `/docs/` に書き換えられ、GitHub ではそのまま機能します。**同じパッケージ内の壊れたリンクはビルドを失敗させます** | +| Markdown | CommonMark + GFM:テーブル、ハイライト付きのフェンスコード、見出しのアンカー、GitHub のアラート(`> [!TIP]`) | +| ビルド時に拒否されるもの | **MDX / 埋め込みコンポーネント**(ドキュメントはコードではなくデータであり、信頼の境界です)と**画像の参照**(まだアセットサービスがなく、壊れた画像よりも早い失敗の方がよいため) | + +ドキュメントの解決はパッケージ単位です。インストールされた 2 つのパッケージがそれぞれ同じ素の名前のドキュメントを出荷しても共存でき、どちらも他方を上書きしません。 + +> 動的なコンテンツ(ライブのフロー図、レコードのテーブル)については、コンポーネントを埋め込もうとしないでください。URL でメタデータにリンクします。ライブのビューはプラットフォームがレンダリングし、ドキュメントはそれを指し示すだけです。 + +## 次に進む [#where-to-go-next] + +| ページ | 理由 | +|:--|:--| +| [アプリ](/docs/build/interface/apps) | ページをナビゲーションに置き、`homePageId` を設定する | +| [ビュー](/docs/build/interface/views) | ページが埋め込むオブジェクトの画面 | +| [フォーム](/docs/build/interface/forms) | ロールから導き出されるレコードレイアウトとカスタムのレコードページ | +| [ダッシュボード](/docs/build/interface/dashboards) | 自由形式の代わりの、分析に特化したレイアウト | +| [アクション](/docs/build/interface/actions) | `element:button` のターゲットと `modal` の種類のアクション | +| [AI Builder](/docs/build/ai-builder) | チャットでページのメタデータを生成する | diff --git a/content/docs/build/interface/views.ja.mdx b/content/docs/build/interface/views.ja.mdx new file mode 100644 index 00000000..cb5582a3 --- /dev/null +++ b/content/docs/build/interface/views.ja.mdx @@ -0,0 +1,294 @@ +--- +title: ビュー +seoTitle: "ビュー:リスト、カンバン、カレンダー、ガント、フォーム" +description: リスト、フォーム、カンバン、カレンダー、ガントなど。すべてのオブジェクトの画面がどう宣言されるか。 +editions: [community, cloud, enterprise] +translation: + source_sha: f7208e0810feac70de2d69b3c01e2700665308487ccc26ac2e84bd3f0357fc0d + guide_rev: 1 + mode: auto +--- + +**ビュー**は、ユーザーがレコードを見て編集するための方法です。ビューは宣言的なメタデータで、オブジェクトと同じライフサイクルを持ちます。一度宣言し、パッケージとともに出荷し、どこでもレンダリングできます。 + +2 つの種類があります。 + +- **リストビュー**:多数のレコードを可視化します(グリッド、カンバン、カレンダー……) +- **フォームビュー**:単一のレコードを表示 / 編集します(シンプル、タブ、ウィザード……) + +スキーマのソース:[`packages/spec/src/ui/view.zod.ts`](https://github.com/objectstack-ai/objectstack/blob/main/packages/spec/src/ui/view.zod.ts)。 + +## 最短の宣言 [#the-shortest-possible-declaration] + +ビューを 1 つも宣言しなくても、すべてのオブジェクトには自動的にデフォルトのグリッドリストとシンプルなフォームが用意されます。それらを上書きまたは拡張するには、オブジェクトのビューを、オブジェクトの中ではなくその隣にある `defineView` コンテナで宣言します。`list` がデフォルトのリスト、`form` がデフォルトのフォームで、各ビューは `data` で自分のオブジェクトを指定します。 + +```ts +// src/ui/views/support_ticket.view.ts +import { defineView } from '@objectstack/spec'; + +const data = { provider: 'object' as const, object: 'support_ticket' }; + +export const SupportTicketViews = defineView({ + list: { + type: 'grid', + data, + columns: ['subject', 'status', 'priority', 'assignee'], + }, + form: { + type: 'simple', + data, + sections: [ + { name: 'details', label: 'Details', fields: ['subject', 'description', 'priority', 'status', 'assignee'] }, + ], + }, +}); +``` + +コンテナを、それが記述するオブジェクトの隣に、スタックに登録します。 + +```ts +// objectstack.config.ts +export default defineStack({ + // ... + views: [SupportTicketViews], +}); +``` + +複数のビューを持つオブジェクト(たとえば同じデータに対するカンバン*と*カレンダー)では、同じコンテナに名前付きのビューを追加します。ビュー切り替え用には `listViews`、名前で開くフォーム用には `formViews` です。すべてのリストビューは、種類にかかわらずトップレベルの `columns` を持ちます。 + +```ts +export const SupportTicketViews = defineView({ + list: { type: 'grid', data, columns: ['subject', 'status', 'priority', 'assignee'] }, + listViews: { + by_status: { + label: 'By status', type: 'kanban', data, columns: ['subject', 'priority'], + kanban: { groupByField: 'status', columns: ['subject', 'priority'] }, + }, + schedule: { + label: 'Schedule', type: 'calendar', data, columns: ['subject', 'due_at'], + calendar: { startDateField: 'due_at', titleField: 'subject' }, + }, + by_owner: { + label: 'By owner', type: 'grid', data, columns: ['assignee', 'subject', 'status', 'priority'], + sort: [{ field: 'assignee', order: 'asc' }], + }, + }, + formViews: { + quick: { type: 'modal', data, sections: [{ name: 'quick', label: 'Quick edit', fields: ['status', 'priority', 'assignee'] }] }, + full: { + type: 'tabbed', data, + sections: [ + { name: 'details', label: 'Details', fields: ['subject', 'description'] }, + { name: 'triage', label: 'Triage', fields: ['status', 'priority', 'assignee'] }, + ], + }, + }, +}); +``` + +コンテナとそのルールは、ObjectStack の [View metadata](https://objectstack.ai/docs/ui/views) に完全に記載されています。 + +## リストビューの種類 [#list-view-types] + +すべてのリストビューには、種類にかかわらずトップレベルの `columns` が必要です。その種類のそれ以外の設定は、種類の名前を付けた設定ブロックに入れます。 + +| `type` | レンダリングするもの | 設定ブロックとその必須キー | よく使う省略可能なキー | +|:--|:--|:--|:--| +| `grid` | データテーブル(デフォルト) | — | | +| `kanban` | 列のあるボード | `kanban: { groupByField, columns }` | `summarizeField`、`titleField` | +| `gallery` | カードの束 | `gallery`(必須キーなし) | `coverField`、`titleField` | +| `calendar` | 月 / 週 / 日 | `calendar: { startDateField }` | `endDateField`、`titleField`、`colorField` | +| `timeline` | 時系列のフィード | `timeline: { startDateField, titleField }` | `endDateField`、`groupByField` | +| `gantt` | プロジェクトのタイムライン + 依存関係 | `gantt: { startDateField, endDateField, titleField }` | `progressField`、`dependenciesField` | +| `map` | 地図上のピン | `map`(必須キーなし) | `locationField`、または `latitudeField` + `longitudeField` | +| `tree` | 自己参照の階層 | `tree`(必須キーなし) | `parentField`、`labelField` | +| `chart` | 埋め込みのチャート | `chart: { dataset, values }` | `chartType`、`dimensions` | + +以下の断片はそれぞれ単一のリストビューです。どれも上のように、`data` で自分のオブジェクトを指定して、`defineView` コンテナの `list` として、または `listViews` のエントリとして入れます。 + +### リストの共通オプション [#common-list-options] + +```ts +// One list view; the container and `data` are omitted (see above). +// P is the predicate template tag: import { P } from '@objectstack/spec' +{ + type: 'grid', + columns: ['subject','status','priority','assignee','created_at'], + + filter: [ { field: 'archived', operator: 'equals', value: false } ], + sort: [ { field: 'created_at', order: 'desc' } ], + pagination: { pageSize: 25 }, + searchableFields: ['subject','description'], + filterableFields: ['status','priority','assignee'], + + navigation: { mode: 'drawer' }, // 'page' | 'drawer' | 'modal' | 'split' | 'popover' | 'new_window' | 'none' + selection: { type: 'multiple' }, // 'none' | 'single' | 'multiple' + + rowActions: ['close_ticket','assign_to_me'], + bulkActions: ['bulk_close','bulk_export'], + + conditionalFormatting: [ + { condition: P`record.priority == 'urgent'`, style: { background: '#fef2f2', fontWeight: '600' } } // style values are strings + ], + + exportOptions: ['csv','xlsx'], + emptyState: { title: 'No tickets yet', message: 'Create one to get started', icon: 'inbox' } +} +``` + +`filter` と `sort` は [ObjectQL](/docs/reference/objectql) にコンパイルされます。`rowActions` と `bulkActions` は名前で[アクション](./actions)を参照します。 + +### カンバン [#kanban] + +```ts +// One list view; the container and `data` are omitted (see above). +{ + type: 'kanban', + columns: ['subject', 'priority', 'assignee'], // still required at the top level + kanban: { + groupByField: 'status', // discrete field — usually a select + summarizeField: 'amount', // optional total per column + columns: ['subject', 'priority', 'assignee'] // fields shown on each card + } +} +``` + +ボードの列は `groupByField` の値から作られ、その順序と色はそのフィールドの `select` の選択肢の定義から取られます。 + +列の間でドラッグ&ドロップすると、グループ化しているフィールドを設定する更新が発行されます。権限のルールは手動での編集と同じです。 + +### カレンダー [#calendar] + +```ts +// One list view; the container and `data` are omitted (see above). +{ + type: 'calendar', + columns: ['subject', 'start_at', 'end_at', 'priority'], + calendar: { + startDateField: 'start_at', + endDateField: 'end_at', // optional — single-point if omitted + titleField: 'subject', + colorField: 'priority' // optional — colours events by value + } +} +``` + +### ガント [#gantt] + +```ts +// One list view; the container and `data` are omitted (see above). +{ + type: 'gantt', + columns: ['name', 'start_at', 'due_at', 'percent_complete'], + gantt: { + startDateField: 'start_at', + endDateField: 'due_at', + titleField: 'name', + progressField: 'percent_complete', // optional, drives the progress bar + dependenciesField: 'depends_on' // optional — multiselect lookup to same object + } +} +``` + +### ツリー [#tree] + +```ts +// One list view; the container and `data` are omitted (see above). +{ + type: 'tree', + columns: ['name'], + tree: { + parentField: 'parent_id', // self-lookup that builds the hierarchy + labelField: 'name', // shown indented in the first column + defaultExpandedDepth: 1 // optional — 0 = roots only, omit = expand all + } +} +``` + +自己参照するオブジェクト(カテゴリー、部品表、組織単位、入れ子のコメント)では、ツリーグリッドが `parentField` のポインターに従って行を入れ子にします。 + +### チャート(インライン) [#chart-inline] + +`chart` リストビューは、名前付きの**データセット**(セマンティックな分析レイヤー、ADR-0021)にバインドし、そのディメンションとメジャーを**名前で**選びます。指標を一度定義すれば、同じデータセットにバインドされたすべてのチャート、ダッシュボード、レポートの一貫性が保たれます。 + +```ts +// One list view; the container and `data` are omitted (see above). +{ + type: 'chart', + columns: ['status'], + chart: { + chartType: 'bar', // 'bar' | 'line' | 'pie' | 'area' | 'scatter' + dataset: 'tickets_by_status', // a dataset declared with defineDataset(...) + dimensions: ['status'], // dataset dimension name(s) — X / group / split + values: ['ticket_count'] // dataset measure name(s) — the value axis + } +} +``` + +インラインの `xAxisField` / `yAxisFields` / `aggregation` / `groupByField` という形は 9.0 で削除されました。今では、すべてのチャート、ダッシュボードのウィジェット、レポートがデータセットにバインドします。より高度な、オブジェクトをまたぐ分析には、専用のレポート画面を使ってください。 + +## フォームビューの種類 [#form-view-types] + +| `type` | レイアウト | +|:--|:--| +| `simple` | 単一の列またはセクション(デフォルト) | +| `tabbed` | タブ付きのセクション | +| `wizard` | ステップごとの流れ | +| `split` | マスター / 詳細の 2 ペイン | +| `drawer` | サイドパネルのフォーム | +| `modal` | ダイアログのフォーム | + +```ts +// One form view; the container and `data` are omitted (see above). +{ + type: 'tabbed', + sections: [ + { label: 'Overview', fields: ['subject','status','priority','assignee'] }, + { label: 'Customer', fields: ['customer','contact','email','phone'] }, + { label: 'Resolution', fields: ['resolution_notes','resolved_at'] } + ], + submitBehavior: { kind: 'next-record' } // 'thank-you' | 'redirect' | 'continue' | 'next-record' +} +``` + +### 公開フォーム [#public-forms] + +フォームは匿名でアクセスできるようにできます。 + +```ts +// One form view; the container and `data` are omitted (see above). +{ + type: 'simple', + sections: [ { fields: ['name','email','message'] } ], + sharing: { + enabled: true, + publicLink: 'contact-us', // slug under /forms/ + allowAnonymous: true + }, + submitBehavior: { kind: 'thank-you' } +} +``` + +これにより `GET /api/v1/forms/contact-us` と `POST /api/v1/forms/contact-us/submit` が自動的に公開されます。認証を必要としない公開フォームのルートです。[REST API → Public forms](/docs/reference/rest-api#public-forms) を参照してください。 + +## 表示条件、ARIA、テーマ [#visibility-aria-theming] + +- `visibleOn: P\`...\``:フォームの**セクション**と**フィールド**で、ユーザー / レコード / 環境に基づいてそれらを隠します(CEL の述語) +- `aria: { label, description, ... }`:スクリーンリーダー向けの ARIA 属性(リストビューとフォームビュー) +- `appearance: { showDescription, allowedVisualizations: [...] }`:リストビューで、エンドユーザーが切り替えられるリストの種類を制限します + +## チャットで構築する [#build-by-chat] + +ビューのメタデータを手で書くことは通常ありません。AI Builder にこう伝えます。 + +> *「support_ticket オブジェクトのカンバンビューを、ステータスでグループ化して追加して。カードには件名と優先度を表示して。列はステータスに応じて赤 / 黄 / 緑に色分けして。」* + +AI Builder はメタデータツールを呼び出し、差分をキューに入れ、あなたが承認するとビューが表示されます。[AI Builder](/docs/build/ai-builder) を参照してください。 + +## 関連項目 [#see-also] + +- [データモデル](/docs/build/data):ビューが読み取るオブジェクト +- [アクション](./actions):`rowActions` / `bulkActions` が参照するもの +- [ObjectQL](/docs/reference/objectql):`filter` / `sort` のコンパイル先 +- [CEL](/docs/reference/cel):`conditionalFormatting`、`visibleOn` +- [`@objectstack/spec/ui/view.zod.ts`](https://github.com/objectstack-ai/objectstack/blob/main/packages/spec/src/ui/view.zod.ts):スキーマ From 577b635a3b03b0acb96539b476f401bd832ec8d9 Mon Sep 17 00:00:00 2001 From: Steedos Date: Thu, 29 Oct 2026 12:05:03 +0000 Subject: [PATCH 04/22] fix(search): keep one locale index and read search text from build output (#393) /api/search kept every locale's Orama index (30-40 MB each) and every page module page.data.load() imported, so one Worker isolate grew from 58 MB after its first locale to 283 MB after all eight, and #390's ja pages tipped it past 128 MB into 503s. - scripts/gen-search-data.mjs computes each page's structuredData before next build with fumadocs-mdx's own remark chain and writes one gzipped module per locale to apps/docs/.search/; the route reads that instead of importing page modules. - The route keeps the most recently used locale's index only. - check-search-heap.mjs asks the built route in every locale twice and fails above 100 MB or when the second pass keeps growing; it runs in ci.yml after check-search-locales and its --self-test is in SELF_TESTED. Measured on the built route: levels at 50-54 MB across both passes. Fixes #393 Claude-Session: https://claude.ai/code/session_01QsR2jRsjbApbf83iyTDDXm Co-Authored-By: Claude --- .github/scripts/check-search-heap.mjs | 179 ++++++++++++++++++++++++++ .github/workflows/ci.yml | 12 ++ apps/docs/app/api/search/route.ts | 90 +++++++++++-- apps/docs/package.json | 6 +- apps/docs/scripts/gen-search-data.mjs | 121 +++++++++++++++++ tools/ci-scripts/run-self-tests.mjs | 8 ++ 6 files changed, 401 insertions(+), 15 deletions(-) create mode 100644 .github/scripts/check-search-heap.mjs create mode 100644 apps/docs/scripts/gen-search-data.mjs diff --git a/.github/scripts/check-search-heap.mjs b/.github/scripts/check-search-heap.mjs new file mode 100644 index 00000000..414c4e57 --- /dev/null +++ b/.github/scripts/check-search-heap.mjs @@ -0,0 +1,179 @@ +#!/usr/bin/env node +/** + * The search heap gate for #393: the BUILT `/api/search` route stays under a + * heap budget while it is asked in every locale `apps/docs/lib/i18n.ts` + * declares. + * + * #390 added eleven ja pages, every gate was green, and after the deploy + * `/api/search` answered 503 in two or three locales per smoke run, so the site + * rolled back twice. A Cloudflare Worker isolate has 128 MB. The route kept + * every locale's Orama index (30–40 MB each) in one map, so the second or third + * locale an isolate served pushed it over. Nothing measured that before the + * deploy: the route is dynamic, and `check-search-locales.mjs` asks the right + * questions but not how much memory the answers cost. Measured on the built + * route at `09784e7`, heap after a forced GC: 58 MB after the first locale, + * 283 MB after all eight. + * + * So this gate asks the way an isolate is asked. It loads the route handler out + * of `apps/docs/.next/`, calls its `GET` in-process with `?query=permissions` + * in each locale in turn, and then once more in each, and reads `heapUsed` + * after a forced GC after every request: + * + * - `threw`, `status`: a request that throws or answers anything but 200. + * A heap reading after a failed request measures nothing. + * - `over-budget`: the heap after any request is above `BUDGET`. 100 MB + * leaves 28 MB of the isolate's 128 MB for what Node's `heapUsed` does not + * count (code, the Worker runtime) and for the peak while an index builds. + * - `still-growing`: the second round settles more than `GROWTH` above the + * first round's highest reading. Whatever the route keeps per locale has to + * stop growing once every locale has been asked; a leak under the budget + * today is the next content PR's 503. + * + * Run it after `pnpm turbo run build`, because a missing build fails it. It + * needs `--expose-gc` and re-runs itself with the flag when started without it. + * `--self-test` runs every rule against fake handlers and fake heap readings, + * and needs no build. + */ +import { spawnSync } from 'node:child_process'; +import { existsSync, readFileSync } from 'node:fs'; +import { createRequire } from 'node:module'; +import { dirname, join, resolve } from 'node:path'; +import { fileURLToPath } from 'node:url'; + +const ROOT = resolve(dirname(fileURLToPath(import.meta.url)), '../..'); +const ROUTE = 'apps/docs/.next/server/app/api/search/route.js'; +const QUERY = 'permissions'; +const MB = 1024 * 1024; +const BUDGET = 100 * MB; // `over-budget`: of a Worker isolate's 128 MB +const GROWTH = 8 * MB; // `still-growing`: how far round two may settle above round one + +const RULES = ['threw', 'status', 'over-budget', 'still-growing']; + +/** `languages` out of `i18n.ts`. Throws rather than guessing. */ +function readLanguages(text) { + const list = /languages:\s*\[([^\]]+)\]/.exec(text)?.[1]; + const languages = list?.split(',').map((s) => s.trim().replace(/['"]/g, '')).filter(Boolean) ?? []; + if (!languages.length) throw new Error('could not read languages[] out of apps/docs/lib/i18n.ts'); + return languages; +} + +/** One request. A rejection is recorded, because Next turns it into a 500. */ +async function ask(GET, locale) { + const url = `http://localhost/api/search?locale=${encodeURIComponent(locale)}&query=${QUERY}`; + try { + const res = await GET(new Request(url)); + await res.arrayBuffer(); + return { status: res.status }; + } catch (err) { + return { threw: err?.code ?? String(err?.message ?? err).split('\n')[0] }; + } +} + +const mb = (bytes) => `${(bytes / MB).toFixed(1)} MB`; + +/** Two rounds over `languages`; `heap()` reads `heapUsed` after a forced GC. */ +async function evaluate(GET, languages, heap) { + const findings = []; + const rows = []; + const add = (rule, detail) => findings.push({ rule, detail }); + const peaks = [0, 0]; + const settled = [0, 0]; + rows.push(['route loaded', mb(heap())]); + for (const round of [0, 1]) { + for (const locale of languages) { + const r = await ask(GET, locale); + const label = `${round ? 'again ' : ''}${locale}`; + if (r.threw) add('threw', `${label}: the handler threw ${r.threw}, which Next serves as a 500`); + else if (r.status !== 200) add('status', `${label}: HTTP ${r.status}`); + if (r.threw || r.status !== 200) return { findings, rows }; + const used = heap(); + rows.push([label, mb(used)]); + if (used > BUDGET) add('over-budget', `${label}: ${mb(used)} after GC, above the ${mb(BUDGET)} budget`); + peaks[round] = Math.max(peaks[round], used); + settled[round] = used; + } + } + if (settled[1] - peaks[0] > GROWTH) { + add('still-growing', `round two settled at ${mb(settled[1])}, ${mb(settled[1] - peaks[0])} above round one's highest ${mb(peaks[0])}, more than ${mb(GROWTH)}`); + } + return { findings, rows }; +} + +async function gate() { + if (typeof globalThis.gc !== 'function') { + const child = spawnSync(process.execPath, ['--expose-gc', fileURLToPath(import.meta.url), ...process.argv.slice(2)], { stdio: 'inherit' }); + return child.status ?? 1; + } + const route = join(ROOT, ROUTE); + if (!existsSync(route)) { + console.error(`✗ search heap: ${ROUTE} does not exist. Run pnpm turbo run build first.`); + return 1; + } + const languages = readLanguages(readFileSync(join(ROOT, 'apps/docs/lib/i18n.ts'), 'utf8')); + const GET = (await createRequire(import.meta.url)(route))?.routeModule?.userland?.GET; + if (typeof GET !== 'function') { + console.error(`✗ search heap: ${ROUTE} exposes no routeModule.userland.GET, so nothing was measured.`); + return 1; + } + const heap = () => { + globalThis.gc(); + globalThis.gc(); + return process.memoryUsage().heapUsed; + }; + const { findings, rows } = await evaluate(GET, languages, heap); + console.log(['| after | heapUsed after GC |', '|:--|--:|', ...rows.map(([a, b]) => `| ${a} | ${b} |`)].join('\n')); + for (const f of findings) console.error(` (${f.rule}) ${f.detail}`); + if (findings.length) { + console.error(`\n✗ search heap: ${findings.length} finding(s). The rules are in this script's header.`); + return 1; + } + console.log(`\n✓ search heap: every locale asked twice, heap stayed under ${mb(BUDGET)} and stopped growing`); + return 0; +} + +/* Self-test: one clean fake, then one fake per rule that must break exactly that rule. */ +const LANGS = ['en', 'ja', 'de']; +const ok = async () => new Response('[]'); +/** Heap readings in order: route loaded, then one per request across both rounds. */ +const readings = (...values) => { + const queue = values.map((v) => v * MB); + return () => queue.shift() ?? queue.at(-1) ?? 0; +}; +const CASES = [ + ['clean: levels off under the budget', ok, readings(18, 60, 85, 86, 86, 85, 86), []], + ['ja throws', async (req) => (new URL(req.url).searchParams.get('locale') === 'ja' ? Promise.reject(new Error('x')) : new Response('[]')), readings(18, 60), ['threw']], + ['ja answers 503, as the Worker did', async (req) => new Response('', { status: new URL(req.url).searchParams.get('locale') === 'ja' ? 503 : 200 }), readings(18, 60), ['status']], + ['every index kept: over the budget', ok, readings(18, 58, 98, 137, 137, 137, 137), ['over-budget', 'over-budget', 'over-budget', 'over-budget']], + ['a slow leak under the budget', ok, readings(18, 60, 64, 68, 72, 76, 80), ['still-growing']], + ['round two at round one\'s peak is level', ok, readings(18, 60, 90, 70, 90, 70, 90), []], +]; + +async function selfTest() { + let failed = 0; + const fired = new Set(); + for (const [name, GET, heap, want] of CASES) { + const got = (await evaluate(GET, LANGS, heap)).findings.map((f) => f.rule).sort(); + got.forEach((r) => fired.add(r)); + const pass = JSON.stringify(got) === JSON.stringify([...want].sort()); + if (!pass) failed += 1; + console.log(`${pass ? '✓' : '✗'} ${name}: ${got.length ? got.join(', ') : 'no findings'}`); + } + const silent = RULES.filter((r) => !fired.has(r)); + if (silent.length) { + failed += 1; + console.log(`✗ rules no fixture makes fire: ${silent.join(', ')}`); + } + const langsOk = readLanguages("defineI18n({ languages: ['en', 'zh-Hans'] })").join() === 'en,zh-Hans'; + let unreadable = false; + try { + readLanguages('defineI18n({})'); + } catch { + unreadable = true; + } + if (!langsOk || !unreadable) failed += 1; + console.log(`${langsOk ? '✓' : '✗'} i18n.ts is read; ${unreadable ? '✓' : '✗'} an unreadable one is rejected`); + console.log(failed ? `\n✗ search heap self-test: ${failed} failure(s)` : `\n✓ search heap self-test: ${CASES.length} cases, all ${RULES.length} rules can fire`); + return failed ? 1 : 0; +} + +process.exitCode = process.argv.includes('--self-test') ? await selfTest() : await gate(); diff --git a/.github/workflows/ci.yml b/.github/workflows/ci.yml index 266f3410..0ed37e43 100644 --- a/.github/workflows/ci.yml +++ b/.github/workflows/ci.yml @@ -199,6 +199,18 @@ jobs: shell: bash run: node .github/scripts/check-search-locales.mjs | tee -a "$GITHUB_STEP_SUMMARY" + # #393: #390's eleven ja pages passed every step above, and after the + # deploy `/api/search` answered 503 and the site rolled back twice. A + # Worker isolate has 128 MB, and the route kept every locale's index + # (30–40 MB each). This step asks the BUILT handler in every locale, then + # in each once more, the way one isolate is asked, and fails when the + # heap after a forced GC goes above 100 MB or is still growing on the + # second pass. A content PR that would tip the Worker over goes red here, + # not after the deploy. Same footing as the step above. + - name: Search fits the Worker's memory + shell: bash + run: node --expose-gc .github/scripts/check-search-heap.mjs | tee -a "$GITHUB_STEP_SUMMARY" + - run: pnpm turbo run test # Defect 2 of #269: the deploy used to run its own `pnpm install` and its diff --git a/apps/docs/app/api/search/route.ts b/apps/docs/app/api/search/route.ts index 46004afc..b41e3342 100644 --- a/apps/docs/app/api/search/route.ts +++ b/apps/docs/app/api/search/route.ts @@ -1,5 +1,6 @@ import { source } from '@/lib/source'; import { i18n } from '@/lib/i18n'; +import { searchData } from '@/.search'; import { createSearchAPI, type AdvancedIndex, @@ -118,22 +119,65 @@ function breadcrumbs(locale: Locale, url: string): string[] | undefined { return names.filter((name): name is string => typeof name === 'string' && name.length > 0); } -/** `locale`'s pages, indexed as `createFromSource` indexes them. */ +type StructuredData = AdvancedIndex['structuredData']; + +/** + * One locale's `structuredData` — each page's headings and paragraphs — keyed + * by file path under `content/docs`, from `.search/` (#393). + * + * `scripts/gen-search-data.mjs` writes it before every build, with the same + * remark chain fumadocs-mdx compiles the pages with. Reading it from there + * instead of from `page.data.load()` is the point: `load()` imports the page's + * compiled module, the module registry keeps it for the life of the isolate, + * and one locale's page modules are 4–5 MB of heap that outlived its index. + * The module imported here is one string, and the unzipped, parsed copy is + * dropped once the index has the text. + */ +async function texts(locale: Locale): Promise> { + // Gzipped JSON in base64, because the module is Worker upload too. + const packed = (await searchData[locale]()).default; + const bytes = Uint8Array.from(atob(packed), (c) => c.charCodeAt(0)); + const json = new Blob([bytes]).stream().pipeThrough(new DecompressionStream('gzip')); + return JSON.parse(await new Response(json).text()); +} + +/** + * `locale`'s pages, indexed as `createFromSource` indexes them. A page that + * has no translation in `locale` is the default language's file, so its text + * is read from the default language's module. + */ async function indexes(locale: Locale): Promise { + const [own, fallback] = await Promise.all([ + texts(locale), + locale === i18n.defaultLanguage ? undefined : texts(i18n.defaultLanguage), + ]); return Promise.all( - source.getPages(locale).map(async (page) => ({ - id: page.url, - url: page.url, - title: page.data.title, - description: page.data.description, - structuredData: (await page.data.load()).structuredData, - breadcrumbs: breadcrumbs(locale, page.url), - })), + source.getPages(locale).map(async (page) => { + const file = page.data.info.path; + let structuredData = own[file] ?? fallback?.[file]; + if (!structuredData) { + // `next dev` serves pages added since it wrote `.search/`; a build + // writes it first, so there a missing page is a stale `.search/`. + if (process.env.NODE_ENV !== 'development') { + throw new Error(`/api/search: no search data for ${file}; run scripts/gen-search-data.mjs`); + } + structuredData = (await page.data.load()).structuredData; + } + return { + id: page.url, + url: page.url, + title: page.data.title, + description: page.data.description, + structuredData, + breadcrumbs: breadcrumbs(locale, page.url), + }; + }), ); } /** - * One index per locale, built on that locale's first search (#301). + * One index per locale, built on that locale's first search (#301), and only + * the most recent `KEEP` of them kept (#393, below). * * `createFromSource` with i18n builds every locale's index on the first search * in any locale, so the first reader after a cold start paid for all eight: @@ -156,16 +200,38 @@ async function indexes(locale: Locale): Promise { */ const servers = new Map(); +/** + * How many locales' indexes one isolate keeps (#393). + * + * One index is 30–40 MB of heap, and a Cloudflare Worker isolate has 128 MB in + * all. The map above used to keep every locale an isolate had served, so the + * second or third locale pushed it over and `/api/search` answered 503: on the + * built route at `09784e7`, heap after a forced GC grew from 58 MB after the + * first locale to 283 MB after all eight. Keeping the most recently used one + * holds it level. A search in another locale then pays that locale's build + * again (0.5–1.5 s), and a second entry would leave too little room for that + * build's peak. `.github/scripts/check-search-heap.mjs` measures the level + * after every build. + */ +const KEEP = 1; + function server(locale: Locale): SearchAPI { let found = servers.get(locale); - if (!found) { + if (found) { + // Most recently used last, so the first key is the one to drop. + servers.delete(locale); + } else { const options: Partial = localeOptions[locale]; found = createSearchAPI('advanced', { ...options, search: { ...options.search, sortBy: byWeightedScore }, indexes: () => indexes(locale), }); - servers.set(locale, found); + } + servers.set(locale, found); + for (const oldest of servers.keys()) { + if (servers.size <= KEEP) break; + servers.delete(oldest); } return found; } diff --git a/apps/docs/package.json b/apps/docs/package.json index f7a3034d..7d875e3c 100644 --- a/apps/docs/package.json +++ b/apps/docs/package.json @@ -5,12 +5,12 @@ "description": "ObjectOS Documentation Site", "license": "Apache-2.0", "scripts": { - "dev": "next dev", + "dev": "fumadocs-mdx && node scripts/gen-search-data.mjs && next dev", "gen:zh-hant": "node scripts/gen-zh-hant.mjs", - "build": "next build", + "build": "fumadocs-mdx && node scripts/gen-search-data.mjs && next build", "start": "next start", "lint": "next lint", - "type-check": "next typegen && fumadocs-mdx && tsc --noEmit && node scripts/check-frontmatter.mjs", + "type-check": "next typegen && fumadocs-mdx && node scripts/gen-search-data.mjs && tsc --noEmit && node scripts/check-frontmatter.mjs", "postinstall": "fumadocs-mdx", "preview": "opennextjs-cloudflare build && opennextjs-cloudflare preview", "deploy": "opennextjs-cloudflare build && opennextjs-cloudflare deploy", diff --git a/apps/docs/scripts/gen-search-data.mjs b/apps/docs/scripts/gen-search-data.mjs new file mode 100644 index 00000000..59c20e38 --- /dev/null +++ b/apps/docs/scripts/gen-search-data.mjs @@ -0,0 +1,121 @@ +#!/usr/bin/env node +/** + * Writes the text `/api/search` indexes, one module per locale (#393). + * + * The route used to read each page's `structuredData` (its headings and + * paragraphs) through `page.data.load()`, which imports the page's compiled + * MDX module. That is the whole rendered page, highlighted code included, and + * a module once imported stays in the module registry for the life of the + * isolate. Building one locale's index therefore left every page module of + * that locale resident after the index was gone. Measured on the built route + * at `09784e7`, with only one index kept: 58 MB after English, 86 MB after all + * eight locales, about 94 MB with ja fully translated, against a Worker + * isolate's 128 MB. + * + * So the same `structuredData` is computed here, before `next build`, and + * written as one string per locale to `.search/.ts`: the JSON, + * gzipped, in base64. The route imports the locale it is asked for, unzips and + * parses it. What stays resident is that string, not the page modules. + * + * Gzipped because the string is also Worker upload, which has a budget the + * `Worker bundle fits the size budget` CI step holds: as plain JSON the + * English, zh-Hans and zh-Hant modules were about 1 MB each, 3.5 MB of the + * 6 MB headroom main had at `09784e7`; gzipped and in base64, about a third. + * + * It is the same `structuredData`, not a lookalike. The processor is + * fumadocs-mdx's own remark chain, built with the public `applyMdxPreset` from + * the compiled `source.config` (`.source/source.config.mjs`, written by the + * `fumadocs-mdx` CLI), plus `remarkInclude`, which `buildMDX` puts first. + * `remarkStructure` runs in the remark phase, so the rehype plugins, which run + * after it and only shape the rendered HTML, are left out: that is + * `rehypeCode`, and it is most of the cost. + * + * A file's locale is its suffix, as `source.config.ts` reads it: `foo.ja.mdx` + * is `ja`, `foo.mdx` is the default language. A locale whose page falls back + * to English reads that page from the default language's module, so English + * text is written once. + * + * The output directory carries its own `.gitignore`, because it is a build + * product. Run from `apps/docs`, after `fumadocs-mdx`, as the `build`, + * `type-check` and `dev` scripts do. + */ +import { applyMdxPreset, remarkInclude } from 'fumadocs-mdx/config'; +import { frontmatter } from 'fumadocs-core/content/md/frontmatter'; +import { createRequire } from 'node:module'; +import { existsSync, mkdirSync, readFileSync, readdirSync, rmSync, writeFileSync } from 'node:fs'; +import { dirname, join, relative, resolve } from 'node:path'; +import { fileURLToPath, pathToFileURL } from 'node:url'; +import { gzipSync } from 'node:zlib'; + +const APP = resolve(dirname(fileURLToPath(import.meta.url)), '..'); +const CONTENT = resolve(APP, '../../content/docs'); +const CONFIG = join(APP, '.source/source.config.mjs'); +const OUT = join(APP, '.search'); + +/** `languages` and `defaultLanguage` out of `lib/i18n.ts`, read as text. Throws rather than guessing. */ +function readI18n() { + const text = readFileSync(join(APP, 'lib/i18n.ts'), 'utf8'); + const languages = /languages:\s*\[([^\]]+)\]/.exec(text)?.[1]?.split(',').map((s) => s.trim().replace(/['"]/g, '')).filter(Boolean) ?? []; + const defaultLanguage = /defaultLanguage:\s*['"]([^'"]+)['"]/.exec(text)?.[1]; + if (!languages.length || !languages.includes(defaultLanguage)) { + throw new Error('could not read languages[] and defaultLanguage out of apps/docs/lib/i18n.ts'); + } + return { languages, defaultLanguage }; +} + +function walk(dir) { + return readdirSync(dir, { withFileTypes: true }) + .flatMap((e) => (e.isDirectory() ? walk(join(dir, e.name)) : e.name.endsWith('.mdx') ? [join(dir, e.name)] : [])) + .sort(); +} + +if (!existsSync(CONFIG)) { + console.error(`✗ search data: ${relative(process.cwd(), CONFIG)} does not exist. Run \`fumadocs-mdx\` first.`); + process.exit(1); +} + +const { languages, defaultLanguage } = readI18n(); +// @mdx-js/mdx is fumadocs-mdx's dependency, not this app's, so it is resolved from there: the copy buildMDX uses. +const { createProcessor } = await import( + pathToFileURL(createRequire(import.meta.resolve('fumadocs-mdx')).resolve('@mdx-js/mdx')).href +); +const config = (await import(pathToFileURL(CONFIG).href)).default; +const mdx = await applyMdxPreset({ ...config.mdxOptions, rehypeCodeOptions: false })('bundler'); +const processor = createProcessor({ + outputFormat: 'program', + ...mdx, + remarkPlugins: [remarkInclude, ...(mdx.remarkPlugins ?? [])], + rehypePlugins: [], + format: 'mdx', +}); + +const byLocale = new Map(languages.map((l) => [l, {}])); +for (const path of walk(CONTENT)) { + const file = relative(CONTENT, path).split('\\').join('/'); + const locale = languages.find((l) => l !== defaultLanguage && file.endsWith(`.${l}.mdx`)) ?? defaultLanguage; + const vfile = await processor.process({ + path, + value: frontmatter(readFileSync(path, 'utf8')).content, + data: { frontmatter: {}, _getProcessor: () => processor }, + }); + if (!vfile.data.structuredData) throw new Error(`${file}: remarkStructure wrote no structuredData`); + byLocale.get(locale)[file] = vfile.data.structuredData; +} + +rmSync(OUT, { recursive: true, force: true }); +mkdirSync(OUT, { recursive: true }); +writeFileSync(join(OUT, '.gitignore'), '*\n'); +const banner = '// Generated by scripts/gen-search-data.mjs before every build. Do not edit.\n'; +for (const [locale, pages] of byLocale) { + // A string, not an object literal: the route parses it when it builds the + // index, and the parsed copy is garbage once the index holds the text. + const packed = gzipSync(JSON.stringify(pages), { level: 9 }).toString('base64'); + writeFileSync(join(OUT, `${locale}.ts`), `${banner}export default ${JSON.stringify(packed)};\n`); +} +const loaders = languages.map((l) => ` ${JSON.stringify(l)}: () => import(${JSON.stringify(`./${l}`)}),`).join('\n'); +writeFileSync( + join(OUT, 'index.ts'), + `${banner}/** Each locale's \`structuredData\`, keyed by file path under content/docs, as gzipped JSON in base64. */\nexport const searchData = {\n${loaders}\n} as const;\n`, +); +const sizes = [...byLocale].map(([l, pages]) => `${l} ${Object.keys(pages).length}`).join(', '); +console.log(`✓ search data: wrote .search/ (pages per locale: ${sizes})`); diff --git a/tools/ci-scripts/run-self-tests.mjs b/tools/ci-scripts/run-self-tests.mjs index f5cbadad..fb1f15f6 100644 --- a/tools/ci-scripts/run-self-tests.mjs +++ b/tools/ci-scripts/run-self-tests.mjs @@ -114,6 +114,13 @@ * malformed pin or SHA is refused, that the same commit bumps nothing, and that * the pull-request body stays inside GitHub's size limit with every upstream * reference inside a fence. + * + * `check-search-heap.mjs` is listed for its `--self-test` only (#393), on the + * footing of `check-search-locales.mjs`: its gate mode loads the built search + * route out of `apps/docs/.next/`, so it is a `ci.yml` step after the build. + * Its fixtures are fake handlers and fake heap readings. They prove that a + * failed request, a reading above the budget, and a heap still growing on the + * second pass each go red. */ import { readFileSync, readdirSync, existsSync } from 'node:fs'; @@ -137,6 +144,7 @@ const SELF_TESTED = [ 'check-translation-ownership.mjs', 'check-positioning.mjs', 'check-search-locales.mjs', + 'check-search-heap.mjs', 'check-doc-samples.mjs', 'bump-upstream-pin.mjs', ]; From d0ad718131deb91d673f13e93c22983b6bfe061e Mon Sep 17 00:00:00 2001 From: Steedos Date: Thu, 29 Oct 2026 12:22:00 +0000 Subject: [PATCH 05/22] docs(i18n): re-land build/automation/ and build/interface/ ja pages (#388, PR 2 of 7) Reverts #392, which reverted #390 because /api/search ran out of Worker memory. #394 (#393) fixed that, so the same 11 ja pages come back unchanged. Refs #388 Claude-Session: https://claude.ai/code/session_01QsR2jRsjbApbf83iyTDDXm Co-Authored-By: Claude --- .../docs/build/automation/approvals.ja.mdx | 279 ++++++++++++ content/docs/build/automation/flows.ja.mdx | 404 ++++++++++++++++++ content/docs/build/automation/index.ja.mdx | 43 ++ .../docs/build/automation/workflows.ja.mdx | 181 ++++++++ content/docs/build/interface/actions.ja.mdx | 208 +++++++++ content/docs/build/interface/apps.ja.mdx | 137 ++++++ .../docs/build/interface/dashboards.ja.mdx | 201 +++++++++ content/docs/build/interface/forms.ja.mdx | 175 ++++++++ content/docs/build/interface/index.ja.mdx | 49 +++ content/docs/build/interface/pages.ja.mdx | 166 +++++++ content/docs/build/interface/views.ja.mdx | 294 +++++++++++++ 11 files changed, 2137 insertions(+) create mode 100644 content/docs/build/automation/approvals.ja.mdx create mode 100644 content/docs/build/automation/flows.ja.mdx create mode 100644 content/docs/build/automation/index.ja.mdx create mode 100644 content/docs/build/automation/workflows.ja.mdx create mode 100644 content/docs/build/interface/actions.ja.mdx create mode 100644 content/docs/build/interface/apps.ja.mdx create mode 100644 content/docs/build/interface/dashboards.ja.mdx create mode 100644 content/docs/build/interface/forms.ja.mdx create mode 100644 content/docs/build/interface/index.ja.mdx create mode 100644 content/docs/build/interface/pages.ja.mdx create mode 100644 content/docs/build/interface/views.ja.mdx diff --git a/content/docs/build/automation/approvals.ja.mdx b/content/docs/build/automation/approvals.ja.mdx new file mode 100644 index 00000000..c0d4b0ef --- /dev/null +++ b/content/docs/build/automation/approvals.ja.mdx @@ -0,0 +1,279 @@ +--- +title: 承認 +seoTitle: "承認フロー:レコードを人による承認へ回す" +description: レコードを人による承認へ回します。自動化が行レベルセキュリティを黙ってすり抜けることはさせません。 +editions: [community, cloud, enterprise] +translation: + source_sha: e03dd11f32910f971d7514f12aab8e3c2ac1eceb25966b2b4162185eb062a521 + guide_rev: 1 + mode: auto +--- + +**承認とは、承認ノードを持つ[フロー](/docs/build/automation/flows)です。フローは人が承認または却下するまで一時停止し、その後、対応する分岐に沿って再開します。** 新たに覚えるべき独立した承認エンジンはありません。トリガー、分岐、エラー処理は、ほかのフローとまったく同じように動作します。このページが加えるのは承認ノードそのものと、ルーティングと同じくらい重要な 2 つのアクセスの判断です。 + +## 誰が何をするか [#who-does-what] + +意図的に分けられた 3 つのロールです。 + +| ロール | できること | 必要なもの | +|---|---|---| +| **ビルダー** | 承認フローを作成、編集する | `manage_metadata`(通常は Studio のユーザー) | +| **申請者** | フローに入るレコードを申請する | 通常のレコードアクセス。自動化の設定は不要 | +| **承認者** | 承認依頼に対応する(承認 / 却下) | 権限セットで付与された機能 | + +エンドユーザーはレコードを申請し、依頼に対応します。自動化を編集することはありません。自動化の設定画面は、利用者向けのアプリに含めないでください。 + +## 誰として実行するか:安全上の判断 [#as-whom-does-it-run--the-safety-decision] + +フローは `runAs` を宣言します。承認にとって、これはフローが行レベルセキュリティを黙ってすり抜けないようにするための判断です。 + +| `runAs` | データ操作を実行する主体 | 使う場面 | +|---|---|---| +| `'user'`(デフォルト) | **申請者**。その RLS に従います | フローが、申請者がすでに見られるレコードにだけ触れる場合 | +| `'system'` | **昇格**。RLS をすり抜けます | 申請者が見られないレコードをフローが読み書きしなければならない場合(元帳への記帳、申請者が見られない行を所有する承認者への通知) | + +昇格は、偶然ではなく見える形にするために**明示的に**宣言します。デフォルトが `'user'` なので、承認フローが申請者に、テナントや所有者をまたぐ到達範囲を黙って与えることはできません。昇格はオプトインで、監査できます。 + +> **ヒント:** スケジュールで起動するエスカレーションには起動したユーザーがいないので、そもそも動作させるには `runAs: 'system'` でなければなりません。これが昇格の正当なケースです。「動かすためにどこでも `system`」はアンチパターンです。 + +## 承認ノード [#the-approval-node] + +ノードは**誰が承認するか**と、その判断をどう集約するかを宣言します。 + +```ts +// One flow node; the flow around it is omitted (see the complete flow below). +{ + id: 'manager_approval', + type: 'approval', + label: 'Manager Approval', + config: { + approvers: [{ type: 'field', value: 'owner_manager_id' }], + behavior: 'unanimous', + approvalStatusField: 'approval_status', + lockRecord: true, + }, +} +``` + +| 設定 | 働き | +|---|---| +| `approvers` | 誰が判断しなければならないか。下記の承認者の種類を参照 | +| `behavior` | 複数の承認者をどう集約するか:`'first_response'`(デフォルト)、`'unanimous'`、`'quorum'`、`'per_group'` | +| `minApprovals` | 必要な承認数。`quorum` では合計(N 人中 M 人)、`per_group` ではグループごと(デフォルト 1) | +| `onEmptyApprovers` | 承認者の解決結果が誰もいなかったときの動作:`'admin_rescue'`(デフォルト)、`'fail'`、`'auto_approve'` | +| `decisionOutputs` | 判断が構造化された出力としてフローに持ち帰れるキー | +| `approvalStatusField` | プラグインが依頼のステータスを反映する、省略可能なレコードのフィールド | +| `lockRecord` | 依頼が保留中の間、レコードを編集からロックします | + +`approvers` の各エントリは `type` と `value` を指定します。 + +| `type` | 解決先 | +|---|---| +| `manager` | 申請者のマネージャー(`sys_user.manager_id`)。value は取りません | +| `position` | 組織のポジションの保持者 | +| `department` | 事業単位**とそのすべての下位単位**のメンバー | +| `team` | フラットなコラボレーションチームのメンバー | +| `field` | 起動したレコードのフィールドが保持するユーザー ID | +| `user` | 名前で指定した 1 人のユーザー ID | +| `org_membership_level` | [組織メンバーシップの階層](/docs/configure/users#organization-membership-tiers)(`owner` / `admin` / `delegated_admin` / `member`) | +| `expression` | ノードに入るときに解決される CEL 式。下記を参照 | + +文字どおりの `user` ID よりも、間接的なバインディング(`manager`、`position`、`department`、`team`)を優先してください。本人がチームを移ったり退職したりしても機能し続けますが、ハードコードされた ID は、もう承認を見るべきではない人に黙って承認を回してしまいます。 + +> **警告:`position` とメンバーシップの階層。** `{ type: 'position', value: 'finance_manager' }` はポジション(`sys_user_position`)の保持者に回します。[組織メンバーシップの階層](/docs/configure/users#organization-membership-tiers)(`sys_member.role`:`owner`/`admin`/`delegated_admin`/`member`)は 16.0 以降 `type: 'org_membership_level'` で指定します。旧来の表記 `role` は **1 リリースの間だけの非推奨エイリアス**で、警告付きで今も同じように読み込まれて解決されますが、次のメジャーで削除されます。メンバーシップ階層の種類として書かれたポジション名は誰にも一致せず、依頼は止まってしまいます。`os lint` は両方のケースを指摘します(`approval-approver-not-membership-tier`、`approval-approver-type-deprecated`)。value が組織のポジションを指している場合、修正は `type: 'position'` です。 + +### クォーラムとグループごとの承認(16.0) [#quorum-and-per-group-sign-off-160] + +`first_response` と `unanimous` に加えて、16.0 では 2 つの集約モードが追加されました。**クォーラム**は N 人中 M 人の承認で確定します。 + +```ts +// The `config` of an `approval` node; the node around it is omitted. +config: { + approvers: [ + { type: 'user', value: 'director_a' }, + { type: 'user', value: 'director_b' }, + { type: 'user', value: 'director_c' }, + ], + behavior: 'quorum', + minApprovals: 2, // any 2 of the 3 approve +} +``` + +**グループごと**は、ラベル付けされた*各*グループからの承認(会签)を必要とします。承認者に `group` でラベルを付けると、すべてのグループが `minApprovals` 件の承認(デフォルトはグループごとに 1)を得たときにだけノードが先に進みます。 + +```ts +// The `config` of an `approval` node; the node around it is omitted. +config: { + approvers: [ + { type: 'position', value: 'legal_counsel', group: 'legal' }, + { type: 'position', value: 'finance_manager', group: 'finance' }, + ], + behavior: 'per_group', // one sign-off from legal AND one from finance +} +``` + +すべてのモードに共通する意味: + +- 承認者の集合は、不在時の代理を含む**依頼開始時のスナップショット**に照らして集計されます。誰が応答しなければならないかは依頼が開始されたときに確定し、不在の承認者は依頼を止めるのではなく代理に置き換えられます。 +- **1 件の却下はやはり拒否権です**。どのモードでも、ノードを `rejected` として確定させます。 +- しきい値は実行時に、解決できる承認者の数に**切り詰められる**ので、誤設定された `minApprovals` が依頼をデッドロックさせることはありません。 +- `group` ラベルのない承認者はそれぞれが独自のグループになるので、ラベルなしの承認者リストでも `per_group` のもとで妥当に動作します。 + +### 動的なルーティング:承認者が次の承認者を選ぶ(17.0) [#dynamic-routing-an-approver-picks-the-next-approver-170] + +17.0 で追加された 3 つの機能により、ノードは固定の宣言からではなく、実行がそれまでに生み出したものから承認者を決められます。 + +**`expression` 承認者**は、ノードに入るときに、3 つの明示的なルートに対して CEL 式を解決します。`current.*`(レコードの現在の状態)、`trigger.*`(申請時のスナップショット)、`vars.*`(上流ノードの出力を含むフロー変数)です。結果が承認者の顔ぶれになります。 + +```ts +// The `config` of an `approval` node; the node around it is omitted. +config: { + approvers: [ + { + type: 'expression', + value: 'vars.legal_review.picked_departments', + resolveAs: 'department', // each value is a department id, fanned out to its members + }, + ], +} +``` + +`resolveAs` は `expression` 承認者自身のキー(デフォルトは `'user'`、または `'department'` / `'position'` / `'team'`)で、式が返した ID の種類を示し、静的な承認者の種類と同じグラフ検索で各 ID を展開します。`behavior: 'per_group'` のもとでは、返された各値が独自のグループになり、返された部署ごとに 1 件の承認が必要になります。 + +`record` と素のフィールド名は意図的に**使えません**。プラットフォームのほかのすべての場面で `record` は「イベント時点のレコード」を意味しており、ここで再利用すると 2 つの時点のどちらかを黙って指してしまうからです。 + +上のような式に値を供給するのが **`decisionOutputs`** です。判断が持ち帰れるキーは*作成者*が宣言し、承認者は値を埋めるだけです。受け付けられた出力は `.` というフロー変数として実行を再開させます。素の名前には決してならないので、承認者が作成者の変数を覆い隠すことはできません。 + +```ts +// One flow node; the flow around it is omitted. +{ + id: 'legal_review', + type: 'approval', + label: 'Legal Review', + config: { + approvers: [{ type: 'position', value: 'legal_counsel' }], + decisionOutputs: [ + { key: 'picked_departments', type: 'department', multiple: true }, + ], + }, +} +``` + +エントリは、素のキー(判断の UI ではプレーンなテキスト入力としてレンダリングされます)か、型付きの宣言 `{ key, type, multiple }` のいずれかです。型付きの宣言は、判断の UI に代わりにレコードピッカーをレンダリングさせます。`user` / `department` / `position` / `team` はそれぞれ対応するシステムオブジェクトのピッカーになり、`multiple: true` は ID の配列を集めます。宣言されていないキーを持つ判断は拒否されます。`decision` と `requestId` は予約されています。 + +**`onEmptyApprovers`** は、解決結果に具体的な人が 1 人もいないとき(式の結果が空、ポジションに人がいない、複数選択フィールドが空)の動作を決めます。 + +| 値 | 動作 | +|---|---| +| `'admin_rescue'`(デフォルト) | とにかく依頼を開始し、大きく警告します。特権を持つ管理者が Reassign で引き継げます。レコードを素通りさせることも、実行を止めることもしない唯一の選択肢です | +| `'fail'` | ノードが失敗します(fault エッジ / 実行の失敗)。顔ぶれが空なら設定のバグとしか考えられない場合に選びます | +| `'auto_approve'` | 依頼をスキップし、`output.autoApproved = true` とともに `approve` エッジに沿って続行します。レコードを黙って素通りさせるので、オプトインです | + +このデフォルトは意図的なものです。承認の役目は門番なので、空の顔ぶれが黙って通ることがあってはなりません。 + +## 完全な承認フロー [#a-complete-approval-flow] + +大型の提案を所有者のマネージャーに回し、その判断で分岐します。 + +```ts +export const opportunityApproval = defineFlow({ + name: 'opportunity_approval', + label: 'Opportunity Approval', + type: 'record_change', + status: 'active', + runAs: 'user', // submitter's RLS unless a step genuinely needs more + nodes: [ + { + id: 'start', + type: 'start', + label: 'Proposal over 50,000', + config: { + triggerType: 'record-after-update', + objectName: 'opportunity', + condition: "record.amount >= 50000 && record.stage == 'proposal'", + }, + }, + { + id: 'manager_approval', + type: 'approval', + label: 'Manager Approval', + config: { + approvers: [{ type: 'field', value: 'owner_manager_id' }], + behavior: 'unanimous', + approvalStatusField: 'approval_status', + lockRecord: true, + }, + }, + { + id: 'mark_approved', + type: 'update_record', + label: 'Mark Approved', + config: { + objectName: 'opportunity', + filter: { id: '{record.id}' }, + fields: { stage: 'negotiation' }, + }, + }, + { + id: 'mark_rejected', + type: 'update_record', + label: 'Mark Rejected', + config: { + objectName: 'opportunity', + filter: { id: '{record.id}' }, + fields: { stage: 'closed_lost' }, + }, + }, + { id: 'end', type: 'end', label: 'End' }, + ], + edges: [ + { id: 'e1', source: 'start', target: 'manager_approval' }, + { id: 'approved', source: 'manager_approval', target: 'mark_approved', label: 'approve' }, + { id: 'rejected', source: 'manager_approval', target: 'mark_rejected', label: 'reject' }, + { id: 'e4', source: 'mark_approved', target: 'end' }, + { id: 'e5', source: 'mark_rejected', target: 'end' }, + ], +}); +``` + +ラベル付きのエッジに注目してください。`approve` と `reject` が判断後の分岐に名前を付けています。却下の経路は必ずモデル化してください。承認の分岐しかないフローでは、却下されたレコードが行き場を失います。 + +**多段階の承認:** 複数の `approval` ノードをつなぎます。**並行承認:** [フロー](/docs/build/automation/flows)の集約ノードのパターンを参照してください。 + +## 承認者が体験すること [#what-the-approver-experiences] + +永続的な承認の状態は `@objectstack/plugin-approvals` パッケージが管理します。依頼が保留中の間: + +1. プラグインは依頼(`sys_approval_request`)と、それに対して行われたすべての判断(`sys_approval_action`)を永続化します。承認の履歴はクエリできるデータです。 +2. `lockRecord: true` の場合、判断が下るまでレコードは編集からロックされます。 +3. `approvalStatusField` を設定すると、レコード自身のフィールドが依頼のステータスを反映するので、ビューやレポートでそれを使ってフィルターできます。 +4. 承認者が承認または却下すると、プラグインは一時停止していたフローを対応するエッジに沿って再開します。16.0 以降、判断には**添付ファイル**を付けられます(`sys_approval_action.attachments` に永続化され、decide/comment のルートとクライアント SDK を通じて受け渡されます)。署名済みの PDF や証拠は判断とともに保管されます。 +5. 依頼はサーバーで計算された **`decision_progress`** を公開します。`unanimous`/`quorum` では得た承認数と必要な承認数、`per_group` ではグループごとの内訳です。そのため受信トレイや独自の UI は、集計を再実装せずに進捗をレンダリングできます。 + +**依頼を見られるのは誰か(17.0)。** 依頼はレコードのスナップショット、判断の履歴全体、添付ファイルを持つので、読めるのはその参加者だけです。申請者、現在の承認者(依頼が待っているポジションの保持者を含む)、そしてすでに対応またはコメントした人です。プラットフォームと組織の管理者はすべての依頼を見られます。それ以外の人には何も見えず、レコードを読めるかどうかはそれを変えません。承認者で依頼リストをフィルターするのはフィルターであって付与ではありません。それを省くと、テナント全体ではなく、自分が参加している依頼だけが返されます。見える依頼の中でも、スナップショットからは、読み手がそのレコードで読めないフィールドがすべて取り除かれます。17.6 以降は、マスクされた状態でしか読めないフィールドもすべて取り除かれます。 + +**判断は宣言されたアクションです(16.0)。** 判断の全体(承認、却下、再割り当て、修正のための差し戻し(`/revise`)、情報の依頼、リマインド、取り消し、再申請)は、`sys_approval_request` 上の `type: 'api'` アクションとして宣言されており、型付きのパラメータ、保留中のときだけ表示するゲート、申請者か承認者かの述語(例:`record.submitter_id == ctx.user.id`)を持ちます。承認の受信トレイは、手書きのボタンではなく、これらの宣言されたアクションをレンダリングします。そのため新しい判断機能はメタデータとして出荷され、クライアントのリリースは必要ありません。 + +承認すること自体がゲート付きのアクションです。「承認してよい」は、承認者の権限セットで付与される機能(例:`approve_invoice`)としてモデル化し、承認アクションの `requiredPermissions` をそれでゲートします。そうすればゲートは画面から隠されるだけでなく、UI とサーバーの**両方**で強制されます。 + +## ベストプラクティス [#best-practices] + +| すること | しないこと | +|---|---| +| 明確な開始条件を定義する | 承認ステップを作りすぎる | +| 妥当なタイムアウト期間を設定する | 承認を複雑にしすぎる | +| 適切な場合は取り消しを許す | 却下の経路を忘れる | +| すべての関係者に通知する | 承認者をハードコードする | +| 承認の履歴を追跡する | 「承認」を UI でだけゲートする | +| デフォルトは `runAs: 'user'` にし、1 ステップずつ昇格する | 「動かすために」どこでも `runAs: 'system'` を設定する | + +## 次に進む [#where-to-go-next] + +| ページ | 理由 | +|---|---| +| [フロー](/docs/build/automation/flows) | このページの土台となるフローのリファレンス:トリガー、ステップ、エラー処理 | +| [ワークフロー](/docs/build/automation/workflows) | 承認が置かれるライフサイクルを制約する | +| [アクション](/docs/build/interface/actions) | 申請と承認をインターフェースのボタンとして表示する | +| [CEL 式](/docs/reference/cel) | 開始条件の背後にある言語 | +| [メール](/docs/configure/email) | 承認者と関係者に通知する | +| [自動化の概要](/docs/build/automation) | 選び方:フロー、ワークフロー、承認 | diff --git a/content/docs/build/automation/flows.ja.mdx b/content/docs/build/automation/flows.ja.mdx new file mode 100644 index 00000000..46a7b726 --- /dev/null +++ b/content/docs/build/automation/flows.ja.mdx @@ -0,0 +1,404 @@ +--- +title: フローと自動化 +description: 宣言的なビジネスロジック。AI に説明しても TypeScript で書いても、ランタイムはどちらの場合も同じ成果物を実行します。 +editions: [community, cloud, enterprise] +translation: + source_sha: 011506676f1192c1d884573299f8404d1cf906edfc56cb81b122979ba8410d43 + guide_rev: 1 + mode: auto +--- + +フローは、サーバーを書かずにビジネスロジックを表現する方法です。すべてのフローは、ランタイムが実行する宣言的なメタデータであり、オブジェクトやビューと同じです。そのため、フローは `os diff`、監査ログ、Studio のフロービルダー、そして [AI Builder](/docs/build/ai-builder) のすべてに同時に現れます。 + +ほとんどのお客様は、AI に頼んでフローを作成します。 + +> *「優先度の高いチケットが 'new' のまま 30 分経ったら、Slack でマネージャーに通知して」* + +AI はこのページで説明する形でフローのメタデータを生成するので、読んで編集できます。 + +フローはグラフです。`nodes` が作業を行い、`edges` がそれらをつなぎ、`start` ノードがフローを起動するものを示します。この形は ObjectStack の `FlowSchema` で、ObjectStack の [Flow metadata](https://objectstack.ai/docs/automation/flows) に完全に記載されています。 + +スタックでこの機能を有効にします。 + +```ts +export default defineStack({ + // ... + requires: ['automation', 'triggers'], // the flow engine, and the triggers that start flows +}); +``` + +両方のトークンが必要です。レコードの変更、スケジュール、API 呼び出しで開始するフローがあるのに `requires` にどちらかが欠けているスタックを、`defineStack` は拒否します。そのようなフローは登録されても決して実行されないからです。 + +## フローの種類 [#flow-types] + +| `type` | 起動するもの | 用途 | +|---|---|---| +| `record_change` | レコードの挿入、更新、削除。開始ノードで結び付けます | 「チケットが作成されたら担当者にメールする」 | +| `schedule` | 開始ノード上の cron スケジュール | 「毎晩午前 2 時に古いタスクをマークする」 | +| `schedule`、相対時間 *(16.0)* | 日付フィールドと今日との近さ。毎日のスイープで判定 | 「契約終了の 60 日前に通知する」 | +| `autolaunched` | アクションボタン、別のフロー、または API 呼び出し | 「請求書を承認」アクション | +| `screen` | ユーザー。1 つ以上の画面を通じて | ガイド付きのデータ入力 | +| `api` | 開始ノードの `config.secret` で署名された HTTP リクエスト | 外部システム向けのエンドポイント | + +## レコード変更:レコードの変更に反応する [#record-change-react-to-a-record-change] + +```ts +// src/flows/ticket_assigned_email.ts +import { defineFlow } from '@objectstack/spec'; + +export const ticketAssignedEmail = defineFlow({ + name: 'ticket_assigned_email', + label: 'Email the assignee of a new ticket', + type: 'record_change', + status: 'active', + nodes: [ + { + id: 'start', + type: 'start', + label: 'Ticket created', + config: { objectName: 'support_ticket', triggerType: 'record-after-create' }, + }, + { + id: 'email_assignee', + type: 'notify', + label: 'Email the assignee', + config: { + recipients: '{record.assignee}', + title: 'New ticket: {record.subject}', + message: 'You have been assigned {record.subject}, priority {record.priority}.', + channels: ['email'], + }, + }, + { id: 'end', type: 'end', label: 'End' }, + ], + edges: [ + { id: 'e1', source: 'start', target: 'email_assignee' }, + { id: 'e2', source: 'email_assignee', target: 'end' }, + ], +}); +``` + +メールは `notify` ノードを通じて送られます。独立したメールノードの種類はありません。`channels: ['email']` は、[メール](/docs/configure/email)で設定されたトランスポートを通じて、メールチャネルで通知を送ります。`channels` がなければ、通知はアプリ内の受信トレイにだけ届きます。インラインのテキストの代わりに保存済みのメールテンプレートを送るには、`title` と `message` の代わりに `template`(`sys_email_template` の名前)を設定します。 + +ノードの `config` 内のフィールド値と通知テキストはテンプレートです。`{record.}` は起動したレコードを、`{}` はフロー変数を、`{$User.Id}` は現在のユーザーを読み、`{NOW()}` / `{TODAY()}` は日付マクロです。条件は波括弧なしの素の CEL です。[条件と分岐](#conditions-and-branches)を参照してください。 + +開始ノードの `triggerType` がイベントを選び、省略可能な `condition` がそれを絞り込みます。たとえば `condition: "record.priority == 'high'"` です。 + +| `triggerType` | 発動するタイミング | +|---|---| +| `record-after-create` | 挿入の後 | +| `record-after-update` | 更新の後 | +| `record-after-delete` | 削除の後 | +| `record-after-write` | 挿入**または**更新の後 | +| `record-before-create` | 挿入の前 | +| `record-before-update` | 更新の前 | +| `record-before-delete` | 削除の前 | +| `record-before-write` | 挿入**または**更新の前 | + +更新では、`previous` が変更前のレコードを保持します:`condition: 'record.stage != previous.stage'`。同じ書き込みの中で、保存される前に保留中のレコードを変更するには、フローではなく before フックを使います。フローは保存の副作用のためのものです。レコードの作成、通知、HTTP 呼び出し、承認の依頼などです(ObjectStack の [Hooks vs flows](https://objectstack.ai/docs/automation/hooks#hooks-vs-flows))。 + +## スケジュール:時刻に従って実行する [#scheduled-run-on-a-clock] + +```ts +export const nightlyCleanup = defineFlow({ + name: 'nightly_cleanup', + label: 'Mark overdue tasks', + type: 'schedule', + status: 'active', + runAs: 'system', // a scheduled run has no user, so its data operations need an explicit identity + nodes: [ + { + id: 'start', + type: 'start', + label: 'Every night at 2am', + config: { + triggerType: 'schedule', + schedule: { type: 'cron', expression: '0 2 * * *', timezone: 'America/New_York' }, + }, + }, + { + id: 'mark_overdue', + type: 'update_record', + label: 'Mark open tasks past due', + config: { + objectName: 'task', + filter: { status: 'open', due_date: { $lt: '{TODAY()}' } }, + fields: { status: 'overdue' }, + multi: true, // update every match; without it, a filter that is not a single id is refused + }, + }, + { id: 'end', type: 'end', label: 'End' }, + ], + edges: [ + { id: 'e1', source: 'start', target: 'mark_overdue' }, + { id: 'e2', source: 'mark_overdue', target: 'end' }, + ], +}); +``` + +`@objectstack/service-job` 機能に支えられています。[ランタイム機能](/docs/reference/runtime-capabilities)を参照してください。時間で起動するフローには組織を引き継ぐ呼び出し元がいません。開始ノードで `organization` を使って組織を宣言しなければならない場合については、ObjectStack の [Flow metadata](https://objectstack.ai/docs/automation/flows#the-acting-organization) に記載されています。 + +> **スケジュールされた処理は、デプロイメントが有効にするまでオフです。** ObjectStack 17.5 以降、時間で起動するフロー(`schedule` の周期、または下記の相対時間スイープ)とパッケージ化された `defineJob` の cron ジョブは、デプロイメントが `OS_AUTOMATION_SCHEDULED_WORK_ENABLED` を `true`(または `1`、`on`、`yes`)に設定したときにだけ有効になります。未設定なら何も有効にならず、そのようなフローはそれぞれエラーではなく *disabled by deployment policy* として報告されます。オフは ObjectStack ランタイムのデフォルトです。お使いの ObjectOS イメージやそのデプロイバンドルのテンプレートがこの変数を設定してくれるかどうかは、このページでは約束できません。アプリがスケジュールフローに依存するときは明示的に設定し、実効値を表示する `os doctor` で確認してください。[環境変数](/docs/reference/environment-variables#runtime-services)を参照してください。プラットフォーム自身のスケジュール処理(承認のエスカレーション、保持期間、メッセージの配信)には影響しません。`isolated` テナンシー方式では、開始ノードで `organization` を宣言していないスケジュールフローは、スイッチがオンでも有効になりません。 + +## 相対時間:日付フィールドを基準に発動する(16.0) [#time-relative-fire-relative-to-a-date-field-160] + +「契約終了の 60 日前に通知する」は、かつては `record.end_date == daysFromNow(60)` を条件とするレコード変更フローとして作成されていました。この述語はレコードが*たまたま変更された*ときにしか評価されないので、放っておくとほとんど発動しません。そのようには書かないでください。代わりに**相対時間トリガー**を宣言します。フローの開始ノードが `config.timeRelative` 記述子を持ち、ランタイムがスケジュールに従ってオブジェクトをスイープし、**一致したレコードごとに 1 回**フローを起動します。 + +```ts +export const renewalReminder = defineFlow({ + name: 'contract_renewal_reminder', + label: 'Contract renewal reminder', + type: 'schedule', + status: 'active', + runAs: 'system', // a sweep has no user to act as + nodes: [ + { + id: 'start', + type: 'start', + label: 'Start', + config: { + timeRelative: { + object: 'contracts', + dateField: 'end_date', + offsetDays: [60, 30, 7], // T-minus thresholds + filter: { status: 'active' }, // AND-ed with the date window + }, + // Optional sweep cadence — defaults to daily at 08:00 UTC. + schedule: { type: 'cron', expression: '0 8 * * *' }, + }, + }, + { + id: 'notify_owner', + type: 'notify', + label: 'Notify Owner', + config: { recipients: '{record.owner}', title: 'Contract {record.name} ends on {record.end_date}' }, + }, + { id: 'end', type: 'end', label: 'End' }, + ], + edges: [ + { id: 'e1', source: 'start', target: 'notify_owner' }, + { id: 'e2', source: 'notify_owner', target: 'end' }, + ], +}); +``` + +| キー | 宣言するもの | +|---|---| +| `object` | スイープがレコードを問い合わせるオブジェクト(マシン名) | +| `dateField` | 今日を基準に評価される `date` / `datetime` フィールド(日単位) | +| `offsetDays` | **オフセットモード**:`dateField` がちょうど今日 + 列挙した各オフセットのときに発動します(`[60, 30, 7]`。負の値は過去で、たとえば `[-1]` は翌日) | +| `withinDays` | **範囲モード**:`dateField` が今日から N 日以内である日には毎日発動します。正の値は今後(「まもなく期限切れ」)、負の値は範囲を区切った期限超過の遡り、`0` は今日が期限 | +| `filter` | 計算された日付の範囲と AND 結合される、省略可能な ObjectQL の where マップ(例:`{ status: 'active' }`) | +| `maxRecords` | 1 回のスイープで起動するレコード数の上限(デフォルト 1000。上限で切り詰めるとスイープがログに記録します) | + +`offsetDays` と `withinDays` のどちらか**一方だけ**を設定しなければなりません。ほかによくある 2 つの形です。 + +```ts +// Two variants of the start node's config.timeRelative; the rest of the flow is as above. + +// "Expiring soon" — fires every day a document is within 30 days of expiry. +timeRelative: { object: 'hr_document', dateField: 'expires_on', withinDays: 30 } + +// Overdue sweep — fires for POs up to 14 days past due (bounded lookback). +timeRelative: { object: 'purchase_order', dateField: 'due_date', + withinDays: -14, filter: { status: 'open' } } +``` + +各起動は一致したレコードを自動化コンテキストに置くので、開始ノードの `condition` と `{record.}` の埋め込みは、レコード変更フローとまったく同じように動作します。検出のクエリはシステムとして実行され、レコードごとに障害が分離されます。`os validate` には準備状況のチェックが加わり、`timeRelative.object` がスタックで定義されていないオブジェクトを指しているとき、および自動起動のフローが `draft` ステータスのまま残っているときに警告します。 + +> **同じ日のチェックは、今は問題なく使えます(#3183)。** 16.0 では `record.due_date == today()` が一致します。エンジンが時間型の `==` / `!=` 比較を変換するので、日付フィールドが `today()` と正しく比較されます。本当に「今日が期限」という条件にはこれを使い、「日付の N 日前/後」という形のものには `timeRelative` を使ってください。 + +## 手動で開始:アクションと API 呼び出し [#started-by-hand-actions-and-api-calls] + +```ts +export const approveInvoice = defineFlow({ + name: 'approve_invoice', + label: 'Approve invoice', + type: 'autolaunched', + status: 'active', + variables: [ + { name: 'invoice_id', type: 'text', isInput: true }, + ], + nodes: [ + { id: 'start', type: 'start', label: 'Start' }, + { + id: 'approve', + type: 'update_record', + label: 'Approve the invoice', + config: { + objectName: 'invoice', + filter: { id: '{invoice_id}' }, + fields: { status: 'approved', approved_by: '{$User.Id}' }, + }, + }, + { id: 'end', type: 'end', label: 'End' }, + ], + edges: [ + { id: 'e1', source: 'start', target: 'approve' }, + { id: 'e2', source: 'approve', target: 'end' }, + ], +}); +``` + +請求書のビューで、種類が `flow` の[アクション](/docs/build/interface/actions)を使ってボタンとして表示するか、REST で呼び出します。 + +```bash +curl -X POST https://app.example.com/api/v1/automation/approve_invoice/trigger \ + -H 'Authorization: Bearer ' \ + -H 'Content-Type: application/json' \ + -d '{"params": {"invoice_id": "inv_123"}}' +``` + +入力は `isInput: true` で宣言したフロー変数で、同じ名前で `params` に入れて送ります。宣言された入力だけがバインドされます。呼び出し元のアイデンティティが実行に引き渡されるので、更新は呼び出し元の権限のもとで実行されます。 + +このルートは何が起きたかを示す HTTP ステータスで応答するので、本文の `success` フラグではなくステータスで分岐してください。ディスパッチされた実行(完了、一時停止、または[拒否](#ending-a-run-completed-or-refused))には `200`、不明なフローには `404`、オフに切り替えられたフローには `409 FLOW_DISABLED`、開始ノードのない定義には `422 FLOW_NO_START_NODE`、ディスパッチされて失敗した実行には `400 FLOW_FAILED` です。種類が `flow` のアクションも同じように応答します。[REST API → Flow status table](/docs/reference/rest-api#flow-status-table) を参照してください。 + +## ノードの種類 [#node-types] + +| ノードの `type` | 目的 | +|---|---| +| `get_record` | ObjectQL でレコードを読みます。1 件、または `limit` が 1 より大きいときはリスト | +| `create_record` / `update_record` / `delete_record` | オブジェクトに書き込みます(`multi: true` で一致したすべてを更新または削除) | +| `notify` | 通知を送ります。デフォルトはアプリ内の受信トレイ、`channels: ['email']` でメール | +| `http` | HTTP エンドポイントを呼び出します | +| `connector_action` | インストール済みのコネクタ(Slack など)でアクションを実行します | +| `script` | `config.function` で名前を指定した登録済みの関数を呼び出します | +| `decision` | エッジの条件で分岐します | +| `assignment` | フロー変数を設定します | +| `loop` | コレクションの各項目について本体の領域を 1 回ずつ実行します | +| `parallel` | 分岐の領域を並行して実行します | +| `try_catch` | 領域内の失敗を捕捉し、必要に応じて再試行します | +| `wait` | タイマーまたは名前付きシグナルまで一時停止します | +| `screen` | ユーザーの入力を待って一時停止します | +| `subflow` | 別のフローを呼び出します | +| `approval` | 承認者が判断するまでブロックします(`@objectstack/plugin-approvals` が必要) | +| `end` | 実行を終了します。デフォルトは `completed`、または理由付きの `refused`(下記) | + +### 実行の終了:完了または拒否 [#ending-a-run-completed-or-refused] + +ObjectStack 17.4 以降、`end` ノードは実行の**結果**を宣言します。断らなければならないフロー(重複、上限を超える金額など)は、失敗したり、断ったことを伝えるだけの画面を表示したりする代わりに、拒否の `end` で終わります。 + +```ts +// One flow node; the flow around it is omitted. +{ + id: 'refuse_duplicate', + type: 'end', + label: 'Refused: duplicate', + config: { + outcome: 'refused', // 'completed' (the default) | 'refused' + message: 'Refused: {record.name} is already registered.', + }, +} +``` + +拒否された実行は失敗した実行ではありません。何も例外を投げていないからです。実行は `refused` ステータスで終わり、トリガーのルートはそのステータスとともに `200` で応答し、レンダリングされた `message` は `refusalMessage` として返され、その横に `successMessage` はありません。`outcome` が `refused` のときは `message` が必須で、完了の end では拒否されます。そこでは誰の目にも触れないからです。拒否の `end` には `decision` の分岐から到達させ、すべての書き込みは拒否が通らない分岐に置いてください。 + +## 条件と分岐 [#conditions-and-branches] + +```ts +export const expenseRouting = defineFlow({ + name: 'expense_routing', + label: 'Route new expenses', + type: 'record_change', + status: 'active', + nodes: [ + { + id: 'start', + type: 'start', + label: 'Expense submitted', + config: { objectName: 'expense', triggerType: 'record-after-create' }, + }, + { id: 'check_amount', type: 'decision', label: 'Over 10,000?' }, + { + id: 'ask_approver', + type: 'notify', + label: 'Ask the approver', + config: { recipients: '{record.approver}', title: 'Expense over 10,000: {record.name}' }, + }, + { + id: 'auto_approve', + type: 'update_record', + label: 'Auto-approve', + config: { objectName: 'expense', filter: { id: '{record.id}' }, fields: { status: 'auto_approved' } }, + }, + { id: 'end', type: 'end', label: 'End' }, + ], + edges: [ + { id: 'e1', source: 'start', target: 'check_amount' }, + { id: 'e_large', source: 'check_amount', target: 'ask_approver', condition: 'record.amount > 10000' }, + { id: 'e_other', source: 'check_amount', target: 'auto_approve', isDefault: true }, + { id: 'e2', source: 'ask_approver', target: 'end' }, + { id: 'e3', source: 'auto_approve', target: 'end' }, + ], +}); +``` + +`decision` ノードは出力エッジで分岐します。エッジは `edges` に並んだ順に評価され、`condition` が成り立つ最初のものが実行され、どれも成り立たないときは `isDefault` のエッジが実行されます。`isDefault` がない場合、条件のないエッジは、一致した分岐と並んで毎回実行されます。条件が成り立つ*すべての*分岐を実行するには、decision に `config: { mode: 'inclusive' }` を宣言します。最初の一致を採用するのは ObjectStack 17.5 からのルールです。それ以前は真になったすべての分岐が実行されていました。データベースに保存された decision(Studio から保存されたもの)は、書き換えられることなく、アップグレード時に新しい意味になりました。 + +## エラー処理 [#error-handling] + +```ts +// Keys of a record_change flow on `invoice`. The nodes are omitted: `charge_card` is an +// `http` node, `mark_paid` an `update_record`, and `flag_for_review` a `notify`. +edges: [ + { id: 'e_ok', source: 'charge_card', target: 'mark_paid' }, + { id: 'e_fault', source: 'charge_card', target: 'flag_for_review', type: 'fault' }, +], +errorHandling: { strategy: 'retry', maxRetries: 3, backoffMs: 1000, backoffMultiplier: 2 }, +``` + +どちらの仕組みもなければ、ノードの失敗で実行は終了します。これらは 2 つの範囲で働きます。 + +| | 範囲 | 失敗時 | +|---|---|---| +| `fault` エッジ | 1 つのノード | 実行はハンドラーから続行し、完了します | +| `errorHandling: { strategy: 'retry', maxRetries }` | フロー全体 | フローは最初から再実行されます。最大で `maxRetries` 回まで | + +`strategy` は `'fail'`(デフォルト)、`'retry'`、`'continue'` のいずれかです。再試行は、すでに成功したすべてのノードを再生します。2 通目のメール、2 件目の作成レコードが生まれるので、失敗が局所的な場合は fault エッジを優先してください。fault エッジが処理した失敗はフローの失敗ではなく、再試行を消費せず、失敗したステップは実行のトレースに残ります。 + +## 数式と式(CEL) [#formulas-and-expressions-cel] + +条件(開始ノードの `condition`、エッジの `condition`)は **CEL**(Common Expression Language)で書きます。安全な式評価のための Google の言語です。 + +```ts +'record.amount > 10000 && record.tier == "enterprise"' +'record.stage != previous.stage' +'!isBlank(record.notes)' +``` + +`record` と `previous` は宣言されたすべてのフィールドを持ち、値のないフィールドは `null` として読まれます。そのため `has(record.notes)` が示すのはフィールドが宣言されていることで、値があることではありません。値の有無は `record.notes != null` または `isBlank(record.notes)` で確かめてください。 + +CEL はサンドボックス化されており(副作用なし、I/O なし)、サーバー側で評価され、フロービルダーで監査できます。 + +## ビジュアルビルダー [#visual-builder] + +ObjectOS には、宣言的なメタデータと相互に変換できるビジュアルフロービルダーが付属しています。エンジニアでなくてもフローを編集でき、編集結果は手で書く TypeScript と同じ形にシリアライズされます。これは Studio の **Automations** の柱です。 + +Studio から保存したフローは、インストール済みのパッケージが提供するフローと並んで、デプロイメントに保存されます。そこから 2 つのルールが導かれます。どちらも ObjectStack 17.6 からです。 + +- **パッケージ化されたフローがその名前を取ります。** パッケージ化されたフローと同じ名前を持つ保存済みのフローは隠され、実行されません。起動ログに警告が出ます。パッケージ化されたフローをカスタマイズするには、新しい名前で複製してください。 +- **保存済みのフローは `status` で切り替えます。** オン/オフのトグルが切り替えるのはパッケージ化されたフローだけです。デプロイメント内で作成したフローは、`status: 'obsolete'` で保存するとオフになり、`status: 'active'` で保存するとオンに戻ります。 + +## フローのテスト [#testing-flows] + +```bash +os test qa/ticket-email.test.json # run a Quality Protocol test suite against a running server +``` + +`os test` は、JSON のテストスイートとして書かれた Quality Protocol のシナリオを、実行中のサーバーに対して実行します。`--tags` はタグでシナリオを選びます。[CLI リファレンス](/docs/reference/cli)を参照してください。 + +## 制限とベストプラクティス [#limits--best-practices] + +- **before フックは小さく保ちます。** 書き込みトランザクションをブロックするからです。 +- **長時間実行のステップの代わりに `wait` ノードを使います。** 実行を永続的に待機させ、タイマーまたは名前付きシグナルで再開します。 +- **独立した作業には `parallel` ブロックを使います。** 分岐を並行して実行し、フローが続行する前に合流させます。 +- **冪等性が重要です。** フローレベルの再試行は、すでに成功したノードを再実行します。外部への副作用は重複を排除すべきです(フローの実行 ID をキーとして使います)。 +- **監査上重要なアクション。** 権限を変更したりレコードを削除したりするフローは、それ自体が `sys_audit_log` にログを書くべきです。 + +## 次に進む [#where-to-go-next] + +- [Webhook](/docs/configure/webhooks):外向きの通知。フローから起動されることが多いもの +- [メール](/docs/configure/email):`notify` ノードの `email` チャネルの背後にあるトランスポート +- [通知](/docs/configure/notifications):受信者、チャネル、テンプレートがどう解決されるか +- [API アクセス](/docs/configure/api-access):外部システムからフローを呼び出す +- [@objectstack/service-automation](https://github.com/objectstack-ai/objectstack/tree/main/packages/services/service-automation):実行エンジンのソース diff --git a/content/docs/build/automation/index.ja.mdx b/content/docs/build/automation/index.ja.mdx new file mode 100644 index 00000000..e9db7348 --- /dev/null +++ b/content/docs/build/automation/index.ja.mdx @@ -0,0 +1,43 @@ +--- +title: 自動化 +seoTitle: "自動化:フロー、ワークフロー、承認" +description: 用途に合ったツールを選びます。手順にはフロー、状態にはワークフロー、人による承認には承認を使います。 +editions: [community, cloud, enterprise] +translation: + source_sha: e39ead174c229520946d302d63cc2c7e6903c12d87048df02a15aed0b5ab0a84 + guide_rev: 1 + mode: auto +--- + +**自動化は、ビジネスロジックをアプリケーションコードに散らばらせるのではなく、ランタイムが実行するメタデータとして、データモデルに宣言的に結び付けます。** 3 つのツールがその範囲をカバーしており、最初に正しいものを選べば、後で作り直す手間が省けます。 + +## どれが必要か [#which-one-do-i-need] + +| 必要なもの | 使うもの | 読むもの | +|---|---|---| +| 「X が起きたら Y をする」:レコードの変更、スケジュール、ボタンのクリックで実行される手順 | **フロー** | [フロー](/docs/build/automation/flows) | +| 「このレコードはこれらの状態だけを通って進める」:管理されたライフサイクル | **ワークフロー**(ステートマシン) | [ワークフロー](/docs/build/automation/workflows) | +| 「先に進む前に人が承認しなければならない」:ルーティングされる人の判断 | **承認** | [承認](/docs/build/automation/approvals) | + +目安:**状態**はワークフローで、**手順**はフローでモデル化します。承認は別のエンジンではありません。承認とは、人が判断するまで承認ノードで一時停止するフローです。 + +## どう組み合わせるか [#how-they-combine] + +3 つは競合せず、組み合わせて使います。 + +- **ワークフロー**は、そもそもどのライフサイクル遷移が有効かを制約します。状態とその間の移動だけで、それ以外は扱いません。 +- **フロー**は、それらの遷移の前後で副作用を実行します。メールを送る、レコードを更新する、外部サービスを呼び出す、待機する、分岐する、などです。 +- フロー内の**承認ノード**は、承認者が操作するまで実行を止め、その後、承認または却下の分岐に沿って再開します。 + +つまり「ケースが new → assigned → resolved と進む」はワークフローであり、「エスカレーションされたらマネージャーに通知する」はフローであり、「5 万ドルを超える値引きには財務マネージャーの承認が必要」は承認ノードを持つフローです。 + +> **ヒント:** 要求が「X が起きたら Y をする」と読めるならフローです。「このレコードは決して状態を飛ばしてはならない」と読めるならワークフローです。ここから始めれば、選択を誤ることはほとんどありません。 + +## 次に進む [#where-to-go-next] + +| ページ | 理由 | +|---|---| +| [フロー](/docs/build/automation/flows) | フローの完全なリファレンス:トリガー、ステップの種類、エラー処理、CEL | +| [ワークフロー](/docs/build/automation/workflows) | 厳密なライフサイクルのための、状態とその許可された遷移 | +| [承認](/docs/build/automation/approvals) | 承認ノード、実行アイデンティティ、承認者の体験 | +| [CEL 式](/docs/reference/cel) | 条件と検証ルールで使われる式言語 | diff --git a/content/docs/build/automation/workflows.ja.mdx b/content/docs/build/automation/workflows.ja.mdx new file mode 100644 index 00000000..00fbe406 --- /dev/null +++ b/content/docs/build/automation/workflows.ja.mdx @@ -0,0 +1,181 @@ +--- +title: ワークフロー +seoTitle: "ワークフロー:ステートマシンとしてのレコードのライフサイクル" +description: レコードのライフサイクルをステートマシンとしてモデル化します。レコードが取りうる状態、その間で許される移動、そしてフローの方がうまくできることは何も含めません。 +editions: [community, cloud, enterprise] +translation: + source_sha: 7ec55c7f19bcf4f40b34dc0d852ea4cf3534169ad263dbdff0f1ed34fbb0c600 + guide_rev: 1 + mode: auto +--- + +**ワークフローは、レコードのライフサイクルを有限ステートマシンとしてモデル化します。レコードが取りうる状態と、その間で許される移動です。** オブジェクト上の `state_machine` 検証ルールとして宣言し、状態フィールドへのすべての書き込みがそれに照らしてチェックされます。中心となる要件が「このオブジェクトはこれらの状態だけを通って進める」であるときに使います。 + +Salesforce 風の独立した Workflow Rule という作成タイプはありません。かつての「ワークフロー」の概念は、きれいに 2 つに分かれます。 + +- **`state_machine` 検証ルール**:厳密なライフサイクル遷移のため。このページです。 +- **[フロー](/docs/build/automation/flows)**:イベントで起動する、またはスケジュールされた自動化のため。[承認](/docs/build/automation/approvals)による一時停止も含みます。 + +## ワークフローとフロー [#workflows-vs-flows] + +| | ワークフロー(ステートマシン) | フロー | +|---|---|---| +| モデル化するもの | *状態*:レコードがライフサイクルのどこにあるか | *手順*:何かが起きたときに何が起こるか | +| 答える問い | 「この遷移は今許されるか?」 | 「それについて何をするか?」 | +| 形 | 状態フィールドと、許される移動の表 | ノードとエッジ:トリガー、アクション、分岐 | +| 副作用 | なし。制約するだけです | すべて:メール、更新、HTTP、待機 | + +両者は組み合わせて使います。ステートマシンが遷移を制約し、通知、レコード更新、外部呼び出しが必要なときには、フローがその前後で副作用を実行します。 + +## ステートマシンを定義する [#define-a-state-machine] + +`new → assigned → resolved` と進まなければならず、エスカレーションの経路を持つサポートケースです。ステートマシンはオブジェクトの `validations` のひとつです。 + +```ts +import { P } from '@objectstack/spec'; +import { ObjectSchema, Field } from '@objectstack/spec/data'; + +export const SupportCase = ObjectSchema.create({ + name: 'support_case', + label: 'Support Case', + fields: { + status: Field.select({ + label: 'Status', + required: true, + options: [ + { label: 'New', value: 'new', default: true }, + { label: 'Assigned', value: 'assigned' }, + { label: 'Escalated', value: 'escalated' }, + { label: 'Resolved', value: 'resolved' }, + ], + }), + resolution: Field.textarea({ + label: 'Resolution', + requiredWhen: P`record.status == 'resolved'`, // no resolved case without one + }), + }, + validations: [ + { + type: 'state_machine', + name: 'case_lifecycle', + field: 'status', + message: 'This status change is not allowed.', + initialStates: ['new'], + transitions: { + new: ['assigned'], + assigned: ['resolved', 'escalated'], + escalated: ['resolved'], + resolved: [], + }, + }, + ], +}); +``` + +これを契約として読みます。ケースは `new` として作成され、`new` のケースは担当割り当てしかできません。`assigned` のケースは解決またはエスカレーションでき、エスカレーションされたケースは解決できます。`resolved` には何も列挙されていないので、それ以上は何も移動させられません。ステータスが `resolved` のときは `resolution` が必須なので、それなしでケースを解決する書き込みは拒否されます。 + +## 構成 [#anatomy] + +| キー | 宣言するもの | +|---|---| +| `type: 'state_machine'` | この検証ルールがステートマシンであること | +| `name` | ルールの識別子(snake_case) | +| `field` | ルールが管理する状態フィールド | +| `transitions` | 各状態 → 移動できる状態のマップ。レコードの更新時にチェックされます | +| `initialStates` | レコードを作成できる状態。挿入時にチェックされます | +| `message` | 拒否された書き込みが返すエラー | + +このルールは、すべての検証ルールに共通するキー `severity`、`events`、`active`、`priority` も受け付けます。 + +### 最終状態 [#final-states] + +リストが空の状態は最終状態で、そこから出るすべての移動が拒否されます。キーがまったくない状態は最終状態ではありません。そこではチェックに判断材料がなく、書き込みを通してしまうので、「最終」を意味するときは `[]` を宣言してください。 + +### 遷移の条件 [#conditions-on-a-transition] + +`state_machine` ルールには遷移ごとのガードがありません。移動を条件付きにするには、プラットフォームが強制する場所に条件を置きます。 + +- **ある状態に必要な値**:上の `resolution` のように、そのフィールドに `requiredWhen` を付けます。値なしでその状態に入る書き込みを拒否し、ルールより前から存在する行には手を付けません。 +- **それ以外すべて**:同じ `validations` 配列に、兄弟の `script` または `conditional` 検証ルール(CEL の述語)を置きます。 + +### イベントではなく書き込み [#writes-not-events] + +マシンは状態フィールドへの書き込み時にチェックされます。`status` を現在の値の下に列挙されていない値に変える更新は拒否され、`initialStates` 以外での挿入も同様です。宣言すべき名前付きイベントはありません。正当な移動の表がマシンのすべてです。 + +> **ヒント:** マシンは最小限に保ちます。状態とその間の移動だけです。「そしてメールを送る」と言いたくなった瞬間、ワークフローの領域を離れています。その副作用は、遷移に反応する[フロー](/docs/build/automation/flows)に置いてください。 + +## 副作用はフローに置く [#side-effects-belong-in-flows] + +ステートマシンは有効な遷移を記述するだけで、それ以外は何もしません。遷移で何かを*する*必要があるとき(営業に通知する、クローズ日を記録する、外部システムを呼び出す)は、マシンとレコード変更で起動するフローを組み合わせます。 + +```ts +export const dealClosedWon = defineFlow({ + name: 'deal_closed_won', + label: 'Deal closed won', + type: 'record_change', + status: 'active', + nodes: [ + { + id: 'start', + type: 'start', + label: 'Stage moved to closed won', + config: { + triggerType: 'record-after-update', + objectName: 'opportunity', + condition: "record.stage == 'closed_won' && previous.stage != 'closed_won'", + }, + }, + { + id: 'set_closed_date', + type: 'update_record', + label: 'Set Closed Date', + config: { + objectName: 'opportunity', + filter: { id: '{record.id}' }, + fields: { closed_date: '{TODAY()}' }, + }, + }, + { + id: 'notify_sales', + type: 'notify', + label: 'Notify Sales', + config: { recipients: '{record.owner}', title: 'Deal won: {record.name}' }, + }, + { id: 'end', type: 'end', label: 'End' }, + ], + edges: [ + { id: 'e1', source: 'start', target: 'set_closed_date' }, + { id: 'e2', source: 'set_closed_date', target: 'notify_sales' }, + { id: 'e3', source: 'notify_sales', target: 'end' }, + ], +}); +``` + +マシンは商談が正当に `closed_won` へ*到達した*ことを保証し、フローはその後に起こることを処理します。上のような条件は CEL 式です。[CEL](/docs/reference/cel) を参照してください。 + +## ワークフロールールからの移行 [#migrating-from-workflow-rules] + +Workflow Rules を持つプラットフォームから来た場合の対応は次のとおりです。 + +| 旧来の概念 | 現在の対応するもの | +|---|---| +| Workflow Rule | フロー | +| 時間トリガー(「日付の N 日前/後」) | 相対時間トリガー:フローの開始ノードの `config.timeRelative`(16.0、[フロー](/docs/build/automation/flows)を参照) | +| 時間トリガー(固定時刻) | スケジュールフロー | +| 項目自動更新アクション | `update_record` ノード | +| メールアラート | `notify` ノード | +| HTTP 呼び出し | `http` ノード | +| 承認プロセス | 1 つ以上の `approval` ノードを持つフロー | + +判断の基準:旧ルールが「X が起きたら Y をする」なら、小さなフローとしてモデル化します。「日付フィールドの N 日前/後に Y をする」なら、相対時間トリガーを宣言します。レコード変更フローに日付が等しいという条件を付けてはいけません。それはレコードがたまたま変更されたときにしか評価されないからです。「このレコードは管理された状態を通って進まなければならない」なら、`state_machine` 検証ルールを宣言し、副作用にはフローを使います。 + +## 次に進む [#where-to-go-next] + +| ページ | 理由 | +|---|---| +| [フロー](/docs/build/automation/flows) | 遷移の前後の副作用:トリガー、ステップ、エラー処理 | +| [承認](/docs/build/automation/approvals) | フロー内の一時停止としての、人による承認 | +| [検証ルール](/docs/build/data/validation-rules) | ステートマシンが属するルールの系統 | +| [CEL 式](/docs/reference/cel) | `requiredWhen`、検証ルール、フロー条件の背後にある言語 | +| [データモデリング](/docs/build/data) | ライフサイクルを制約するオブジェクト | +| [自動化の概要](/docs/build/automation) | 選び方:フロー、ワークフロー、承認 | diff --git a/content/docs/build/interface/actions.ja.mdx b/content/docs/build/interface/actions.ja.mdx new file mode 100644 index 00000000..c89a8f0a --- /dev/null +++ b/content/docs/build/interface/actions.ja.mdx @@ -0,0 +1,208 @@ +--- +title: アクション +seoTitle: "アクション:REST エンドポイント、ボタン、AI ツール" +description: プラットフォームが 1 つの宣言から REST エンドポイント、ボタン、AI ツールとして公開する、名前付きの操作。 +editions: [community, cloud, enterprise] +translation: + source_sha: 85e291bd4a1a724fe1ba2fbbf181d61ab30004d9389a19eaee2e9ae3175b1096 + guide_rev: 1 + mode: auto +--- + +**アクション**は、オブジェクトに対する名前付きの操作です。一度宣言すると、次のものとして現れます。 + +- `/api/v1/actions//` の **REST エンドポイント** +- レコード詳細ページの**ボタン** +- エージェントと AI Builder 向けの **AI ツール**(`action_`)。AI に公開したとき(`ai.exposed`、[下記](#from-an-ai-agent))に限ります + +3 つの画面で同じことを繰り返す必要はありません。1 つの宣言で、3 通りの呼び出し方ができます。作業が 1 ステップで終わらないときは、アクションから[フロー](/docs/build/automation/flows)を開始することもできます(`type: 'flow'`)。 + +## アクションを宣言する [#declare-an-action] + +```ts +// src/actions/approve_invoice.action.ts +import { Action } from '@objectstack/spec/ui'; + +export const approveInvoice = Action.create({ + name: 'approve_invoice', // lowercase snake_case (machine id) + label: 'Approve Invoice', + objectName: 'invoice', // attaches to the invoice object + icon: 'check', + variant: 'primary', + locations: ['record_header'], // where the button shows + description: 'Approve this invoice?', // shown in the param dialog + successMessage: 'Invoice approved', + refreshAfter: true, + + // collect input before running + params: [ + { name: 'note', label: 'Approval note', type: 'textarea' }, + ], + + // only show the button when the record is still pending + visible: 'record.status == "pending"', + + // expose it to agents and the AI Builder as `action_approve_invoice` + ai: { + exposed: true, + description: 'Approve a pending invoice, recording the approver and an optional note.', + }, + + // what it does — a sandboxed script body. `input` is the params bag; + // `ctx.record` is a read-only snapshot, so the write goes through `ctx.api`, + // which needs the `api.write` capability + type: 'script', + body: { + language: 'js', + capabilities: ['api.write'], + source: ` + await ctx.api.object('invoice').update({ + id: ctx.recordId, + status: 'approved', + approved_by: ctx.user.id, + approved_at: new Date().toISOString(), + approval_note: input.note, + }); + `, + }, +}); +``` + +`os dev` が再コンパイルした後: + +- `POST /api/v1/actions/invoice/approve_invoice` が動作します +- 請求書のレコードページに **Approve Invoice** ボタンが表示されます +- AI アシスタントは、スキルが許可していれば `action_approve_invoice` を呼び出せます。AI に公開されているからです + +## アクションの種類 [#action-types] + +`type` フィールドが、アクションが何をするかを決めます。 + +| `type` | 実行されるもの | 用途 | +|---|---|---| +| `script` | `body`:L1 の数式、またはサンドボックス化された L2 の JavaScript | ほとんどの場合。サーバー側のロジックで、監査でき、公開すれば AI から呼び出せます | +| `api` | `target` エンドポイントへの HTTP 呼び出し(`method`、`bodyExtra`) | データ API やプラットフォームのエンドポイントの再利用 | +| `flow` | `target` で名前を指定したフローを実行します | 多段階のビジネスプロセス | +| `url` | `target` の URL に移動します | ディープリンク、リダイレクト型のアクション | +| `modal` | `target` で名前を指定したページ / モーダルを開きます | カスタムのダイアログ | +| `form` | `target` で名前を指定した FormView を開きます | ガイド付きのデータ入力 | + +```ts +// api type — reuse a data-API endpoint +Action.create({ + name: 'archive_order', + objectName: 'order', + label: 'Archive', + locations: ['list_item'], + type: 'api', + method: 'PATCH', + target: '/api/v1/data/order/{id}', + bodyExtra: { archived: true }, +}); +``` + +`script` 以外の種類には `target` が必要です。どの種類でも 1 つの宣言ですが、`url`、`modal`、`form` のアクションは UI でしか実行されないので、AI ツールになることはありません。 + +## アクションを呼び出す [#calling-an-action] + +### REST [#rest] + +```bash +# the record id can go in the body, or in the path +curl -X POST https://app.example.com/api/v1/actions/invoice/approve_invoice/inv_123 \ + -H 'Authorization: Bearer ' \ + -H 'Content-Type: application/json' \ + -d '{"note": "LGTM"}' +``` + +パラメータはリクエスト本文にフラットに入れて送ります。レコード ID は、末尾のパスセグメント(`.../approve_invoice/:recordId`)としても本文の中でも指定できます。レスポンスは、スクリプト本体の戻り値です(`api` の種類のアクションでは呼び出しの結果)。 + +### UI から [#from-the-ui] + +ボタンをどこに表示するかはアクション自身で宣言します。`locations`(`record_header`、`record_more`、`list_item`、`list_toolbar` など)と `order` です。その後、`visible` の述語がレコードごとにレンダリングするかどうかを決めます。リストビューでも、各行と行の選択に対するアクションを名前で指定できます。 + +```ts +// One list view; the container and `data` are omitted (see Views). +{ + type: 'grid', + columns: ['number', 'customer', 'amount', 'status'], + rowActions: ['approve_invoice', 'reject_invoice'], + bulkActions: ['send_to_customer'], +} +``` + +### フローとともに [#with-a-flow] + +アクションを呼び出すフローのノードはありません。逆向きにしてください。多段階のロジックをフローに置き、`type: 'flow'` と、`target` にフローの名前を指定したアクションからそれを開始します。 + +```ts +// flow type — start a flow by name +Action.create({ + name: 'run_invoice_approval', + objectName: 'invoice', + label: 'Run approval', + locations: ['record_more'], + type: 'flow', + target: 'approve_invoice', +}); +``` + +### AI エージェントから [#from-an-ai-agent] + +アクションがエージェントに届くのは、作成者が AI に公開したときだけです。上の例のように、UI なしで実行される種類(`script`、`flow`、`api`)で、`ai: { exposed: true }` と 40 文字以上の `ai.description` を指定します。公開されたアクションは、ObjectOS 自身のエージェントと AI Builder では `action_` ツールになり、[MCP クライアント](/docs/configure/mcp)では `run_action` になります。公開されていなければ、エージェントからは見えず、呼び出されても拒否されます。 + +`approve_invoice` が公開されていて、エージェントが持つスキルに含まれていれば、LLM はそれを呼び出せます。入力は会話から得られ、ユーザーがボタンを押した場合と同じ呼び出し時のチェックが適用されます。 + +> *「請求書 INV-2042 を、メモ『電話で確認済み』を付けて承認して。」* + +## 権限 [#permissions] + +誰がアクションを実行できるかは、呼び出されたときに、呼び出し元としてチェックされます。REST からでも、ボタンからでも、エージェントからでも同じです。 + +1. **`requiredPermissions`**:呼び出し元の[権限セット](/docs/configure/permissions/permission-sets)が持っていなければならない機能です。1 つでも欠けている呼び出し元は `403` を受け取ります。 +2. **対象のレコード**:呼び出し元として読み込まれます。呼び出し元が読めないレコードは、見つからないものとして応答されます。 +3. **AI への公開**:エージェントが届くのは、AI に公開されたアクションだけです。 +4. **UI のゲート**:`visible` と `disabled` の述語(CEL。`record`、`os.user`、パラメータに対して評価されます)が、ボタンをレンダリングするか、グレーアウトするかを制御します。 + +その後アクションが行うことは、信頼されたアプリのコードです。`script` 本体の読み書きはアプリの権限で実行され、レコードアクセスとフィールドレベルのセキュリティはそれを制限**しません**。`flow` アクションはフローの `runAs` に従います。そのため、機密性のあるものには `requiredPermissions` を宣言し、アクションを書くことはコードレビューに値する行為として扱ってください。 + +## 組み込みのアクション [#built-in-actions] + +すべてのオブジェクトには、これらが無償で用意されます。 + +| アクション | 働き | +|---|---| +| `create` | レコードを挿入します | +| `update` | レコードを更新します | +| `delete` | レコードを削除(またはソフト削除)します | +| `restore` | ソフト削除を取り消します | +| `clone` | レコードをディープコピーします | +| `share` | ユーザー、チーム、ポジション、事業単位、または単位とその配下に直接共有します | + +これらを再宣言しないでください。オブジェクトの[ライフサイクルと機能のフラグ](/docs/build/data)に従います。 + +## 監査 [#auditing] + +プラットフォームのイベントは、変更不可能な証跡である `sys_audit_log` に記録されます。次のようなフィールドがあります。 + +- `user_id`:操作を起こしたユーザー +- `action`:アクションの名前 +- `object_name` と `record_id`:何に触れたか +- `old_value` / `new_value`:変更内容 +- `ip_address` / `user_agent`:リクエストの発信元 +- `created_at`:いつ起きたか + +*「誰がボタンを押したのか?」* という質問には、まずここを見てください。 + +## AI Builder でアクションを生成する [#generating-actions-with-the-ai-builder] + +> *「`support_ticket` に `escalate_ticket` というアクションを作って。優先度を urgent に設定し、オンコールのエンジニアに割り当てるもの。」* + +[AI Builder](/docs/build/ai-builder) はアクションのメタデータを生成し、変更を承認待ちのキューに入れます。承認後、アクションは REST、UI、そして再帰的に AI 自身から呼び出せるようになります。 + +## 次に進む [#where-to-go-next] + +- [フロー](/docs/build/automation/flows):`type: 'flow'` のアクションが開始する多段階のロジック +- [エージェント](/docs/build/agents):アクションを AI ツールとして公開する +- [API アクセス](/docs/configure/api-access):外部システムからアクションを呼び出す +- [権限](/docs/configure/permissions):誰が何を呼び出せるかをゲートする diff --git a/content/docs/build/interface/apps.ja.mdx b/content/docs/build/interface/apps.ja.mdx new file mode 100644 index 00000000..d11da2d9 --- /dev/null +++ b/content/docs/build/interface/apps.ja.mdx @@ -0,0 +1,137 @@ +--- +title: アプリ +seoTitle: "アプリ:ナビゲーション、ブランディング、対象者のゲート" +description: オブジェクト、ビュー、ページ、ダッシュボードを、ブランド付きでナビゲーションできる外枠にまとめ、誰が何を見るかを正確にゲートします。 +editions: [community, cloud, enterprise] +translation: + source_sha: 92a61a2c5ecd3b085a106339e991600fa0fc1dc9db0194a67c257c4946b4f080 + guide_rev: 1 + mode: auto +--- + +**アプリ**は、オブジェクト、ビュー、ページ、ダッシュボードをひとつのまとまった体験にまとめる論理的なコンテナです。ナビゲーションツリー、ブランディング、そして決定的に重要な、誰が入れるかを定義します。 + +```ts +import { App } from '@objectstack/spec/ui' + +export const CrmApp = App.create({ + name: 'crm_app', + label: 'CRM', + icon: 'briefcase', + branding: { primaryColor: '#2563EB' }, + navigation: [ + { id: 'group_sales', type: 'group', label: 'Sales', icon: 'briefcase', children: [ + { id: 'nav_leads', type: 'object', objectName: 'crm_lead', label: 'Leads', icon: 'funnel' }, + { id: 'nav_accounts', type: 'object', objectName: 'crm_account', label: 'Accounts', icon: 'building' }, + ]}, + ], + requiredPermissions: ['crm_access'], +}) +``` + +## アプリのプロパティ [#app-properties] + +| プロパティ | 型 | 必須 | 説明 | +|:--|:--|:--|:--| +| `name` | `string` | はい | マシン名(`snake_case`) | +| `label` | `string` | はい | 表示名 | +| `icon` | `string` | — | アプリのアイコン(Lucide) | +| `description` / `version` | `string` | — | 一覧表示用のメタデータ | +| `active` | `boolean` | — | アプリが有効かどうか(デフォルト `true`) | +| `isDefault` | `boolean` | — | これがデフォルトのアプリかどうか | +| `navigation` | `NavigationItem[]` | — | ナビゲーションツリー | +| `branding` | `AppBranding` | — | `primaryColor`、`logo`、`favicon` | +| `requiredPermissions` | `string[]` | — | そもそも誰がアプリを開けるか | +| `homePageId` | `string` | — | ランディングページとして使うナビゲーション項目の `id` | + +## ナビゲーション項目 [#navigation-items] + +ナビゲーションツリーは 8 種類の項目をサポートします。よく使う 5 つは `object`、`dashboard`、`page`、`url`、`group` で、仕様ではほかに `report`、`action`、`component` の項目も定義されています。 + +| `type` | 着地先 | 主な設定 | +|:--|:--|:--| +| `object` | オブジェクトのリストビュー | `objectName`、および省略可能なターゲット指定(下記) | +| `dashboard` | ダッシュボード | `dashboardName` | +| `page` | カスタムページ | `pageName`、省略可能な `params` | +| `url` | 外部の URL | `url`、`target: '_blank'` | +| `group` | 折りたたみ可能なセクション | `children`、`expanded` | + +すべての項目は一意な `id`(小文字の `snake_case`)を宣言**しなければなりません**。`homePageId` が参照するのはこれです。共通のプロパティ:`label`、`icon`、`order`、`badge`、そして下記の 3 つのゲートです。 + +### オブジェクトのエントリのターゲット指定 [#targeting-an-object-entry] + +3 つの省略可能なフィールドで `object` エントリの着地先を絞り込めます。優先順位は `recordId` → `filters` → `viewName` です。 + +- `viewName`:エントリを名前付きのリストビューに固定します。 +- `recordId`:単一のレコードへのディープリンク(「マイプロフィール」)。`{current_user_id}` / `{current_org_id}` のテンプレート変数をサポートします。 +- `filters`:一回限りのパラメータ付きの切り出しです。エントリは素のデータ画面に着地し、各条件は削除できる URL のフィルターチップになります。ビューを作成せずに「自分に割り当てられたもの」のリンクを作るのに最適です。セキュリティ機能ではありません。何を表示するかは、引き続き行レベルの権限が決めます。 + +```ts +// One navigation item of an app. +{ id: 'nav_my_open', type: 'object', label: 'My Open Deals', objectName: 'opportunity', + filters: { owner_id: '{current_user_id}', status: 'open' }, icon: 'user-check' } +``` + +### モバイルのナビゲーション [#mobile-navigation] + +モバイル専用のナビゲーションブロックはありません。`mobileNavigation` は、どのレンダラーも読み取っていなかったため、ObjectStack 17.0 で削除されました。 + +## 対象者によるアプリのゲート [#gating-apps-by-audience] + +同じデータが、まったく異なる 2 つの対象者に役立ちます。スキーマを設計する**ビルダー**と、データを入力して読むだけの**エンドユーザー**です。これらの画面はデフォルトで分けてください。各管理者が手で隠すことに頼ってはいけません。 + +| 対象者 | 画面 | ゲートするもの | +|:--|:--|:--| +| エンドユーザー(利用者) | 厳選されたアプリ → `page` / `view` のエントリ | `App.requiredPermissions`、ナビゲーション項目のゲート | +| ビルダー / 管理者 | Setup / Studio、素のオブジェクトテーブル | 機能:`setup.access`、`studio.access`、`manage_metadata` | + +組み込みの権限セットはすでにこの区分を表しています。`member_default` と `viewer_readonly` は `studio.access` / `manage_metadata` を持た**ない**ので、これらの権限セットのユーザーにはビルダー向けの画面が見えません。`admin_full_access` と `organization_admin` は持っています。 + +各ナビゲーション項目は、独立した 3 つのゲートをサポートします。 + +| ゲート | 型 | 次の場合を除き項目を隠す…… | +|:--|:--|:--| +| `requiredPermissions` | `string[]` | ユーザーが RBAC の機能(例:`manage_metadata`)を持っている | +| `visible` | CEL 式 | 述語が真と評価される(例:`'org_admin' in current_user.positions`) | +| `requiresObject` / `requiresService` | `string` | 指定したオブジェクト / カーネルサービスがインストールされている | + +```ts +// Keys of an app; its other keys are omitted. +navigation: [ + { id: 'nav_contacts', type: 'object', label: 'Contacts', objectName: 'showcase_contact' }, + // Builder-only entry — consumers never render it: + { id: 'nav_designer', type: 'component', label: 'Object Designer', + componentRef: 'metadata:resource', params: { type: 'object' }, + requiredPermissions: ['manage_metadata'] }, +] +``` + +> **無効化せず、隠します。** 無効化されていても見えているビルダー向けのエントリは、やはりノイズです。ゲートされたナビゲーション項目は、その機能を持たないユーザーには*レンダリングされません*。エンドユーザーを混乱させるグレーアウトした部品はありません。 + +利用者向けの画面をすっきり保つ習慣がさらに 2 つあります。 + +- **エンドユーザーには素のテーブルではなくページを渡します。** `page` エントリなら、公開するものを正確に厳選できます。選んだ列、固定された可視化、有効にしたフィルターとアクションだけです。`object` エントリは制限の緩いグリッドを与えます。切り替え可能なビュー、個人用ビュー、完全なツールバーです。 +- **データ画面そのものを厳選します。** 素のオブジェクトの読み取り権限を与えて 40 列のグリッドにユーザーを放り込むよりも、[厳選したビュー](/docs/build/interface/views)を優先してください。 + +アクションのゲートは両面です。UI がボタンを隠すか無効にし、**かつ**サーバーが呼び出しを拒否します。「UI ではゲートされているがサーバーでは開いている」という落とし穴はありません。[アクション](/docs/build/interface/actions)を参照してください。 + +## Setup アプリ:組み込みの例 [#the-setup-app--a-built-in-example] + +プラットフォーム自身の管理 UI である **Setup アプリ**も、同じアプリのメタデータプロトコルからレンダリングされています。ナビゲーション、ページ、ゲートはデータとして宣言され、あなたのアプリと同じレンダラーが描画します。そのゲートは、あなたのビルダー向け画面がそうあるべきとおりのものです。利用者向けの権限セットが持たない `setup.access` 機能の背後にあります。メタデータとしてのアプリがスケールする証拠が欲しいなら、すでにそれを使っています。 + +## アンチパターン [#anti-patterns] + +- **すべてのエンドユーザーをビルダー並みの共同作業者にして**、タブを 1 つずつ隠すこと。利用者とビルダーの区分をデフォルトにしてください。 +- **ビルダー向けのエントリを隠さずに無効化すること。** 見えているのに動かない部品は、やはり混乱を招きます。 +- 厳選したページでエンドユーザーに必要なものを正確に公開できるのに、**素のオブジェクトの読み取り権限を与えること**。 + +## 次に進む [#where-to-go-next] + +| ページ | 理由 | +|:--|:--| +| [ビュー](/docs/build/interface/views) | `object` のナビゲーションエントリの着地先 | +| [ページ](/docs/build/interface/pages) | エンドユーザー向けの厳選された `page` エントリ | +| [ダッシュボード](/docs/build/interface/dashboards) | `dashboard` エントリがレンダリングするもの | +| [アクション](/docs/build/interface/actions) | ボタンとその両面のゲート | +| [権限](/docs/configure/permissions) | `requiredPermissions` の背後にある権限セット | +| [インターフェースの概要](/docs/build/interface) | すべての部品がどう組み合わさるか | diff --git a/content/docs/build/interface/dashboards.ja.mdx b/content/docs/build/interface/dashboards.ja.mdx new file mode 100644 index 00000000..04155fc1 --- /dev/null +++ b/content/docs/build/interface/dashboards.ja.mdx @@ -0,0 +1,201 @@ +--- +title: ダッシュボード +seoTitle: "ダッシュボードの構築:データセット、ウィジェット、ドリルダウン" +description: 名前付きデータセットにバインドされたチャートウィジェットで構築する分析ページ。グローバルフィルター、自動更新、元のレコードへのドリルスルーを備えます。 +editions: [community, cloud, enterprise] +translation: + source_sha: c67b6877ef40bb832312c2b13597c8aa27a0351ad3ce7bd72469323bdef0ddc6 + guide_rev: 1 + mode: auto +--- + +**ダッシュボードはウィジェットのグリッドであり、すべてのウィジェットはデータセットにバインドします。** データセットはセマンティックレイヤーで、基になるオブジェクト、結合、ディメンション、メジャーを持ちます。ウィジェットはそれらを名前で選ぶので、「売上」は、それを使うすべてのダッシュボードとレポートで同じ意味になります。 + +```ts +// One dashboard, bound to the `sales` dataset defined below. +const salesDashboard = { + name: 'sales_overview', + label: 'Sales Overview', + description: 'Key sales metrics and pipeline analysis', + refreshIntervalSeconds: 300, // auto-refresh every 5 minutes + + dateRange: { + field: 'close_date', + defaultRange: 'this_quarter', + allowCustomRange: true, + }, + + widgets: [ + { id: 'total_revenue', title: 'Total Revenue', type: 'metric', + dataset: 'sales', values: ['revenue'], + layout: { x: 0, y: 0, w: 3, h: 2 } }, + { id: 'revenue_by_region', title: 'Revenue by Region', type: 'bar', + dataset: 'sales', dimensions: ['region'], values: ['revenue'], + layout: { x: 3, y: 0, w: 6, h: 4 } }, + { id: 'deals_by_month', title: 'Deals by Month', type: 'pie', + dataset: 'sales', dimensions: ['close_month'], values: ['deal_count'], + layout: { x: 9, y: 0, w: 3, h: 4 } }, + ], +} +``` + +## ダッシュボードのプロパティ [#dashboard-properties] + +| プロパティ | 型 | 必須 | 説明 | +|:--|:--|:--|:--| +| `name` | `string` | はい | マシン名(`snake_case`) | +| `label` | `string` | はい | 表示ラベル | +| `description` | `string` | — | ダッシュボードの説明 | +| `widgets` | `DashboardWidget[]` | はい | チャートと指標のウィジェット | +| `refreshIntervalSeconds` | `number` | — | 自動更新の間隔(秒) | +| `dateRange` | `object` | — | グローバルな日付範囲のフィルター | +| `globalFilters` | `GlobalFilter[]` | — | 対話的なフィルターコントロール | + +## まずデータセット [#datasets-first] + +データセットを一度定義し、すべてのウィジェットをそれにバインドします。 + +```ts +import { defineDataset } from '@objectstack/spec/ui' + +export const salesDataset = defineDataset({ + name: 'sales', + label: 'Sales', + object: 'opportunity', + include: ['account'], + dimensions: [ + { name: 'region', field: 'account.region', type: 'string' }, + { name: 'close_month', field: 'close_date', type: 'date', dateGranularity: 'month' }, + ], + measures: [ + { name: 'revenue', field: 'amount', aggregate: 'sum' }, + { name: 'deal_count', aggregate: 'count' }, + ], +}) +``` + +集計はウィジェットではなく、データセットのメジャー(`aggregate`)に置かれます:`count`、`sum`、`avg`、`min`、`max`、`count_distinct`、`array_agg`、`string_agg`。ウィジェットの `dimensions` と `values` は、バインドしたデータセットで宣言された名前を参照しなければなりません。 + +実行時、データセットのクエリは分析サービスを通じて実行され、基になるオブジェクトと結合したオブジェクトに、呼び出し元の行レベルセキュリティの範囲が自動的に適用されます。ダッシュボードが、ユーザーの[権限](/docs/configure/permissions)では見られないレコードを見せることはありません。 + +> 16.0 以降、ウィジェットのスキーマは**厳格**です。宣言されていないトップレベルのキー(入力ミス、ハルシネーションによるキー、削除されたインラインクエリのキー(`object` + `categoryField` + `valueField` + `aggregate`、ピボットの `rowField` / `columnField`))は、**問題のキーを名指しするパースエラー**になり、データセットの形を示します。何もレンダリングしないウィジェットへと黙って取り除かれることは、もうありません。データセットを定義してウィジェットをそれにバインドしてください。`options` は、レンダラー固有の追加設定のための自由形式の逃げ道として残っています。 + +## ウィジェット [#widgets] + +| プロパティ | 型 | 必須 | 説明 | +|:--|:--|:--|:--| +| `id` | `string` | はい | 一意なウィジェット ID(`snake_case`) | +| `dataset` | `string` | はい | バインドするデータセットの名前 | +| `values` | `string[]` | はい | メジャーの名前(少なくとも 1 つ) | +| `dimensions` | `string[]` | — | ディメンションの名前:X / グループ / 分割 | +| `type` | `ChartType` | — | 可視化の種類(デフォルト `metric`) | +| `title` / `description` | `string` | — | 表示用のタイトルとサブタイトル | +| `filter` | `FilterCondition` | — | 表示範囲のフィルター | +| `layout` | `object` | — | グリッド上の位置(省略時は自動配置) | +| `colorVariant` | `enum` | — | KPI / カードのアクセントカラー | +| `compareTo` | `enum \| object` | — | 期間比較のウィンドウ | +| `filterBindings` | `object` | — | ウィジェットごとのグローバルフィルターの対応付け(下記) | + +### チャートの種類 [#chart-types] + +| 種類 | 最適な用途 | +|:--|:--| +| `metric` *(デフォルト)* | 単一の数値の KPI:売上、件数、割合 | +| `bar` / `horizontal-bar` / `column` | カテゴリーの比較 | +| `line` | 時間の経過による傾向 | +| `pie` / `donut` | 分布 | +| `area` | 時間の経過による量 | +| `scatter` | 相関 | +| `radar` | 多次元の比較 | +| `funnel` | コンバージョンの段階 | +| `gauge` / `solid-gauge` / `bullet` / `kpi` | 目標に対する進捗 | +| `treemap` / `sankey` | 階層の比率 / 流れ | +| `table` | 詳細なレコード:**ドリルスルー** | +| `pivot` | クロス集計:**ドリルスルー** | + +### レイアウト [#layout] + +ウィジェットは 12 列のグリッドに配置されます。 + +```ts +// Keys of a dashboard widget; its other keys are omitted. +layout: { + x: 0, // column position (0-11) + y: 0, // row position + w: 6, // width in columns (1-12) + h: 4, // height in rows +} +``` + +## ドリルダウン [#drill-down] + +`table` と `pivot` のウィジェットは**ドリルスルー**できます。集計された行やセルをクリックすると、そのグループの背後にある*元のレコード*を一覧するサイドドロワーが開きます。データセットは生のグループキーを保持しているので、ドロワーのフィルターは正確なレコードに一致します。ラベルから ID を推測することはありません。ドロワー内の任意の行をクリックすると、そのレコードの詳細が開きます。**グループ → レコード一覧 → レコード**という一連の流れです。 + +ドロワーには **"Open in list →"** という逃げ道もあり、同じドリルのフィルターで範囲を絞ったまま、のぞき見をオブジェクトの完全なリストページ(並べ替え、一括選択、エクスポート、共有できる URL)に格上げします。 + +チャートのウィジェットも同じようにドリルできます。棒、点、扇形をクリックすると、ドロワーにそのバケットのレコードが一覧されます。日付のディメンションなら、そのバケットの日付範囲ぴったりです。データセットが基になるオブジェクトを公開し、ウィジェットが少なくとも 1 つのディメンションでグループ化していれば、ドリルスルーは自動的に働き、ウィジェットごとの設定は不要です。`metric` のタイルは集計値だけを表示します。[レポート](/docs/build/reports)も同じようにドリルスルーできます。 + +## グローバルな日付範囲とフィルター [#global-date-range-and-filters] + +グローバルな時間のフィルターはすべてのウィジェットに適用されます。 + +```ts +// Keys of a dashboard; its other keys are omitted. +dateRange: { field: 'created_at', defaultRange: 'this_month', allowCustomRange: true } +``` + +プリセットの範囲:`today`、`yesterday`、`this_week`、`last_week`、`this_month`、`last_month`、`this_quarter`、`last_quarter`、`this_year`、`last_year`、`last_7_days`、`last_30_days`、`last_90_days`、`custom`。 + +対話的なグローバルフィルターも同じように働きます。 + +```ts +// Keys of a dashboard; its other keys are omitted. +globalFilters: [ + { name: 'region', field: 'region', label: 'Region', type: 'select' }, + { field: 'owner', label: 'Sales Rep', type: 'lookup' }, +] +``` + +各フィルターの `name`(デフォルトは `field`)がその安定した識別子です。ウィジェットが `filterBindings` で参照するキーであり、ウィジェットの式の中で `page.` として読めるダッシュボードレベルの変数です。`dateRange` という名前は組み込みの日付範囲のために予約されています。 + +### ウィジェットごとのフィルターのバインディング [#per-widget-filter-bindings] + +デフォルトでは、フィルターはすべてのウィジェットで自身の `field` に適用されます。ウィジェットがその概念を別のフィールドに保持している場合、またはフィルターを無視すべき場合は、`filterBindings` を宣言します。 + +```ts +// Keys of a dashboard; each widget's dataset, values and title are omitted (`/* … */`). +widgets: [ + // Default binding: dateRange → created_at, region → region. + { id: 'invoices_by_status', /* … */ }, + // This widget's fields differ — map each filter explicitly. + { id: 'accounts_signed', + filterBindings: { dateRange: 'signed_at', region: 'sales_region' }, /* … */ }, + // Opt out of a filter with `false`. + { id: 'total_invoices', filterBindings: { region: false }, /* … */ }, +] +``` + +> 優先順位:明示的な `filterBindings` のエントリ(文字列による上書き、または `false` によるオプトアウト)→ フィルターの旧来の `targetWidgets` 許可リスト → フィルター自身の `field`。 + +## ダッシュボードを表示する [#surfacing-a-dashboard] + +[アプリ](/docs/build/interface/apps)に `dashboard` のナビゲーションエントリを追加します。 + +```ts +// One navigation item of an app. +{ id: 'nav_analytics', type: 'dashboard', label: 'Analytics', + dashboardName: 'sales_overview', icon: 'bar-chart' } +``` + +あるいは [AI Builder](/docs/build/ai-builder) に説明します(*「地域別の売上と月次の商談の推移を含む営業概要ダッシュボード」*)。そして承認する前に、生成されたデータセット + ダッシュボードのメタデータを確認します。 + +## 次に進む [#where-to-go-next] + +| ページ | 理由 | +|:--|:--| +| [レポート](/docs/build/reports) | 同じデータセットに対するグループ化レポートとクロス集計レポート | +| [アプリ](/docs/build/interface/apps) | ダッシュボードをナビゲーションに置く | +| [ビュー](/docs/build/interface/views) | 同じデータセットに対するインラインの `chart` リストビュー | +| [ページ](/docs/build/interface/pages) | ウィジェットのグリッドでは足りないときの自由形式のレイアウト | +| [データモデル](/docs/build/data) | データセットが集計するオブジェクト | +| [権限](/docs/configure/permissions) | ダッシュボードが継承する行レベルセキュリティ | diff --git a/content/docs/build/interface/forms.ja.mdx b/content/docs/build/interface/forms.ja.mdx new file mode 100644 index 00000000..3e5be655 --- /dev/null +++ b/content/docs/build/interface/forms.ja.mdx @@ -0,0 +1,175 @@ +--- +title: フォーム +seoTitle: "フォーム:作成と編集、セクション、送信後" +description: 作成フォームと編集フォームを 1 つのフラットなフィールドの集合から導き出し、ずれを生まずにフィールドをセクションにまとめ、送信後に起こることを制御します。 +editions: [community, cloud, enterprise] +translation: + source_sha: 7b91231facd6607664e7ec8baee9af1949872ed91a12abe14e7b20eb2d0c96e2 + guide_rev: 1 + mode: auto +--- + +**フォームはオブジェクトのフィールドの投影であり、2 つ目のフィールドリストではありません。** フィールドはオブジェクトで一度だけ宣言し、フォームは*どのフィールドをどこに*置くかを選びます。データの意味(型、検証、デフォルト、フィールドレベルのセキュリティ)がフォームに置かれることはないので、フォームがずれてデータについて偽ることはありません。 + +フォームビューの*種類*(`simple`、`tabbed`、`wizard`、`modal` など)と公開フォームの REST の契約は、[ビュー](/docs/build/interface/views)で扱っています。このページはレイアウトの問題、つまり作成と編集、グループ化、順序についてです。 + +## 作成フォーム ≠ 編集フォーム [#create-form--edit-form] + +新規レコードのフォームはいくつかの必須項目だけを尋ね、編集フォームはレコード全体をセクションに分けて表示するべきです。**2 つのフォームを作成しないでください。** 作成フォームのサブセットは、各フィールドにすでにある意図から*導き出せます*。 + +| フィールドの手がかり | 作成フォームへの影響 | +|:--|:--| +| `required: true` | 作成時に表示**しなければなりません** | +| `readonly` / 数式 / ロールアップ / 自動採番 / システムが記録するもの | 作成時には**決して**表示しません。設定できないからです | +| `defaultValue` がある | **省略できます**。自動で埋まるからです | +| `hidden` | デフォルトではどこにも表示しません | +| `group` | フィールドが属するセクション | +| *宣言の順序* | これがデフォルトの表示順序**です**。`field.order` はありません | + +そのため、妥当な作成フォーム(*編集可能で、必須または中核のフィールドを、宣言の順序で*)は、何も作成しなくてもオブジェクトから自然に導かれます。省略が正解です。余分なものを何も出力しなくても、完全で正しいフォームが得られます。完全な編集フォームも導き出され、各 `field.group` がセクションとして具体化されます。 + +### 作成フォームを手で整えるのは、レイアウトや流れが異なる場合だけ [#hand-shape-the-create-form-only-when-layout-or-flow-diverges] + +逃げ道は、作成のエントリポイントにバインドした名前付きのフォームビューです。これは**疎な上書き**として作成します。ほとんどはフィールド名のリストです。 + +```ts +import { defineView } from '@objectstack/spec' + +const data = { provider: 'object' as const, object: 'showcase_contact' } + +export const ContactViews = defineView({ + list: { + type: 'grid', data, + columns: [{ field: 'name' }, { field: 'email' }, { field: 'company' }, { field: 'stage' }], + // Bind the "+ Add record" entry point to the slim create form: + addRecord: { enabled: true, mode: 'form', formView: 'create' }, + }, + + // Full edit form — grouped by field.group; bare strings inherit field defs. + form: { + type: 'simple', data, + sections: [ + { name: 'contact', label: 'Contact', columns: 2, fields: ['name', 'email', 'phone'] }, + { name: 'work', label: 'Work', columns: 2, fields: ['company', 'title'] }, + { name: 'status', label: 'Status', columns: 2, fields: ['stage', 'lead_score'] }, + ], + }, + + formViews: { + // Sparse create override: only the core fields, one section. + create: { + type: 'simple', data, title: 'New contact', + sections: [ + { label: 'Who is this?', columns: 1, fields: ['name', 'email', 'phone', 'company'] }, + ], + }, + }, +}) +``` + +バインディングは `addRecord.mode: 'form'` + `addRecord.formView: 'create'` です。`formViews.create` がなければ、作成のエントリはデフォルトを導き出します。あれば、作成時にはそれが優先されます。 + +| 本当に必要なこと | 使うもの | +|:--|:--| +| 作成時に尋ねるフィールドを減らす(必須 + いくつかの中核) | **純粋な導出**。手で書かないでください | +| 作成時のグループ化が異なるが、小さなサブセットにすぎない | たいていはやはり導出 | +| 作成がウィザード / 多段階、作成専用の文言、条件付きの表示を持つ | **`formViews.create` を手で書く** | + +> 目安:*フィールドのサブセットが異なる* → 導出する。*レイアウトや流れが異なる* → 上書きする。フィールドを減らすためだけに完全な作成フォームを書くと、2 つの成果物がずれる罠にまっすぐはまります。必須フィールドを追加し、作成フォームのことを忘れ、作成時に実行時の「必須フィールドがありません」が出る、という具合です。 + +作成のフィールドは編集のフィールドの*同じ順序とグループの*サブセットなので、「4 つのフィールドでクイック作成 → 保存 → 完全なレコードに着地」が視覚的に途切れません。導出はそれを無償で保ちます。 + +## フィールドのグループ化と順序 [#field-grouping-and-order] + +モデルはフラットなフィールドの集合です。グリッドはフラットな列を表示します。フォームにはセクションが必要です。これは矛盾ではありません。1 つのフラットな集合を、異なるレンズを通して見ているのです。 + +| レンズ | フィールドの形 | 理由 | +|:--|:--|:--| +| オブジェクトの定義 | フラット | モデルは*どんなデータが存在するか*を記述します | +| テーブル / グリッド | フラットな列 | グリッドはレコード × フィールドの行列です | +| フォーム / レコードページ | グループ化されたセクション | 1 件のレコードを読む人間には区切りが必要です | + +グループ化の概念は **2 つ**あります。区別しておいてください。 + +**1. 意味上のグループ化:`field.group`(オブジェクト上)。** フィールドの論理的な居場所です。モデルとともに移動し、自動生成されるフォームの*デフォルトの*セクション分けの元になります。 + +```ts +// Fields of an object; the object around them is omitted. +fields: { + name: Field.text({ label: 'Full name', group: 'contact' }), + email: Field.email({ label: 'Email', group: 'contact' }), + stage: Field.select({ + label: 'Stage', + group: 'status', + options: [ + { label: 'Lead', value: 'lead' }, + { label: 'Customer', value: 'customer' }, + ], + }), +} +``` + +**2. レイアウト上のグループ化:フォームの `sections`(ビュー上)。** 特定のフォームの明示的な配置です。どのフィールドを、どのセクションに、何列(`columns`)で置くか、折りたたみ可能か。`field.group` をデフォルトとして継承し、必要に応じてフォームごとに上書きします。 + +```ts +// Keys of a view container; `data` and its other keys are omitted. +form: { + type: 'simple', + sections: [ + { name: 'contact', label: 'Contact', columns: 2, fields: ['name', 'email', 'phone'] }, + { name: 'status', label: 'Status', columns: 2, fields: ['stage'] }, + ], +} +``` + +**順序は作成した順序です。** `field.order` はありません。オブジェクト上のフィールドの宣言の順序が、どこでもデフォルトの表示順序であり、`sections`(とその中のフィールド)は順序付きのリストです。 + +> **「グループ」の罠。** グリッドビューの `groupByField` は、フィールドの*値*で **レコード(行)** をグループ化します。`stage = qualified` の行がすべてまとまります。フォームのセクションは **フィールド(列)** を視覚的にグループ化します。同じ言葉で、無関係な 2 つの軸です。グリッドのグループがフォームをセクションに分けることは決してありません。 + +## 送信後に起こること [#what-happens-after-submit] + +送信後の体験を制御するには、フォームビューに `submitBehavior` を追加します。 + +```ts +// Keys of a form view; its other keys are omitted. +submitBehavior: { + kind: 'thank-you', + title: 'Thanks!', + message: 'A specialist will reach out within 24 hours.', +} +``` + +| `kind` | 動作 | +|:--|:--| +| `thank-you` *(デフォルト)* | フォームを確認パネル(`title`、`message`)に置き換えます | +| `redirect` | `delayMs`(デフォルト 0)の後に `url` へ移動します。マーケティングページに最適です | +| `continue` | 次の回答のためにフォームをリセットします。キオスク、一括入力向けです | +| `next-record` | キュー内の次のレコードに進みます(内部モード) | + +公開フォームと内部フォームのどちらも、`?prefill_=` という URL パラメータに従います。メールのリンクやキャンペーンページからフォームに値を入れておけます。事前入力は UX の近道であって、権限のすり抜けではありません。値はやはり検証と、(公開フォームの場合は)サーバー側のフィールドのホワイトリストを通ります。 + +``` +/console/f/contact-us?prefill_company=Acme&prefill_email=ada@example.com +/console/forms/quick_create?prefill_lead_source=event_booth_2026 +``` + +## レコードの詳細はフォームのバインディングではなくロールで決まる [#record-detail-is-driven-by-roles-not-a-form-binding] + +フォームビューをレコード詳細画面に固定するオブジェクトレベルのキーはありません。詳細のレンダリングは、オブジェクトの画面をまたぐ**意味上のロール**から導き出されます。`nameField`(表示名)、`highlightFields`(最も重要なフィールドの帯)、`stageField`(ライフサイクルの進捗ステッパー)、そして `fieldGroups` + `Field.group`(フォーム、モーダル、詳細ページで共有されるセクション分け)です。ロールから導き出せる以上の特注のレイアウトがレコードページに必要なときは、そのオブジェクトにカスタムの[ページ](/docs/build/interface/pages)を割り当てます。 + +## アンチパターン [#anti-patterns] + +- **手で作成した 2 つの完全なフィールドリスト**(`contact_create_form` + `contact_edit_form`)。ずれることが確実です。 +- **フィールドの型 / 検証 / 選択肢をフォームで書き直すこと。** データの意味はオブジェクトにだけ置きます。 +- **すべてのフォームでグループ化を打ち直すこと。** `field.group` を一度宣言し、本当に異なる場合だけ上書きします。 +- **フォームを満たすためにデータモデルに構造的な入れ子を加えること。** モデルはフラットのままにし、フォームがグループ化します。 + +## 次に進む [#where-to-go-next] + +| ページ | 理由 | +|:--|:--| +| [ビュー](/docs/build/interface/views) | フォームビューの種類、公開フォームの共有、ビューの完全なスキーマ | +| [データモデル](/docs/build/data) | フィールドとその意図が宣言される場所 | +| [アクション](/docs/build/interface/actions) | フォームビューを開く `type: 'form'` のアクション | +| [ページ](/docs/build/interface/pages) | 導出されたレイアウトを超えるカスタムのレコードページ | +| [権限](/docs/configure/permissions) | フォームが従うフィールドレベルのセキュリティ | diff --git a/content/docs/build/interface/index.ja.mdx b/content/docs/build/interface/index.ja.mdx new file mode 100644 index 00000000..dc6217f8 --- /dev/null +++ b/content/docs/build/interface/index.ja.mdx @@ -0,0 +1,49 @@ +--- +title: インターフェース +seoTitle: "インターフェース:アプリ、ビュー、フォーム、ダッシュボード、ページ" +description: アプリ、ビュー、フォーム、ダッシュボード、ページ、アクション。ユーザーが目にするすべての画面をメタデータとして宣言し、ObjectOS がレンダリングします。 +editions: [community, cloud, enterprise] +translation: + source_sha: b5a75aba85c279c1de7f1e2e11254b300b51906392cfaa0a5f4e1f50a803e61c + guide_rev: 1 + mode: auto +--- + +**ユーザーが目にするものはすべてメタデータです。** インターフェースはデータとして宣言し、オブジェクトと同じライフサイクルを持ちます。バージョン管理し、パッケージで出荷し、AI Builder に生成させることができ、準拠したレンダラーならどれでも描画できます。 + +各部品は上から下へと組み合わさります。 + +1. **アプリ**は外枠です。ナビゲーション、ブランディング、対象者のゲートを持ちます。 +2. その**ナビゲーション**は、オブジェクト、ダッシュボード、ページ、URL を指します。 +3. オブジェクトのエントリは**ビュー**に着地します。グリッド、カンバン、カレンダーなどです。 +4. レコードを開いたり作成したりすると**フォーム**がレンダリングされます。セクションはフィールドのメタデータから導き出され、モードごとに上書きできます。 +5. **ダッシュボード**は同じデータを、名前付きデータセットにバインドされたチャートウィジェットに集約します。 +6. **ページ**はオブジェクトの枠から完全に抜け出します。コンポーネントとリージョンで構成する自由形式のレイアウトです。 +7. **アクション**は上記のすべてにボタンを置きます。1 つの宣言で、UI、REST、フロー、AI エージェントから呼び出せます。 + +## 概念 [#the-concepts] + +| 概念 | 宣言するもの | ページ | +|:--|:--|:--| +| アプリ | ナビゲーションの外枠、ブランディング、対象者のゲート | [アプリ](/docs/build/interface/apps) | +| ビュー | レコードのレンダリング方法:グリッド、カンバン、カレンダー、ガント…… | [ビュー](/docs/build/interface/views) | +| フォーム | 作成 / 編集のレイアウト、セクション、フィールドのグループ化 | [フォーム](/docs/build/interface/forms) | +| ダッシュボード | チャートウィジェット、グローバルフィルター、ドリルダウン | [ダッシュボード](/docs/build/interface/dashboards) | +| ページ | 自由形式のコンポーネントレイアウト。パッケージ化されたドキュメントページ | [ページ](/docs/build/interface/pages) | +| アクション | あらゆる場所にボタンとして表示される名前付きの操作 | [アクション](/docs/build/interface/actions) | + +UI はデータなので、表示するレコードと同じ[権限](/docs/configure/permissions)に従います。また [AI Builder](/docs/build/ai-builder) は、同じ型付きのインターフェースを通じて、そのどれでも生成または変更できます。欲しいインターフェースを説明し、差分を確認して、承認します。 + +> まずデータから始めてください。ビューとフォームは[オブジェクトの定義](/docs/build/data)から妥当なデフォルトを導き出すので、インターフェースのメタデータを書くのは、デフォルトが望みどおりでない箇所だけです。 + +## 次に進む [#where-to-go-next] + +| ページ | 理由 | +|:--|:--| +| [アプリ](/docs/build/interface/apps) | オブジェクトをナビゲーションできる外枠で包む | +| [ビュー](/docs/build/interface/views) | レコードのレンダリング方法を選ぶ | +| [フォーム](/docs/build/interface/forms) | 作成と編集の体験を形作る | +| [ダッシュボード](/docs/build/interface/dashboards) | 分析ウィジェットを追加する | +| [ページ](/docs/build/interface/pages) | 自由形式のレイアウトを構成する | +| [アクション](/docs/build/interface/actions) | 操作をボタンの背後に置く | +| [データモデル](/docs/build/data) | すべての画面が読み取るオブジェクト | diff --git a/content/docs/build/interface/pages.ja.mdx b/content/docs/build/interface/pages.ja.mdx new file mode 100644 index 00000000..f46decbb --- /dev/null +++ b/content/docs/build/interface/pages.ja.mdx @@ -0,0 +1,166 @@ +--- +title: ページ +seoTitle: "自由形式のページ:リージョン、コンポーネント、ドキュメントページ" +description: リージョン、コンポーネント、ローカル状態で構成する自由形式のレイアウト。さらに、パッケージの中に同梱して出荷する Markdown のドキュメントページ。 +editions: [community, cloud, enterprise] +translation: + source_sha: 4a88c0ee1ee387d77d686cf62b3d5270e2d183f2d362cd66274326205db8a3d4 + guide_rev: 1 + mode: auto +--- + +**ページは自由形式のコンテナです。** 単一のオブジェクトにバインドされる[ビュー](/docs/build/interface/views)とは異なり、ページは複数のコンポーネントを組み合わせ、ビューを埋め込み、ローカル状態を管理します。ホーム画面、カスタムのレコードレイアウト、ユーティリティパネルなどです。 + +```ts +// One page. +const homePage = { + name: 'sales_home', + label: 'Sales Home', + type: 'home', + regions: [ + { name: 'header', width: 'full', components: [ + { type: 'metric_card', id: 'total_revenue', label: 'Total Revenue', + properties: { dataset: 'sales', values: ['revenue'], format: 'currency' } }, + ]}, + { name: 'main', width: 'large', components: [ + { type: 'list_view', id: 'recent_deals', label: 'Recent Deals', + properties: { object: 'opportunity', view: 'recent_open', limit: 10 } }, + ]}, + ], +} +``` + +## ページのプロパティ [#page-properties] + +| プロパティ | 型 | 必須 | 説明 | +|:--|:--|:--|:--| +| `name` | `string` | はい | マシン名(`snake_case`) | +| `label` | `string` | はい | 表示ラベル | +| `type` | `enum` | — | ページの種類(デフォルト `'record'`、下記を参照) | +| `object` | `string` | — | 関連するオブジェクト(`record` の種類の場合) | +| `template` | `string` | — | レイアウトテンプレートの名前(デフォルト `'default'`) | +| `regions` | `PageRegion[]` | — | コンポーネントを含むレイアウトの区画 | +| `variables` | `PageVariable[]` | — | ローカル状態の変数 | +| `isDefault` | `boolean` | — | その種類のデフォルトのページかどうか | +| `assignedProfiles` | `string[]` | — | このページにアクセスできるプロファイル | + +### ページの種類 [#page-types] + +| 種類 | 用途 | +|:--|:--| +| `record` | 1 つのオブジェクトのレコードに結び付いたカスタムの詳細ページ | +| `home` | アプリのランディング / 入口 | +| `app` | 一般的なアプリケーションのレイアウト | +| `utility` | ツール、設定、ウィザード | +| `list` | データ駆動のインターフェース画面 | + +有効なのはこの 5 つの種類だけです。レンダラーが出荷されなかった以前のロードマップ上の種類は、スキーマから削除されました。 + +## リージョン [#regions] + +リージョンはレイアウトの区画で、それぞれがコンポーネントを保持します。 + +```ts +// Keys of a page; its other keys, and the regions' components, are omitted. +regions: [ + { name: 'sidebar', width: 'small', components: [/* … */] }, + { name: 'content', width: 'large', components: [/* … */] }, +] +``` + +`width` には `'small'`、`'medium'`、`'large'`、`'full'` を指定できます。 + +## コンポーネント [#components] + +コンポーネントはリージョンの中の構成要素です。 + +```ts +// One page component; the page and region around it are omitted. +{ + type: 'chart', + id: 'revenue_chart', + label: 'Revenue Trend', + properties: { chartType: 'line', dataset: 'sales', + dimensions: ['close_month'], values: ['revenue'] }, + events: { onClick: "navigate_to('opportunity_detail', { id: $event.id })" }, + visibleWhen: "'sales_manager' in os.user.positions", +} +``` + +分析を扱うコンポーネント(`chart`、`metric_card`)は名前付きの**データセット**にバインドし、その `dimensions` + `values` を名前で選びます。これは[ダッシュボード](/docs/build/interface/dashboards)のウィジェットと同じ ADR-0021 の形であり、Studio が出力する唯一の形です。削除されたインライン分析の形(コンポーネント上の `object` + `categoryField` + `valueField` + `aggregate`)は、16.0 以降はパースエラーになり、黙って無視される何もしない設定ではありません。 + +| プロパティ | 型 | 説明 | +|:--|:--|:--| +| `type` | `string` | 標準のコンポーネントの種類、またはカスタムの文字列 | +| `id` | `string` | 一意なコンポーネントインスタンスの ID | +| `properties` | `object` | コンポーネント固有の設定 | +| `events` | `object` | イベントハンドラー(アクションの式) | +| `visibleWhen` | `string` | CEL の表示条件の述語。TRUE のときだけコンポーネントがレンダリングされます(`visibility` は非推奨のエイリアスで、今も受け付けられ、`visibleWhen` に正規化されます) | +| `style` / `className` | — | その場限りの CSS | +| `responsiveStyles` | `object` | **推奨される**スタイル指定の手段:デスクトップ優先のブレークポイントごとのスタイルマップ(`large` を基準に、`medium` / `small` / `xsmall` で上書き)。スコープ付きの CSS にコンパイルされます。`var(--space-8)` のようなデザイントークンを優先してください | + +標準の、名前空間付きのコンポーネントの種類: + +| 名前空間 | 種類 | +|:--|:--| +| 構造 | `page:header`、`page:footer`、`page:sidebar`、`page:tabs`、`page:accordion`、`page:card`、`page:section` | +| レコードのコンテキスト | `record:details`、`record:highlights`、`record:related_list`、`record:activity`、`record:chatter`、`record:path`、`record:alert`、`record:quick_actions`、`record:reference_rail`、`record:history` | +| ナビゲーション | `app:launcher`、`nav:menu`、`nav:breadcrumb` | +| ユーティリティ | `global:search`、`global:notifications`、`user:profile` | +| AI | `ai:chat_window`、`ai:suggestion` | +| 要素 | `element:text`、`element:number`、`element:image`、`element:divider`、`element:button`、`element:filter`、`element:form`、`element:record_picker`、`element:text_input` | + +コンポーネントは、`dataSource`(複数オブジェクトのページ向けの、要素ごとのオブジェクトのバインディング)、`responsive`、`aria` の設定を持つこともできます。プロジェクト固有のウィジェットには、カスタムの文字列の種類も受け付けられます。 + +## 変数 [#variables] + +ページは、コンポーネントの間で共有されるローカル状態を保持します。 + +```ts +// Keys of a page; its other keys are omitted. +variables: [ + { name: 'selected_tab', type: 'string', defaultValue: 'overview' }, + { name: 'date_range', type: 'object', defaultValue: { start: null, end: null } }, +] +``` + +`type` には `'string'`(デフォルト)、`'number'`、`'boolean'`、`'object'`、`'array'`、`'record_id'` を指定できます。 + +> `record` の種類のページは、特注のレコードレイアウトのためにサポートされている方法です。ロールから導き出される詳細ページ([フォーム](/docs/build/interface/forms)を参照)では足りないときに使います。全幅のヘッダーに `record:highlights` を、サイドバーに `record:details` と `record:activity` を、メインのリージョンに `record:related_list` のコンポーネントを配置します。 + +[アプリ](/docs/build/interface/apps)から `page` のナビゲーションエントリでページを表示するか、`homePageId` でアプリのランディングページにします。 + +## ドキュメントページ [#doc-pages] + +**ドキュメント**はパッケージのドキュメントのページです。フラットな `src/docs/` ディレクトリに置いたプレーンな Markdown ファイルで、パッケージの成果物にコンパイルされ、UI の `/docs/` でレンダリングされます。ドキュメントは、AI アシスタントがパッケージについての質問に答えるときの根拠にもなります。 + +``` +src/docs/ + crm_index.md → doc name "crm_index" + crm_user_guide.md → doc name "crm_user_guide" +``` + +ファイル名の語幹がドキュメントの `name` になります。ディレクトリによる分類も、順序のファイルもありません。フラットな配置により相互参照が安定します。リンクはパスではなく、常にベース名で解決されます。 + +| ルール | 詳細 | +|:--|:--| +| 命名 | `snake_case`。ビルドの lint は**名前空間のプレフィックス**を要求します(`user_guide` ではなく `crm_user_guide`) | +| フロントマター | 省略可能。`title` と `description` が読み取られます。タイトルはフロントマター → 最初の `#` 見出し → ドキュメント名の順に解決されます | +| 相互参照 | プレーンな相対リンク(`[overview](./crm_index.md)`)。UI では `/docs/` に書き換えられ、GitHub ではそのまま機能します。**同じパッケージ内の壊れたリンクはビルドを失敗させます** | +| Markdown | CommonMark + GFM:テーブル、ハイライト付きのフェンスコード、見出しのアンカー、GitHub のアラート(`> [!TIP]`) | +| ビルド時に拒否されるもの | **MDX / 埋め込みコンポーネント**(ドキュメントはコードではなくデータであり、信頼の境界です)と**画像の参照**(まだアセットサービスがなく、壊れた画像よりも早い失敗の方がよいため) | + +ドキュメントの解決はパッケージ単位です。インストールされた 2 つのパッケージがそれぞれ同じ素の名前のドキュメントを出荷しても共存でき、どちらも他方を上書きしません。 + +> 動的なコンテンツ(ライブのフロー図、レコードのテーブル)については、コンポーネントを埋め込もうとしないでください。URL でメタデータにリンクします。ライブのビューはプラットフォームがレンダリングし、ドキュメントはそれを指し示すだけです。 + +## 次に進む [#where-to-go-next] + +| ページ | 理由 | +|:--|:--| +| [アプリ](/docs/build/interface/apps) | ページをナビゲーションに置き、`homePageId` を設定する | +| [ビュー](/docs/build/interface/views) | ページが埋め込むオブジェクトの画面 | +| [フォーム](/docs/build/interface/forms) | ロールから導き出されるレコードレイアウトとカスタムのレコードページ | +| [ダッシュボード](/docs/build/interface/dashboards) | 自由形式の代わりの、分析に特化したレイアウト | +| [アクション](/docs/build/interface/actions) | `element:button` のターゲットと `modal` の種類のアクション | +| [AI Builder](/docs/build/ai-builder) | チャットでページのメタデータを生成する | diff --git a/content/docs/build/interface/views.ja.mdx b/content/docs/build/interface/views.ja.mdx new file mode 100644 index 00000000..cb5582a3 --- /dev/null +++ b/content/docs/build/interface/views.ja.mdx @@ -0,0 +1,294 @@ +--- +title: ビュー +seoTitle: "ビュー:リスト、カンバン、カレンダー、ガント、フォーム" +description: リスト、フォーム、カンバン、カレンダー、ガントなど。すべてのオブジェクトの画面がどう宣言されるか。 +editions: [community, cloud, enterprise] +translation: + source_sha: f7208e0810feac70de2d69b3c01e2700665308487ccc26ac2e84bd3f0357fc0d + guide_rev: 1 + mode: auto +--- + +**ビュー**は、ユーザーがレコードを見て編集するための方法です。ビューは宣言的なメタデータで、オブジェクトと同じライフサイクルを持ちます。一度宣言し、パッケージとともに出荷し、どこでもレンダリングできます。 + +2 つの種類があります。 + +- **リストビュー**:多数のレコードを可視化します(グリッド、カンバン、カレンダー……) +- **フォームビュー**:単一のレコードを表示 / 編集します(シンプル、タブ、ウィザード……) + +スキーマのソース:[`packages/spec/src/ui/view.zod.ts`](https://github.com/objectstack-ai/objectstack/blob/main/packages/spec/src/ui/view.zod.ts)。 + +## 最短の宣言 [#the-shortest-possible-declaration] + +ビューを 1 つも宣言しなくても、すべてのオブジェクトには自動的にデフォルトのグリッドリストとシンプルなフォームが用意されます。それらを上書きまたは拡張するには、オブジェクトのビューを、オブジェクトの中ではなくその隣にある `defineView` コンテナで宣言します。`list` がデフォルトのリスト、`form` がデフォルトのフォームで、各ビューは `data` で自分のオブジェクトを指定します。 + +```ts +// src/ui/views/support_ticket.view.ts +import { defineView } from '@objectstack/spec'; + +const data = { provider: 'object' as const, object: 'support_ticket' }; + +export const SupportTicketViews = defineView({ + list: { + type: 'grid', + data, + columns: ['subject', 'status', 'priority', 'assignee'], + }, + form: { + type: 'simple', + data, + sections: [ + { name: 'details', label: 'Details', fields: ['subject', 'description', 'priority', 'status', 'assignee'] }, + ], + }, +}); +``` + +コンテナを、それが記述するオブジェクトの隣に、スタックに登録します。 + +```ts +// objectstack.config.ts +export default defineStack({ + // ... + views: [SupportTicketViews], +}); +``` + +複数のビューを持つオブジェクト(たとえば同じデータに対するカンバン*と*カレンダー)では、同じコンテナに名前付きのビューを追加します。ビュー切り替え用には `listViews`、名前で開くフォーム用には `formViews` です。すべてのリストビューは、種類にかかわらずトップレベルの `columns` を持ちます。 + +```ts +export const SupportTicketViews = defineView({ + list: { type: 'grid', data, columns: ['subject', 'status', 'priority', 'assignee'] }, + listViews: { + by_status: { + label: 'By status', type: 'kanban', data, columns: ['subject', 'priority'], + kanban: { groupByField: 'status', columns: ['subject', 'priority'] }, + }, + schedule: { + label: 'Schedule', type: 'calendar', data, columns: ['subject', 'due_at'], + calendar: { startDateField: 'due_at', titleField: 'subject' }, + }, + by_owner: { + label: 'By owner', type: 'grid', data, columns: ['assignee', 'subject', 'status', 'priority'], + sort: [{ field: 'assignee', order: 'asc' }], + }, + }, + formViews: { + quick: { type: 'modal', data, sections: [{ name: 'quick', label: 'Quick edit', fields: ['status', 'priority', 'assignee'] }] }, + full: { + type: 'tabbed', data, + sections: [ + { name: 'details', label: 'Details', fields: ['subject', 'description'] }, + { name: 'triage', label: 'Triage', fields: ['status', 'priority', 'assignee'] }, + ], + }, + }, +}); +``` + +コンテナとそのルールは、ObjectStack の [View metadata](https://objectstack.ai/docs/ui/views) に完全に記載されています。 + +## リストビューの種類 [#list-view-types] + +すべてのリストビューには、種類にかかわらずトップレベルの `columns` が必要です。その種類のそれ以外の設定は、種類の名前を付けた設定ブロックに入れます。 + +| `type` | レンダリングするもの | 設定ブロックとその必須キー | よく使う省略可能なキー | +|:--|:--|:--|:--| +| `grid` | データテーブル(デフォルト) | — | | +| `kanban` | 列のあるボード | `kanban: { groupByField, columns }` | `summarizeField`、`titleField` | +| `gallery` | カードの束 | `gallery`(必須キーなし) | `coverField`、`titleField` | +| `calendar` | 月 / 週 / 日 | `calendar: { startDateField }` | `endDateField`、`titleField`、`colorField` | +| `timeline` | 時系列のフィード | `timeline: { startDateField, titleField }` | `endDateField`、`groupByField` | +| `gantt` | プロジェクトのタイムライン + 依存関係 | `gantt: { startDateField, endDateField, titleField }` | `progressField`、`dependenciesField` | +| `map` | 地図上のピン | `map`(必須キーなし) | `locationField`、または `latitudeField` + `longitudeField` | +| `tree` | 自己参照の階層 | `tree`(必須キーなし) | `parentField`、`labelField` | +| `chart` | 埋め込みのチャート | `chart: { dataset, values }` | `chartType`、`dimensions` | + +以下の断片はそれぞれ単一のリストビューです。どれも上のように、`data` で自分のオブジェクトを指定して、`defineView` コンテナの `list` として、または `listViews` のエントリとして入れます。 + +### リストの共通オプション [#common-list-options] + +```ts +// One list view; the container and `data` are omitted (see above). +// P is the predicate template tag: import { P } from '@objectstack/spec' +{ + type: 'grid', + columns: ['subject','status','priority','assignee','created_at'], + + filter: [ { field: 'archived', operator: 'equals', value: false } ], + sort: [ { field: 'created_at', order: 'desc' } ], + pagination: { pageSize: 25 }, + searchableFields: ['subject','description'], + filterableFields: ['status','priority','assignee'], + + navigation: { mode: 'drawer' }, // 'page' | 'drawer' | 'modal' | 'split' | 'popover' | 'new_window' | 'none' + selection: { type: 'multiple' }, // 'none' | 'single' | 'multiple' + + rowActions: ['close_ticket','assign_to_me'], + bulkActions: ['bulk_close','bulk_export'], + + conditionalFormatting: [ + { condition: P`record.priority == 'urgent'`, style: { background: '#fef2f2', fontWeight: '600' } } // style values are strings + ], + + exportOptions: ['csv','xlsx'], + emptyState: { title: 'No tickets yet', message: 'Create one to get started', icon: 'inbox' } +} +``` + +`filter` と `sort` は [ObjectQL](/docs/reference/objectql) にコンパイルされます。`rowActions` と `bulkActions` は名前で[アクション](./actions)を参照します。 + +### カンバン [#kanban] + +```ts +// One list view; the container and `data` are omitted (see above). +{ + type: 'kanban', + columns: ['subject', 'priority', 'assignee'], // still required at the top level + kanban: { + groupByField: 'status', // discrete field — usually a select + summarizeField: 'amount', // optional total per column + columns: ['subject', 'priority', 'assignee'] // fields shown on each card + } +} +``` + +ボードの列は `groupByField` の値から作られ、その順序と色はそのフィールドの `select` の選択肢の定義から取られます。 + +列の間でドラッグ&ドロップすると、グループ化しているフィールドを設定する更新が発行されます。権限のルールは手動での編集と同じです。 + +### カレンダー [#calendar] + +```ts +// One list view; the container and `data` are omitted (see above). +{ + type: 'calendar', + columns: ['subject', 'start_at', 'end_at', 'priority'], + calendar: { + startDateField: 'start_at', + endDateField: 'end_at', // optional — single-point if omitted + titleField: 'subject', + colorField: 'priority' // optional — colours events by value + } +} +``` + +### ガント [#gantt] + +```ts +// One list view; the container and `data` are omitted (see above). +{ + type: 'gantt', + columns: ['name', 'start_at', 'due_at', 'percent_complete'], + gantt: { + startDateField: 'start_at', + endDateField: 'due_at', + titleField: 'name', + progressField: 'percent_complete', // optional, drives the progress bar + dependenciesField: 'depends_on' // optional — multiselect lookup to same object + } +} +``` + +### ツリー [#tree] + +```ts +// One list view; the container and `data` are omitted (see above). +{ + type: 'tree', + columns: ['name'], + tree: { + parentField: 'parent_id', // self-lookup that builds the hierarchy + labelField: 'name', // shown indented in the first column + defaultExpandedDepth: 1 // optional — 0 = roots only, omit = expand all + } +} +``` + +自己参照するオブジェクト(カテゴリー、部品表、組織単位、入れ子のコメント)では、ツリーグリッドが `parentField` のポインターに従って行を入れ子にします。 + +### チャート(インライン) [#chart-inline] + +`chart` リストビューは、名前付きの**データセット**(セマンティックな分析レイヤー、ADR-0021)にバインドし、そのディメンションとメジャーを**名前で**選びます。指標を一度定義すれば、同じデータセットにバインドされたすべてのチャート、ダッシュボード、レポートの一貫性が保たれます。 + +```ts +// One list view; the container and `data` are omitted (see above). +{ + type: 'chart', + columns: ['status'], + chart: { + chartType: 'bar', // 'bar' | 'line' | 'pie' | 'area' | 'scatter' + dataset: 'tickets_by_status', // a dataset declared with defineDataset(...) + dimensions: ['status'], // dataset dimension name(s) — X / group / split + values: ['ticket_count'] // dataset measure name(s) — the value axis + } +} +``` + +インラインの `xAxisField` / `yAxisFields` / `aggregation` / `groupByField` という形は 9.0 で削除されました。今では、すべてのチャート、ダッシュボードのウィジェット、レポートがデータセットにバインドします。より高度な、オブジェクトをまたぐ分析には、専用のレポート画面を使ってください。 + +## フォームビューの種類 [#form-view-types] + +| `type` | レイアウト | +|:--|:--| +| `simple` | 単一の列またはセクション(デフォルト) | +| `tabbed` | タブ付きのセクション | +| `wizard` | ステップごとの流れ | +| `split` | マスター / 詳細の 2 ペイン | +| `drawer` | サイドパネルのフォーム | +| `modal` | ダイアログのフォーム | + +```ts +// One form view; the container and `data` are omitted (see above). +{ + type: 'tabbed', + sections: [ + { label: 'Overview', fields: ['subject','status','priority','assignee'] }, + { label: 'Customer', fields: ['customer','contact','email','phone'] }, + { label: 'Resolution', fields: ['resolution_notes','resolved_at'] } + ], + submitBehavior: { kind: 'next-record' } // 'thank-you' | 'redirect' | 'continue' | 'next-record' +} +``` + +### 公開フォーム [#public-forms] + +フォームは匿名でアクセスできるようにできます。 + +```ts +// One form view; the container and `data` are omitted (see above). +{ + type: 'simple', + sections: [ { fields: ['name','email','message'] } ], + sharing: { + enabled: true, + publicLink: 'contact-us', // slug under /forms/ + allowAnonymous: true + }, + submitBehavior: { kind: 'thank-you' } +} +``` + +これにより `GET /api/v1/forms/contact-us` と `POST /api/v1/forms/contact-us/submit` が自動的に公開されます。認証を必要としない公開フォームのルートです。[REST API → Public forms](/docs/reference/rest-api#public-forms) を参照してください。 + +## 表示条件、ARIA、テーマ [#visibility-aria-theming] + +- `visibleOn: P\`...\``:フォームの**セクション**と**フィールド**で、ユーザー / レコード / 環境に基づいてそれらを隠します(CEL の述語) +- `aria: { label, description, ... }`:スクリーンリーダー向けの ARIA 属性(リストビューとフォームビュー) +- `appearance: { showDescription, allowedVisualizations: [...] }`:リストビューで、エンドユーザーが切り替えられるリストの種類を制限します + +## チャットで構築する [#build-by-chat] + +ビューのメタデータを手で書くことは通常ありません。AI Builder にこう伝えます。 + +> *「support_ticket オブジェクトのカンバンビューを、ステータスでグループ化して追加して。カードには件名と優先度を表示して。列はステータスに応じて赤 / 黄 / 緑に色分けして。」* + +AI Builder はメタデータツールを呼び出し、差分をキューに入れ、あなたが承認するとビューが表示されます。[AI Builder](/docs/build/ai-builder) を参照してください。 + +## 関連項目 [#see-also] + +- [データモデル](/docs/build/data):ビューが読み取るオブジェクト +- [アクション](./actions):`rowActions` / `bulkActions` が参照するもの +- [ObjectQL](/docs/reference/objectql):`filter` / `sort` のコンパイル先 +- [CEL](/docs/reference/cel):`conditionalFormatting`、`visibleOn` +- [`@objectstack/spec/ui/view.zod.ts`](https://github.com/objectstack-ai/objectstack/blob/main/packages/spec/src/ui/view.zod.ts):スキーマ From 3fd70471c184514458239f32260271399caa859c Mon Sep 17 00:00:00 2001 From: Steedos Date: Thu, 29 Oct 2026 13:15:06 +0000 Subject: [PATCH 06/22] fix(worker): stop bundling every docs page twice (#395) Six route handlers (search, og, sitemap, llms.txt, llms-full.txt, llms.mdx) import lib/source.ts, whose fumadocs-mdx collection holds a lazy import() of every compiled page. Turbopack compiles route handlers as their own module graph, so the Worker carried a second copy of every page module: ~20 MB of upload, and each translated page cost ~170-235 KiB instead of ~86. #388's PR 3 would have gone over the 61,440 KiB budget. - scripts/gen-route-data.mjs (was gen-search-data.mjs) also writes .route-data/collection.ts: .source/server.ts with each page's body import replaced by a read of generated data, and markdown.ts, the English pages' processed Markdown the llms routes serve. With --dev it re-exports the full collection so next dev sees new pages. - lib/source.ts builds its loader on that collection; the page route loads bodies through lib/page-body.ts, the only module that imports the full collection. - lib/packed.ts unpacks the generated gzip+base64 strings. - The Worker budget step prints a per-page projection from the bundle's metafile (check-worker-page-cost.mjs, in SELF_TESTED). Measured, same machine: main f7e4a57 59,173 KiB, this change 38,909 KiB; with every ja page filled in, 43,700 KiB. Fixes #395 Claude-Session: https://claude.ai/code/session_01QsR2jRsjbApbf83iyTDDXm Co-Authored-By: Claude --- .github/scripts/check-worker-page-cost.mjs | 214 ++++++++++++++++++ .github/workflows/ci.yml | 14 +- .../docs/app/[lang]/docs/[[...slug]]/page.tsx | 11 +- apps/docs/app/api/search/route.ts | 19 +- apps/docs/lib/packed.ts | 12 + apps/docs/lib/page-body.ts | 22 ++ apps/docs/lib/source.ts | 26 ++- apps/docs/package.json | 6 +- apps/docs/scripts/gen-route-data.mjs | 203 +++++++++++++++++ apps/docs/scripts/gen-search-data.mjs | 121 ---------- tools/ci-scripts/run-self-tests.mjs | 8 + 11 files changed, 514 insertions(+), 142 deletions(-) create mode 100644 .github/scripts/check-worker-page-cost.mjs create mode 100644 apps/docs/lib/packed.ts create mode 100644 apps/docs/lib/page-body.ts create mode 100644 apps/docs/scripts/gen-route-data.mjs delete mode 100644 apps/docs/scripts/gen-search-data.mjs diff --git a/.github/scripts/check-worker-page-cost.mjs b/.github/scripts/check-worker-page-cost.mjs new file mode 100644 index 00000000..a3c99d33 --- /dev/null +++ b/.github/scripts/check-worker-page-cost.mjs @@ -0,0 +1,214 @@ +#!/usr/bin/env node +/** + * The Worker's cost per docs page, and how many more pages the budget holds + * (#395). It runs in `Worker bundle fits the size budget`, after the size + * itself is measured. + * + * #390's eleven ja pages and #388's PR 3 showed how a content batch finds out + * it is too big: the budget step goes red after the batch is written. A + * translated page costs its compiled module, its search text and a little + * routing data, and nothing said how much up front. So this prints, from the + * bundle just packaged: + * + * - the KiB each locale's page modules and search text take, per page; + * - what one more translated page costs: the most expensive locale's + * module and search text per page, plus `OVERHEAD_KIB`; + * - how many more such pages fit under the budget; + * - what one more fully translated locale (one page per English page) would + * cost, and whether it fits. + * + * `OVERHEAD_KIB` is what a page adds outside its module and search text: + * frontmatter, the route manifests, the prerender entry. Measured on #395: + * filling ja from 43 to 98 pages added 4,791 KiB of upload, of which 4,019 + * were page modules and 238 search text, so 534 KiB over 55 pages, about 10 + * KiB each. The projection is within about 2% of that measured growth. + * + * It reads the esbuild metafile OpenNext writes next to the bundled handler + * (`handler.mjs.meta.json`). Turbopack names a page's chunk after its file, + * `content_docs___mdx_.js`, and an English page's chunk + * has no locale part, so `bytesInOutput` per chunk is the bytes each page puts + * in the upload. A chunk under `content_docs_` that names no `_mdx_` file is + * shared between pages and is counted as such, not as a page. A locale's + * search text is the chunk of `.route-data/search-.ts`. + * + * The projection is a mean, not a promise: a page with long code samples costs + * more. It never fails the step on a number; the budget check above does that. + * It fails when it cannot read what it projects from (`unreadable`, + * `no-pages`), because a projection that silently prints nothing is the + * state #395 exists to end. + * + * Usage: `check-worker-page-cost.mjs --meta --size + * --budget `, from anywhere. `--self-test` runs every rule against fake + * metafiles and needs no build. + */ +import { readFileSync } from 'node:fs'; +import { basename, dirname, join, resolve } from 'node:path'; +import { fileURLToPath } from 'node:url'; + +const ROOT = resolve(dirname(fileURLToPath(import.meta.url)), '../..'); +const KIB = 1024; +const OVERHEAD_KIB = 10; // per page, outside its module and search text (header) +const RULES = ['unreadable', 'no-pages']; + +/** `languages` and `defaultLanguage` out of `i18n.ts`. Throws rather than guessing. */ +function readI18n(text) { + const languages = /languages:\s*\[([^\]]+)\]/.exec(text)?.[1]?.split(',').map((s) => s.trim().replace(/['"]/g, '')).filter(Boolean) ?? []; + const defaultLanguage = /defaultLanguage:\s*['"]([^'"]+)['"]/.exec(text)?.[1]; + if (!languages.length || !languages.includes(defaultLanguage)) { + throw new Error('could not read languages[] and defaultLanguage out of apps/docs/lib/i18n.ts'); + } + return { languages, defaultLanguage }; +} + +/** Per-locale page bytes out of a parsed metafile. */ +function pageBytes(meta, { languages, defaultLanguage }) { + const locales = new Map(languages.map((l) => [l, { pages: 0, bytes: 0, search: 0 }])); + let shared = 0; + for (const output of Object.values(meta?.outputs ?? {})) { + for (const [path, input] of Object.entries(output.inputs ?? {})) { + const name = basename(path); + const search = languages.find((l) => name.includes(`route-data_search-${l}_ts`)); + if (search) locales.get(search).search += input.bytesInOutput; + if (!name.startsWith('content_docs_')) continue; + if (!name.includes('_mdx_')) { + shared += input.bytesInOutput; + continue; + } + const locale = languages.find((l) => l !== defaultLanguage && name.includes(`_${l}_mdx_`)) ?? defaultLanguage; + const row = locales.get(locale); + row.pages += 1; + row.bytes += input.bytesInOutput; + } + } + return { locales, shared }; +} + +/** The summary, as Markdown lines, plus findings. */ +function project({ meta, size, budget, i18n }) { + const findings = []; + if (!meta || !Number.isFinite(size) || !Number.isFinite(budget)) { + findings.push({ rule: 'unreadable', detail: 'no metafile, size or budget to project from' }); + return { findings, lines: [] }; + } + const { locales, shared } = pageBytes(meta, i18n); + const english = locales.get(i18n.defaultLanguage); + const translated = [...locales].filter(([l, r]) => l !== i18n.defaultLanguage && r.pages > 0); + if (!english.pages) { + findings.push({ rule: 'no-pages', detail: 'the metafile names no `content_docs_*_mdx_*` chunk, so the page modules were not found' }); + return { findings, lines: [] }; + } + // A translated page is what the next batch adds; English stands in when no locale has one yet. + // The most expensive locale sets the cost, so the projection errs towards less room. + const cost = (r) => (r.bytes + r.search) / r.pages / KIB; + const [costliest, worst] = (translated.length ? translated : [[i18n.defaultLanguage, english]]).reduce((a, b) => (cost(b[1]) > cost(a[1]) ? b : a)); + const perPage = cost(worst) + OVERHEAD_KIB; + const headroom = budget - size; + const left = Math.max(0, Math.floor(headroom / perPage)); + const locale = english.pages * perPage; + const lines = [ + '#### Per-page cost', + '', + '| locale | page modules | module KiB | search KiB | KiB per page |', + '|:--|--:|--:|--:|--:|', + ...[...locales] + .filter(([, r]) => r.pages) + .map(([l, r]) => `| ${l} | ${r.pages} | ${(r.bytes / KIB).toFixed(2)} | ${(r.search / KIB).toFixed(2)} | ${cost(r).toFixed(2)} |`), + `| shared | — | ${(shared / KIB).toFixed(2)} | — | — |`, + '', + `A translated page costs about **${perPage.toFixed(2)} KiB**: ${costliest}'s ${cost(worst).toFixed(2)} KiB per page, the most of any locale, plus ${OVERHEAD_KIB} KiB of routing data.`, + `The budget holds **${left}** more such pages (${headroom.toFixed(2)} KiB of headroom).`, + `One more fully translated locale (${english.pages} pages) would add about ${locale.toFixed(0)} KiB: ${ + locale <= headroom ? `it fits, leaving ${(headroom - locale).toFixed(0)} KiB` : `it does NOT fit, by ${(locale - headroom).toFixed(0)} KiB` + }.`, + ]; + return { findings, lines }; +} + +function arg(name) { + const i = process.argv.indexOf(name); + return i < 0 ? undefined : process.argv[i + 1]; +} + +function gate() { + const i18n = readI18n(readFileSync(join(ROOT, 'apps/docs/lib/i18n.ts'), 'utf8')); + let meta; + try { + meta = JSON.parse(readFileSync(arg('--meta') ?? '', 'utf8')); + } catch { + meta = undefined; + } + const { findings, lines } = project({ meta, size: Number(arg('--size')), budget: Number(arg('--budget')), i18n }); + if (lines.length) console.log(lines.join('\n')); + for (const f of findings) console.error(` (${f.rule}) ${f.detail}`); + if (findings.length) { + console.error(`\n✗ Worker page cost: NOT MEASURED. The rules are in this script's header.`); + return 1; + } + return 0; +} + +/* Self-test: fake metafiles, each case checked for its findings and, where it projects, its numbers. */ +const I18N = { languages: ['en', 'ja', 'de'], defaultLanguage: 'en' }; +const chunk = (name, kib) => [`.next/server/chunks/ssr/${name}`, { bytesInOutput: kib * KIB }]; +const metafile = (...chunks) => ({ outputs: { 'handler.mjs': { inputs: Object.fromEntries([chunk('next_dist_x.js', 900), ...chunks]) } } }); +const CASES = [ + [ + 'ja pages set the per-page cost; en and shared are listed, not averaged', + { meta: metafile(chunk('content_docs_a_mdx_1.js', 50), chunk('content_docs_b_mdx_2.js', 70), chunk('content_docs_a_ja_mdx_3.js', 100), chunk('content_docs_x._.js', 30)), size: 1000, budget: 1450, i18n: I18N }, + [], + ['**110.00 KiB**', 'ja\'s 100.00', '**4** more', '2 pages) would add about 220 KiB: it fits, leaving 230 KiB', '| shared | — | 30.00 |'], + ], + [ + 'no translation yet: English sets the cost', + { meta: metafile(chunk('content_docs_a_mdx_1.js', 40), chunk('content_docs_b_mdx_2.js', 60)), size: 1000, budget: 1100, i18n: I18N }, + [], + ['**60.00 KiB**', '**1** more', 'about 120 KiB: it does NOT fit, by 20 KiB'], + ], + [ + 'over the budget: no page left, and a locale does not fit', + { meta: metafile(chunk('content_docs_a_mdx_1.js', 40), chunk('content_docs_a_de_mdx_9.js', 80)), size: 1200, budget: 1100, i18n: I18N }, + [], + ['**0** more', 'it does NOT fit, by 190 KiB'], + ], + [ + 'search text counts, and the costliest locale sets the cost', + { meta: metafile(chunk('content_docs_a_mdx_1.js', 40), chunk('content_docs_a_ja_mdx_3.js', 60), chunk('content_docs_b_ja_mdx_4.js', 60), chunk('apps_docs__route-data_search-ja_ts_0xv.js', 20), chunk('content_docs_a_de_mdx_9.js', 50)), size: 1000, budget: 1400, i18n: I18N }, + [], + ['| ja | 2 | 120.00 | 20.00 | 70.00 |', 'about **80.00 KiB**: ja\'s 70.00', '**5** more'], + ], + ['no metafile', { meta: undefined, size: 1, budget: 2, i18n: I18N }, ['unreadable'], []], + ['no size', { meta: metafile(chunk('content_docs_a_mdx_1.js', 40)), size: NaN, budget: 2, i18n: I18N }, ['unreadable'], []], + ['the chunks were renamed', { meta: metafile(chunk('pages_a.js', 40)), size: 1, budget: 2, i18n: I18N }, ['no-pages'], []], +]; + +function selfTest() { + let failed = 0; + const fired = new Set(); + for (const [name, input, wantRules, wantText] of CASES) { + const { findings, lines } = project(input); + const got = findings.map((f) => f.rule).sort(); + got.forEach((r) => fired.add(r)); + const text = lines.join('\n'); + const missing = wantText.filter((t) => !text.includes(t)); + const pass = JSON.stringify(got) === JSON.stringify([...wantRules].sort()) && !missing.length; + if (!pass) failed += 1; + console.log(`${pass ? '✓' : '✗'} ${name}: ${got.length ? got.join(', ') : 'no findings'}${missing.length ? ` — missing ${JSON.stringify(missing)}` : ''}`); + } + const silent = RULES.filter((r) => !fired.has(r)); + if (silent.length) { + failed += 1; + console.log(`✗ rules no fixture makes fire: ${silent.join(', ')}`); + } + let unreadable = false; + try { + readI18n('defineI18n({})'); + } catch { + unreadable = true; + } + if (!unreadable) failed += 1; + console.log(`${unreadable ? '✓' : '✗'} an unreadable i18n.ts is rejected`); + console.log(failed ? `\n✗ Worker page cost self-test: ${failed} failure(s)` : `\n✓ Worker page cost self-test: ${CASES.length} cases, all ${RULES.length} rules can fire`); + return failed ? 1 : 0; +} + +process.exitCode = process.argv.includes('--self-test') ? selfTest() : gate(); diff --git a/.github/workflows/ci.yml b/.github/workflows/ci.yml index 0ed37e43..6754206e 100644 --- a/.github/workflows/ci.yml +++ b/.github/workflows/ci.yml @@ -409,6 +409,7 @@ jobs: exit 1 fi + VERDICT=0 awk -v size="$SIZE_KIB" -v budget="$WORKER_BUDGET_KIB" -v limit="$WORKER_LIMIT_KIB" ' BEGIN { over = (size > budget) @@ -426,7 +427,18 @@ jobs: printf "one of them. Reduce the bundle, or raise the budget deliberately and say why.\n" } exit (over ? 1 : 0) - }' | tee -a "$GITHUB_STEP_SUMMARY" + }' | tee -a "$GITHUB_STEP_SUMMARY" || VERDICT=$? + + # #395: what the next content batch has room for, printed whether or + # not this one fits. The KiB a translated page costs, read from the + # bundle just packaged, and how many more pages and locales that + # leaves under the budget. It goes red only when it cannot read the + # bundle; the verdict above is the budget gate. + echo | tee -a "$GITHUB_STEP_SUMMARY" + node "$GITHUB_WORKSPACE/.github/scripts/check-worker-page-cost.mjs" \ + --meta .open-next/server-functions/default/apps/docs/handler.mjs.meta.json \ + --size "$SIZE_KIB" --budget "$WORKER_BUDGET_KIB" | tee -a "$GITHUB_STEP_SUMMARY" + exit "$VERDICT" # `include-hidden-files` is load-bearing, not tidiness: the compiled # OpenNext config the deploy reads lives at `.open-next/.build/`, and diff --git a/apps/docs/app/[lang]/docs/[[...slug]]/page.tsx b/apps/docs/app/[lang]/docs/[[...slug]]/page.tsx index b23fbc38..cf977c19 100644 --- a/apps/docs/app/[lang]/docs/[[...slug]]/page.tsx +++ b/apps/docs/app/[lang]/docs/[[...slug]]/page.tsx @@ -17,6 +17,7 @@ import type { InferPageType } from 'fumadocs-core/source'; import type { TOCItemType } from 'fumadocs-core/toc'; import { EditionBadges } from '@/components/editions'; import { EDITIONS_PAGE_SLUGS } from '@/lib/editions'; +import { loadPageBody } from '@/lib/page-body'; /** * The page type the loader actually produces, frontmatter schema included. @@ -267,7 +268,11 @@ export default async function Page(props: { // Under `dynamicParams = false` this await runs at BUILD time, in Node, on // every one of the 1139 prerendered paths — the Worker serves the prerendered // result out of the static-assets incremental cache and does not re-render. - const loaded = await page.data.load(); + // + // Loaded through `lib/page-body.ts`, not `page.data.load()`: `source` is + // built without the compiled bodies so the route handlers do not bundle a + // second copy of every page (#395). + const loaded = await loadPageBody(page); const MDX = loaded.body; // Resolved once and handed to both controls (through `copySource` and @@ -309,11 +314,11 @@ export default async function Page(props: { // translation it is this locale's text, which the `.mdx` surface does not // serve (English-only, see `markdownUrl`), so it is rendered into the page // instead: `getLLMText` builds it exactly as `/llms.mdx/docs/...` builds the - // English body, from the module `page.data.load()` above already loaded. + // English body, from the module `loadPageBody` above already loaded. const copySource: MarkdownSource = contentLang === i18n.defaultLanguage ? { url: pageMarkdownUrl } - : { text: await getLLMText(page) }; + : { text: await getLLMText(page, loaded._exports._markdown as string) }; // "Open in ChatGPT / Claude" follows the same rule (#305): the assistant is // sent to the page on screen. The English Markdown when that is the English diff --git a/apps/docs/app/api/search/route.ts b/apps/docs/app/api/search/route.ts index b41e3342..a762706a 100644 --- a/apps/docs/app/api/search/route.ts +++ b/apps/docs/app/api/search/route.ts @@ -1,6 +1,7 @@ import { source } from '@/lib/source'; import { i18n } from '@/lib/i18n'; -import { searchData } from '@/.search'; +import { unpack } from '@/lib/packed'; +import { searchData } from '@/.route-data/search'; import { createSearchAPI, type AdvancedIndex, @@ -123,9 +124,9 @@ type StructuredData = AdvancedIndex['structuredData']; /** * One locale's `structuredData` — each page's headings and paragraphs — keyed - * by file path under `content/docs`, from `.search/` (#393). + * by file path under `content/docs`, from `.route-data/` (#393). * - * `scripts/gen-search-data.mjs` writes it before every build, with the same + * `scripts/gen-route-data.mjs` writes it before every build, with the same * remark chain fumadocs-mdx compiles the pages with. Reading it from there * instead of from `page.data.load()` is the point: `load()` imports the page's * compiled module, the module registry keeps it for the life of the isolate, @@ -134,11 +135,7 @@ type StructuredData = AdvancedIndex['structuredData']; * dropped once the index has the text. */ async function texts(locale: Locale): Promise> { - // Gzipped JSON in base64, because the module is Worker upload too. - const packed = (await searchData[locale]()).default; - const bytes = Uint8Array.from(atob(packed), (c) => c.charCodeAt(0)); - const json = new Blob([bytes]).stream().pipeThrough(new DecompressionStream('gzip')); - return JSON.parse(await new Response(json).text()); + return unpack((await searchData[locale]()).default); } /** @@ -156,10 +153,10 @@ async function indexes(locale: Locale): Promise { const file = page.data.info.path; let structuredData = own[file] ?? fallback?.[file]; if (!structuredData) { - // `next dev` serves pages added since it wrote `.search/`; a build - // writes it first, so there a missing page is a stale `.search/`. + // `next dev` serves pages added since it wrote `.route-data/`; a build + // writes it first, so there a missing page is a stale `.route-data/`. if (process.env.NODE_ENV !== 'development') { - throw new Error(`/api/search: no search data for ${file}; run scripts/gen-search-data.mjs`); + throw new Error(`/api/search: no search data for ${file}; run scripts/gen-route-data.mjs`); } structuredData = (await page.data.load()).structuredData; } diff --git a/apps/docs/lib/packed.ts b/apps/docs/lib/packed.ts new file mode 100644 index 00000000..8d448fed --- /dev/null +++ b/apps/docs/lib/packed.ts @@ -0,0 +1,12 @@ +/** + * Reads a value `scripts/gen-route-data.mjs` packed: JSON, gzipped, in base64. + * + * The generated modules are Worker upload as well as text the route handlers + * read, so they are stored compressed (#393). `atob`, `Blob` and + * `DecompressionStream` are in both Node and the Workers runtime. + */ +export async function unpack(packed: string): Promise { + const bytes = Uint8Array.from(atob(packed), (c) => c.charCodeAt(0)); + const json = new Blob([bytes]).stream().pipeThrough(new DecompressionStream('gzip')); + return JSON.parse(await new Response(json).text()); +} diff --git a/apps/docs/lib/page-body.ts b/apps/docs/lib/page-body.ts new file mode 100644 index 00000000..301e9a9c --- /dev/null +++ b/apps/docs/lib/page-body.ts @@ -0,0 +1,22 @@ +import { docs } from 'fumadocs-mdx:collections/server'; +import type { InferPageType } from 'fumadocs-core/source'; +import type { source } from '@/lib/source'; + +/** + * Each page's entry in fumadocs-mdx's full collection, by file path under + * `content/docs`. + * + * This is the one module that imports the full collection, with its lazy + * import of every compiled page (#395). Import it from the page route only: + * anything a route handler imports puts every compiled page in the route + * handlers' module graph, a second copy of them in the Worker upload, which is + * what `lib/source.ts` is built to avoid. + */ +const entries = new Map(docs.docs.map((entry) => [entry.info.path, entry])); + +/** `page`'s compiled body, toc and exports, as `page.data.load()` returns them on the full collection. */ +export async function loadPageBody(page: InferPageType) { + const entry = entries.get(page.data.info.path); + if (!entry) throw new Error(`${page.data.info.path}: not in the fumadocs-mdx collection`); + return entry.load(); +} diff --git a/apps/docs/lib/source.ts b/apps/docs/lib/source.ts index 5feca672..b478cef4 100644 --- a/apps/docs/lib/source.ts +++ b/apps/docs/lib/source.ts @@ -1,8 +1,22 @@ -import { docs } from 'fumadocs-mdx:collections/server'; +import { docs } from '@/.route-data/collection'; import { type InferPageType, loader } from 'fumadocs-core/source'; import { lucideIconsPlugin } from 'fumadocs-core/source/lucide-icons'; import { i18n } from '@/lib/i18n'; +/** + * Every page's tree position, URL and frontmatter, WITHOUT its compiled body + * (#395). + * + * The collection is fumadocs-mdx's own, rewritten by + * `scripts/gen-route-data.mjs` so that a page's body is not a lazy import of + * its compiled module. Six route handlers import this file, and a lazy import + * is still bundled: with the full collection here the route handlers' module + * graph carried a second copy of every page, about 20 MB of the Worker upload. + * `page.data.load()` therefore does not return a renderable body on this + * source; the page route loads bodies through `lib/page-body.ts`, which is the + * one module that imports the full collection. `getText('processed')` works + * for English pages, which is what the `llms` routes read. + */ export const source = loader({ baseUrl: '/docs', i18n, @@ -79,8 +93,14 @@ function stripMdxComments(markdown: string): string { return markdown.replace(FENCE_OR_MDX_COMMENT, (match, fence?: string) => (fence ? match : '')); } -export async function getLLMText(page: InferPageType) { - const processed = stripMdxComments(await page.data.getText('processed')); +/** + * `page`'s Markdown as the `llms` surfaces serve it. `processed` is the page's + * processed Markdown when the caller already has it (the page route, from the + * module it rendered); otherwise it is read through `source`, which has it for + * English pages only. + */ +export async function getLLMText(page: InferPageType, processed?: string) { + processed = stripMdxComments(processed ?? (await page.data.getText('processed'))); return `# ${page.data.title} diff --git a/apps/docs/package.json b/apps/docs/package.json index 7d875e3c..1c23e75a 100644 --- a/apps/docs/package.json +++ b/apps/docs/package.json @@ -5,12 +5,12 @@ "description": "ObjectOS Documentation Site", "license": "Apache-2.0", "scripts": { - "dev": "fumadocs-mdx && node scripts/gen-search-data.mjs && next dev", + "dev": "fumadocs-mdx && node scripts/gen-route-data.mjs --dev && next dev", "gen:zh-hant": "node scripts/gen-zh-hant.mjs", - "build": "fumadocs-mdx && node scripts/gen-search-data.mjs && next build", + "build": "fumadocs-mdx && node scripts/gen-route-data.mjs && next build", "start": "next start", "lint": "next lint", - "type-check": "next typegen && fumadocs-mdx && node scripts/gen-search-data.mjs && tsc --noEmit && node scripts/check-frontmatter.mjs", + "type-check": "next typegen && fumadocs-mdx && node scripts/gen-route-data.mjs && tsc --noEmit && node scripts/check-frontmatter.mjs", "postinstall": "fumadocs-mdx", "preview": "opennextjs-cloudflare build && opennextjs-cloudflare preview", "deploy": "opennextjs-cloudflare build && opennextjs-cloudflare deploy", diff --git a/apps/docs/scripts/gen-route-data.mjs b/apps/docs/scripts/gen-route-data.mjs new file mode 100644 index 00000000..8f69feaa --- /dev/null +++ b/apps/docs/scripts/gen-route-data.mjs @@ -0,0 +1,203 @@ +#!/usr/bin/env node +/** + * Writes what the route handlers read instead of the compiled pages: + * `apps/docs/.route-data/` (#393, #395). + * + * ## Search text (#393) + * + * `/api/search` used to read each page's `structuredData` (its headings and + * paragraphs) through `page.data.load()`, which imports the page's compiled + * MDX module. That is the whole rendered page, highlighted code included, and + * a module once imported stays in the module registry for the life of the + * isolate. Building one locale's index therefore left every page module of + * that locale resident after the index was gone. Measured on the built route + * at `09784e7`, with only one index kept: 58 MB after English, 86 MB after all + * eight locales, about 94 MB with ja fully translated, against a Worker + * isolate's 128 MB. + * + * So the same `structuredData` is computed here and written as one module per + * locale, `search-.ts`, which `search.ts` maps to a lazy import. The + * route imports the locale it is asked for, unzips and parses it. + * + * ## The route handlers' collection (#395) + * + * Every page's compiled module was in the Worker twice. Turbopack compiles the + * page routes and the route handlers as two separate module graphs, and six + * route handlers (search, og, sitemap, `llms.txt`, `llms-full.txt`, + * `llms.mdx`) import `lib/source.ts`, whose collection holds a lazy + * `import()` of every page. A lazy import is still bundled, so the handlers' + * graph carried a second copy of all of them: 19,847 KiB of a 61,529 KiB + * upload with #388's PR 3 applied, which is what put that PR over the budget. + * Only the page route renders a page body, and only at build time. + * + * So `collection.ts` is the collection fumadocs-mdx writes to + * `.source/server.ts`, with every page's lazy body import replaced by a + * function that reads this directory instead. The frontmatter and `meta.json` + * imports are kept as they are, so the page tree, URLs and frontmatter are the + * ones `fumadocs-mdx` built. `lib/source.ts` builds its loader on it; the page + * route loads bodies from the full collection itself. + * + * What the handlers read from a body is the processed Markdown + * (`getText('processed')`, for the `llms` routes), and only for English pages: + * `/llms.mdx/docs/...` and `/llms-full.txt` serve English. That is + * `markdown.ts`. A translation's Markdown is read by the page route, from the + * module it already loaded. + * + * With `--dev`, `collection.ts` re-exports `.source/server.ts` instead: + * `next dev` regenerates that file when a page is added, and a copy taken at + * startup would not see the new page. + * + * ## How the text is made + * + * It is the same text, not a lookalike. The processor is fumadocs-mdx's own + * remark chain, built with the public `applyMdxPreset` from the compiled + * `source.config` (`.source/source.config.mjs`, written by the `fumadocs-mdx` + * CLI), plus `remarkInclude`, which `buildMDX` puts first, and `remarkLLMs`, + * which its postprocess step runs last for `includeProcessedMarkdown`. + * `remarkStructure` runs in the remark phase too, so the rehype plugins, which + * run after both and only shape the rendered HTML, are left out: that is + * `rehypeCode`, and it is most of the cost. + * + * Every string is JSON, gzipped, in base64 (`lib/packed.ts` unpacks it), + * because it is Worker upload too: as plain JSON the English, zh-Hans and + * zh-Hant search modules were about 1 MB each. + * + * A file's locale is its suffix, as `source.config.ts` reads it: `foo.ja.mdx` + * is `ja`, `foo.mdx` is the default language. A locale whose page falls back + * to English reads that page from the default language's module, so English + * text is written once. + * + * The output directory carries its own `.gitignore`, because it is a build + * product. Run from `apps/docs`, after `fumadocs-mdx`, as the `build`, + * `type-check` and `dev` scripts do. + */ +import { applyMdxPreset, remarkInclude } from 'fumadocs-mdx/config'; +import { frontmatter } from 'fumadocs-core/content/md/frontmatter'; +import { remarkLLMs } from 'fumadocs-core/mdx-plugins/remark-llms'; +import { createRequire } from 'node:module'; +import { existsSync, mkdirSync, readFileSync, readdirSync, rmSync, writeFileSync } from 'node:fs'; +import { dirname, join, relative, resolve } from 'node:path'; +import { fileURLToPath, pathToFileURL } from 'node:url'; +import { gzipSync } from 'node:zlib'; + +const APP = resolve(dirname(fileURLToPath(import.meta.url)), '..'); +const CONTENT = resolve(APP, '../../content/docs'); +const CONFIG = join(APP, '.source/source.config.mjs'); +const COLLECTION = join(APP, '.source/server.ts'); +const OUT = join(APP, '.route-data'); +const DEV = process.argv.includes('--dev'); + +/** `languages` and `defaultLanguage` out of `lib/i18n.ts`, read as text. Throws rather than guessing. */ +function readI18n() { + const text = readFileSync(join(APP, 'lib/i18n.ts'), 'utf8'); + const languages = /languages:\s*\[([^\]]+)\]/.exec(text)?.[1]?.split(',').map((s) => s.trim().replace(/['"]/g, '')).filter(Boolean) ?? []; + const defaultLanguage = /defaultLanguage:\s*['"]([^'"]+)['"]/.exec(text)?.[1]; + if (!languages.length || !languages.includes(defaultLanguage)) { + throw new Error('could not read languages[] and defaultLanguage out of apps/docs/lib/i18n.ts'); + } + return { languages, defaultLanguage }; +} + +function walk(dir) { + return readdirSync(dir, { withFileTypes: true }) + .flatMap((e) => (e.isDirectory() ? walk(join(dir, e.name)) : e.name.endsWith('.mdx') ? [join(dir, e.name)] : [])) + .sort(); +} + +/** + * `.source/server.ts` with each page's `() => import("…?collection=docs")` + * replaced by `() => body("")`. Throws unless every page's import was + * replaced and no other `import(` is left, so a change in what fumadocs-mdx + * writes fails the build here instead of putting the bodies back. + */ +function lightCollection(source, pages) { + const BODY = /("[^"]+\.mdx"): \(\) => import\("[^"]+\?collection=docs"\)/g; + const replaced = source.match(BODY)?.length ?? 0; + const light = source.replace(BODY, (_, key) => `${key}: () => body(${key})`); + const left = light.match(/\bimport\(\s*["'][^"']*\?collection=/g)?.length ?? 0; + if (replaced !== pages || left) { + throw new Error( + `.source/server.ts: replaced ${replaced} page body import(s) of ${pages} pages and ${left} are left. ` + + 'fumadocs-mdx changed what it writes; update lightCollection() in scripts/gen-route-data.mjs.', + ); + } + return `${light} +import { unpack } from '../lib/packed'; + +/** + * What a route handler reads from a page body (scripts/gen-route-data.mjs): the + * processed Markdown of an English page. The page route renders bodies from the + * full collection, so nothing else is asked for here. + */ +let markdown: Promise> | undefined; +async function body(file: string) { + markdown ??= import('./markdown').then((m) => unpack>(m.default)); + const text = (await markdown)[file]; + if (text === undefined) { + throw new Error(\`\${file}: the route handlers' collection has no body for it; only English pages' processed Markdown is generated (scripts/gen-route-data.mjs)\`); + } + return { _markdown: text }; +} +`; +} + +if (!existsSync(CONFIG) || !existsSync(COLLECTION)) { + console.error(`✗ route data: ${relative(process.cwd(), CONFIG)} or ${relative(process.cwd(), COLLECTION)} does not exist. Run \`fumadocs-mdx\` first.`); + process.exit(1); +} + +const { languages, defaultLanguage } = readI18n(); +// @mdx-js/mdx is fumadocs-mdx's dependency, not this app's, so it is resolved from there: the copy buildMDX uses. +const { createProcessor } = await import( + pathToFileURL(createRequire(import.meta.resolve('fumadocs-mdx')).resolve('@mdx-js/mdx')).href +); +const config = (await import(pathToFileURL(CONFIG).href)).default; +const mdx = await applyMdxPreset({ ...config.mdxOptions, rehypeCodeOptions: false })('bundler'); +const processor = createProcessor({ + outputFormat: 'program', + ...mdx, + remarkPlugins: [remarkInclude, ...(mdx.remarkPlugins ?? []), [remarkLLMs, { _data: true }]], + rehypePlugins: [], + format: 'mdx', +}); + +const search = new Map(languages.map((l) => [l, {}])); +const markdown = {}; +const files = walk(CONTENT); +for (const path of files) { + const file = relative(CONTENT, path).split('\\').join('/'); + const locale = languages.find((l) => l !== defaultLanguage && file.endsWith(`.${l}.mdx`)) ?? defaultLanguage; + const vfile = await processor.process({ + path, + value: frontmatter(readFileSync(path, 'utf8')).content, + data: { frontmatter: {}, _getProcessor: () => processor }, + }); + if (!vfile.data.structuredData) throw new Error(`${file}: remarkStructure wrote no structuredData`); + if (typeof vfile.data.markdown !== 'string') throw new Error(`${file}: remarkLLMs wrote no Markdown`); + search.get(locale)[file] = vfile.data.structuredData; + if (locale === defaultLanguage) markdown[file] = vfile.data.markdown; +} + +const banner = '// Generated by scripts/gen-route-data.mjs before every build. Do not edit.\n'; +const pack = (value) => gzipSync(JSON.stringify(value), { level: 9 }).toString('base64'); +const write = (name, text) => writeFileSync(join(OUT, name), `${banner}${text}`); + +rmSync(OUT, { recursive: true, force: true }); +mkdirSync(OUT, { recursive: true }); +writeFileSync(join(OUT, '.gitignore'), '*\n'); +for (const [locale, pages] of search) { + // A string, not an object literal: the route parses it when it builds the + // index, and the parsed copy is garbage once the index holds the text. + write(`search-${locale}.ts`, `export default ${JSON.stringify(pack(pages))};\n`); +} +const loaders = languages.map((l) => ` ${JSON.stringify(l)}: () => import(${JSON.stringify(`./search-${l}`)}),`).join('\n'); +write('search.ts', `/** Each locale's \`structuredData\`, keyed by file path under content/docs, packed (lib/packed.ts). */\nexport const searchData = {\n${loaders}\n} as const;\n`); +write('markdown.ts', `/** Each English page's processed Markdown, keyed by file path under content/docs, packed (lib/packed.ts). */\nexport default ${JSON.stringify(pack(markdown))};\n`); +write( + 'collection.ts', + DEV + ? "/** `next dev`: the full collection, which fumadocs-mdx keeps current as pages are added. */\nexport { docs } from '../.source/server';\n" + : lightCollection(readFileSync(COLLECTION, 'utf8'), files.length), +); +const sizes = [...search].map(([l, pages]) => `${l} ${Object.keys(pages).length}`).join(', '); +console.log(`✓ route data: wrote .route-data/${DEV ? ' for next dev' : ''} (pages per locale: ${sizes}; English Markdown: ${Object.keys(markdown).length})`); diff --git a/apps/docs/scripts/gen-search-data.mjs b/apps/docs/scripts/gen-search-data.mjs deleted file mode 100644 index 59c20e38..00000000 --- a/apps/docs/scripts/gen-search-data.mjs +++ /dev/null @@ -1,121 +0,0 @@ -#!/usr/bin/env node -/** - * Writes the text `/api/search` indexes, one module per locale (#393). - * - * The route used to read each page's `structuredData` (its headings and - * paragraphs) through `page.data.load()`, which imports the page's compiled - * MDX module. That is the whole rendered page, highlighted code included, and - * a module once imported stays in the module registry for the life of the - * isolate. Building one locale's index therefore left every page module of - * that locale resident after the index was gone. Measured on the built route - * at `09784e7`, with only one index kept: 58 MB after English, 86 MB after all - * eight locales, about 94 MB with ja fully translated, against a Worker - * isolate's 128 MB. - * - * So the same `structuredData` is computed here, before `next build`, and - * written as one string per locale to `.search/.ts`: the JSON, - * gzipped, in base64. The route imports the locale it is asked for, unzips and - * parses it. What stays resident is that string, not the page modules. - * - * Gzipped because the string is also Worker upload, which has a budget the - * `Worker bundle fits the size budget` CI step holds: as plain JSON the - * English, zh-Hans and zh-Hant modules were about 1 MB each, 3.5 MB of the - * 6 MB headroom main had at `09784e7`; gzipped and in base64, about a third. - * - * It is the same `structuredData`, not a lookalike. The processor is - * fumadocs-mdx's own remark chain, built with the public `applyMdxPreset` from - * the compiled `source.config` (`.source/source.config.mjs`, written by the - * `fumadocs-mdx` CLI), plus `remarkInclude`, which `buildMDX` puts first. - * `remarkStructure` runs in the remark phase, so the rehype plugins, which run - * after it and only shape the rendered HTML, are left out: that is - * `rehypeCode`, and it is most of the cost. - * - * A file's locale is its suffix, as `source.config.ts` reads it: `foo.ja.mdx` - * is `ja`, `foo.mdx` is the default language. A locale whose page falls back - * to English reads that page from the default language's module, so English - * text is written once. - * - * The output directory carries its own `.gitignore`, because it is a build - * product. Run from `apps/docs`, after `fumadocs-mdx`, as the `build`, - * `type-check` and `dev` scripts do. - */ -import { applyMdxPreset, remarkInclude } from 'fumadocs-mdx/config'; -import { frontmatter } from 'fumadocs-core/content/md/frontmatter'; -import { createRequire } from 'node:module'; -import { existsSync, mkdirSync, readFileSync, readdirSync, rmSync, writeFileSync } from 'node:fs'; -import { dirname, join, relative, resolve } from 'node:path'; -import { fileURLToPath, pathToFileURL } from 'node:url'; -import { gzipSync } from 'node:zlib'; - -const APP = resolve(dirname(fileURLToPath(import.meta.url)), '..'); -const CONTENT = resolve(APP, '../../content/docs'); -const CONFIG = join(APP, '.source/source.config.mjs'); -const OUT = join(APP, '.search'); - -/** `languages` and `defaultLanguage` out of `lib/i18n.ts`, read as text. Throws rather than guessing. */ -function readI18n() { - const text = readFileSync(join(APP, 'lib/i18n.ts'), 'utf8'); - const languages = /languages:\s*\[([^\]]+)\]/.exec(text)?.[1]?.split(',').map((s) => s.trim().replace(/['"]/g, '')).filter(Boolean) ?? []; - const defaultLanguage = /defaultLanguage:\s*['"]([^'"]+)['"]/.exec(text)?.[1]; - if (!languages.length || !languages.includes(defaultLanguage)) { - throw new Error('could not read languages[] and defaultLanguage out of apps/docs/lib/i18n.ts'); - } - return { languages, defaultLanguage }; -} - -function walk(dir) { - return readdirSync(dir, { withFileTypes: true }) - .flatMap((e) => (e.isDirectory() ? walk(join(dir, e.name)) : e.name.endsWith('.mdx') ? [join(dir, e.name)] : [])) - .sort(); -} - -if (!existsSync(CONFIG)) { - console.error(`✗ search data: ${relative(process.cwd(), CONFIG)} does not exist. Run \`fumadocs-mdx\` first.`); - process.exit(1); -} - -const { languages, defaultLanguage } = readI18n(); -// @mdx-js/mdx is fumadocs-mdx's dependency, not this app's, so it is resolved from there: the copy buildMDX uses. -const { createProcessor } = await import( - pathToFileURL(createRequire(import.meta.resolve('fumadocs-mdx')).resolve('@mdx-js/mdx')).href -); -const config = (await import(pathToFileURL(CONFIG).href)).default; -const mdx = await applyMdxPreset({ ...config.mdxOptions, rehypeCodeOptions: false })('bundler'); -const processor = createProcessor({ - outputFormat: 'program', - ...mdx, - remarkPlugins: [remarkInclude, ...(mdx.remarkPlugins ?? [])], - rehypePlugins: [], - format: 'mdx', -}); - -const byLocale = new Map(languages.map((l) => [l, {}])); -for (const path of walk(CONTENT)) { - const file = relative(CONTENT, path).split('\\').join('/'); - const locale = languages.find((l) => l !== defaultLanguage && file.endsWith(`.${l}.mdx`)) ?? defaultLanguage; - const vfile = await processor.process({ - path, - value: frontmatter(readFileSync(path, 'utf8')).content, - data: { frontmatter: {}, _getProcessor: () => processor }, - }); - if (!vfile.data.structuredData) throw new Error(`${file}: remarkStructure wrote no structuredData`); - byLocale.get(locale)[file] = vfile.data.structuredData; -} - -rmSync(OUT, { recursive: true, force: true }); -mkdirSync(OUT, { recursive: true }); -writeFileSync(join(OUT, '.gitignore'), '*\n'); -const banner = '// Generated by scripts/gen-search-data.mjs before every build. Do not edit.\n'; -for (const [locale, pages] of byLocale) { - // A string, not an object literal: the route parses it when it builds the - // index, and the parsed copy is garbage once the index holds the text. - const packed = gzipSync(JSON.stringify(pages), { level: 9 }).toString('base64'); - writeFileSync(join(OUT, `${locale}.ts`), `${banner}export default ${JSON.stringify(packed)};\n`); -} -const loaders = languages.map((l) => ` ${JSON.stringify(l)}: () => import(${JSON.stringify(`./${l}`)}),`).join('\n'); -writeFileSync( - join(OUT, 'index.ts'), - `${banner}/** Each locale's \`structuredData\`, keyed by file path under content/docs, as gzipped JSON in base64. */\nexport const searchData = {\n${loaders}\n} as const;\n`, -); -const sizes = [...byLocale].map(([l, pages]) => `${l} ${Object.keys(pages).length}`).join(', '); -console.log(`✓ search data: wrote .search/ (pages per locale: ${sizes})`); diff --git a/tools/ci-scripts/run-self-tests.mjs b/tools/ci-scripts/run-self-tests.mjs index fb1f15f6..ab995a5b 100644 --- a/tools/ci-scripts/run-self-tests.mjs +++ b/tools/ci-scripts/run-self-tests.mjs @@ -121,6 +121,13 @@ * Its fixtures are fake handlers and fake heap readings. They prove that a * failed request, a reading above the budget, and a heap still growing on the * second pass each go red. + * + * `check-worker-page-cost.mjs` is listed for its `--self-test` only (#395). Its + * gate mode reads the packaged Worker's metafile, so it runs inside `ci.yml`'s + * `Worker bundle fits the size budget` step. Its fixtures are fake metafiles: + * they prove the per-page cost and the pages left are computed from the + * costliest locale, and that a missing metafile or renamed page chunks fail + * rather than print nothing. */ import { readFileSync, readdirSync, existsSync } from 'node:fs'; @@ -145,6 +152,7 @@ const SELF_TESTED = [ 'check-positioning.mjs', 'check-search-locales.mjs', 'check-search-heap.mjs', + 'check-worker-page-cost.mjs', 'check-doc-samples.mjs', 'bump-upstream-pin.mjs', ]; From 8688a48b80aab0f729b1f7cf401016cbbec61931 Mon Sep 17 00:00:00 2001 From: Steedos Date: Thu, 29 Oct 2026 13:28:45 +0000 Subject: [PATCH 07/22] docs(i18n): translate configure/ into ja (#388, PR 3 of 7) Adds ja translations for the 14 configure/ pages: index, ai, api-access, authentication, data-sources, email, localization, mcp, notifications, runtime, storage, system-settings, users and webhooks. configure/ meta.ja.json already matches the English pages list. Same rules as the earlier batches: English heading ids, fences byte for byte, glossary ja column, UI labels in English, one line per paragraph, each page stamped. check-translations: ja 0 stale, 41 missing (was 55). Refs #388 Claude-Session: https://claude.ai/code/session_01QsR2jRsjbApbf83iyTDDXm Co-Authored-By: Claude --- content/docs/configure/ai.ja.mdx | 145 +++++++++++ content/docs/configure/api-access.ja.mdx | 134 ++++++++++ content/docs/configure/authentication.ja.mdx | 146 +++++++++++ content/docs/configure/data-sources.ja.mdx | 206 +++++++++++++++ content/docs/configure/email.ja.mdx | 57 +++++ content/docs/configure/index.ja.mdx | 74 ++++++ content/docs/configure/localization.ja.mdx | 52 ++++ content/docs/configure/mcp.ja.mdx | 235 ++++++++++++++++++ content/docs/configure/notifications.ja.mdx | 138 ++++++++++ content/docs/configure/runtime.ja.mdx | 67 +++++ content/docs/configure/storage.ja.mdx | 176 +++++++++++++ content/docs/configure/system-settings.ja.mdx | 95 +++++++ content/docs/configure/users.ja.mdx | 154 ++++++++++++ content/docs/configure/webhooks.ja.mdx | 80 ++++++ 14 files changed, 1759 insertions(+) create mode 100644 content/docs/configure/ai.ja.mdx create mode 100644 content/docs/configure/api-access.ja.mdx create mode 100644 content/docs/configure/authentication.ja.mdx create mode 100644 content/docs/configure/data-sources.ja.mdx create mode 100644 content/docs/configure/email.ja.mdx create mode 100644 content/docs/configure/index.ja.mdx create mode 100644 content/docs/configure/localization.ja.mdx create mode 100644 content/docs/configure/mcp.ja.mdx create mode 100644 content/docs/configure/notifications.ja.mdx create mode 100644 content/docs/configure/runtime.ja.mdx create mode 100644 content/docs/configure/storage.ja.mdx create mode 100644 content/docs/configure/system-settings.ja.mdx create mode 100644 content/docs/configure/users.ja.mdx create mode 100644 content/docs/configure/webhooks.ja.mdx diff --git a/content/docs/configure/ai.ja.mdx b/content/docs/configure/ai.ja.mdx new file mode 100644 index 00000000..4aa258ef --- /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 00000000..fc33fec9 --- /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 00000000..d1fc91fc --- /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 00000000..4e9cfd7a --- /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 00000000..d56fa397 --- /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 00000000..53076dbd --- /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 00000000..4c958c76 --- /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 00000000..34196ed3 --- /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 00000000..2aadd89c --- /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 00000000..23a4ca0f --- /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 00000000..b2715a4e --- /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 00000000..752d4c17 --- /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 00000000..5fe33ce4 --- /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 00000000..b03dc1fd --- /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 にシークレットを入れないでください(クエリ文字列はログに記録されます)。 +- 専用の受信側ホスト名を使うと、メインのアプリに影響を与えずに、エッジでそれをブロックして負荷を切り離せます。 +- ディスパッチャーの遅延を監視します。アウトボックスが増え続けているなら、たいていは受信側の性能が落ちています。 From 8fdcd289b7e52c12e9039084e72d6306b6c3edc5 Mon Sep 17 00:00:00 2001 From: Steedos Date: Thu, 29 Oct 2026 13:41:10 +0000 Subject: [PATCH 08/22] docs(i18n): translate configure/permissions/ and cloud/ into ja (#388, PR 4 of 7) Adds ja translations for the 7 configure/permissions/ pages (index, managing-access, permission-sets, positions, record-access, field-level-security, hierarchy-visibility) and the 8 cloud/ pages (organization, environments, plans-and-seats, ai-credits-and-limits, storage-and-limits, domains, apps, cloud-connection), plus a new cloud/meta.ja.json whose pages match the English. configure/permissions/ meta.ja.json already matched. Same rules as the earlier batches. check-translations: ja 0 stale, 26 missing (was 41). Refs #388 Claude-Session: https://claude.ai/code/session_01QsR2jRsjbApbf83iyTDDXm Co-Authored-By: Claude --- .../docs/cloud/ai-credits-and-limits.ja.mdx | 66 ++++++++ content/docs/cloud/apps.ja.mdx | 113 +++++++++++++ content/docs/cloud/cloud-connection.ja.mdx | 63 +++++++ content/docs/cloud/domains.ja.mdx | 68 ++++++++ content/docs/cloud/environments.ja.mdx | 87 ++++++++++ content/docs/cloud/meta.ja.json | 5 + content/docs/cloud/organization.ja.mdx | 73 ++++++++ content/docs/cloud/plans-and-seats.ja.mdx | 75 +++++++++ content/docs/cloud/storage-and-limits.ja.mdx | 61 +++++++ .../permissions/field-level-security.ja.mdx | 157 ++++++++++++++++++ .../permissions/hierarchy-visibility.ja.mdx | 106 ++++++++++++ .../docs/configure/permissions/index.ja.mdx | 141 ++++++++++++++++ .../permissions/managing-access.ja.mdx | 145 ++++++++++++++++ .../permissions/permission-sets.ja.mdx | 152 +++++++++++++++++ .../configure/permissions/positions.ja.mdx | 124 ++++++++++++++ .../permissions/record-access.ja.mdx | 104 ++++++++++++ 16 files changed, 1540 insertions(+) create mode 100644 content/docs/cloud/ai-credits-and-limits.ja.mdx create mode 100644 content/docs/cloud/apps.ja.mdx create mode 100644 content/docs/cloud/cloud-connection.ja.mdx create mode 100644 content/docs/cloud/domains.ja.mdx create mode 100644 content/docs/cloud/environments.ja.mdx create mode 100644 content/docs/cloud/meta.ja.json create mode 100644 content/docs/cloud/organization.ja.mdx create mode 100644 content/docs/cloud/plans-and-seats.ja.mdx create mode 100644 content/docs/cloud/storage-and-limits.ja.mdx create mode 100644 content/docs/configure/permissions/field-level-security.ja.mdx create mode 100644 content/docs/configure/permissions/hierarchy-visibility.ja.mdx create mode 100644 content/docs/configure/permissions/index.ja.mdx create mode 100644 content/docs/configure/permissions/managing-access.ja.mdx create mode 100644 content/docs/configure/permissions/permission-sets.ja.mdx create mode 100644 content/docs/configure/permissions/positions.ja.mdx create mode 100644 content/docs/configure/permissions/record-access.ja.mdx diff --git a/content/docs/cloud/ai-credits-and-limits.ja.mdx b/content/docs/cloud/ai-credits-and-limits.ja.mdx new file mode 100644 index 00000000..e26104b2 --- /dev/null +++ b/content/docs/cloud/ai-credits-and-limits.ja.mdx @@ -0,0 +1,66 @@ +--- +title: AI クレジットと上限 +seoTitle: "ObjectOS Cloud の AI 利用枠:週ごとの上限、ペース、クレジットパック" +description: ObjectOS Cloud で製品内 AI がどう計量されるか。構築と質問のための 1 つの利用枠、ローリングする週ごとの上限と 5 時間のペース、クレジットパック、各プランが使うモデル、そして拒否されたときのメッセージ。 +editions: [cloud, enterprise] +translation: + source_sha: 67429e9e53ae8850c44792b0659fead909aa7791fb06d24d6153d6be29182837 + guide_rev: 1 + mode: auto +--- + +ObjectOS Cloud では私たちが AI モデルを実行するので、製品内 AI([AI Builder](/docs/build/ai-builder) と、データについての質問に答えるアシスタント)は **AI 利用枠**を消費します。セルフマネージドの ObjectOS Enterprise のデプロイメントでは代わりに自分のモデルを用意し、このページの上限はどれも適用されません。[ObjectOS Enterprise の場合](#on-objectos-enterprise)を参照してください。 + +## すべての AI の作業に 1 つの利用枠 [#one-allowance-for-all-ai-work] + +アプリの構築、データについての質問、アシスタントを通じたアクションの実行は、すべて**同じ利用枠**を消費します。作業の種類ごとの別々の予算はありません。各リクエストは、モデルがそのために行う作業に比例して利用枠を消費し、プランで選択肢がある場合、より高性能なモデルはより多くを消費します。 + +利用枠は**環境**ごとに数えられます。クラウドコンソールの **Home** に、今週の利用枠をどれだけ使ったかが表示されます。 + +## 2 つのローリングウィンドウ [#two-rolling-windows] + +すべてのプランに同じ 2 つの上限があり、どちらも**ローリング**です。使用量は一定の時間だけ数えられた後に外れるので、余裕はカレンダーの日付ではなく、連続的に戻ってきます。[cloud#2059](https://github.com/objectstack-ai/cloud/issues/2059) で決定されました。 + +| ウィンドウ | 内容 | Free | Team 以上 | +|---|---|---|---| +| **7 日** | 予算:1 週間に収まる AI の作業量 | 環境ごとに週 1 回分の利用枠。厳格な上限です | AI シートごとのより大きな利用枠に、組織の AI シートの数を掛けたもの。[クレジットパック](#buy-ai-credits)で引き上げられます | +| **5 時間** | ペース:短い集中した利用に収まる量。暴走したセッション 1 つが 1 週間分を使い切れないようにします | 適用されますが、Free の週ごとの利用枠より上にあります | AI シートごとで、シートの数を掛けます。クレジットパックでは引き上げられません | + +ObjectOS Cloud が[パブリックプレビュー](/docs/editions/public-preview)の間は、利用枠の正確な大きさは公表されません。Free の利用枠は、最初の体験全体(アプリを構築し、何度か変更し、それでもまだ質問できる)に合わせた大きさです。 + +## 上限に達したとき [#when-a-limit-is-reached] + +リクエストは HTTP `429` で拒否され、チャットにはどの上限に達したか、いつ空くかを示すメッセージが表示されます。 + +| 状況 | コード | メッセージ | +|---|---|---| +| Free、週ごとの利用枠を使い切った | `AI_DESIGN_QUOTA_EXHAUSTED` | *You've used this week's free AI quota. It resets on DATE — upgrade to keep going.* | +| 有料、週ごとの利用枠を使い切った | `AI_ALLOWANCE_EXHAUSTED` | *Your AI allowance for this week is used up. It resets on DATE, or buy a credit pack to continue now.* | +| どのプランでも、5 時間のペースに達した | Free では `AI_DESIGN_QUOTA_EXHAUSTED`、有料プランでは `AI_ALLOWANCE_EXHAUSTED` | *You've hit the five-hour AI usage limit. It resets within five hours — then you're good to go.* | + +日付は、まだ数えられている最も古い使用量がウィンドウから外れる時点です。エラーの `details.resetsAt` は、同じ時点を ISO タイムスタンプで持っています。環境のほかのものには影響しません。アプリ、データ、連携は動き続けます。 + +## AI クレジットを購入する [#buy-ai-credits] + +有料プランでは、オーナーまたは管理者が、一回限りの **AI クレジットパック**で週ごとの利用枠を補充できます。環境の **Settings → Plan and billing** を開き、**AI credits** → **Buy AI Credits** を選びます。新しいタブで安全なチェックアウトが開きます。 + +- クレジットパックが引き上げるのは **7 日**の予算だけです。5 時間のペースはレート制限であり、購入で引き上げることはできません。 +- Free はクレジットパックを受け付けません。Free の週ごとの上限を超える方法は [Team へのアップグレード](/docs/cloud/plans-and-seats#upgrade)です。 +- 組織でクレジットパックがまだ販売されていない場合、ボタンはチェックアウトを開く代わりにそのことを伝えます。 + +## どのモデルが答えるか [#which-model-answers] + +すべてのプランは**同じデフォルトのモデル**で答えます。有料プランが Free と違うのは利用枠の大きさであって、より強力なモデルではありません。有料の環境でモデルの選択肢が提供されている場合は、AI チャットで選べます。より高性能なモデルは利用枠をより早く減らします。 + +## 自分のクライアントを通じた AI はここでは計量されない [#ai-through-your-own-client-is-not-metered-here] + +[MCP](/docs/configure/mcp) で接続するエージェント(Claude Code、Cursor など)は、**あなたの**モデルとあなた自身のトークンで動きます。AI 利用枠は消費しません。その制限となるのは、環境の MCP リクエストの上限です([ストレージと上限](/docs/cloud/storage-and-limits#mcp-limits))。 + +## ObjectOS Enterprise の場合 [#on-objectos-enterprise] + +セルフマネージドの Enterprise のデプロイメントは、[AI サービス](/docs/configure/ai)で設定する独自のモデルとキーを用意し、モデルのプロバイダーに直接支払います。プラットフォームの AI クレジットも、利用枠も、計量もありません。AI シートごとの料金はライセンスであって、使用量のパッケージではありません。デプロイメントがどれだけの AI の作業をするかは、自分のプロバイダーのアカウントによってのみ制限されます。 + +## 次へ [#next] + +- [プランと AI シート](/docs/cloud/plans-and-seats):各プランに含まれるもの。 +- [AI Builder](/docs/build/ai-builder):AI が構築できるもの。 diff --git a/content/docs/cloud/apps.ja.mdx b/content/docs/cloud/apps.ja.mdx new file mode 100644 index 00000000..8ff87dce --- /dev/null +++ b/content/docs/cloud/apps.ja.mdx @@ -0,0 +1,113 @@ +--- +title: アプリ +seoTitle: "ObjectOS Cloud のアプリ:インストール、更新、公開、CLI からのデプロイ" +description: ObjectOS Cloud の環境にアプリをインストールし、更新を確認し、環境のアプリを組織向けのパッケージとして公開し、ローカルでビルドしたアプリを os CLI からデプロイします。 +editions: [cloud] +translation: + source_sha: 0adc0c246817f68e5c28824736e064a5591eadd4b69aa953dd25f91a3c85a4a0 + guide_rev: 1 + mode: auto +--- + +アプリが ObjectOS Cloud の環境に届く方法は 3 つあります。マーケットプレイスまたは組織のレジストリから**インストール**する、環境の中で([AI Builder](/docs/build/ai-builder) を使うか手作業で)**構築**する、または自分のマシンから `os` CLI で**公開**する、のいずれかです。どの方法でも、インストールされるのは[パッケージ](/docs/build/packages)、つまりオブジェクト、ビュー、フローなどをまとめたバージョン付きのバンドルです。 + +## アプリをインストールする [#install-an-app] + +クラウドコンソールで環境の **Settings → Apps** を開き、**Install an app**(**Install Application**)を選びます。アプリを選んでから、次を設定します。 + +- **Include sample data**:パッケージのデモレコードで環境を埋め、すぐに試せるようにします。クリーンな本番環境ではチェックを外したままにします。 +- **Accept additional permissions**:初回のインストールではチェックを外したままにします。これは、以前に付与された権限より多くの権限を求める更新のためのものです([更新を確認する](#check-for-updates)を参照)。 + +アプリは再起動なしで、環境への次のリクエストから表示されます。インストール後のメッセージには、どのように反映されたか(インストール、再インストール、更新、ロールバックのいずれかと、そのバージョン)と、知っておくべきこと(アプリが使う機能のうちプランに含まれないものなど)が表示されます。 + +環境の中からインストールすることもできます。環境の **Marketplace** を開き、アプリを見つけて **Install** を選びます。どちらの方法でも、同じパッケージが同じ環境にインストールされます。[マーケットプレイス](/docs/build/marketplace)を参照してください。 + +インストールは組織のオーナーと管理者が行います。 + +## 更新を確認する [#check-for-updates] + +**Settings → Apps → Check for app updates** は、インストール済みの各アプリを公開されている最新バージョンと比較し、更新があるか、すべてのアプリが最新か、まだ何もインストールされていないかを表示します。 + +アプリを更新するには、もう一度インストールします。すでにインストールされているアプリをインストールすると、その場で公開済みの最新バージョンに移行します。 + +新しいバージョンが、アプリに以前付与されていなかった権限を求める場合、更新は `PERMISSION_RECONSENT_REQUIRED` で拒否され、メッセージに追加される各権限が一覧表示されます。内容を確認してから、**Accept additional permissions** にチェックを入れてもう一度インストールし、権限を付与します。 + +## 環境をパッケージとして公開する [#publish-an-environment-as-a-package] + +**Settings → Apps → Publish as a package**(**Publish to Registry**)は、この環境で構築したアプリを、組織のレジストリにあるパッケージの新しいバージョンとして公開します。そこから組織の他のどの環境にもインストールできます。開発環境で構築したアプリは、この方法で本番環境に届きます。 + +| フィールド | 意味 | +|---|---| +| **App Name** | レジストリに表示される名前。デフォルトは環境の名前です。 | +| **Version** | `1.2.0` のようなセマンティックバージョン。空欄のままにすると、最新バージョンの次のパッチとして公開されます。 | +| **Visibility** | **Private**:自分の組織だけがインストールできます。**Organization**:組織全体で共有されます。 | +| **Description** | アプリ全体として何をするか。 | +| **Release notes** | このバージョンでの変更点。バージョンとともに表示されます。 | +| **Package ID**(詳細設定) | 逆ドメイン形式の識別子。空欄の場合は環境の名前から導出されます。 | + +公開マーケットプレイスへの掲載は、審査を伴う別の手順であり、ここでは提供されません。サイドバーの **Advanced → Packages** に、組織が公開したものがすべて一覧表示されます。 + +## CLI からデプロイする [#deploy-from-the-cli] + +アプリをコードとして(自分のマシン上の ObjectStack プロジェクトとして)開発している場合、`os` CLI でそれを組織に公開し、環境にインストールできます。流れは **ログイン → ビルド → 公開 → インストール** です。 + +必要なものは、ObjectStack プロジェクト([Path B — `os init`](/docs/start/community#path-b--os-init-developer) を参照)、`os` CLI、そして環境を持つ ObjectOS Cloud アカウントです。 + +### 1. ログイン [#1-log-in] + +```bash +os cloud login +``` + +これはブラウザのサインインを開き、クラウドトークンを `~/.objectstack/cloud.json` に保存します。サインインリンクを開く代わりに表示するには `--no-browser` を使います。CI ではログインを省略し、`--token` または `OS_CLOUD_API_KEY` 変数で `os package publish` に API キーを渡します。 + +クラウドログインは、ランタイムにサインインする `os login` とは別のものです。公開には常にクラウドログインが使われます。 + +### 2. ビルド [#2-build] + +```bash +os build +``` + +これはプロジェクトをひとつのアーティファクト `dist/objectstack.json` にコンパイルします。オブジェクト、ビュー、アプリ、ダッシュボード、フロー、サンプルデータが含まれます。後でアップロードされるのはこのアーティファクトだけで、ソースファイル、`node_modules`、ローカルの認証情報がアップロードされることはありません。 + +### 3. 公開 [#3-publish] + +```bash +os package publish +``` + +プロジェクトのルートで実行します。パッケージを組織に登録し(初回のみ。`com.acme.crm` のような逆ドメイン形式のパッケージ id をキーとします)、アーティファクトを新しい不変のバージョンとして公開します。同じバージョンを 2 回公開することはできません。`manifest.version` を上げるか、`--version` を渡します。 + +| フラグ | 目的 | +|---|---| +| `--manifest-id ` | 逆ドメイン形式のパッケージ id。デフォルト:アーティファクトから導出 | +| `--version ` | 公開するバージョン。デフォルト:`manifest.version` | +| `--visibility ` | 誰が表示・インストールできるか。ObjectOS Cloud では新しいパッケージのデフォルトは `org` です。既存のパッケージの公開範囲を維持するにはフラグを省略します | +| `--install` | 新しいバージョンをすぐに環境にインストールします | +| `--env ` | `--install` の対象環境。デフォルト:`os environments switch` で選択した環境 | +| `--seed-sample-data` | インストール時にアーティファクトのサンプルデータを含めます | +| `--note ""` | リリースノート | +| `--submit` | `marketplace` パッケージの新しいバージョンを審査に提出します | + +### 4. インストール [#4-install] + +利用者は環境からインストールします。環境の **Marketplace** を開き、パッケージを見つけて **Install** を選ぶか、[前述](#install-an-app)のクラウドコンソールの **Install an app** を使います。 + +既知の環境にデプロイするパイプラインは、ひとつのコマンドで公開とインストールを行えます。 + +```bash +os package publish --env --install --seed-sample-data +``` + +これは全か無かです。インストールが拒否された場合(その環境にインストールできない、環境が存在しない、またはそのバージョンがその環境で承認されていない)、何も公開されません。コマンドは拒否内容を表示してゼロ以外で終了するため、パイプラインは失敗します。原因を修正し、同じバージョンをもう一度公開してください。 + +### マーケットプレイスへの掲載 [#marketplace-listings] + +`--visibility marketplace` はパッケージを公開カタログの対象にしますが、新しいバージョンはそれぞれ**下書き**として届きます。審査に送るには `--submit` を渡します。プライベートと組織のパッケージは審査が不要で、組織はすぐにインストールできます。 + +## 次へ [#next] + +- [パッケージ](/docs/build/packages):パッケージに含まれるものと、バージョンの仕組み。 +- [マーケットプレイス](/docs/build/marketplace):環境の中からの閲覧とインストール。 +- [CLI リファレンス](/docs/reference/cli):すべての `os` コマンド。 diff --git a/content/docs/cloud/cloud-connection.ja.mdx b/content/docs/cloud/cloud-connection.ja.mdx new file mode 100644 index 00000000..0956e771 --- /dev/null +++ b/content/docs/cloud/cloud-connection.ja.mdx @@ -0,0 +1,63 @@ +--- +title: クラウド接続 +seoTitle: "セルフホストの ObjectOS サーバーを ObjectOS Cloud の組織に接続する" +description: セルフホストの ObjectOS Community または Enterprise サーバーをワンタイムコードで ObjectOS Cloud の組織にリンクし、その Marketplace に組織のパッケージを表示します。取り消しや切断で何が失われるかも説明します。 +editions: [community, cloud, enterprise] +translation: + source_sha: f32aef27f0099041cbdc82e55e1d2ab1c2b73289b0b3f87ca5cc8e9b0af6ca26 + guide_rev: 1 + mode: auto +--- + +セルフホストの ObjectOS サーバー(Community または Enterprise)は、ObjectOS Cloud の組織に接続できます。接続すると、サーバーの **Marketplace** に公開パッケージと並んで組織自身のパッケージが表示され、サーバー自身の認証情報でそれらをインストールします。接続はサーバー側で開始し、クラウド側でワンタイムコードを使って承認します。サーバーに何かを入力する必要はありません。 + +接続には 2 つの側面があり、このページは両方を扱います。 + +- **サーバー側**(Community、Enterprise):接続の開始と切断。前提条件、サーバーが保存するもの、パネルに表示されうるすべてのメッセージを含むサーバー側の完全なリファレンスは、[objectstack.ai の Cloud Connection](https://objectstack.ai/docs/deployment/cloud-connection) にあります。 +- **クラウドの組織側**(Cloud):リクエストの承認と、**Advanced → Connected Runtimes** での接続済みサーバーの管理。 + +## 接続で得られるもの [#what-connecting-gives-you] + +- **サーバーの Marketplace に表示される組織のパッケージ**:"Your organization" の下に、[公開](/docs/cloud/apps#publish-an-environment-as-a-package)したプライベートおよび組織のパッケージが表示され、サーバー自身の認証情報で閲覧・インストールされます。 +- **組織内の登録**:Connected Runtimes に一覧表示され、サーバーの名前とバージョン、承認したアカウント、接続日時と最終使用日時が示されます。 + +接続が**不要な**こと:公開マーケットプレイスの閲覧と公開パッケージのインストールは、接続していないサーバーでも動作します。また、コンパイル済みのアーティファクトからのインストールはクラウドを一切呼び出しません。 + +## 接続する [#connect] + +1. **サーバー側で**、**Manage Platform Settings** 権限を持つユーザーとしてサインインし、**Setup → Integrations → Cloud Connection** を開きます。**Connect** を選びます。 +2. サーバーはクラウドにワンタイムコードを要求し、新しいウィンドウで承認ページを開きます。コードはサーバーのページにも表示されます。 +3. **クラウド側で**、サーバーが参加すべき組織の ObjectOS Cloud アカウントにサインインし、コードが一致することを確認して承認します。 +4. サーバーは自動的に完了します。ページが **Connected to ObjectStack Cloud** に変わり、ランタイム、組織、承認したアカウント、日時が表示されます。 + +時間内に誰も承認しないとコードは期限切れになります。**Connect** からやり直してください。 + +**承認できる人。** ロールにかかわらず、組織のどのメンバーでも承認できます。サーバーは承認者の**アクティブな**組織に参加します。複数の組織に所属している場合は、承認する前にクラウドコンソールで正しい組織に切り替えてください。 + +サーバーにはクラウドへのアウトバウンド HTTPS が必要で、作業ディレクトリは永続ストレージでなければなりません。接続はそこにファイルとして保持されます。ObjectOS Cloud 自体がホストするサーバーはプラットフォームによって接続されるため、Cloud Connection ページはありません。 + +## クラウドで接続済みサーバーを管理する [#manage-connected-servers-in-the-cloud] + +クラウドコンソールの **Advanced → Connected Runtimes** には、組織に接続されたすべてのサーバーが、名前、ランタイムのバージョン、承認したアカウント、ステータス、接続日時、最終使用日時とともに一覧表示されます。各行には次の操作があります。 + +| 操作 | 内容 | +|---|---| +| **Rename** | ここと承認ページに表示される名前を変更します。 | +| **Revoke** | サーバーを即座に切り離します。認証情報が機能しなくなるため、再び承認されるまで、そのサーバー上での組織のパッケージの閲覧、インストール、更新は失敗します。サーバーにすでにインストールされているアプリは動作し続けます。 | +| **Remove** | もう接続されていないサーバー向け:その行を削除します。サーバーはいつでも新しいデバイスとして再接続できます。 | + +## サーバーから切断する [#disconnect-from-the-server] + +サーバーの **Cloud Connection** ページで **Disconnect** を選びます。サーバーはクラウドに接続の取り消しを依頼し、結果にかかわらず認証情報を削除します。その Marketplace には組織のパッケージが表示されなくなります。 + +切断しても、次の 2 つは保持されます。 + +- **インストール済みのすべて。** サーバーにすでにインストールされているパッケージは、インストールされたまま動作し続けます。 +- **サーバーのランタイム id。** 再接続すると、新しい行を追加するのではなく、Connected Runtimes の同じ行に紐づきます。 + +切断時にクラウドに到達できなかった場合でも、サーバーは認証情報を破棄しますが、クラウドには通知されていません。Connected Runtimes を確認し、そこで該当の行を **Revoke** してください。 + +## 次へ [#next] + +- [マーケットプレイス](/docs/build/marketplace):任意のサーバーへのアプリのインストール。 +- [アプリ](/docs/cloud/apps):組織向けのパッケージの公開。 diff --git a/content/docs/cloud/domains.ja.mdx b/content/docs/cloud/domains.ja.mdx new file mode 100644 index 00000000..a45990d0 --- /dev/null +++ b/content/docs/cloud/domains.ja.mdx @@ -0,0 +1,68 @@ +--- +title: ドメイン +seoTitle: "ObjectOS Cloud のドメイン:プラットフォームのサブドメインと独自のドメイン" +description: すべての ObjectOS Cloud のプランにはブランド付きのプラットフォームのサブドメインが含まれます。Team 以上では、TXT レコードで所有を証明し、証明書が発行される独自のドメインを本番環境に追加できます。 +editions: [cloud] +translation: + source_sha: e09fb1bee012ece2c40eb7165542858668830bbe291102a95f4b038ffa7c7e77 + guide_rev: 1 + mode: auto +--- + +ObjectOS Cloud の環境には、2 種類のアドレスでアクセスできます。 + +| | **プラットフォームのサブドメイン** | **独自のドメイン** | +|---|---|---| +| 見た目 | プラットフォームのドメイン上の `acme` | `app.acme.com` | +| プラン | Free を含むすべてのプラン | Team 以上 | +| 環境 | 本番。開発環境は固定のアドレスのまま | 本番のみ | +| 数 | いくつでも追加できます | Team では本番環境ごとに 1 つ。契約によりそれ以上 | +| 証明書 | プラットフォーム自身のものでカバーされます | 所有が証明されると発行されます | + +このページのルールは、[cloud#1087](https://github.com/objectstack-ai/cloud/issues/1087)(プラットフォームのサブドメインはすべてのプランで無料)と [cloud#2136](https://github.com/objectstack-ai/cloud/issues/2136)(独自のドメイン)で決定されました。 + +## プラットフォームのサブドメイン [#platform-subdomains] + +本番環境のアドレスは、プラットフォームのドメイン上の組織の[スラッグ](/docs/cloud/organization#the-organization-slug)です。これはすべてのプランで無料で、自分で選ぶほかのブランド付きのラベルも同じく無料です。 + +変更するには、環境の **Settings → Name and domain** を開き、**Change Hostname** を選びます。ラベルだけを入力します。プラットフォームのドメインは自動で付きます。ラベルは 4〜63 文字の小文字、数字、ダッシュで、両端にダッシュは使えず、2 つ続けることもできません。いくつかの予約語は拒否されます。組織のスラッグで始まる必要はありません。 + +最初のものを置き換えるのではなく 2 つ目のプラットフォームのサブドメインを追加するには、同じセクションの **Add Domain** を使います。環境の **Overview** に表示されるアドレスが、人に伝えるべきアドレスです。 + +## 独自のドメイン [#your-own-domain] + +**Team** 以上では、本番環境は、`app.acme.com` のような、所有するドメインのサブドメインでも応答できます。 + +1. **追加します。** **Settings → Name and domain** で **Add Domain**(または **Change Hostname**)を選び、完全なホスト名を入力します。サブドメイン(少なくとも 3 つのラベル)でなければなりません。`acme.com` のようなルートドメインは拒否されます。`www.acme.com` などのサブドメインを使ってください。 +2. **所有を証明します。** ドメインは **Pending Verification** として作成され、コンソールに公開すべき TXT レコードが表示されます。名前は `_objectos-challenge.` で、値はこのドメインに固有のものです。ホスト名が向けるべき CNAME のターゲットも表示されます。 +3. **確認します。** TXT レコードを公開したら、ドメインで **Verify DNS** を選びます。ObjectOS Cloud はレコードを確認し、それから証明書を要求します。ドメインは **Verified** と **Provisioning Certificate** を経て **Active** になります。途中のステップで止まった場合は、もう一度 **Verify DNS** を選んで先に進めます。 +4. **プライマリにします**(省略可能)。**Set as Primary** は、サインインのリダイレクト、メールのリンク、共有リンクがどのアドレスを使うかを決めます。プラットフォームのサブドメインも並んで機能し続けます。 + +セッションは 1 つのアドレスに属します。プラットフォームのサブドメインと独自のドメインを切り替えると、もう一度サインインすることになります。 + +### うまくいかないとき [#when-something-goes-wrong] + +| 表示されるもの | 理由と対処 | +|---|---| +| `403 CUSTOM_DOMAIN_PLAN_LOCKED` | 組織が Free です。Team にアップグレードしてください。 | +| `403 DEV_ENV_DOMAIN_LOCKED` | これは開発環境です。ドメインは本番環境に追加してください。 | +| www またはサブドメインを求める `400 INVALID_FORMAT` | ルートドメインを入力しました。`www.acme.com` のようなサブドメインを使ってください。 | +| `403 CONTACT_SALES_PLAN` | 環境はすでに 1 つのドメインを持っています。複数持つには Enterprise の契約が必要です。 | +| `409 DUPLICATE_VALUE` | 別の環境がすでにそのホスト名を提供しています。 | +| 確認の応答が、TXT レコードがまだ見えないと言う | DNS が伝播していないか、レコードの名前または値が異なります。応答には期待されるレコードが繰り返し示されます。 | +| **Failed** | 証明書を発行できませんでした。CNAME を確認し、もう一度 **Verify DNS** を選んでください。まず所有を証明し直します。 | + +### ダウングレードとアップグレード [#downgrade-and-upgrade] + +ダウングレードは独自のドメインを**一時停止**します。決して解放はしません。ドメインは **Suspended** になって提供を止め、証明書は取り下げられますが、レコードは残ります。それがプライマリだった場合、リンクは影響を受けないプラットフォームのサブドメインにフォールバックします。後でアップグレードすると、CNAME がまだ私たちを向いていれば、ドメインは自動的に再プロビジョニングされます。「N 日後に解放」というものはありません。 + +一時停止されたドメインが、そのホスト名の所有を証明できるほかの誰かを妨げることはありません。別の環境がそれを証明すれば、一時停止されていた主張は放棄されます。 + +### ドメインを削除する [#removing-a-domain] + +ドメインの **Delete** は提供を止め、ホスト名を解放します。環境を完全に削除すると、そのすべてのドメインもあわせて削除されます。 + +## 次へ [#next] + +- [環境](/docs/cloud/environments):本番と開発。 +- [プランと AI シート](/docs/cloud/plans-and-seats):Team が追加するもの。 diff --git a/content/docs/cloud/environments.ja.mdx b/content/docs/cloud/environments.ja.mdx new file mode 100644 index 00000000..c58768a3 --- /dev/null +++ b/content/docs/cloud/environments.ja.mdx @@ -0,0 +1,87 @@ +--- +title: 環境 +seoTitle: "ObjectOS Cloud の環境:本番、開発、ライフサイクル" +description: ObjectOS Cloud の本番環境と開発環境。プランごとに誰がどれを得るか、環境の作成、そして一時停止、アーカイブ、復元、削除がそれぞれデータに何をするか。 +editions: [cloud] +translation: + source_sha: 697f7e55052fc9b88c5feb928caad9c8197a04cc0f52c2e514abe2b95c4995b6 + guide_rev: 1 + mode: auto +--- + +**環境**は、独自のデータベース、ファイル、アプリ、アドレスを持つ、ObjectOS の稼働中のコピー 1 つです。組織のアプリは環境の中にあり、チームはそれを使うために環境にサインインします。ObjectOS Cloud には 2 種類があります。 + +| | **本番** | **開発** | +|---|---|---| +| 数 | どのプランでも、組織ごとにちょうど 1 つ | 有料プランのみ:2 つに加えて AI シートごとに 1 つ。組織全体で共有されます | +| アドレス | プラットフォームのドメイン上の組織のスラッグ。[独自のドメイン](/docs/cloud/domains)を付けられます | プラットフォームが割り当てる `dev-` という形式の固定のアドレス。ブランド付きのサブドメインや独自のドメインには決してなりません | +| アイドル | 非アクティブによるアーカイブは決してされません | 使われないまま 7 日経つと自動的にアーカイブされます | +| 用途 | チームが使うアプリ | 変更が本番に届く前に構築して試す | + +組織が作成する**最初の**環境が本番環境で、それ以降のすべてが開発環境です。 + +## 誰がどれを得るか [#who-gets-which] + +**Free:本番環境が 1 つだけで、ほかには何もありません。** 本番で直接構築します。2 つ目の環境の作成は `403 DEV_ENV_PLAN_LOCKED` で拒否され、コンソールは代わりにアップグレードを提示します。 + +**Team 以上:本番に加えて開発環境のプール。** プールは開発環境 2 つに加えて、組織が支払う AI シートごとに 1 つで、組織全体で数えられます。開発環境はシートの料金に含まれており、請求書に行が追加されることは決してありません。有料プランでの通常の流れは、開発環境で構築し、[パッケージとして公開](/docs/cloud/apps#publish-an-environment-as-a-package)して、そのパッケージを本番にインストールすることです。 + +そもそも開発環境が存在するかどうかはプランが決めます([cloud#1252](https://github.com/objectstack-ai/cloud/issues/1252) で決定)。1 つの本番環境はどのプランでも同じです。 + +## 環境を作成する [#create-an-environment] + +**Environments** で **Create Environment** を選び、名前を付けます。アドレスはプラットフォームが割り当てます。本番環境のアドレスは後から **Change Hostname**([ドメイン](/docs/cloud/domains))で変更できます。開発環境は、与えられた固定のアドレスのままです。新しい環境は **Provisioning** で始まり、データベースの準備ができると **Active** になります。 + +環境に入るには **Open** を選びます。新しいタブで環境自身のコンソールが、あなたとしてサインインした状態で開きます。 + +## 環境のページ [#the-environment-page] + +各環境には、2 つのタブを持つページがあります。 + +- **Overview**:アドレス、ステータス、プランと種類、インストールされているアプリ、アクセスの設定。折りたたまれた **Features that need a higher plan** の行は、現在のプランに含まれていないものを数え、開くとその一覧を表示します。 +- **Settings**:すべてのアクションが 5 つのセクションにあります。**Apps**、**Plan and billing**、**Name and domain**、**Access and sign-in**([AI エージェントのアクセス](/docs/configure/mcp#on-objectos-cloud)を含む)、**Lifecycle and danger zone** です。 + +環境を変更するアクションは、組織のオーナーと管理者に提示されます。 + +## ライフサイクル [#lifecycle] + +| 状態 | 意味 | データ | +|---|---|---| +| **Active** | リクエストを処理しています | — | +| **Suspended** | 再開するまで、ランタイムへのすべてのトラフィックがブロックされます | 保持されます | +| **Archived** | アクティブな表示から外され、訪問されても起動しなくなります | 保持期間が終わるまで保持され、その後削除されます | +| **Failed** | プロビジョニングが完了しませんでした | 何も作成されていません | + +**一時停止と再開。** 一時停止すると、人からも連携からも、環境へのすべてのリクエストがブロックされます。何も削除されず、**Resume** で元どおりに戻ります。 + +**アーカイブと復元。** アーカイブすると、環境は使われなくなり、その保持期間のカウントが始まります。**Restore** はその期間内に環境を戻し、次の訪問で再び起動します。 + +**削除。** 削除は 2 段階の操作なので、1 回のクリックでデータが失われることは決してありません。 + +1. まだアーカイブされていない環境は、完全な削除を求めた場合でも**アーカイブ**されます。 +2. **アーカイブ済み**の環境を、**Delete permanently if already archived** にチェックを入れて削除すると、そのデータベースとすべてのファイルが一度に破棄され、復旧はできません。 + +本番環境を削除するときは、さらに **Force-delete the production environment** にチェックを入れるよう求められます。プロビジョニングに失敗した環境はデータを持たないので、即座に削除されます。 + +### アーカイブされた環境がどれだけ保持されるか [#how-long-an-archived-environment-is-kept] + +| アーカイブのされ方 | 保持期間 | +|---|---| +| あなたによる(**Archive**、または **Delete** の第 1 段階) | 少なくとも 30 日。Business では 90 日、Enterprise では 1 年 | +| 自動的に、7 日間アイドルだった開発環境 | プランの期間:Team では 30 日、Business では 90 日、Enterprise では 1 年 | + +アーカイブされた環境が削除される少し前に環境のオーナーに警告が届くので、復元する時間があります。期間を過ぎると、データベース、ファイル、ドメインとともに完全に削除されます。 + +### アイドル状態の開発環境 [#idle-development-environments] + +**7 日間**誰も訪問も構築もしていない開発環境は、自動的にアーカイブされます。環境を使うことと、その中で開発すること(公開、インストール、パッケージの編集)の両方がアクティビティとして数えられます。本番環境がこの方法でアーカイブされることは決してありません。 + +### Free へのダウングレード後 [#after-a-downgrade-to-free] + +ダウングレードはさかのぼって適用されません。組織がすでに動かしている開発環境は**動き続けます**。ダウングレードによって一時停止やアーカイブされることはありません。Free が拒否するのは*追加*です。開発環境の作成や、アーカイブされた開発環境の復元は、組織が再びアップグレードするまで `403 DEV_ENV_PLAN_LOCKED` で応答します。アーカイブされた開発環境は、その後 Free の期間である 7 日間保持されます([cloud#2253](https://github.com/objectstack-ai/cloud/issues/2253) と [cloud#2204](https://github.com/objectstack-ai/cloud/issues/2204) で決定)。 + +## 次へ [#next] + +- [プランと AI シート](/docs/cloud/plans-and-seats):有料プランが追加するもの。 +- [ストレージと上限](/docs/cloud/storage-and-limits):環境ごとのストレージの割り当て。 +- [アプリ](/docs/cloud/apps):環境でアプリをインストール、更新、公開する。 diff --git a/content/docs/cloud/meta.ja.json b/content/docs/cloud/meta.ja.json new file mode 100644 index 00000000..1f134b75 --- /dev/null +++ b/content/docs/cloud/meta.ja.json @@ -0,0 +1,5 @@ +{ + "title": "Cloud 組織", + "defaultOpen": false, + "pages": ["organization", "environments", "plans-and-seats", "ai-credits-and-limits", "storage-and-limits", "domains", "apps", "cloud-connection"] +} diff --git a/content/docs/cloud/organization.ja.mdx b/content/docs/cloud/organization.ja.mdx new file mode 100644 index 00000000..72ae0d3e --- /dev/null +++ b/content/docs/cloud/organization.ja.mdx @@ -0,0 +1,73 @@ +--- +title: 組織とメンバー +seoTitle: "ObjectOS Cloud の組織:スラッグ、メンバー、招待、ロール" +description: ObjectOS Cloud の組織。そのスラッグ、クラウドコンソール、メンバーの招待、5 つのメンバーシップのロール、そしてサインインが環境ではなくクラウドにある理由。 +editions: [cloud] +translation: + source_sha: 45e832e16685da44f31911d619138580836770640112ee1300fc5cc35796ac0d + guide_rev: 1 + mode: auto +--- + +ObjectOS Cloud では、所有するものはすべて**組織**に属します。環境、アプリとパッケージ、プラン、メンバーです。組織はサインアップ時に作成し([ObjectOS Cloud で始める](/docs/start/cloud))、[cloud.objectos.ai](https://cloud.objectos.ai) の**クラウドコンソール**で管理します。 + +## クラウドコンソール [#the-cloud-console] + +コンソールのサイドバーが、このセクションの地図です。 + +| サイドバーの項目 | 中身 | ページ | +|---|---|---| +| **Home** | 組織の概要:本番環境、アプリ、メンバー、今週の AI 利用枠 | — | +| **Environments** | すべての環境と、その設定とライフサイクル | [環境](/docs/cloud/environments) | +| **Members** | 組織の人と、保留中の招待 | このページ | +| **Billing** | プランの比較とアップグレード | [プランと AI シート](/docs/cloud/plans-and-seats) | +| **Advanced → Connected Runtimes** | この組織にリンクされたセルフホストのサーバー | [クラウド接続](/docs/cloud/cloud-connection) | +| **Advanced → Packages** | 組織が公開したパッケージ | [アプリ](/docs/cloud/apps) | + +各環境にも、その環境自身のアドレスに独自のコンソールがあります。チームがアプリを使うのはそこで、クラウドコンソールはそれらを取り巻く組織を管理する場所です。 + +## 組織のスラッグ [#the-organization-slug] + +**スラッグ**は組織の短い識別子で、サインアップ時に選びます。本番環境のアドレスでもあり、スラッグの後にプラットフォームのドメインが続きます。 + +- 4〜30 文字:小文字、数字、ダッシュ。 +- 先頭と末尾にダッシュは使えず、ダッシュを 2 つ続けることもできません。 +- 予約語の短いリストは拒否されます(`admin`、`api`、`www`、`docs`、`default` など、プラットフォーム自身が使うもの)。 + +オーナーまたは管理者は、組織のレコードの **Change Slug** でスラッグを変更できます。変更は 90 日に 1 回までです。組織のすべてのプラットフォームのサブドメインが新しいスラッグに書き換えられ、古いスラッグは 90 日間保持されるので、その間にほかの誰かがそれを取ることはできません。独自のドメイン([ドメイン](/docs/cloud/domains))はスラッグの変更の影響を受けません。 + +## メンバーと招待 [#members-and-invitations] + +サイドバーで **Members** を開きます。このページには 2 つのタブがあります。ロール付きのメンバーと、まだ保留中の招待です。 + +誰かを追加するには、**Invite members** を選び、メールアドレスを入力してロールを選びます。相手は招待を受け取り、それを承諾すると組織のメンバーになります。 + +**組織の招待が、その環境に入る唯一の方法です。** 環境には独自の招待もセルフサインアップもありません。ここで招待した全員が組織の環境に入ることができ、環境の中で何ができるかは、その環境の[権限](/docs/configure/permissions)が決めます。 + +リストから、組織を管理する人は**メンバーのロールを変更**、**メンバーを削除**、保留中の招待を**再送**または**取り消し**できます。 + +## ロール [#roles] + +メンバーシップのロールは、人が組織の中で何に届くかを決めます。これは権限セットではありません。環境の中でレコードに対して何ができるかは、その環境の[権限セットとポジション](/docs/configure/permissions)から来ます。 + +| ロール | 用途 | 招待できる人 | +|---|---|---| +| **Owner** | 組織、そのプラン、その環境の完全な管理 | オーナー | +| **Admin** | 組織を管理します:メンバー、環境、請求 | オーナーまたは管理者 | +| **Delegated Admin** | 管理者でなくても招待のエンドポイントに届きます。人をどこに配置できるかは、別に付与される管理のスコープから来ます | オーナーまたは管理者 | +| **Member** | 組織の環境とアプリを使います | 招待できる人なら誰でも | +| **External** | ポータルのユーザー(仕入先や顧客)で、自分の行と明示的に共有されたものだけを見ます。事業単位のツリーには決して含まれません | 招待できる人なら誰でも | + +このセクションで「組織を管理する人」と言うのは、オーナーと管理者のことです。彼らには、プラン、アップグレード、何かを変更する環境のアクションが表示されます。一般のメンバーは環境を見て開けますが、完了できないアクションは提示されません。 + +## サインインのある場所 [#where-sign-in-lives] + +ObjectOS Cloud では、すべてのアカウントがクラウドのアカウントです。ObjectOS Cloud が人をサインインさせ、環境がその人を受け入れます。環境が各人について保持するのは**認可だけ**、つまりポジション、権限セット、共有です。すべてのホスト型の環境は、どのプランでもデフォルトでこの単一のサインインを使うので、人は ObjectOS Cloud のアカウントで一度サインインし、環境の間を移動できます。 + +**環境を自社のインフラストラクチャに移す場合。** アカウントは環境ではなく ObjectOS Cloud にあるので、環境とともに移動はしません。セルフマネージドのデプロイメントでは、そこで人に新しい認証情報を発行するか、自社のアイデンティティプロバイダーにバインドしてそれを通じてサインインさせます。[認証](/docs/configure/authentication)を参照してください。 + +## 次へ [#next] + +- [環境](/docs/cloud/environments):本番と開発、そしてそのライフサイクル。 +- [プランと AI シート](/docs/cloud/plans-and-seats):Free、Team、Enterprise のそれぞれに含まれるもの。 +- [権限](/docs/configure/permissions):環境の中でメンバーができること。 diff --git a/content/docs/cloud/plans-and-seats.ja.mdx b/content/docs/cloud/plans-and-seats.ja.mdx new file mode 100644 index 00000000..36b415c8 --- /dev/null +++ b/content/docs/cloud/plans-and-seats.ja.mdx @@ -0,0 +1,75 @@ +--- +title: プランと AI シート +seoTitle: "ObjectOS Cloud のプラン:Free、Team、Enterprise と AI シート" +description: ObjectOS Cloud のプラン(Free、Team、Enterprise)、唯一の有料シートである AI シート、アップグレードの方法、そしてプランに含まれないものをコンソールのどこで確認できるか。 +editions: [cloud] +translation: + source_sha: c5f15cf821325b61b91091b0b7377b4a9750dc285a87202f969b73eae1eb8b97 + guide_rev: 1 + mode: auto +--- + +ObjectOS Cloud には 3 つのプランがあります。プランは**組織**に属し、そのすべての環境に適用されます。料金がかかるのは **AI シート**だけで、組織のそれ以外の全員は無料でアプリを使い、閲覧できます。 + +| | **Free** | **Team** | **Enterprise** | +|---|---|---|---| +| 料金 | $0 | AI シートあたり月額 $24、または年払いで AI シートあたり月額 $20 | 契約による | +| 本番環境 | 1 | 1 | 1 | +| [開発環境](/docs/cloud/environments) | — | 2 つに加えて AI シートごとに 1 つ | ✓ | +| アーカイブされた開発環境の保持 | — | 30 日 | 1 年 | +| [AI 利用枠](/docs/cloud/ai-credits-and-limits) | 週ごとの利用枠 | AI シートとともに増える、より大きな利用枠と [AI クレジットパック](/docs/cloud/ai-credits-and-limits#buy-ai-credits) | AI シートとともに増える利用枠と AI クレジットパック | +| [環境ごとのストレージ](/docs/cloud/storage-and-limits) | 1 GB | 20 GB | 上限なし | +| [AI エージェントのアクセス(MCP)](/docs/configure/mcp#on-objectos-cloud) | 1 分あたり 20 リクエスト、1 日 1,000 | 1 分あたり 120 リクエスト、1 日の上限なし | 1 分あたり 120 リクエスト、1 日の上限なし | +| ブランド付きのプラットフォームのサブドメイン | ✓ | ✓ | ✓ | +| [独自のドメイン](/docs/cloud/domains) | — | 本番環境ごとに 1 つ | ✓ | +| 承認ワークフロー | — | — | ✓ | +| サインイン | ObjectOS Cloud のサインイン | ObjectOS Cloud のサインイン | ObjectOS Cloud のサインイン。契約により、自社のアイデンティティプロバイダーによるシングルサインオン | +| サポート | コミュニティ | 標準 | 優先 | + +ObjectOS Cloud は[パブリックプレビュー](/docs/editions/public-preview)中です。料金はプレビュー期間の料金であり、変更があれば事前に告知されます。 + +## AI シート [#the-ai-seat] + +**AI シート**は、AI で構築し、データについて AI に質問できるメンバーです。[AI Builder](/docs/build/ai-builder) とアプリ内のアシスタントのことです。これが唯一の有料シートです。AI シートを持たないメンバー、閲覧者、そして [MCP](/docs/configure/mcp) 経由で自分の AI クライアントを使って構築する開発者には料金がかかりません。 + +購入する AI シートの数は組織の設定で、チェックアウト時に選び、後から変更できます。それによって 3 つのものの大きさが決まります。 + +- 組織の **AI 利用枠**。シートごとです([AI クレジットと上限](/docs/cloud/ai-credits-and-limits))。 +- **開発環境のプール**。2 つに加えてシートごとに 1 つです([環境](/docs/cloud/environments))。 +- 人ごとのシートの割り当てが有効になっている環境で、AI シートを**割り当てられる**人の数。 + +## アップグレード [#upgrade] + +アップグレードは、オーナーまたは管理者が環境のページ(そのヘッダー、または **Settings → Plan and billing**)から行います。 + +1. **Upgrade Plan** を選びます。ダイアログで、プラン(Team)、請求の周期(月払い、または AI シートあたり月額 $20 の年払い)、AI シートの数を尋ねられます。 +2. 新しいタブで安全なチェックアウトが開きます。請求先は 1 つの環境ではなく、組織です。 +3. 支払いが完了すると組織のプランが変わり、そのすべての環境が再デプロイなしに新しいプランを取り込みます。 + +組織でまだオンライン決済が利用できない間は、ボタンは **Upgrade to Team** と表示され、代わりに **Billing** を開きます。そこで Team の **Contact sales** ボタンを押すと、私たちとともにアップグレードを始められます。 + +Enterprise は営業担当者が支援します。**Billing** の Enterprise の列にある **Contact sales** を使ってください。 + +## プランに含まれないものを確認する [#see-what-your-plan-leaves-out] + +コンソールの 2 か所で、営業ページを挟まずに確認できます。 + +- **Billing** は 3 つのプランを並べて比較し、現在のプランに **Current plan** の印を付けます。すべてのメンバーが読めますが、そのボタンが表示されるのはオーナーと管理者だけです。 +- 環境の **Overview** タブには、折りたたまれた **Features that need a higher plan: N · View** の行があります。開くと、現在のプランに含まれない各機能が、それを含むプランとともに一覧されます。ロックされた機能がコンソールのほかの場所に現れる場合は、**Team plan and above** のような、そのプランの名前を示す短い印が付き、**Billing** へ移動できます。 + +## ダウングレード [#downgrading] + +下位のプランに下げても、データが削除されることは決してありません。 + +- 開発環境は動き続けます。Free が拒否するのは、その作成と復元だけです([環境](/docs/cloud/environments#after-a-downgrade-to-free))。 +- Free のストレージの割り当てを超えた環境は、すべてのバイトを保持し、読み取りとエクスポートができる状態のまま、アップロードとインポートを受け付けなくなります([ストレージと上限](/docs/cloud/storage-and-limits))。 +- 独自のドメインは解放されずに一時停止され、後でアップグレードすると自動的に戻ります([ドメイン](/docs/cloud/domains#downgrade-and-upgrade))。 + +## Business [#business] + +**Business** は、ホスト型サービスにおける ObjectOS Enterprise の契約オプションで、**Billing** からではなく[営業](/docs/editions/license)が販売します。ObjectOS Cloud では、承認ワークフローと、アーカイブされた開発環境の 90 日間の保持期間を追加します。料金と契約がカバーする内容は[ライセンスと料金](/docs/editions/license)にあります。 + +## 次へ [#next] + +- [エディションの比較](/docs/editions/compare):Community と Enterprise と並べたプラン。 +- [AI クレジットと上限](/docs/cloud/ai-credits-and-limits):AI 利用枠の仕組み。 diff --git a/content/docs/cloud/storage-and-limits.ja.mdx b/content/docs/cloud/storage-and-limits.ja.mdx new file mode 100644 index 00000000..26f20f4e --- /dev/null +++ b/content/docs/cloud/storage-and-limits.ja.mdx @@ -0,0 +1,61 @@ +--- +title: ストレージと上限 +seoTitle: "ObjectOS Cloud の上限:環境ごとのストレージと MCP リクエストの上限" +description: ObjectOS Cloud の環境の使用上限。1 GB と 20 GB のストレージの割り当て、いっぱいになった環境が止めるものと決して止めないもの、80% の警告、そしてプランごとの MCP リクエストとドラフトの上限。 +editions: [cloud] +translation: + source_sha: d814bf7b8ecb5b58b6975c5ccb4927b9788c2e96517b9d44980d7da7b2c72a30 + guide_rev: 1 + mode: auto +--- + +各 ObjectOS Cloud の環境には、独自の上限がいくつかあります。このページでは、それぞれの数値が属するプランとともに一覧します。AI 利用枠には専用のページがあります:[AI クレジットと上限](/docs/cloud/ai-credits-and-limits)。 + +| 上限 | Free | Team 以上 | Enterprise | +|---|---|---|---| +| [環境ごとのストレージ](#storage) | 1 GB | 20 GB | 上限なし | +| [1 分あたりの MCP リクエスト](#mcp-limits) | 20 | 120 | 120 | +| [UTC の 1 日あたりの MCP リクエスト](#mcp-limits) | 1,000 | 1 日の上限なし | 1 日の上限なし | +| [UTC の 1 日あたりの MCP 経由の作成の書き込み](#drafts-and-authoring-writes) | 200 | 2,000 | 2,000 | +| [環境ごとの未公開のドラフト](#drafts-and-authoring-writes) | 500 | 500 | 500 | + +## ストレージ [#storage] + +すべての環境には**ストレージの割り当て**があります。Free では **1 GB**、Team では **20 GB** で、**環境ごと**に数えられます。開発環境も本番と同じ割り当てを得ます。Enterprise 契約にはストレージの数値はありません(プロダクトオーナーの決定、2026-09-08:数値は確定です)。 + +**数えられるもの。** 環境のデータベースと添付ファイルです。使用量はおよそ 1 時間ごとに測り直されるので、大きなアップロードやインポートは 1 時間以内に測定値に現れます。この遅れは意図的なものです。 + +**いっぱいになった環境が止めるもの。** 割り当ての 100% から、2 つのことが拒否されます。 + +- **添付ファイルのアップロード**(ファイルと画像のフィールド) +- レコードの**一括インポート** + +拒否は、コード `STORAGE_LIMIT_REACHED` とアップグレードの方法とともに `403` で返されます。 + +**決して止めないもの。** 単一のレコードの作成、編集、削除。何かを読むこと。エクスポート。そして空き容量を作るための添付ファイルの削除です。環境が割り当てに近づいているせいで、その環境で構築されたアプリを使う人がフォームを保存できなくなることは決してありません。 + +**警告。** **80%** でコンソールにバナーが表示されます。これは警告であって上限ではありません。アップロードとインポートは 100% まで引き続き通ります。 + +**ダウングレードは何も削除しません。** ダウングレードの後で Free の割り当てを超えてしまった環境は、すべてのバイトを保持し、読み取りとエクスポートができる状態のまま、再びアップグレードされるか空き容量ができるまで、アップロードとインポートを受け付けなくなるだけです。 + +## MCP の上限 [#mcp-limits] + +すべての環境の [MCP エンドポイント](/docs/configure/mcp#on-objectos-cloud)が受け付けるリクエストの数は決まっており、その環境に接続しているすべてのエージェントで共有されます。[cloud#3203](https://github.com/objectstack-ai/cloud/issues/3203) で決定されました。 + +- **Free:** 1 分あたり 20 リクエスト、UTC の 1 日あたり 1,000。 +- **Team 以上:** 1 分あたり 120 リクエスト、1 日の上限なし。 + +リクエストは 1 つの MCP メッセージです。ツールの呼び出し、一覧の取得、接続のハンドシェイクの各ステップです。バッチはその中の各メッセージを数え、その日の残りの数に収まらないバッチは丸ごと拒否されます。1 分あたりの割り当ては連続的に補充されるので、1 分あたりの数値までの短い集中した利用は問題ありません。 + +上限を超えると、エンドポイントは `Retry-After` ヘッダー付きの `429 Too Many Requests` で応答し、本文の `error.code` は `RATE_LIMIT_EXCEEDED` です。メッセージには、どの上限に達したか、いつリセットされるかが示され、Free では Team へのアップグレードも案内されます。拒否されたリクエストは実行されておらず、どちらの上限も消費しません。待った後の次のリクエストは通常どおり処理されます。人が操作するエージェントは有料プランの上限を十分に下回ります。上限に達するエージェントは、たいていは同じツールを繰り返し呼び出すループです。 + +## ドラフトと作成の書き込み [#drafts-and-authoring-writes] + +アプリの設計への変更は、公開されるまで**ドラフト**としてステージングされます。環境が保持できる**未公開のドラフトは最大 500 件**で、どのプランでも、どの方法で作られたものでも同じです。それを超えると、さらにドラフトをステージングする変更は、ドラフトが公開または破棄されるまで拒否されます。これは時間でリセットされることはありません。 + +MCP 経由で届く作成の書き込み(メタデータを作成または変更するビルドツール)も、UTC の 1 日ごとに数えられます。Free では **200**、Team 以上では **2,000** です。読み取りとチェックは数えられません。どちらの拒否も、リクエストの上限と同じ `RATE_LIMIT_EXCEEDED` の応答を使い、その数、上限、いつリセットされるかを示します。[cloud#3303](https://github.com/objectstack-ai/cloud/issues/3303) で決定されました。 + +## 次へ [#next] + +- [プランと AI シート](/docs/cloud/plans-and-seats):各プランに含まれるもの。 +- [AI ツールを接続する(MCP)](/docs/configure/mcp#on-objectos-cloud):環境の MCP エンドポイントを有効にする。 diff --git a/content/docs/configure/permissions/field-level-security.ja.mdx b/content/docs/configure/permissions/field-level-security.ja.mdx new file mode 100644 index 00000000..e3aa636b --- /dev/null +++ b/content/docs/configure/permissions/field-level-security.ja.mdx @@ -0,0 +1,157 @@ +--- +title: フィールドレベルのセキュリティ +seoTitle: "フィールドレベルのセキュリティ:付与と API での強制" +description: 個々のフィールドを隠す、マスクする、ロックする。付与の意味、サーバー側での強制、そしてフォーム、ビュー、API で FLS がどう動作するか。 +editions: [community, cloud, enterprise] +translation: + source_sha: 58871db7d6fcecf258805b25fbf6750df2977a64c4fc479c32004dad5e19422b + guide_rev: 1 + mode: auto +--- + +フィールドレベルのセキュリティ(FLS)は、オブジェクトの権限と[レコードアクセス](/docs/configure/permissions/record-access)がユーザーにそもそもレコードへの到達を許した*後で*、個々のフィールドの表示と編集の可否を制御します。「サポートは取引先を見られるが、その `annual_revenue` は見られない」や「営業担当者は外部 ID を読めるが、決して変更できない」のための層です。 + +FLS のルールは[権限セット](/docs/configure/permissions/permission-sets)にあります。このページは、そこにある[フィールドのセキュリティの付録](/docs/configure/permissions/permission-sets#field-security-appendix)よりも、付与の意味と強制について掘り下げます。 + +## フィールドの権限の付与 [#field-permission-grants] + +フィールドの権限は `.` をキーとし、`readable` / `editable` を使います。 + +```ts +// Keys of a permission set; its other keys are omitted. +fields: { + // Read-only: visible but not editable + 'account.annual_revenue': { readable: true, editable: false }, + 'account.description': { readable: true, editable: true }, + // Hidden: not visible at all + 'account.ssn': { readable: false, editable: false }, + 'opportunity.amount': { readable: true, editable: true }, + 'opportunity.probability': { readable: true, editable: false }, +} +``` + +2 つのフラグで 3 つの状態が生まれます。 + +| 状態 | ルール | 効果 | +|---|---|---| +| **非表示** | `{ readable: false, editable: false }` | フィールドはまったく見えません。すべてのレスポンスから取り除かれます | +| **読み取り専用** | `{ readable: true, editable: false }` | フィールドは返されますが、それへの書き込みは拒否されます | +| **編集可能** | `{ readable: true, editable: true }` | フィールドは見えて、書き込めます | + +> フィールドの権限のキーは、常に**オブジェクトで修飾して**書きます(`budget` ではなく `crm_lead.budget`)。ObjectStack 14.4 以降、`security-fls-unqualified-key` の lint はコンパイル時に素のキーを拒否します。それらは黙って何にも一致していなかったからです。 + +## マスクされたフィールド [#masked-fields] + +ObjectStack 17.1 以降、フィールドは**マスク**することもできます。値の大部分を置き換えて提供するので、開示されることなく識別できる状態が保たれます。マスクは権限セットではなく、フィールドそのものに宣言します。 + +```ts +// Fields of an object; the object around them is omitted. +mobile: Field.phone({ + label: 'Mobile', + maskingRule: 'phone', // served as 138****5678 + requiredPermissions: ['view_pii'], // holders of view_pii see the stored value +}), +tax_id: Field.text({ + label: 'Tax ID', + maskingRule: { keepHead: 2, keepTail: 2 }, // keep two characters at each end +}), +``` + +`maskingRule` は 5 つのプリセット(`phone`、`id_card`、`bank_account`、`email`、`name`)のいずれか、または両端に残す文字数を表す `{ keepHead, keepTail }` を取ります。マスクは決定的で、値の長さを保ちます。 + +保存された値を見られるのは誰か: + +| 呼び出し元 | 見えるもの | +|---|---| +| フィールドの `requiredPermissions` の機能を**すべて**持っている | 保存された値 | +| フィールドが `requiredPermissions` を宣言している場合の、それ以外の全員 | マスク | +| フィールドが `requiredPermissions` を宣言していない場合の、システムのコンテキスト以外の全員 | マスク | +| `readable: false` の付与によってフィールドが隠される呼び出し元 | 何も見えません。フィールドは隠されたままです | + +`requiredPermissions` の機能は、ほかの機能と同じく権限セットで付与されます。マスクが隠されたフィールドを広げることは決してありません。`readable: false` の付与は、引き続きフィールドを完全に取り除きます。 + +マスクはすべての画面で 1 つの値です。API のレスポンス、リストビューとフォーム、CSV と XLSX のエクスポート、AI エージェントが読むコンテキストのすべてが、同じマスクを提供します。漏洩を防ぐためのルールがさらに 2 つあります。 + +- **マスクされたフィールドはクエリできません。** それによるフィルター、並べ替え、グループ化、集計は、隠されたフィールドと同じく拒否されます。[API での強制](#enforcement-in-the-api)を参照してください。 +- **マスクが値を上書きすることは決してありません。** マスクされたプレースホルダーを送り返す書き込み(読み取ったレコード全体を再送信するクライアント)は、`138****5678` を保存する代わりに `400 VALIDATION_ERROR` で拒否されます。 + +## 付与はどう組み合わさるか [#how-grants-combine] + +FLS は**デフォルトで表示(ブロックリスト)の意味**を使います。明示的なルールのないフィールドは、そのまま通過します。読み取り可能*かつ*書き込み可能です。権限セットが制約するのは、明示的に列挙したフィールドだけです。 + +フィールドの付与は、ユーザーのセットをまたいで**最も許容的に**合算されます。あるセットの `readable: true` は、別のセットの `false` に勝ちます。減算的なミュートの層(ADR-0066 ⑧ として予約)が導入されるまでは、`{ readable: false }` のルールがフィールドを隠すのは、**ユーザーが持つほかのどのセットも**それを `readable: true` と宣言していない間だけです。実際的な結果: + +- 機密性の高いフィールドは、それが必要なセットで**だけ**付与することで保護します。あるセットの `false` のルールが別の場所の `true` を上書きすることに頼ってはいけません。 +- 広く付与されたオブジェクト上の機密性の高いフィールドは、見直すべき兆候として扱ってください。 + +宣言されたルールそのものは安全側に倒れて強制されます。隠されたフィールドは読み取り時に取り除かれ、編集不可能なフィールドへの書き込みは例外を投げます。 + +## API での強制 [#enforcement-in-the-api] + +SecurityPlugin のミドルウェアは、リクエストが REST、ObjectQL、そのほかのどの経路で届いたかにかかわらず、サーバーでフィールドのルールを強制します。下位レベルの API を通る裏口はありません。 + +**読み取り時**:`find` / `findOne` の結果は、レスポンスがエンジンを離れる前に、すべてのレコードから読み取り不可能なフィールドが取り除かれ、マスクされたフィールドはマスクに置き換えられます。 + +**クエリ時**:呼び出し元が読めない、またはマスクされた状態でしか読めないフィールドは、行の選択にも使えません。どの行が一致するかによって、1 回の探りごとにその値が開示されてしまうからです。それによるフィルター、並べ替え、グループ化、集計は `403 PERMISSION_DENIED` で拒否されます。ObjectStack 17.6 以降、これはデータ API のフィルターと並べ替えだけでなく、すべてのクエリの入口で成り立ちます。 + +- フィルターや集計の中で、比較の右辺として指定されたフィールド +- 分析のクエリ +- アクティビティストリーム、[監査ログ](/docs/operate/audit-logs)、承認のスナップショットにコピーされた値に対するフィルターと並べ替え。フィルターが等価比較で 1 つのオブジェクトを指定し、呼び出し元がそのすべてのフィールドを読める場合を除いて拒否されます + +**書き込み時**:`insert` / `update` のリクエストは、操作がドライバーに届く**前に**チェックされます。呼び出し元が編集を許されていないフィールドがペイロードに含まれていれば、エンジンは問題のフィールド名とともに `PermissionDeniedError`(HTTP 403)を投げます。 + +```json +{ + "error": { + "code": "PERMISSION_DENIED", + "message": "[Security] Field write denied: not permitted to edit [salary, ssn] on 'employee'", + "details": { + "operation": "insert", + "object": "employee", + "forbiddenFields": ["salary", "ssn"] + } + } +} +``` + +**なぜ黙って取り除かずに例外を投げるのか?** 黙って取り除くと、誠実なクライアントからはセキュリティの境界が見えなくなり(更新が「保存されない」のに理由がわからない)、*しかも*探りを入れるクライアントにも、どちらの方向にも何の手がかりも与えません。例外を投げれば、境界はどちらの方向にも観察できるようになります。正当な UI は修正すべき実用的なエラーを受け取り、探りを入れるクライアントは、すでに推測できた以上のことを何も知りません。 + +強制についての詳細がさらに 2 つあります。 + +- **一括の挿入**は行ごとにチェックされます。どの行であれ問題のフィールドが 1 つでもあれば、バッチ全体がアトミックに拒否されます。 +- **システムの操作**(`ExecutionContext { isSystem: true }`)はチェックを完全にすり抜けます。マイグレーション、初期データの読み込み、監査ログの書き込みに使われます。 + +## フォームとビューでの FLS [#fls-in-forms-and-views] + +生成されたフォームとインラインのグリッドは、編集不可能なフィールドを UI から隠しますが、それは **UX の層にすぎません**。上のサーバー側のチェックが正であるので、動作はどこでも一貫しています。 + +| 画面 | 非表示のフィールド | マスクされたフィールド | 読み取り専用のフィールド | +|---|---|---|---| +| レコードのフォーム / インラインのグリッド | レンダリングされません | 値はマスクされて表示されます。マスクを書き戻すと `400 VALIDATION_ERROR` で拒否されます | 編集用のコントロールなしでレンダリングされます。直接の書き込みの試みは 403 で拒否されます | +| リストビュー、関連リスト、エクスポート | 列の値はレスポンスから取り除かれます | マスクされた値が表示されます。CSV と XLSX のエクスポートでも同じです | 値は通常どおり表示されます | +| REST / ObjectQL | 結果から取り除かれます | マスクされた値が返されます | 読み取り時は返されます。書き込みは `forbiddenFields` とともに `PERMISSION_DENIED` を投げます | +| MCP / AI エージェント | 取り除かれます。エージェントは[呼び出したユーザーとして実行されます](/docs/configure/mcp#permission-enforcement) | REST と同じ | REST と同じ | +| フィルター、並べ替え、グループ化、集計 | `403 PERMISSION_DENIED` で拒否されます | `403 PERMISSION_DENIED` で拒否されます | 許可されます | + +読み取りはエラーにならずに取り除かれるので、隠されたフィールドはそのユーザーには単に存在しないように見えます。それが狙いです。それに対するクエリは例外で、上のとおり `403` で応答します。 + +## FLS を確認してレビューする [#verifying-and-reviewing-fls] + +- **判定ごとに、実行時に**:[explain エンジン](/docs/configure/permissions#diagnose--audit)は、ほかのすべての層と並べて FLS の層の判定を報告し、寄与した権限セットの名前を示します。また、マスクされたフィールドを隠されたものではなくマスクされたものとして報告します。ユーザーがフィールドが「ない」と報告してきたときに使ってください。 +- **変更ごとに、ビルド時に**:アプリがアクセスマトリクスのスナップショットのゲートを有効にしている場合、`os compile` は導出された(権限セット × オブジェクト)の機能のマトリクスを、コミットされた `access-matrix.json` と比較し、ずれがあれば失敗します。そのため機能の変更は、レビューできる意味上の差分としてプルリクエストに載ります。 + +```bash +os compile --update-access-matrix +``` + +> フィールドが機密性の高いデータを持つ場合は、読み取り専用ではなく**非表示**をデフォルトにします。読み取り専用でも、値はレスポンスとログに漏れます。フィールドのルールは実際の職務に合った権限セットにまとめ、コンプライアンスのケースでは監査ログの保持と組み合わせてください。作成のパターンはほかにもあります:[Permission Sets](/docs/configure/permissions/permission-sets#field-security-appendix)。 + +## 次に進む [#where-to-go-next] + +| タスク | ページ | +|---|---| +| 権限セットの中でフィールドのルールを作成する | [権限セット](/docs/configure/permissions/permission-sets) | +| そもそもどの行に到達できるかを制御する | [レコードアクセス](/docs/configure/permissions/record-access) | +| 階層化されたモデルの全体を見る | [権限](/docs/configure/permissions) | +| 特定のユーザーのアクセスを確認する | [アクセスの管理](/docs/configure/permissions/managing-access) | +| AI エージェントが何を読めるかを確認する | [AI ツールを接続する(MCP)](/docs/configure/mcp) | diff --git a/content/docs/configure/permissions/hierarchy-visibility.ja.mdx b/content/docs/configure/permissions/hierarchy-visibility.ja.mdx new file mode 100644 index 00000000..9b372dc8 --- /dev/null +++ b/content/docs/configure/permissions/hierarchy-visibility.ja.mdx @@ -0,0 +1,106 @@ +--- +title: 階層による表示範囲 +seoTitle: "階層による表示範囲:マネージャーに部下のレコードを見せる" +description: 読み手がどこに位置するか(その事業単位、その下の単位、またはその報告ライン)によって、誰がレコードを読めるかを広げます。unit、unit_and_below、own_and_reports のスコープを使います。 +editions: [cloud, enterprise] +translation: + source_sha: 11e8c60b7087869d03eca49ac3513df7dd066eef47d302fd1b95ffe53d110258 + guide_rev: 1 + mode: auto +--- + +**階層による表示範囲**は、組織の中で*どこに位置するか*によって、人が読めるレコードを広げます。地域マネージャーは自分の地域の誰かが所有するすべてのレコードを見られ、チームリーダーは直属と間接の部下のレコードを見られます。これは[権限セット](/docs/configure/permissions/permission-sets)でオブジェクトごとに、読み取り(または書き込み)の**スコープ**として設定します。 + +> **利用できる場所。** セルフマネージドの ObjectOS Enterprise のデプロイメントで、`hierarchySecurity` 機能を含むライセンスのもと。ObjectOS Cloud では、Enterprise 契約のもと。それ以外のどこでも、このページの 3 つのスコープは所有者自身のレコード以上のものを何も付与しません。*開いた*側に倒れて失敗することは決してありません。[要件](#requirements)を参照してください。 + +## 3 つのスコープ [#the-three-scopes] + +`own`(レコードの所有者)と `org`(組織内の全員)はすべてのエディションで機能します。3 つの階層のスコープは、その間に位置します。 + +| スコープ | 読み手が見られるのは、次の人が所有するレコード | 構築の元 | +|---|---|---| +| `unit` | 読み手と、読み手の事業単位のほかのすべてのメンバー。下へは降りません。 | 読み手のポジションの割り当て、なければ単位のメンバーシップ | +| `unit_and_below` | 読み手の事業単位**とツリーでその下にあるすべての単位**、そしてそのすべてのメンバー | 事業単位のツリー | +| `own_and_reports` | 読み手と、管理の連鎖でその下にいる全員(直属と間接) | 各ユーザーのマネージャー | + +スコープは、人が読めるものを**広げる**だけです。共有ルールとレコードの共有に追加され、誰かがすでに持っているアクセスを取り除くことはなく、`org` を越えることもありません。スコープが決めるのは権限が*どのレコード*に適用されるかであって、新しい権限を付与することは決してありません。 + +### 例 [#example] + +事業単位のツリーには **Region** があり、その下に **Team**、そして兄弟の単位 **Other** があります。Alice と Carol は Region に、Bob は Team に、Dave は Other にいます。Bob は Alice の部下です。 + +- `unit` の Alice が見られるのは **Alice、Carol** です。Bob と Dave は見られません。 +- `unit_and_below` の Alice が見られるのは **Alice、Carol、Bob** です。Region は Team へ降ります。兄弟の単位の Dave は外れたままです。 +- `unit_and_below` の Bob が見られるのは **Bob だけ**です。下に何もない単位が、親へと*上に*広がることはありません。 +- `own_and_reports` の Alice が見られるのは **Alice、Bob** です。Bob の単位がどこであっても、彼女の部下だからです。 + +## スコープを設定する [#set-a-scope] + +権限セットのオブジェクトのエントリに `readScope`(必要なら `writeScope` も)を設定します。地域全体を読む営業担当者: + +```ts +// Keys of a permission set; its other keys are omitted. +objects: { + opportunity: { allowRead: true, allowEdit: true, readScope: 'unit_and_below' }, +} +``` + +自分の報告ラインに限られるチームリーダー: + +```ts +// Keys of a permission set; its other keys are omitted. +objects: { + opportunity: { allowRead: true, readScope: 'own_and_reports' }, +} +``` + +階層のスコープを使う、コードで書かれたスタックは `requires: ['hierarchy-security']` を宣言しなければなりません。なければスタックはビルドされません。スコープを解決できない環境は、それを使うメタデータの公開を拒否し、そのようなドラフトが保存されたときに警告します。 + +## どの単位があなたのものか [#which-unit-is-yours] + +`unit` と `unit_and_below` では、読み手の単位はまず**ポジションの割り当て**から取られます。現在の各割り当てが配置されている事業単位です。配置された割り当てを持たない読み手だけが、**メンバー**である単位にフォールバックします。 + +これは、複数の単位に属していても 1 つしか管理していない人にとって重要です。Alice は **Region** と部門横断の **Project** 単位のメンバーですが、彼女のセールスマネージャーのポジションは Region で割り当てられています。`unit` では、彼女が見られるのは Region のメンバーだけです。Project のメンバーシップが、彼女の読めるものを広げることはありません。 + +- **配置された割り当てが複数あれば合算されます**:読み手の単位はそのすべてです。 +- **期限切れの割り当ては数えられません**:valid-from / valid-until の期間外にある割り当ては、その単位の付与を止めます。 + +割り当てと事業単位のツリーについては[ポジション](/docs/configure/permissions/positions)を参照してください。 + +## 投入するデータ [#what-to-populate] + +スコープは、ディレクトリや人事のソースが SCIM、連携、管理画面を通じて提供するデータを読みます。 + +| データ | 使うもの | +|---|---| +| 事業単位のツリー(各単位の親) | `unit_and_below` | +| ポジションの割り当て(事業単位と有効期間付き) | `unit`、`unit_and_below`(第一候補) | +| 事業単位のメンバーシップ | `unit`、`unit_and_below`(フォールバック) | +| 各ユーザーの**マネージャー** | `own_and_reports` | + +どちらのたどり方も 20 階層までに制限されているので、不正なツリーや偶然の報告の循環が無限ループになることはありません。結果はユーザーごとに短時間キャッシュされ、ツリー、メンバーシップ、割り当て、またはユーザーのマネージャーが変わるたびに消去されます。 + +## 報告ラインは 1 つの組織の中にとどまる [#a-reporting-line-stays-inside-one-organization] + +複数の組織を持つデプロイメントでは、マネージャーとその部下は少なくとも 1 つの組織を共有していなければなりません。 + +- **組織をまたいでマネージャーを設定することは拒否されます。** 部下と提案されたマネージャーがどちらも組織に属していて、1 つも共有していない場合、書き込みは `400 INVALID_REFERENCE`(`reason: 'cross-organization-manager'`)で拒否されます。管理画面、API、インポート、システムのコードのいずれからでも同じです。修正するには、2 人に共有の組織を与えるか、部下自身の組織の中からマネージャーを選びます。 +- **「同じ組織」ではなく「組織を共有する」です。** グループと工場の両方のメンバーであるグループレベルのマネージャーは、どちらの人も管理できます。 +- **まだ組織を持たないユーザーが拒否されることは決してなく**、たどる対象から外されることもありません。 +- **読み取りも同じルールに従います。** `own_and_reports` は境界で止まります。別の組織にだけ属する部下は外され、その下の全員も外されます。 + +グループレベルの監督のためには、その人に監督する組織のメンバーシップを与えてそこでより広いスコープの権限セットを付与するか、1 つの組織の中で事業単位のツリーを使ってください。 + +## 要件 [#requirements] + +- **セルフマネージドの ObjectOS Enterprise:** 機能に `hierarchySecurity` を含むライセンス(デフォルトの Enterprise の機能セットは含みます)。なければ、スコープは `own` として動作します。 +- **ObjectOS Cloud:** Enterprise 契約。Free と Team ではスコープは `own` として動作し、環境はそれを使うメタデータの公開を拒否します。 +- **ObjectOS Community:** 利用できません。スコープは `own` として動作します。 + +ほかのすべての Enterprise の機能と同じく、権利を失うとアクセスが狭まります。ランタイムが止まることは決してありません。 + +## 次へ [#next] + +- [権限セット](/docs/configure/permissions/permission-sets):スコープを設定する場所。 +- [レコードアクセス](/docs/configure/permissions/record-access):スコープが追加される先の、共有ルールとレコードの共有。 +- [ポジション](/docs/configure/permissions/positions):割り当てと事業単位のツリー。 diff --git a/content/docs/configure/permissions/index.ja.mdx b/content/docs/configure/permissions/index.ja.mdx new file mode 100644 index 00000000..8ab681a7 --- /dev/null +++ b/content/docs/configure/permissions/index.ja.mdx @@ -0,0 +1,141 @@ +--- +title: 権限 +seoTitle: "権限モデル:ポジション、権限セット、レコードアクセス" +description: アイデンティティ、ポジション、権限セット、レコードアクセス、フィールドのセキュリティ。アクセスモデルの全体を 1 ページで。 +editions: [community, cloud, enterprise] +translation: + source_sha: 62da1addaebe59555e84667986dd672e36ad681514d179b84709100b01fc0b61 + guide_rev: 1 + mode: auto +--- + +ObjectOS は、エンタープライズソフトウェアで 20 年にわたって機能してきた定石から借りた、階層化されたアクセスモデルを持っています。アイデンティティ → ポジション → 権限セット → レコードアクセス → フィールドのセキュリティです。各層は異なる問いに答え、必要のない層は無視できます(ObjectStack 13 では、旧来の Roles と Profiles の概念が**ポジション**に統合されました。[ポジション](/docs/configure/permissions/positions)を参照してください)。 + +## 1 枚の図で見るモデル [#the-model-in-one-diagram] + +```text +Authentication Who is the caller? + ↓ +Identity Which user/org/membership is active? + ↓ +Positions Which job functions do they hold? + ↓ +Permission sets What CAN they do — apps, objects, fields, system? + ↓ +Record access WHICH records can they touch? + ↓ +Field security For those records, which FIELDS are readable / writable? +``` + +各層はセキュリティプラグインによって強制されます。シンプルなアプリでは権限セットだけ(ポジションも共有ルールもなし)を使い、要件が出てきたところで残りを追加できます。 + +## 第 1 層:アイデンティティ [#layer-1--identity] + +アイデンティティのオブジェクトはプロジェクトのデータベースにあります。最も重要なもの: + +| オブジェクト | 表すもの | +|---|---| +| `sys_user` | 認証できる人、またはサービスアカウント | +| `sys_organization` | テナント / ワークスペースの境界(マルチテナントのアプリ) | +| `sys_member` | 組織におけるユーザーのメンバーシップ | +| `sys_business_unit`、`sys_team` | 共有ルールのための省略可能な組織構造 | +| `sys_invitation` | 承諾を待っている保留中の招待 | +| `sys_session` | アクティブな認証済みセッション | +| `sys_api_key` | ユーザーに結び付いた、長期間有効なプログラム用の認証情報 | + +マルチテナントのデプロイメントでは: + +- ユーザーはプロジェクトのデータベースにスコープされます。 +- セッションはプロジェクトのホスト名にスコープされます。 +- 行レベルのチェックは、現在のユーザーの組織と権限を使います。 +- コントロールプレーンのユーザーが自動的に業務ユーザーになることは**ありません**。プラットフォーム SSO または明示的なプロビジョニングで対応付ける必要があります。 + +これらは実行時に **Setup**(`/_console/`)で作成 / 管理するか、新しい環境のために `objectstack.config.ts` で初期投入します。 + +## 第 2 層:ポジション [#layer-2--positions] + +ポジションは職務(「Sales Manager」、「Support Agent」)をモデル化します。ポジションはフラットです。階層は事業単位のツリーにあるので、共有ルールやレポートは「レコードの所有者の単位とその下位の単位」のような言い方をします。初期投入される対象者のアンカー `everyone`(認証されたすべてのユーザー)を使えば、カスタムのフォールバックのロジックなしにベースラインの権限セットをバインドできます。その対になる `guest`(匿名の呼び出し元)は何も付与しません。匿名の訪問者がデータに届くのは、公開フォームや共有リンクのように、それを宣言した画面を通じてだけです。ポジションは職務ごとに権限セットを配布するのに使い、フラットなチームではカスタムのポジションを省略してください。 + +[ポジション](/docs/configure/permissions/positions)を参照してください。 + +## 第 3 層:権限セット [#layer-3--permission-sets] + +権限セットは、機能を付与する主な方法です。ユーザーに直接、またはポジションを通じて付けます。 + +### 何を付与するか [#what-they-grant] + +| 種類 | 例 | +|---|---| +| アプリケーションへのアクセス | CRM を開く、サポートポータルを開く | +| オブジェクトの権限 | オブジェクトのレコードを作成 / 読み取り / 更新 / 削除する | +| フィールドの権限 | 特定のフィールドを読み取る、または更新する | +| システムの権限 | Setup にアクセスする、レポートを実行する、監査ログを表示する | +| 連携の権限 | API キーを使う、Webhook を設定する、管理アクションを実行する | + +### オブジェクトの権限フラグ [#object-permission-flags] + +セキュリティプラグインがチェックする、正確なフラグの名前です。 + +| フラグ | 意味 | +|---|---| +| `allowRead` | レコードアクセスによってユーザーが見られるレコードを読み取ります | +| `allowCreate` | 新しいレコードを作成します | +| `allowEdit` | ユーザーが見られるレコードを更新します | +| `allowDelete` | ユーザーが見られるレコードを削除します | +| `allowExport` | オブジェクトのレコードの、機械可読な一括コピーを取ります | +| `viewAllRecords` | レコードアクセスのルールを無視して、そのオブジェクトの**すべての**レコードを読み取ります | +| `modifyAllRecords` | **すべての**レコードを更新 / 削除します。`viewAllRecords` を含意します | + +`viewAllRecords` と `modifyAllRecords` は、そのオブジェクトについてのテナント全体のスーパーユーザーの付与です。明示的な管理用の権限セットのために取っておき、ユーザー向けのどのポジションにも含めないでください。 + +**エクスポートは独立したオプトインの付与です。** `allowExport` が未設定なら**拒否**を意味します。`allowRead` から継承されることはなく、`viewAllRecords` / `modifyAllRecords` もそれを与え**ません**。レコードを読むことと、テーブル全体の機械可読なコピーを取ることは別の行為であり、これはその 2 つを分ける職務分掌の軸です。エクスポートすべき人が持つすべてのセットで、オブジェクトのエントリ(またはワイルドカード `'*'`)に明示的に付与してください。[Permission Sets](/docs/configure/permissions/permission-sets#export-is-its-own-grant) を参照してください。 + +[権限セット](/docs/configure/permissions/permission-sets)を参照してください。 + +## 第 4 層:レコードアクセス [#layer-4--record-access] + +`viewAllRecords` を持た**ない**ユーザーは、どの行を見られるのでしょうか。 + +このモデルは次のものをサポートします。 + +- 暗黙の所有(ユーザーが作成した、または所有している行) +- 共有ルール(宣言的。「チーム A はチーム A のレコードを見られる」) +- 明示的な共有(`sys_record_share` の行。ユーザー、ポジション、または単位とその配下に付与する一回限りの共有) +- 組織によるスコープ(行の `organization_id` がユーザーの組織と一致する) + +ObjectStack 13 以降、所有者のフィールドを持つカスタムオブジェクトの共有モデルのデフォルトは**非公開**です。公開するには `sharingModel` を明示的に宣言してください。 + +[レコードアクセス](/docs/configure/permissions/record-access)を参照してください。 + +## 第 5 層:フィールドのセキュリティ [#layer-5--field-security] + +ユーザーがレコードを見られる場合でも、個々のフィールドは次のようにできます。 + +- **非表示**:フィールドは API と UI のレスポンスから取り除かれます。 +- **読み取り専用**:フィールドは返されますが、書き込みは拒否されます。 +- **マスク**:呼び出し元がそのフィールドの要求する機能を持っていない限り、値の大部分が置き換えられて返されます(`138****5678`)(ObjectStack 17.1)。 + +非表示と読み取り専用はオブジェクトごと + 権限セットごとに設定し、マスクはフィールドそのものに宣言します。典型的な使い方: + +- `sys_user` の `salary` を、人事以外の全員から隠す。 +- `external_account_id` を、サポート担当者には読めるが編集できないようにする。 +- 顧客の電話番号を、顧客に電話をかけるチーム以外の全員には `138****5678` と表示する。 + +これはオブジェクトの権限と同じ評価器で強制されるので、REST、ObjectQL、UI のすべてに一様に適用されます。[フィールドレベルのセキュリティ](/docs/configure/permissions/field-level-security)を参照してください。 + +## どこから始めるか [#where-to-start] + +| 構築しているもの | 使うもの | +|---|---| +| 単一チームの社内ツール | 権限セットだけ | +| マネージャーがレポートを見る複数チームのアプリ | 事業単位 + ポジション + 権限セット | +| マルチテナントの SaaS 型アプリ | 組織によるスコープ + 権限セット | +| 個人情報を扱う規制対象のアプリ | その上にフィールドのセキュリティを追加 | +| 複雑な CRM 型アプリ | すべての層 | + +## 診断と監査 [#diagnose--audit] + +- **explain エンジン**(`explain(principal, object, operation)`)は、必要な権限、オブジェクトの CRUD、フィールドのセキュリティ、OWD のベースライン、共有、行レベルセキュリティの各層の判定を順に、層ごとの帰属とともに報告します。Studio の **Access** の柱は、これを「Why can this user access?」パネルとして表示します。ほかのユーザーについて説明するには `manage_users` 機能が必要です。 +- `/_console/` は、任意のユーザーの実効的な権限を、評価されるとおりに表示します。 +- 監査ログ(`sys_audit_log`)は、権限に関わる変更(付与、ロールの割り当て、権限セットの編集)を記録します。 +- 拒否されたリクエストは失敗したルール(オブジェクトの権限か、レコードアクセスか、フィールドのセキュリティか)を記録するので、サポートは「なぜこれが見えないのか?」に素早く答えられます。 diff --git a/content/docs/configure/permissions/managing-access.ja.mdx b/content/docs/configure/permissions/managing-access.ja.mdx new file mode 100644 index 00000000..5eb868cf --- /dev/null +++ b/content/docs/configure/permissions/managing-access.ja.mdx @@ -0,0 +1,145 @@ +--- +title: アクセスの管理 +seoTitle: "アクセスの管理:入社、ロールの変更、退社" +description: 日々の管理の手引き。新入社員を迎え入れ、ロールを変更し、誰かが何を見られるかを確認し、きれいに退社させます。 +editions: [community, cloud, enterprise] +translation: + source_sha: be810828c60d389cf16c7b89bedd3c8e68110d089cd9da60fb2c59a3a67321be + guide_rev: 1 + mode: auto +--- + +これは、管理者が毎週扱うアクセスの問題のためのタスクガイドです。[モデルの概要](/docs/configure/permissions)は各層が*どう*機能するかを説明し、このページは*何をクリックするか*を説明します。 + +> **日々の管理作業の 90% は、人をポジションに割り当てることです。** ポジション、その背後にある権限セット、セキュリティのベースラインは、プラットフォームとインストールしたアプリとともに提供されます。機能を一から作ることはほとんどなく、そうすべきでもありません。 + +ユーザーの実効的なアクセスは加算的です。 + +```text +effective access = union of permission sets reached through positions + + direct grants + + the built-in member_default baseline +``` + +制限は*付与しない*ことで行います。保守すべき減算のルールはありません。 + +## 新入社員を迎え入れる [#onboard-a-new-hire] + +順序のある 4 つのステップで、それぞれが前のステップに依存します。 + +| ステップ | 場所 | 内容 | +|---|---|---| +| 1. ユーザーを作成する | Setup → People & Organization → Users | **Invite**、**Create**、または **Import**。[ユーザーと組織](/docs/configure/users#add-people)を参照してください | +| 2. 組織ツリーに配置する | 同じリスト → Business Unit Member の行 | ユーザー + 事業単位、1 つを*主*としてマークします。深さに基づく表示範囲はこれを通じて解決されます | +| 3. ポジションを割り当てる | Setup → Access Control → Positions | 日々の 90%。下記を参照してください | +| 4. 確認する | Impersonate + Explain | テストせずに「準備できました」と伝えてはいけません。下記を参照してください | + +### ポジションを割り当てる [#assigning-positions] + +割り当ては 1 つの行です。**User Position**(`sys_user_position`)= *ユーザー* + *ポジション* + 省略可能な、そのポジションを保持する**事業単位**。このアンカーが、ポジションの深さの付与が*どこに*適用されるかを決めます。「**East の**セールスマネージャー」は、会社全体ではなく East のレコードを見ます。 + +**Setup → Access Control → Positions** でポジションを開き、その関連リストから割り当てを追加します(または User Position の行を直接作成します)。これらの書き込みは統制されています。テナントレベルの管理者は通過し、委任された管理者は自分のサブツリーの中で、許可リストにあるセットだけを割り当てられます。自分自身の権限の昇格は構造的に拒否されます([委任された管理](/docs/configure/permissions/permission-sets#delegated-administration)を参照)。 + +隣接する 2 つの画面で全体像が完成します。 + +- **直接の付与**:権限セットのレコードページ(**Setup → Access Control → Permission Sets**)にある **Assigned Users** パネルは、ポジションなしにユーザーごとの付与を追加します。*ポジションを通じて*保持されている行も表示されますが、削除はここではなくポジションで行います。 +- **事業単位のメンバーシップ**:ステップ 2 のものです。割り当てのアンカーとは独立しています。 + +## 誰かのロールを変更する [#change-someones-role] + +誰かが部署や職務を変えたとき: + +1. その人の **Business Unit Member** の行を新しい単位に更新します。 +2. **User Position の行を付け直します。** 古い単位をアンカーとする割り当てを削除または編集し、新しい単位の割り当てを追加します。 +3. 古いロールに属していた直接の付与を削除します。 +4. 確認します(下記)。 + +割り当ては `valid_from` / `valid_until` の期間を持てます。期限切れの付与は即座に解決されなくなるので、計画的な異動や一時的な代行のロールを扱うきれいな方法です。[権限セット](/docs/configure/permissions/permission-sets)を参照してください。 + +## 誰かが何を見られるかを確認する [#verify-what-someone-can-see] + +組み込みの確認ツールが 2 つあります。 + +- **Impersonate。** Users のリスト → 行のメニュー → **Impersonate User**。そのユーザーのセッションを得られます。その人が開くアプリを開き、見えるべきものが見え、見えるべきでないものが見え*ない*ことを確認します。なりすましは正当なサポートと確認のためのもので、セッションは記録されます。 +- **Explain。** Studio の **Access** の柱 → **Explain access**:ユーザー、オブジェクト、操作を選ぶと、エンジンが判定とすべての評価の層を返します。どの権限セットが付与したか、それをどのポジションを通じて保持しているか、どの共有ルールが広げたか、どのポリシーが絞り込んだかです。 + +同じレポートは REST でも利用できます。 + +```bash +# GET, query-string form +curl -H "Authorization: Bearer $TOKEN" \ + "$BASE/api/v1/security/explain?object=crm_lead&operation=read&userId=usr_123" + +# POST, body form +curl -X POST -H "Authorization: Bearer $TOKEN" -H 'Content-Type: application/json' \ + -d '{"object":"crm_lead","operation":"read","userId":"usr_123"}' \ + "$BASE/api/v1/security/explain" +``` + +`operation` は `read | create | update | delete | transfer | restore | purge` のいずれかです(デフォルトは `read`)。`userId` を省略すると**自分自身**について説明します。自分自身についての説明は常に許可されます。*ほかの*ユーザーについて説明するには、`manage_users` 機能か、そのユーザーをカバーする委任された管理のスコープが必要です。 + +> 何かが誤って解決されたときは、推測して切り替えるより、まず説明させるほうがうまくいきます。レポートが、修正すべき正確な権限セットと層を示します。[診断と監査のセクション](/docs/configure/permissions#diagnose--audit)を参照してください。 + +## 誰かを退社させる [#offboard-someone] + +1. **Ban User**:サインインを即座にブロックします。急ぐ必要があるのはこのステップだけです。 +2. ポジションの割り当てと直接の付与を、落ち着いて削除します。 +3. Business Unit Member の行を削除するか、親を付け替えます。 +4. そのユーザーに結び付いた API キーを失効させます。キーはそのユーザーとして動作し、基になる付与が存在する間は機能し続けます。 + +## 提供されたポジションが合わないとき [#when-the-shipped-positions-dont-fit] + +権限は Studio で*設計し*、Setup で*割り当てます*。提供されたポジションでは足りない場合は、機能する最小の変更を次の順で選んでください。 + +1. **既存の権限セットをポジションにバインドします。** +2. **提供されたセットを複製して調整します。** +3. Studio の権限セットのマトリクスエディターで**新しいセットを作成します**。オブジェクトの CRUD、フィールドレベルのセキュリティ、機能のための構造化されたスプレッドシートで、JSON を手で書くことはありません。 + +アプリとともに提供されたセットを編集すると、*環境のオーバーレイ*が作られます。あなたの変更が優先され、アップグレードを越えて残り、ベンダーのベースラインにリセットすることもできます。加算的なモデルを念頭に置いてください。まとまりのある機能の束を作成し、「減算のセット」は決して作らないでください。[権限セット](/docs/configure/permissions/permission-sets)を参照してください。 + +要件を変更に落とし込むときは、対応する層を選びます。 + +| 要件 | 層 | 扱っている場所 | +|---|---|---| +| オブジェクトの種類を読み取り / 作成 / 編集 / 削除できる | オブジェクトの権限 | [権限セット](/docs/configure/permissions/permission-sets) | +| 特定のフィールドを見られる / 編集できる | フィールドレベルのセキュリティ | [フィールドレベルのセキュリティ](/docs/configure/permissions/field-level-security) | +| ユーザーがどの*行*を見るか | レコードアクセス | [レコードアクセス](/docs/configure/permissions/record-access) | +| オブジェクトのレコードを一括エクスポートできる | オブジェクトの権限:`allowExport`。読み取りでは与えられ**ない**オプトインの付与です | [Export is its own grant](/docs/configure/permissions/permission-sets#export-is-its-own-grant) | +| 機能上の能力(ユーザーの管理、監査ログの表示) | システムの権限 | [権限セット](/docs/configure/permissions/permission-sets#system-permissions) | +| アプリやナビゲーションのエントリを開ける | アプリケーションへのアクセス | [権限セット](/docs/configure/permissions/permission-sets) | + +## よく使う手順 [#quick-paths] + +| やりたいこと | すること | +|---|---| +| 新しい従業員を迎え入れる | ユーザーを Invite/Create → Business Unit Member の行 → ポジションを割り当てる | +| 誰かを退社させる | **Ban User**(サインインを即座にブロック)、その後で割り当てを落ち着いて削除する | +| 「サインインできない」 | ユーザーのレコード → Ban されている?ロックされている?**Unlock Account** または **Set Password**(一時的で、変更が必須) | +| 「なぜ X が見えないのか?」 | Studio → Access → そのユーザー + オブジェクトについて **Explain access** | +| 誰かが部署を移った | その人の Business Unit Member の行を更新し、User Position の行を付け直す | +| 子会社に自社のスタッフを管理させる | [委任された管理のスコープ](/docs/configure/permissions/permission-sets#delegated-administration)を持つセットを付与する | +| 1 人のユーザーに機能を 1 つ追加する | 権限セットのレコード → **Assigned Users** → 追加(直接の付与) | + +## どこに何があるか [#where-is-everything] + +| もの | 場所 | +|---|---| +| ユーザー、招待 | Setup → People & Organization → Users / Invitations | +| 事業単位のツリー | Setup → People & Organization → Business Units | +| チーム | Setup → People & Organization → Teams | +| ポジション、権限セット | Setup → Access Control | +| 共有ルール、レコードの共有 | Setup → Access Control | +| パスワードのポリシー、MFA、ロックアウト、SSO | Setup → Configuration → Authentication | +| セッション、通知のイベント、監査ログ | Setup → Diagnostics | +| 権限のマトリクスエディター、Explain access | Studio → Access | + +## 次に進む [#where-to-go-next] + +| タスク | ページ | +|---|---| +| ユーザーを作成し、組織ツリーを作る | [ユーザーと組織](/docs/configure/users) | +| ポジションと対象者のアンカーを理解する | [ポジション](/docs/configure/permissions/positions) | +| 権限セットを作成または調整する | [権限セット](/docs/configure/permissions/permission-sets) | +| 人がどの行を見るかを制御する | [レコードアクセス](/docs/configure/permissions/record-access) | +| 機密性の高いフィールドを隠す、またはロックする | [フィールドレベルのセキュリティ](/docs/configure/permissions/field-level-security) | +| サインインのポリシーと SSO | [認証](/docs/configure/authentication) | diff --git a/content/docs/configure/permissions/permission-sets.ja.mdx b/content/docs/configure/permissions/permission-sets.ja.mdx new file mode 100644 index 00000000..3d5bf139 --- /dev/null +++ b/content/docs/configure/permissions/permission-sets.ja.mdx @@ -0,0 +1,152 @@ +--- +title: 権限セット +seoTitle: "権限セット:オブジェクト、フィールド、システムの付与" +description: アプリケーション、オブジェクト、フィールド、システムの権限を付与します。 +editions: [community, cloud, enterprise] +translation: + source_sha: a358f4bda450dc16411f50560d7b6c74d2257257f89d2e6a509da19a9b8f70eb + guide_rev: 1 + mode: auto +--- + +権限セットは、機能を付与する主な方法です。ユーザーに直接、または[ポジション](/docs/configure/permissions/positions)を通じて間接的に割り当てられます。割り当ては `valid_from` / `valid_until` の期間を持てます。期限切れの付与は即座に解決されなくなります。 + +## 権限セットが制御するもの [#what-permission-sets-control] + +| 権限の種類 | 例 | +|---|---| +| アプリケーションへのアクセス | ユーザーが CRM や Setup を開ける | +| オブジェクトの権限 | レコードを作成、読み取り、更新、削除する | +| フィールドの権限 | 選んだフィールドを読み取る、または更新する | +| システムの権限 | Setup にアクセスする、レポートを実行する、監査ログを表示する | +| 連携の権限 | API キー、Webhook、管理アクションを使う | + +## オブジェクトの権限 [#object-permissions] + +オブジェクトの権限は次の問いに答えます。 + +```text +Can this user perform this operation on this object at all? +``` + +権限セットの付与は、次のフラグの名前を使います(セキュリティプラグインの権限評価器が強制するとおりです)。 + +| フラグ | 意味 | +|---|---| +| `allowRead` | レコードアクセスのルールが許すレコードを読み取ります | +| `allowCreate` | レコードを作成します | +| `allowEdit` | レコードアクセスのルールが許すレコードを更新します | +| `allowDelete` | レコードアクセスのルールが許すレコードを削除します | +| `allowExport` | オブジェクトのレコードの、機械可読な一括コピーを取ります | +| `viewAllRecords` | レコードアクセスをすり抜けて、そのオブジェクトのすべてのレコードを読み取ります | +| `modifyAllRecords` | レコードアクセスをすり抜けて、そのオブジェクトのすべてのレコードを更新または削除します。読み取りについては `viewAllRecords` を含意します | + +`viewAllRecords` または `modifyAllRecords` が通常の行レベルの境界をすり抜けない限り、[レコードアクセス](/docs/configure/permissions/record-access)は引き続き重要です。これらのフラグは管理用の権限セットのために取っておいてください。事実上、そのオブジェクトについてのテナント全体のスーパーユーザーの付与です。 + +### エクスポートは独立した付与 [#export-is-its-own-grant] + +エクスポートはシステムの権限ではなく**オブジェクトの権限**であり、**オプトイン**です。 + +| `allowExport` | 結果 | +|---|---| +| 未設定 | エクスポートは**拒否** | +| `false` | 拒否 | +| `true` | 許可(引き続き `allowRead` の範囲内) | + +以前は、未設定は「読み取りを継承する」を意味していました。ObjectStack 17.0 以降は拒否を意味し、`viewAllRecords` / `modifyAllRecords` もそれを与えなくなりました。「すべてのデータを見てよい」と「その一括コピーを取ってよい」は、意図的に別の付与になっています。 + +```ts +// Keys of a permission set; its other keys are omitted. +objects: { + deal: { allowRead: true, allowExport: true }, // ← add the grant +} +``` + +計画しておくべき 3 つの結果: + +- **この付与を持つ提供済みのセットはなく、それを取り去るのはアップグレードです。** パッケージで提供されるセットはアップグレード時に再投入され、ObjectStack 17.1 以降、`admin_full_access`、`organization_admin`、そこから派生した `organization_admin_no_bypass` は、ワイルドカード `*` でエクスポートを付与しなくなりました。自動的な代替は意図的に用意されていません。エクスポートは、アプリ自身の権限セットの中で、オブジェクトごとに付与されます。管理者によるエクスポートを意図するところでは、自分で作成するセットで `allowExport` を明示的に付与してください。**環境で作成されたセットも、これを持ったことはありません**。ユーザーがエクスポートするカスタムのセットはすべて編集してください。パースの時点では何も失敗しないので、何も編集しないアップグレードは有効なメタデータのままで、その管理者は、どのアプリのセットも指定していないすべてのオブジェクトで、気づかないうちにエクスポートを失っています。 +- **`member_default` は意図的にこの付与を持ちません**。そのため一般の認証済みユーザーは、管理者が付与するまでエクスポートを失います。それがこの切り替えの目的であって、見落としではありません。 +- **`allowExport` を持つセットは高権限です**。そのため `everyone` や `guest` の対象者のアンカーにバインドすることはできません。そうでなければ、エクスポートできるセットを匿名のアンカーにバインドすることで、オプトインを無効にできてしまいます。 + +マージは CRUD のビットとまったく同じく、最も許容的なものが採用されます。割り当てられたセットのどれかが `true` を付与していればエクスポートが付与され、`false` と未設定は同じ結果になります。レポートも同じ軸で扱われます。 + +## システムの権限 [#system-permissions] + +システムの権限は、次のようなプラットフォームの操作のためのものです。 + +- Setup へのアクセス +- ユーザーの管理 +- ポジションと権限セットの管理 +- レポートの実行 +- 連携の管理 +- 監査ログの表示 + +管理者が簡単に監査できるように、システムの権限は業務オブジェクトの権限と分けておいてください。 + +## 推奨されるセット [#recommended-sets] + +名前付きのいくつかの権限セットから始めます。 + +| 権限セット | 目的 | +|---|---| +| Basic User | ログインし、メインのアプリケーションにアクセスする | +| Setup Administrator | ユーザー、ロール、設定、診断を管理する | +| Report Viewer | レポートとダッシュボードを表示する | +| Integration Operator | Webhook / API キーを管理する | +| Support User | サポートのオブジェクトを読み取る / 更新する | + +その後、顧客のアプリケーションのためのドメイン固有のセットを追加します。 + +セットに `isDefault` を付けると、そのセットを所有するパッケージがインストールされたときに、割り当ての候補として提案されます(13 より前の `isProfile` フラグを置き換えるものです)。 + +## 権限セットを無効にする [#deactivating-a-permission-set] + +権限セットの **Deactivate** アクションは、その付与を即座に止めます(ObjectStack 17.1)。無効化されたセットは、ユーザーに直接届く場合もポジションを通じて届く場合も、オブジェクト、フィールド、システム、タブの権限を何も与えず、本来与えるはずの管理者としての立場も与えません。`active` の値が空のセットは影響を受けません。数えられるのは明示的な無効化だけです。 + +2 つの結果: + +- **これで全員を締め出すことはできません。** 管理者を管理者たらしめているセットを無効にしようとすると、それを削除しようとしたときと同じ「最後の管理者」のガードによって拒否されます。 +- **17.1 を越えるアップグレードは取り消しです。** 17.1 より前はこのスイッチは何もしておらず、無効化されたセットも付与を続けていました。アップグレードの前に、無効化されたセットとポジションを一覧し、まだ付与を続けるべきものを再び有効にしてください。[ポジションを無効にする](/docs/configure/permissions/positions#deactivating-a-position)を参照してください。 + +## 委任された管理 [#delegated-administration] + +権限セットは、その保持者をスコープ付きの管理者にする `adminScope` を持てます。スコープは次のものを宣言します。 + +- 委任者が**どこで**操作できるか:事業単位のサブツリー +- **何を**できるか:`manageAssignments`、`manageBindings`、`authorEnvironmentSets` +- **どの**権限セットを配布できるか(`assignablePermissionSets`) + +委任者は、許可リストにあるセットに対してだけ単一の行を書き込み、すべての付与には監査のために `granted_by` が記録されます。それ自体が `adminScope` を持つセットを付与または作成するには、付与する側が、それを厳密に包含するスコープを持っている必要があります。テナントレベルの管理者は、このゲートを完全にすり抜けます。 + +## フィールドのセキュリティ(付録) [#field-security-appendix] + +権限セットはフィールドレベルの付与も持ちます。ユーザーがレコードを読める場合でも、個々のフィールドを隠したり、読み取り専用にしたりできます。 + +### 2 つのモード [#two-modes] + +| モード | 効果 | +|---|---| +| **非表示** | フィールドは API のレスポンスと生成されたビューから完全に取り除かれます | +| **読み取り専用** | フィールドは返されますが、書き込みは拒否されます | + +3 つ目の状態である**マスク**(`138****5678`)は、権限セットのモードではありません。フィールドに宣言されるもので、権限セットが決めるのは、マスクを外す機能を誰が持つかだけです。[Field-Level Security](/docs/configure/permissions/field-level-security#masked-fields) を参照してください。 + +### どこで強制されるか [#where-its-enforced] + +オブジェクトの権限をチェックするのと同じ評価器が、REST、ObjectQL、生成されたフォーム、エクスポートのすべての経路でフィールドのルールを適用します。下位レベルの API を通る「裏口」はありません。 + +### 典型的なパターン [#typical-patterns] + +| ユースケース | 推奨 | +|---|---| +| `sys_user` の人事データ(給与、社会保障番号) | `HR` 権限セット以外の全員から隠す | +| 外部システムの識別子 | サポートには読み取り専用、連携の運用者には書き込み可能 | +| `product` の社内コストと顧客価格 | `cost` を営業から隠し、財務には表示する | +| 保護対象の医療情報を含むメモのフィールド | 権限セットが該当する臨床上のロールを含まない限り隠す | + +### 作成のガイダンス [#authoring-guidance] + +- フィールドが機密性の高いデータを持つ場合は、読み取り専用ではなく**非表示**をデフォルトにします。読み取り専用でも、値はレスポンスとログに漏れます。 +- フィールドの権限のキーは、常に**オブジェクトで修飾して**書きます(`budget` ではなく `crm_lead.budget`)。ObjectStack 14.4 以降、`security-fls-unqualified-key` の lint はコンパイル時に素のキーを拒否します。それらは黙って何にも一致していなかったからです。 +- フィールドごとに 1 つのセットを作るのではなく、実際の職務(`HR Manager`、`Finance Read-only`)に合った権限セットにフィールドのルールをまとめます。監査が簡単になります。 +- コンプライアンスのユースケースでは、フィールドのセキュリティと監査ログの保持を組み合わせ、後から「誰がこの行を見たか?」に答えられるようにします。 diff --git a/content/docs/configure/permissions/positions.ja.mdx b/content/docs/configure/permissions/positions.ja.mdx new file mode 100644 index 00000000..bc3027a6 --- /dev/null +++ b/content/docs/configure/permissions/positions.ja.mdx @@ -0,0 +1,124 @@ +--- +title: ポジション +seoTitle: "ポジション:職務と対象者のアンカー" +description: ポジションで職務と対象者のアンカーをモデル化します。 +editions: [community, cloud, enterprise] +translation: + source_sha: 9a6096331cd3521f789262b74df4f6d0c036eb8279faa0759092e883c35b050c + guide_rev: 1 + mode: auto +--- + +ポジションは、ユーザーが担う職務(「Sales Manager」、「Support Agent」、「Auditor」)を記述します。ObjectStack 13(Permission Model v2、ADR-0090)以降、ポジションは人をグループ化する**唯一の**概念です。旧来の Role と Profile の枠組みはポジションに統合され、プロトコルから削除されました。 + +ポジションは意図的に**フラット**です。`parent` フィールドもポジションの階層もありません。報告の構造とサブツリーに基づく表示範囲は、代わりに[事業単位のツリー](/docs/configure/permissions/record-access)にあります。 + +## ポジションの役割 [#position-responsibilities] + +ポジションは次のもののモデル化に使います。 + +- 職務(「Sales Manager」、「Recruiter」、「Auditor」) +- アプリ、タブ、ブックの対象者の指定 +- 承認の責任(種類が `position` の承認者は、現在の保持者に自動的に展開されます) +- 同じ職務を持つ全員への[権限セット](/docs/configure/permissions/permission-sets)の配布 + +組織図(部署、地域、上司 / 部下の構造)のモデル化には**事業単位**を、オブジェクト、フィールド、システムの具体的な機能の付与には**権限セット**を使います。 + +## システムオブジェクト [#system-objects] + +| オブジェクト | 目的 | +|---|---| +| `sys_position` | ポジションの定義(フラット。階層なし) | +| `sys_user_position` | ユーザーのポジションへの割り当て | +| `sys_position_permission_set` | ポジションを通じて配布される権限セット | +| `sys_business_unit` | 階層とサブツリーの共有に使う組織図のツリー | +| `sys_business_unit_member` | 事業単位におけるユーザーのメンバーシップ(`function_in_business_unit`) | + +RBAC のリンクテーブル(`sys_user_position`、`sys_position_permission_set`、`sys_user_permission_set`、`sys_permission_set`)への書き込みには、テナントレベルの管理者権限か[委任された管理のスコープ](/docs/configure/permissions/permission-sets#delegated-administration)が必要です。それらのテーブルに対する単なる CRUD の付与では足りません。 + +## 対象者のアンカー:`everyone` と `guest` [#audience-anchors-everyone-and-guest] + +すべてのデプロイメントには、システム管理の 2 つのポジションが初期投入されています。 + +| アンカー | 保持者 | +|---|---| +| `everyone` | 認証されたすべてのプリンシパル(暗黙的に) | +| `guest` | セッションのない(匿名の)HTTP のプリンシパルだけ | + +サインインしたすべてのユーザーにベースラインを付与するには、権限セットを `everyone` にバインドします。バインディングは加算的で、プラットフォームは高権限のセット(View All / Modify All、delete/purge/transfer、システムの権限、ワイルドカード)をこれらのアンカーにバインドすることを拒否します。 + +**`guest` は何も付与しません。** オブジェクトのデータへの匿名のアクセスは、すべての HTTP の画面で拒否され(ObjectStack 17.0)、`guest` アンカーへのどのバインディングも、匿名の呼び出し元に権限セットを与えません(ObjectStack 17.6)。匿名の訪問者に何かを公開するには、代わりに画面を宣言します。[公開フォーム](/docs/build/interface/views#public-forms)や共有リンクで、それぞれ宣言したものだけを認可します。 + +設定されたベースラインの権限セット(`fallbackPermissionSet`、デフォルトは `member_default`)は、同じ `everyone` のバインディングの経路で適用されます。ObjectStack 14.2 以降、メンバーのベースラインには**削除**が含まれなくなったことに注意してください。レコードの削除は、ポジションで配布される権限セットを通じて、オブジェクトごとに明示的に付与しなければなりません。 + +**権限セットを持たない呼び出し元は拒否のベースラインを得ます**(ObjectStack 17.6)。権限セットをまったく解決しないリクエスト(匿名のリクエスト、または存在しないセットだけを指定するリクエスト)は、すべてのオブジェクトで `403 PERMISSION_DENIED` で拒否されます。`requiredPermissions` でゲートされたフィールドは提供されず(フィールドが `maskingRule` を宣言していればマスクされて提供されます)、そのフィールドでフィルター、並べ替え、グループ化、書き込みをすることもできません。ベースラインのセットが設定されている限り、サインインしたユーザーは影響を受けません。デフォルトの `member_default` は、彼らについて常に解決されます。 + +## ポジションを無効にする [#deactivating-a-position] + +ポジションの **Deactivate** アクションは、それが与えるものすべてを即座に取り除きます(ObjectStack 17.1)。 + +- 権限セットを何も配布しなくなり、その名前は保持者の `current_user.positions` から外れます。 +- そのポジションを受け手とする共有ルールは誰とも共有しなくなり、すでに付与していたレコードの共有は次の再調整で取り消されます。 + +無効化が止めるのはアクセスであって、宛先の指定ではありません。種類が `position` の承認者を持つ承認ステップは、無効化されたポジションの保持者に引き続き回されます。`active` の値が空のポジションは影響を受けません。数えられるのは明示的な無効化だけです。 + +> ObjectStack 17.1 より前は、このスイッチは何もしていませんでした。無効化されたポジションも付与を続けていました。それを越えてアップグレードすると、稼働中のデータでそのアクセスが取り消されるので、まだ付与を続けるべき無効化されたポジションは、アップグレードの前に再び有効にしてください。 + +## 有効期間付きの割り当て [#effective-dated-assignments] + +ポジションと権限セットの割り当ては、省略可能な `valid_from` / `valid_until` の期間(半開区間、UTC。null は無制限)を持ちます。期限切れの付与は即座に解決されなくなります。一時的な代行、契約社員、資格に結び付いたアクセスに便利です。各付与には `reason` を、委任の場合は `delegated_from` も記録できます。 + +`delegatable: true` とマークされたポジションは、その現在の保持者が、期間を区切って(将来の `valid_until` で、上限は 30 日、理由は必須)別のユーザーに自分で委任することを許します。管理のスコープを持つ権限セットを配布するポジションは、決して委任可能にはできません。 + +## 推奨されるパターン [#recommended-pattern] + +職務の形をした、小さく安定したポジションの集合を保ちます。 + +```text +Sales Manager +Sales Representative +Support Manager +Support Agent +``` + +組織図は事業単位としてモデル化します。 + +```text +Sales + ├─ EMEA + └─ AMER +Support +``` + +そして、機能のために権限セットをポジションに付けます。 + +```text +Sales Manager position + -> CRM User + -> Sales Manager Access + -> Report Viewer +``` + +こうすれば、権限が独立して変化していく間も、ポジションは安定したままです。 + +## 避けるべきこと [#avoid] + +- ユーザー 1 人ごとに 1 つのポジションを作ること +- すべての権限をすべてのポジションに重複させること +- ポジションの名前をビジネスロジックのチェックに使うこと +- ポジションで階層を作り直すこと。サブツリーの表示範囲は、事業単位と[レコードの共有](/docs/configure/permissions/record-access)の役割です +- レコードの共有のほうがより正確なのに、マネージャーのポジションを通じて広いアクセスを付与すること + +## ロールからの移行(13 より前) [#migrating-from-roles-pre-13] + +ObjectStack 12 以前に対して作成されたメタデータをアップグレードする場合: + +| 旧来 | 現在 | +|---|---| +| `sys_role` / `sys_user_role` / `sys_role_permission_set` | `sys_position` / `sys_user_position` / `sys_position_permission_set` | +| `defineRole` / `RoleSchema`(`parent` 付き) | `definePosition` / `PositionSchema`(フラット) | +| メタデータの種類 `role` または `profile` | `position` | +| 共有の受け手 `role` / `role_and_subordinates` | `position` / `unit_and_subordinates` | +| `PermissionSetSchema.isProfile` | 削除されました。`isDefault` がインストール時の推奨をマークします | + +ロールの階層は、事業単位のツリーとしてモデル化し直す必要があります。`os lint` は、`security-role-word` ルールで残っているロールの語彙を指摘します。 diff --git a/content/docs/configure/permissions/record-access.ja.mdx b/content/docs/configure/permissions/record-access.ja.mdx new file mode 100644 index 00000000..21a05701 --- /dev/null +++ b/content/docs/configure/permissions/record-access.ja.mdx @@ -0,0 +1,104 @@ +--- +title: レコードアクセス +seoTitle: "レコードアクセス:共有モデル、ルール、共有" +description: オブジェクトの権限が許した後に、ユーザーがどのレコードを見たり変更したりできるかを制御します。共有モデルのデフォルト、テナントの分離、共有ルール、レコードの共有です。 +editions: [community, cloud, enterprise] +translation: + source_sha: 7b46161549b128c59dc28ff67e96983da80e27b14b32166a87dd0fe2b00e1789 + guide_rev: 1 + mode: auto +--- + +レコードアクセスは、オブジェクトの権限が操作を許した後に、ユーザーがどの行を見たり変更したりできるかを制御します。 + +## 仕組み [#mechanisms] + +| 仕組み | 目的 | +|---|---| +| 行レベルセキュリティ | テナントまたは組織の分離を強制します | +| 共有ルール | 宣言的な条件に基づいてアクセスを付与します | +| レコードの共有 | 特定のユーザー、チーム、ポジション、事業単位、または単位とその配下にアクセスを付与します | +| 所有 / 階層 | 所有者と事業単位のツリーを通じてアクセスを付与します | + +## 共有モデルのデフォルト [#sharing-model-defaults] + +すべてのオブジェクトは、組織全体のデフォルトを設定する `sharingModel` を宣言(または継承)します:`private`、`public_read`、`public_read_write`、`controlled_by_parent`。 + +ObjectStack 13 以降、所有者のフィールドを持ち `sharingModel` を宣言していないカスタムオブジェクトのデフォルトは**非公開**です。レコードは、共有ルール、レコードの共有、またはより広いデフォルトが公開するまで、その所有者(と管理者)にだけ見えます。開いた動作に戻すには、モデルを明示的に宣言します。 + +```ts +ObjectSchema.create({ + name: 'crm_lead', + sharingModel: 'public_read_write', + fields: { + company: Field.text({ label: 'Company' }), + // … + }, +}); +``` + +13 より前のエイリアス `read`、`read_write`、`full` は削除されました。`os compile` は、`security-owd-unset` と `security-owd-alias` の lint で、未設定またはエイリアスのモデルを指摘します。 + +## デフォルトのテナント分離 [#default-tenant-isolation] + +セキュリティプラグインは、現在のユーザーのコンテキストを通じてテナントの分離を強制します。標準のプラットフォームのオブジェクトでは、通常の組織フィールドを持たないグローバルなテーブルを、デフォルトのルールが保護します。 + +顧客が実際に期待するのは次のことです。 + +```text +Users only see records that belong to their organization or records +explicitly shared with them. +``` + +## 共有ルール [#sharing-rules] + +共有ルールは、繰り返し適用される業務上のポリシーに使います。 + +- すべての地域マネージャーは、自分の地域の取引先を読める +- サポートマネージャーは、エスカレーションされたケースを見られる +- 財務は、承認済みの請求書を読める +- 監査担当者は、監査レビューのタグが付いたレコードを読める + +ルールはフィールドの値に対する CEL の `condition` で、作成時に行のフィルターにコンパイルされます。一致したレコードは、解決された受け手(ユーザー、チーム、ポジション、事業単位、または単位とその配下)に対する `sys_record_share` の付与を具体化します。作成できる形式は `criteria` ルールだけです。 + +### どちらのスイッチも安全側に倒れる [#both-switches-fail-closed] + +読み手が当然そう思ってよいことで、ObjectStack 17.0 以降にようやく真になった 2 つのことです。 + +- **条件のない共有ルールは何も共有しません。** 条件の述語なしに保存されたルールは、以前は*オブジェクトのすべてのレコード*(空のフィルター)として評価されていたので、検証されない書き込み経路を通った入力ミスが、黙ってテーブル全体を公開していました。すべてに一致する条件を書くことは今は拒否され、評価器は空の条件を**何にも**一致しないものとして扱います。 +- **`enabled: false` の RLS ポリシーは無効です。** 以前は、オフにしたポリシーも OR 分岐の付与を加え続けていたので、ポリシーをオフにしてもアクセスは取り除かれませんでした。今は、無効なポリシーは単に評価されません。 + +以前のリリースでアクセスを監査し、「このルールは何も付与していない」や「このポリシーはオフだ」と結論づけた場合は、[explain エンジン](/docs/configure/permissions#diagnose--audit)を再実行する価値があります。答えは、メタデータが示していたより広かったかもしれません。 + +## 行レベルセキュリティは強制できないものを拒否する [#row-level-security-refuses-what-it-cannot-enforce] + +ObjectStack 17.5 以降、RLS ポリシーは書かれているとおりに正確に絞り込むか、拒否するかのどちらかです。 + +- **`check` のないポリシーは、その `using` で書き込みをゲートします。** `check` のデフォルトは `using` であると常に記載されていましたが、書き込みに適用されていたのは `check` を宣言したポリシーだけだったので、ユーザーは読み戻せない行を書き込めていました。単一行の挿入や ID による更新で、その結果が適用されるすべての書き込みポリシーの `using` の外にある場合、今は `403 PERMISSION_DENIED` で応答します。書き込みを読み取りの範囲の外に置くことを意図したポリシーは、それを認める `check` を宣言しなければなりません。 +- **強制できない述語は拒否します。** フィールドをリストと比較する(`record.status != ['closed', 'archived']`)、`current_user.id` ではなく素の `current_user` と比較する、またはオブジェクトが宣言していないフィールドを指定すると、拒否するために書いたはずの行や書き込みそのものを認めてしまう可能性がありました。そのようなポリシーは今は安全側に倒れて失敗します。読み取りは行を返さず、書き込みは `403` で応答します。 +- **書き込みは保存される行で判定されます。** `check` と組織の壁は、`beforeInsert` / `beforeUpdate` のフックが実行された後の、エンジンが保存するとおりの行を見ます。 + +`os validate` は、出荷する前にこれらの形を報告し(`rls-predicate-unenforceable`、`rls-predicate-unknown-field`)、メタデータの保存の入口は、それを持つ権限セットを拒否します(`422 INVALID_METADATA`)。 + +## レコードの共有 [#record-shares] + +レコードの共有は例外のために使います。 + +- 1 件の商談を専門家と共有する +- エスカレーションの間、一時的なアクセスを付与する +- 外部の連携に特定のレコードへのアクセスを与える + +## 表示範囲のトラブルシューティング [#troubleshooting-visibility] + +ユーザーがレコードを見られないときは、次の順で確認します。 + +1. ユーザーは認証されていて、想定した組織にいるか? +2. ユーザーはオブジェクトの `read` 権限を持っているか? +3. オブジェクトの `sharingModel` は何か(ObjectStack 13 以降、カスタムオブジェクトのデフォルトは `private`)? +4. 行レベルセキュリティはそのレコードを許しているか? +5. 適用されるべき共有ルールはあるか? +6. 直接のレコードの共有はあるか? +7. レコードは、想定した事業単位のサブツリーにいるユーザーが所有しているか? +8. ユーザーは正しいプロジェクト / ホスト名を見ているか? + +[explain エンジン](/docs/configure/permissions#diagnose--audit)は、これらすべてに 1 回の呼び出しで答えます。各層の判定と、どの付与(または欠けている付与)が結果を決めたかを報告します。 From c74c76af73abe379c6dc5908bc65b3979548b19f Mon Sep 17 00:00:00 2001 From: Steedos Date: Thu, 29 Oct 2026 13:48:59 +0000 Subject: [PATCH 09/22] docs(i18n): translate deploy/ and operate/ into ja (#388, PR 5 of 7) Adds ja translations for the 4 deploy/ pages (index, docker, kubernetes, air-gapped) and the 7 operate/ pages. Both sections' meta.ja.json already match the English pages list. Same rules as the earlier batches. check-translations: ja 0 stale, 15 missing (was 26). Refs #388 Claude-Session: https://claude.ai/code/session_01QsR2jRsjbApbf83iyTDDXm Co-Authored-By: Claude --- content/docs/deploy/air-gapped.ja.mdx | 74 +++++ content/docs/deploy/docker.ja.mdx | 299 ++++++++++++++++++++ content/docs/deploy/index.ja.mdx | 83 ++++++ content/docs/deploy/kubernetes.ja.mdx | 112 ++++++++ content/docs/operate/audit-logs.ja.mdx | 114 ++++++++ content/docs/operate/backup.ja.mdx | 144 ++++++++++ content/docs/operate/index.ja.mdx | 38 +++ content/docs/operate/observability.ja.mdx | 96 +++++++ content/docs/operate/production.ja.mdx | 110 +++++++ content/docs/operate/troubleshooting.ja.mdx | 113 ++++++++ content/docs/operate/upgrade.ja.mdx | 142 ++++++++++ 11 files changed, 1325 insertions(+) create mode 100644 content/docs/deploy/air-gapped.ja.mdx create mode 100644 content/docs/deploy/docker.ja.mdx create mode 100644 content/docs/deploy/index.ja.mdx create mode 100644 content/docs/deploy/kubernetes.ja.mdx create mode 100644 content/docs/operate/audit-logs.ja.mdx create mode 100644 content/docs/operate/backup.ja.mdx create mode 100644 content/docs/operate/index.ja.mdx create mode 100644 content/docs/operate/observability.ja.mdx create mode 100644 content/docs/operate/production.ja.mdx create mode 100644 content/docs/operate/troubleshooting.ja.mdx create mode 100644 content/docs/operate/upgrade.ja.mdx diff --git a/content/docs/deploy/air-gapped.ja.mdx b/content/docs/deploy/air-gapped.ja.mdx new file mode 100644 index 00000000..5f30ad90 --- /dev/null +++ b/content/docs/deploy/air-gapped.ja.mdx @@ -0,0 +1,74 @@ +--- +title: エアギャップデプロイメント +seoTitle: "エアギャップデプロイメント:ライセンスモードと設定" +description: エアギャップはファイアウォールの設定ではなくライセンスモードです。切断されたデプロイメントが宣言しなければならない 2 つの設定と、起動時に拒否される組み合わせを説明します。 +editions: [enterprise] +translation: + source_sha: d0fbf234ac1fc9be7bcdb652e29a259e133103a63533267bf3f065bdee48ce9b + guide_rev: 1 + mode: auto +--- + +## エアギャップはライセンスモードである [#air-gap-is-a-license-mode] + +ネットワークを抜くだけでは、エアギャップのデプロイメントにはなりません。通常の ObjectOS ライセンスは**オンライン**で検証されます。ランタイムはコントロールプレーンでライセンスキーを短期のエンタイトルメントと交換し、定期的に再確認します。その経路を断つと、ライセンスは「オフラインにフォールバック」するのではなく、そもそも一切有効になりません。 + +**エアギャップライセンスは別のライセンス**であり、私たちが意図的にオフラインで発行します。イメージに埋め込まれた公開鍵に対してローカルで検証され、**ネットワークトラフィックなし**でエンタイトルメントを有効にします。エアギャップ運用は Enterprise の機能であり([ライセンスと料金](/docs/editions/license)を参照)、必要なライセンスは設定するものではなく申請するものです。 + +したがって、切断されたデプロイメントは次の **2 つ**を同時に宣言します。 + +- **エアギャップライセンス** +- **コントロールプレーンなし**:クラウドの姿勢の設定を明示的に `off` にします(別名の `none`、`local`、`disabled` も同じ意味です) + +## 設定を未設定のままにすることは「クラウドなし」ではない [#leaving-the-setting-unset-is-not-no-cloud] + +これはこのページで最も高くつく間違いなので、専用の見出しを設けています。 + +> **未設定のクラウドの姿勢の設定は、公開コントロールプレーンに解決されます。** + +未設定は中立だったことは一度もありません。接続された動作を選びます。そのため、「何もしなかった」デプロイメントは、誰とも通信しないことが前提のサイトであるにもかかわらず、マーケットプレイスのプロキシがマウントされ、デバイスバインディングのルートが公開された状態になります。姿勢を宣言することは受け入れられますが、**決めないことは受け入れられません。** `off` を明示的に書いてください。 + +## サポートされる組み合わせ [#the-supported-combinations] + +これらは設定の読み込み時、ライセンスに関わる処理が始まる**前に**確認されます。サポートされない組み合わせは警告でも劣化でもありません。ランタイムは*両方*の設定を名指しした致命的エラーを表示して終了します。 + +| ライセンス | クラウドの姿勢 | 結果 | +|---|---|---| +| エアギャップライセンス | `off` | **ネットワークトラフィックなしで、完全にライセンスされた状態で動作します。** 切断環境の答えです。 | +| ライセンスなし | `off` | Community の動作で実行されます。マルチ組織の姿勢には引き続きライセンスが必要です。 | +| 通常の(オンライン)ライセンス | 到達可能なコントロールプレーン、デバイスバインディング完了済み | 通常の接続されたデプロイメント。 | +| 通常の(オンライン)ライセンス | `off` | **起動時に拒否されます。** | +| 通常の(オンライン)ライセンス | 未設定 | 公開コントロールプレーンとして扱われます(上記を参照)。動作するかどうかは、そのコントロールプレーンに実際に到達でき、バインドされているかどうかによります。 | + +### 拒否が存在する理由 [#why-the-refusal-exists] + +オンラインライセンスは、デプロイメントをコントロールプレーンにバインドする際に発行されたランタイムトークンを提示する交換によって検証されます。コントロールプレーンがなければバインディングもなく、トークンは存在しえず、交換は決して行われません。今回の起動でも、以降の起動でもです。猶予期間も役に立ちません。猶予は最後に*成功した*検証から計測されますが、最初の成功が永遠に来ないからです。 + +強制しなければ、その設定は後になって失敗し、間違ったものを責めます。マルチ組織の姿勢では、デプロイメントが「ライセンスを必要とする」という苦情で終わります。ライセンスこそが唯一間違っていなかったものなのにです。ランタイムは代わりに早い段階で拒否し、どの 2 つの設定が食い違っているかを示します。拒否はあらゆる検証の試行より前に行われるため、拒否された起動は**パケットを一切送信しません**。 + +## ホスト型のマルチ組織形態もエアギャップライセンスである [#the-hosted-multi-organization-shape-is-air-gap-licensed-too] + +**composed** 形態(公開済みアプリをこのデプロイメントのアプリとして起動し、分離の壁の背後で複数の組織が 1 つのデータベースを共有する)を実行する場合、そこでもエアギャップライセンスは任意ではありません。このモードはマーケットプレイスとクラウド接続のサーフェスを完全に拒否するため、オンラインライセンスに必要なバインディングがこのモードで行われることはありません。エアギャップライセンスと `off` が必須で、どちらも起動時に強制され、デプロイバンドル内に専用の環境テンプレートがあります。単一環境のテンプレートを手直ししてこの形態にしないでください。composed のテンプレートをコピーすれば、それが決めるすべての値が一緒についてきます。 + +## イメージをネットワーク内に持ち込む [#getting-the-image-inside-the-network] + +ObjectOS のランタイムイメージは、切断されたサイトからは到達できないプライベートレジストリにあるため、イメージは他の成果物と同じ方法で境界を越えます。 + +検証は、レジストリとツールがまだ使える接続側で行います。内部へ持ち込もうとしている正確なダイジェストについて、**署名**、**SBOM**、**ビルドの来歴**を確認します(コマンドはバンドルの README に記載されています)。あとは**ダイジェスト**に任せます。ダイジェストはコンテンツアドレスなので、ネットワーク内のコピーが同じダイジェストであることを確認すれば、それが検証したのと同じバイトであることの証明になります。デプロイメントがタグではなくダイジェストを固定するのもこのためです。境界の内側には、タグを再解決する相手がありません。 + +アップグレードも同じ方法で行います。新しいダイジェストを外部で検証し、内部に転送し、固定するダイジェストを変更して再起動します。以前のダイジェストは残しておいてください。エアギャップのネットワーク内では、それがロールバック先となる唯一のコピーかもしれません。 + +## 到達可能でなければならないもの [#what-still-has-to-be-reachable] + +エアギャップとは、*ObjectOS 自体が*必要とするトラフィックがないということです。ライセンスの検証も、マーケットプレイスも、更新の確認もありません。デプロイメントにネットワークがないという意味ではありません。境界の内側では、引き続き次のものが必要です。 + +- 設定されたデータベース(クラスター構成の場合は Redis も) +- インバウンドのイングレスまたはロードバランサー +- **あなたが**通信するよう設定したもの:アイデンティティプロバイダー、SMTP、オブジェクトストレージ、Webhook の送信先、AI プロバイダーのエンドポイント。ユーザーが OIDC でサインインする場合、そのアイデンティティプロバイダーにこのネットワークから到達できる必要があります。できない場合はローカルアカウントを使います。 + +ライセンス自体には有効期限があり、起動のたびにローカルで確認されます。外部への問い合わせはないため、更新はランタイムが取得するものではなく、納品として計画してください。 + +## 次へ [#next] + +- [Docker → Enterprise で追加されるもの](/docs/deploy/docker#enterprise-adds):検証、ライセンス、スケーリング、アップグレードの全体。 +- [アップグレード](/docs/operate/upgrade)と[バックアップ](/docs/operate/backup):上記の手順の詳細な手順書。 diff --git a/content/docs/deploy/docker.ja.mdx b/content/docs/deploy/docker.ja.mdx new file mode 100644 index 00000000..7a3ef42c --- /dev/null +++ b/content/docs/deploy/docker.ja.mdx @@ -0,0 +1,299 @@ +--- +title: Docker +seoTitle: "Docker:ObjectOS Community と Enterprise を実行する" +description: Docker で ObjectOS を実行します。イメージを固定し、必須の 3 つの変数を設定し、Compose で PostgreSQL を追加し、プローブとプロキシを接続し、アップグレードとロールバックを行います。Enterprise イメージでは、プライベートレジストリ、検証、ライセンスが加わります。 +editions: [community, enterprise] +translation: + source_sha: 7fb88e85e29666d6c9ec80215a289bfa2bbe75dc1a35ab842ddd53f33bf4ea72 + guide_rev: 1 + mode: auto +--- + +Docker は、自社のサーバーで ObjectOS を実行する標準的な方法です。手順はセルフマネージドの両エディションで同じです。正確に固定したひとつのイメージ、実行時に注入する設定、コンテナの外にあるデータベース。このページでは、オープンな **Community** イメージ `ghcr.io/objectstack-ai/objectstack` を使って手順を説明します。ライセンスされたイメージで変わる点は、最後の [Enterprise で追加されるもの](#enterprise-adds)のセクションで扱います。 + +## イメージを固定する [#pin-the-image] + +Community イメージは ObjectStack のリリースごとに公開されます。タグは内部の ObjectStack CLI のバージョンを反映しています。リリース `X.Y.Z` は `X.Y.Z` としてプッシュされ、`latest`、`X.Y`、`X` がそこへ移動します。移動するタグは公開のたびに動くため、`latest` に対する日常的な `docker compose pull` によって、デプロイの操作なしに実行中のバージョンが置き換わることがあります。 + +正確なタグが固定するのはバージョンであって、バイトではありません。メンテナーは、たとえば `node:22-slim` ベースイメージのセキュリティパッチを取り込むために、すでにリリースされたバージョンを再ビルドすることがあり、その再ビルドは同じ `X.Y.Z` タグを新しいイメージに再びプッシュします。内部の ObjectStack CLI は同じバージョンのままですが、ベースイメージと、バージョン範囲でインストールされるデータベースドライバーは新たに解決されます。[公開ワークフロー](https://github.com/objectstack-ai/objectstack/blob/main/.github/workflows/docker-publish.yml)がその再ビルドを宣言しています。同じバイトを永続的に指すのは**ダイジェスト**だけです。 + +**本番では正確なバージョンを実行してください。** アプリをビルドした CLI と同じバージョンです。そして、すべてのホストで、すべての再起動後に同じバイトが必要な場所では、そのダイジェストを固定します。ダイジェストはレジストリから読み取ります。 + +```bash +docker buildx imagetools inspect ghcr.io/objectstack-ai/objectstack:X.Y.Z +``` + +`Name:` の下にある最初の `Digest:` の行を固定します。これはイメージ全体(両方のアーキテクチャ)を指します。`Manifests:` の下に並ぶダイジェストは、それぞれ 1 つのプラットフォームを指します。そのダイジェストでイメージを参照し、ダイジェストからはどのリリースかわからないので、バージョンを横に書いておきます。 + +```bash +# ObjectStack X.Y.Z +ghcr.io/objectstack-ai/objectstack@sha256:<64 hex characters> +``` + +以前のバージョンとそのダイジェストは書き残しておいてください。それがロールバックです。イメージは `linux/amd64` と `linux/arm64` 向けに公開され、非 root ユーザーで実行され、ポート **8080** で待ち受け、独自のヘルスチェックを持っています。PostgreSQL(`pg`)と MySQL(`mysql2`)のドライバーが含まれています。 + +## 設定する 3 つの値 [#the-three-values-you-set] + +それ以外はすべて、使えるデフォルトがあります。次の 3 つにはありません。 + +| 変数 | ない場合に起きること | +|---|---| +| `OS_DATABASE_URL` | データはランタイムのホームディレクトリの下の SQLite ファイルに書き込まれます。永続的な単一ホストでは問題ありませんが、コンテナのファイルシステムとともに失われます。本番では `postgres://…` を使います。 | +| `OS_AUTH_SECRET` | `/api/v1/auth/*` の下のサインインエンドポイントが**スキップ**され、サーバーは認証なしで実行されます。 | +| `OS_SECRET_KEY` | ランタイムは保存されたシークレット用に独自のキーを生成し、自身のファイルシステムに保持します。コンテナではそのキーはコンテナとともに消え、それで暗号化されたすべてのシークレットが読めなくなります。 | + +2 つのシークレットは一度だけ生成し、シークレットマネージャーに保管します。 + +```bash +OS_AUTH_SECRET=$(openssl rand -hex 32) +OS_SECRET_KEY=$(openssl rand -hex 32) +``` + +**どちらのシークレットもイメージに焼き込まないでください。** オーケストレーターのシークレットストアから実行時に渡します。`OS_SECRET_KEY` はデータベースと一緒にバックアップします。キーなしで復元したデータベースは、自身のシークレットを復号できません。[バックアップ](/docs/operate/backup)を参照してください。完全な一覧は[環境変数](/docs/reference/environment-variables)にあります。 + +## 実行する [#run-it] + +イメージにはアプリが含まれていません。`os build` がコンパイルする `objectstack.json` を、次の 3 つの方法のいずれかで渡します。 + +**アーティファクトをマウントする。** イメージのビルドは一切不要です。イメージは `/srv/app/objectstack.json` でアプリを探します。 + +```bash +docker run -p 8080:8080 \ + -v "$PWD/dist/objectstack.json:/srv/app/objectstack.json:ro" \ + -e OS_DATABASE_URL="postgres://objectos:secret@db-host:5432/objectos" \ + -e OS_AUTH_SECRET \ + -e OS_SECRET_KEY \ + ghcr.io/objectstack-ai/objectstack:X.Y.Z +``` + +**アーティファクトを URL で指定する。** `OS_ARTIFACT_URL` は公開済みのアーティファクトを指します。固定したイメージと 1 つの変数で動くアプリになり、アプリのアップグレードはその変数の変更と再起動で済みます。 + +```bash +docker run -p 8080:8080 \ + -e OS_ARTIFACT_URL="https://releases.example.com/crm-2.2.2.json#sha256=<64 hex characters>" \ + -e OS_DATABASE_URL -e OS_AUTH_SECRET -e OS_SECRET_KEY \ + ghcr.io/objectstack-ai/objectstack:X.Y.Z +``` + +任意の `#sha256=` フラグメントはアーティファクトのバイトを固定し、ランタイムは起動時にそれを守ります。 + +| 状況 | ランタイムの動作 | +|---|---| +| 固定なし | 検証なしで起動します。アーティファクトを取得できない場合、オーケストレーターが再試行するよう起動は**失敗**します。フォールバックできるキャッシュはありません。 | +| 固定あり、バイトが一致 | 起動し、検証済みのコピーを保持します。 | +| 固定あり、バイトが不一致 | 期待するダイジェストと実際のダイジェストを示して**起動を拒否**します。 | +| 固定あり、ホストに到達不能 | キャッシュされたコピーが固定と一致する場合に限りそこから起動し、警告でその旨を表示します。 | + +マウントしたファイルには `file:///…` も使えます。アーティファクトは不変で、バージョン名の付いたオブジェクトとして公開し、書き込みアクセスはリリースパイプラインだけに与えてください。そうすることで、アプリのロールバックがロールフォワードと同じ操作になります。 + +**アーティファクトを自分のイメージにコピーする。** リリースごとに自己完結したイメージを 1 つ作ります。プロジェクトの雛形(`npm create objectstack`)が、この形の Dockerfile を書き出してくれます。 + +```dockerfile title="Dockerfile" +FROM node:22-slim AS build +WORKDIR /app +COPY package.json pnpm-lock.yaml* pnpm-workspace.yaml* package-lock.json* ./ +RUN if [ -f pnpm-lock.yaml ]; then corepack pnpm@10 install --frozen-lockfile; \ + else npm ci; fi +COPY . . +RUN npx os build # → dist/objectstack.json + +FROM ghcr.io/objectstack-ai/objectstack:X.Y.Z +COPY --from=build --chown=node:node /app/dist/objectstack.json /srv/app/objectstack.json +``` + +## PostgreSQL と Compose で構成する [#compose-with-postgresql] + +単一ホストの本番スタックです。上記のイメージと、その横のデータベース。 + +```yaml title="docker-compose.yml" +services: + app: + build: . + ports: + - "8080:8080" + environment: + OS_DATABASE_URL: postgres://objectos:${POSTGRES_PASSWORD}@db:5432/objectos + OS_AUTH_SECRET: ${OS_AUTH_SECRET} + OS_SECRET_KEY: ${OS_SECRET_KEY} + depends_on: + db: + condition: service_healthy + restart: unless-stopped + + db: + image: postgres:17 + environment: + POSTGRES_USER: objectos + POSTGRES_PASSWORD: ${POSTGRES_PASSWORD} + POSTGRES_DB: objectos + volumes: + - pgdata:/var/lib/postgresql/data + healthcheck: + test: ["CMD-SHELL", "pg_isready -U objectos -d objectos"] + interval: 5s + timeout: 3s + retries: 10 + restart: unless-stopped + +volumes: + pgdata: +``` + +```bash +# .env beside docker-compose.yml — never committed +POSTGRES_PASSWORD=… +OS_AUTH_SECRET=… +OS_SECRET_KEY=… + +docker compose up -d +curl -fsS http://localhost:8080/api/v1/health +``` + +マネージド PostgreSQL に移行するときは、`OS_DATABASE_URL` をそこに向けて `db` サービスを削除します。スキーマはランタイムの起動時に最新の状態にされます。安全な変更は自動的に実行され、破壊的な変更は、`os migrate apply --allow-destructive` で意図的に適用するまで、各変更を示して**起動を拒否**します([CLI](/docs/reference/cli#database-migrations--os-migrate))。 + +## ヘルスチェック [#health-checks] + +エンドポイントは 2 つあり、互換性はありません。 + +| エンドポイント | 答える内容 | 接続先 | +|---|---|---| +| `/api/v1/health` | プロセスが起動し、HTTP を提供している。データベースには一切触れません。 | Liveness | +| `/api/v1/ready` | ランタイムが起動し、**データドライバーが応答している**。応答しないドライバーがある間は、そのドライバーを示して `503` を返します。 | Readiness、およびロードバランサー | + +取り違えると、ひどい失敗になります。`/api/v1/ready` に対する liveness プローブは、データベースの障害時にすべてのレプリカを再起動させ(再起動では直りません)、設定の不具合を、それを隠す再起動ループに変えてしまいます。反応すべきなのは readiness です。データベースが不在の間はレプリカをローテーションから外し、データベースが戻れば再起動なしで元に戻します。アプリがバインドするデータソースも起動時に接続できなければならず、そうでなければ起動はその場で失敗します。到達できないデータベースはデプロイの失敗であり、起動してからすべてのリクエストでエラーを返すコンテナではありません。 + +## リバースプロキシと TLS [#reverse-proxy-and-tls] + +ランタイムの前段で TLS を終端し(Caddy、nginx、Traefik、またはクラウドのロードバランサー)、3 つの値を公開アドレスと揃えておきます。 + +```bash +OS_AUTH_URL=https://app.example.com # sign-in callbacks and cookie origin +OS_TRUSTED_ORIGINS=https://app.example.com # sign-in callback and CSRF allow-list +OS_PORT=8080 # the proxy's upstream port +``` + +```text title="Caddyfile" +app.example.com { + reverse_proxy localhost:8080 +} +``` + +ポートやオリジンのずれは、セルフホスティングの典型的な失敗です。アプリは動くのに、サインインは跳ね返され、ブラウザは API 呼び出しをブロックします。Console と API が同じ公開オリジンを共有している間は、CORS の設定は不要です。**別の**オリジンから提供されるフロントエンドは、`OS_CORS_ORIGIN` に明示的に列挙します。認証情報が有効な間、`*` は起動時に拒否されます。HSTS は TLS を確認してから有効にしてください。残りは[本番環境への準備](/docs/operate/production)にあります。 + +## 初回起動:最初の管理者 [#first-boot-the-first-administrator] + +新しいデータベースでは、デプロイメントのアドレスを開いて**登録します。最初のアカウントが管理者になります。** 最初のデプロイの直後、アドレスを共有する前に行ってください。本番サーバーはデフォルトの認証情報を投入しません。`os dev` で見覚えのある `admin@objectos.ai` アカウントは、開発用データベースにしか存在しません。 + +代わりに設定で管理者を指定するには、`OS_PLATFORM_OWNER_EMAIL` に 1 つのアドレスまたはカンマ区切りのリストを設定します。列挙された各アカウントは、メールアドレスが確認されるとその地位を持ちます。マルチ組織の姿勢ではこれが必須です。[環境変数](/docs/reference/environment-variables#multi-organization-deployments)を参照してください。 + +サインインアカウントなしで人のレコードを投入するアプリは、この入り口を閉ざします。最初のアカウントのルールは、ログインではなく人を数えるからです。起動ログにその旨が表示されます。[トラブルシューティング](/docs/operate/troubleshooting#nobody-can-sign-in)を参照してください。 + +## マルチノード [#multi-node] + +ObjectOS Community は**レプリカ 1 つ**で実行します。ロック、キュー、スケジュールといった調整はプロセス内にあるため、2 つ目のレプリカはそれを共有しません。ライセンスなしで複数のレプリカを宣言すると(`OS_CLUSTER_REPLICAS` が 1 より大きい)、プロセスごとのロックで実行するのではなく、**起動を拒否**します。クラスタリングと高可用性は Enterprise の機能です。後述の[マルチノード](#multi-node-on-enterprise)を参照してください。 + +## アップグレードとロールバック [#upgrade-and-rollback] + +1. 通過するすべての ObjectStack バージョンのリリースノートと、それらがオペレーターに求める[バージョン固有の手順](/docs/operate/upgrade#version-specific-steps)を読みます。 +2. **データベースをバックアップします。** スキーマのマイグレーションは前にしか進みません。イメージをロールバックしても、スキーマはロールバックされません。 +3. イメージを新しい正確なバージョン(ダイジェストを固定している場合はそのダイジェスト)に変更し、再起動します。スキーマは、ランタイムが準備完了を報告する前の起動時に最新の状態にされます。 +4. `/api/v1/ready` が 200 を返すことを確認します。 +5. ロールバックするには、以前のタグまたはダイジェストに戻して手順 3 を繰り返します。離れるバージョンが互換性のないスキーマ変更を行っていない限り有効です。 + +アプリは別にバージョン管理されます。`OS_ARTIFACT_URL` やマウントするアーティファクトを変更すれば、イメージに触れずにアプリをアップグレードできます。 + +## Enterprise で追加されるもの [#enterprise-adds] + +ライセンスされた Enterprise イメージも同じ方法で実行し、プライベートレジストリ、サプライチェーンの検証、ライセンス、マルチノードが加わります。固定すべきダイジェストはリリースノートに記載されています。リリースには**デプロイバンドル**が付属し、Compose スタック、デプロイメント形態ごとの環境テンプレート、そして正確なバージョンのコマンドを記載した README が含まれます。このセクションは、そのバンドルが設定するものの判断マップです。 + +### 提供されるもの [#what-you-are-given] + +ライセンスには、プライベートなランタイムイメージ用の**レジストリの認証情報**が付属します。サインインにはパッケージの **read** アクセスを持つトークンが必要です。公開の Enterprise イメージやソースからのビルドはありません。イメージは、配布されないソースから私たちのリリースパイプラインが生成するため、`docker build` という手段は存在しません。 + +**サポートされるアーキテクチャ:`linux/amd64` のみ。** これは記載漏れではなく宣言です。ビルドは、宣言していないアーキテクチャのイメージの生成を拒否します。Apple Silicon や Graviton のホストではエミュレーションで実行されることになり、試すには問題ありませんが、本番には不適切です。 + +### ダイジェストでイメージを固定する [#pin-the-image-by-digest] + +本番で実行するイメージの参照は、タグではなく**ダイジェスト**です。 + +``` +OS_EE_IMAGE=@sha256:<64 hex characters> +``` + +タグは人が読める名前であり、別のバイトに付け替えられることがあります。ダイジェストはコンテンツアドレスです。同じダイジェストは、どのホストでも永遠に同じイメージです。タグでは、問題が起きたときに実際に何が動いていたかを後から証明する方法がありません。ダイジェストはリリースノートに記載されているので、そのまま貼り付けてください。**以前の**ダイジェストも残しておきます。 + +### イメージは自分が何であるかを示せる [#the-image-can-tell-you-what-it-is] + +イメージには 2 つの異なるバージョン番号が付いており、混同してはいけません。ObjectOS の**製品バージョン**と、それに組み込まれた **ObjectStack ランタイムの互換性範囲**で、後者は独自のスケジュールで動きます。どちらも、イメージのビルド元となったソースのリビジョンとともに、OCI ラベルおよび機械可読なリリースマニフェストとしてイメージ自体の中に記録されています。どのビルドを持っているかを私たちに尋ねる必要はありません。 + +このマニフェストは、サポートリクエストに添付するものとして最も役立つものでもあります。それだけで正確なイメージを再現できます。 + +### 本番の前にイメージを検証する [#verify-the-image-before-production] + +イメージは(リリースパイプラインの OIDC アイデンティティによるキーレス方式で)**署名**されており、**SBOM** と**ビルドの来歴**が付属します。本番へのロールアウトの前に一度検証してください。3 つのチェックは、それぞれ異なる問いに答えます。 + +| チェック | 答える問い | +|---|---| +| 署名 | このダイジェストは、他の誰かではなく ObjectOS のリリースパイプラインによって生成されたか | +| SBOM | このイメージの中に何が入っているか | +| 来歴 | このイメージはどのソースから、どのようにビルドされたか | + +バンドルの README には、照合すべきアイデンティティと発行者を含む検証コマンドが、リリースに合わせて記載されています。 + +### ライセンス [#license] + +**ライセンスは通常の手順の一部です。** ライセンスなしの Enterprise イメージの動作は、何を求めたかによって異なります。 + +- **単一組織、ライセンスなし**:デプロイメントは ObjectOS Community として実行されます。オープンな MCP サーバーと、自前の AI の持ち込み。何も動かなくなることはありません。 +- **単一組織、ライセンスあり**:自社のインフラストラクチャ上で製品内 AI が有効になります。AI Builder と「データに質問する」です。 +- **マルチ組織(壁で区切られたテナンシーの姿勢)、ライセンスなし**:ランタイムはライセンスを名指しして**起動時に終了**します。組織間の分離はライセンスされた機能であり、分離を求めたデプロイメントが、分離があるふりをしてトラフィックを提供することがあってはなりません。 + +同じ流れに 2 つ目の制約があり、こちらが人を驚かせるものです。**ライセンスにはモードがあり、そのモードはクラウドの姿勢と結びついています。** 通常のライセンスはコントロールプレーンに対してオンラインで検証され、エアギャップライセンスはローカルで検証されてネットワークを一切必要としません。通常のライセンスと「コントロールプレーンなし」の組み合わせは、劣化した状態ではなく不可能な状態です。後でライセンスについての誤解を招く苦情で失敗するのではなく、両方の設定を名指しして**起動時に拒否されます**。サポートされる組み合わせの完全な表は[エアギャップ](/docs/deploy/air-gapped)にあります。 + +### 壁で区切られたデプロイメントはさらに 2 つの判断を宣言しなければならない [#a-walled-deployment-must-declare-two-more-decisions] + +マルチ組織の姿勢では、2 つの設定に安全なデフォルトがないため、ランタイムは**決めるまで起動を拒否します**。どちらの値を宣言しても受け入れられますが、決めないことは受け入れられません。 + +| 判断 | デフォルトにできない理由 | +|---|---| +| **新しいサインアップが何に参加するか** | メンバーシップそのものがテナントの境界である場所では、メンバーシップは明示的な行為(招待、管理者、SSO プロビジョニング)によってのみ付与されるべきです。自動参加は、既存の組織の中に見知らぬ人を入れてしまいます。 | +| **どの AI エージェントをマウントするか** | 「ask」エージェントは読み取ります。「build」エージェントは**メタデータを作成**します。そしてメタデータの範囲は組織ではなくデプロイメントです。共有データベースでは、ある顧客の build のターンが、他のすべての顧客が使うスキーマを書き換えます。 | + +単一組織のデプロイメントでは、どちらのチェックも行われません。 + +### 提供されるスタック [#the-shipped-stack] + +バンドルの Compose スタックは、デプロイメントをあるべき順序で進めます。他のどのオーケストレーターでもこの順序を再現する必要があるため、知っておく価値があります。 + +1. データベースが正常な状態になります。 +2. **1 回限りのマイグレーション**がスキーマを完了まで実行します。アプリケーションのレプリカが起動する前なので、同時に動くレプリカが互いにスキーマ変更を実行し合うことはありません。 +3. アプリケーションのレプリカが起動します。イメージは独自のヘルスチェックを持っています。 +4. リバースプロキシは、レプリカが単に起動しただけでなく実際に応答するようになってから転送を始めます。 + +本番では、デプロイメントを**マネージド**の PostgreSQL(クラスター構成の場合は Redis も)に向け、バンドルのデータベースサービスを削除します。自動 HTTPS を得るには、プロキシにドメインを指定します。ランタイムのコンテナは非 root ユーザーで実行され、ランタイムの状態を宣言されたボリュームに保持します。 + +### Enterprise でのマルチノード [#multi-node-on-enterprise] + +レプリカを 2 つ以上にスケールすると、必須となるものが変わります。 + +- **クラスタードライバー**(Redis ベース)を有効にします。 +- **共有シークレットキーが必須になります。** クラスタードライバーがない場合、ランタイムは独自のキーを生成して永続化します。レプリカ間ではそれらのキーが黙って食い違うことになるため、食い違う代わりに**ランタイムは起動を拒否します**。キーを 1 つ生成し、すべてのレプリカに同じ値を渡してください。 +- **認証シークレットもすべてのレプリカで同一でなければなりません**。変更すると既存のすべてのセッションが無効になり、署名キーが宙に浮きます。ローテーションに伴う 1 回限りのクリーンアップは、環境テンプレートに記載されています。 +- `OS_CLUSTER_REPLICAS` は、バンドルのスタックが起動するアプリケーションのレプリカ数を設定します。 + +### ダイジェストでアップグレードする [#upgrade-by-digest] + +上記のアップグレード手順は、タグの代わりにダイジェストを使って同じように適用されます。 + +1. リリースノートから**新しいダイジェスト**を取得し、ロールアウトの前にイメージのリリースマニフェストを読みます。製品のメジャーラインが現在のものと同じであることを確認し、組み込まれたランタイムの互換性範囲が動いたかどうかを確認します。ランタイムのメジャーバージョンの移動は下層に破壊的変更があることを意味するため、先にそのリリースのノートを読んでください。 +2. データベースをバックアップします。 +3. イメージのダイジェストを変更し、スタックを再起動します。マイグレーションは、新しいレプリカがトラフィックを受ける前に完了まで実行されます。 +4. readiness が 200 を返し、レプリカが正常と報告することを確認します。 +5. ロールバックするには、以前のダイジェストに戻して手順 3 を繰り返します。離れるバージョンが互換性のないスキーマ変更を行っていない限り有効です(行った場合はリリースノートに記載されています)。 + +## 次へ [#next] + +- [Kubernetes](/docs/deploy/kubernetes):オーケストレーター上の同じイメージ。 +- [本番環境への準備](/docs/operate/production):本番稼働前のチェックリスト。 +- [オブザーバビリティ](/docs/operate/observability):ログ、メトリクス、監査。 +- [エアギャップ](/docs/deploy/air-gapped):切断されたサイト向けの Enterprise ライセンスモード。 diff --git a/content/docs/deploy/index.ja.mdx b/content/docs/deploy/index.ja.mdx new file mode 100644 index 00000000..aad5c9d8 --- /dev/null +++ b/content/docs/deploy/index.ja.mdx @@ -0,0 +1,83 @@ +--- +title: デプロイ +seoTitle: "デプロイ:セルフマネージドの ObjectOS、Community と Enterprise" +description: 自社のインフラストラクチャで ObjectOS を実行します。オープンな Community イメージとライセンスされた Enterprise イメージ、ひとつのランタイム、ひとつの設定の契約、そしてライセンスが追加するものを説明します。 +editions: [community, enterprise] +translation: + source_sha: 8e3a6c8cf20d9cbca8dbf4e4162996b6398eecf09e17b90912fd9914ec86e3f6 + guide_rev: 1 + mode: auto +--- + +ObjectOS にはセルフマネージドのエディションが 2 つあり、デプロイ方法は同じです。**ObjectOS Community** はオープンソースのランタイムイメージで、**ObjectOS Enterprise** はライセンスされたイメージです。後者は、シングルノードの Business Self-Managed としても、完全な Enterprise デプロイメントとしても実行できます。どちらも同じランタイムを実行し、同じ設定(データベース、認証シークレット、シークレットキー)を読み込みます。違いは、イメージの入手元、アプリの組み込み方、ライセンスで有効になるものです。このセクションの各ページは両方を対象に一度だけ書かれており、ライセンスされたイメージがより多くを行う箇所では、最後に **Enterprise で追加されるもの** のセクションがあります。 + +## 2 つのイメージ [#the-two-images] + +| | **Community** | **Enterprise** | +|---|---|---| +| イメージ | `ghcr.io/objectstack-ai/objectstack`、公開 | ライセンスされた Enterprise イメージ。プライベートレジストリから取得し、レジストリの認証情報はライセンスとともに提供されます | +| 固定する方法 | 内部の ObjectStack CLI と一致する正確なバージョンタグ(`X.Y.Z`)、そしてバイトが変わってはならない場所ではその**ダイジェスト**([理由](/docs/deploy/docker#pin-the-image)) | リリースノートに記載されたイメージの**ダイジェスト** | +| アーキテクチャ | `linux/amd64` と `linux/arm64` | `linux/amd64` のみ | +| アプリの組み込み方 | `os build` でコンパイルした `objectstack.json` を、マウントする、自分のイメージにコピーする、または `OS_ARTIFACT_URL` で指定する。空のランタイムでは、代わりに Console のマーケットプレイスからアプリをインストールします。 | 3 つの実行形態のいずれか:イメージにバンドルされたアプリ、公開済みアーティファクト、またはイメージの Enterprise プラグインと組み合わせた公開済みアーティファクト([後述](#how-the-app-gets-in)) | +| 設定が必須の変数 | `OS_DATABASE_URL`、`OS_AUTH_SECRET`、`OS_SECRET_KEY`(イメージはすでに `OS_PORT=8080` を設定しています) | 同じもの、加えて `OS_LICENSE_KEY` と意図して設定した `OS_CLOUD_URL` | +| コピーできる設定 | これらのページの例 | 各リリースとともに提供される**デプロイバンドル** | +| ライセンスで有効になるもの | — | 製品内 AI(AI Builder、「データに質問する」)、AI ガバナンス、クラスタリングと高可用性、1 つのデプロイメント上の複数の組織、SCIM、エアギャップ運用 | + +[エディションの比較](/docs/editions/compare)に完全な一覧があります。Community で構築したアプリは通常の ObjectStack メタデータであり、Enterprise でもそのまま動作します。 + +## すべてのデプロイメントが決める 3 つのこと [#every-deployment-decides-three-things] + +| 判断 | 意味 | +|---|---| +| **どのバイトを実行するか** | 正確なイメージをひとつに固定します。`latest` のような移動するタグは知らないうちに付け替えられることがあり、正確なバージョンタグもそのバージョンが再ビルドされれば同様です。それが起きないのはダイジェストだけです。以前のものは残しておきます。それがロールバックです。 | +| **設定をどこに置くか** | イメージとアプリの外です。データベース URL、シークレット、デプロイメントの識別情報は、実行時に注入される環境変数であり、決して焼き込みません。契約は[環境変数](/docs/reference/environment-variables)にあります。 | +| **どのデータベースか** | 本番は PostgreSQL で実行します。`OS_DATABASE_URL` がない場合、ランタイムはホームディレクトリの下に SQLite ファイルを書き込みます。これは永続的な単一ホストには適していますが、コンテナの一時的なファイルシステムではデータが失われます。 | + +## アプリの組み込み方 [#how-the-app-gets-in] + +Community イメージには**アプリが含まれていません**。`os build` がコンパイルするアーティファクト `dist/objectstack.json` を、次の 3 つの方法のいずれかで渡します。 + +| 方法 | やり方 | 使う場面 | +|---|---|---| +| **マウントする** | イメージがデフォルトで探す `/srv/app/objectstack.json` にファイルをマウントします | イメージのビルドを一切したくない | +| **自分のイメージにコピーする** | 公式イメージを `FROM` とする 2 段階の Dockerfile | リリースごとに自己完結したイメージを 1 つ出荷する | +| **URL で指定する** | `OS_ARTIFACT_URL`、任意で `#sha256=` による完全性の固定 | アプリのアップグレードを環境の変更と再起動で済ませたい | + +[Docker](/docs/deploy/docker#run-it) に 3 つすべてを示しています。アーティファクトがまったくない場合、ランタイムは空のカーネルで起動し、アプリは Console のマーケットプレイスからインストールします。 + +## ガイド [#guides] + +- [Docker](/docs/deploy/docker):イメージを実行し、設定し、プロキシの背後に置き、アップグレードします。 +- [Kubernetes](/docs/deploy/kubernetes):オーケストレーター上の同じイメージと、維持すべき性質。 +- [エアギャップ](/docs/deploy/air-gapped):Enterprise のみ。**ライセンスモード**としてのエアギャップと、起動時に拒否される組み合わせ。 + +コンテナランタイムがない場合は、Node.js 22 のホスト上で、同じアーティファクトを `os start` で実行できます。[ObjectOS Community をローカルで実行する](/docs/start/community)を参照してください。 + +## Enterprise で追加されるもの [#enterprise-adds] + +### さらに 2 つの判断:ライセンスとクラウドの姿勢 [#two-more-decisions-license-and-cloud-posture] + +| 判断 | 意味 | +|---|---| +| **どのライセンスか** | ライセンスは追加オプションではなく、通常の手順の一部です。デプロイメントの形態によっては、ライセンスがないと*起動を拒否*します。 | +| **どのクラウドの姿勢か** | このランタイムがコントロールプレーンと通信するかどうか。これは**ライセンスモードと結びついて**おり、サポートされない組み合わせは、黙って劣化するのではなく起動時に拒否されます。 | + +実際には、この 2 つはひとつの判断です。間違えるとゆっくりとした漏れではなく、起動の失敗になります。サポートされる組み合わせの全体は[エアギャップ](/docs/deploy/air-gapped)に記載されています。組み合わせが*なぜ*そうなっているかを説明しているページなので、サイトがネットワークに接続されている場合でも読んでください。 + +### デプロイバンドル [#the-deploy-bundle] + +リリースには**デプロイバンドル**が付属します。Compose スタック、サポートされる各形態の環境テンプレート、そしてそのバージョンの正確なコマンド(レジストリの参照、ダイジェスト、サプライチェーン検証の手順を含む)を記載した README です。 + +これらのページが扱うのは**判断**です。なぜダイジェストなのか、どの形態にどのライセンスモードか、マルチノードで何が必須になるか、ランタイムが何を拒否するか。バンドルが扱うのは**コピーする値**です。両者が食い違うように見えるときは、イメージとともに提供されたバンドルが正しいものです。バンドルは、それが設定するランタイムとともにバージョン管理されています。 + +### 3 つの実行形態 [#three-run-shapes] + +Enterprise イメージは 3 つの方法でアプリを実行でき、その選択によって利用できるものが変わります。単なるパッケージングの問題ではありません。 + +| 形態 | アプリの出どころ | 使う場面 | +|---|---|---| +| **Config-authored** | イメージ自身にバンドルされたアプリケーション。イメージ内で作成されたメタデータと、そこにインストールされたもの | 単一組織のデプロイメント。Compose スタックが設定するデフォルトで、設定が不要な形態です。 | +| **Artifact-pinned** | URL で指定された公開済みのアプリアーティファクト。デプロイメントの設定が実行される前に解決されます | 公開済みのアプリを 1 つ実行し、イメージを再ビルドせずに、環境の変更と再起動でアプリをアップグレードしたい。この経路では、デプロイメントの Enterprise プラグインは読み込まれ**ない**ことに注意してください。 | +| **Composed** | このデプロイメントの Enterprise プラグイン*と*組み合わせた公開済みのアプリアーティファクト | 複数の組織が 1 つのデータベースを共有する。これはホスト型の単一アプリ SaaS の形態であり、**エアギャップライセンスのみ**で、起動時に強制されます。 | + +各形態には、デプロイバンドル内に専用の環境テンプレートがあります。別のものを手直しするのではなく、自分の形態のものをコピーしてください。テンプレートは姿勢を決める値が異なり、それらはまさにランタイムが何かを提供する前に確認する値です。 diff --git a/content/docs/deploy/kubernetes.ja.mdx b/content/docs/deploy/kubernetes.ja.mdx new file mode 100644 index 00000000..8bdfbf5c --- /dev/null +++ b/content/docs/deploy/kubernetes.ja.mdx @@ -0,0 +1,112 @@ +--- +title: Kubernetes +seoTitle: "Kubernetes:プローブ、シークレット、固定、マイグレーション" +description: Kubernetes で ObjectOS イメージを実行します。参照用の Deployment、正しいエンドポイントへの正しいプローブ、Secret からのシークレット、そしてマルチレプリカの Enterprise デプロイメントが維持すべきものを説明します。 +editions: [community, enterprise] +translation: + source_sha: 2270aa161805c5ab5a80c2c48562ac8ab6c54573019e3c7d17acc51587a2d6c0 + guide_rev: 1 + mode: auto +--- + +**Helm チャートや公式のマニフェスト一式はありません。** イメージは Kubernetes でもそのまま動作するため、このページでは最小限の参照例と、マニフェストが維持しなければならない性質を示します。それぞれ、ランタイムが依存するか強制するものです。[Docker](/docs/deploy/docker) の内容はすべて当てはまります。同じイメージ、同じ変数、同じアップグレードのルールです。 + +## 参照用の Deployment [#a-reference-deployment] + +Community イメージのレプリカ 1 つ、`Secret` からのシークレット、それぞれ専用のエンドポイントに向けたプローブ: + +```yaml title="deployment.yaml" +apiVersion: apps/v1 +kind: Deployment +metadata: + name: objectos +spec: + replicas: 1 + selector: + matchLabels: { app: objectos } + template: + metadata: + labels: { app: objectos } + spec: + containers: + - name: objectos + image: registry.example.com/crm:2.2.2 # your image FROM ghcr.io/objectstack-ai/objectstack:X.Y.Z + ports: + - containerPort: 8080 + envFrom: + - secretRef: + name: objectos-secrets # OS_DATABASE_URL, OS_AUTH_SECRET, OS_SECRET_KEY + livenessProbe: + httpGet: { path: /api/v1/health, port: 8080 } + periodSeconds: 30 + readinessProbe: + httpGet: { path: /api/v1/ready, port: 8080 } + initialDelaySeconds: 5 + periodSeconds: 10 +--- +apiVersion: v1 +kind: Service +metadata: + name: objectos +spec: + selector: { app: objectos } + ports: + - port: 80 + targetPort: 8080 +``` + +## 維持すべき性質 [#properties-to-preserve] + +### イメージが正確に固定されている [#the-image-is-pinned-exactly] + +イメージは `@sha256:` ダイジェストで参照し、読み取り元の正確なバージョンを横に書いておきます。移動するタグでは決して参照しないでください。オーケストレーターでは、単一ホストよりもこれが重要です。プルポリシーと移動するタグの組み合わせでは、「同じ」Deployment の 2 つの Pod が異なるビルドを実行することがあります。移動するタグはリリースのたびに動き、正確なバージョンタグもそのバージョンが再ビルドされれば動きます。[Docker → イメージを固定する](/docs/deploy/docker#pin-the-image)を参照してください。 + +### プローブが正しいエンドポイントに向いている [#probes-address-the-right-endpoints] + +`/api/v1/health` は liveness です。`/api/v1/ready` は readiness です。readiness は、ランタイムの起動中、シャットダウン中、そしてデータドライバーが応答しなくなったときに **503** を返します。そのため、ローリング再起動はきれいにドレインされ、データベースを失った Pod はエラーを返す代わりに Service のエンドポイントから外れます。 + +readiness を liveness プローブに使わないでください。そうしないと、データベースの障害ですべての Pod が一斉に再起動し(それではデータベースは戻りません)、設定の不具合はその不具合自体ではなく `CrashLoopBackOff` として現れます。データベースが戻れば Pod は自動的に回復します。readiness プローブが、不在の間は Pod をドレインし、その後に再び受け入れます。 + +### シークレットは Secret から [#secrets-come-from-a-secret] + +`OS_AUTH_SECRET` と `OS_SECRET_KEY` は `Secret` に入れ、一度だけ生成してすべての Pod にマウントします。Pod ごとに生成したり、イメージに焼き込んだりは決してしないでください。独自のシークレットキーを生成した Pod は、次の再スケジュールでそのキーを失い、それで暗号化されたすべてのシークレットも一緒に失います。 + +### 業務データはクラスターの外に置く [#business-data-lives-outside-the-cluster] + +デプロイメントはマネージド PostgreSQL に向けます。クラスター内の永続ボリュームは、業務データの置き場所として想定されていません。 + +### Community ではレプリカ 1 つ [#one-replica-on-community] + +Community の調整はプロセス内で行われるため、`replicas: 1` のままにします。それ以上を宣言すると(`OS_CLUSTER_REPLICAS` が 1 より大きい)、ライセンスなしでは起動が拒否されます。マルチレプリカは Enterprise の機能です(後述)。 + +### Ingress [#ingress] + +TLS はエッジで終端し、`OS_AUTH_URL` と `OS_TRUSTED_ORIGINS` を公開アドレスに設定します。クロスオリジンのフロントエンドは `OS_CORS_ORIGIN` に明示的に列挙し、ワイルドカードのオリジンと認証情報付きのリクエストを組み合わせないでください。ランタイムがプロキシの背後にある場合は、クライアントが指定した forwarded-for ヘッダーをプロキシが自身のもので置き換えるようにしてください。レート制限と監査証跡は、呼び出し元の識別情報が信頼できることに依存しています。 + +## Enterprise で追加されるもの [#enterprise-adds] + +**私たちが提供するのは Compose スタックであり、Helm チャートや Kubernetes マニフェストではありません。** リリースのデプロイバンドルが、サポートされテストされた構成です。Kubernetes ではマニフェストを自分で組み立てることになるため、そのスタックの次の性質も再現してください。オーケストレーターが何であれ、デプロイメントが受けられる権利は変わりません。 + +### イメージはダイジェストで固定する [#the-image-is-pinned-by-digest] + +Pod の spec では、Enterprise イメージを `@sha256:` ダイジェストで参照します。プルには、ライセンスされたレジストリの認証情報を持つプルシークレットが必要です。 + +### マイグレーションは、レプリカが提供を始める前に一度だけ、完了まで実行する [#migrations-run-once-to-completion-before-replicas-serve] + +Compose スタックは、アプリケーションのレプリカが起動する前に完了しなければならない 1 回限りのマイグレーションコンテナを実行します。Kubernetes ではこれは Job(または同等の提供前フック)であり、各レプリカの init コンテナではありません。要点は、スキーマ変更がレプリカごとに並行してではなく**一度だけ**実行されることです。イメージはまさにこのためにマイグレーションして終了するモードをサポートしており、その変数はバンドルに記載されています。 + +### すべてのレプリカに同一のシークレットを渡す [#every-replica-gets-identical-secrets] + +マルチレプリカは、レプリカ数を増やすだけの問題ではありません。 + +- Redis をバックエンドとする**クラスタードライバー**を有効にする必要があります。 +- **共有シークレットキー**が必須になります。クラスタードライバーがない場合、各レプリカは独自のキーを生成します。レプリカ間ではそれらが食い違うことになるため、食い違う代わりに**ランタイムは起動を拒否します**。1 つの値を、すべてのレプリカにマウントしてください。 +- **認証シークレット**も同様に、すべてのレプリカで同一でなければなりません。 + +### ライセンスとクラウドの姿勢はデプロイメント全体で共通 [#license-and-cloud-posture-are-deployment-wide] + +ライセンスキー、ライセンスモード、クラウドの姿勢の設定は、デプロイメントの識別情報の一部です。すべてのレプリカで同じでなければならず、サポートされる組み合わせは**起動時に**確認されます。設定が食い違う Pod は劣化した状態で動くのではなく、終了します。組み合わせについては[エアギャップ](/docs/deploy/air-gapped)を参照してください。 + +### ローリングアップグレードはダイジェストを変更する [#rolling-upgrades-change-the-digest] + +アップグレードとはイメージのダイジェストの変更であり、新しいレプリカが提供を始める前にマイグレーションの Job が完了まで実行されます。スキーマのマイグレーションは前にしか進みません。イメージをロールバックしてもスキーマはロールバックされないため、先にバックアップを取り、ロールバック先として以前のダイジェストを残しておいてください。アプリ自体は、公開済みアーティファクトとして提供される場合、イメージとは独立してバージョン管理されます。[デプロイ](/docs/deploy#three-run-shapes)の実行形態を参照してください。 diff --git a/content/docs/operate/audit-logs.ja.mdx b/content/docs/operate/audit-logs.ja.mdx new file mode 100644 index 00000000..1da3f217 --- /dev/null +++ b/content/docs/operate/audit-logs.ja.mdx @@ -0,0 +1,114 @@ +--- +title: 監査ログ +seoTitle: "監査ログ:すべての変更、サインイン、イベント" +description: デプロイメント上のすべての変更、サインイン、発行されたイベントを記録する、改ざんできない監査証跡と診断ログを読みます。 +editions: [community, enterprise] +translation: + source_sha: 8c6b53d05235befa452e3b9a3953df31e5b1ba4c01aaf168a9392a49da21197f + guide_rev: 1 + mode: auto +--- + +監査ログは、デプロイメントで何が起きたかの改ざんできない記録です。誰が、何を、いつ、どこから変更したかを示します。このページは、**Setup → Diagnostics** の下にある診断サーフェスの詳細なリファレンスです。ログ、メトリクス、リクエストの識別についてのオペレーター向けの概要は、[オブザーバビリティ](/docs/operate/observability)を参照してください。 + +> これらのサーフェスには `manage_platform_settings` 権限が必要です。 + +次のことを証明または調査する必要があるときに、監査ログを使います。 + +- 権限に関わる変更 +- 設定と構成の変更 +- ユーザーとセッションのアクティビティ +- 連携と自動化のアクティビティ +- 拒否されたアクセスの分析 + +## 監査ログ [#audit-logs] + +**Setup → Diagnostics → Audit Logs**(`sys_audit_log`)にあります。このオブジェクトは**読み取り専用で改ざんできません**。プラットフォームのイベントを追記専用で記録した証跡です。行の絞り込み、グループ化、確認はできますが、Setup から行を編集・削除することはできません。 + +### 各閲覧者に提供されるもの [#what-each-reader-is-served] + +すべての行は保存されたままですが、ObjectStack 17.6 以降、あるレコードに関する行は、閲覧者がそのレコード自体を読める場合にだけ提供されます。レコードを開けるかどうかを決めるのと同じ、オブジェクト権限、共有、行レベルセキュリティです。これにより次のものが除外されます。 + +- すべての `delete` の行と、その後削除されたレコードに関するその他すべての行 +- サインアウトの行と、その後セッションが削除されたサインインの行 +- 閲覧者が開けないレコードに関する行 + +どのレコードにも関係しない行(構成の変更、ユーザーインポートの実行、セッションを持たない認証イベント)は、従来どおり台帳自体の付与のもとで提供されます。 + +**`view_all_audit_log`** 機能はこの絞り込みを解除します(ObjectStack 17.7)。その保持者には、削除とサインアウトの証跡、そして開けないレコードに関する行が提供されます。プラットフォーム管理者はデフォルトでこれを保持していますが、組織の管理者は保持していないため、証跡全体を読む必要があるその他の人には明示的に付与してください。 + +フィールドレベルのセキュリティは、すべての行の中で引き続き適用されます。`old_value` と `new_value` は、マスクなしでそのフィールドを読める閲覧者にだけそのフィールドを提供します。また、フィルターが等価条件で 1 つのオブジェクトを指定し(`object_name`)、かつそのオブジェクトのすべてのフィールドを読める場合を除き、これらでの絞り込み、並べ替え、グループ化は拒否されます(`403`)。 + +### プリセットビュー [#preset-views] + +一覧は、アクションのカテゴリで絞り込むタブとともに開きます。どのタブにも上記のルールが適用されます。 + +| ビュー | 表示内容 | +|---|---| +| `Recent` | すべてのイベント、新しい順 | +| `Writes` | 作成 / 更新 / 削除のアクション。`delete` の行は `view_all_audit_log` がある場合のみ | +| `Auth` | サインインとサインアウトのイベント。サインアウトと、その後セッションが削除されたサインインは `view_all_audit_log` がある場合のみ | +| `Config` | 設定と構成の変更 | + +### 列とフィールド [#columns-and-fields] + +デフォルトの列は `Timestamp`、`Action`(create / update / … を示す色付きのピル)、`Object`、`Record ID`、`Actor` です。フッターにはレコードの総数が表示されます(例:*36 records*)。 + +各行は完全なフィールドのセットを持ちます。 + +| フィールド | 意味 | +|---|---| +| `created_at` | イベントが記録された日時 | +| `action` | 操作(create、update、delete、auth など) | +| `user_id` | 実行した User へのルックアップ | +| `actor` | 実行者の識別情報(テキスト) | +| `object_name` | イベントが影響したオブジェクト(例:`sys_user`) | +| `record_id` | 影響を受けたレコード | +| `old_value` | 変更前の値(テキストエリア) | +| `new_value` | 変更後の値(テキストエリア) | +| `ip_address` | リクエストの送信元 IP | +| `user_agent` | クライアントのユーザーエージェント | +| `tenant_id` | 所有するテナント | +| `metadata` | 追加の構造化されたコンテキスト | + +> `Config` ビューは、「誰がこの設定を変更したか」に答える最も速い方法です。行を読み始める前に、証跡を構成のアクションに絞り込みます。 + +### 変更を読む [#reading-a-change] + +書き込みアクションで重要な詳細は、変更前と変更後です。行の `⋮` メニューを開いて `old_value` と `new_value` を展開すると、そのレコードで何が変わったかが表示されます。読めるフィールドはすべて完全に表示され、それ以外は何も表示されません。`Object` と `Record ID` の列は*何が*影響を受けたかを、`old_value`/`new_value` は*どのように*を、`actor`、`ip_address`、`user_agent` は*誰が*、*どこから*を示します。 + +> 規制のある環境では、ストレージの層でも改ざん不可能性を担保してください。データベースでテーブルを追記専用にし、保持ポリシーを定めます。 + +## 通知イベント [#notification-events] + +**Setup → Diagnostics → Notification Events**(`sys_notification`)にあります。これは**通知システムの受信ログ**であり、`emit()` ごとに 1 行が、配信の判断より前に書き込まれます。通知が受信トレイに届いた理由、届かなかった理由の診断に使います。その後のルーティングと具体化については、[通知](/docs/configure/notifications)に記載されています。 + +プリセットビューは `Recent` と `By Topic` です。デフォルトの列は `Topic`(例:`project.digest`)、`Severity`(info/warn/… を示すピル)、`Actor`、`Source Object`、`Created At` です。 + +| フィールド | 意味 | +|---|---| +| `topic` | 発行されたトピック | +| `payload` | イベントのペイロード(JSON) | +| `severity` | 重大度 | +| `dedup_key` | 重複した発行をまとめるためのキー | +| `source_object` | イベントを発生させたオブジェクト | +| `source_id` | イベントを発生させたレコード | +| `actor_id` | 発行をトリガーしたプリンシパル | +| `created_at` | イベントが取り込まれた日時 | + +`dedup_key` は重複した発行をまとめ、`payload` はテンプレートの描画元となる生のイベントコンテキストを保持します。このログはルーティングの*上流*にあるため、ここに行があるのに対応する受信トレイのメッセージがない場合、通常は対象者がそのユーザーに解決されなかったか、ユーザーの設定がそのチャネルでそのトピックをミュートしています。ユーザーからアラートが届かないと報告があったときは、[通知](/docs/configure/notifications)を確認してください。 + +下流では、各イベントはユーザーごとの受信トレイのメッセージ(`sys_inbox_message`)に具体化されます。受信者側の表示については[通知](/docs/use/notifications)にあります。 + +## セッション [#sessions] + +**Setup → Diagnostics → Sessions** にあります。Sessions には有効なサインインセッションと最近のサインインセッションが一覧表示されるため、ユーザーのアクティビティを調査したり、アクセスを取り消したりできます。サインインのインシデントを確認するときは、`Auth` 監査ビューと組み合わせて使います。 + +## 次に進む [#where-to-go-next] + +| タスク | ページ | +|---|---| +| ログ、メトリクス、リクエストの識別についてのオペレーター向けの概要 | [オブザーバビリティ](/docs/operate/observability) | +| 通知のルーティングと描画の仕組みを理解する | [通知](/docs/configure/notifications) | +| 本番稼働の前にデプロイメントを堅牢化する | [本番環境への準備](/docs/operate/production) | +| 運用の概要に戻る | [運用](/docs/operate) | diff --git a/content/docs/operate/backup.ja.mdx b/content/docs/operate/backup.ja.mdx new file mode 100644 index 00000000..2dc6f5ea --- /dev/null +++ b/content/docs/operate/backup.ja.mdx @@ -0,0 +1,144 @@ +--- +title: バックアップと災害復旧 +description: 何をバックアップし、どのように復元し、障害にどう備えるか。 +editions: [community, enterprise] +translation: + source_sha: ef15634a21d14d8b172d6f1b203d01b045bb64b427e5810ca1d6c85c4ae69004 + guide_rev: 1 + mode: auto +--- + +ObjectOS 自体はステートレスです。ランタイムはコンテナイメージから再構築できます。**バックアップの対象は、ObjectOS 自体ではなく、ObjectOS が依存するデータです。** 復旧はそれらのデータセットを中心に計画してください。このページの内容はすべて、Community にも Enterprise にも当てはまります。 + +## バックアップするもの [#what-to-back-up] + +| 資産 | 所有者 | バックアップ戦略 | +|---|---|---| +| 業務データベース | 顧客 | データベースネイティブのバックアップ(マネージドサービスでは PITR)。四半期ごとに復元をテスト | +| コンパイル済みアーティファクト(`objectstack.json`) | アプリケーション/リリースチーム | 公開したすべてのアーティファクトを不変のストレージに保存し、決して上書きしない | +| シークレットの基準値。何よりも `OS_SECRET_KEY` | 顧客のシークレットマネージャー | 値そのものを預託する。ローテーションの頻度はポリシーに従う | +| オブジェクト/ファイルストレージ(`storage` 機能が有効な場合) | 顧客 | バケットのバージョニング + 必要に応じてリージョン間レプリケーション | +| ローカルストレージ上のアップロードされたファイル(`OS_STORAGE_LOCAL_ROOT`) | 顧客 | データベースと同じスケジュールで。レコードとその添付ファイルが同じ時点に復元されるように | +| 顧客管理のアイデンティティプロバイダー | IdP ベンダー | ベンダーネイティブ | + +> **`OS_SECRET_KEY` のないデータベースバックアップは不完全なバックアップです。** 保存されたすべてのシークレット(暗号化された設定、`secret` フィールド、データソースの認証情報)は、その 1 つのキーで暗号化されています。元のキーなしで復元したデータベースは、それらの値を読めないまま永久に保持することになります。キーは生成したその日に預託し、キーとデータベースをひとつのバックアップ単位として扱ってください。 + +`OS_DATABASE_URL` と `OS_SECRET_KEY` を設定したコンテナは、自身のファイルシステムをバックアップする必要がありません。キャッシュは再構築できます。キャッシュされたアーティファクトは読み取りのたびに完全性の固定に照らして再検証されるため、キャッシュを失っても取得が 1 回増えるだけで、正しさが損なわれることはありません。デフォルト設定で動作する**単一ホスト**は事情が異なります。そのホームディレクトリには SQLite データベース、アップロードされたファイル、自己生成したシークレットキーがあるため、ファイルのバックアップに含めてください。 + +## データベースのバックアップ [#database-backups] + +戦略はドライバーに合わせます。 + +| ドライバー | 推奨される方法 | +|---|---| +| PostgreSQL | 継続的な WAL アーカイブ + ベースバックアップ。ポイントインタイムリストア。小さなデータベースでは、`pg_dump --format=custom` も実用的な論理バックアップです | +| MySQL | バイナリログのアーカイブ + フルダンプ。ポイントインタイムリストア | +| MongoDB | レプリカセットのスナップショット。PITR には oplog | +| SQLite(シングルノード / デスクトップ) | WAL モード + `VACUUM INTO` または Online Backup API によるホットスナップショット。任意で継続的なレプリケーションに Litestream。後述の [SQLite のデプロイメント](#sqlite-deployments)を参照 | + +ドライバーにかかわらず、次のことを検証してください。 + +- バックアップが顧客の RPO 内に完了する +- 新しいデータベースで、同じアーティファクトから ObjectOS を起動し、トラフィックを提供できる +- 復元テストを少なくとも四半期に一度、エンドツーエンドで実施する + +## SQLite のデプロイメント [#sqlite-deployments] + +SQLite はデフォルトのドライバーであり、**シングルノード**の ObjectOS(デスクトップアプリ、小規模チームの社内ツール、エッジ / オンプレミスのアプライアンス、評価環境)にとって正当な本番の選択肢です。トレードオフは構造的なものです。SQLite は単一ライターなので、マルチノードの ObjectOS、高い同時書き込みスループット、共有データベースのデプロイメントには適しません。それらには PostgreSQL を使ってください。 + +本番で SQLite を実行する場合は、安全にするための設定とバックアップの手順をセットで考えます。 + +**ランタイムの設定** + +- ランタイムはファイルベースの SQLite を WAL モードで保持します(読み取りが書き込みをブロックせず、クラッシュに対して安全)。つまり、データベースの横にある `app.db-wal` には、まだ `app.db` に入っていないコミット済みの書き込みが含まれることがあります。ランタイムの実行中に `app.db` だけをコピーしないでください。 +- `PRAGMA synchronous=NORMAL` は、デスクトップ/シングルノードの通常のデフォルトです。WAL と組み合わせれば安全で、`FULL` よりはるかに高速です。 +- データベースファイルは**ローカルディスク**に置いてください。ランタイムの実行中に、NFS、SMB、または Dropbox / OneDrive / iCloud で同期されるフォルダーの中に置か**ない**でください。それらでは SQLite のロックが信頼できず、SQLite のデプロイメントが破損する最も一般的な原因です。 + +**ホットスナップショット(ダウンタイムなし)** + +SQLite の Online Backup API または `VACUUM INTO` でスナップショットを取る間も、ランタイムはトラフィックを提供し続けます。 + +```sql +VACUUM INTO '/var/backups/objectos/db-2026-05-27T13-00Z.sqlite'; +``` + +RPO に合った頻度でスケジュールします(cron、systemd タイマー、またはプロセス内のスケジューラー)。各スナップショットには、それを生成したアーティファクトのバージョンをタグ付けし、データベースとアーティファクトを一緒にロールバックできるようにします(後述の[アーティファクトのバージョン管理](#artifact-versioning)を参照)。 + +**オフサイトのコピー** + +ローカルのスナップショットはディスクの喪失を乗り越えられません。各スナップショットを耐久性のあるストレージに送ります。 + +- サーバー / VM:S3 または S3 互換のバケットに送ります(`storage` 機能のためにすでに設定しているものがあるはずです)。 +- デスクトップアプリ:ユーザーが管理する同期フォルダー(OneDrive / iCloud / Google Drive)にスナップショットを書き込みます。稼働中のデータベースと違い、スナップショットファイルは**閉じていて不変**なので、ここでは問題ありません。 + +**継続的なレプリケーション(より低い RPO)** + +SQLite のまま 1 分未満の RPO を実現するには、ObjectOS のプロセスと並べて [Litestream](https://litestream.io) を実行します。WAL を S3 互換のストレージにストリーミングし、ポイントインタイムリストアをサポートします。シングルノードの SQLite デプロイメントでデータ損失をほぼゼロにする必要がある場合の推奨される方法です。 + +**復元** + +ランタイムを停止し、データベースファイルを選んだスナップショットで置き換え(または `litestream restore` を実行し)、古い `-wal` や `-shm` ファイルが横に残っていないことを確認してから、スナップショットを生成したのと同じアーティファクトのバージョンでランタイムを起動します。 + +## アーティファクトのバージョン管理 [#artifact-versioning] + +公開したアーティファクトは不変として扱います。各アーティファクトには、コンパイルに使ったリリース id をタグ付けします(例:`objectstack-2026-05-24.json`)。正常だとわかっている業務の状態への復旧は、通常次のようになります。 + +1. データベースを選んだ時点に復元します。 +2. ObjectOS を、その時点で稼働していたアーティファクトのバージョンに向け直します。 +3. ランタイムを再起動します。 + +アーティファクトをその場で上書きすると、データベースのバックアップが完璧でも、きれいにロールバックする能力を失います。 + +## RPO/RTO の計画 [#rporto-planning] + +顧客のデプロイメントで実用的な最初の目標: + +| 区分 | RPO | RTO | 備考 | +|---|---|---|---| +| 評価 / デモ | ベストエフォート | ベストエフォート | SQLite のスナップショットで十分 | +| デスクトップアプリ / 小規模チームのシングルノード | 1 時間以内(スナップショット)または数秒以内(Litestream) | 数分 | SQLite + WAL + スケジュールされた `VACUUM INTO` + オフサイトのコピー | +| シングルテナントの本番 | 15 分以内 | 1 時間以内 | PITR 付きのマネージド PostgreSQL + ウォームイメージ | +| マルチテナント / 規制対象 | 5 分以内 | 30 分以内 | HA データベース + マルチ AZ の ObjectOS + テスト済みのランブック | + +より厳しい目標には、ObjectOS のコンテナ自体の外にあるプラットフォームの変更(HA データベース、マルチ AZ のイングレス、ウォームレプリカ)が必要です。 + +## 予行演習すべき障害モード [#failure-modes-worth-rehearsing] + +- **データベースが長時間利用できない。** ObjectStack 17.0 以降、これは期待するものではなく契約上の動作です。データドライバーが応答しない間、`/api/v1/ready` は 503 を返すため、readiness プローブは Pod を準備未完了とマークします。*復旧*を予行演習してください。データベースが戻ればレプリカが再参加すること、そしてそれに気づくために何も再起動を必要としないことです。オブジェクトがバインドするデータソースで、起動時に接続できないものは起動を失敗させるようになったため、アプリケーションのレプリカがロールする前に復元が完了することを確認してください。 +- **アーティファクトの不具合。** アーティファクトのポインターをロールバックします。データには影響しません。 +- **シークレットのローテーション。** `OS_AUTH_SECRET` をローテーションすると、すべてのセッションが無効になります。メンテナンスウィンドウ中に実施するか、レプリカごとに時間をずらして実施してください。 +- **リージョンの障害。** 顧客がリージョンのフェイルオーバーを求める場合、業務データベース、シークレットマネージャー、イングレスのすべてがリージョンをまたぐ必要があります。ObjectOS 自体は、イメージが利用できる場所ならどこでも実行できます。 + +## 復元の予行演習 [#the-restore-drill] + +本番稼働の**前に**一時的なホストでこれを予行演習し、ストレージを変更した後にもう一度行ってください。復元したことのないバックアップは、バックアップではなく希望にすぎません。 + +1. バックアップを取得したときと同じイメージのバージョンで、**クリーンなホストを用意します**。 +2. **データベースを復元します**。プロバイダーのスナップショットを使うか、次のようにします。 + + ```bash + pg_restore --clean --if-exists -d "$OS_DATABASE_URL" backup-2026-07-14.dump + ``` +3. **元のシークレットを用意します。** `OS_SECRET_KEY` と `OS_AUTH_SECRET` は預託した元の値であり、新たに生成した値であってはなりません。ローカルストレージを使っている場合は、アップロードされたファイルも復元します。 +4. **同じアーティファクトのバージョンで起動し、検証します。** + + ```bash + curl -fsS https://app.example.com/api/v1/health + curl -fsS https://app.example.com/api/v1/ready + ``` + + 次に、復元をエンドツーエンドで証明します。実際のアカウントでサインインし、バックアップ前から存在したレコードを開き、暗号化された設定から値を読み取ります。これが `OS_SECRET_KEY` を検証する操作です。 + +## ランブックに記載すべきこと [#what-to-capture-in-the-runbook] + +- 各データセットのバックアップのスケジュール、保持期間、オンコールの連絡先。 +- ステップごとの復元手順(まずデータベース、次にアーティファクト、そして ObjectOS の起動)。 +- 復元したデータベースの整合性を確認する検証クエリ。 +- ObjectOS のイメージとアーティファクトのバージョンの両方のロールバック計画([アップグレードとロールバック](/docs/operate/upgrade)を参照)。 +- 顧客に見えるインシデントのための連絡テンプレート。 + +## Enterprise で追加されるもの [#enterprise-adds] + +- **以前のイメージのダイジェストをバックアップと一緒に保管します。** ある時点への復元は、その時点で稼働していたダイジェストへの復元です。エアギャップのサイトでは、以前のダイジェストが唯一のコピーかもしれません。[エアギャップ](/docs/deploy/air-gapped#getting-the-image-inside-the-network)を参照してください。 +- **`OS_LICENSE_KEY` はシークレットの基準値に含めます。** 復元したデプロイメントは与えられたライセンスで起動し、マルチ組織の姿勢ではライセンスがないと起動を拒否します。 +- **レプリカがロールする前に復元します。** バンドルのスタックは、どのレプリカよりも先に 1 回限りのマイグレーションを実行するため、スタックが起動する時点でデータベースが完全でなければなりません。 diff --git a/content/docs/operate/index.ja.mdx b/content/docs/operate/index.ja.mdx new file mode 100644 index 00000000..894953f2 --- /dev/null +++ b/content/docs/operate/index.ja.mdx @@ -0,0 +1,38 @@ +--- +title: 運用 +seoTitle: "運用:本番環境への準備、バックアップ、アップグレード" +description: 稼働中の ObjectOS デプロイメントを健全に保ちます。本番環境への準備、オブザーバビリティ、監査証跡、バックアップ、アップグレード、復旧を扱います。 +editions: [community, enterprise] +translation: + source_sha: a17ed607565693a65e32a25c8fe8db345aa917afac9348647fecca7a35e9c8f7 + guide_rev: 1 + mode: auto +--- + +このセクションは、ObjectOS を**本番で健全に**保つためのものです。[設定](/docs/configure)がセットアップ時の管理(ユーザー、アクセス、サインイン、連携)を扱うのに対し、*運用*は稼働後の作業を扱います。デプロイメントの堅牢化、監視、何が起きたかの証明、そして問題が起きたときの復旧です。 + +ここのすべてのページは、セルフマネージドの両エディション、ObjectOS Community と ObjectOS Enterprise を対象としています。両者は同じランタイムを実行するため、運用方法も同じです。ライセンスされた Enterprise イメージがより多くを行う箇所(リリースノートに記載されたダイジェスト、ライセンスキー、複数のレプリカ)では、ページの最後に **Enterprise で追加されるもの** のセクションがあります。ObjectOS Cloud では、私たちがデプロイメントを運用します。 + +## 運用のページ [#operations-pages] + +| ページ | 用途 | +|---|---| +| [本番環境への準備](/docs/operate/production) | 本番稼働の前後にデプロイメントを堅牢化する | +| [オブザーバビリティ](/docs/operate/observability) | ログ、リクエスト id、メトリクス、エラーを接続する | +| [監査ログ](/docs/operate/audit-logs) | 改ざんできない監査証跡と診断ログを読む | +| [バックアップ](/docs/operate/backup) | バックアップと災害復旧を計画する | +| [アップグレード](/docs/operate/upgrade) | 安全にアップグレードまたはロールバックする | +| [トラブルシューティング](/docs/operate/troubleshooting) | 壊れたデプロイメントを診断する | + +## 設定と運用の違い [#configure-vs-operate] + +セットアップ時の管理(ユーザーの追加、アクセスの付与、メール、ストレージ、連携の接続)は[設定](/docs/configure)にあります。デプロイメントが稼働し、監視、監査、バックアップ、アップグレードが必要になったら、ここに戻ってきてください。 + +## 次に進む [#where-to-go-next] + +| タスク | ページ | +|---|---| +| 本番前のチェックリスト | [本番環境への準備](/docs/operate/production) | +| 変更やサインインを追跡する | [監査ログ](/docs/operate/audit-logs) | +| 監視を設定する | [オブザーバビリティ](/docs/operate/observability) | +| セットアップ時の管理 | [設定](/docs/configure) | diff --git a/content/docs/operate/observability.ja.mdx b/content/docs/operate/observability.ja.mdx new file mode 100644 index 00000000..49cb34af --- /dev/null +++ b/content/docs/operate/observability.ja.mdx @@ -0,0 +1,96 @@ +--- +title: オブザーバビリティ +seoTitle: "オブザーバビリティ:ログ、リクエスト ID、メトリクス、エラー" +description: ログ、リクエスト id、メトリクス、エラー、セッション、監査ログ。 +editions: [community, enterprise] +translation: + source_sha: 6260a1763af40fdb7320387d9d4a60879fc6f529e51b110ee98e9a10dff64f6e + guide_rev: 1 + mode: auto +--- + +ObjectOS の運用には、インフラストラクチャのシグナルとアプリケーションのシグナルの両方が必要です。フレームワークはリクエスト id、メトリクス、エラーレポーター、監査のプリミティブを提供し、どこにエクスポートするかはデプロイメントが決めます。 + +## リクエストの識別 [#request-identity] + +すべての本番デプロイメントは、リクエスト id を伝播または生成すべきです。 + +```text +X-Request-Id +``` + +これを使って次のものを関連付けます。 + +- イングレスのログ +- ObjectOS のログ +- データベースのスロークエリ +- エラーレポート +- 顧客サポートのチケット + +## メトリクスとエラー [#metrics-and-errors] + +ランタイムはメトリクスとエラーレポートをプロセス内に保持し、エクスポーターを選んだときにだけエクスポートします。少なくとも次のものを追跡してください。 + +| シグナル | 理由 | +|---|---| +| ルート/ステータス別のリクエスト数 | エラーの急増を検知する | +| リクエストの所要時間 | レイテンシの悪化を検知する | +| 5xx エラー | ランタイムの障害でアラートを出す | +| readiness の遷移 | プロセスはカーネルが構築されてから初めて準備完了を報告し、データドライバーが停止すると `/api/v1/ready` は 503 を返します | + +リクエスト数と所要時間は、サインインや REST データ API を含むすべての受信リクエストについて、メソッド、ルートパターン、ステータスのラベル付きで `http_requests_total` と `http_request_duration_ms` として出力されます。 + +### OpenTelemetry でエクスポートする [#export-with-opentelemetry] + +メトリクスは **OTLP** でランタイムの外に出ます。`OS_OBS_EXPORTER=otlp` **と** `OS_OTLP_ENDPOINT`(例:`https:///otlp`)を設定します。エクスポーターのデフォルトは `noop`(実行時コストゼロ)なので、エクスポートはオプトインです。`OS_OBS_EXPORTER=otlp` なしでエンドポイントを設定しても何も出力されず、エンドポイントなしの `otlp` は警告を出して `noop` にフォールバックします。ローカルのデバッグには `OS_OBS_EXPORTER=console` または `json` を使い、デプロイメントのタグ付けには `OS_OBS_DEPLOYMENT_ENV` を使います(デフォルトは `production`)。残りは[環境変数](/docs/reference/environment-variables#observability)に一覧があります。 + +ランタイムは独自のスクレイプエンドポイントを提供しません。Prometheus を使うには、エクスポーターを OpenTelemetry Collector に向け、コレクターから Prometheus にメトリクスを公開させます。あるいは、Grafana Cloud や Datadog など、OTLP を受け付ける任意のバックエンドに送信します。 + +パイプラインがランタイムのメトリクス名を維持していると仮定した、最初のアラートの例です。 + +```yaml +groups: + - name: objectos + rules: + - alert: ObjectOS5xxSpike + expr: | + sum(rate(http_requests_total{status=~"5.."}[5m])) + / sum(rate(http_requests_total[5m])) > 0.02 + for: 5m + annotations: + summary: "ObjectOS 5xx rate above 2% for 5 minutes" +``` + +アラートは `http_request_errors_total` ではなく `http_requests_total{status=~"5.."}` に対して設定してください。前者の系列は ObjectStack 17.2 で廃止され、常にゼロを示すため、正常なサーバーのように見えてしまいます。 + +コールドスタートは一覧にありません。カーネルは起動時に一度だけ構築され、プロセスはその後に初めて[準備完了](/docs/deploy/docker#health-checks)を報告します。定常状態でのキャッシュミスのシグナルはないので、代わりに readiness でアラートを出してください。 + +認証の失敗も一覧にありません。ランタイムのメトリクスレジストリは HTTP、ストレージ、キャッシュ、バックグラウンドジョブ、パッケージレジストリを対象としており、そのどれも拒否された認証情報を数えないため、アラートを出す系列がありません。`http_requests_total` から 401/403 を数えても代わりにはなりません。拒否された API キーは認証情報をまったく持たないリクエストと区別できず、どちらのステータスも、問題なく認証されたユーザーに対する通常の権限拒否が大半を占めます。代わりに、`view_all_audit_log` の保持者として、Setup の `Auth` 監査ビューでサインインのアクティビティを確認してください。プラットフォーム管理者はデフォルトでこれを保持しています。これがないと、サインアウトと、その後セッションが削除されたサインインは提供されません。[監査ログ](/docs/operate/audit-logs#what-each-reader-is-served)を参照してください。 + +## 監査ログ [#audit-logs] + +監査機能が有効な場合、ObjectOS は監査レコードを `sys_audit_log` に書き込みます。 + +監査ログは次の用途に使います。 + +- 権限に関わる変更 +- 設定の変更 +- ユーザー/セッションの調査 +- 連携のアクティビティ +- 拒否されたアクセスの分析 + +規制のある環境では、データベースまたはストレージの層で監査テーブルを追記専用にし、保持ポリシーを定めてください。 + +完全なフィールドのリファレンス、プリセットビュー、関連する診断ログについては、[監査ログ](/docs/operate/audit-logs)を参照してください。 + +## Setup の診断 [#setup-diagnostics] + +Setup は次のような運用向けのサーフェスを提供します。 + +- Sessions +- Audit Logs +- Notifications +- Webhook Deliveries(Webhook が有効な場合) +- System と Security の概要ダッシュボード + +これらは開発者だけでなく、オペレーターやサポートエンジニアを対象としています。 diff --git a/content/docs/operate/production.ja.mdx b/content/docs/operate/production.ja.mdx new file mode 100644 index 00000000..7798854c --- /dev/null +++ b/content/docs/operate/production.ja.mdx @@ -0,0 +1,110 @@ +--- +title: 本番環境への準備 +seoTitle: "本番環境への準備:堅牢化、シークレット、CORS、本番稼働" +description: セルフマネージドの ObjectOS デプロイメントを本番で安全に実行するためのチェックリストです。ヘッダー、シークレット、レート制限、CORS、起動時のガード、スケジュールされた処理、保持期間を扱います。 +editions: [community, enterprise] +translation: + source_sha: 0d1f08122f21ab1bab4439881d84e8ef4cd8c08c847bfc56516c59fbcc0d48c2 + guide_rev: 1 + mode: auto +--- + +ObjectOS を本番トラフィックに公開する前に、このチェックリストを使ってください。Community にも Enterprise にも当てはまります。最後の [Enterprise で追加されるもの](#enterprise-adds)のセクションには、ライセンスされたイメージに伴う項目を挙げています。 + +## HTTP の堅牢化 [#http-hardening] + +ランタイムは、デフォルトでルートに保守的なセキュリティヘッダーを送信します。ヘッダーを書き換えるプロキシを通った後の、最終的なレスポンスを確認してください。 + +- `Content-Security-Policy` +- `X-Content-Type-Options` +- `X-Frame-Options` +- `Referrer-Policy` +- `Permissions-Policy` +- `Cross-Origin-Resource-Policy` +- HSTS。ランタイムはデフォルトでは送信しません。TLS を確認してからプロキシで追加してください。 + +```bash +curl -I https://app.example.com +``` + +## シークレット [#secrets] + +これらはシークレットマネージャーに保管し、実行時に注入します。 + +| シークレット | 目的 | +|---|---| +| `OS_AUTH_SECRET` | セッション署名の基本シークレット。**すべてのレプリカで同一**にします。値の異なるレプリカは互いのセッションを拒否します。 | +| `OS_SECRET_KEY` | 保存されたすべてのシークレットを暗号化するキー。自己生成したキーがファイルシステムとともに消えるコンテナでは必須です。**データベースと一緒にバックアップしてください**。一方だけでは何も復号できません。 | +| データベースの認証情報 | 業務データベースへのアクセス | +| OIDC クライアントシークレット | シングルサインオン | +| プロバイダーの API キー | メール、ストレージ、AI、連携 | + +シークレットをアーティファクトやイメージに焼き込まないでください。 + +コントロールプレーンに**バインド**されたデプロイメントはランタイムトークンも保持しますが、それは設定するシークレットではありません。バインディングの際に発行され、ランタイムが永続化します。そのために配布するデプロイメントレベルの API キーはありません。 + +## レート制限 [#rate-limiting] + +ランタイムには組み込みのトークンバケット方式のレート制限があり、**アプリが予算を宣言するまでオフ**です(スタックの `server.security.rateLimit`)。予算を超えた呼び出し元には、`Retry-After` 付きの `429` が返されます。バケットのキーは、サインインしたユーザー、匿名のトラフィックでは呼び出し元のアドレスです。 + +リバースプロキシの背後では、アプリが `server.trustProxy: true` を設定しない限り、呼び出し元のアドレスはプロキシのものになります。これは、すべてのリクエストで `X-Forwarded-For` を上書きするプロキシの背後でだけ設定してください。そうでなければ、呼び出し元が自分のアドレスを選べてしまいます。カウンターはプロセスごとにメモリ内に保持されます。サインインには、**Setup → Authentication** で、より厳しい専用の予算を設定できます。 + +制限を代わりにエッジ(イングレスやゲートウェイ)に置く場合は、次のような予算から始めてください。 + +| トラフィック | 制限の例 | +|---|---:| +| 認証エンドポイント | 10/分/IP | +| 書き込みリクエスト | 60/分/IP | +| 読み取りリクエスト | 600/分/IP | + +## CORS [#cors] + +`OS_CORS_ORIGIN` がない場合、ランタイムはクロスオリジンの呼び出し元を**一切**受け入れません。Console と API が同じ公開オリジンを共有している間は、それで問題ありません。別のオリジンから提供されるフロントエンドは、カンマ区切りで明示的に列挙します。 + +```bash +OS_CORS_ORIGIN=https://portal.example.com,https://admin.example.com +``` + +認証情報が有効な間、`*` は起動時に拒否されます。 + +## 起動時のガードはオンのままにする [#boot-guards-stay-on] + +開発用に 2 つの抜け道があります。どちらも本番には不適切です。 + +- **`OS_ALLOW_DRIVER_CONNECT_FAILURE` は未設定にします。** 起動時に接続できないデータベースは起動を拒否するため、誤った `OS_DATABASE_URL`、ローテーションされたパスワード、閉じたネットワーク経路はデプロイの失敗になります。すべてのリクエストに 500 を返す「起動済み」のサーバーにはなりません。このフラグはデータベースなしで起動し、再接続することはありません。 +- **`OS_ALLOW_DEGRADED_TENANCY` は未設定にします。** 組織のランタイムなしで複数の組織を求めるデプロイメントは起動を拒否します。このフラグは、分離が欠けたまま起動させてしまいます。 + +## スケジュールされた処理は判断である [#scheduled-work-is-a-decision] + +アプリやパッケージが宣言するスケジュールされた処理(時間で起動するフローとパッケージ化された cron ジョブ)は、デプロイメントが `OS_AUTOMATION_SCHEDULED_WORK_ENABLED=true` を設定するまで**オフ**です。ダイジェスト、スイープ、リマインダーの起動を期待するデプロイメントは、これをオンにする必要があります。オフのままにするのも正当な答えです。意図して決めてください。実効値は `os doctor` で確認し、起動時のサマリーを読んでください。そこに *disabled by deployment policy* と表示される処理は壊れているのではなく、オフになっているだけです。[環境変数](/docs/reference/environment-variables#runtime-services)を参照してください。 + +## 保持期間は本番稼働前に設定する [#retention-is-set-before-go-live] + +プラットフォームはテレメトリをスケジュールに従って削除します。アクティビティは 14 日後、ジョブの実行は 30 日後、通知は 90 日後、監査レコードは 90 日後にホットストレージから外れます。コンプライアンス上より長い期間が必要な場合は、本番稼働の**前に** `lifecycle.retention_overrides` 設定で期間を延長してください。ポリシーによって削除されたデータは、その後に取得するすべてのバックアップから消えています。 + +## 本番稼働のチェックリスト [#go-live-checklist] + +- [ ] TLS がエッジまたはイングレスで終端されている。 +- [ ] 最終的なレスポンスにセキュリティヘッダーが含まれている。 +- [ ] TLS の検証後に HSTS が有効になっている。 +- [ ] `OS_AUTH_URL` と `OS_TRUSTED_ORIGINS` が公開アドレスと一致している。 +- [ ] CORS が、提供するクロスオリジンのフロントエンドだけを正確に受け入れている。 +- [ ] レート制限がサインインと書き込みのエンドポイントを保護している。 +- [ ] `OS_AUTH_SECRET` と `OS_SECRET_KEY` が強力で、シークレットとして保管され、預託されている。 +- [ ] アドレスを共有する前に、最初の管理者が登録されている。 +- [ ] OIDC のコールバック URL が公開ドメインと一致している。 +- [ ] `OS_ALLOW_DRIVER_CONNECT_FAILURE` と `OS_ALLOW_DEGRADED_TENANCY` が未設定である。 +- [ ] `OS_AUTOMATION_SCHEDULED_WORK_ENABLED` が、誰かが下した判断になっている。 +- [ ] 保持期間がポリシーと一致している。 +- [ ] 業務データベースのバックアップと復元がテストされている。[バックアップ](/docs/operate/backup#the-restore-drill)を参照。 +- [ ] 監査ログがポリシーに従って保持されている。 +- [ ] 監視が 5xx の割合と readiness でアラートを出す。[オブザーバビリティ](/docs/operate/observability)を参照。 +- [ ] ロールバック計画が、イメージのバージョンとアプリのアーティファクトのバージョンの両方を対象にしている。 + +## Enterprise で追加されるもの [#enterprise-adds] + +- [ ] `OS_LICENSE_KEY`(デプロイメントのエンタイトルメント)がシークレットとして保管されている。 +- [ ] `OS_CLOUD_URL` が宣言され、ライセンスモードと一致している。通常のライセンスと `off` の組み合わせは起動時に拒否されます。[エアギャップ](/docs/deploy/air-gapped#the-supported-combinations)を参照。 +- [ ] イメージがダイジェストで固定され、その署名、SBOM、来歴が検証されている([Docker](/docs/deploy/docker#verify-the-image-before-production))。 +- [ ] 複数のレプリカでは、`OS_AUTH_SECRET` と `OS_SECRET_KEY` がすべてのレプリカで同一である。 +- [ ] マルチ組織の姿勢では、メンバーシップのポリシーとマウントする AI エージェントが宣言され、`OS_PLATFORM_OWNER_EMAIL` が確認済みの管理者を 2 人以上指定し、組織をまたぐアクセスの否定テストが合格している。 diff --git a/content/docs/operate/troubleshooting.ja.mdx b/content/docs/operate/troubleshooting.ja.mdx new file mode 100644 index 00000000..7cc1518c --- /dev/null +++ b/content/docs/operate/troubleshooting.ja.mdx @@ -0,0 +1,113 @@ +--- +title: トラブルシューティング +seoTitle: "トラブルシューティング:起動、ログイン、権限" +description: 起動、アーティファクト、認証、権限、デプロイメントの問題を診断します。 +editions: [community, enterprise] +translation: + source_sha: 46522dea81d25b77061b5acda2115df72c67d2e29c36c1829b96b0df1da194eb + guide_rev: 1 + mode: auto +--- + +症状から始め、最も小さな境界から確認していきます。 + +## ObjectOS が起動しない [#objectos-does-not-start] + +**何よりも先に、ログの最後の数行を読んでください。** ここでの起動失敗の多くは、クラッシュではなく*意図的な拒否*です。ランタイムは与えられた設定を確認し、食い違っている変数を名指しした致命的エラーを表示して終了します。それらのメッセージは問題を正確に示しており、何度再起動しても結果は変わりません。 + +どちらのエディションでも最もよく遭遇する拒否は次のとおりです。 + +| ログの内容 | 意味 | +|---|---| +| データドライバーが接続できなかった | `OS_DATABASE_URL` のデータベース、またはアプリがオブジェクトをバインドするデータソースに到達できないか、認証情報が間違っています。すべてのリクエストでエラーを返すサーバーを提供する代わりに、起動が拒否されます。 | +| 破壊的なスキーマ変更が保留中で、各変更が示されている | 新しいアプリまたはバージョンに、データを失う変更が必要です。バックアップを取ってから、`os migrate apply --allow-destructive` で意図的に適用し、再起動します。 | +| アーティファクトの期待するダイジェストと実際のダイジェスト | `OS_ARTIFACT_URL` の完全性の固定が、取得したバイトと一致しません。[後述](#the-app-is-not-the-one-you-expected)を参照してください。 | +| ポートが使用中 | `os start` は別のポートに移ることはありません。ポートを解放するか、`OS_PORT` とプロキシのアップストリームを一緒に変更してください。 | +| マルチノードのトポロジーが宣言された | マルチノードのライセンスがない、または調整がプロセス内で行われるランタイムで、`OS_CLUSTER_REPLICAS` が 1 より大きくなっています。レプリカ 1 つで実行してください。[Docker → マルチノード](/docs/deploy/docker#multi-node)を参照してください。 | +| `Cannot find module 'pg'` | 素の Node.js のインストールには PostgreSQL ドライバーがありません。イメージには `pg` と `mysql2` が含まれています。イメージの外では、CLI と並べてドライバーをインストールします(`npm install -g pg`)。 | + +ログに致命的エラーがない場合は、一般的な原因を確認します。失敗しているサービスのコンテナログと、プローブです。`/api/v1/health` はプロセスが HTTP を提供し始めると応答し、`/api/v1/ready` はデータベースが応答してから初めて応答します。 + +## アプリが期待したものと違う [#the-app-is-not-the-one-you-expected] + +デプロイメントが提供するアプリはただ 1 つの場所から来ており、その場所はデプロイメントが宣言する判断です。[起動モード](/docs/architecture#boot-modes)を参照してください。実行中のアプリが公開したものと違う場合: + +- **このデプロイメントがどのモードかを確認します。** アーティファクトの参照が設定されていない場合、ランタイムはイメージが持っているものを提供しています。Community では `/srv/app/objectstack.json` のファイル、または空のカーネルとそこにインストールされたアプリ。Enterprise では、イメージ内で作成されたメタデータとそこにインストールされたもの。新しいアーティファクトを公開しても、デプロイメントがそれを指定するまでは何も変わりません。 +- **起動時のバナーを確認します。** 実際に読み込まれたアプリの名前が表示されます。 +- **一致しない完全性の固定は起動を拒否し**、期待するダイジェストと実際のダイジェストの両方を表示します。両方が一緒に表示されることが要点です。再公開されたアーティファクトと、すり替えられたアーティファクトを区別できます。 +- **固定がなく、アーティファクトのホストに到達できない場合、起動ははっきりと失敗します。** 固定なしの経路にはキャッシュへのフォールバックがありません。キャッシュされたコピーを認証する手段がないからです。オーケストレーションが再試行します。ランタイムが別のアプリをでっち上げることはありません。 +- **固定があり、ホストに到達できない場合、ローカルにキャッシュされたコピーが提供されることがあります。** ただし、そのバイトのハッシュが固定と一致するものに限られ、警告でその旨が表示されます。キャッシュは読み取りのたびに再ハッシュされます。ファイル名が根拠になることはありません。 +- **廃止されたアーティファクトの変数を設定しても、アプリは選択されません。** Enterprise イメージでは、そのうちの 1 つは起動をその場で拒否します。その他はまったく読み取られないため、デプロイメントは何も設定しなかったかのように起動します。[廃止された名前](/docs/reference/environment-variables#retired-names)に、それらと代替となる変数の対応が一覧になっています。 + +## 誰もサインインできない [#nobody-can-sign-in] + +新しいデプロイメントでは、最初に登録したアカウントが管理者になります。このルールは**ログインではなく人**を数えます。サインインアカウントなしで人のレコードを投入するアプリは、データベースにデータがあるように見せるため登録は閉じたままになり、投入された人にはサインインに使うパスワードがありません。起動ログは、これを `no_sign_in_account_at_boot` としてエラーレベルで報告します。復旧は帯域外で行います。招待の行を 1 つデータベースに書き込み、通常の登録を行います。手順は ObjectStack の[セルフホスティングガイド](https://objectstack.ai/docs/deployment/self-hosting#a-seeded-directory-opens-no-bootstrap-window)で説明されています。これを防ぐには、人と一緒にサインインアカウントを投入するか、最初の管理者ができるまでディレクトリを空のままにしてください。 + +## ログインに失敗する [#login-fails] + +確認すること: + +- `OS_AUTH_SECRET` が設定されている。これがないと、サインインエンドポイントはまったく有効になりません +- `OS_AUTH_URL` と `OS_TRUSTED_ORIGINS` が公開アドレスを指している +- OIDC のコールバック URL が公開アドレスと一致している +- OIDC のディスカバリー URL に ObjectOS から到達できる +- 信頼されたオリジンに公開ドメインが含まれている +- Cookie のスコープがデプロイメントの公開ホスト名になっている + +## ユーザーがレコードを見られない [#user-cannot-see-records] + +確認すること: + +1. デプロイメントのホスト名が正しい。 +2. ユーザーが想定した組織に所属している。 +3. オブジェクトの `read` 権限。 +4. 行レベルセキュリティ。 +5. 共有ルールまたはレコードの共有。 +6. 一部のフィールドだけが見えない場合は、フィールドのセキュリティ。 + +## 設定を編集できない [#settings-are-not-editable] + +設定は環境のオーバーライドによってロックされている場合があります。実効的な設定は次の順序で解決されます。 + +```text +Environment -> Tenant -> User -> Default +``` + +環境が値を提供している場合、実行時の編集は、黙って上書きするのではなく拒否されるべきです。 + +## 保存されたシークレットを読めない [#stored-secrets-cannot-be-read] + +暗号化された設定、`secret` フィールド、データソースの認証情報は、`OS_SECRET_KEY` で暗号化されています。再起動や復元の後に復号できなくなった場合は、キーが変わっています。キーを設定しなかったコンテナが独自のキーを生成し、ファイルシステムとともに失ったか、データベースが元のキーなしで復元されたかです。預託した元の値を設定してください。[バックアップ](/docs/operate/backup)を参照してください。新しいキーで、古いキーで暗号化された値を回復することはできません。 + +## Webhook やジョブが実行されない [#webhooks-or-jobs-do-not-run] + +確認すること: + +- アーティファクトの `requires` リストに必要な機能が含まれている +- ObjectOS イメージにオプションのサービスパッケージが含まれている +- キュー/ジョブサービスの設定が利用できる +- スケジュールフローと cron ジョブには `OS_AUTOMATION_SCHEDULED_WORK_ENABLED=true` が必要。未設定はオフです +- 送信先へのアウトバウンドのネットワークアクセスが許可されている +- 配信ログまたはジョブの実行が Setup の診断で表示される + +## データベースのエラー [#database-errors] + +確認すること: + +- データベース URL とドライバーの種類 +- ObjectOS からデータベースへのネットワークアクセス +- 認証情報と TLS のオプション +- スキーマの同期/マイグレーションのログ +- ローカルの SQLite を使っている場合は、ストレージの永続性 + +## Enterprise で追加されるもの [#enterprise-adds] + +ライセンスされたイメージは、起動時にさらにいくつかの設定を拒否します。 + +| ログの内容 | 意味 | +|---|---| +| 2 つの設定がサポートされない組み合わせとして一緒に示されている | 両立しないライセンスモードとクラウドの姿勢です。最も多いのは、コントロールプレーンなしで設定されたデプロイメント上の、オンラインで検証される通常のライセンスです。サポートされる組み合わせの表は[エアギャップ](/docs/deploy/air-gapped)にあります。 | +| 壁で区切られたデプロイメントにはライセンスが必要 | ライセンスなしでマルチ組織のテナンシーの姿勢が求められました。分離はライセンスされた機能であり、ランタイムは分離があるふりをしてトラフィックを提供することはありません。 | +| 判断が下されていない | マルチ組織の姿勢では、新規サインアップのメンバーシップのポリシーと、マウントする AI エージェントのセットに安全なデフォルトがありません。どちらの値を宣言しても受け入れられますが、未設定のままにすることは受け入れられません。 | +| 廃止された変数が設定されている | 古いアーティファクト選択の変数は起動を拒否し、代替となる変数を示します。[廃止された名前](/docs/reference/environment-variables#retired-names)を参照してください。 | +| クラスターのシークレットがない | クラスタードライバーを有効にすると、すべてのレプリカで共有する 1 つのシークレットキーが必須になります。 | diff --git a/content/docs/operate/upgrade.ja.mdx b/content/docs/operate/upgrade.ja.mdx new file mode 100644 index 00000000..c55ccb0b --- /dev/null +++ b/content/docs/operate/upgrade.ja.mdx @@ -0,0 +1,142 @@ +--- +title: アップグレードとロールバック +description: データベースをバックアップしたうえで、固定する正確なイメージを変更して、セルフマネージドの ObjectOS デプロイメントをアップグレードまたはロールバックします。ObjectStack の各リリースが求めるオペレーターの手順も扱います。 +editions: [community, enterprise] +translation: + source_sha: 98d9f60a7e174ca49ba4e63e570cba5e24d158bd80e44ddfc9cc8d36d2fb0d5d + guide_rev: 1 + mode: auto +--- + +アップグレードとは固定する正確なイメージの変更であり、ロールバックとは以前のイメージに戻すことです。Community では、それはイメージの正確なバージョンタグと、固定している場合はそのダイジェストです。タグはそのバージョンが再ビルドされると新しいバイトに再びプッシュされることがありますが、ダイジェストは決して動きません([Docker → イメージを固定する](/docs/deploy/docker#pin-the-image)を参照)。Enterprise では、リリースノートに記載されたダイジェストです([Enterprise で追加されるもの](#enterprise-adds))。このページのそれ以外の内容は両方に共通です。[Docker → アップグレードとロールバック](/docs/deploy/docker#upgrade-and-rollback)に手順と各ステップの理由を記載しています。このページはそれをチェックリストとして繰り返し、特定のリリースが求める手順を追加します。 + +## アップグレード [#upgrade] + +1. 実行中のバージョンから移行先のバージョンまでの、すべての ObjectStack リリースのノートを読み、後述の[バージョン固有の手順](#version-specific-steps)を順に実施します。メジャーバージョンの移動は、下層に破壊的変更があることを意味します。 +2. **データベースをバックアップします。** スキーマのマイグレーションは*前にしか進みません*。イメージをロールバックしても、スキーマはロールバックされません。 +3. イメージを新しい正確なバージョン(ダイジェストを固定している場合はそのダイジェスト)に変更し、再起動します。スキーマはランタイムが準備完了を報告する前に最新の状態にされます。破壊的な変更は、`os migrate apply --allow-destructive` で適用するまで、その変更を示して起動を拒否します。 +4. readiness(`/api/v1/ready`)が 200 を返すことを確認します。 + +## ロールバック [#roll-back] + +**以前の**バージョンと、固定している場合はそのダイジェストを残しておきます。それがロールバックです。ロールバックするには、それに戻して手順 3 を繰り返します。離れるバージョンが互換性のないスキーマ変更を行っていない限り有効です(行った場合はリリースノートに記載されています)。シークレットにも同じ一方通行の境界があります。ObjectStack 17.7 以降で設定またはローテーションしたシークレットは、17.7 より前のリリースでは読めません(後述の [17.7](#objectstack-177) を参照)。 + +## アプリは別にバージョン管理される [#the-app-versions-separately] + +アプリ自体は、公開済みアーティファクトとして提供される場合、イメージとは独立してバージョン管理されます。[デプロイ → アプリの組み込み方](/docs/deploy#how-the-app-gets-in)を参照してください。公開したアーティファクトは不変として扱ってください。その場で上書きすると、データベースのバックアップが完璧でも、きれいにロールバックする能力を失います([バックアップ → アーティファクトのバージョン管理](/docs/operate/backup#artifact-versioning))。 + +## バージョン固有の手順 [#version-specific-steps] + +上記の手順はすべてのリリースで同じです。ObjectOS の下層にある ObjectStack のリリースの中には、オペレーターに対応を求めるものもあります。新しいイメージが起動する前に変数を設定する、データマイグレーションを実行する、認証情報をローテーションする、などです。Community イメージのバージョンは ObjectStack のバージョン**そのもの**です。Enterprise では、イメージの[リリースマニフェスト](/docs/deploy/docker#the-image-can-tell-you-what-it-is)に、組み込まれた ObjectStack のバージョンが記載されています。通過するすべてのバージョンのサブセクションを、古いものから順に、上記の手順と並べて実施してください。 + +各サブセクションは、そのリリースのアップグレードチェックリストのうちオペレーターが担う部分であり、チェックリスト全体へのリンクがあります。リリースが実行中のアプリ(そのメタデータとコード)に対して変更する内容は、同じチェックリストと[変更履歴](/docs/resources/changelog)にあります。`os migrate` コマンドは、新しいイメージが組み込むバージョンの ObjectStack CLI です。メタデータを読むためにアプリを起動するので、デプロイメントの起動時と同じ環境(同じデータベースと同じアプリ)で実行してください。[CLI → データベースのマイグレーション](/docs/reference/cli#database-migrations--os-migrate)を参照してください。 + +> **コピーで予行演習してください。** リリースノートでは、チェックリストのほとんどの行が *not exercised* とされています。実際のアップグレードを通して確認したものではなく、変更内容から導いたものです。各手順はまずデータベースのコピーに対して実行し、本番の前にバックアップを取ってください。 + +### ObjectStack 17.0 [#objectstack-170] + +- **2 つのデータマイグレーションを実行します。** `os migrate files-to-references` を実行してから `--apply` 付きでもう一度実行します。そして `os migrate value-shapes` を実行し、何も報告されなくなったら `--apply` を実行します。それぞれがフラグを記録するまで、17.0 より前に作成されたデータベースは不正な形式のファイル値と参照値を警告付きで受け入れ続けます。記録後は拒否します。期限までに修正できない連携については、[抜け道](/docs/reference/environment-variables#data-contract-escape-hatches)を参照してください。 +- **アプリがバインドするすべてのデータソースが接続できなければなりません。** 接続できないものがあると起動は失敗し、応答しなくなったものがある間、`/api/v1/ready` は `503` を返します。 + +チェックリスト全体:[17.0.0](https://objectstack.ai/docs/releases/v17/17-0#upgrade-checklist)。 + +### ObjectStack 17.1 [#objectstack-171] + +- **アップグレードの前に、オフにされた権限セットとポジション**(`active: false`)**を一覧にします。** 17.1 以降、それらは権限を付与しなくなり、無効化されたポジションを指定する共有ルールは共有が取り消されます。引き続き権限を付与すべきものは再度有効にしてください。 +- **`isolated` では API キーを再発行します。** 17.1 より前に発行されたキーは組織を持たないため、`OS_TENANCY_POSTURE=isolated` では拒否されます。 +- **エクスポートはオブジェクトごとに付与されます。** 標準の管理者権限セットは、すべてのオブジェクトをエクスポートできなくなりました。エクスポートを意図する場所では、アプリ自身の権限セットで `allowExport` を付与してください。 + +チェックリスト全体:[17.1.0](https://objectstack.ai/docs/releases/v17/17-1#upgrade-checklist)。 + +### ObjectStack 17.2 [#objectstack-172] + +- **`http_request_errors_total` をキーとする監視を向け直します。** この系列は廃止され、常にゼロを示すため、正常なサーバーのように見えてしまいます。`http_requests_total{status=~"5.."}` を使ってください。 +- 外部データソースのルートを呼び出す認証情報には、**`manage_platform_settings` または `manage_metadata` を付与します**。これらのルートは、それ以外の呼び出し元を `403` で拒否するようになりました。 + +チェックリスト全体:[17.2.0](https://objectstack.ai/docs/releases/v17/17-2#upgrade-checklist)。 + +### ObjectStack 17.3 [#objectstack-173] + +- **壁で区切られた姿勢では、新しいイメージが起動する前に `OS_PLATFORM_OWNER_EMAIL` を設定します。** そうしないと起動を拒否します。[環境変数](/docs/reference/environment-variables#multi-organization-deployments)を参照してください。 +- **新しい一意インデックスを構築できるように、自動採番の重複を解消します。** `os migrate duplicates` を実行し、報告された重複を修正してから、`os migrate plan` を再実行します。それまではインデックスは構築されず、一意性も強制されません。起動時にはログが出るだけなので、問題なく起動したことはインデックスが存在する証拠になりません。 +- **`sys_record_share` をバックフィルします。** 17.3 より前に書き込まれた共有の付与は組織を持たず、テナントスコープの読み取りでは見つからなくなります。ObjectStack はこのバックフィルを、`os` コマンドではなく、`@objectstack/plugin-sharing` の 2 つの関数 `planSysRecordShareOrganizationBackfill`(ドライラン)と `runSysRecordShareOrganizationBackfill` として提供しており、起動時に自動実行されることはありません。 +- **オープンなサインアップは宣言が必要になりました。** 対象者の姿勢を宣言しないアプリは招待制です。アドレスに保留中の招待がない限り、自己登録は `403 SELF_REGISTRATION_CLOSED` で拒否されます(新規インストールの最初のアカウントは例外です)。 + +チェックリスト全体:[17.3.0](https://objectstack.ai/docs/releases/v17/17-3#upgrade-checklist)。 + +### ObjectStack 17.4 [#objectstack-174] + +- **`isolated` では、組織を持たない API キーを再発行します。** それらは `200` から `401` に変わります。`group` では、そのようなキーは引き続き機能します。 +- 認可ストアに到達できない間、**ストレージのダウンロードと設定のルートは `503` を返します**。以前は黙って劣化していました。 + +チェックリスト全体:[17.4.0](https://objectstack.ai/docs/releases/v17/17-4#upgrade-checklist)。 + +### ObjectStack 17.5 [#objectstack-175] + +アップグレードの前に: + +- **壁で区切られた姿勢では、すべてのプラットフォーム管理者を `OS_PLATFORM_OWNER_EMAIL` に列挙します**(カンマ区切り、確認済みのアドレス)。`admin_full_access` の付与はその地位を与えなくなり、宣言のないデプロイメントはプラットフォーム管理者なしで起動します。 +- **スケジュールされた処理について決めます。** 時間で起動するフローとパッケージ化された cron ジョブは、デプロイメントが `OS_AUTOMATION_SCHEDULED_WORK_ENABLED=true` を設定しない限り実行されなくなります。`isolated` では、まず各スケジュールフローの開始ノードに実行時の `organization` を指定し、中断中の実行を排出してください。[フローと自動化](/docs/build/automation/flows#scheduled-run-on-a-clock)を参照してください。 +- **アカウント識別情報の変更を事前確認します。** `os migrate account-issuer` を実行し(読み取り専用。2 つのアカウントが衝突する間はゼロ以外で終了します)、報告されたすべての衝突を解消します。衝突する行が自動的にマージされることはありません。 + +リリースへの移行: + +```bash +os migrate account-issuer # expect: safe to drop +os migrate plan # read every destructive change first +os migrate apply --allow-destructive # drops sys_account.issuer, after a backup +os migrate account-issuer # again: expect zero collisions +``` + +`--allow-destructive` は、これだけでなくプランに列挙されたすべての破壊的な変更を適用します。そのため、先にプランを確認します。 + +その後: + +- 匿名の `GET /api/v1/auth/get-session` は、`null` 付きの `200` ではなく `401` を返します。 +- Analytics は、オブジェクトを読めない呼び出し元を `403` で拒否します。 +- 失敗した通知の配信は 90 日ではなく 7 日間保持されます。 + +チェックリスト全体:[17.5.0](https://objectstack.ai/docs/releases/v17/17-5#upgrade-checklist)。 + +### ObjectStack 17.6 [#objectstack-176] + +- **アプリがオブジェクトを読み書きする匿名エンドポイント**(`authRequired: false`)**を宣言している場合は、アップグレードを保留します。** 17.6 以降、そのエンドポイントはすべてのオブジェクトで拒否され、匿名の呼び出し元に権限セットを付与するサポートされた方法は、17.7 でもありません。公開フォームは別の入り口であり、引き続き機能します。 +- `/api/v1/meta` を通じて `datasource` または `external_catalog` のメタデータを読む、あるいは `datasource` のメタデータを保存するすべてのユーザーまたは連携に、**`manage_platform_settings` を付与します**。 +- **パッケージ化されたフローと同じ名前を持つ保存済みのフローを見つけます**(起動ログがそれぞれについて警告します)。17.6 以降はパッケージ化されたフローが優先され、保存済みのものは実行されなくなります。必要なものは新しい名前で複製してください。 +- **保存されたメタデータ本体のコピーを書き換えます:** `os migrate audit-metadata-bodies` を実行してから、`--apply` 付きでもう一度実行します。⚠️ 17.6.0 ではドライランでもデータベースに書き込みます。コピーに対して実行してください。 +- **西暦 1000 年より前の `datetime` の値を見つけて**書き換えます。アップグレード後は、そのような値を含む書き込みはすべて拒否されます。 + +チェックリスト全体:[17.6.0](https://objectstack.ai/docs/releases/v17/17-6#upgrade-checklist)。 + +### ObjectStack 17.7 [#objectstack-177] + +アップグレードの前に: + +- **廃止されたフィールドの残りの列を読む変換は**、そのフィールドがまだ宣言されている間に**実行します**。アップグレード後は、ランタイムのどの入り口もその列を返しません。読めるのは `os migrate unmapped-columns --object NAME` だけです。 +- **公開のままにする必要があるすべての公開フォームに `sharing.enabled: true` を追加します**。アプリと保存済みのオーバーレイの両方です。これがないと、フォームは `404 FORM_NOT_FOUND` を返します。 +- **17.7 より前にロールバックする可能性がある場合は、すべてのシークレットを再設定できる手段を残しておきます。** 17.7 で設定、ローテーション、または再封印されたシークレットは、以前のリリースでは開けない形式で書き込まれます。 +- **インメモリの起動ストアを置き換えます**(`OS_DATABASE_DRIVER=memory` または `memory://` の URL)。これは拒否されます。 + +リリースへの移行:`os migrate audit-metadata-bodies` を実行してから `--apply` 付きでもう一度実行し、監査とアクティビティのコピーから保存されたコンテンツハッシュを削除します。17.7 のドライランは書き込みを行わなくなりました。アップグレード前から保持しているメタデータのバージョントークンは、一度だけ `409 METADATA_CONFLICT` を返します。項目を読み直して新しいトークンを取得してください。 + +最初の起動の後: + +- **すべてのフローのシークレット**(受信フックの `secret` と `http` ノードの `signingSecret`)**をローテーションします**。起動ログが `sys_flow_credential` に移動したと報告してから行い、署名または検証する人に新しい値を渡してください。 +- **JWT の署名キーをローテーションし、非公開のままにすべき共有リンクを取り消して再発行します。** 以前の値は監査証跡にコピーが残っている可能性があり、アップグレードはそれを書き換えません。 +- **アップグレード前に一時停止したフローの実行を、再開、キャンセル、またはパージします。** 保存された変数には、まだ認証情報が平文で残っています。 +- **任意。17.7 より前にロールバックしないと決めてから:** `os secret rewrap` を実行してから `--apply` 付きでもう一度実行すると、古いシークレットが新しい形式で再封印されます。アップグレードの過程でこれが実行されることはありません。 +- `/api/settings/localization` に書き込むクライアントから、**廃止されたローカライズのキーを削除します**:`date_format`、`time_format`、`number_format`、`first_day_of_week`。いずれかを指定したリクエストは、全体が `400` で拒否されます。 +- **未確認のローカルメールアドレスへの外部サインインは拒否されます**(`account_not_linked`)。そのアカウントに黙ってリンクされることはなくなりました。 + +チェックリスト全体:[17.7.0](https://objectstack.ai/docs/releases/v17/17-7#upgrade-checklist)。 + +## Enterprise で追加されるもの [#enterprise-adds] + +Enterprise イメージはタグではなく、常に**ダイジェスト**で固定します。したがって、アップグレードはダイジェストの変更であり、ロールバックは以前のダイジェストに戻すことです。 + +1. リリースノートから**新しいダイジェスト**を取得し、ロールアウトの前にイメージの[リリースマニフェスト](/docs/deploy/docker#the-image-can-tell-you-what-it-is)を読みます。製品のメジャーラインが現在のものと同じであることを確認し、組み込まれたランタイムの互換性範囲が動いたかどうかを確認します。 +2. データベースをバックアップしてから、イメージのダイジェストを変更してスタックを再起動します。マイグレーションは、新しいレプリカがトラフィックを受ける前に完了まで実行されます。 +3. readiness が 200 を返し、レプリカが正常と報告することを確認します。ロールバック先として以前のダイジェストを残しておいてください。 + +- **Kubernetes**:アップグレードは同じくイメージのダイジェストの変更であり、新しいレプリカが提供を始める前にマイグレーションの Job が完了まで実行されます。[Kubernetes → ローリングアップグレードはダイジェストを変更する](/docs/deploy/kubernetes#rolling-upgrades-change-the-digest)を参照してください。 +- **エアギャップ**:新しいダイジェストを外部で検証し、内部に転送し、固定するダイジェストを変更して再起動します。以前のダイジェストは残しておいてください。エアギャップのネットワーク内では、それがロールバック先となる唯一のコピーかもしれません。[エアギャップ → イメージをネットワーク内に持ち込む](/docs/deploy/air-gapped#getting-the-image-inside-the-network)を参照してください。 From 3df88d4a2de1ff8583f1bb4317533626bc65b154 Mon Sep 17 00:00:00 2001 From: Steedos Date: Thu, 29 Oct 2026 13:57:56 +0000 Subject: [PATCH 10/22] docs(i18n): translate reference/, architecture and ontology into ja (#388, PR 6 of 7) Adds ja translations for the 9 reference/ pages and the two root pages, architecture and ontology. reference/meta.ja.json already matches the English pages list; the root sidebar has only meta.json. Same rules as the earlier batches. check-translations: ja 0 stale, 4 missing (was 15). Refs #388 Claude-Session: https://claude.ai/code/session_01QsR2jRsjbApbf83iyTDDXm Co-Authored-By: Claude --- content/docs/architecture.ja.mdx | 137 +++++++++ content/docs/ontology.ja.mdx | 62 +++++ content/docs/reference/cel.ja.mdx | 92 +++++++ content/docs/reference/cli.ja.mdx | 259 ++++++++++++++++++ .../reference/environment-variables.ja.mdx | 162 +++++++++++ content/docs/reference/field-types.ja.mdx | 96 +++++++ content/docs/reference/objectql.ja.mdx | 77 ++++++ content/docs/reference/rest-api.ja.mdx | 122 +++++++++ .../reference/runtime-capabilities.ja.mdx | 66 +++++ content/docs/reference/security.ja.mdx | 241 ++++++++++++++++ content/docs/reference/skills-cli.ja.mdx | 48 ++++ 11 files changed, 1362 insertions(+) create mode 100644 content/docs/architecture.ja.mdx create mode 100644 content/docs/ontology.ja.mdx create mode 100644 content/docs/reference/cel.ja.mdx create mode 100644 content/docs/reference/cli.ja.mdx create mode 100644 content/docs/reference/environment-variables.ja.mdx create mode 100644 content/docs/reference/field-types.ja.mdx create mode 100644 content/docs/reference/objectql.ja.mdx create mode 100644 content/docs/reference/rest-api.ja.mdx create mode 100644 content/docs/reference/runtime-capabilities.ja.mdx create mode 100644 content/docs/reference/security.ja.mdx create mode 100644 content/docs/reference/skills-cli.ja.mdx diff --git a/content/docs/architecture.ja.mdx b/content/docs/architecture.ja.mdx new file mode 100644 index 00000000..0b2b36f8 --- /dev/null +++ b/content/docs/architecture.ja.mdx @@ -0,0 +1,137 @@ +--- +title: アーキテクチャ +seoTitle: "アーキテクチャ:何が動き、データがどこにあるか" +description: 実際に何を動かすことになるのか。導入するかどうかを評価しているエンジニアのために。 +editions: [community, cloud, enterprise] +translation: + source_sha: 9292459ed8a30885f3b5c660fb772187d5d1edb8ead66c12839ab7900dcbef3f + guide_rev: 1 + mode: auto +--- + +ObjectOS をデプロイしたときに何が動くのか(**ObjectOS Enterprise** で自社のマシン上で動かす場合も、**ObjectOS Cloud** で私たちが運用する場合も)、どのデータがネットワークの外に出て、どのデータが出ないのかを、実践的な視点から説明します。 + +メンタルモデルは、ひとつの定義と、それを実行するひとつのランタイムです。 + +1. **あなたの[オントロジー](/docs/ontology)**:ビジネスの定義です。オブジェクトとフィールド、リレーション、アクション、権限、フロー、そしてエージェントとツールの定義。ビュー、ダッシュボード、アプリ、翻訳は、そのプロジェクションとして横で作成されます。ほとんどはサンドボックス化されたツール API を通じて [AI Builder](/docs/build/ai-builder) が書き、ときには手で編集されます。実行される前に必ず検証され、バージョン管理され、監査されます。 +2. **単一の Node.js ランタイム**:そこから動作するアプリケーション(データベーススキーマ、REST API、Console の UI、エージェントが呼び出す MCP サーバー)を**導出**し、すべての呼び出しでそれを**強制**します。RBAC、行レベルとフィールドレベルのセキュリティ、共有、監査は、REST のリクエストにも、Console でのクリックにも、エージェントのツール呼び出しにも同じように適用されます。すべてがひとつのプロセスの中で、あなたのデータベースと通信します。 + +```text +your ontology + objects · relations · actions + permissions · flows · agents + + projections: views · dashboards + apps · translations + │ + ▼ +ObjectOS runtime + derives the app, enforces it + │ + ├──▶ database its schema + ├──▶ REST API /api/v1/* + ├──▶ Console /_console/ + └──▶ MCP server /api/v1/mcp +``` + +「ユーザーが望むものを説明した」と「それが稼働している」の間に、コード生成の手順もデプロイのパイプラインもありません。ランタイムは、ヒューマンインザループ(HITL)の承認の後に新しいメタデータをホットロードします。 + +## デプロイするもの [#what-you-deploy] + +ひとつのアプリを提供する、ひとつの Node.js プロセス。それだけです。ObjectOS Community では、オープンソースのイメージからそのプロセスを自分で実行します(`os start`)。ObjectOS Cloud では私たちが実行します。ObjectOS Enterprise では、[デプロイ](/docs/deploy)で説明しているライセンスされた Enterprise イメージからデプロイします。 + +```text +┌─────────────────────────────────────────────────────┐ +│ ObjectOS process │ +│ ┌───────────────────────────────────────────────┐ │ +│ │ HTTP dispatcher (/ · /api · /_console …) │ │ +│ ├───────────────────────────────────────────────┤ │ +│ │ ObjectKernel — this deployment's app │ │ +│ │ ├─ Auth (Better Auth) │ │ +│ │ ├─ Security (RBAC + row-level + field) │ │ +│ │ ├─ ObjectQL (data engine, generates SQL) │ │ +│ │ ├─ REST API generator │ │ +│ │ ├─ MCP server (/api/v1/mcp, on by default) │ │ +│ │ └─ Capabilities loaded per artifact │ │ +│ │ (audit, storage, jobs, queue, AI …) │ │ +│ └───────────────────────────────────────────────┘ │ +└──────────┬──────────────────────────────────────────┘ + │ + ▼ + Your business database + (Postgres / MySQL / SQLite / Turso / MongoDB) +``` + +複雑さは、静的にリンクされた単一のバイナリ程度です。サイドカーも、Kafka も、別のキャッシュレイヤーも必要ありません。必要になったときに追加すればよく、初日からそのコストを払う必要はありません。 + +**デプロイメントはひとつのアプリを提供します。** どのアプリかはデプロイメントレベルの判断であり([起動モード](#boot-modes)を参照)、デプロイメントが提供するすべての人にとって同じアプリです。複数の組織が共有する、壁で区切られたデプロイメントでも同様です。デプロイメントを拡張するには、ひとつのプロセスに多くのアプリを詰め込むのではなく、同じプロセスの同一のレプリカを増やします。[Docker](/docs/deploy/docker) を参照してください。 + +## データの置き場所 [#where-your-data-lives] + +**ObjectOS Enterprise**(この表が記述するセルフマネージドのエディション)では、以下のものはどれもネットワークの外に出ません。**ObjectOS Cloud** では、同じプロセスが代わりに私たちのインフラストラクチャで動作します。どちらのエディションでも、オントロジー自体はあなたのものです。エクスポートして、オープンソースの ObjectStack ランタイムで実行できます。[データレジデンシー](/docs/reference/security#data-residency)には、データの各分類について、どこに保存され、ネットワークの外に出るかどうかが記載されています。 + +セルフマネージドの ObjectOS はライセンスをオンラインで検証します。Enterprise のエアギャップライセンスはオフラインで検証します。したがって、インターネットにまったくアクセスできないデプロイメントも動作し続けます。サポートされるライセンスとクラウドの姿勢の組み合わせについては、[エアギャップ](/docs/deploy/air-gapped)を参照してください。 + +## リクエストの処理 [#how-a-request-is-served] + +```text +1. Ingress / TLS termination (your load balancer) +2. HTTP dispatcher (security headers, request id) +3. AuthPlugin — session cookie, bearer token, or API key +4. SecurityPlugin — RBAC + row-level + field-level checks +5. Route handler — generated REST, MCP tool call, declarative action, + or custom +6. Data driver — ObjectQL compiles to SQL / Mongo query +7. Response with X-Request-Id propagated +``` + +エージェントの呼び出しも同じ経路をたどります。MCP クライアントは OAuth または API キーでユーザーとして認証し、同じ権限のチェックが、そのツール呼び出しが読み書きできる範囲を制限します。[AI ツールを接続する(MCP)](/docs/configure/mcp)を参照してください。 + +アプリは最初のリクエストが届く前にすでに解決されています。カーネルは起動時に構築され、それが終わるまでプロセスは[準備完了](/docs/deploy/docker)を報告しません。そのため、提供されるリクエストには、それが*どの*アプリに属するかを決める手順がなく、読み手が考慮すべきアプリごとのウォームアップもありません。リクエストのコストは、認証、権限のチェック、そしてコンパイル済みのクエリ 1 つです。 + +## 3 つの層(連携する場合にのみ重要) [#the-three-layers-only-matters-if-youre-integrating] + +ほとんどの顧客は **ObjectOS** だけを実行します。他の 2 つの層は、アーティファクトがどこから来るのかを知りたい場合のためにあります。 + +| 層 | 内容 | 動作する場所 | +|---|---|---| +| **フレームワーク**(`@objectstack/*`) | オープンソースのカーネル、ObjectQL、プラグイン、ドライバー | npm。ビルド時に取り込まれます | +| **コントロールプレーン**(任意) | コンパイル済みの `objectstack.json` アーティファクトを公開します。ホスト型の ObjectOS Cloud を使うことも、自前で運用することも、まったく使わないこともできます | あなたの CI、私たちのクラウド、またはあなたのノートパソコン | +| **ObjectOS** | フレームワーク上に構築された商用ランタイム環境 | **ObjectOS Cloud**(私たちが運用)または**あなたのインフラストラクチャ**(ObjectOS Enterprise) | + +単一のアプリを出荷するなら、コントロールプレーンは不要です。CI で `objectstack.config.ts → dist/objectstack.json` をコンパイルし、その JSON をイメージに入れて出荷します。複数のデプロイメントがインストールするアプリを公開する場合は、コントロールプレーンがそのカタログの置き場所になります。 + +## 起動モード [#boot-modes] + +実行中のアプリがどこから来るかはひとつの判断であり、デプロイメントがそれを宣言します。提供されるデフォルトは設定が不要です。その他の各モードは公開済みのアーティファクトを指定することで選択され、それぞれの正確な契約は[環境変数](/docs/reference/environment-variables)のリファレンスにあります。 + +| モード | 使う場面 | アプリの届き方 | +|---|---|---| +| **Config-authored** | 提供される形態。単一のアプリ、評価、エアギャップ、ほとんどの本番デプロイメント | ランタイムは、イメージ内で作成されたメタデータと、そこにインストールされたものを起動します | +| **Artifact-pinned** | アプリが、ランタイムのイメージとは別に、独自のペースでリリースされる | 1 つの変数が、公開済みのアーティファクトを URL で指定します。完全性の固定は任意です。アプリのアップグレードは、その変数の変更と再起動で済みます | +| **Composed** | 分離の壁の背後にある複数の組織が 1 つのデータベースを共有し、公開済みのアプリを実行する。ホスト型の単一アプリ SaaS の形態です | 同じアーティファクトの参照を、デプロイメント自身の設定から読み込むため、Enterprise プラグインが一緒に読み込まれます。エアギャップライセンスのみで、それ以外は[起動時に拒否されます](/docs/deploy/air-gapped) | + +デプロイメントが**コントロールプレーン**とも通信するかどうかは別の判断であり、クラウドの姿勢の変数で決まります。接続されたデプロイメントは、上記のどのモードでもかまいません。セルフマネージドのランタイムは、ファイルに貼り付けたキーではなく、デプロイメントがコントロールプレーンに**バインド**されたときに発行されたトークンで認証します。間違ったライセンスモードと間違ったクラウドの姿勢の組み合わせは、[起動時に拒否されます](/docs/deploy/air-gapped)。 + +## 性能の特性 [#performance-characteristics] + +**このページはレイテンシやメモリの数値を掲載しません。** 実行するのは、*あなたの*データベースに対して*あなたの*アプリを提供する、ダイジェストで固定したイメージであり、デプロイメントのサイジングに使う価値のある数値は、それを実際に計測したものだけです。このページが示せるのはその形です。各コストがどこから来るか、そしてそれを何として計測すべきかです。 + +| 特性 | どこから来るか、どう計測するか | +|---|---| +| **起動** | プロセスが起動し、このデプロイメントのアプリのためにカーネルを構築し、その後で初めて準備完了を報告します。自分のイメージとアーティファクトで、`/api/v1/ready` が 200 を返すまでの時間として計測します。アプリが大きく、読み込む機能が多いほど、処理は増えます。 | +| **リクエストのレイテンシ** | 認証、権限のチェック、そして ObjectQL がコンパイルしたクエリ 1 つ。リクエストごとにどのアプリを提供するかを解決する処理はないため、通常変動するのはデータベースとの往復です。自分のデータ量に対して、自分のパーセンタイルで計測してください。 | +| **メモリ** | このデプロイメントのメタデータの常駐コピー 1 つ、アプリが読み込む機能(オプションのプラグインなので、読み込みが少ないデプロイメントほど保持するものも少なくなります)、そして同時実行中の処理。アイドル時ではなく、自分の負荷のもとでコンテナの RSS を計測してください。 | +| **1 つのプロセスを超えて拡張する** | 同じプロセスのレプリカで、それぞれが同じアプリを提供します。レプリカが 2 つ以上になると、クラスタードライバーと同一の共有シークレットが必須になります。[Docker](/docs/deploy/docker) を参照してください。 | + +## なぜこの形なのか [#why-this-shape] + +- **ひとつの Node プロセス、サイドカーなし** → `docker run` に収まり、systemd のユニットに収まり、長時間動作するコンテナや VM に収まります。 +- **デプロイメントごとにひとつのアプリ** → メタデータはリクエストごとではなく起動時に一度だけ解決されるため、正しく設定すべきキャッシュのサイズがありません。複数の組織がデプロイメントを共有する場合も、組織はそのアプリを共有し、組織間の分離の壁はランタイムの内部で強制されます。 +- **宣言されたメタデータの上に生成される API** → CI にコード生成の手順はなく、公開すべきクライアント SDK もありません。API は構造上、データモデルと一致します。 +- **すべての機能はオプションのプラグイン** → イメージのサイズは、実際に使うものに応じて増減します。 + +## 次に進む [#where-to-go-next] + +- [本番環境への準備](/docs/operate/production):実際のトラフィックに公開する前のチェックリスト。 +- [ランタイム設定](/docs/configure/runtime):データベース、キャッシュ、シークレットの接続。 +- [ランタイムの機能](/docs/reference/runtime-capabilities):どのオプションのパッケージがあり、何を有効にするか。 diff --git a/content/docs/ontology.ja.mdx b/content/docs/ontology.ja.mdx new file mode 100644 index 00000000..ebcec30c --- /dev/null +++ b/content/docs/ontology.ja.mdx @@ -0,0 +1,62 @@ +--- +title: ObjectOS におけるあなたのオントロジー +seoTitle: "ObjectOS におけるあなたのオントロジー:コア、プロジェクション、置き場所" +description: ObjectOS におけるあなたのオントロジーとは何か。ランタイムが実行するコア、その横で作成されるプロジェクション、置き場所、そしてオントロジーでないものを説明します。 +editions: [community, cloud, enterprise] +translation: + source_sha: 89b7e2e2e35db3cfc1e321a759eade603c86bbf958670a2c0abd7952bb51a8ab + guide_rev: 1 + mode: auto +--- + +**オントロジーこそがソフトウェアです。** ObjectOS において、*あなたのオントロジー*とは、ランタイムが実行するビジネスの定義です。型付けされ、バージョン管理されたひとまとまりの ObjectStack メタデータです。ランタイムはそこからデータベーススキーマ、REST API、Console、MCP ツールを導出し、すべての呼び出しでそれを強制します。このページはこの言葉をこのサイトに対応付けます。完全な説明は、ObjectStack ドキュメントの [Business Ontology](https://objectstack.ai/docs/concepts/ontology) にあります。 + +## コア [#the-core] + +オントロジーそのものは 6 種類のものから成ります。 + +| コア | 宣言するもの | このサイトでは | +|---|---|---| +| **オブジェクトとフィールド** | ビジネスのエンティティと、その型付きの属性 | [データモデル](/docs/build/data)、[フィールドタイプ](/docs/reference/field-types) | +| **リレーション** | オブジェクト間のルックアップと主従関係のリンク | [リレーションシップ](/docs/build/data/relationships) | +| **アクション** | ユーザー(または、作成者が公開した場合はエージェント)がレコードに対して呼び出せる操作 | [アクション](/docs/build/interface/actions) | +| **権限** | 誰が何を読み、作成し、編集し、削除できるか:権限セット、レコードアクセス、フィールドレベルのセキュリティ | [権限](/docs/configure/permissions) | +| **フロー** | ビジネスプロセス:フロー、レコードトリガー、スケジュール、承認、ワークフロー | [自動化](/docs/build/automation) | +| **エージェントとツールの定義** | アプリに付属する AI エージェント、そのスキル、エージェントが呼び出せるツール | [エージェント](/docs/build/agents) | + +## プロジェクション [#the-projections] + +ビュー、ダッシュボード、アプリ、翻訳もメタデータとして作成され、同じ検証ゲートを通過しますが、これらはオントロジーの一部ではなく、オントロジーの**プロジェクション**です。コアを変更すればそれらは追従し、1 つを削除しても、それが表示していたビジネスは変わりません。 + +| プロジェクション | 投影するもの | このサイトでは | +|---|---|---| +| **ビュー** | オブジェクトのフィールドと権限を、リスト、フォーム、カンバン、カレンダーに | [ビュー](/docs/build/interface/views)、[フォーム](/docs/build/interface/forms) | +| **ダッシュボード** | オブジェクトに対するクエリをグラフに | [ダッシュボード](/docs/build/interface/dashboards) | +| **アプリ** | オブジェクト、ビュー、アクションを、ナビゲーションできる製品にまとめたもの | [アプリ](/docs/build/interface/apps) | +| **翻訳** | すべてのラベルを、あるロケールに | [ローカライズ](/docs/configure/localization) | + +## ObjectOS での置き場所 [#where-it-lives-on-objectos] + +ひとつの定義が、3 つの形で存在します。 + +| 形 | 内容 | +|---|---| +| **テナントのメタデータ** | [AI Builder](/docs/build/ai-builder) と Studio が書き込むもの:デプロイメント内の稼働中のメタデータ。AI Builder による変更は、適用される前に人の承認待ちのキューに入ります | +| **リポジトリのソース** | 開発者とそのコーディングエージェントが [AI スキル](/docs/build/ai-skills)を使って書くもの:`objectstack.config.ts` とそのメタデータファイル。プルリクエストとしてレビューされます | +| **コンパイル済みアーティファクト** | `os compile` が生成するもの:デプロイメントが起動に使う `objectstack.json`。[起動モード](/docs/architecture#boot-modes)を参照してください。公開したものはすべて保管してください([バックアップ](/docs/operate/backup)) | + +どの形で作成しても、メタデータは実行される前に同じ[検証ゲート](/docs/resources/glossary#validation-gate)を通過します。どちらのエディションでも、オントロジーはあなたのものです。通常の ObjectStack メタデータであり、エクスポートしてオープンソースの ObjectStack ランタイムで実行できます。 + +## オントロジーでないもの [#what-it-is-not] + +- **知識オントロジーではありません。** クラスの継承も、公理も、推論器もありません。定義は検証され、そして実行されます。 +- **既存システムの上のセマンティックレイヤーではありません。** セマンティックレイヤーは、自らが実行しないビジネスを記述します。あなたのオントロジーはシステムそのものです。データベース、API、UI、エージェントのツールはそこから導出されます。すでに運用しているデータベースを接続することは可能ですが、デフォルトでは読み取り専用で、まだ初期段階です。[既存システムの拡張](/docs/build/extend-existing-systems)を参照してください。 + +## さらに読む [#read-further] + +このサイトはランタイムを説明しています。概念は ObjectStack のサイトが扱います。 + +- [Business Ontology](https://objectstack.ai/docs/concepts/ontology):この言葉の意味と、ランタイムがそれをどう実行するか +- [How ObjectStack compares](https://objectstack.ai/docs/concepts/compare):知識オントロジー、セマンティックレイヤー、メタデータプラットフォーム、AI によるコード生成との比較 +- [When to use ObjectStack](https://objectstack.ai/docs/concepts/when-to-use):現時点で適している場面と、適していない場面 +- [The Ontology Is the Software](https://objectstack.ai/blog/the-ontology-is-the-software):長文の解説 diff --git a/content/docs/reference/cel.ja.mdx b/content/docs/reference/cel.ja.mdx new file mode 100644 index 00000000..435a67d9 --- /dev/null +++ b/content/docs/reference/cel.ja.mdx @@ -0,0 +1,92 @@ +--- +title: CEL 式 +seoTitle: "CEL 式:数式、述語、テンプレート" +description: 数式フィールド、検証ルール、表示条件、共有、フローの条件を支える式言語です。ObjectOS での使いどころ、いくつかの例、そして objectstack.ai にある言語の完全な説明を紹介します。 +editions: [community, cloud, enterprise] +translation: + source_sha: ba57e518fc6626502da8e3012659d4218d65c7703dcb70c1834432e11a711d17 + guide_rev: 1 + mode: auto +--- + +**完全な仕様:** [objectstack.ai の Expressions (CEL)](https://objectstack.ai/docs/data-modeling/formulas)。このページはその要約です。ObjectOS での使いどころと、いくつかの例を示します。 + +ObjectOS は、定義に小さく安全な式が必要な場所で [CEL](https://github.com/google/cel-spec)(Common Expression Language)を使います。CEL には副作用も I/O もなく、サーバー上で評価されます。式からは、評価対象のレコードが `record`(その以前の状態が `previous`)として見え、実行ユーザーがいる場合はそのユーザーが `current_user` として見えます。 + +## ObjectOS での使いどころ [#where-objectos-uses-it] + +| 場所 | 式が決めること | +|:--|:--| +| 数式フィールド | レコードから導出されるフィールドの値 | +| フィールドの `requiredWhen`、`visibleWhen`、`readonlyWhen` | このレコードでフィールドが必須か、表示されるか、編集できるか | +| 検証ルール | 書き込みが拒否されるかどうか([検証ルール](/docs/build/data/validation-rules)) | +| 共有ルール | ユーザーのグループにどのレコードが付与されるか([レコードアクセス](/docs/configure/permissions/record-access)) | +| アクションの `visible` / `disabled` | ボタンが表示されるかどうか | +| フローの開始条件とその分岐 | フローが実行されるかどうか、どちらに進むか([フローと自動化](/docs/build/automation/flows)) | +| フィールドの `defaultValue` | 新しいレコードの初期値 | + +## 例 [#examples] + +**数式フィールド**:明細行の合計: + +```ts +subtotal: Field.formula({ + label: 'Subtotal', + expression: F`record.quantity * record.unit_price`, +}), +``` + +**検証**:完了日は未来でなければならない。`script` ルールの `condition` は*無効な*レコードを記述します。これが true のとき、書き込みは拒否されます。 + +```ts +// One validation rule, an entry of the object's `validations` +{ + type: 'script', + name: 'close_date_in_future', + message: 'Close date must be in the future', + condition: P`record.close_date <= today()`, +} +``` + +**表示条件**:商談が成立してから初めてフィールドを表示する: + +```ts +close_reason: Field.textarea({ + label: 'Close reason', + visibleWhen: P`record.stage == 'closed_won'`, +}), +``` + +**フローの条件**:金額が大きい場合だけ、レコード変更フローを開始する: + +```ts +// The `config` of a `start` node; the rest of the flow is omitted (see Flows). +config: { + objectName: 'opportunity', + triggerType: 'record-after-update', + condition: P`record.amount >= 1000`, +} +``` + +## 権限のチェック [#permission-checks] + +ObjectStack 17.5 以降、`current_user.can(object, verb)` は、実行ユーザーがオブジェクト権限を持っているかを尋ね、そのユーザーの実効的な権限に基づいて答えます。 + +```ts +discount: Field.percent({ + label: 'Discount', + defaultValue: cel`current_user.can('crm_quote', 'edit') ? 10 : 0`, +}), +``` + +サーバーは、選択肢の `visibleWhen`(ユーザーが選べない選択肢は `invalid_option` で拒否されます)、数式フィールド、CEL の `defaultValue` でこれに答えます。評価に権限のデータが伴わない場所(検証ルールがその一例です)では、`can()` は推測されるのではなく拒否され、式は失敗します。 + +## 式が間違っているとき [#when-an-expression-is-wrong] + +黙って失敗することはありません。形式が不正な式や、オブジェクトにないフィールドを指定する式は、場所と「もしかして」のヒントを示して `os compile` で失敗します。実行時には、不正な式は `null` や `false` に評価されるのではなく、原因を特定したエラーを投げます。そのため、数式の値やガードの判断を黙って壊すのではなく、ログと監査証跡に失敗が表れます。 + +## 関連項目 [#see-also] + +- [数式](/docs/build/data/formulas):アプリにおける数式フィールド +- [検証ルール](/docs/build/data/validation-rules):書き込みを拒否する述語 +- [フィールドタイプ](./field-types):数式フィールドと条件付きのプロパティ diff --git a/content/docs/reference/cli.ja.mdx b/content/docs/reference/cli.ja.mdx new file mode 100644 index 00000000..3ff61271 --- /dev/null +++ b/content/docs/reference/cli.ja.mdx @@ -0,0 +1,259 @@ +--- +title: CLI リファレンス +seoTitle: "CLI リファレンス:すべての os コマンドとそのフラグ" +description: すべての `os` コマンド、その動作、最も役立つフラグ。 +editions: [community, cloud, enterprise] +translation: + source_sha: 3a77aa68e28e880be0de253974a5977e4412d168b16c73e544224ce1bdd82412 + guide_rev: 1 + mode: auto +--- + +`@objectstack/cli` パッケージは、`os` という 1 つのバイナリ(`objectstack` としても利用可能)をインストールします。以下の例はすべて短い `os` を使います。 + +```bash +npm i -g @objectstack/cli +os --help +``` + +## サーバーのコマンド [#server-commands] + +### `os start`:設定不要の起動 [#os-start--zero-config-boot] + +段階的な 4 つのモードを自動検出します。 + +1. **空の起動**:カレントディレクトリにアーティファクトも設定もない → UI とマーケットプレイスを備えた素のカーネルで起動します。 +2. **プロジェクトの起動**:カレントディレクトリに `objectstack.config.ts` がある → `./dist/objectstack.json` に自動コンパイルし、そこから起動します。 +3. **アーティファクトの起動**:`dist/objectstack.json` に到達できる → そこから直接起動します。 +4. **明示的な上書き**:`--artifact`、`--database`、`--port` が優先されます。 + +```bash +os start # default port 3000 +os start --port 8080 +os start --artifact ./build/myapp.json +os start --artifact https://cdn.example.com/app.json +os start --database file:./data/prod.db +os start --database postgres://user:pass@host:5432/mydb +os start --database libsql://my-db.turso.io --database-auth-token $TURSO +os start --auth-secret "$(openssl rand -hex 32)" +os start --home /var/lib/objectos # persistent home dir +os start --no-ui # API only (no UI/Account portals) +``` + +HOME ディレクトリのデフォルト: +- カレントディレクトリにプロジェクトの設定がある場合 → `/.objectstack`(プロジェクトローカル) +- ない場合 → `~/.objectstack`(グローバル。実行間で共有) + +### `os serve`:本番サーバー [#os-serve--production-server] + +`objectstack.config.ts` があればそれを読み、なければ `dist/objectstack.json` にフォールバックします。厳格な動作が必要な本番のコンテナで使います。 + +代わりに**公開済み**のアーティファクトで起動するには、`OS_ARTIFACT_URL` で指定します。絶対的な `https://`、`http://`、`file://` の URL で、フラグメントに `#sha256=` による完全性の固定を任意で付けられます。設定が読み込まれる前に解決されます。古い綴りの `OS_ARTIFACT_PATH` は廃止されています。ObjectOS のランタイムイメージでは、デフォルト以外の値は代替の変数を示して**起動を拒否**します。[環境変数](/docs/reference/environment-variables#retired-names)を参照してください。 + +```bash +os serve # port 3000 +os serve --port 4000 --no-ui +``` + +### `os dev`:ホットリロード付きの開発 [#os-dev--development-with-hot-reload] + +`objectstack.config.ts` と `src/` を監視し、保存時に再コンパイルと再読み込みを行います。雛形から作成したプロジェクトでは、npm の `dev` スクリプトとして使われます。 + +```bash +os dev # port 3000 by default +os dev -p 4000 +``` + +`os dev` は `os start` と同じポート(3000)を要求します。そのポートが使用中の場合は次の空きポートにバインドし、`↪ server bound to port 3001 (requested 3000)` のようにその旨を表示します。 + +## プロジェクトのコマンド [#project-commands] + +### `os init`:新しいプロジェクトの雛形を作る [#os-init--scaffold-a-new-project] + +```bash +os init my-app # interactive +os init my-app -t app --install # auto-install with default pnpm +os init my-app -t app --install -p npm +os init my-app -t plugin # plugin scaffold +os init my-app -t empty # bare minimum +``` + +テンプレート: +| テンプレート | 得られるもの | +|---|---| +| `app` | 完全なアプリ。オブジェクト、ビュー、アクションがあり、すぐに拡張できます | +| `plugin` | 再利用可能な機能を配布するためのプラグインの雛形 | +| `empty` | マニフェストと tsconfig のみ | + +### `os create`:カーネルのコードプラグインの雛形を作る [#os-create--scaffold-a-kernel-code-plugin] + +```bash +os create plugin my-plugin +``` + +`os create plugin` は、カーネルの `Plugin` 契約を実装する TypeScript パッケージを書き出します。これは `os init` にはできないことです。`os create example` は ObjectStack 17.4 で廃止されました。`os init` が書き出すものの一部を書き出すだけだったため、現在は `os init` を示すエラーで終了します。 + +## ビルド / 検証のコマンド [#build--validate-commands] + +| コマンド | 目的 | +|---|---| +| `os compile`(`os build`) | `objectstack.config.ts` を `dist/objectstack.json` にコンパイルする | +| `os validate` | プロトコルのスキーマに照らして設定を検証する | +| `os lint` | スタイルと規約のチェック(CI で推奨) | +| `os diff ` | 2 つの設定を比較し、破壊的変更を検出する | +| `os info` | 設定またはアーティファクトのメタデータの概要を表示する | +| `os explain ` | オブジェクトのスキーマを人が読める形で説明する | +| `os doctor` | ヘルスチェック:循環依存、壊れた参照、環境の問題を検出する | +| `os generate`(`os g`) | TypeScript の型 / メタデータファイルを生成する | +| `os db clean` | 1 回限りの SQLite の `VACUUM` と、増分の自動バキュームの有効化。回収したバイト数を報告します(14.5 以降) | + +`os doctor` は、**何かおかしいと感じたときに最初に実行するもの**です。ランタイムでは実行時の警告としてしか表れない設定の誤りを捉えます。 + +ObjectStack 13 以降、`os compile` は**セキュリティの姿勢**によってもビルドを制限します。`validateSecurityPosture` のエラー(未設定や別名の共有モデル、高い権限を持つアンカーのバインディング、残っているロールの語彙、修飾されていないフィールド権限のキーなど)はビルドを失敗させ、`os lint` はそれらをループのより早い段階で報告します。`access-matrix.json` のスナップショットをコミットしている場合、権限の機能にずれがあると、`--update-access-matrix` で再スナップショットするまで `os compile` が失敗します。すべての機能の変更がレビュー可能になります。 + +## データのコマンド [#data-commands] + +ターミナルからレコードを操作します。シードデータの投入、マイグレーション、CI のスモークテストに便利です。 + +```bash +os data create --data '{"subject": "Hello"}' +os data get +os data query --filter 'status:active' --limit 10 +os data update --data '{"done": true}' +os data delete +``` + +## メタデータのコマンド [#metadata-commands] + +実行時にメタデータのレコード(オブジェクト、ビュー、権限セットなど)を読み書きします。 + +```bash +os meta list +os meta get +os meta register +os meta delete +``` + +## データベースのマイグレーション:`os migrate` [#database-migrations--os-migrate] + +`os migrate` は、デプロイメントのデータベースをメタデータと一致させ、リリースが求める 1 回限りのデータマイグレーションを実行します。すべてのサブコマンドは `--database-url` で指定したデータベースに対して動作します。デフォルトは `$OS_DATABASE_URL`、次にプロジェクト自身のデータベースなので、デプロイメントのデータベースを明示的に指定してください。いずれもメタデータを読むためにアプリを起動します。先にデータベースをバックアップしてください。各アップグレードで必要なコマンドは[アップグレードとロールバック](/docs/operate/upgrade#version-specific-steps)にあります。 + +### スキーマ [#schema] + +| コマンド | 動作 | +|---|---| +| `os migrate plan` | データベースがメタデータからどのようにずれているかを、安全、確認が必要、破壊的の変更として表示します。何も書き込みません | +| `os migrate apply` | 確認のプロンプトの後(`--yes` で省略)、破壊的でない変更を適用します。`--allow-destructive` を付けると、孤立した列の削除、`NOT NULL` の厳格化、型の縮小も行います | +| `os migrate multi-value-columns` | フィールドが `multiple: true` を宣言している場所で、古いテキスト列を JSON に移します。`apply` が決して行わない唯一の型変更です。`--apply` を付けるまではドライランです | +| `os migrate unmapped-columns --object NAME` | 廃止されたフィールドの列に残る値を、レコード id をキーとして読み取ります。読み取り専用です。17.7 以降、ランタイムのどの入り口もそれらの列を返さないため、`apply --allow-destructive` が列を削除する前に、変換処理はこの方法で値を読み取ります | +| `os migrate duplicates` | すでに 2 回発行された識別子と、一意インデックスを妨げる行を JSON で報告します。読み取り専用です | + +```bash +os migrate plan # what would change; writes nothing +os migrate apply --allow-destructive --yes # also drop and tighten (CI / scripts) +os migrate unmapped-columns --object contact --json > contact-unmapped.json +``` + +### データマイグレーション [#data-migrations] + +これらはいずれもスキーマではなく行を書き換えるもので、インストールしたバージョンではなく、データベースについての事実に関わります。ランタイムがこれらを代わりに実行することはありません。行に別の記載がない限り、`--apply` を渡すまではドライランです。 + +| コマンド | 動作 | +|---|---| +| `os migrate files-to-references` | (17.0)インラインで保存されたファイルフィールドの値を `sys_file` の参照に変換します。`--apply` は、このデプロイメントでメディアの値の厳格なチェックを有効にするフラグを記録します | +| `os migrate value-shapes` | (17.0)参照と構造化 JSON の値を、その契約に照らしてスキャンします。スキャンで何も見つからなくなると、`--apply` がフラグを記録します | +| `os migrate meta --from 17` | アプリの**ソース**に対してメタデータの変換チェーンを再実行し、行う編集を一覧表示します。`--out FILE` は変換後のスタックを書き出します。作成時の手順であり、データベースには触れません | +| `os migrate meta --stored` | 同じ変換を、このデプロイメントに**保存された**メタデータに対して行います。`--apply` で行を書き換えます | +| `os migrate account-issuer` | (17.5)`sys_account.issuer` 列を削除できるかを確認します。読み取り専用です。2 つのアカウントが衝突する間はゼロ以外で終了します | +| `os migrate audit-metadata-bodies` | (17.6)監査証跡とアクティビティストリームが保持するメタデータ本体のコピーを書き換え、認証情報と保存されたコンテンツハッシュを削除します | +| `os migrate summary-nulls` | 古い親の行で、まだ `NULL` として保存されているロールアップの `count` / `sum` の列を埋めます | +| `os migrate recorded-by` | メタデータの履歴にあるレガシーな `'system'` マーカーを `NULL` に書き換えます | +| `os migrate resume` | 中断されたマイグレーションの実行を一覧表示します。`--run ID` を付けるまでは読み取り専用で、付けるとその実行を再開または巻き戻します | + +```bash +os migrate account-issuer # read-only pre-flight +os migrate audit-metadata-bodies # dry run: what it would rewrite +os migrate audit-metadata-bodies --apply # rewrite +``` + +### シークレットと保存されたファイル [#secrets-and-stored-files] + +| コマンド | 動作 | +|---|---| +| `os secret rewrap` | 古い `sys_secret` の暗号文を 17.7 の形式で再封印します。`--apply` を付けるまではドライランです。ホストがコードでデータソースを宣言しているかどうかを指定する必要があります(`--declared-datasources FILE` または `--no-declared-datasources`)。⚠️ 17.7 より前のリリースは、これが書き込んだものを開けません | +| `os secret orphans` | もう何からも参照されていない `sys_secret` の行を報告します。削除するのは `--delete` を付けた場合だけです | +| `os storage orphans` | 何も保持しておらず、どの保持ポリシーも回収することのない保存ファイルを報告します。何も書き込みません | + +## i18n のコマンド [#i18n-commands] + +```bash +os i18n extract # extract translation keys from source +os i18n check # find missing keys across configured locales +``` + +## クラウドのコマンド [#cloud-commands] + +ObjectOS Cloud(オプションのホスト型コントロールプレーン)のユーザー向けです。 + +```bash +os login # interactive +os logout +os whoami +os register # create an account +os cloud login | logout | whoami +``` + +## 公開 / パッケージのコマンド [#publish--package-commands] + +```bash +os package publish # publish artifact as a versioned package +os package install # install into a RUNNING runtime: catalog id + # (com.acme.crm) or a compiled artifact JSON + # (air-gapped, inline). --runtime / --email / + # --password identify the runtime to install into +``` + +## 環境のコマンド [#environment-commands] + +コントロールプレーンに支えられた、プロジェクトごとに複数の環境(dev、staging、prod)を使うデプロイメント向けです。 + +```bash +os environments list +os environments show +os environments create +os environments switch +os environments bind # bind local artifact to an environment +``` + +## テストのコマンド [#test-command] + +```bash +os test # run Quality Protocol scenarios against a running server +``` + +## 共通のフラグの規則 [#common-flag-conventions] + +| フラグ | 意味 | +|---|---| +| `-p, --port` | HTTP ポート | +| `-a, --artifact` | コンパイル済みアーティファクトのパスまたは URL | +| `-d, --database` | データベース URL | +| `--home` | 永続的な状態のディレクトリ | +| `-v, --verbose` | 詳細な出力 | +| `--no-ui` | UI と Account ポータルを無効にする | + +完全なフラグの一覧は、任意のコマンドに `--help` を付けて実行すると表示されます。 + +```bash +os start --help +os data query --help +``` + +## CLI の位置づけ [#where-the-cli-fits] + +- **オペレーター / 初回実行** → `os start` +- **アプリを構築する開発者** → `os init` → `os dev` → `os compile` +- **CI / リリースパイプライン** → `os lint && os validate && os compile && os test` +- **本番のランタイム** → `os serve`(通常は Docker イメージの `CMD` の中) +- **デプロイメントのアップグレード** → [アップグレードのページ](/docs/operate/upgrade#version-specific-steps)が、お使いのバージョンについて挙げている `os migrate` の手順 +- **診断** → `os doctor`、`os info`、`os explain` diff --git a/content/docs/reference/environment-variables.ja.mdx b/content/docs/reference/environment-variables.ja.mdx new file mode 100644 index 00000000..029f1197 --- /dev/null +++ b/content/docs/reference/environment-variables.ja.mdx @@ -0,0 +1,162 @@ +--- +title: 環境変数 +seoTitle: "セルフホストのデプロイメントの環境変数" +description: セルフマネージドの ObjectOS デプロイメント(Community または Enterprise)の環境の契約です。各変数が何を決めるか、どのエディションがそれを読むか、どの組み合わせが起動時に失敗するか、どの名前が廃止されたかを説明します。 +editions: [community, enterprise] +translation: + source_sha: 470c8ef488571d10b3f0c678d447ccf97b2f06c6c29ef0f48515b291169ecb2c + guide_rev: 1 + mode: auto +--- + +環境変数は**デプロイメントレベル**の判断を担います。どのイメージが動いているか、データがどこにあるか、このデプロイメントが何であることを認められているか。デプロイメントの稼働中にテナントや管理者が変更できるべきものは、代わりにシステム設定に置きます。 + +このページは**契約**です。各変数が何を決めるか、そして 2 つの変数が食い違ったときに何が起きるかを示します。**エディション**の列は、どのイメージがそれを読むかを示します。 + +- **両方**:オープンな Community イメージ `ghcr.io/objectstack-ai/objectstack` と、ライセンスされた Enterprise イメージの両方。 +- **Enterprise**:Enterprise イメージ、またはそれに付属するデプロイバンドルのみ。 + +Community では、設定する値は [Docker](/docs/deploy/docker) に示しています。Enterprise では、**コピーする値**はリリースに付属するデプロイバンドルにあります。`.env` にコピーして編集する、注釈付きのテンプレートです。そのテンプレートはリリースに固定されていますが、このページはそうではありません。両者が異なる場合は、イメージとともに提供されたテンプレートが優先されます。 + +> **命名。** ObjectOS が所有する変数は `OS_` の接頭辞を使います。1.0 より前の接頭辞のない名前のいくつかは引き続き機能し、一度だけ非推奨の警告を出します。[レガシーな名前](#legacy-names)を参照してください。覚えている名前を使う前に知っておくべきグループが他に 2 つあります。何にも読まれないか起動をその場で拒否する[廃止された名前](#retired-names)と、まだ解決されるレガシーな名前です。 + +## すべてのデプロイメントが下す判断 [#the-decisions-every-deployment-makes] + +| 変数 | エディション | 決めること | +|---|---|---| +| `OS_EE_IMAGE` | Enterprise | どのイメージを実行するか。ランタイムではなく、バンドルの Compose スタックが読みます。タグではなく、必ず**ダイジェスト**を固定してください。[Docker](/docs/deploy/docker) を参照してください。 | +| `OS_AUTH_SECRET` | 両方 | セッションの署名に使う基本シークレット。未設定の場合、サインインエンドポイントはスキップされ、サーバーは認証なしで実行されます。**すべてのレプリカで同一**でなければなりません。ローテーションすると既存のすべてのセッションが無効になります。 | +| `OS_DATABASE_URL` | 両方 | デプロイメントが動作するデータベース。未設定の場合、ランタイムはホームディレクトリの下に SQLite ファイルを書き込み、コンテナではファイルシステムとともに失われます。本番ではマネージド PostgreSQL に向けてください。Enterprise では、バンドルのデータベースサービスを削除します。 | +| `OS_SECRET_KEY` | 両方 | 保存されたすべてのシークレット(暗号化された設定、`secret` フィールド、データソースの認証情報)を暗号化するキー。未設定の場合、ランタイムはキーを生成して自身のファイルシステムに保持し、コンテナでは再起動で失われます。32 バイトの値(`openssl rand -hex 32`)を設定し、シークレットマネージャーに保管し、データベースと一緒にバックアップしてください。複数のレプリカでは**必須**であり、すべてのレプリカで*同じ*値でなければなりません。[マルチノード](#multi-node)を参照してください。 | +| `OS_DB_USER`、`OS_DB_PASSWORD`、`OS_DB_NAME` | Enterprise | 提供される Compose スタックの**バンドルの**データベースサービスをプロビジョニングします。`OS_DATABASE_URL` の中の認証情報はこれらと一致していなければなりません。マネージドデータベースを使う場合は関係ありません。 | +| `AI_GATEWAY_API_KEY` | Enterprise | 「データに質問する」エージェントの背後にある AI プロバイダーの認証情報。 | + +## ライセンスとクラウドの姿勢 [#license-and-cloud-posture] + +この 2 つはペアです。片方を設定するときにもう片方を読まないのは、このページで最も高くつく間違いです。サポートされない組み合わせは、劣化するのではなく**起動時に拒否される**からです。 + +| 変数 | エディション | 決めること | +|---|---|---| +| `OS_LICENSE_KEY` | Enterprise | デプロイメントのエンタイトルメント。ライセンスには**モード**もあります。通常のライセンスはコントロールプレーンに対してオンラインで検証され、エアギャップライセンスはネットワークトラフィックを一切伴わずにローカルで検証されます。モードは発行されたライセンスの性質であり、ここで設定するものではありません。 | +| `OS_CLOUD_URL` | 両方 | このデプロイメントにコントロールプレーンがあるかどうか、あるならどれか。`off`(および別名の `none`、`local`、`disabled`)は**コントロールプレーンなし**を意味します。マーケットプレイスもライセンスの検証もありません。 | + +Community にはライセンスがないため、`OS_CLOUD_URL` が決めるのは、デプロイメントがコントロールプレーンに接続するかどうかだけです。Enterprise では 2 つの変数はペアであり、次の 2 つの帰結があります。どちらも人を驚かせます。 + +- **未設定は「off」ではありません**。どちらのエディションでもです。未設定の `OS_CLOUD_URL` は*公開*コントロールプレーンに解決されます。中立な値だったことは一度もなく、接続された動作を選びます。誰とも通信しないはずのデプロイメントは、`off` をはっきりと書かなければなりません。 +- **通常のライセンスと `off` の組み合わせは起動時に拒否され**、両方の変数が名指しされます。これは劣化した状態ではなく不可能な状態です。オンラインライセンスはコントロールプレーンを必要とする交換によって検証されるため、コントロールプレーンが設定されていなければ交換は行われず(今回の起動でも以降の起動でも)、猶予期間も始まりません。猶予は最後に*成功した*検証から計測されるからです。 + +サポートされる組み合わせの完全な表と、拒否の理由は[エアギャップデプロイメント](/docs/deploy/air-gapped)にあります。 + +## マルチ組織のデプロイメント [#multi-organization-deployments] + +**壁で区切られた**テナンシーの姿勢は、組織ごとの分離の壁を立てます。これはライセンスされた機能であり、さらに 3 つの判断を必須にします。それぞれが宣言されるまで、ランタイムは起動を拒否します。どの値を宣言しても受け入れられますが、決めないことは受け入れられません。 + +| 変数 | エディション | 決めること | +|---|---|---| +| `OS_TENANCY_POSTURE` | 両方。壁で区切られた値は Enterprise | 組織を互いに分離するかどうか。未設定または `single` は 1 つの組織です。壁で区切られた値は `isolated` と `group` です。壁で区切られた姿勢には**ライセンスが必要**です。ライセンスがない場合、ランタイムは分離されているふりをしてトラフィックを提供するのではなく、起動時に終了します。 | +| `OS_AUTH_MEMBERSHIP_POLICY` | 両方 | 新しいサインアップが何に参加するか。`auto` はすべての新規ユーザーをデプロイメントのデフォルトの組織に紐づけます。単一組織の環境には適切ですが、メンバーシップそのものがテナントの境界である場所では不適切です。`invite-only` は、明示的な行為(ワークスペースの作成、招待の承諾、管理者、SSO プロビジョニング)によってのみメンバーシップを付与します。**Setup → Authentication → Membership** でも設定できます。ここで設定するとその値に固定され、Setup のフィールドは読み取り専用になります。 | +| `OS_AI_STUDIO_AGENTS` | Enterprise | どの AI エージェントをマウントするか。`ask` と `build` のカンマ区切りの部分集合です。未設定では**両方**がマウントされます。`ask` は読み取ります。`build` は**メタデータを作成**します。そしてメタデータの範囲は組織ではなくデプロイメントなので、共有データベースでは、ある顧客の `build` のターンが、他のすべての顧客が使うスキーマを書き換えます。AI シートはこれをカバーしません。両方のエージェントに対する 1 つのフラグです。スペルの誤った値は、黙って両方のマウントにフォールバックするのではなく、起動を失敗させます。 | +| `OS_PLATFORM_OWNER_EMAIL` | 両方 | デプロイメントのプラットフォーム管理者が誰か。1 つのメールアドレス、またはカンマ区切りのリストです。壁で区切られた姿勢では、プラットフォーム管理者の地位の**唯一の**根拠です(ObjectStack 17.5 以降、そこでは `admin_full_access` の付与はその地位を与えません)。未設定または空の場合、ランタイムは起動を拒否します。列挙されたアカウントは、アドレスが**確認**されて初めてその地位を持つため、デプロイメントには確認の手段(メールの送信手段、または信頼できるフェデレーションによるサインイン)が必要です。解析できないエントリが 1 つでもあると、リスト全体が無効になります。変更は再起動で反映されます。 | + +単一組織のデプロイメントでは、これらのチェックは一切行われません。後の 3 つは未設定のままでかまいません。`OS_PLATFORM_OWNER_EMAIL` で指定されていない限り、最初に登録したアカウントがプラットフォーム管理者になります。指定されている場合は、その確認済みのアカウントがなります。 + +## マルチノード [#multi-node] + +マルチノードは Enterprise の機能です。Community のデプロイメントはレプリカ 1 つで実行され、それ以上を宣言すると(`OS_CLUSTER_REPLICAS` が 1 より大きい)、プロセスごとのロックでレプリカを実行するのではなく、起動を拒否します。レプリカを 2 つ以上にスケールすると、必須となるものが変わります。クラスタードライバー、そしてすべてのレプリカで同じ `OS_SECRET_KEY` と `OS_AUTH_SECRET` です。 + +| 変数 | エディション | 決めること | +|---|---|---| +| `OS_CLUSTER_DRIVER` | Enterprise | 共有のコーディネーターを有効にします。未設定は、組み込みのインメモリのコーディネーターでレプリカ 1 つを意味します。 | +| `OS_REDIS_URL` | Enterprise | そのコーディネーターの場所。 | +| `OS_CLUSTER_REPLICAS` | Enterprise | バンドルのスタックが起動するアプリケーションのレプリカ数。ランタイムも、宣言されたトポロジーとしてこれを読みます。マルチノードのライセンスなしで 1 より大きい場合、起動は拒否されます。 | + +クラスタードライバーが設定されると、`OS_SECRET_KEY` は**必須になります**。クラスタードライバーがない場合、各レプリカは独自のキーを生成して永続化します。レプリカ間ではそれらのキーが黙って食い違うことになるため、ランタイムは一貫しない暗号で提供する代わりに起動を拒否します。 + +## 公開済みアプリを実行する [#running-a-published-app] + +ランタイムのイメージと、それが提供するアプリは、独立したリリースの軸です。1 つの変数が公開済みアーティファクトを指定し、アプリのアップグレードはその変数の変更と再起動で済みます。イメージの再ビルドは不要です。 + +| 変数 | エディション | 決めること | +|---|---|---| +| `OS_ARTIFACT_URL` | 両方 | **アプリを選択する唯一の変数。** ビルド済みの `objectstack.json` を指す、絶対的な `https://`、`http://`、`file://` の URL で、URL フラグメントに SRI 形式の完全性の固定(`#sha256=` に続けて 16 進数 64 文字)を任意で付けられます。固定されたアーティファクトのバイトが一致しない場合、期待するダイジェストと実際のダイジェストを示して**起動を拒否**します。Community イメージが `/srv/app/objectstack.json` で探すアーティファクトを上書きします。Enterprise イメージでは、設定が読み込まれる前に解決されるため、この経路ではイメージ自身の Enterprise の配線は読み込まれません。 | +| `OS_COMPOSED_ARTIFACT_URL` | Enterprise | **composed** 形態(公開済みアプリをイメージの Enterprise プラグインと一緒に起動し、複数の組織が 1 つのデータベースを共有する)のアプリを選択します。この形態にはデプロイバンドル内に専用のテンプレートがあり、エアギャップライセンスのみで、`OS_CLOUD_URL=off` が必須です。どちらも起動時に強制されます。これと `OS_ARTIFACT_URL` の両方を設定すると、起動は拒否されます。 | + +完全性のハッシュ用の対となる変数は、意図的に用意していません。固定は URL フラグメントにあるため、コピーする値もローテーションする値も 1 つだけで、「URL は更新したがハッシュは更新していない」という状態は表現できません。 + +アーティファクトは**不変でバージョン名の付いた**オブジェクトとして公開し、アーティファクトのホストへの書き込み認証情報は公開パイプラインだけに与え、本番ではダイジェストを固定してください。この 3 つのルールがあるからこそ、ロールバック(古い URL を使った、アップグレードと同じ操作)が実際に機能します。 + +## ランタイムのサービス [#runtime-services] + +| 変数 | エディション | 決めること | +|---|---|---| +| `OS_PORT` | 両方 | ランタイムが待ち受ける HTTP ポート。Community イメージは `8080` を設定します。`os start` は別のポートに移ることはなく、使用中のポートでは起動に失敗します。レガシーな別名:`PORT`。 | +| `OS_AUTH_URL` | 両方 | サインインサーバーの公開ベース URL:コールバックと Cookie のオリジン。プロキシの背後と本番では必須です。 | +| `OS_CORS_ORIGIN` | 両方 | クロスオリジンのリクエストを受け入れるオリジン(カンマ区切り)。未設定では何も受け入れません。Console と API が同じ公開オリジンを共有している間は、何も受け入れる必要はありません。認証情報が有効な間、`*` は起動時に拒否されます。 | +| `OS_ENVIRONMENT_ID` | 両方 | 単一環境のランタイムが自身のものとして報告する環境 id。クラウドへのバインディングが完了するとこれが永続化され、その後のセルフホストのランタイムでは設定する必要がありません。 | +| `OS_TRUSTED_ORIGINS` | 両方 | 追加の信頼されたオリジン(カンマ区切り)。 | +| `OS_ROOT_DOMAIN` | 両方 | プラットフォーム SSO のデプロイメントで、サブドメインを信頼するために使うルートドメイン。 | +| `OS_DATABASE_DRIVER` | 両方 | `OS_DATABASE_URL` のスキームから推測されるドライバーを上書きします。スキームから推測できない場合にだけ設定してください。サポートされない値はフォールバックせずに失敗します。ObjectStack 17.7 以降、インメモリのエンジンは、ここで指定した場合(`memory`)も `memory://` の URL で指定した場合も、起動用のストアとして拒否されます。 | +| `OS_DATABASE_AUTH_TOKEN` | 両方 | 認証トークンを使うマネージドドライバー向けのトークン。 | +| `OS_SKIP_SCHEMA_SYNC` | 両方 | `1` に設定すると、起動時のスキーマ同期をスキップします。スキーマを帯域外で管理する場合に使います。Enterprise のデプロイバンドルのスタックは、どのレプリカよりも先に、別の 1 回限りの手順としてすでにマイグレーションを実行しています。 | +| `OS_TELEMETRY_DB` | 両方 | ライフサイクルで分類されるシステムデータ専用のデータソース。オプトアウトするには `0`、オプトインするにはパスまたは URL を設定します。 | +| `OS_STORAGE_LOCAL_ROOT` | 両方 | ローカルのファイルストレージアダプターがアップロードを保存する場所。作業ディレクトリからの相対パスです(デフォルトは `./.objectstack/data/uploads`)。データベースと一緒にバックアップしてください。設定すると **Setup → Settings → File Storage → Root directory** が固定されます。 | +| `OS_LIFECYCLE_DISABLED` | 両方 | `1` に設定すると、ライフサイクルサービス(保持期間による削除、テーブルのローテーション、監査のアーカイブ)を無効にします。保持期間自体は、環境変数ではなく `lifecycle.retention_overrides` 設定で調整します。 | +| `OS_AUTOMATION_SCHEDULED_WORK_ENABLED` | 両方 | アプリやパッケージが宣言するスケジュールされた処理を、デプロイメントが実行するかどうか。時間で起動する[フロー](/docs/build/automation/flows#scheduled-run-on-a-clock)(スケジュール、または相対時間のスイープ)と、パッケージ化された `defineJob` の cron ジョブです。オンになるのは `true`、`1`、`on`、`yes` だけです。**未設定はオフ**で、これは 17.5 以降、すべてのテナンシーの姿勢における ObjectStack ランタイムのデフォルトです。オフの間は時間で動くものは何も有効にならず、そのようなフローはそれぞれデプロイメントのポリシーにより無効と報告されます。プラットフォーム自身のスケジュール処理(承認のエスカレーション、保持期間、メッセージの配信)には影響しません。`isolated` では、スケジュールフローやジョブは実行時の組織も宣言しなければなりません。⚠️ お使いの ObjectOS イメージやデプロイバンドルのテンプレートがこれを設定してくれるかどうかは、このページでは約束できません。アプリがスケジュールフローに依存する場合は明示的に設定し、実効値を `os doctor` で確認してください。 | +| `OS_MCP_SERVER_ENABLED` | 両方 | `/api/v1/mcp` における HTTP 経由の Model Context Protocol サーバーを制御します。対象はそのサーフェスだけです。**デフォルトでオン**です。無効にするには、明示的に偽の値(`false`、`0`、`off`、`no`)を設定します。認証済みのプリンシパルが常に必要です。 | +| `OS_MCP_STDIO_ENABLED` | 両方 | 真の値に設定すると、長時間動作する **stdio** の MCP トランスポートを自動起動します。デフォルトはオフで、上記の HTTP サーフェスとは独立しています。 | +| `OS_MCP_STDIO_API_KEY` | 両方 | stdio トランスポートがプリンシパルとして紐づく API キー。HTTP の MCP と同じ認可チェーンで解決されるため、レコードとフィールドのレベルのセキュリティは引き続き適用されます。フェイルクローズです。stdio が有効で解決できるキーがない場合、トランスポートは起動しません。 | + +## オブザーバビリティ [#observability] + +エクスポートはオプトインです。エクスポーターのデフォルトは `noop` なので、選択するまでデプロイメントは何も出力しません。**エンドポイントを設定するだけでは何も起きません。** + +| 変数 | エディション | デフォルト | 決めること | +|---|---|---:|---| +| `OS_OBS_EXPORTER` | 両方 | `noop` | `noop`、`console`、`json`、`otlp`。ローカルのデバッグには `console` または `json` を、コレクターには `otlp` を使います。 | +| `OS_OTLP_ENDPOINT` | 両方 | — | OTLP/HTTP のルート URL。エクスポーターが `otlp` のときは必須です。空の場合、ランタイムは警告を出して `noop` にフォールバックします。 | +| `OS_OTLP_HEADERS` | 両方 | — | 追加の OTLP ヘッダー。カンマ区切りの `key=value` のペアです。 | +| `OS_OBS_SERVICE_NAME` | 両方 | — | 出力されるメトリクスの `service.name` リソース属性。 | +| `OS_OBS_DEPLOYMENT_ENV` | 両方 | `production` | `deployment.environment` リソース属性。 | +| `OS_OTLP_FLUSH_MS` | 両方 | — | OTLP エクスポーターのフラッシュ間隔(ミリ秒)。 | + +## データ契約の抜け道 [#data-contract-escape-hatches] + +ObjectStack 17.0 で、プラットフォームは宣言された契約に反する値を、以前のように警告して受け入れるのではなく、拒否するようになりました。これらの変数は、今すぐには修正できない連携のために、古い動作を**一時的に**再び有効にします。それぞれ `1` だけを受け付け、それ以外では厳格な動作のままです。違反は引き続きログに記録されるため、ずれは見えたままです。 + +| 変数 | エディション | 再び有効にするもの | +|---|---|---| +| `OS_ALLOW_LAX_ACTION_PARAMS` | 両方 | `params` が必須パラメーターを欠く、`options` / `multiple` / `reference` の宣言に反する、または宣言されていないキーを含むアクションの呼び出し。これがない場合、そのような呼び出しは `400 VALIDATION_FAILED` を返します。 | +| `OS_ALLOW_LAX_MEDIA_VALUES` | 両方 | 厳格にチェックされる場所での、不正な形式の `file` / `image` / `avatar` / `video` / `audio` の値。 | +| `OS_ALLOW_LAX_VALUE_SHAPES` | 両方 | 厳格にチェックされる場所での、不正な形式の参照(`lookup`、`master_detail`、`user`、`tree`)または構造化 JSON の値(`location`、`address` など)。 | + +メディアと値の形は、17.x のランタイムが作成したデータベースでは厳格にチェックされます。以前のメジャーバージョンからアップグレードしたデータベースは、対応するマイグレーションがフラグを記録して初めて厳格にチェックされます。[CLI → データマイグレーション](/docs/reference/cli#data-migrations)を参照してください。そこへ早く到達するために `OS_DATA_VALUE_SHAPE_STRICT_ENABLED=1` を使わないでください。これは、このデプロイメントのデータが実際に何を含んでいるかにかかわらず、すべての値の種類の厳格なチェックを一度にオンにします。 + +## システム設定を固定する [#pinning-a-system-setting] + +システム設定(テナントと管理者が編集できる `ai`、`email`、`feature_flags` などの名前空間)は、`OS_` に名前空間とキーを続け、大文字にして `.` と `-` を `_` に置き換えた名前の変数で、デプロイメントレベルで固定できます。たとえば `ai.openai_base_url` は `OS_AI_OPENAI_BASE_URL` に、`feature_flags.ai_enabled` は `OS_FEATURE_FLAGS_AI_ENABLED` になります。固定された設定は Setup では読み取り専用です。 + +**Setup → Authentication** で設定できる Google サインインも、デプロイメントレベルで `GOOGLE_CLIENT_ID` と `GOOGLE_CLIENT_SECRET` を読み取ります。 + +## 廃止された名前 [#retired-names] + +これらの名前は以前の ObjectOS のドキュメントに登場していました。ここに挙げるのは、引き継いだ設定ファイルを読んで修正できるようにするためであり、使えるようにするためでは**ありません**。行に別の記載がある場合を除き、いずれも両方のエディションで廃止されています。 + +| 廃止された名前 | 代わりに使うもの | +|---|---| +| `OS_ARTIFACT_FILE` | `OS_ARTIFACT_URL`。提供されるランタイムで `OS_ARTIFACT_FILE` を読むものはありません。これを設定したデプロイメントは何も設定しなかった場合と同じように起動し、間違いを指摘するエラーも出ません。ローカルファイルは代替の変数で `file://` として指定し、完全性の固定も代替の変数が担います。 | +| `OS_ARTIFACT_PATH` | `OS_ARTIFACT_URL`。**Enterprise イメージは、デフォルト以外の `OS_ARTIFACT_PATH` を持つ起動を拒否し**、代替の変数を示します。「どのアーティファクトで起動するか」を表す綴りが 2 つあるのは 1 つ多すぎますし、廃止された方は完全性の固定を持ったことがありません。Community イメージは、自身が探すパスである `/srv/app/objectstack.json` を今もこれに設定しています。そのままにしてアーティファクトをそこにマウントし、それ以外のアーティファクトは `OS_ARTIFACT_URL` で指定してください。 | +| `OS_BUSINESS_DB_URL` | `OS_DATABASE_URL`、またはアーティファクトで宣言したデータソース。`OS_BUSINESS_DB_URL` を読むものはありません。これだけを設定したデプロイメントには、データベースが一切設定されていません。 | +| `OS_LOCALIZATION_DATE_FORMAT`、`OS_LOCALIZATION_TIME_FORMAT`、`OS_LOCALIZATION_NUMBER_FORMAT`、`OS_LOCALIZATION_FIRST_DAY_OF_WEEK` | なし。ObjectStack 17.7 で、これらが固定していた設定は廃止され、日付、時刻、数値、週の始まりは言語に従うようになりました。[ローカライズ](/docs/configure/localization#dates-times-and-numbers-follow-the-language)を参照してください。 | + +`OS_CLOUD_API_KEY` は、セルフホストのデプロイメントが設定する変数では**ありません**。ホスト型のクラウドが自ら運用するランタイムに注入するサービスの認証情報であり、それとは別に、`os package publish` が CI からパッケージカタログに対して認証するために使うベアラートークンでもあります([パッケージ](/docs/build/packages)を参照)。コントロールプレーンに接続するセルフホストのデプロイメントは、ファイルに貼り付けるキーではなく、デプロイメントがそのコントロールプレーンに**バインド**されたときに発行されたランタイムトークンを提示します。 + +## レガシーな名前 [#legacy-names] + +これらは両方のエディションで引き続き解決されますが、正式な名前が推奨され、レガシーな名前は将来のメジャーバージョンで削除される可能性があります。 + +| 正式な名前 | レガシー | 備考 | +|---|---|---| +| `OS_PORT` | `PORT` | 一度だけ非推奨の警告を出します。 | +| `OS_AUTH_SECRET` | `AUTH_SECRET` | 一度だけ非推奨の警告を出します。 | +| `OS_TENANCY_POSTURE` | `OS_MULTI_ORG_ENABLED` | 姿勢がレガシーなブール値から導出されるのは、`OS_TENANCY_POSTURE` が未設定の場合だけです。そこでの `true` は isolated を意味します。姿勢は直接宣言してください。ライセンスと起動時のチェックは、その変数に対して書かれています。 | +| `OS_MULTI_ORG_ENABLED` | `OS_MULTI_TENANT` | | diff --git a/content/docs/reference/field-types.ja.mdx b/content/docs/reference/field-types.ja.mdx new file mode 100644 index 00000000..1c9ffaee --- /dev/null +++ b/content/docs/reference/field-types.ja.mdx @@ -0,0 +1,96 @@ +--- +title: フィールドタイプ +seoTitle: "フィールドタイプ:各フィールドが保存し、表示するもの" +description: ObjectOS でフィールドタイプが決めるもの(列、API、フォームのウィジェット、AI Builder が尋ねる内容)を、いくつかの例と、objectstack.ai にある完全な一覧とともに紹介します。 +editions: [community, cloud, enterprise] +translation: + source_sha: d8cf773f496622e8a3d84f80d1e3e96dbcc89f6f2892ef7cf6847d049db4a2ca + guide_rev: 1 + mode: auto +--- + +**完全な仕様:** [objectstack.ai のフィールドタイプ](https://objectstack.ai/docs/data-modeling/field-types)。このページはその要約です。ObjectOS での使いどころと、いくつかの例を示します。 + +フィールドのタイプは、何を保存し、すべてのサーフェスがそれをどう扱うかを決めます。組み込みのタイプは 48 種類あります。テキスト、数値、日付、選択肢、リレーション、計算値、メディア、構造化データ、そして住所、評価、署名のようなより豊かな入力です。また、すべてのオブジェクトには、宣言しなくてもシステムフィールド(`id`、`created_at`、`updated_at`、`created_by`、`updated_by`)があります。 + +## ObjectOS での使いどころ [#where-objectos-uses-it] + +ひとつのフィールド定義が、これらすべてを動かします。 + +``` +*.object.ts (field spec) + │ + ├─► Postgres / MySQL / SQLite column + index + constraint + ├─► REST: validated on POST/PATCH, exposed on GET + ├─► UI: form widget + list column + ├─► AI Builder: tool argument schema (so the AI knows what to ask) + └─► Audit: change-tracked if `trackHistory: true` +``` + +- **データベース**には、列、そのインデックス、制約が作られます。 +- **REST API** は、書き込みのたびにフィールドを検証し、読み取りでそれを返します([REST API](./rest-api))。 +- **UI** は、タイプからフォームのウィジェットとリストの列を選びます。 +- **AI Builder** は、タイプがそのツールの引数スキーマなので、何を尋ねればよいかがわかります。 +- **監査**は、`trackHistory` がオンのとき、フィールドの変更を記録します。 + +## 例 [#examples] + +**選択肢**:`select` フィールドの選択肢: + +```ts +// Keys of a `select` field; its other keys are omitted. +options: [ + { value: 'low', label: 'Low' }, + { value: 'high', label: 'High', color: '#e02' }, + { value: 'urgent', label: 'Urgent', color: '#c00' } +] +``` + +**リレーション**:アカウントへのルックアップ。選択画面を有効なものに絞り込みます。 + +```ts +// One field. +{ + type: 'lookup', + reference: 'account', // target object name + lookupFilters: [ // narrow the lookup picker + { field: 'status', operator: 'eq', value: 'active' } + ], + deleteBehavior: 'set_null' // 'set_null' | 'cascade' | 'restrict' +} +``` + +**計算値**:[CEL](./cel) で書かれた数式フィールド: + +```ts +// One field. +{ + name: 'profit_margin', + type: 'formula', + expression: F`(record.revenue - record.cost) / record.revenue * 100` +} +``` + +**添付ファイル**:サーバーでチェックされるファイル: + +```ts +// One field. +{ + type: 'file', + multiple: true, // store an array of attachments + accept: ['image/png', 'image/jpeg'], // MIME types / extensions + maxSize: 10_000_000 // bytes +} +``` + +## メディア [#media] + +メディアフィールドは**不透明な `sys_file` id** を保存します。URL でも、インラインのメタデータの塊でもありません。レコードを読んだときに見える `{ url, name, size, mimeType, … }` オブジェクトは展開された形であり、所有する `sys_file` レコードから導出されます。`url` は `/files/:fileId` リゾルバーから来ます。 + +バイトはプラットフォームが所有するため、`accept` と `maxSize` はブラウザのファイル選択画面へのヒントにとどまりません。サーバーはすべてのレコードの書き込みをそれらに照らして再チェックするため、API を直接呼び出す呼び出し元もそれらを回避できません。ダウンロードには実際のファイル名とコンテンツタイプが付き、読み取りアクセスは所有するオブジェクトに委ねられます。既存のデプロイメントは `os migrate files-to-references` で変換します。バイトの置き場所は[ストレージ](/docs/configure/storage)を、マイグレーションについては [17.0 のリリースノート](https://objectstack.ai/docs/releases/v17)を参照してください。 + +## 関連項目 [#see-also] + +- [構築 → データモデル](/docs/build/data):フィールドを組み合わせてオブジェクトにする +- [リレーションシップ](/docs/build/data/relationships):ルックアップと主従関係 +- [ObjectQL](./objectql):これらのフィールドのクエリ diff --git a/content/docs/reference/objectql.ja.mdx b/content/docs/reference/objectql.ja.mdx new file mode 100644 index 00000000..8e59d02d --- /dev/null +++ b/content/docs/reference/objectql.ja.mdx @@ -0,0 +1,77 @@ +--- +title: ObjectQL +seoTitle: "ObjectQL:JSON のクエリ形式、フィルター、結合" +description: データ API、ビュー、レポート、AI ツールを支える構造化クエリ形式です。ObjectOS での使いどころ、いくつかの例、そして objectstack.ai にある完全な構文を紹介します。 +editions: [community, cloud, enterprise] +translation: + source_sha: 694b3e7d0f7ea2228656bfed5c5c5b145b9a592f05c3dfea1c8efb55640a8505 + guide_rev: 1 + mode: auto +--- + +**完全な仕様:** [objectstack.ai の ObjectQL クエリ構文](https://objectstack.ai/docs/data-modeling/queries)。このページはその要約です。ObjectOS での使いどころと、いくつかの例を示します。 + +ObjectQL は、データエンジンが受け取る JSON のクエリ形式です。クエリはオブジェクトを指定し、どのレコードを返すかを記述します。`where` フィルター、`orderBy`、ページ(`limit`、`offset`)、`expand` するリレーション、そして任意で `aggregations` 付きの `groupBy` です。すべてのクエリは要求したユーザーとして実行されるため、そのユーザーが読めるレコードとフィールドしか返しません。 + +## ObjectOS での使いどころ [#where-objectos-uses-it] + +- **データ API**:`GET /api/v1/data/:object` はクエリ文字列のパラメーターとしてクエリを受け取ります。`POST /api/v1/data/:object/query` は完全な本文を受け取り、`groupBy` と `aggregations` を受け付けるのはこちらです([REST API](./rest-api))。 +- **ビュー**:ビューの `filter` と `sort` は ObjectQL にコンパイルされます([ビュー](/docs/build/interface/views))。 +- **レポート**:レポートは ObjectQL にシリアライズされます。 +- **AI**:`query_data` ツールは ObjectQL の本文を生成します。 + +## 例 [#examples] + +**緊急または期限切れの未解決チケット。** フィールドの演算子は `$` で始まります。`$and`、`$or`、`$not` がそれらを組み合わせ、`{ "$cel": "…" }` はサーバーがクエリ時に評価する [CEL](./cel) 式を埋め込みます。 + +```jsonc +{ + "$and": [ + { "status": { "$eq": "open" } }, + { + "$or": [ + { "priority": { "$in": ["high", "urgent"] } }, + { "due_at": { "$lt": { "$cel": "now()" } } } + ] + } + ] +} +``` + +**担当者と顧客アカウント付きのチケット。** 行ごとに 1 回リクエストするのではなく、1 回のバッチで解決されます。 + +```jsonc +{ + "object": "support_ticket", + "expand": ["assignee", "customer.account"], + "limit": 20 +} +``` + +**顧客ごとの月次売上で、10,000 を超えるもの。** `POST /data/order/query` を使います。 + +```jsonc +{ + "object": "order", + "where": { "status": { "$ne": "cancelled" } }, + "groupBy": [ + "customer_id", + { "field": "created_at", "dateGranularity": "month" } + ], + "aggregations": [ + { "function": "sum", "field": "amount", "alias": "total_sales" }, + { "function": "count", "alias": "order_count" } + ], + "having": { "total_sales": { "$gt": 10000 } }, + "orderBy": [{ "field": "total_sales", "order": "desc" }], + "limit": 25 +} +``` + +**クエリ文字列での並べ替え:** `?orderBy=-priority,created_at`。優先度の降順、次に古い順です。 + +## 関連項目 [#see-also] + +- [REST API](./rest-api):ObjectQL を受け付けるエンドポイント +- [フィールドタイプ](./field-types):各フィールドが何を保存し、したがって何で絞り込めるか +- [CEL](./cel):`$cel` の中の式言語 diff --git a/content/docs/reference/rest-api.ja.mdx b/content/docs/reference/rest-api.ja.mdx new file mode 100644 index 00000000..f2043777 --- /dev/null +++ b/content/docs/reference/rest-api.ja.mdx @@ -0,0 +1,122 @@ +--- +title: REST API +seoTitle: "REST API:生成されるエンドポイント、認証、OpenAPI" +description: ObjectOS がメタデータから生成する HTTP サーフェスです。製品での使いどころ、いくつかの例、そして objectstack.ai にある完全な仕様を紹介します。 +editions: [community, cloud, enterprise] +translation: + source_sha: 9fa13b663d57b4d063262824875deb8a379c76338ec7272227af4e273972d0b1 + guide_rev: 1 + mode: auto +--- + +**完全な仕様:** [objectstack.ai の REST and GraphQL APIs](https://objectstack.ai/docs/api)。このページはその要約です。ObjectOS での使いどころと、いくつかの例を示します。 + +宣言したすべてのオブジェクトに REST エンドポイントが用意され、すべてのアクションは `POST` になり、すべてのフローは HTTP から開始できます。書いたりデプロイしたりする別の API レイヤーはありません。ベース URL は `https:///api/v1` で、実行中のランタイムは `/api/v1/openapi.json`(OpenAPI 3.0)と `/api/v1`(サービスディスカバリー)で自身を記述します。 + +[公開フォーム](#public-forms)や[共有リンク](#share-links)のように、宣言によって匿名の呼び出し元に開放されている場合を除き、`/api/v1` の下のすべてのルートには、サインイン済みのセッションまたはベアラートークンが必要です。権限はルートごと、レコードごとにチェックされます。オブジェクト、レコード、フィールドのレベルのセキュリティは、UI とまったく同じように API の呼び出し元にも適用されます。キーとトークンについては [API アクセス](/docs/configure/api-access)を参照してください。 + +## ObjectOS での使いどころ [#where-objectos-uses-it] + +| サーフェス | ルート | 利用者 | +|:--|:--|:--| +| データ | `/data/:object`、`/data/:object/:id`、`/data/:object/query` | 生成された UI、連携、インポートとエクスポート。クエリは [ObjectQL](./objectql) です | +| アクション | `/actions/:object/:action` | UI のボタン、そしてアクションが AI に公開されている場合はエージェント([アクション](/docs/build/interface/actions)) | +| 自動化 | `/automation/:name/trigger`、`/automation/:name/runs` | 別のシステムからのフローの開始と、その実行の読み取り([フローと自動化](/docs/build/automation/flows)) | +| メタデータ | `/meta/:type/:name` | これを通じて保存する Studio と、実行中のメタデータを読むツール | +| AI | `/ai/chat`、`/ai/pending-actions` | [AI Builder](/docs/build/ai-builder) とその承認キュー | +| 公開フォーム | `/forms/:slug` | 匿名の回答者向けに公開されたフォームビュー | + +## 例 [#examples] + +**未解決のチケットを新しい順に一覧表示する:** + +```http +GET /api/v1/data/support_ticket?where={"status":{"$eq":"open"}}&orderBy=-created_at&limit=20 +Authorization: Bearer +``` + +```json +{ + "object": "support_ticket", + "records": [ { "id": "...", "subject": "...", "status": "open" } ], + "total": 137, + "hasMore": true +} +``` + +**オブジェクトを API から外す、または読み取り専用にする。** `enable` ブロックで指定します。 + +```ts +import { ObjectSchema, Field } from '@objectstack/spec/data'; + +// A read-only reference object, never writable over the API: +ObjectSchema.create({ + name: 'exchange_rate', + enable: { apiMethods: ['get', 'list'] }, + fields: { + rate: Field.number({ label: 'Rate', scale: 6 }), + // ...more fields + }, +}) + +// An internal object that the API never exposes: +ObjectSchema.create({ + name: 'sync_cursor', + enable: { apiEnabled: false }, + fields: { + cursor: Field.text({ label: 'Cursor' }), + // ...more fields + }, +}) +``` + +**メッセージではなく、エラーコードで分岐する:** + +```json +{ + "error": { + "code": "PERMISSION_DENIED", + "message": "Missing ai:approve on conversation 01H…", + "httpStatus": 403, + "details": { "permission": "ai:approve", "subject": "01H…" } + } +} +``` + +## API サーフェスを制限する [#restricting-the-api-surface] + +オブジェクトの `enable` ブロックは、生成されるエンドポイントを制御します。`apiEnabled: false` はオブジェクトを REST サーフェスから完全に除外するため、そのルートは `404` を返します。`apiMethods` は `get`、`list`、`create`、`update`、`delete`、`bulk` の許可リストで、それ以外の操作は REST レイヤーで拒否されます。どちらも強制されます(ADR-0049)。以前のバージョンは、これらを解析するだけで適用していませんでした。 + +## 公開フォーム [#public-forms] + +セッションなしで応答します。フォームビューは `sharing` でオプトインし、3 つのキーすべてが必要です:`enabled: true`、`allowAnonymous: true`、そして `publicLink` のスラッグ。ObjectStack 17.7 以降、後の 2 つだけを設定したフォームは `404 FORM_NOT_FOUND` を返します。[ビュー → 公開フォーム](/docs/build/interface/views#public-forms)を参照してください。`GET /forms/:slug` はフォームを返し、`POST /forms/:slug/submit` はそれを送信します。 + +## 共有リンク [#share-links] + +これもセッションなしで応答します。リンクに含まれるトークンが認可です。`GET /share-links/:token/resolve` は、リンクが隠すフィールドを除いて、リンクが共有する 1 つのレコードを返します。サインイン済みのユーザーに限定されたリンクは、セッションのない呼び出し元に `401 SIGN_IN_REQUIRED` を返し、パスワードで保護されたリンクは、パスワードが送信されるまで `401 NEEDS_PASSWORD` を返します。リンクの作成、一覧表示、取り消し(`POST /share-links`、`GET /share-links`、`DELETE /share-links/:idOrToken`)にはセッションが必要です。[共有リンク:リンクを知っている全員](/docs/use/collaboration#share-links-anyone-with-the-link)を参照してください。 + +## フローのステータス表 [#flow-status-table] + +トリガーのルート、タイプ `flow` のアクション、宣言された `type: 'flow'` のエンドポイントは、すべて同じステータスを返します。本文の中の `success` フラグではなく、HTTP ステータスで分岐してください。 + +| ステータス | コード | 意味 | +|:--|:--|:--| +| `200` | — | 実行がディスパッチされました。その `status` は `completed`、`paused`(画面、承認、タイマーを待機中)、または `refused`(`outcome: 'refused'` の `end` ノードに到達。テキストは `refusalMessage` にあります)です | +| `404` | `RESOURCE_NOT_FOUND` | その名前のフローがありません | +| `409` | `FLOW_DISABLED` | フローがオフになっています | +| `422` | `FLOW_NO_START_NODE` | 保存された定義に開始ノードがなく、実行できません | +| `400` | `FLOW_FAILED` | 実行はディスパッチされましたが失敗しました。詳細にはフローの `errorMessage` が含まれます | + +## メタデータ:`/api/v1/meta/*` [#metadata--apiv1meta] + +`/meta/:type/:name` はメタデータ項目の唯一のアドレスです。スラッシュを含む名前はパーセントエンコードします(`GET /api/v1/meta/lead/views%2Fall_leads`)。セクション分けされた `/meta/:type/:section/:name` のルートは ObjectStack 17.3 で廃止され、`404 ROUTE_NOT_FOUND` を返します。保存には作成の機能が必要で、`datasource` のメタデータの読み取りや保存には `manage_platform_settings` が必要です。 + +## レポート [#reports] + +保存済みレポートの API はありません。ObjectStack 17.5 で `/reports`、`/reports/:id/run`、`/reports/:id/schedule` が削除され、現在は `404` を返します。レポートはメタデータであり、`/meta/report/:name` で読み取ります。その数値は分析(`POST /analytics/query`)から得られます。 + +## 関連項目 [#see-also] + +- [API アクセス](/docs/configure/api-access):キー、トークン、誰が何を呼び出せるか +- [ObjectQL](./objectql):`/data/*` が受け付けるクエリ形式 +- [セキュリティ](./security):すべてのルートが実行前にチェックするもの diff --git a/content/docs/reference/runtime-capabilities.ja.mdx b/content/docs/reference/runtime-capabilities.ja.mdx new file mode 100644 index 00000000..2bba23cf --- /dev/null +++ b/content/docs/reference/runtime-capabilities.ja.mdx @@ -0,0 +1,66 @@ +--- +title: ランタイムの機能 +seoTitle: "ランタイムの機能:ベースとオプションのパッケージ" +description: ObjectOS が ObjectStack フレームワークのパッケージから読み込める機能。 +editions: [community, cloud, enterprise] +translation: + source_sha: 3beb96f0a63636343e3b8750462e6b3051b331b4addc65c3e2c18c93c9ec4d4e + guide_rev: 1 + mode: auto +--- + +ObjectOS はすべてのプロジェクトでベースのランタイムを読み込み、その後、アプリケーションのアーティファクトが宣言したオプションの機能をインストールします。 + +## ベースのランタイム [#base-runtime] + +ベースのプロジェクトカーネルには次のものが含まれます。 + +- ObjectKernel のライフサイクルとサービスレジストリ +- ObjectQL データエンジン +- 設定されたデータドライバー +- メタデータサービス +- アプリケーションのアーティファクトの登録 +- `OS_AUTH_SECRET` が設定されている場合の認証 +- RBAC、行レベルセキュリティ、フィールドのセキュリティのためのセキュリティプラグイン +- i18n サービス + +## オプションの機能 [#optional-capabilities] + +アーティファクトは `requires` リストで機能を宣言できます。ObjectOS は、イメージに存在する場合、一致するフレームワークのパッケージを読み込みます。 + +| 機能 | パッケージ | 目的 | +|---|---|---| +| `automation` | `@objectstack/service-automation` | フロー/DAG の実行と自動化ノード | +| `ai` | フレームワークのパッケージではありません。AI ランタイムは ObjectOS に付属します([AI サービス](/docs/configure/ai)) | LLM アダプター、会話、ツール、SSE ルート | +| `analytics` | `@objectstack/service-analytics` | キューブ、分析クエリ、レポートのデータ | +| `audit` | `@objectstack/plugin-audit` | 監査ログのオブジェクトと監査証跡 | +| `cache` | `@objectstack/service-cache` | キャッシュの抽象化とアダプター | +| `storage` | `@objectstack/service-storage` | ファイル/オブジェクトストレージのサービス | +| `queue` | `@objectstack/service-queue` | キューの抽象化とワーカー | +| `job` | `@objectstack/service-job` | スケジュール/バックグラウンドのジョブ | +| `realtime` | `@objectstack/service-realtime` | WebSocket と pub/sub のリアルタイム | +| `settings` | `@objectstack/service-settings` | 設定のマニフェストと K/V リゾルバー | + +機能が要求されているのにイメージにそのパッケージが含まれていない場合、**ObjectOS は警告をログに出力し、その機能を無効にしたまま実行を続けます。** これは意図的な動作です。開発中にオプションのパッケージが欠けていてもランタイムが起動できるようにするためです。しかし**本番では現実のリスク**になります。 + +- 監査を必要とするアプリを `@objectstack/plugin-audit` のないイメージに読み込むと、問題なく起動し、**監査ログを一切書き込みません**。コンプライアンスの証拠が、エラーもなく欠落します。 +- ジョブで動くアプリを `@objectstack/service-job` のないイメージに読み込むと、問題なく起動し、**スケジュールされた処理を黙って一切実行しません**。 + +**本番のチェックリスト:** + +1. 機能の警告はデプロイの失敗として扱います。起動ログを `capability not loaded`(またはそれに相当するもの)で検索し、1 つでもあれば readiness プローブ / ロールアウトを失敗させます。 +2. ObjectOS ランタイムのイメージは、アーティファクトが `requires` で宣言するすべてのパッケージを含むものに固定します。 +3. アーティファクトを公開するときは、その `requires` リストを一緒に記載し、オペレーターが対応するイメージを確認できるようにします。 + +## API サーフェス [#api-surface] + +ObjectOS が一般的に公開するもの: + +- 生成された REST API +- `/api/v1/auth/*` の下の認証エンドポイント +- メタデータと i18n のエンドポイント +- 有効な機能のサービスエンドポイント + +OData はフレームワークレベルの機能であり、デプロイされたランタイムのパッケージに含まれ、かつ有効になっている場合にだけ、サポートされていると記載すべきものです。 + +**GraphQL はそれらに含まれません。** GraphQL のサーフェスは ObjectStack 17.0 で削除されました。このルートの背後にエンドポイントが実装されたことは一度もなく、現在 `/graphql` は 404 を返します。どのランタイムパッケージについても、利用可能またはオプションの機能として記載しないでください。(`graphql` は**外部データソース**のプロトコルとしては引き続き有効です。それは ObjectOS がクエリするシステムであり、ObjectOS が提供するサーフェスではありません。) diff --git a/content/docs/reference/security.ja.mdx b/content/docs/reference/security.ja.mdx new file mode 100644 index 00000000..7f6e2c51 --- /dev/null +++ b/content/docs/reference/security.ja.mdx @@ -0,0 +1,241 @@ +--- +title: セキュリティとコンプライアンス +description: 何が、どのように保護され、誰が責任を負うのか。セキュリティレビューのために。 +editions: [community, cloud, enterprise] +translation: + source_sha: f4b8cc8aeeb89ea330e8e0c536e84ad3f27d8bb2ae336f839e9321ab0da0c9a7 + guide_rev: 1 + mode: auto +--- + +このページは、セキュリティレビューの担当者、IT 管理者、そして「これを導入しても安全か」に答えなければならないすべての人のためのものです。 + +## 一文で表す脅威モデル [#threat-model-in-one-sentence] + +ObjectOS は、1 つのデータベースと通信する単一の Node.js プロセスとして動作します。**ObjectOS Enterprise** では**あなたの**ネットワークの中で、**ObjectOS Cloud** では私たちのネットワークの中で動作します。セルフマネージドの場合、ObjectOS が自ら行う唯一のアウトバウンドの呼び出しはライセンスの検証であり、Enterprise のエアギャップライセンスはオフラインで検証されます。侵害の影響範囲は、接続先のデータベース上のデータであり、それ以上ではありません。 + +## データレジデンシー [#data-residency] + +この表は、セルフマネージドのエディションである **ObjectOS Enterprise** について記述しています。**ObjectOS Cloud** では、同じ種類のデータが私たちがあなたのために運用するインフラストラクチャに置かれます。どちらのエディションでも、オントロジーはオープンソースの ObjectStack ランタイムへエクスポートできます。 + +| データの種類 | 置き場所 | ネットワークの外に出るか | +|---|---|---| +| 業務レコード | あなたのデータベース | **いいえ** | +| ユーザーアカウント、セッション、OAuth トークン | あなたのデータベース | **いいえ** | +| 監査ログ | あなたのデータベース | **いいえ** | +| 設定、API キー、シークレット | あなたのデータベース / あなたのシークレットマネージャー | **いいえ** | +| アップロードされたファイル | あなたのディスク、または S3 互換のバケット(S3、R2、MinIO) | **いいえ** | +| コンパイル済みのアプリ定義(`objectstack.json`) | ディスク上のファイル、またはあなたのコントロールプレーンから取得 | 任意 | +| ランタイム自体 | あなたのサーバーまたはコンテナ | **いいえ** | +| テレメトリ / 利用データ | — | **一切収集しません** | + +明示的に設定した連携(OIDC ディスカバリー、メールプロバイダー、AI プロバイダー、Webhook の送信先、外部ストレージ)以外で、セルフマネージドの ObjectOS が自ら行う唯一のアウトバウンドの呼び出しは**ライセンスの検証**です。Enterprise のエアギャップライセンスはオフラインで検証されるため、エアギャップのデプロイメントは何も呼び出しません。[ライセンスと料金](/docs/editions/license#faq)を参照してください。 + +## 暗号化 [#encryption] + +| 層 | 仕組み | 責任 | +|---|---|---| +| 通信中(ブラウザ ↔ ObjectOS) | TLS。あなたのエッジ / イングレスで終端 | あなた | +| 通信中(ObjectOS ↔ データベース) | ドライバーレベルの TLS(Postgres の `sslmode=require`、MongoDB の `tls=true` など) | あなた(接続文字列で設定) | +| 保存時(業務データ) | データベースネイティブ(例:Postgres TDE、RDS の暗号化) | あなた | +| 保存時(アップロードされたファイル) | ストレージネイティブ(S3 SSE、R2 のデフォルト、ディスクレベルの FDE) | あなた | +| DB 内のシークレット(設定、OIDC クライアントシークレット) | 設定サービスによって暗号化 | ObjectOS | +| セッション Cookie / トークン | `OS_AUTH_SECRET` で HMAC 署名 | ObjectOS | +| API キーの値 | DB では**ハッシュ化**。DB の行が漏洩してもキーは復元できません | ObjectOS | + +## 認証 [#authentication] + +組み込み(Better Auth を基盤とする `@objectstack/plugin-auth` による): + +- 確認とリセット付きのメール/パスワード +- 取り消しが可能なセッション管理 +- ソーシャル OAuth(Google、GitHub、Microsoft、Apple など) +- エンタープライズの OIDC/SSO(Okta、Entra ID、Keycloak、Ping) +- 二要素認証(TOTP) +- パスキー / WebAuthn +- マジックリンク +- 電話番号と SMS の OTP によるサインインとパスワードリセット(`auth.plugins.phoneNumber` でオプトイン。Aliyun / Twilio のトランスポート、レート制限付き) +- CLI/ブラウザのデバイスフロー +- API キー(ハッシュ化、有効期限付き、取り消し可能、ユーザーに紐づく) +- MCP クライアント向けのセルフサービスの OAuth 2.1(認可コード + PKCE、動的クライアント登録、スコープから導出される権限の上限) +- 管理者主導のユーザー作成と一括インポート(`must_change_password` による強制変更付きのワンタイムパスワード) + +[認証](/docs/configure/authentication)を参照してください。 + +## 認可 [#authorization] + +Permission Model v2(ObjectStack 13、ADR-0090)に従った、層状の強制(`@objectstack/plugin-security` による): + +1. **オブジェクト権限**:権限セットごと、オブジェクトごとの CRUD。ユーザーに直接、またはフラットな**ポジション**を通じて配布されます +2. **組織全体のデフォルト**:所有者を持つカスタムオブジェクトは、デフォルトで `private` の共有モデルになります。オブジェクトのデータへの匿名アクセスは無条件に拒否され、それを開くスイッチはありません(ObjectStack 17.0)。公開アクセスはサーフェスごとに宣言します(公開フォームまたは共有リンク)。`guest` アンカーは何も付与しません +3. **行レベルセキュリティ**:クエリに注入される宣言的なポリシー式。省略はできず、ランタイムが強制できないポリシーは範囲を広げるのではなく拒否します(ObjectStack 17.5) +4. **フィールドレベルのセキュリティ**:フィールドはレスポンスから除去されるか、部分的にマスクされるか(`maskingRule`、ObjectStack 17.1)、書き込み時に拒否されます(キーはオブジェクトで修飾され、lint で強制されます)。非表示またはマスクされたフィールドでは、絞り込み、並べ替え、グループ化、集計ができません。ObjectStack 17.6 以降、すべてのクエリの入り口で `403` になります +5. **組織のスコープ**:マルチテナントの分離。回避には明示的な `viewAllRecords` が必要です + +システムコンテキストの操作は、内部のジョブやマイグレーションが実行できるようにチェックを回避します。これらの経路は監査可能です。 + +それを支える仕組み: + +- **説明エンジン**:`explain(principal, object, operation)` は、強制と同じ評価器を使って、各層の判定を層ごとの根拠とともに報告します(構造上ずれは生じません)。 +- **作成時の lint**:`os compile` はセキュリティの姿勢(`security-owd-unset`、`security-anchor-high-privilege`、`security-fls-unqualified-key` など)によってビルドを制限します。また、任意でコミットする `access-matrix.json` のスナップショットにより、機能のずれがあると明示的に再承認されるまで CI が失敗します。 +- **委任された管理**:権限セットに `adminScope` を持たせると、サブ管理者は自分のビジネスユニットのサブツリー内でのみ、許可リストから、`granted_by` の監査付きで割り当てを管理できます。 +- **MCP のスコープの上限**:OAuth で接続した AI エージェントは `effective_permission = scope_ceiling ∩ user_grants`(`data:read` / `data:write` / `actions:execute`)のもとで実行され、フェイルクローズです。 + +[権限](/docs/configure/permissions)を参照してください。 + +## 監査と証拠 [#audit--evidence] + +監査機能(`@objectstack/plugin-audit`)が読み込まれている場合: + +- すべてのオブジェクトにおけるすべての CRUD 操作 → 監査の行。 +- フィールドの変更の変更前と変更後の値。 +- 認証、権限の付与、セッションの取り消しのイベント。 +- 監査の行は**改ざんできません**。変更はできず、アーカイブのみ可能です。 +- 保持期間はオブジェクトの `lifecycle` ブロックで宣言され(`sys_audit_log` は 90 日間ホット、その後アーカイブとして提供されます)、`lifecycle.retention_overrides` で環境ごとに調整できます。データベースのアーカイブポリシーと組み合わせてください。 + +これが、SOC 2 CC6/CC7、ISO 27001 A.12.4、HIPAA §164.312(b)、GDPR 第 30 条の証拠の基盤になります。 + +## コンプライアンスのフレームワーク [#compliance-frameworks] + +ObjectOS は、一般的なフレームワークのすべてが求める**技術的なプリミティブ**を提供します。認証はソフトウェアではなくデプロイメントの性質ですが、統制はきれいに対応します。 + +| フレームワーク | ObjectOS が提供するもの | +|---|---| +| **SOC 2** | アクセス制御(CC6)、変更管理(監査ログ)、暗号化(デプロイメント)、監視(オブザーバビリティ)、バックアップ(operate/backup) | +| **ISO 27001** | A.5 ポリシー(RBAC)、A.8 資産管理(オブジェクトのカタログ)、A.9 アクセス制御、A.12 運用、A.18 コンプライアンス | +| **HIPAA** | アクセス制御(§164.312(a))、監査制御(§164.312(b))、完全性(改ざんできない監査)、伝送のセキュリティ(TLS) | +| **GDPR** | 第 30 条 処理の記録(監査)、第 32 条 処理のセキュリティ、第 17 条 消去権(論理削除と物理削除をサポート)、データレジデンシー(リージョンを選択可能) | +| **CCPA / 中国データセキュリティ法 / ロシア 152-FZ** | 適切なリージョンの ObjectOS Enterprise でレジデンシーを満たします。アクセス制御と監査で、報告義務のほとんどをカバーします | + +認証の対象はバイナリではなく稼働中のデプロイメントであるため、ObjectOS 自体は**認証を受けていません**。あなたのデプロイメントは認証を受けることができ、すでに多くが受けています。 + +## シークレットの取り扱い [#secrets-handling] + +| シークレット | 置き場所 | +|---|---| +| `OS_AUTH_SECRET` | あなたのシークレットマネージャー(Vault、AWS Secrets Manager、k8s Secret)。環境変数として注入します | +| 認証情報を含むデータベース URL | 同上 | +| OIDC クライアントシークレット | 同上 | +| OAuth プロバイダーのシークレット | 同上 | +| API プロバイダーのキー(メール、ストレージ、AI) | 同上 | +| DB に保存された設定 | 保存時に設定サービスによって暗号化 | + +シークレットをアーティファクト(`objectstack.json`)、Docker イメージ、compose ファイル、Git に**決して**焼き込まないでください。Setup の設定 UI は、環境で管理された値をロックされた状態で表示するため、オペレーターが誤って上書きすることはありません。 + +## ネットワークモデル [#network-model] + +必須のインバウンド: +- イングレス / ロードバランサーから ObjectOS の `:3000`(デフォルト)への HTTPS。 + +必須のアウトバウンド: +- セルフマネージドの ObjectOS のライセンスの検証。Enterprise のエアギャップライセンスはオフラインで検証されるため、そのための送信は不要です。 + +次の機能を設定した場合にのみ必要なアウトバウンド: +- データベース(Postgres / Mongo / Turso など)。 +- S3 互換のストレージ(`storage` 機能を S3 アダプターで有効にした場合)。 +- OIDC のディスカバリー URL(SSO を有効にした場合)。 +- メールプロバイダーの API(Resend / Postmark)。 +- AI プロバイダーの API(OpenAI / Anthropic / Google など)。 +- Webhook の送信先。 + +送信のサーフェスはこれですべてです。さらに削減するデプロイメントについては[エアギャップ](/docs/deploy/air-gapped)を参照してください。 + +## AI:ツール、承認、分離 [#ai-tools-approvals-isolation] + +AI Builder は、公開するものの中で最もセキュリティに敏感なサーフェスです。そのため、上記のすべてに加えて独自の強制の層を持っています。 + +### AI が状態を変更する仕組み [#how-ai-can-mutate-state] + +モデルはデータベースに**直接書き込むことはできません**。状態が変わる唯一の方法は、構造化されたツール呼び出しを出力し、AI サービスがそれを受け取り、検証し、キューに入れることです。その流れは次のとおりです。 + +```text +user prompt + → model emits tool call (e.g. add_field { object: 'ticket', name: 'severity', type: 'select' }) + → AI service validates payload against the tool's Zod schema + → if the tool is "mutating": queue as pending action (no state change yet) + → human reviewer approves → mutation applied → audit row written + → if the tool is "read-only": run immediately, response returned to model +``` + +ファーストパーティのメタデータツールが 11 個あり([構築 → AI Builder](/docs/build/ai-builder) を参照)、加えて、作成者が [AI に公開した](/docs/build/interface/actions#from-an-ai-agent)アクションごとに `action_` ツールが 1 つあります。公開とは、UI なしで実行されるタイプ(`script`、`flow`、`api`)で、40 文字以上の `ai.description` とともに `ai: { exposed: true }` を指定することです。公開されていないアクションはエージェントからは見えず、呼び出されても拒否されます。ファーストパーティでもカスタムでも、すべてのツールは同じライフサイクルを持ちます。 + +### 権限のキー [#permission-keys] + +| キー | 付与するもの | +|:--|:--| +| `ai:chat` | 会話を行う、モデルを使う、エージェントに読み取り専用のツールを呼び出させる | +| `ai:complete` | 生の補完エンドポイント(エージェントループなし) | +| `ai:conversations` | 会話の一覧表示 / 確認 / 削除(RBAC のスコープに応じて自分のものまたはすべて) | +| `ai:agents` | エージェントのメタデータの管理(呼び出すには `ai:chat` も必要) | +| `ai:tools` | ツールのカタログの一覧表示 | +| `ai:execute` | REST でツールを直接呼び出す(上級者向け。通常は常駐エージェントだけが必要とします) | +| `ai:read` | 保留中のアクションのキューとモデルの一覧の読み取り | +| `ai:approve` | キューに入った変更の承認 / 却下 | +| `ai:admin` | AI サービスの完全な管理 | + +重要な分離は **`ai:chat` ≠ `ai:approve`** です。アシスタントが機能するように、ほとんどのユーザーには `ai:chat` を付与し、`ai:approve` は構造的な変更をレビューすべき管理者 / アプリのオーナーに限定します。そうすれば、エンドユーザーは安全に「バイブビルド」できます。最悪の場合でも、他の誰かが承認しなければならない悪い変更をキューに入れるだけです。 + +### テナントの分離 [#tenant-isolation] + +- エージェント、会話、ナレッジベース、保留中のアクションは、1 つの **Environment**(テナント)にスコープされます。テナント A は、同じマーケットプレイスのパッケージから同じエージェント定義をインストールしていても、テナント B の会話、AI が提案したツール、ナレッジのコーパスを見ることはできません。 +- メタデータツール(`create_object`、`add_field` など)は、呼び出し元のテナントの**アクティブなパッケージ**に対して動作します。その外には届きません。 +- ツールの入力は CEL で検証され、エンジンは予約されたシステムパッケージ(`sys.*`)や他のテナントのオブジェクト名への参照を拒否します。 + +### 監査イベント [#audit-events] + +監査機能が読み込まれている場合: + +- `ai.chat.message`:ユーザー / アシスタントのすべてのメッセージ。モデルとトークン数付き +- `ai.tool.call`:ツール名、検証済みの入力、完全な出力(またはエラー) +- `ai.pending_action.queued`:提案された変更と、その完全な差分 +- `ai.pending_action.approved` / `.rejected`:誰が、いつ、なぜ決めたか +- `ai.metadata.applied`:メタデータストアへの実際の書き込みと、その差分 + +これらの行は改ざんできず、セキュリティレビューやチャージバックのためにエクスポートできます。(プロバイダー、モデル、ユーザー)ごとのトークン数が、コストの配分に使われます。 + +### プロンプトインジェクションへの姿勢 [#prompt-injection-posture] + +間接的なプロンプトインジェクション(エージェントが取得したドキュメント内の悪意あるコンテンツなど)は現実のリスクです。ObjectOS は構造的に影響範囲を縮小します。 + +- AI は**ツールの検証を回避できません**。悪意のあるペイロードを出力するよう説得されたとしても、Zod スキーマが不正な形式の入力をエンジンに届く前に拒否します。 +- 変更を行うツールは常にキューに入ります。注入されたプロンプトが黙ってデータベースに書き込むことはできません。 +- ツールの呼び出しは、モデルのサービスアカウントの権限ではなく、**エンドユーザーの権限**を継承します。ユーザーが UI や REST で自分ではできないことを、AI を使って行うことは決してできません。 +- エージェントに読み込まれるスキルは、バージョン管理された明示的なものです。[構築 → IDE スキル](/docs/build/ai-skills)と[構築 → AI Builder](/docs/build/ai-builder) を参照してください。 + +### 外部の AI プロバイダーへのデータの流れ [#external-ai-provider-data-flow] + +プロバイダー(OpenAI、Anthropic など)を設定した場合、ネットワークの外に出るのは次のものだけです。 + +- モデルが必要とする会話の履歴 +- ツールの定義(名前、JSON スキーマ。レコードのデータは含みません) +- モデルが続行するために必要なツールの出力(ユーザーが明示的に求めたクエリの結果など) + +エアギャップのデプロイメントでは、AI サービスをローカルの Ollama / vLLM / TGI のエンドポイントに向ければ、同じ流れが境界の内側にとどまります。 + +## 脆弱性の開示 [#vulnerability-disclosure] + +セキュリティの問題は **security@objectstack.ai** に非公開で報告してください。1 営業日以内に回答します。セキュリティの問題について、公開の GitHub issue を作成しないでください。 + +## サプライチェーン [#supply-chain] + +- **Community** イメージ `ghcr.io/objectstack-ai/objectstack` は公開されています。ObjectStack のリリースごとに、オープンソースの [objectstack-ai/objectstack](https://github.com/objectstack-ai/objectstack) リポジトリからビルドされて公開され、タグは内部の ObjectStack CLI のバージョンを反映しています。 +- **Enterprise** イメージはライセンスされたイメージで、プライベートレジストリから取得します。レジストリの認証情報はライセンスとともに提供されます。[デプロイ](/docs/deploy#the-two-images)を参照し、[Docker](/docs/deploy/docker#verify-the-image-before-production) の説明に従って本番の前にイメージを検証してください。 +- すべての `@objectstack/*` パッケージは、ソースが GitHub で公開されています。Apache-2.0 で、難読化はありません。 +- 本番では正確なイメージをひとつに固定し、ダイジェストで固定してください。決して動かないのはダイジェストだけです。Community では、正確なバージョンタグ(`X.Y.Z`)を実行し、そのダイジェストを固定します。`latest` のような移動するタグはリリースのたびに付け替えられ、公開済みのバージョンの再ビルドは、その `X.Y.Z` タグを新しいバイトに再プッシュします。Enterprise では、リリースノートに記載されたダイジェストを固定します。[Docker](/docs/deploy/docker#pin-the-image) を参照してください。 + +## 推奨される堅牢化のチェックリスト [#suggested-hardening-checklist] + +- [ ] 本物の証明書で、エッジで TLS が終端されている。 +- [ ] `OS_AUTH_SECRET` が 32 バイト以上のランダムな値で、シークレットマネージャーにある。 +- [ ] データベースの接続が TLS を使っている。 +- [ ] TLS の検証後に HSTS が有効になっている。 +- [ ] CORS のオリジンが明示されている(認証情報と `*` を決して組み合わせない)。 +- [ ] 認証エンドポイントにレート制限がある(`10/min/IP` を推奨)。 +- [ ] 監査の保持期間がポリシーと一致している。 +- [ ] 人のアカウントには OIDC、マシンのアカウントには API キー。 +- [ ] バックアップと復元の予行演習を実施し、所要時間を計測した。 +- [ ] 否定テスト:組織をまたぐアクセスが拒否される、フィールドのセキュリティが保たれる、期限切れのセッションが拒否される。 +- [ ] イメージが移動するタグではなく、ダイジェストで固定されている(Community では、正確なバージョンタグ `X.Y.Z` のダイジェスト)。 +- [ ] 各リリースの前に、CI で `os doctor` がクリーンである。 + +本番稼働の完全なチェックリストは[本番環境への準備](/docs/operate/production)を参照してください。 diff --git a/content/docs/reference/skills-cli.ja.mdx b/content/docs/reference/skills-cli.ja.mdx new file mode 100644 index 00000000..dbdf59e0 --- /dev/null +++ b/content/docs/reference/skills-cli.ja.mdx @@ -0,0 +1,48 @@ +--- +title: skills CLI +seoTitle: "skills CLI:コーディングエージェントにスキルをインストールする" +description: ObjectStack のスキルをコーディングエージェントにインストールする npx コマンドです。ObjectOS での使いどころ、いくつかの例、そして objectstack.ai にある完全なスキルリファレンスを紹介します。 +editions: [community, cloud, enterprise] +translation: + source_sha: 26df3bfe697fc1dcc37dc143c85b53c43d842b6b8a5801ad85e00738000a6399 + guide_rev: 1 + mode: auto +--- + +**完全な仕様:** [objectstack.ai の AI スキルリファレンス](https://objectstack.ai/docs/ai/skills-reference)。このページはその要約です。ObjectOS での使いどころと、いくつかの例を示します。 + +[`skills`](https://www.npmjs.com/package/skills) CLI([vercel-labs/skills](https://github.com/vercel-labs/skills) 製)は、ドメインごとの指示を AI コーディングエージェントにインストールします。ObjectStack のスキルは、Claude Code、Cursor、Copilot、Codex などに、ObjectOS が実行するメタデータ(オブジェクト、ビュー、フロー、権限、クエリ、CEL)を実際のスキーマに沿って書く方法を教えるため、エージェントが書いたものはコンパイルが通ります。 + +## ObjectOS での使いどころ [#where-objectos-uses-it] + +- **IDE でアプリを手作業で作成する。** ブラウザ内の [AI Builder](/docs/build/ai-builder) は ObjectOS の中でメタデータを書いてくれます。リポジトリで作業する場合は、スキルが自分のコーディングエージェントに同じ語彙を与えます。[構築 → IDE スキル](/docs/build/ai-skills)を参照してください。 +- **エージェントを最新に保つ。** スキルは、それが説明するスキーマと並んで [objectstack リポジトリ](https://github.com/objectstack-ai/objectstack/tree/main/skills)にあるため、アップグレード後に再インストールすればエージェントが最新の状態になります。 + +## 例 [#examples] + +現在のプロジェクトにスキルを**インストール**します。CLI はプロジェクトが使っているエージェントを検出し、それぞれのネイティブ形式(`.claude/skills/`、`.cursor/rules/`、`AGENTS.md` など)で書き込みます。 + +```bash +npx skills add objectstack-ai/objectstack/skills +``` + +再現可能な CI のために**バージョンを固定**します。 + +```bash +npx skills add https://github.com/objectstack-ai/objectstack/tree//skills +``` + +インストールされているものを**確認・管理**します。 + +```bash +npx skills detect # show which agents the CLI will write to +npx skills list # list installed skills +npx skills remove # remove a skill +``` + +**出力をコミットします。** スキルは、チーム全体(CI のエージェントを含む)で共有すべき Markdown であり、CLI が書き込むパスはいずれにせよチェックインするものです。 + +## 関連項目 [#see-also] + +- [構築 → IDE スキル](/docs/build/ai-skills):AI Builder と並ぶスキル +- [vercel-labs/skills](https://github.com/vercel-labs/skills):アップストリームの CLI From 4b48d10db53dab85d2b825e01015595e05ac45c9 Mon Sep 17 00:00:00 2001 From: Steedos Date: Thu, 29 Oct 2026 14:08:33 +0000 Subject: [PATCH 11/22] docs(i18n): translate resources/ into ja, completing ja coverage (#388, PR 7 of 7) Adds ja translations for the 4 resources/ pages: changelog, faq, glossary and support. resources/meta.ja.json already matches the English pages list. Same rules as the earlier batches. With this batch every English page has a ja translation. check-translations: ja 0 stale, 0 missing (was 4). Fixes #388 Claude-Session: https://claude.ai/code/session_01QsR2jRsjbApbf83iyTDDXm Co-Authored-By: Claude --- content/docs/resources/changelog.ja.mdx | 289 ++++++++++++++++++++++++ content/docs/resources/faq.ja.mdx | 178 +++++++++++++++ content/docs/resources/glossary.ja.mdx | 190 ++++++++++++++++ content/docs/resources/support.ja.mdx | 77 +++++++ 4 files changed, 734 insertions(+) create mode 100644 content/docs/resources/changelog.ja.mdx create mode 100644 content/docs/resources/faq.ja.mdx create mode 100644 content/docs/resources/glossary.ja.mdx create mode 100644 content/docs/resources/support.ja.mdx diff --git a/content/docs/resources/changelog.ja.mdx b/content/docs/resources/changelog.ja.mdx new file mode 100644 index 00000000..3272adcb --- /dev/null +++ b/content/docs/resources/changelog.ja.mdx @@ -0,0 +1,289 @@ +--- +title: 変更履歴とバージョン管理 +description: ObjectOS のバージョン管理の方法、リリース間で何が変わるか、どのバージョンがサポートされるか。 +editions: [community, cloud, enterprise] +translation: + source_sha: 323046628fabcce6da190adf852a2f76c7c2b603056f600290b8dbf3ef64dfd3 + guide_rev: 1 + mode: auto +--- + +## バージョン管理の方針 [#versioning-policy] + +ObjectOS のバージョンは **[セマンティックバージョニング](https://semver.org/)** の形式 `MAJOR.MINOR.PATCH` を取ります。ただし表に記載の例外が 1 つあります。v17 系では、マイナーでも破壊的な変更が入ることがあります。 + +| バージョンの上がり方 | 意味 | すること | +|---|---|---| +| **パッチ**(`14.7.0 → 14.7.1`) | バグ修正。動作の変更なし | そのまま更新します。アプリの変更は不要です | +| **マイナー**(`17.4 → 17.5`) | 新機能。v17 系では破壊的な修正も含みます。17.x のどのリリースノートにも同じ言葉で書かれています。「影響範囲ではなく、バージョン番号の上でのマイナー」です | 更新の前に、そのリリースのアップグレードチェックリストと[バージョン別の手順](/docs/operate/upgrade#version-specific-steps)を読んでください | +| **メジャー**(`13 → 14`) | リリースノートに記載された破壊的な変更 | アップグレードの前に移行ガイドを読んでください | + +すべての `@objectstack/*` パッケージは、同期したバージョン番号で一緒にリリースされます。個別ではなく、マトリクスとしてテストされています。 + +## 互換性マトリクス [#compatibility-matrix] + +| コンポーネント | 互換性のルール | +|---|---| +| ObjectOS イメージ ↔ コンパイル済みの成果物 | 同じマイナーバージョン。14.7.x のイメージは 14.7.x の成果物を実行します。14.7 の成果物は、14.0 のイメージにない機能を使っている場合があります。プロトコルハンドシェイク(`PROTOCOL_VERSION`、12.0 以降)が、互換性のないパッケージをインストール時に拒否します。 | +| ObjectOS ↔ CLI | 同じマイナーバージョンを推奨します。`npm i -g` で入れた CLI は、自身のバージョンに固定したスキャフォールドを書き出します。 | +| ObjectOS ↔ データベースドライバー | ドライバーはイメージのビルドで固定されます。Postgres 13 以上 / MongoDB 5 以上 / Turso(現行のもの)であることを確認してください。 | +| Node.js | **22 以上**。17.0 以降に公開されたすべての `@objectstack/*` パッケージで `engines.node` は `>=22.0.0` です。Node 20 は 2026-04-30 にサポートが終了しました。 | + +## サポート期間 [#support-windows] + +サポートは固定の日付ではなく、**現在のメジャーを基準に**定義されます。 + +| ブランチ | 状態 | +|---|---| +| 現在のメジャー(現時点では 17.x) | 活発に開発中。新機能と修正 | +| 1 つ前のメジャー(現時点では 16.x) | セキュリティ修正のみ | +| それより古いメジャー | サポート対象外 | + +重大なセキュリティ修正は、現在のメジャーと 1 つ前のメジャーにバックポートされます。それ以外はすべて `main` に入ります。特定のメジャーに関する日付は、そのメジャーの[リリースノート](https://objectstack.ai/docs/releases)とともに公開されます。 + +## リリースノート [#release-notes] + +リリースされた ObjectOS のバージョンと CHANGELOG のエントリーは、次の場所で公開されています。 + +- **npm**:[`@objectstack/runtime`](https://www.npmjs.com/package/@objectstack/runtime) +- **GitHub**:[github.com/objectstack-ai/objectstack/releases](https://github.com/objectstack-ai/objectstack/releases) +- **ソースの CHANGELOG**:[`CHANGELOG.md`](https://github.com/objectstack-ai/objectstack/blob/main/CHANGELOG.md) +- **詳しいリリースノート**:リリースごとに 1 ページで、アップグレードチェックリスト付き。[objectstack.ai/docs/releases](https://objectstack.ai/docs/releases) にあります。v17 系は [v17](https://objectstack.ai/docs/releases/v17) です。 + +通知を受け取るには、GitHub で [github.com/objectstack-ai/objectstack](https://github.com/objectstack-ai/objectstack) → Releases を watch してください。 + +## 最近の主な変更 [#recent-highlights] + +以下の 17.x のマイナーは、どれも稼働中のデプロイの動作を変えます。各アップグレードチェックリストのうちオペレーターが行う部分は、[アップグレードとロールバック → バージョン別の手順](/docs/operate/upgrade#version-specific-steps)にあります。 + +### 17.7 [#177] + +`@objectstack` **17.7.0**(2026-10-06 リリース)は、v17 系の現在のリリースです。資格情報を、それまで作られていたコピーから取り除き、見えない行を存在しない行と同じように応答させます。詳細なノート:[objectstack.ai/docs/releases/v17/17-7](https://objectstack.ai/docs/releases/v17/17-7)。 + +> **警告:** アップグレードの後、すべてのフローのシークレットと JWT 署名鍵をローテーションし、プライベートな共有リンクを発行し直してください。アップグレード前に作られたコピーは監査証跡に残ります。17.7 で設定したシークレットはそれより前のリリースでは読めないので、ロールバックの計画ではその点を考慮してください。[アップグレードとロールバック → 17.7](/docs/operate/upgrade#objectstack-177)を参照してください。 + +変わったこと: + +- **資格情報がコピーに乗って移動しなくなりました**(セキュリティ)。フローの受信 `secret` と `http` ノードの `signingSecret` は書き込み専用のストアに移り、監査証跡は資格情報のフィールドを記録しなくなり、資格情報のフィールドはすべての書き込みレスポンス、レコードイベント、Webhook の本文、フローのトリガーレコードでマスクされます。 +- **公開フォームは明示的なスイッチでのみ開きます**(破壊的)。フォームが匿名で提供されるのは、その `sharing` が `allowAnonymous` と `publicLink` に加えて `enabled: true` を設定している場合だけです。後の 2 つだけを設定したフォームは `404 FORM_NOT_FOUND` を返します。[ビュー](/docs/build/interface/views#public-forms)を参照してください。 +- **読めない行は存在しません**。呼び出し元が読めない行に対する ID 指定の更新や削除は `404 RECORD_NOT_FOUND` を返し、フィルター指定の更新や削除は読める行だけに作用します。 +- **読み書きは宣言されたフィールドだけを返します**。廃止されたフィールドの残りなど、どのメタデータも宣言していない列は返されなくなりました。変換のためには `os migrate unmapped-columns` がそれを読みます。[CLI](/docs/reference/cli#database-migrations--os-migrate)を参照してください。 +- **アプリのコードは、保存されたメタデータにメタデータ API 経由でのみアクセスします**。フック、アクション、ジョブのコードは `sys_metadata` を直接読み書きしなくなり、それに書き込むフローのノードは拒否されます。 +- **日付、時刻、数値は言語に従います**。4 つの書式設定は廃止され、そのいずれかを指定する設定の書き込みは `400` を返します。[ローカリゼーション](/docs/configure/localization)を参照してください。 +- **インメモリエンジンは起動時のストアではなくなりました**。また、外部のサインインが、メールアドレスが未検証のローカルアカウントに自動でリンクすることはなくなりました。 +- **Console(Studio)**:objectui のピンを 5 回更新しました。最初の更新で、17.6 の既知の Console の問題 4 件を修正しています。 + +### 17.6 [#176] + +`@objectstack` **17.6.0**(2026-10-02 リリース)は、どの入口でも同じ方法でアクセスを判定します。権限セットを持たない呼び出し元は何も得られず、フィールドレベルセキュリティはすべてのクエリに届きます。詳細なノート:[objectstack.ai/docs/releases/v17/17-6](https://objectstack.ai/docs/releases/v17/17-6)。 + +変わったこと: + +- **権限セットが 1 つも解決されない呼び出し元は、すべてのオブジェクトで拒否されます**(破壊的、セキュリティ)。以前は、どのセットも付与していないすべてのオブジェクトに入ることができました。アプリが宣言した匿名エンドポイント(`authRequired: false`)はオブジェクトを読み書きできなくなり、匿名の呼び出し元に権限セットを付与するサポート対象の経路はありません。公開フォームは引き続き動作します。 +- **フィールドレベルセキュリティがすべてのクエリの入口に届きます**。フィールド間の比較、アクティビティストリーム、監査証跡、承認のスナップショット、分析が対象です。監査証跡とアクティビティストリームは、管理者を含むシステム以外の閲覧者に、その閲覧者が読めるレコードについての行だけを表示します。17.7 の `view_all_audit_log` 機能(プラットフォーム管理者が既定で持つ)により、削除とサインアウトの証跡は管理者に戻ります。[監査ログ](/docs/operate/audit-logs)を参照してください。 +- **パッケージのフローがその名前を取ります**。パッケージのフローと同じ名前でデプロイに保存されたフローは実行されなくなり、オン/オフの切り替えはパッケージのフローだけを切り替えます。[フロー](/docs/build/automation/flows#visual-builder)を参照してください。 +- **保存されたメタデータの本文は、コピーされる場所ではどこでも秘匿化されます**。保存済みのコピーには `os migrate audit-metadata-bodies --apply` を実行してください。`/api/v1/meta` のデータソースのメタデータには `manage_platform_settings` が必要です。 +- **共有ルールとビューの「is empty」は `''` と `[]` にも一致します**。テキストと複数値のフィールドが対象です。 +- **日付はどの入口でも 1 つのルールに従います**。`datetime` は 1000 年から 9999 年までの年を表し、インポートは日付のセルを ISO 8601、エクスポート自身の形式、年が先の形式でのみ読みます。 +- **共有選択リスト**。新しい `picklist` メタデータ種別で、フィールドから名前で参照でき、他のパッケージが拡張できます。 + +### 17.5 [#175] + +`@objectstack` **17.5.0**(2026-09-29 リリース)は、いくつかの既定値を安全側に変えます。スケジュールされた処理はデプロイが求めるまでオフになり、行レベルセキュリティ、分析、レコードの書き込みは守れないものを拒否します。詳細なノート:[objectstack.ai/docs/releases/v17/17-5](https://objectstack.ai/docs/releases/v17/17-5)。 + +> **警告:** アップグレードして何もしないデプロイでは、スケジュールされたフローもパッケージの cron ジョブも実行されません。また walled のデプロイには、`OS_PLATFORM_OWNER_EMAIL` で指定するまでプラットフォーム管理者がいません。[アップグレードとロールバック → 17.5](/docs/operate/upgrade#objectstack-175)を参照してください。 + +変わったこと: + +- **スケジュールされた処理は、デプロイがオンにするまでオフです**(破壊的)。`OS_AUTOMATION_SCHEDULED_WORK_ENABLED` が、時刻でトリガーされるすべてのフローとパッケージの cron ジョブを制御します。[環境変数](/docs/reference/environment-variables#runtime-services)を参照してください。 +- **walled のデプロイは、プラットフォーム管理者の地位を `OS_PLATFORM_OWNER_EMAIL` からのみ取ります**(破壊的)。`admin_full_access` の付与ではもう与えられません。 +- **保存済みレポートの仕組みは削除されました**(破壊的)。`/api/v1/reports` とスケジュールされたレポート配信が対象で、後継はありません。`report` メタデータ種別、データセット、分析は変わりません。[REST API](/docs/reference/rest-api#reports)を参照してください。 +- **行レベルセキュリティは、適用できない述語では閉じる側に失敗します**。また `check` のないポリシーは、挿入と更新をその `using` に従わせるようになりました。 +- **分析は、オブジェクトを読める呼び出し元にだけ応答します**。それ以外は `/data` と同じく `403` で拒否されます。 +- **ディシジョンは最初に一致した分岐を取ります**。`mode: 'inclusive'` は真になるすべての分岐を実行します。Studio から保存されたディシジョンは、アップグレード時に新しい意味になります。[フロー](/docs/build/automation/flows#conditions-and-branches)を参照してください。 +- **書き込まれる値は宣言された型に従います**。`date` は `YYYY-MM-DD`、`datetime` は ISO 8601、数値は JSON での表記です。それ以外は `400 VALIDATION_FAILED` になります。 +- **入力規則はルックアップを 1 段たどって読めます**。また CEL に `current_user.can(object, verb)` が加わりました。[入力規則](/docs/build/data/validation-rules#reading-a-related-record)と [CEL](/docs/reference/cel#permission-checks)を参照してください。 +- **ページサイズを宣言していないビューは、25 行ではなく 50 行を表示します**。 + +### 17.4 [#174] + +`@objectstack` **17.4.0**(2026-09-09 リリース)は、すべての期間のキーを単位付きの名前に変え、目立たない書き込み経路を 2 つ塞ぎます。詳細なノート:[objectstack.ai/docs/releases/v17/17-4](https://objectstack.ai/docs/releases/v17/17-4)。 + +変わったこと: + +- **読み取り専用のフィールドは、更新だけでなくシステム以外による作成でも取り除かれます**。`droppedFields` で報告されます。初期値はシステムとして投入してください。[入力規則](/docs/build/data/validation-rules)を参照してください。 +- **すべての期間のキーは名前に単位を持ちます**(破壊的)。`timeout` は `timeoutMs` に、`refreshInterval` は `refreshIntervalSeconds` になる、などです。エイリアスはありません。古い表記はパース時にキーの名前を示して拒否されます。 +- **セッションの `positions` がセキュリティの軸です**。ポジションで絞り込まれた Console のゲートは、そのポジションを持つ人に対して応答するようになりました。 +- **フローは理由を付けて拒否できます**。`outcome: 'refused'` とレコードごとの `message` を持つ `end` ノードです。[フロー](/docs/build/automation/flows#ending-a-run-completed-or-refused)を参照してください。 +- **分析の日付範囲は閉じた語彙です**。宣言されたプリセットか `[start, end]` のペアで、それ以外は `400` になります。 +- **複数組織のランタイムはオープンソースです**。`@objectstack/organizations` は公開パッケージです。 + +### 17.3 [#173] + +`@objectstack` **17.3.0**(2026-09-04 リリース)は、v17 系で最大のリリースです。詳細なノート:[objectstack.ai/docs/releases/v17/17-3](https://objectstack.ai/docs/releases/v17/17-3)。 + +変わったこと: + +- **オープンなセルフ登録は宣言が必要です**(破壊的)。オーディエンスの態勢を宣言していないアプリは招待制で、保留中の招待がないサインアップは `403 SELF_REGISTRATION_CLOSED` で拒否されます(新規インストールの最初のアカウントは対象外です)。 +- **共有の付与はテナントのスコープを持ちます**。17.3 より前に書き込まれた `sys_record_share` の行には、オペレーターが実行するバックフィルが必要です。[アップグレードとロールバック → 17.3](/docs/operate/upgrade#objectstack-173)を参照してください。 +- **権限ストアの障害ははっきりと失敗します**(`503`)。機能を持たないユーザーとして解決されることはなくなりました。 +- **自動採番は組織ごとに一意です**。既存の重複は新しいインデックスを妨げるので、先に `os migrate duplicates` を実行してください。 +- **複合のメタデータアドレス指定は廃止されました**。`/api/v1/meta/:type/:section/:name` は `404 ROUTE_NOT_FOUND` を返します。[REST API](/docs/reference/rest-api#metadata--apiv1meta)を参照してください。 +- **フローのオン/オフの切り替えには `manage_metadata` が必要です。** +- **SDK**:`client.projects.*` は `client.environments.*` になりました。エイリアスはありません。 + +### 17.2 [#172] + +`@objectstack` **17.2.0**(2026-08-23 リリース)は、誰も評価しなかった条件を宣言した書き込みが、条件付きの書き込みとして扱われないようにします。詳細なノート:[objectstack.ai/docs/releases/v17/17-2](https://objectstack.ai/docs/releases/v17/17-2)。 + +変わったこと: + +- **ID 指定の書き込みが述語を落とさなくなりました**(破壊的)。`where` が `id` 以外も指定している ID 指定の更新や削除は、`multi: true` を宣言しない限り拒否されます。また `data.id` と `where.id` が一致しないものは `400 UPDATE_ID_MISMATCH` を返します。 +- **`http_request_errors_total` は廃止されました**。これをキーにしたパネルはゼロのままになります。`http_requests_total{status=~"5.."}` を使ってください。 +- **外部データソースのルートには機能の権限が必要です**。`manage_platform_settings` か `manage_metadata` です。 +- **`os g agent` は廃止されました**。代わりにスキルを作成してください。 + +### 17.1 [#171] + +`@objectstack` **17.1.0**(2026-08-20 リリース)は v17 系の最初のマイナーでした。17.0 が*作成できる範囲*をはっきりさせたのに対し、17.1 はランタイムの応答をはっきりさせます。アクセスを取り消すと約束したフラグは実際に取り消し、失敗した読み取りは空の結果として返されなくなり、ディスパッチされなかったフローは失敗した実行として報告されなくなり、読めるはずのなかった資格情報は返されなくなります。詳細なノート:[objectstack.ai/docs/releases/v17/17-1](https://objectstack.ai/docs/releases/v17/17-1)。 + +> **警告:** 17.1.0 は、影響範囲ではなくバージョン番号の上でのマイナーです。そのセキュリティ修正のいくつかは、既存のデプロイで誰が読み書きできるかを変えますが、気づくきっかけになる移行の手順はありません。更新する前に、詳細なノートにある 17.1.0 のアップグレードチェックリストを確認してください。 + +変わったこと: + +- **権限セットやポジションを無効化すると、実際にアクセスの付与が止まるようになりました**(セキュリティ)。どちらのオブジェクトにも、アクセスが止まると約束するダイアログ付きの Deactivate アクションがありますが、その列を読むものはありませんでした。`active: false` で投入したポジションは引き続き権限セットを付与し、`active: false` で投入した権限セットは引き続きプラットフォーム管理者の態勢を返していました。共有ルールはその境界を通らない別の経路でユーザーに届いていたため、無効化されたポジションとレコードを共有するルールは共有を続けていました。それらの共有は次の調整で取り消されます。`active` 列がないか NULL の行は影響を受けません。このスイッチを効果がないと思って使っていたデプロイでは、これは稼働中のデータに対する実際の取り消しになるので、先に無効化された行を監査してください。[権限セット](/docs/configure/permissions/permission-sets)を参照してください。 +- **出荷される管理者セットは、`*` ワイルドカードでのエクスポートを付与しなくなりました**(破壊的)。`admin_full_access`、`organization_admin`、そこから派生した `organization_admin_no_bypass` は `objects['*'].allowExport: true` を持っており、17.0 のエクスポートの軸を拒否できないものにしていました。アプリケーションがあるオブジェクトを誰もエクスポートできないと宣言しても、プラットフォームはエクスポートしていました。エクスポートは現在、アプリ自身の権限セットでオブジェクトごとに付与します。自動の代替は意図的に用意していません。読み取りは変わりません。これは一括での持ち出しだけを狭めるものです。 +- **部分的なフィールドのマスキング**。`FieldSchema` は `maskingRule` を宣言します。閉じたプリセットの列挙 `phone` / `id_card` / `bank_account` / `email` / `name` に加え、`{ keepHead, keepTail }` という逃げ道があります。ルールを宣言したフィールドは、システム以外のすべての呼び出し元に、マスクされているが判別できる形(`138****5678`)で返され、フィールドの `requiredPermissions` がマスク解除のゲートになります。マスキングは単一のランタイムの経路を通るので、API の呼び出し元、ブラウザのユーザー、CSV/XLSX のエクスポートルートはすべて同じ値を見ます。マスクされた呼び出し元は、そのフィールドでフィルター、並べ替え、グループ化、集計ができません。[フィールドレベルセキュリティ](/docs/configure/permissions/field-level-security)を参照してください。 +- **ObjectOS が公開していないオープンランタイムの機能が 2 つあります**。17.1 で、レコード閲覧の監査(`sys_audit_log` の `read` アクション)と、レコードを読める人がその承認リクエストを見られる読み取り専用の階層が追加されました。どちらもコンストラクターのオプション(`AuditPlugin` の `readAudit`、承認サービスの `recordReaderVisibleObjects`)でのみ有効になり、ObjectOS のランタイムはそれを設定しないので、ObjectOS のデプロイではどちらも使えません。 +- **フローの 3 つの入口すべてが、1 つの正直なステータス表で応答します**。拒否されたディスパッチは失敗した実行として報告されなくなりました。見つからない場合は `404`、`409` `FLOW_DISABLED`、`422` `FLOW_NO_START_NODE`、そして実際に実行されて拒否された場合は `400` `FLOW_FAILED` です。オートメーションの `trigger` ルート、アクションの入口、宣言された `type: 'flow'` のエンドポイントは、3 つの個別のコピーではなく 1 つの共有の定義を読むようになり、`outputMapping` は失敗には適用されなくなりました。呼び出し元は内側の `success` フラグではなく、HTTP ステータスで分岐してください。[フロー](/docs/build/automation/flows)を参照してください。 +- **`error.code` はどの入口でも閉じた語彙です**。プラットフォームの標準セット外のコードを投げても `error.code` には届かず、新しい任意の `declaredCode` に入ります。アプリケーション独自の表記は、プラットフォームの語彙を広げずに残ります。 +- **失敗した読み取りは空の読み取りとして扱われなくなりました**。メタデータプロトコル、積み上げ集計のインデックス、カスケード削除とレジストリの検査にわたって、繰り返し起きていた種類の問題を塞ぎました。以前は*失敗した*読み取りと、正当に何も見つからなかった読み取りを区別できず、upsert の事前読み込みはすべての更新を挿入に変え、「これを削除すると何が壊れるか」には「何も」と答えていました。`catch` は 1 つも削除していません。それぞれをエラーの種類で判別するので、プロビジョニングされていないテーブルは無害なまま、それ以外はすべて表面化します。 +- **作成時のゲートがランタイムの公開の入口に届きます**。`os build` / `os validate` だけが実行していたルールが、ランタイムの書き込みも判定するようになったので、CLI が拒否するものを Studio やメタデータ API が通すことはできません。アップグレード後に `os build` / `os validate` を再実行してください。いくつかの新しい拒否によって、17.0 で問題なくビルドできたスタックが失敗することがあります。未知のトップレベルのスタックキー、ターゲットが宣言されたページでないダッシュボードヘッダーの `modal` アクション、数式フィールドを指定したかフィールドを指定していないリストビューの `sort` などです。 +- **Console(Studio)**:objectui のピンを 2 回更新しました。ダッシュボードのコンポーネントのキーの付け直し、アクションの構造化された `confirm` オブジェクトの廃止、メトリクスウィジェットの `I18nLabel`、サブパスにマウントされた Console 向けにホストが行う `submitBehavior.url` のリダイレクトが入っています。 + +### 17.0 [#170] + +`@objectstack` **17.0.0**(2026-08-14 リリース)は、真実を語るリリースです。16.0 が*宣言されたメタデータ*を正直にしたように、17.0 はその周りの部分に同じことをします。詳細なノート:[objectstack.ai/docs/releases/v17/17-0](https://objectstack.ai/docs/releases/v17/17-0)。変わったこと: + +- **Node.js 22 が下限です**(破壊的)。公開されている 50 のマニフェストすべてで、`engines.node` が `>=18.0.0` から `>=22.0.0` になりました。CI、リリースパイプライン、出荷されるすべての Docker イメージはすでに 22 で動いていたので、約束が実態に合いました。Node 22 以上では何も変わりません。CI で Node のバージョンを固定している場合は、22 に固定してください。 +- **一括エクスポートは独立した特権です**(破壊的)。`allowExport` が未設定の場合、以前は「読み取りを継承する」という意味でしたが、現在は**拒否**を意味します。また `viewAllRecords` / `modifyAllRecords` もそれを与えなくなりました。パッケージが出荷するセットはアップグレード時に投入し直されるので、`admin_full_access` と `organization_admin` は引き続きエクスポートできますが、**環境で作成したセットはそうではありません**。ユーザーがエクスポートするカスタムセットには `allowExport: true` を追加してください。[権限セット](/docs/configure/permissions/permission-sets)を参照してください。 +- **ファイルは列の中の blob ではなく、レコードです**。メディアフィールド(`file`/`image`/`avatar`/`video`/`audio`)は不透明な `sys_file` の ID を格納し、`{ url, name, size, … }` オブジェクトは*読み取り*(展開)の形になります。プラットフォームがバイトを持つので、`accept` / `maxSize` はブラウザ側のヒントではなく、宣言できて**サーバーで強制される**ものになります。変換は `os migrate files-to-references` が行います。[フィールドの型](/docs/reference/field-types#media)を参照してください。 +- **GraphQL は削除されました**(破壊的)。最初からスキーマだけでした。サービスが割り当てられていなかったため、ハンドラーは常に 501 を返していました。現在 `/graphql` は 404 を返します。影響しないもの:**外部**データソースのプロトコルとしての `graphql`。これは ObjectOS が提供する API ではなく、他者の API です。 +- **条件のない共有ルールは何も共有せず、無効化された RLS ポリシーは無効です**(破壊的、セキュリティ)。条件なしで保存されたルールは、以前は*そのオブジェクトのすべてのレコード*として評価されていました。また `enabled: false` でオフにした RLS ポリシーは、OR 分岐の付与を加え続けていました。どちらも閉じる側に失敗するようになりました。[レコードアクセス](/docs/configure/permissions/record-access)を参照してください。 +- **承認リクエストは参加者に表示されます**(セキュリティ)。`getRequest` / `listRequests` / `countRequests` は表示ルールのうちテナントの半分しか適用していなかったため、認証済みのユーザーなら誰でも、自分のテナントのどのリクエストでも、ペイロードのスナップショット、判断の履歴、添付ファイルを読めました。 +- **承認者を動的にルーティングできます**。承認ノードに、`expression` 承認者(`current.*` / `trigger.*` / `vars.*` に対する CEL)、ノードレベルの `onEmptyApprovers` ポリシー、作成者が宣言する判断の出力(実行を `.` のフロー変数として再開する)が加わりました。[承認](/docs/build/automation/approvals)を参照してください。 +- **壊れたデータソースは起動時にはっきりと失敗します**。オブジェクトが結び付いたデータソースは接続できなければ起動が失敗し、`objectql.init()` は応答しないデータドライバーでは起動を拒否し、ドライバーが応答しなくなると `/api/v1/ready` は 503 を返します。以前は、そのような起動は問題なく始まり、ゼロで終了し、その後で結び付いたオブジェクトのすべての読み書きが失敗していました。 +- **`enable.apiMethods` は 6 つの基本操作に縮小されました**(破壊的)。作成できる列挙は `get`、`list`、`create`、`update`、`delete`、`bulk` だけです。8 つの従来の値は*導出される*実効操作です。保存されたものは、置き換え先を示す警告とともにパース時に取り除かれます。 +- **使われていないメタデータの掃除は続きます**(破壊的)。`object.enable.trash` と `enable.mru`、`tool.requiresConfirmation`、`agent.tools[]`、`agent.knowledge`、`SkillSchema.permissions`、レポートの `aria` / `performance`、`flow.active`、そしてパースはされるが無視されていた多数のキーが削除されました。どれも黙って取り除かれるのではなく、アップグレードの処方を示してパース時に拒否されます。ソースを書き換えるには `os migrate meta --from 16` を実行してください。 +- **作成できる範囲は閉じています**。作成できるすべてのメタデータ型は、`create()` だけでなくパースの経路でも、未知のキーを名前付きの処方とともに拒否するようになりました。タイプミスは、黙って効かない設定ではなく、位置の分かるエラーになります。 + +### 16.0 [#160] + +`@objectstack` **16.0.0** は開発者向けの範囲を収束させ、宣言されたメタデータを正直にします。呼び出し元の組織を表す公認の名前を 1 つにし、本物の複数承認者のガバナンス、実際に発火する時刻相対のオートメーション、そして黙って無視されていたメタデータを作成時のはっきりしたエラーに変えるプラットフォーム全体の掃除を入れました。詳細なノート:[objectstack.ai/docs/releases](https://objectstack.ai/docs/releases)。変わったこと: + +- **フック/アクションの `ctx` から `tenantId` エイリアスを削除**(16.0、破壊的)。すべての `*.hook.ts` / `*.action.ts` の本体で、呼び出し元の組織は `ctx.user.organizationId` / `ctx.session.organizationId` として読んでください(値は変わりません。システムの書き込みでは `ctx.user` は `undefined` です)。ドライバー層のテナンシーの軸(`ExecutionContext.tenantId`)は別の概念で、変わりません。 +- **承認:定足数、グループごとの承認(会签)、メタデータ駆動の受信箱**。承認ステップは M-of-N の定足数(`minApprovals`)と、各グループから 1 人の承認者を求めるステップをサポートします。開始時のスナップショットに対して集計し、不在時の代理を適用します。1 件の却下は引き続き拒否権を持ち、しきい値は範囲内に収められるので、設定ミスで行き詰まることはありません。判断には添付ファイルを付けられ、進捗(「2 of 3 · finance pending」)はサーバー側で計算されます。承認 / 却下 / 再割り当て / 差し戻し / 情報要求 / 催促 / 取り下げ / 再提出は、`sys_approval_request` の `type:'api'` アクションとして宣言されています。承認の受信箱は、手書きのボタンではなく汎用のアクションランタイムでそれらを表示します。 +- **時刻相対のオートメーション**。フローの開始ノードは `timeRelative`(`offsetDays: [60, 30, 7]` か `withinDays`)を宣言できます。毎日のスイープが一致するレコードごとにフローを 1 回起動するので、「契約終了の 60 日前に知らせる」がようやくそのまま動きます。たまたま編集したときにしか発火しない日付の等値条件は、もう必要ありません。 +- **フィルター付きの積み上げ集計**。`summaryOperations.filter` により、親の合計は一致する子の行だけを集計し、子が述語の範囲に出入りすると再集計します。 +- **厳密なダッシュボードウィジェット**(16.0、破壊的)。`DashboardWidgetSchema` は `.strict()` です。宣言されていないキー(タイプミスや、削除されたインライン分析のキー)は、黙って何も表示しないのではなく、キーの名前を示してデータセットの形(`dataset` + `dimensions` + `values`)を指すパースエラーになります。 +- **MCP:stdio に ID、エージェントにリンター**。stdio の自動起動は独自の `OS_MCP_STDIO_ENABLED` スイッチ(既定はオフ)に移り、`OS_MCP_STDIO_API_KEY=osk_...` のプリンシパルが必要です。閉じる側に失敗し、HTTP と同じ認可のチェーンで解決されます(RLS/FLS/テナントを適用し、`system` のバイパスはありません)。新しい `validate_expression` ツールで、エージェントは数式を保存する前に実際のオブジェクトのスキーマに対して検査できます。 +- **強制するか削除するかの掃除**(16.0、破壊的)。宣言されているが強制されていなかったメタデータは、はっきりとエラーになりました。使われていないフィールド/オブジェクト/エージェントのプロパティは、案内付きで削除または廃止扱いになり、フックのイベントは 18 から 8 に統合され、入力規則から評価されることのなかった `'delete'` イベントが外れ、Webhook の `undelete` / `api` トリガーは削除され、未知の `requires` 機能トークンは作成時に拒否されます(`aiStudio` / `aiSeat` のエイリアスはなくなりました。ケバブケースの `ai-studio` / `ai-seat` を使ってください)。 +- **エンジンが所有するシステムの行は、汎用データ API からは読み取り専用です**(ADR-0103)。ジョブ、通知、承認ランタイムの行、共有の行、監査証跡、シークレットなどは `get`/`list` に限定され、閉じる側に失敗するガードが `/data` を通じたユーザーコンテキストの書き込みを拒否します。正当にユーザーの書き込みを受け付けるサードパーティの `system` オブジェクトは、`userActions` を宣言する必要があります。 +- **日付のロジックが嘘をつかなくなりました**。`record.due_date == today()` が一致するようになりました(日時の等値比較は、フィールドのオペランドを変換するように書き換えられます)。一方、数式での日付の*算術*(`end - start + 1`、`today() + 30`)は、`daysBetween` / `daysFromNow` / `addDays` / `addMonths` を示すビルド時のエラーになります。それらの式はいずれにせよ、ランタイムでは常に `null` になって失敗していました。 +- **ユーザーの一括インポートは既定で `passwordPolicy: 'auto'` になりました**。届けられる経路(実在のメールアドレスと設定済みのメールサービス、または電話番号と SMS の招待経路)がある行は招待され、届けられない行だけが 1 回限りの一時パスワード(`must_change_password`)を受け取ります。従来の ID のみの動作にするには、明示的に `passwordPolicy: 'none'` を渡してください。行ごとの結果は `rows[].delivery` にあります。 + +### 14.x [#14x] + +ObjectOS One とバンドルされたサーバーは `@objectstack` **14.7.0** で出荷されました。ランタイムの起動の契約は変わりません(`createStandaloneStack` は同じ成果物、環境、データベースの設定を受け取ります)が、13.0 と 14.0 はどちらも認可の語彙に破壊的な変更を入れているので、**12.x 以前から更新する場合は、先に権限のメタデータを見直してください**。詳細なノート:[objectstack.ai/docs/releases](https://objectstack.ai/docs/releases)。14.x で変わったこと: + +- **ADR-0090 の語彙の収束が完了**(14.0、破壊的)。`book.audience` は `{ permissionSet }` で制御します(以前は `{ profile }`)。`PortalSchema.profiles` → `positions`、`RLSUserContextSchema.role` → `positions`(文字列の配列)、`sys_record_share.recipient_type: 'role'` → `'position'`。 +- **オブジェクトの機能フラグが強制されます**(14.0、ほぼ破壊的)。`enable.*` フラグは、パースされるだけで使われないものから実際のゲートになりました。`activities` と `feeds` はオプトアウトです(既定は `true`。`feeds: false` はコメントを 403 `FEEDS_DISABLED` で拒否します)。`trackHistory` は履歴タブを動かし、`files` はオプトインです(`enable: { files: true }` までは 403 `FILES_DISABLED`)。 +- **メンバーの基本権限から削除が外れました**(14.2、破壊的)。`member_default` はレコードの削除を付与しなくなりました。ポジションで配布する権限セットを通じて、オブジェクトごとに付与し直してください。 +- **管理者によるユーザー管理と電話認証**(14.3)。ユーザーの直接作成(`POST /api/v1/auth/admin/create-user`、強制ローテーション付きの 1 回限りのパスワード)、一括インポート(行/CSV/XLSX、ドライラン、upsert)、`@objectstack/plugin-sms`(Aliyun / Twilio)による SMS OTP でのオプトインの電話サインイン、`sms` 通知チャネルが入りました。 +- **データのライフサイクルの契約**(14.4、ADR-0057)。オブジェクトは `lifecycle`(クラス、保持期間、ローテーション、アーカイブ)を宣言します。既定で有効な LifecycleService がプラットフォームのデータを削除、ローテーション、アーカイブします(`sys_activity` は 14 日、`sys_audit_log` はホットで 90 日)。`OS_LIFECYCLE_DISABLED=1` で無効にし、`lifecycle.retention_overrides` で調整します。14.5 では、プラグインごとの `retentionDays` / `retentionSweepMs` オプション(`JobRunRetention`、`NotificationRetention`)をライフサイクルの宣言に置き換えて削除し、ライフサイクルのクラスを持つシステムのデータを専用のテレメトリーデータソース(`OS_TELEMETRY_DB`)に分けました。`os db clean` は SQLite の領域を回収します。 +- **有効期間付きの付与と委任**(14.4、ADR-0091)。ポジションと権限セットの割り当ては `valid_from` / `valid_until` の期間をサポートします(閉じる側に失敗し、バックグラウンドジョブはありません)。また `delegatable` のポジションでは、保持者が期間を区切って自分で委任できます(30 日以内、理由が必須、管理者のスコープは不可)。 +- **MCP のスコープの上限**(14.5、ADR-0090 D10)。OAuth で接続したエージェントは `effective_permission = scope_ceiling ∩ user_grants`(`data:read` / `data:write` / `actions:execute`)のもとで動き、閉じる側に失敗します。 +- **セキュリティ修正**(14.4〜14.5)。FLS のキーはオブジェクトで修飾する必要があります(修飾のないキーは黙って何にも一致していませんでした。現在は自動修正付きのリントで拒否されます)。設定と共有リンクのルートは、なりすまし可能な `x-user-id` のようなヘッダーを信頼しなくなりました。分析のクエリは呼び出し元の読み取りフィルターのスコープに限定されます。 + +### 13.x:権限モデル v2 [#13x--permission-model-v2] + +`@objectstack` **13.0** は認可を再構成しました(ADR-0090)。破壊的な変更: + +- **ロールとプロファイルはポジションに収束**。`sys_role*` テーブル、`RoleSchema` / `defineRole`、メタデータ種別 `role` / `profile`、`ExecutionContext.roles[]` はなくなりました。ポジションはフラットで、階層は事業単位のツリーに移りました。共有の受け手は名前が変わりました(`role` → `position`、`role_and_subordinates` → `unit_and_subordinates`)。 +- **カスタムオブジェクトの既定は非公開**。所有者を持つオブジェクトで `sharingModel` を明示していないものは非公開になりました。`read` / `read_write` / `full` の OWD エイリアスは削除されました。以前の動作に戻すには `sharingModel: 'public_read_write'` を宣言してください。 +- **RBAC のリンクテーブルへの書き込みを制限**。`sys_user_position`、`sys_position_permission_set`、`sys_user_permission_set`、`sys_permission_set` への書き込みには、テナント管理者か委任管理者のスコープが必要です。 + +新機能:`everyone` / `guest` のオーディエンスのアンカー、委任管理(`PermissionSet.adminScope`)、層ごとの帰属を示す `explain()` エンジン、`os compile` のアクセスマトリクスのスナップショットゲート、MCP クライアント向けのセルフサービスの OAuth 2.1、作成時のセキュリティリント(`validateSecurityPosture`)、操作ごとの `Object.requiredPermissions` のマップ、パッケージの名前空間プレフィックスの強制。一度も強制されなかったスキーマ(コンプライアンス / マスキング / グローバル RLS の設定)はそのまま削除されました。 + +### 12.x [#12x] + +`@objectstack` **12.0** は API の既定の態勢を強化しました。 + +- **匿名のデータアクセスは既定で拒否**(破壊的)。`api.requireAuth` の既定は `true` になり、匿名の `/data/*` リクエストは 401 になります。公開データのデプロイは `api: { requireAuth: false }` で明示的にオプトアウトする必要があります(起動時に警告が出ます)。共有リンク、公開フォーム、`/auth`、`/health` は影響を受けません。 +- **プロトコルハンドシェイクの強制**。`PROTOCOL_VERSION` と `checkProtocolCompat()` が、互換性のないパッケージをインストール時に拒否します。 +- **適応的なレコード表示**。レコードはフィールドの複雑さから、ページかモーダル/ドロワーかの表示を導きます。`FormField.span` はレスポンシブになり(`'auto'` / `'full'`)、関連リストに `'primary'` タブへの昇格が加わりました。 +- **パッケージが出荷する権限**。パッケージは既定の権限セットを宣言でき、それは出所の追跡付きで起動時に実体化されます。 +- **ビルド時のリント**。`lint-view-refs`、`validateListViewMode`、`validateFormLayout`、破壊的な操作の RBAC マッピングが、コンパイルを制御します。 + +### 10.x [#10x] + +10.x 系は `@objectstack` **10.0 〜 10.2** で出荷されました。破壊的な変更はすべて複数組織のテナンシー層に入ったので、単一テナントの ObjectOS のデプロイは、設定を変えずに 9.x から更新できました。変わったこと: + +- **行レベルの組織のスコープ設定を独自のプラグインに分離**(10.0、破壊的)。`organization_id` の自動付与、組織ごとのシードの再生、既定の組織のブートストラップは、`@objectstack/plugin-security` からオプトインの [`@objectstack/plugin-org-scoping`](https://www.npmjs.com/package/@objectstack/plugin-org-scoping) に移りました。単一組織のデプロイは軽くなり(すべてのクエリで取り除くワイルドカードの RLS がありません)、`OS_MULTI_TENANT=true` は引き続き `plugin-security` より前にこのプラグインを自動登録するので、CLI で動かすプロジェクトはコードの変更が不要です。ADR-0002 では、*テナント*は物理的な分離(1 つの Environment = 1 つのデータベース)であり、`organization_id` は 1 つのデータベース内での*論理的な*スコープ設定なので、独自のプラグインに値します。 +- **個人のワークスペースの自動作成を廃止**(10.0、破壊的)。`plugin-security` は、新しいユーザーごとに「`'s Workspace`」組織を作成しなくなりました。ユーザーは招待を受け入れるか、最初の組織を明示的に作成します(Slack / Linear / GitHub Orgs のモデル)。最初に登録したユーザー(プラットフォーム管理者に自動昇格)は、セッションが RLS を解決できるように、マルチテナントのモードでは引き続き `Default Organization` を 1 つ受け取ります。単一テナントのデプロイは組織を作成しません。 +- **`record` フォームフィールド型**(ADR-0014)。`Record` のプロパティ(オブジェクトの `fields` マップなど)は、生の JSON として漏れ出るのではなく、Studio で第一級のフォームフィールドとして編集できるようになりました。またオブジェクトのプレビューペインは実際の `ObjectGrid` レンダラーをマウントします。プレビューしたものがそのまま出荷されます。 +- **`IEmbedder` による差し替え可能な埋め込み**。新しい埋め込みのプロトコルと [`@objectstack/embedder-openai`](https://www.npmjs.com/package/@objectstack/embedder-openai) が加わりました。ナレッジ / RAG のアダプターは `IEmbedder` を使うようになり、名前から `plugin-` プレフィックスが外れました。 +- **公開フォーム**。`/f/:slug` で提供される匿名の Web-to-Lead / Web-to-Case フォーム、統合された FormPage(公開の `/f/:slug` と内部の `/forms/:name`)、`type: 'form'` アクションのバリアント、`ObjectSchema` の `defaultDetailForm` が入りました。 +- **クラウドの ID の分離**。`os cloud login` は `os login` と別になり、クラウドのコントロールプレーンは非公開のリポジトリに移り(OSS のランタイムが軽くなりました)、`objectstack init` は再びビルドと起動ができるプロジェクトをスキャフォールドします。 + +### 9.x [#9x] + +9.x 系は、10.0 への切り替えの前に `@objectstack` **9.0 〜 9.11** で動いていました。ランタイムの起動の契約は 8.0 から変わりません(`createStandaloneStack` は引き続き同じ成果物、環境、データベースの設定を受け取ります)。そのため 8.0 のデプロイは設定を変えずに更新できます。変わったのは作成者向けの範囲です。 + +- **分析のデータセットが唯一の作成の場**(9.0、破壊的)。ダッシュボードのウィジェット、レポート、リストのチャートは、セマンティックな `dataset`(`defineDataset(...)`)に結び付き、ディメンションとメジャーを**名前で**選びます。古いインラインのクエリフィールド(ウィジェットの `object`/`valueField`/`aggregate`、レポートの `objectName`/`columns`/`groupingsDown`、リストのチャートの `xAxisField`/`yAxisFields`)は削除されました。移行:インラインのクエリを `defineDataset` に移し、名前で参照してください。`ChartTypeSchema` からも、基本の型としてしか描画されなかった 8 つのバリアント型が外れました(`stacked-bar`→`bar`、`spline`→`line`、`bubble`→`scatter`、…)。 +- **ビルド時の検証の厳格化**(9.6〜9.7)。`os compile` は、修飾のないフィールド参照(`record.amount` ではなく `amount`)、未知の CEL 関数、誤ったフロー値の埋め込み構文で**失敗する**ようになり、それぞれに「もしかして」のヒントが付きます。以前は「ビルドできたが黙って間違っていた」スタックが、はっきりと失敗するようになります。アップグレード後に `os compile` を再実行し、指摘されたものを修正してください。 +- **数値フィールドの数式が混在した算術を計算します**(9.7)。`record.amount / 100` と `record.price * 2` は、黙って `null` になるのではなく評価されるようになりました。`/ 100.0` という浮動小数点リテラルの回避策は不要になりました。 +- **オブジェクトレベルの REST の制御が強制されます**(ADR-0049)。オブジェクトの `apiEnabled: false` は REST からそのオブジェクトを外し、`apiMethods` のホワイトリストは到達できる操作を制限します。以前はパースされるだけで強制されていませんでした。 +- **メタデータとしてのパッケージのドキュメントと `book` ナビゲーション**(9.3〜9.6)。`src/docs/*.md` は `doc` メタデータとして登録されます。`book` 要素(ADR-0046)は、所属を導出するナビゲーションの背骨を宣言し、オーディエンスによる制御付きで `GET /api/v1/meta/book/:name/tree` から提供されます。 +- **`os package install`**(9.3)。カタログ ID かインラインのエアギャップ用成果物から、稼働中のランタイムにパッケージをインストールします。認証には `--email` / `--password` を使います。 +- **承認**(9.3)。修正のための差し戻し(`maxRevisions`、既定は 3)、ジョブを使った SLA の自動エスカレーション、リストの検索/ページネーション、セッション不要の 2 か国語の承認/却下の確認リンクが入りました。 +- **受信 Webhook のフロートリガー**(9.3)。`type: 'api'` のフローは、HMAC で検証される `POST /api/v1/automation/hooks/:flowName/:hookId` エンドポイントをマウントし、べき等でキューを使った取り込みを行います。 +- **通知の保持が既定で有効**(9.5)。通知の履歴は **90 日**で自動的に削除されます。履歴をずっと残すには、メッセージングの `retentionDays: 0` を設定してください。 +- **CLI に AI プロバイダーの SDK を同梱**(9.0)。OpenAI 互換のプロバイダー(DeepSeek、DashScope、SiliconFlow、OpenRouter、Cloudflare)が、グローバルにインストールした CLI でそのまま動きます。 + +フローの作成に関する動作の変更が 1 つあります。`create_record` ノードの `outputVariable` は**作成されたレコードのオブジェクト**を持つようになりました(以前は ID だけでした)。ID を期待していた `{var}` の参照は `{var.id}` に更新してください。 + +### 8.0.x [#80x] + +ObjectOS One とバンドルされたサーバーは `@objectstack` **8.0.1** で出荷されました。 + +- **Streamable HTTP での MCP**。すべてのデプロイが、ネットワークから到達できる [Model Context Protocol](https://modelcontextprotocol.io) サーバーとして動けます。`OS_MCP_SERVER_ENABLED=true` でオプトインし、エンドポイントは閉じる側に失敗する認証付きで `/api/v1/mcp` に提供されます(匿名のリクエストは拒否されます)。プラグインの名前は `@objectstack/plugin-mcp-server` → `@objectstack/mcp` に変わりました。 +- **セルフサービスの API キー**。`POST /api/v1/keys` は 1 回だけ表示される `sys_api_key` を発行します。REST のデータとメタデータの API(`/api/v1/data`、`/api/v1/meta`)は、MCP と同じ検証器で API キーを認証するようになり、キーの所有者の権限とレコードレベルセキュリティのもとで動きます。 +- **フィールドレベルの条件付きルール**。`visibleWhen`、`readonlyWhen`、`requiredWhen` は、フォームの UI だけでなく ObjectQL によってサーバー側で強制されます。 +- **再利用できる RLS の読み取りフィルター**。`security.getReadFilter(object, context)` はレコードアクセスの読み取りスコープを公開します。分析のデータセット、ダッシュボード、レポートはそれにつながり、スコープを適用できないときは閉じる側に失敗します。 +- **スタンドアロンのホストスタック**。ランタイムは単一テナントの `createStandaloneStack` ホストを出荷します。7.x の、クラウドに接続しホスト名でルーティングする `createObjectOSStack` のラッパーは削除されました。別に公開されたアプリを動かすデプロイは、それ以降その成果物を **URL** で指定します。現在それを行う変数と、それを行わない廃止された表記については、[環境変数](/docs/reference/environment-variables#retired-names)を参照してください。 + +### 5.0:`project` → `environment` の名前変更(出荷済み) [#50--project--environment-rename-shipped] + +以前 *Project* と呼ばれていたランタイムの概念は、全体を通して *Environment* に名前が変わりました。影響を受けるもの: + +- CLI のフラグ:`--environment` / `-e` +- HTTP のパス:`/api/v1/environments/:environmentId/...` +- ヘッダー:`X-Environment-Id` +- 環境変数:`OS_ENVIRONMENT_ID`(`OS_PROJECT_ID` は当時、非推奨のエイリアスとして残されていましたが、現在は読まれません) +- データベースの列:`environment_id` +- JSON スキーマ:`EnvironmentArtifact` + +## アップグレード [#upgrading] + +機械的な手順は[アップグレードとロールバック](/docs/operate/upgrade)を、通過するすべてのリリースについてはその[バージョン別の手順](/docs/operate/upgrade#version-specific-steps)を参照してください。事前の確認: + +1. 現在のバージョンから目標のバージョンまでの、すべてのマイナーの CHANGELOG のエントリーを読みます。 +2. `os diff ` を実行して、スキーマの破壊的な変更を洗い出します。 +3. 目標のバージョンに対して `os doctor` を実行します。 +4. フリート全体を更新する前に、カナリアのインスタンスを 1 つ立ち上げます。 +5. イメージのタグと成果物のバージョンの両方について、ロールバックの計画を用意します(この 2 つは別々に更新されます)。 + +## リグレッションの報告 [#reporting-regressions] + +パッチやマイナーで、以前は動いていたものが壊れた場合は、更新前と更新後のバージョンを添えて [github.com/objectstack-ai/objectstack/issues](https://github.com/objectstack-ai/objectstack/issues) にバグを登録してください。リグレッションは最優先の種類のバグとして扱います。 diff --git a/content/docs/resources/faq.ja.mdx b/content/docs/resources/faq.ja.mdx new file mode 100644 index 00000000..53131d11 --- /dev/null +++ b/content/docs/resources/faq.ja.mdx @@ -0,0 +1,178 @@ +--- +title: よくある質問 +seoTitle: "よくある質問:セットアップ、マルチテナンシー、料金、ライセンス" +description: ObjectOS についてのよくある質問。はじめ方、データベースとマルチテナンシー、マイグレーション、権限、連携、運用、料金とライセンス。 +editions: [community, cloud, enterprise] +translation: + source_sha: a04083fa1854e4094b8d7487ba533efd4b0fdc6a14425451ab84b21f739465d7 + guide_rev: 1 + mode: auto +--- + +## はじめに [#getting-started] + +### ObjectOS をいちばん早く試す方法は? [#whats-the-absolute-fastest-way-to-try-objectos] + +[ObjectOS Cloud](https://www.objectos.ai) にサインインしてください。ブラウザで動くホスト型で、何もインストールする必要はありません。オープンソースの ObjectStack ランタイムを自分のマシンで動かす場合は、`npm i -g @objectstack/cli && os start` を実行して http://localhost:3000 を開きます。[ObjectOS Community をローカルで実行する](/docs/start/community)を参照してください。 + +### Docker は必要ですか? [#do-i-need-docker] + +いいえ。ObjectOS Cloud は何もインストールする必要がありません。オープンなランタイムには Node 22 以上と CLI があれば十分です。セルフマネージドの本番デプロイでは Docker を推奨します。 + +### データベースは必要ですか? [#do-i-need-a-database] + +始めるだけなら不要です。ObjectOS Cloud はマネージドで、オープンなランタイムは既定でローカルの SQLite を使います。セルフマネージドのデプロイは、本番に移行するときに Postgres / MySQL / Turso / Mongo に切り替えます。 + +### アカウントやクラウドサービスは必要ですか? [#do-i-need-an-account--cloud-service] + +ObjectOS Cloud *が*アカウントそのものです。サインインして構築を始めてください。ObjectOS Enterprise はセルフマネージドで、動作にクラウドサービスは不要です。コントロールプレーンへの接続は任意です。オープンソースの ObjectStack ランタイムにはアカウント自体が不要です。 + +## オントロジー [#the-ontology] + +### ObjectOS のいうオントロジーとは何ですか? [#what-does-objectos-mean-by-ontology] + +アプリの定義です。オブジェクトとフィールド、リレーション、アクション、権限、フロー、エージェントとツールの定義を、型付きでバージョン管理されたひとまとまりの ObjectStack メタデータとして持ち、ランタイムがそれを実行します。ビュー、ダッシュボード、アプリ、翻訳はその投影であり、オントロジーの一部ではありません。これは検証してから実行する実行可能なものであり、継承、公理、推論器を備えた知識オントロジーではありません。[ObjectOS におけるあなたのオントロジー](/docs/ontology)を参照してください。 + +### ObjectOS はセマンティックレイヤーですか? [#is-objectos-a-semantic-layer] + +いいえ。セマンティックレイヤーは既存のシステムをマッピングして問い合わせられるようにするもので、ビジネスを記述しますが実行はしません。ObjectOS はあなたのオントロジーを実行します。データベース、REST API、UI、エージェントのツールはオントロジーから導出されます。すでに運用しているデータベースを外部データソースとして接続することもできます(既定で読み取り専用で、まだ初期段階です)。その場合、記録システムは元の場所に残ります。[既存システムの拡張](/docs/build/extend-existing-systems)と、比較表は [How ObjectStack compares](https://objectstack.ai/docs/concepts/compare) を参照してください。 + +## アーキテクチャ [#architecture] + +### Postgres / MySQL / MongoDB は使えますか? [#can-i-use-postgres--mysql--mongodb] + +はい。Postgres、MySQL、SQLite、Turso/libSQL、MongoDB のドライバーをサポートしています。[ランタイムの設定](/docs/configure/runtime)を参照してください。 + +### UI や Account ポータルを無効にして REST API だけを使えますか? [#can-i-disable-the-ui--account-portals-and-use-only-the-rest-api] + +はい。`os start --no-ui` を実行するか、対応するフラグを設定します。UI をマウントしてもしなくても、REST API は同じです。 + +### 生成された UI の代わりに独自のフロントエンドを使えますか? [#can-i-use-my-own-front-end-instead-of-the-generated-ui] + +はい。生成された UI は、独自のコードから呼び出すのと同じ `/api/v1/*` エンドポイントを使っています。`@objectstack/client` SDK か任意の HTTP クライアントを使ってください。 + +### ObjectOS は GraphQL をサポートしていますか? [#does-objectos-support-graphql] + +いいえ。API は REST です。GraphQL エンドポイントは ObjectStack 17.0 で削除されました。そのルートの裏側は一度も実装されておらず、現在 `/graphql` は 404 を返します。同じことは、生成された REST API と [ObjectQL](/docs/reference/objectql) クエリ言語(`?filter=` / `?sort=` / `?expand=` 経由)でできます。GraphQL を話すサードパーティのシステムには影響ありません。`graphql` は*外部*データソースのプロトコルとして引き続き有効です。外部データソースは他者の API のクライアントであり、ObjectOS が提供する API ではありません。 + +### マルチテナンシーはどう扱われますか? [#how-is-multi-tenancy-handled] + +1 つのデプロイが 1 つのアプリを 1 つのデータベースに対して提供します。[アーキテクチャ](/docs/architecture)を参照してください。複数の組織が 1 つのデプロイを共有できます。**walled** のテナンシー態勢(`OS_TENANCY_POSTURE`)が組織ごとの分離の壁を設けます。これはライセンスが必要な機能で、ライセンスがなければランタイムは起動を拒否します。壁が分離するのは組織のデータとメンバーシップであり、メタデータではありません。スキーマのスコープは組織ではなくデプロイです。そのため walled のデプロイでは、どの AI エージェントをマウントするかも宣言する必要があります。壁より強い分離はデプロイの分離です。専用のデータベースが必要な顧客には専用のデプロイを用意します。[複数組織のデプロイ](/docs/reference/environment-variables#multi-organization-deployments)を参照してください。 + +### ObjectOS はサーバーレスや Lambda の環境で動きますか? [#can-objectos-run-in-a-serverless--lambda-environment] + +ランタイムは長時間動き続ける Node プロセスで、ステートレスな関数ではなくコンテナや VM 向けに設計されています。カーネルは起動時に構築され、プロセスはその後で初めて ready を報告します。このプロセス内のウォームな状態と Better Auth のセッションモデルは、呼び出しごとに起動する関数では保持できません。 + +### 水平スケールできますか? [#does-it-scale-horizontally] + +はい。ロードバランサーの背後で複数のインスタンスを動かしてください。セッションはメモリではなくデータベースにあるので、どのインスタンスでもどのリクエストにも応答できます。レート制限やキューの機能を有効にする場合は、共有のために Redis を使ってください。 + +## データとマイグレーション [#data--migrations] + +### スキーマのマイグレーションはどう扱われますか? [#how-are-schema-migrations-handled] + +ドライバーが起動時に、データベースのスキーマを宣言したオブジェクトに同期します。Postgres では `CREATE TABLE` / `ALTER TABLE` 文になります。規制のある環境でマイグレーションを管理したい場合は、`OS_SKIP_SCHEMA_SYNC=1` を設定して DDL を自分で管理してください。 + +### フィールド名を変更するとデータはどうなりますか? [#what-happens-to-data-when-i-rename-a-field] + +名前の変更はデータ層では破壊的な変更です(「古い列を削除し、新しい列を追加する」ように見えます)。`os diff` でこれを検出し、マイグレーションの手順を追加してください(新しい成果物をデプロイする前に、データベースで列名を変更します)。 + +### CSV / Excel / Salesforce からデータをインポートできますか? [#can-i-import-data-from-csv--excel--salesforce] + +CSV はできます。`os data create` をループで実行するか、UI の一括アップロードを使ってください。Salesforce は、現時点では CSV にエクスポートしてインポートするのが最善です。ネイティブのコネクターはロードマップにあります。 + +### ObjectOS をアップグレードするとデータは失われますか? [#will-upgrading-objectos-lose-my-data] + +いいえ。パッチとマイナーのアップグレードは非破壊的です。メジャーのアップグレード(例:4 → 5)では、必要なマイグレーションを明記しています。先にバックアップを取ってください。[バックアップと DR](/docs/operate/backup)を参照してください。 + +## 権限とマルチテナンシー [#permissions--multi-tenancy] + +### 行レベルセキュリティはどう実現しますか? [#how-do-i-do-row-level-security] + +オブジェクトの `recordAccess` 設定に、共有ルール(Salesforce のような宣言型)か CEL の述語を宣言します。セキュリティプラグインが、対応するフィルターをすべてのクエリに注入します。[権限](/docs/configure/permissions)を参照してください。 + +### 特定のユーザーから一部のフィールドを見えなくできますか? [#can-i-make-some-fields-invisible-to-certain-users] + +はい。権限セットのフィールドレベルセキュリティです。権限セットごと、フィールドごとに、非表示または読み取り専用にできます。REST、ObjectQL、UI で一様に適用されます。[権限セット](/docs/configure/permissions/permission-sets)を参照してください。 + +### Okta / Entra / Keycloak と連携するには? [#how-do-i-integrate-okta--entra--keycloak] + +OIDC を使います。**Setup → Authentication**(または環境変数)でディスカバリー URL とクライアント ID / シークレットを設定します。プロバイダーのコールバック URL は `/api/v1/auth/oauth2/callback/` です。[認証](/docs/configure/authentication)を参照してください。 + +## 連携 [#integrations] + +### Webhook を送信できますか? [#can-i-send-webhooks] + +はい。`requires` で `webhooks` を有効にしてください。ObjectOS は HMAC-SHA256 署名付きの永続的なアウトボックスを使います。[Webhook](/docs/configure/webhooks)を参照してください。 + +### Zapier / Make / n8n と連携できますか? [#can-i-integrate-with-zapier--make--n8n] + +はい。送信には Webhook、受信には REST API と API キーを使います。よく使われる iPaaS ツール向けのネイティブコネクターはロードマップにあります。 + +### AI エージェントから ObjectOS を呼び出せますか? [#can-ai-agents-call-my-objectos] + +はい。すべての ObjectOS デプロイは `/api/v1/mcp` で MCP サーバーになっており、既定で有効です。すべてのオブジェクトがツールであり、作成者が AI に公開したアクション(`ai.exposed`)もツールです。Claude Code、Claude Desktop、IDE などの MCP クライアントはユーザーとして接続し、すべての呼び出しはそのユーザーとして、人と同じ権限と監査のもとで実行されます。オープンソースの ObjectStack ランタイムも、独自のモデルで同じ MCP を提供します。ObjectOS はそれに製品内 AI(AI Builder と、ユーザーがチャットするアシスタント)を追加します。[AI ツールの接続(MCP)](/docs/configure/mcp)を参照してください。 + +## カスタマイズ [#customization] + +### 独自のプラグインを書けますか? [#can-i-write-custom-plugins] + +はい。プラグインはシンプルな DI とライフサイクルのパターン(`init → start → destroy`)に従います。例は GitHub の `@objectstack/plugin-*` パッケージを参照してください。 + +### ObjectOS の見た目をカスタマイズできますか? [#can-i-customize-how-objectos-looks] + +ブランディング(ロゴ、アクセントカラー、既定のテーマ)は **Setup → System Settings** にあります。UI を深くカスタマイズするには、`@objectstack/client-react` をフォークするか、REST API に対して独自のフロントエンドを構築します。 + +### 英語以外の言語を追加できますか? [#can-i-add-languages-other-than-english] + +はい。i18n は最初から組み込まれています。`os i18n extract` / `os i18n check` を使い、翻訳バンドルを配布してください。 + +## 運用 [#operations] + +### 推奨される本番デプロイは? [#whats-the-recommended-production-deployment] + +Docker(複数 Pod なら Kubernetes)、マネージド Postgres、ファイル用の S3 か R2、`OS_AUTH_SECRET` 用のシークレットマネージャーです。[本番環境への準備](/docs/operate/production)を参照してください。 + +### ObjectOS にはステータスページがありますか? [#does-objectos-have-a-status-page] + +セルフマネージド(Enterprise)のデプロイでは、ステータスはあなたが管理するものです。監視の対象を、死活監視には `/api/v1/health`、レディネスには `/api/v1/ready` に向けてください。[Docker](/docs/deploy/docker) と [Kubernetes](/docs/deploy/kubernetes) はこの 2 つを設定しています。ホスト型のサービスについては [status.objectstack.ai](https://status.objectstack.ai) を参照してください。 + +### どのメトリクスを監視すべきですか? [#what-metrics-should-i-monitor] + +5xx の割合、p95 レイテンシ、レディネス(`/api/v1/ready`)です。認証失敗のメトリクスはありません。代わりに Setup の `Auth` 監査ビューでサインインのアクティビティを確認してください。Prometheus の最小限の例は[オブザーバビリティ](/docs/operate/observability)にあります。 + +### バックアップはどう取りますか? [#how-do-i-take-a-backup] + +**データベース**と**ストレージバケット**をバックアップしてください。顧客データはすべてこの 2 つにあります。ObjectOS 自体はステートレスです。[バックアップ](/docs/operate/backup)を参照してください。 + +## 料金と法務 [#pricing--legal] + +### ObjectOS は無料ですか? [#is-objectos-free] + +**ObjectOS Community** は無料です。**[ObjectStack フレームワーク](https://github.com/objectstack-ai/objectstack)**(Apache-2.0)の上に構築されたオープンソースのランタイムと Console で、シートも利用量の階層もライセンスサーバーもなく、MCP 経由の AI(自分のモデルを持ち込み)が使えます。**ObjectOS Cloud**(無料枠から始められます)と **ObjectOS Enterprise** は、組み込みの**製品内 AI**、ガバナンス、公式の運用を追加し、料金は **AI シート**に対してのみ発生します(閲覧者と AI を使わないユーザーは無料)。[エディション](/docs/editions/license#editions)を参照してください。 + +### 販売する商用製品で使えますか? [#can-i-use-it-in-a-commercial-product-i-sell] + +**ObjectStack フレームワーク**と **ObjectOS Community** は使えます。Apache-2.0 はロイヤリティなしで商用利用を認めています。**ObjectOS Cloud や Enterprise** の再配布、または ObjectOS の名前でのビルドの再配布には OEM 契約が必要です。[ライセンスと料金](/docs/editions/license)を参照してください。 + +### テレメトリーを収集していますか? [#do-you-collect-telemetry] + +ObjectOS Community は、あなたが設定しない限り(OIDC、メール、AI、Webhook)外部への通信を一切行いません。ObjectOS Enterprise はライセンスをオンラインで検証します。エアギャップ環境向けの Enterprise ライセンスはオフラインで検証します。[セキュリティとコンプライアンス](/docs/reference/security#data-residency)を参照してください。 + +### ObjectOS は SOC 2 / ISO 27001 / HIPAA / GDPR に準拠していますか? [#is-objectos-soc-2--iso-27001--hipaa--gdpr-compliant] + +ObjectOS は、どのフレームワークも求める**基本要素**(RBAC、監査、暗号化への対応、データレジデンシー)を提供します。認証はバイナリではなく、あなたの**デプロイ**が取得するものです。認証を取得している ObjectOS のデプロイは多数あります。[セキュリティとコンプライアンス](/docs/reference/security#compliance-frameworks)を参照してください。 + +## 行き詰まったら [#getting-unstuck] + +### 何かが壊れています。どこから始めればよいですか? [#somethings-broken--where-do-i-start] + +`os doctor` です。設定ミスの 80% はこれだけで見つかります。その後は[トラブルシューティング](/docs/operate/troubleshooting)を参照してください。 + +### バグはどこに報告しますか? [#where-do-i-report-a-bug] + +[GitHub Issues](https://github.com/objectstack-ai/objectstack/issues) です。すべての ObjectOS エディションに共通の、唯一の公開 issue トラッカーです。`os doctor` の出力を添えてください。セキュリティの問題は **security@objectstack.ai** へ。 + +### 人に助けてもらうには? [#where-do-i-get-help-from-humans] + +[GitHub Issues](https://github.com/objectstack-ai/objectstack/issues)、コミュニティの Discord、または商用サポートなら **sales@objectstack.ai** へ。 diff --git a/content/docs/resources/glossary.ja.mdx b/content/docs/resources/glossary.ja.mdx new file mode 100644 index 00000000..bb86c915 --- /dev/null +++ b/content/docs/resources/glossary.ja.mdx @@ -0,0 +1,190 @@ +--- +title: 用語集 +seoTitle: "用語集:プラットフォームの用語、それぞれ 1 つの定義" +description: ObjectOS と ObjectStack 全体で使われる語彙。それぞれ 1 つの定義。 +editions: [community, cloud, enterprise] +translation: + source_sha: 926190d46d41bff6cbbc425cf9ccf45e6fb26dfadfb12a7d791e2606e71163c2 + guide_rev: 1 + mode: auto +--- + +このドキュメントで使われる各用語について、ひとつの正式な定義を示します。 + +### アクション(Action) [#action] + +メタデータで宣言された名前付きの操作で、REST(`/api/v1/actions//`)、UI のボタン、そして作成者が AI に公開した場合(`ai.exposed`)はエージェントから呼び出せます。呼び出し元がそれを呼び出せるかどうかは、呼び出し元として確認されます。その後、`script` の本体は信頼されたアプリのコードとして実行されます。[アクション](/docs/build/interface/actions)を参照してください。 + +### アダプター(Adapter) [#adapter] + +ObjectStack をホストのランタイム(Express、Fastify、Hono、Next.js、Nuxt、SvelteKit、NestJS)と統合するフレームワークのパッケージ。ほとんどの ObjectOS のデプロイメントでは不要です。ObjectOS は独自の HTTP サーバーを同梱しています。 + +### AI シート(AI seat) [#ai-seat] + +ObjectOS の料金の単位であり、すべてのエディションで唯一課金されるシートです。閲覧者、製品内 AI を使わないアプリのユーザー、MCP で構築する開発者は無料です。[ライセンスと料金](/docs/editions/license#editions)を参照してください。 + +### アプリ(App) [#app] + +オブジェクト、ビュー、権限をまとめ、ナビゲーションできるひとつのアプリケーションとして提示したもの。1 つのランタイムに複数のアプリが共存できます(例:CRM + Helpdesk + Setup)。 + +### アーティファクト(Artifact) [#artifact] + +コンパイル済みの `objectstack.json` ファイル。アプリについての自己完結した不変の記述です(マニフェスト、オブジェクト、ビュー、アプリ、フロー、権限、翻訳)。`os compile` が生成します。ObjectOS が実際に実行するものです。 + +### Better Auth [#better-auth] + +`@objectstack/plugin-auth` を支える認証ライブラリ。Better Auth を直接設定することはありません。プラグインがそれをラップしています。 + +### ビジネスオントロジー(Business ontology) [#business-ontology] + +アプリの定義(オブジェクトとフィールド、リレーション、アクション、権限、フロー、そしてエージェントとツールの定義)を、実行可能でバージョン管理されたひとつの全体としたもの。型付きの ObjectStack メタデータとして作成され、推論されるのではなく検証され、ランタイムによって実行されます。ランタイムはそこからデータベース、REST API、UI、MCP ツールを導出します。ビュー、ダッシュボード、アプリ、翻訳はその[プロジェクション](#projection)であり、その一部ではありません。 + +これは実行可能なものであり、知識オントロジーではありません。オブジェクトの継承も、公理も、推論器もありません。セマンティックレイヤー(ビジネスを記述するが実行はしない、既存システム上の読み取り専用のマッピング)でもありません。どちらの ObjectOS エディションでもあなたのものです。エクスポートして、オープンソースの ObjectStack ランタイムで実行できます。このサイトでは [ObjectOS におけるあなたのオントロジー](/docs/ontology)を参照してください。完全な説明は ObjectStack ドキュメントの [Business Ontology](https://objectstack.ai/docs/concepts/ontology) にあります。 + +### 機能(Capability) [#capability] + +アーティファクトが `requires` リストで宣言する、オプションのランタイムの機能。パッケージに対応します(例:`audit` → `@objectstack/plugin-audit`)。ObjectOS が必要に応じて読み込みます。[ランタイムの機能](/docs/reference/runtime-capabilities)を参照してください。 + +### CEL [#cel] + +[Common Expression Language](https://github.com/google/cel-spec)。Google による、安全でサンドボックス化された式の構文です。数式、検証ルール、権限の述語、共有ルール、フローの条件で使われます。 + +### コントロールプレーン(Control Plane) [#control-plane] + +バージョン管理されたアーティファクトを ObjectOS のインスタンスに公開する、オプションのサービス。ObjectOS Cloud としてホストされるか、セルフホストされます。ほとんどのデプロイメントでは不要です。単一アプリの本番には、ファイルベースのモードで十分です。 + +### ドライバー(Driver) [#driver] + +データバックエンドの実装:`driver-sql`(Postgres、MySQL、SQLite、Turso/libSQL)、`driver-mongodb`、`driver-memory`。起動時にデータベース URL によって選ばれます。 + +### エンベッダー(Embedder) [#embedder] + +RAG / セマンティック検索のために、テキストをベクトルに変換するサービス。プロバイダー(OpenAI、Azure、硅基流动、Ollama など)を差し替えられます。[AI サービス](/docs/configure/ai)を参照してください。 + +### 環境(Environment) [#environment] + +デプロイメント自身の識別情報。`OS_ENVIRONMENT_ID` として報告する id で、クラウドへのバインディングが完了すると永続化されます。セルフマネージドの ObjectOS は**単一環境**のランタイムです。ひとつのプロセス、ひとつの環境、ひとつのアプリ。多くの環境を保持し、それぞれにアーティファクトを公開するのは、コントロールプレーンの役割です。[環境変数](/docs/reference/environment-variables)を参照してください。 + +### フィールド(Field) [#field] + +オブジェクトの型付きのプロパティ。組み込みのタイプは約 48 種類:`text`、`select`、`lookup`、`markdown`、`file`、`formula`、`summary` など。[データモデル](/docs/build/data)を参照してください。 + +### フロー(Flow) [#flow] + +宣言的なビジネスロジック。自動起動(レコードトリガー)、スケジュール(cron)、手動(ボタン / API)があります。条件/ループ/リトライ/並列のプリミティブを持つ DAG として実行されます。[フローと自動化](/docs/build/automation/flows)を参照してください。 + +### 数式フィールド(Formula field) [#formula-field] + +値が読み取り時に評価される CEL 式である計算フィールド。保存はされません。 + +### フック(Hook) [#hook] + +オブジェクトのライフサイクル(`beforeInsert`、`afterUpdate` など)に注入される関数。TypeScript で作成します。フローとは異なり、フックはファーストクラスのコードで、フローはメタデータです。 + +### カーネル(Kernel) [#kernel] + +ObjectOS の内部にあるマイクロカーネルで、プラグインを読み込み、DI コンテナを保持し、イベントをディスパッチし、デプロイメントのメタデータを提供します。1 つのプロセスは起動時に 1 つのカーネルを構築し、構築が終わるまで[準備完了](/docs/deploy/docker)を報告しません。そのため、リクエストごとにどのメタデータを提供するかを決める処理はありません。 + +### マニフェスト(Manifest) [#manifest] + +アーティファクトの先頭にある最上位のメタデータ:`id`、`namespace`、`version`、`type`(`app` / `plugin` / `service`)、`name`、`description`、`requires` リスト。 + +### マーケットプレイス(Marketplace) [#marketplace] + +インストール可能なアプリの組み込みのカタログ。設定可能なパッケージレジストリに支えられています。[マーケットプレイス](/docs/build/marketplace)を参照してください。 + +### MCP(Model Context Protocol) [#mcp-model-context-protocol] + +AI エージェントがツールを発見して呼び出すためのオープンなプロトコル。すべての ObjectOS のデプロイメントは `/api/v1/mcp` にある MCP サーバーであり、デフォルトで有効です。各オブジェクトがツールであり、作成者が AI に公開した(`ai.exposed`)各アクションもツールです。すべての呼び出しは呼び出し元として実行されます。[AI ツールを接続する(MCP)](/docs/configure/mcp)を参照してください。 + +### オブジェクト(Object) [#object] + +型付きのビジネスエンティティ:`task`、`account`、`invoice`。TypeScript のスキーマとして宣言され、REST API、ビュー、監査のエントリ、RBAC のチェックポイントを自動的に生成します。[データモデル](/docs/build/data)を参照してください。 + +### ObjectOS [#objectos] + +ObjectStack 上に構築されたランタイム環境で、3 つのエディションを持つひとつの製品です。**ObjectOS Community** は、objectstack リポジトリで開発され、Apache-2.0 のもとで無料のオープンソースのランタイムと Console です。**ObjectOS Cloud** は、何もインストールせずにブラウザで使えるホスト型です。**ObjectOS Enterprise** は、自社のインフラストラクチャでセルフマネージドで動作するライセンス版です。Cloud と Enterprise は AI シート単位の料金で、どのエディションでもオントロジーをエクスポートしてオープンなランタイムで実行できます。**このドキュメントサイトは ObjectOS のためのものです。** + +### ObjectQL [#objectql] + +データ層のプロトコルとクエリエンジン。宣言的なクエリをネイティブの SQL / Mongo のクエリにコンパイルします。REST エンドポイント、UI、フローのすべてが同じエンジンを使います。 + +### ObjectStack [#objectstack] + +オープンなスタック(Apache-2.0):ビジネスオントロジーを実行するプロトコル、マイクロカーネル、SDK、CLI、本番ランタイムであり、`@objectstack/*` の npm パッケージとランタイムのイメージです。ObjectOS はその上に構築されたランタイム環境です。ObjectOS Community は同じ Apache-2.0 ライセンスのもとでのそのオープンなランタイムと Console であり、ObjectOS Cloud と ObjectOS Enterprise はその上の商用エディションです。 + +### ObjectUI [#objectui] + +ビュー層のプロトコル:アプリ、ビュー、ページ、ダッシュボード、アクション、グラフ、ナビゲーション。ObjectOS は ObjectUI の宣言を描画します。 + +### 権限セット(Permission Set) [#permission-set] + +付与(オブジェクト権限、フィールド権限、システム権限)をまとめたもの。ユーザーに直接、またはポジションを通じて割り当てられます。認可の主要な単位です。[権限](/docs/configure/permissions)を参照してください。 + +### プラグイン(Plugin) [#plugin] + +機能によってランタイムを拡張するフレームワークのパッケージ:`plugin-auth`、`plugin-security`、`plugin-audit`、`plugin-webhooks`、`mcp` など。DI とライフサイクルのフック(`init → start → destroy`)を通じて有効になります。 + +### ポジション(Position) [#position] + +ユーザーが担う職務:「Sales Manager」「Support Agent」「Auditor」。ObjectStack 13 以降、人をグループ化する唯一の概念であり、意図的にフラットです。報告の構造は代わりにビジネスユニットのツリーにあります。ポジションは、アプリやタブを対象者に向け、承認者を指定し、それを担うすべての人に権限セットを配布します。[ポジション](/docs/configure/permissions/positions)を参照してください。 + +### プロジェクト(Project) [#project] + +**環境**の古い名前。引き継いだ設定やフレームワーク内部の識別子に残っていますが、ObjectOS のドキュメントでは*環境*と呼びます。 + +### プロジェクション(Projection) [#projection] + +ビュー、ダッシュボード、アプリ、翻訳のこと。[ビジネスオントロジー](#business-ontology)の横で作成され、同じ[検証ゲート](#validation-gate)でチェックされるメタデータですが、オントロジーの一部ではありません。プロジェクションはコアを提示します。グリッド上のオブジェクトのフィールド、グラフ上のオブジェクトに対するクエリ、あるロケールでのすべてのラベル。コアを変更すればプロジェクションは追従し、プロジェクションを削除しても、それが表示していたビジネスは変わりません。[ObjectOS におけるあなたのオントロジー](/docs/ontology#the-projections)を参照してください。 + +### レコードの共有(Record Share) [#record-share] + +特定のレコードへのアクセスを、1 つの受信者に直接付与するもの。受信者は、ユーザー(`user`)、チーム(`team`)、ポジション(`position`)、ビジネスユニット(`business_unit`)、またはビジネスユニットとその配下のすべてのユニット(`unit_and_subordinates`)です。`sys_record_share` の行として保存され、その `recipient_type` 列はちょうどこの 5 つの値を取ります。共有ルール(宣言的な条件)とは異なります。 + +### Setup [#setup] + +組み込みの管理アプリで、`/_console/` で提供される UI の中の `/apps/setup` にあり、`setup.access` 権限で制限されています。ユーザー、ビジネスユニット、チーム、ポジション、権限セット、共有ルール、レコードの共有、API キー、そして設定、診断、連携を管理します。[設定](/docs/configure)を参照してください。 + +### 共有ルール(Sharing Rule) [#sharing-rule] + +条件に基づいてレコードへのアクセスを付与する宣言的なルール(「地域マネージャーは自分の地域のレコードを見られる」)。クエリ時に評価され、行レベルのフィルターにコンパイルされます。条件**なし**で保存されたルールは何も共有しません。すべてに一致するわけではありません。[レコードアクセス](/docs/configure/permissions/record-access#both-switches-fail-closed)を参照してください。 + +### Studio [#studio] + +組み込みのメタデータ作成のサーフェスで、`/_console/` で提供される UI の中の `/studio` にあり、`studio.access` 権限で制限されています。メタデータそのもの(パッケージ、オブジェクト、アプリ、フロー、権限セット)を、一度に 1 つのパッケージずつ、Data、Automations、Interfaces、Access の 4 つの柱にわたって*設計*する場所です。**Setup** と同列であり、その一部ではありません。Setup は稼働中のデプロイメント(その人々、その付与、その設定)を運用し、Studio はそのデプロイメントが実行するものを作成します。そのため、**権限は Studio で設計し、Setup で割り当てます**。Setup とは異なり、`/apps/` の下のアプリではありません。UI はこれを独自のルートのサブツリーとして提供します。[設定](/docs/configure#setup-and-studio)を参照してください。 + +### サーフェス(Surface) [#surface] + +稼働中の ObjectOS が公開する HTTP の入り口の 1 つ:`/`(REST API)と `/_console/`(UI)。3 つではなく 2 つです。アカウントは独自のサーフェスでは**ありません**。サインイン、登録、アカウントのセルフサービスは、すべて UI の中のルートです。 + +| アカウントのサーフェス | 場所 | +|---|---| +| サインイン | `/_console/login`。サインインしていないとき、保護されたすべてのページがここに送ります | +| 登録 | `/_console/register`。デプロイメントがセルフサービスのサインアップを無効にしていない場合 | +| アカウントのセルフサービス | `/_console/apps/account`。Account アプリで、`/_console/apps/setup` の Setup と並んでいます | + +`/_account/` というサーフェスはありません。独立したアカウントポータルが削除されたときに廃止され、それらの URL は現在 404 を返します。 + +### システムコンテキスト(System Context) [#system-context] + +セキュリティのチェックを回避する必要があるプラグイン、フック、シードスクリプトが使う内部の実行モード。監査可能で、ユーザーのコードには公開されません。 + +### テナント(Tenant) [#tenant] + +1 つのデプロイメントを共有する組織間の分離の境界。壁で区切られたテナンシーの姿勢がその壁を立て、これはライセンスされた機能です。それらの組織は引き続きデプロイメントのアプリ、データベース、メタデータを共有するため、壁が分けるのはスキーマではなく、データとメンバーシップです。[マルチ組織のデプロイメント](/docs/reference/environment-variables#multi-organization-deployments)を参照してください。 + +### トリガー(Trigger) [#trigger] + +フローを起動する条件:レコードのイベント(`after_insert`)、スケジュール(cron)、または手動の呼び出し。 + +### 検証ゲート(Validation gate) [#validation-gate] + +すべてのメタデータが実行される前に通過する、ひとまとまりのチェック:`@objectstack/spec` のスキーマと、型チェックは通るが実行時に黙って失敗するもの(不正な CEL の述語、存在しないものへの参照)を捉える作成ルールです。`os validate` と `os compile` はリポジトリのソースに対してこれを実行し、ランタイムは AI Builder、Studio、メタデータ API から稼働状態になるすべてのメタデータの書き込みに同じゲートを適用します。ObjectStack ドキュメントの [Validating Metadata](https://objectstack.ai/docs/deployment/validating-metadata) を参照してください。 + +### ビュー(View) [#view] + +オブジェクトに付属する宣言的な UI の設定:リスト、フォーム、カンバン、カレンダー、ガント。ObjectOS がそれを描画するため、コンポーネントを書く必要はありません。 + +### Zod schema [#zod-schema] + +`@objectstack/spec` が使う、実行時とコンパイル時の型システム。すべてのオブジェクト、フィールド、ビュー、アプリ、フローは Zod スキーマによって解析・検証されます。JSON Schema、TypeScript の型、REST のリクエストバリデーターは、すべて同じ Zod の定義から導出されます。 diff --git a/content/docs/resources/support.ja.mdx b/content/docs/resources/support.ja.mdx new file mode 100644 index 00000000..64477178 --- /dev/null +++ b/content/docs/resources/support.ja.mdx @@ -0,0 +1,77 @@ +--- +title: サポート +seoTitle: "サポート:ヘルプ、バグの報告、応答時間" +description: どこでヘルプを得るか、バグをどう報告するか、応答の目安。 +editions: [community, cloud, enterprise] +translation: + source_sha: c91dd5746f73af07b73d9af2e79272ab63df7883b882a67dfcc6329bbc1ffc1a + guide_rev: 1 + mode: auto +--- + +## 目的別の窓口 [#where-to-go-for-what] + +| こんなときは | 窓口 | +|---|---| +| 「どうすれば」という質問がある | [GitHub Issues](https://github.com/objectstack-ai/objectstack/issues):ObjectOS のすべてのエディションに共通の、唯一の公開 issue トラッカー | +| バグを見つけた | [GitHub Issues](https://github.com/objectstack-ai/objectstack/issues):バージョン、再現手順、期待した結果と実際の結果を含めてください | +| このドキュメントの誤りを見つけた | [docs.objectos.ai の issues](https://github.com/objectstack-ai/docs.objectos.ai/issues):このサイト自身のリポジトリは、ドキュメントの issue だけを受け付けます | +| セキュリティの脆弱性を見つけた | **security@objectstack.ai**:公開の issue は作成**しないでください** | +| 商用サポート / SLA が必要 | **sales@objectstack.ai** | +| ユーザーやメンテナーと話したい | [Discord](https://discord.gg/objectstack)(コミュニティ運営) | +| リリースを追いたい | [リリースノート](/docs/resources/changelog#release-notes):各リリースが公開される場所です。通知を受け取るには、[github.com/objectstack-ai/objectstack](https://github.com/objectstack-ai/objectstack) → Releases を Watch してください | +| 有償で機能を実装してほしい | **sales@objectstack.ai**:[商用サポートとサービス](#commercial-support--services)を参照してください | + +## よいバグ報告の書き方 [#filing-a-good-bug-report] + +30 秒でわかる版: + +```text +ObjectOS version: 14.7.0 (or sha-abc123) +Node version: 22.4.0 +Install method: docker / npm -g / source +Database: postgres 16 / sqlite / turso / mongo +Repro steps: 1. ... 2. ... 3. ... +Expected: ... +Actual: ... +Logs: (sanitized, last 30 lines) +``` + +設定の問題については、`os doctor` の出力を添付してください。設定の誤りの 80% はそれだけで診断できます。 + +## 応答の目安 [#response-expectations] + +| チャネル | ベストエフォートの応答時間 | +|---|---| +| セキュリティのメール | 1 営業日 | +| GitHub Issues:再現手順付きのバグ | トリアージに 3 営業日、修正は次のリリーストレインで | +| GitHub Issues:機能のリクエスト | トリアージに 7 営業日 | +| 商用サポート | サポート契約に従います | + +これらはベストエフォートであり、SLA ではありません。商用サポートの契約には正式な SLA があります。 + +## 商用サポートとサービス [#commercial-support--services] + +ObjectStack チームから提供されるもの: + +- **ObjectOS Runtime Subscription**:無料のセルフホストのランタイムである ObjectOS Community に対するサポート契約です。応答時間の SLA、指名されたエスカレーション先、セキュリティパッチの優先対応(オープンソース版との機能の違いはありません)。 +- **マネージドホスティング**:ObjectOS Cloud。私たちが運用します。 +- **アーキテクチャレビュー**:デプロイ前の健全性チェック。 +- 仕様に合わせて構築する**カスタムのプラグイン / 機能**。 +- **OEM 再配布**:ObjectOS を自社の製品に組み込みます。 + +**sales@objectstack.ai** にお問い合わせください。 + +## 貢献する [#contributing-back] + +基盤となる ObjectStack フレームワークは Apache-2.0 で、貢献を受け付けています。 + +- [CONTRIBUTING.md](https://github.com/objectstack-ai/objectstack/blob/main/CONTRIBUTING.md) +- [Code of Conduct](https://github.com/objectstack-ai/objectstack/blob/main/CODE_OF_CONDUCT.md) +- ドラフトの PR は早めに出してください。重複した作業よりも、下書きをレビューする方を私たちは望んでいます。 + +## ステータスとインシデント [#status--incidents] + +ホスト型のサービス(ObjectOS Cloud、パッケージレジストリ):[status.objectstack.ai](https://status.objectstack.ai)。 + +セルフホストの ObjectOS デプロイメントのステータスはあなたの管理範囲です。通常の監視に接続してください([オブザーバビリティ](/docs/operate/observability)を参照)。 From 84a7d230d4beeaa1c2cbfabbd0f6e7eed168a015 Mon Sep 17 00:00:00 2001 From: Steedos Date: Thu, 29 Oct 2026 16:32:48 +0000 Subject: [PATCH 12/22] docs(i18n): re-sync start/cloud step 1 in zh-Hans, zh-Hant and ja (#404) #403 changed step 1 of "Start on ObjectOS Cloud" to link the console's register and sign-in pages instead of www.objectos.ai. This carries the same change into zh-Hans and ja, restamps both, and regenerates zh-Hant with gen:zh-hant. check-translations: zh-Hans and ja 0 stale, 0 missing. Fixes #404 Claude-Session: https://claude.ai/code/session_01QsR2jRsjbApbf83iyTDDXm Co-Authored-By: Claude --- content/docs/start/cloud.ja.mdx | 4 ++-- content/docs/start/cloud.zh-Hans.mdx | 4 ++-- content/docs/start/cloud.zh-Hant.mdx | 4 ++-- 3 files changed, 6 insertions(+), 6 deletions(-) diff --git a/content/docs/start/cloud.ja.mdx b/content/docs/start/cloud.ja.mdx index 7086f29a..500de19d 100644 --- a/content/docs/start/cloud.ja.mdx +++ b/content/docs/start/cloud.ja.mdx @@ -4,7 +4,7 @@ seoTitle: "ObjectOS Cloud で始める:サインアップして最初のアプ description: あなたのためにホストされる ObjectOS、インストールするものは何もありません。サインアップし、組織に名前を付け、その本番環境を作成し、最初のアプリを構築してチームを招待します。 editions: [cloud] translation: - source_sha: f83df72638808eeefa3a77e192b7ec0158e83be9e366f36a3d9c7fd74b8fedf5 + source_sha: ce2963934dcc0a33f70d6195e1cae5a6920afc7658ad67bf5cf9af18b4cfaff1 guide_rev: 1 mode: auto --- @@ -15,7 +15,7 @@ translation: ## 1. サインアップする [#1-sign-up] -[www.objectos.ai](https://www.objectos.ai) から始めて、アカウントを作成します。 +[ObjectOS Cloud のサインアップページ](https://cloud.objectos.ai/_console/register)でアカウントを作成します。すでにアカウントをお持ちの場合は、[サインイン](https://cloud.objectos.ai/_console/login)してください。 ## 2. 組織を作成する [#2-create-your-organization] diff --git a/content/docs/start/cloud.zh-Hans.mdx b/content/docs/start/cloud.zh-Hans.mdx index 1f7a58bc..e303fff3 100644 --- a/content/docs/start/cloud.zh-Hans.mdx +++ b/content/docs/start/cloud.zh-Hans.mdx @@ -4,7 +4,7 @@ seoTitle: "在 ObjectOS Cloud 上开始:注册并构建你的第一个应用" description: 为你托管的 ObjectOS,无需任何安装 —— 注册、为你的组织命名、创建它的生产环境、构建第一个应用并邀请你的团队。 editions: [cloud] translation: - source_sha: f83df72638808eeefa3a77e192b7ec0158e83be9e366f36a3d9c7fd74b8fedf5 + source_sha: ce2963934dcc0a33f70d6195e1cae5a6920afc7658ad67bf5cf9af18b4cfaff1 guide_rev: 1 mode: auto --- @@ -19,7 +19,7 @@ translation: ## 1. 注册 [#1-sign-up] -从 [www.objectos.ai](https://www.objectos.ai) 开始,创建你的账户。 +在 [ObjectOS Cloud 注册页面](https://cloud.objectos.ai/_console/register)创建你的账户。已经有账户了?[登录](https://cloud.objectos.ai/_console/login)。 ## 2. 创建你的组织 [#2-create-your-organization] diff --git a/content/docs/start/cloud.zh-Hant.mdx b/content/docs/start/cloud.zh-Hant.mdx index 3d95608c..e9cf2fef 100644 --- a/content/docs/start/cloud.zh-Hant.mdx +++ b/content/docs/start/cloud.zh-Hant.mdx @@ -5,7 +5,7 @@ seoTitle: "在 ObjectOS Cloud 上開始:註冊並構建你的第一個應用" description: 為你託管的 ObjectOS,無需任何安裝 —— 註冊、為你的組織命名、建立它的生產環境、構建第一個應用並邀請你的團隊。 editions: [cloud] translation: - source_sha: f83df72638808eeefa3a77e192b7ec0158e83be9e366f36a3d9c7fd74b8fedf5 + source_sha: ce2963934dcc0a33f70d6195e1cae5a6920afc7658ad67bf5cf9af18b4cfaff1 guide_rev: 1 mode: auto --- @@ -20,7 +20,7 @@ translation: ## 1. 註冊 [#1-sign-up] -從 [www.objectos.ai](https://www.objectos.ai) 開始,建立你的賬戶。 +在 [ObjectOS Cloud 註冊頁面](https://cloud.objectos.ai/_console/register)建立你的賬戶。已經有賬戶了?[登入](https://cloud.objectos.ai/_console/login)。 ## 2. 建立你的組織 [#2-create-your-organization] From 470446bab49342aaaa336e7238a4d2e4c47e07d7 Mon Sep 17 00:00:00 2001 From: Steedos Date: Sat, 31 Oct 2026 12:31:24 +0000 Subject: [PATCH 13/22] docs(i18n): re-sync six pages changed by #410 and #413 in zh-Hans, zh-Hant and ja (#414) #410 added subscription management, AI seat changes and Paddle as the seller to cloud/plans-and-seats and cloud/ai-credits-and-limits. #413 moved the sales contact to sales@objectos.ai on editions/license, resources/support, resources/faq and start/enterprise. This carries only the changed parts into zh-Hans and ja, restamps all twelve pages, and regenerates zh-Hant with gen:zh-hant. Paddle, emails and URLs are copied byte for byte. check-translations: zh-Hans and ja 0 stale, 0 missing. Fixes #414 Claude-Session: https://claude.ai/code/session_01QsR2jRsjbApbf83iyTDDXm Co-Authored-By: Claude --- .../docs/cloud/ai-credits-and-limits.ja.mdx | 9 +++--- .../cloud/ai-credits-and-limits.zh-Hans.mdx | 13 +++++---- .../cloud/ai-credits-and-limits.zh-Hant.mdx | 13 +++++---- content/docs/cloud/plans-and-seats.ja.mdx | 28 +++++++++++++++++-- .../docs/cloud/plans-and-seats.zh-Hans.mdx | 28 +++++++++++++++++-- .../docs/cloud/plans-and-seats.zh-Hant.mdx | 28 +++++++++++++++++-- content/docs/editions/license.ja.mdx | 14 +++++----- content/docs/editions/license.zh-Hans.mdx | 14 +++++----- content/docs/editions/license.zh-Hant.mdx | 14 +++++----- content/docs/resources/faq.ja.mdx | 4 +-- content/docs/resources/faq.zh-Hans.mdx | 4 +-- content/docs/resources/faq.zh-Hant.mdx | 4 +-- content/docs/resources/support.ja.mdx | 8 +++--- content/docs/resources/support.zh-Hans.mdx | 8 +++--- content/docs/resources/support.zh-Hant.mdx | 8 +++--- content/docs/start/enterprise.ja.mdx | 4 +-- content/docs/start/enterprise.zh-Hans.mdx | 4 +-- content/docs/start/enterprise.zh-Hant.mdx | 4 +-- 18 files changed, 141 insertions(+), 68 deletions(-) diff --git a/content/docs/cloud/ai-credits-and-limits.ja.mdx b/content/docs/cloud/ai-credits-and-limits.ja.mdx index e26104b2..577ea6d3 100644 --- a/content/docs/cloud/ai-credits-and-limits.ja.mdx +++ b/content/docs/cloud/ai-credits-and-limits.ja.mdx @@ -4,7 +4,7 @@ seoTitle: "ObjectOS Cloud の AI 利用枠:週ごとの上限、ペース、 description: ObjectOS Cloud で製品内 AI がどう計量されるか。構築と質問のための 1 つの利用枠、ローリングする週ごとの上限と 5 時間のペース、クレジットパック、各プランが使うモデル、そして拒否されたときのメッセージ。 editions: [cloud, enterprise] translation: - source_sha: 67429e9e53ae8850c44792b0659fead909aa7791fb06d24d6153d6be29182837 + source_sha: 364db1e588afb29954596b61a6d0a48eb154431be7f9b233aed6cb3b638af993 guide_rev: 1 mode: auto --- @@ -42,11 +42,12 @@ ObjectOS Cloud が[パブリックプレビュー](/docs/editions/public-preview ## AI クレジットを購入する [#buy-ai-credits] -有料プランでは、オーナーまたは管理者が、一回限りの **AI クレジットパック**で週ごとの利用枠を補充できます。環境の **Settings → Plan and billing** を開き、**AI credits** → **Buy AI Credits** を選びます。新しいタブで安全なチェックアウトが開きます。 +有料プランでは、オーナーまたは管理者が **AI クレジットパック**で環境の週ごとの利用枠を補充できます。環境の **Settings → Plan and billing** を開き、**AI credits** → **Buy AI Credits** を選びます。新しいタブで安全なチェックアウトが開きます。パックはサブスクリプションではなく一回限りの購入で、Paddle が販売し、領収書と利用明細には Paddle と表示されます([支払い、請求書、返金](/docs/cloud/plans-and-seats#payment-invoices-and-refunds))。 +- パックは支払いの完了後に購入元の環境に追加され、その時点から **7 日間**有効です。同じ週に購入したパックは合算されます。 - クレジットパックが引き上げるのは **7 日**の予算だけです。5 時間のペースはレート制限であり、購入で引き上げることはできません。 -- Free はクレジットパックを受け付けません。Free の週ごとの上限を超える方法は [Team へのアップグレード](/docs/cloud/plans-and-seats#upgrade)です。 -- 組織でクレジットパックがまだ販売されていない場合、ボタンはチェックアウトを開く代わりにそのことを伝えます。 +- クレジットパックは有料プラン専用です。Free にはボタンが表示されず、Free の組織からの購入は拒否されます。Free の週ごとの上限を超える方法は [Team へのアップグレード](/docs/cloud/plans-and-seats#upgrade)です。 +- オンライン決済がまだ利用できない間は、ボタンはチェックアウトを開かず、オンライン決済は近日公開予定であることを伝えて [sales@objectos.ai](mailto:sales@objectos.ai) を案内します。 ## どのモデルが答えるか [#which-model-answers] diff --git a/content/docs/cloud/ai-credits-and-limits.zh-Hans.mdx b/content/docs/cloud/ai-credits-and-limits.zh-Hans.mdx index 09dcf46d..d1750df4 100644 --- a/content/docs/cloud/ai-credits-and-limits.zh-Hans.mdx +++ b/content/docs/cloud/ai-credits-and-limits.zh-Hans.mdx @@ -4,7 +4,7 @@ seoTitle: "ObjectOS Cloud AI 额度:每周限制、节奏与点数包" description: ObjectOS Cloud 上的产品内 AI 如何计量 —— 构建和提问共用一份额度、滚动的每周限制和五小时节奏、点数包、每个套餐使用的模型,以及拒绝时会说明什么。 editions: [cloud, enterprise] translation: - source_sha: 67429e9e53ae8850c44792b0659fead909aa7791fb06d24d6153d6be29182837 + source_sha: 364db1e588afb29954596b61a6d0a48eb154431be7f9b233aed6cb3b638af993 guide_rev: 1 mode: auto --- @@ -54,16 +54,19 @@ translation: ## 购买 AI 点数 [#buy-ai-credits] -在付费套餐上,所有者或管理员可以用一次性的 **AI 点数包**补充每周额度: +在付费套餐上,所有者或管理员可以用 **AI 点数包**补充某个环境的每周额度: 打开环境的 **Settings → Plan and billing**,然后 **AI credits** → **Buy AI Credits**。一个安全结账页面会在 -新标签页中打开。 +新标签页中打开。点数包是一次性购买,不是订阅,由 Paddle 售卖,你的收据和账单上会显示 Paddle +([付款、发票与退款](/docs/cloud/plans-and-seats#payment-invoices-and-refunds))。 +- 付款完成后,点数包会加到你购买它的那个环境上,并从那时起持续 **7 天**。同一周内购买的点数包可以叠加。 - 点数包只提高 **7 天**预算。五小时节奏是一个速率限制,任何购买都无法 解除它。 -- Free 不接受点数包;越过 Free 每周限制的办法是 +- 点数包仅适用于付费套餐。Free 不显示该按钮,从 Free 组织发起的购买会被拒绝;越过 Free 每周限制的办法是 [升级到 Team](/docs/cloud/plans-and-seats#upgrade)。 -- 如果你的组织尚未开售点数包,按钮会说明这一点,而不是打开结账页面。 +- 在线支付尚未开放时,按钮不会打开结账页面:它会说明在线支付即将推出,并给出 + [sales@objectos.ai](mailto:sales@objectos.ai)。 ## 由哪个模型回答 [#which-model-answers] diff --git a/content/docs/cloud/ai-credits-and-limits.zh-Hant.mdx b/content/docs/cloud/ai-credits-and-limits.zh-Hant.mdx index 345ba51d..f86f4549 100644 --- a/content/docs/cloud/ai-credits-and-limits.zh-Hant.mdx +++ b/content/docs/cloud/ai-credits-and-limits.zh-Hant.mdx @@ -5,7 +5,7 @@ seoTitle: "ObjectOS Cloud AI 額度:每週限制、節奏與點數包" description: ObjectOS Cloud 上的產品內 AI 如何計量 —— 構建和提問共用一份額度、滾動的每週限制和五小時節奏、點數包、每個套餐使用的模型,以及拒絕時會說明什麼。 editions: [cloud, enterprise] translation: - source_sha: 67429e9e53ae8850c44792b0659fead909aa7791fb06d24d6153d6be29182837 + source_sha: 364db1e588afb29954596b61a6d0a48eb154431be7f9b233aed6cb3b638af993 guide_rev: 1 mode: auto --- @@ -55,16 +55,19 @@ translation: ## 購買 AI 點數 [#buy-ai-credits] -在付費套餐上,所有者或管理員可以用一次性的 **AI 點數包**補充每週額度: +在付費套餐上,所有者或管理員可以用 **AI 點數包**補充某個環境的每週額度: 開啟環境的 **Settings → Plan and billing**,然後 **AI credits** → **Buy AI Credits**。一個安全結賬頁面會在 -新標籤頁中開啟。 +新標籤頁中開啟。點數包是一次性購買,不是訂閱,由 Paddle 售賣,你的收據和賬單上會顯示 Paddle +([付款、發票與退款](/docs/cloud/plans-and-seats#payment-invoices-and-refunds))。 +- 付款完成後,點數包會加到你購買它的那個環境上,並從那時起持續 **7 天**。同一周內購買的點數包可以疊加。 - 點數包只提高 **7 天**預算。五小時節奏是一個速率限制,任何購買都無法 解除它。 -- Free 不接受點數包;越過 Free 每週限制的辦法是 +- 點數包僅適用於付費套餐。Free 不顯示該按鈕,從 Free 組織發起的購買會被拒絕;越過 Free 每週限制的辦法是 [升級到 Team](/docs/cloud/plans-and-seats#upgrade)。 -- 如果你的組織尚未開售點數包,按鈕會說明這一點,而不是開啟結賬頁面。 +- 線上支付尚未開放時,按鈕不會開啟結賬頁面:它會說明線上支付即將推出,並給出 + [sales@objectos.ai](mailto:sales@objectos.ai)。 ## 由哪個模型回答 [#which-model-answers] diff --git a/content/docs/cloud/plans-and-seats.ja.mdx b/content/docs/cloud/plans-and-seats.ja.mdx index 36b415c8..6ca068f8 100644 --- a/content/docs/cloud/plans-and-seats.ja.mdx +++ b/content/docs/cloud/plans-and-seats.ja.mdx @@ -1,10 +1,10 @@ --- title: プランと AI シート seoTitle: "ObjectOS Cloud のプラン:Free、Team、Enterprise と AI シート" -description: ObjectOS Cloud のプラン(Free、Team、Enterprise)、唯一の有料シートである AI シート、アップグレードの方法、そしてプランに含まれないものをコンソールのどこで確認できるか。 +description: ObjectOS Cloud のプラン(Free、Team、Enterprise)、唯一の有料シートである AI シート、アップグレード、解約、シート数の変更の方法、請求元、そしてプランに含まれないものをコンソールのどこで確認できるか。 editions: [cloud] translation: - source_sha: c5f15cf821325b61b91091b0b7377b4a9750dc285a87202f969b73eae1eb8b97 + source_sha: 41b6faf0d1fed03c46a9c06784f4e33f6543c6e69088b25627a0d7e6c9eb989d guide_rev: 1 mode: auto --- @@ -32,7 +32,7 @@ ObjectOS Cloud は[パブリックプレビュー](/docs/editions/public-preview **AI シート**は、AI で構築し、データについて AI に質問できるメンバーです。[AI Builder](/docs/build/ai-builder) とアプリ内のアシスタントのことです。これが唯一の有料シートです。AI シートを持たないメンバー、閲覧者、そして [MCP](/docs/configure/mcp) 経由で自分の AI クライアントを使って構築する開発者には料金がかかりません。 -購入する AI シートの数は組織の設定で、チェックアウト時に選び、後から変更できます。それによって 3 つのものの大きさが決まります。 +購入する AI シートの数は組織の設定で、チェックアウト時に選び、[後から変更できます](#change-ai-seats)。それによって 3 つのものの大きさが決まります。 - 組織の **AI 利用枠**。シートごとです([AI クレジットと上限](/docs/cloud/ai-credits-and-limits))。 - **開発環境のプール**。2 つに加えてシートごとに 1 つです([環境](/docs/cloud/environments))。 @@ -50,6 +50,28 @@ ObjectOS Cloud は[パブリックプレビュー](/docs/editions/public-preview Enterprise は営業担当者が支援します。**Billing** の Enterprise の列にある **Contact sales** を使ってください。 +## サブスクリプションを管理する [#manage-your-subscription] + +オンラインのチェックアウトで購入した Team プランはサブスクリプションで、オーナーまたは管理者が環境の **Settings → Plan and billing** から管理します。**Current plan** の行にある **Manage subscription** を選ぶと、Paddle のカスタマーポータルが新しいタブで開きます。ポータルでは次のことができます。 + +- サブスクリプションを**解約**する。更新が止まり、支払い済みの期間の終わりまでプランはそのまま使えます。その後、組織は Free に戻り、何も削除されません([ダウングレード](#downgrading))。 +- **支払い方法**を更新する。 +- **取引**を確認し、**請求書**をダウンロードする。 + +サブスクリプションの期間中、**Home** の **Plan and usage** カードには、オーナーと管理者に向けて **Next charge:** とその日付が表示されます。解約後は **Cancels at period end:** と、プランが終了する日が表示されます。 + +**Manage subscription** が表示されるのは Team プランで、オーナーと管理者に対して、オンライン決済が利用できるようになってからです。請求書払いのプランには管理するオンラインのサブスクリプションがありません。Business と Enterprise にはこのボタンが表示されず、請求書払いの Team プランではサブスクリプションがないという応答が返ります。こうしたプランの変更や解約は [sales@objectos.ai](mailto:sales@objectos.ai) にご連絡ください。 + +## AI シートを変更する [#change-ai-seats] + +コンソールではまだ AI シートの数を変更できず、カスタマーポータルでもシート数とプランは変更できません。AI シートを追加または削減するには、オーナーまたは管理者が、組織と必要なシート数を添えて [sales@objectos.ai](mailto:sales@objectos.ai) に連絡してください。私たちがサブスクリプション上で変更します。変更後は、AI 利用枠、開発環境のプール、シートの割り当て上限のすべてが新しい数に従います。 + +## 支払い、請求書、返金 [#payment-invoices-and-refunds] + +コンソールでの購入(Team プランと [AI クレジットパック](/docs/cloud/ai-credits-and-limits#buy-ai-credits))は、私たちの再販業者であり Merchant of Record である **Paddle.com** が販売します。Paddle がチェックアウトを運営し、売上税や VAT を計算し、領収書と請求書を発行します。そのため、カードの利用明細と領収書には ObjectOS ではなく **Paddle** と表示されます。請求書はカスタマーポータルにあります([サブスクリプションを管理する](#manage-your-subscription))。 + +支払いが返金される条件と申請の方法は、www.objectos.ai の[返金・解約ポリシー](https://www.objectos.ai/en/refunds/)に記載されています。 + ## プランに含まれないものを確認する [#see-what-your-plan-leaves-out] コンソールの 2 か所で、営業ページを挟まずに確認できます。 diff --git a/content/docs/cloud/plans-and-seats.zh-Hans.mdx b/content/docs/cloud/plans-and-seats.zh-Hans.mdx index 5a6b4c08..06a5ee57 100644 --- a/content/docs/cloud/plans-and-seats.zh-Hans.mdx +++ b/content/docs/cloud/plans-and-seats.zh-Hans.mdx @@ -1,10 +1,10 @@ --- title: 套餐与 AI 席位 seoTitle: "ObjectOS Cloud 套餐:Free、Team、Enterprise 与 AI 席位" -description: ObjectOS Cloud 的套餐 —— Free、Team 和 Enterprise —— AI 席位是唯一付费的席位、如何升级,以及控制台在哪里显示你的套餐不包含什么。 +description: ObjectOS Cloud 的套餐 —— Free、Team 和 Enterprise —— AI 席位是唯一付费的席位、如何升级、取消或更改席位、由谁向你收费,以及控制台在哪里显示你的套餐不包含什么。 editions: [cloud] translation: - source_sha: c5f15cf821325b61b91091b0b7377b4a9750dc285a87202f969b73eae1eb8b97 + source_sha: 41b6faf0d1fed03c46a9c06784f4e33f6543c6e69088b25627a0d7e6c9eb989d guide_rev: 1 mode: auto --- @@ -37,7 +37,7 @@ ObjectOS Cloud 处于[公开预览](/docs/editions/public-preview)阶段: 席位。没有 AI 席位的成员、只读用户,以及通过自己的 AI 客户端经 [MCP](/docs/configure/mcp) 构建的开发者,都不收费。 -你购买的 AI 席位数量是组织的一项设置,在结账时选定,之后可以更改。它决定 +你购买的 AI 席位数量是组织的一项设置,在结账时选定,[之后可以更改](#change-ai-seats)。它决定 三件事的规模: - 组织的 **AI 额度**,按席位计算 @@ -64,6 +64,28 @@ ObjectOS Cloud 处于[公开预览](/docs/editions/public-preview)阶段: Enterprise 由销售协助:在 **Billing** 的 Enterprise 一列点击 **Contact sales**。 +## 管理你的订阅 [#manage-your-subscription] + +通过在线结账购买的 Team 套餐是一项订阅,由所有者或管理员在某个环境的 **Settings → Plan and billing** 中管理:**Current plan** 一行上的 **Manage subscription** 会在新标签页中打开 Paddle 的客户门户。在门户中你可以: + +- **取消**订阅。订阅不再续费,套餐保留到你已付费周期的结束;之后组织回到 Free,不会删除任何内容([降级](#downgrading)); +- 更新**付款方式**; +- 查看你的**交易记录**并下载**发票**。 + +订阅期间,**Home** 上的 **Plan and usage** 卡片会向所有者和管理员显示 **Next charge:** 及其日期;取消之后,它显示 **Cancels at period end:** 以及套餐结束的日期。 + +**Manage subscription** 只在 Team 套餐上、在在线支付开放后提供给所有者和管理员。按发票计费的套餐没有可管理的在线订阅:Business 和 Enterprise 从不显示该按钮,按发票计费的 Team 套餐会答复它没有在线订阅。此类套餐的更改或取消请通过 [sales@objectos.ai](mailto:sales@objectos.ai) 联系我们。 + +## 更改 AI 席位 [#change-ai-seats] + +控制台目前还不能更改 AI 席位数量,客户门户既不能更改席位数量,也不能更改套餐。要增加或减少 AI 席位,由所有者或管理员写信到 [sales@objectos.ai](mailto:sales@objectos.ai),说明组织以及它应有的席位数量,我们会在你的订阅上进行更改。更改之后,AI 额度、开发环境池以及席位分配上限都会随新的数量变化。 + +## 付款、发票与退款 [#payment-invoices-and-refunds] + +控制台中的购买 —— Team 套餐和 [AI 点数包](/docs/cloud/ai-credits-and-limits#buy-ai-credits) —— 由我们的经销商和记录商户(Merchant of Record)**Paddle.com** 售卖。Paddle 负责结账、计算任何销售税或增值税,并开具收据和发票,因此你的银行卡账单上的扣款和收据显示的是 **Paddle**,而不是 ObjectOS。发票在客户门户中([管理你的订阅](#manage-your-subscription))。 + +款项何时可以退款以及如何申请,见 www.objectos.ai 上的[退款与取消政策](https://www.objectos.ai/en/refunds/)。 + ## 查看你的套餐不包含什么 [#see-what-your-plan-leaves-out] 控制台中有两个地方会告诉你,中间无需经过销售页面: diff --git a/content/docs/cloud/plans-and-seats.zh-Hant.mdx b/content/docs/cloud/plans-and-seats.zh-Hant.mdx index 12da902e..4f457384 100644 --- a/content/docs/cloud/plans-and-seats.zh-Hant.mdx +++ b/content/docs/cloud/plans-and-seats.zh-Hant.mdx @@ -2,10 +2,10 @@ # @generated zh-Hant from zh-Hans -- do not edit. Edit the English source, then regenerate: pnpm --filter @objectos/docs gen:zh-hant title: 套餐與 AI 席位 seoTitle: "ObjectOS Cloud 套餐:Free、Team、Enterprise 與 AI 席位" -description: ObjectOS Cloud 的套餐 —— Free、Team 和 Enterprise —— AI 席位是唯一付費的席位、如何升級,以及控制台在哪裡顯示你的套餐不包含什麼。 +description: ObjectOS Cloud 的套餐 —— Free、Team 和 Enterprise —— AI 席位是唯一付費的席位、如何升級、取消或更改席位、由誰向你收費,以及控制台在哪裡顯示你的套餐不包含什麼。 editions: [cloud] translation: - source_sha: c5f15cf821325b61b91091b0b7377b4a9750dc285a87202f969b73eae1eb8b97 + source_sha: 41b6faf0d1fed03c46a9c06784f4e33f6543c6e69088b25627a0d7e6c9eb989d guide_rev: 1 mode: auto --- @@ -38,7 +38,7 @@ ObjectOS Cloud 處於[公開預覽](/docs/editions/public-preview)階段: 席位。沒有 AI 席位的成員、只讀使用者,以及通過自己的 AI 客戶端經 [MCP](/docs/configure/mcp) 構建的開發者,都不收費。 -你購買的 AI 席位數量是組織的一項設定,在結賬時選定,之後可以更改。它決定 +你購買的 AI 席位數量是組織的一項設定,在結賬時選定,[之後可以更改](#change-ai-seats)。它決定 三件事的規模: - 組織的 **AI 額度**,按席位計算 @@ -65,6 +65,28 @@ ObjectOS Cloud 處於[公開預覽](/docs/editions/public-preview)階段: Enterprise 由銷售協助:在 **Billing** 的 Enterprise 一列點選 **Contact sales**。 +## 管理你的訂閱 [#manage-your-subscription] + +通過線上結賬購買的 Team 套餐是一項訂閱,由所有者或管理員在某個環境的 **Settings → Plan and billing** 中管理:**Current plan** 一行上的 **Manage subscription** 會在新標籤頁中開啟 Paddle 的客戶門戶。在門戶中你可以: + +- **取消**訂閱。訂閱不再續費,套餐保留到你已付費週期的結束;之後組織回到 Free,不會刪除任何內容([降級](#downgrading)); +- 更新**付款方式**; +- 檢視你的**交易記錄**並下載**發票**。 + +訂閱期間,**Home** 上的 **Plan and usage** 卡片會向所有者和管理員顯示 **Next charge:** 及其日期;取消之後,它顯示 **Cancels at period end:** 以及套餐結束的日期。 + +**Manage subscription** 只在 Team 套餐上、在線上支付開放後提供給所有者和管理員。按發票計費的套餐沒有可管理的線上訂閱:Business 和 Enterprise 從不顯示該按鈕,按發票計費的 Team 套餐會答覆它沒有線上訂閱。此類套餐的更改或取消請通過 [sales@objectos.ai](mailto:sales@objectos.ai) 聯絡我們。 + +## 更改 AI 席位 [#change-ai-seats] + +控制台目前還不能更改 AI 席位數量,客戶門戶既不能更改席位數量,也不能更改套餐。要增加或減少 AI 席位,由所有者或管理員寫信到 [sales@objectos.ai](mailto:sales@objectos.ai),說明組織以及它應有的席位數量,我們會在你的訂閱上進行更改。更改之後,AI 額度、開發環境池以及席位分配上限都會隨新的數量變化。 + +## 付款、發票與退款 [#payment-invoices-and-refunds] + +控制台中的購買 —— Team 套餐和 [AI 點數包](/docs/cloud/ai-credits-and-limits#buy-ai-credits) —— 由我們的經銷商和記錄商戶(Merchant of Record)**Paddle.com** 售賣。Paddle 負責結賬、計算任何銷售稅或增值稅,並開具收據和發票,因此你的銀行卡賬單上的扣款和收據顯示的是 **Paddle**,而不是 ObjectOS。發票在客戶門戶中([管理你的訂閱](#manage-your-subscription))。 + +款項何時可以退款以及如何申請,見 www.objectos.ai 上的[退款與取消政策](https://www.objectos.ai/en/refunds/)。 + ## 檢視你的套餐不包含什麼 [#see-what-your-plan-leaves-out] 控制台中有兩個地方會告訴你,中間無需經過銷售頁面: diff --git a/content/docs/editions/license.ja.mdx b/content/docs/editions/license.ja.mdx index 7cb56e42..73c52566 100644 --- a/content/docs/editions/license.ja.mdx +++ b/content/docs/editions/license.ja.mdx @@ -3,7 +3,7 @@ title: ライセンスと料金 description: ObjectOS は 3 つのエディションを持つひとつの製品です。Community(オープンソース、無料)、Cloud、Enterprise。それぞれのライセンス形態と、ObjectStack フレームワークとの関係を説明します。 editions: [community, cloud, enterprise] translation: - source_sha: 8214fa1bad828f1ed43938ca72f4a791acb69e4bdb82a1e015eec4e78d2d1128 + source_sha: d526aff1a5e15ece6edf6d7c4a0f01127d620227c07d322183728d081c36444e guide_rev: 1 mode: auto --- @@ -33,13 +33,13 @@ ObjectOS Community は無料です。2 つの商用エディションには、 |---|---|---|---|---| | エディション | ObjectOS Community | ObjectOS Cloud | ObjectOS Cloud | ObjectOS Enterprise | | 提供形態 | **セルフマネージド** | クラウド | クラウド | **セルフマネージド(プライベートデプロイ)** | -| 料金 | **無料**(Apache-2.0) | **無料** | **$24** / AI シート / 月 | 個別見積もり(ボリューム):[営業にお問い合わせください](mailto:sales@objectstack.ai) | +| 料金 | **無料**(Apache-2.0) | **無料** | **$24** / AI シート / 月 | 個別見積もり(ボリューム):[営業にお問い合わせください](mailto:sales@objectos.ai) | | UI 内の AI(AI Builder +「データに質問する」) | MCP のみ(モデルは持ち込み) | お試し | ✓ | ✓ | | AI ガバナンス(アクションの監査、ガードレール、権限のスコープ設定) | — | — | — | ✓ | | クラスタリング / HA、マルチ組織のセルフホスト、エアギャップ、SCIM | — | — | — | ✓ | | サポート | コミュニティ | コミュニティ | スタンダード | SLA + 専任 | -Team とフルのプライベートデプロイの間には、**ObjectOS Enterprise の下の 2 つの契約オプション**があり、料金はこれまでどおりです。**Business**(ObjectOS Cloud 上の SSO と AI ガバナンス、**$54** / AI シート / 月、年額払いでは $45 / AI シート / 月。優先サポート)と **Business Self-Managed**(シングルノードのエントリーオプション、**$540** / AI シート / 年)です。どちらも契約により販売されます。[営業にお問い合わせください](mailto:sales@objectstack.ai)。 +Team とフルのプライベートデプロイの間には、**ObjectOS Enterprise の下の 2 つの契約オプション**があり、料金はこれまでどおりです。**Business**(ObjectOS Cloud 上の SSO と AI ガバナンス、**$54** / AI シート / 月、年額払いでは $45 / AI シート / 月。優先サポート)と **Business Self-Managed**(シングルノードのエントリーオプション、**$540** / AI シート / 年)です。どちらも契約により販売されます。[営業にお問い合わせください](mailto:sales@objectos.ai)。 **無料で**セルフホストしたいですか?それが **ObjectOS Community** です(MCP のみの AI:モデルは持ち込み)。下の [ObjectOS Community](#objectos-community) を参照してください。 @@ -55,7 +55,7 @@ Team とフルのプライベートデプロイの間には、**ObjectOS Enterpr - **Enterprise**:契約により販売されるライセンス制の ObjectOS で、3 つの形があります。 - **Business**:ObjectOS Cloud 上の契約オプション。ホスト型サービス上の SSO / SAML と AI ガバナンス(アクションの監査、ガードレール、権限のスコープ設定)、$54 / AI シート / 月、または年額払いで $45 / AI シート / 月、優先サポート。 - **Business Self-Managed**:シングルノードのエントリーオプション。Business プランを **10〜25 AI シート**向けの**シングルノード Docker ライセンス**として提供します($540/AI シート/年、年額)。自社のインフラストラクチャ上で UI 内の AI と AI ガバナンスを利用でき、**モデル / キーは持ち込み**です(LLM のコストは自分で支払います。プラットフォームの AI 請求や従量課金はありません)。カード払い、スタンダードサポート。ライセンスが失効しても、ランタイムは動作し続け、データはそのまま残ります。有料機能がオフになるだけです(使えなくなることは決してありません)。 - - **フルのプライベートデプロイ**:それを超えるすべてのもの。クラスタリング / HA / マルチノード、マルチ組織のセルフホスト、データレジデンシーと**エアギャップ**運用、SCIM と ID ライフサイクル、コンプライアンスの証明、SLA と専任サポート、オフライン / 請求書払い。複数年の価格固定オプション付きの**年間ライセンス**として販売されます。更新しない場合、デプロイは**最後に支払ったバージョンを永続的に維持**します(失うのはアップデートとサポートであり、システムやデータではありません)。料金はボリュームベースです。[営業にお問い合わせください](mailto:sales@objectstack.ai)。 + - **フルのプライベートデプロイ**:それを超えるすべてのもの。クラスタリング / HA / マルチノード、マルチ組織のセルフホスト、データレジデンシーと**エアギャップ**運用、SCIM と ID ライフサイクル、コンプライアンスの証明、SLA と専任サポート、オフライン / 請求書払い。複数年の価格固定オプション付きの**年間ライセンス**として販売されます。更新しない場合、デプロイは**最後に支払ったバージョンを永続的に維持**します(失うのはアップデートとサポートであり、システムやデータではありません)。料金はボリュームベースです。[営業にお問い合わせください](mailto:sales@objectos.ai)。 **ノードごとの課金はありません**。クラスタリング / スケールは Enterprise に含まれます。 @@ -67,9 +67,9 @@ Team とフルのプライベートデプロイの間には、**ObjectOS Enterpr | ホスト型サービスで **SSO と AI ガバナンス**が必要 | **Business**、ObjectOS Cloud 上の ObjectOS Enterprise の契約オプション | | **自社のシングルノード**で実行しなければならず、製品内の AI が欲しい、25 AI シート以下 | **Business Self-Managed**、ObjectOS Enterprise の契約オプション(シングルノードのエントリー) | | **クラスタリング / HA**、**マルチ組織**、**エアギャップ**、**SCIM**、コンプライアンスの証明、SLA、オフライン払いが必要 | **ObjectOS Enterprise**、フルのプライベートデプロイ | -| ObjectOS Community をセルフホストしているが、**商用契約付きのサポートされたディストリビューション**(SLA、セキュリティパッチの優先対応、指名エスカレーション)が必要 | **ObjectOS Runtime Subscription**:[営業にお問い合わせください](mailto:sales@objectstack.ai) | +| ObjectOS Community をセルフホストしているが、**商用契約付きのサポートされたディストリビューション**(SLA、セキュリティパッチの優先対応、指名エスカレーション)が必要 | **ObjectOS Runtime Subscription**:[営業にお問い合わせください](mailto:sales@objectos.ai) | | **無料のセルフホスト**で、MCP 経由で AI を持ち込みたい | **ObjectOS Community**(オープンソース) | -| ObjectOS または ObjectStack の名前で **OEM / 再配布**の権利が必要 | 商用契約:[営業にお問い合わせください](mailto:sales@objectstack.ai) | +| ObjectOS または ObjectStack の名前で **OEM / 再配布**の権利が必要 | 商用契約:[営業にお問い合わせください](mailto:sales@objectos.ai) | ## ObjectOS Community [#objectos-community] @@ -111,7 +111,7 @@ ObjectOS Enterprise はライセンスをオンラインで検証します。エ ### ObjectOS Community に契約上の保証が欲しい場合は? [#what-if-i-want-a-contractual-warranty-on-objectos-community] -それが **ObjectOS Runtime Subscription** です。ObjectOS Community に対するサポート契約(公式ディストリビューション、SLA、セキュリティパッチの優先対応)で、機能の違いはまったくありません。[sales@objectstack.ai](mailto:sales@objectstack.ai) にお問い合わせください。 +それが **ObjectOS Runtime Subscription** です。ObjectOS Community に対するサポート契約(公式ディストリビューション、SLA、セキュリティパッチの優先対応)で、機能の違いはまったくありません。[sales@objectos.ai](mailto:sales@objectos.ai) にお問い合わせください。 ### ObjectOS Community とフレームワークはずっと無料ですか? [#will-objectos-community-and-the-framework-always-be-free] diff --git a/content/docs/editions/license.zh-Hans.mdx b/content/docs/editions/license.zh-Hans.mdx index bd47cf1b..6b162d70 100644 --- a/content/docs/editions/license.zh-Hans.mdx +++ b/content/docs/editions/license.zh-Hans.mdx @@ -3,7 +3,7 @@ title: 许可与定价 description: ObjectOS 是一个产品、三个版本 —— Community(开源,免费)、Cloud 和 Enterprise —— 每个版本如何授权,以及它们与 ObjectStack 框架的关系。 editions: [community, cloud, enterprise] translation: - source_sha: 8214fa1bad828f1ed43938ca72f4a791acb69e4bdb82a1e015eec4e78d2d1128 + source_sha: d526aff1a5e15ece6edf6d7c4a0f01127d620227c07d322183728d081c36444e guide_rev: 1 mode: auto --- @@ -44,7 +44,7 @@ ObjectOS Community 免费。两个商业版本使用一张价目表、两种交 |---|---|---|---|---| | 版本 | ObjectOS Community | ObjectOS Cloud | ObjectOS Cloud | ObjectOS Enterprise | | 交付方式 | **自管理** | 云 | 云 | **自管理(私有部署)** | -| 价格 | **免费**(Apache-2.0) | **免费** | **24 美元** / AI 席位 / 月 | 定制(按量)—— [联系销售](mailto:sales@objectstack.ai) | +| 价格 | **免费**(Apache-2.0) | **免费** | **24 美元** / AI 席位 / 月 | 定制(按量)—— [联系销售](mailto:sales@objectos.ai) | | UI 内 AI(AI Builder + "问你的数据") | 仅 MCP(自带模型) | 体验版 | ✓ | ✓ | | AI 治理(动作审计、护栏、权限范围限定) | — | — | — | ✓ | | 集群 / 高可用、多组织自托管、物理隔离、SCIM | — | — | — | ✓ | @@ -54,7 +54,7 @@ ObjectOS Community 免费。两个商业版本使用一张价目表、两种交 选项**,价格不变:**Business**(ObjectOS Cloud 上的 SSO 和 AI 治理, **54 美元** / AI 席位 / 月,按年付费为 45 美元 / AI 席位 / 月;优先支持) 和 **Business Self-Managed**(单节点入门选项,**540 美元** / AI 席位 / 年)。 -两者都按合同销售 —— [联系销售](mailto:sales@objectstack.ai)。 +两者都按合同销售 —— [联系销售](mailto:sales@objectos.ai)。 想**免费**自托管?那就是 **ObjectOS Community**(仅 MCP 的 AI:自带模型)。 参见下文的 [ObjectOS Community](#objectos-community)。 @@ -91,7 +91,7 @@ Enterprise**(需许可)。云是 Free 和 Team;Team 之上的一切都是 证明、SLA 和专属支持,以及线下 / 发票付款。以**年度许可证**销售,可选 多年锁价;不续约时,你的部署会**永久保留最后一个已付费的版本**(你失去 的是更新和支持,绝不是你的系统或数据)。价格按量计算 —— - [联系销售](mailto:sales@objectstack.ai)。 + [联系销售](mailto:sales@objectos.ai)。 **不按节点收费** —— 集群 / 扩展已包含在 Enterprise 中。 @@ -103,9 +103,9 @@ Enterprise**(需许可)。云是 Free 和 Team;Team 之上的一切都是 | 你需要托管服务上的 **SSO 和 AI 治理** | **Business**,ObjectOS Enterprise 在 ObjectOS Cloud 上的合同选项 | | 你必须在**你自己的单个节点**上运行,并且想要产品内 AI,AI 席位 ≤25 个 | **Business Self-Managed**,ObjectOS Enterprise 的合同选项(单节点入门) | | 你需要**集群 / 高可用**、**多组织**、**物理隔离**、**SCIM**、合规证明、SLA 或线下付款 | **ObjectOS Enterprise**,完整私有部署 | -| 你自托管 ObjectOS Community,但需要一个**带商业合同的受支持发行版**(SLA、安全补丁优先、指定升级渠道) | **ObjectOS Runtime Subscription** —— [联系销售](mailto:sales@objectstack.ai) | +| 你自托管 ObjectOS Community,但需要一个**带商业合同的受支持发行版**(SLA、安全补丁优先、指定升级渠道) | **ObjectOS Runtime Subscription** —— [联系销售](mailto:sales@objectos.ai) | | 你想要**免费自托管**,并通过 MCP 自带 AI | **ObjectOS Community**(开源) | -| 你需要以 ObjectOS 或 ObjectStack 名义进行 **OEM / 再分发**的权利 | 商业协议 —— [联系销售](mailto:sales@objectstack.ai) | +| 你需要以 ObjectOS 或 ObjectStack 名义进行 **OEM / 再分发**的权利 | 商业协议 —— [联系销售](mailto:sales@objectos.ai) | ## ObjectOS Community [#objectos-community] @@ -178,7 +178,7 @@ ObjectOS Enterprise 会在线校验许可证;物理隔离的 Enterprise 许可 那就是 **ObjectOS Runtime Subscription** —— 针对 ObjectOS Community 的 支持合同(官方发行版、SLA、安全补丁优先),功能上没有任何差别。请联系 -[sales@objectstack.ai](mailto:sales@objectstack.ai)。 +[sales@objectos.ai](mailto:sales@objectos.ai)。 ### ObjectOS Community 和框架会一直免费吗? [#will-objectos-community-and-the-framework-always-be-free] diff --git a/content/docs/editions/license.zh-Hant.mdx b/content/docs/editions/license.zh-Hant.mdx index 64e07135..b744c0e4 100644 --- a/content/docs/editions/license.zh-Hant.mdx +++ b/content/docs/editions/license.zh-Hant.mdx @@ -4,7 +4,7 @@ title: 許可與定價 description: ObjectOS 是一個產品、三個版本 —— Community(開源,免費)、Cloud 和 Enterprise —— 每個版本如何授權,以及它們與 ObjectStack 框架的關係。 editions: [community, cloud, enterprise] translation: - source_sha: 8214fa1bad828f1ed43938ca72f4a791acb69e4bdb82a1e015eec4e78d2d1128 + source_sha: d526aff1a5e15ece6edf6d7c4a0f01127d620227c07d322183728d081c36444e guide_rev: 1 mode: auto --- @@ -45,7 +45,7 @@ ObjectOS Community 免費。兩個商業版本使用一張價目表、兩種交 |---|---|---|---|---| | 版本 | ObjectOS Community | ObjectOS Cloud | ObjectOS Cloud | ObjectOS Enterprise | | 交付方式 | **自管理** | 雲 | 雲 | **自管理(私有部署)** | -| 價格 | **免費**(Apache-2.0) | **免費** | **24 美元** / AI 席位 / 月 | 定製(按量)—— [聯絡銷售](mailto:sales@objectstack.ai) | +| 價格 | **免費**(Apache-2.0) | **免費** | **24 美元** / AI 席位 / 月 | 定製(按量)—— [聯絡銷售](mailto:sales@objectos.ai) | | UI 內 AI(AI Builder + "問你的資料") | 僅 MCP(自帶模型) | 體驗版 | ✓ | ✓ | | AI 治理(動作審計、護欄、許可權範圍限定) | — | — | — | ✓ | | 叢集 / 高可用、多組織自託管、物理隔離、SCIM | — | — | — | ✓ | @@ -55,7 +55,7 @@ ObjectOS Community 免費。兩個商業版本使用一張價目表、兩種交 選項**,價格不變:**Business**(ObjectOS Cloud 上的 SSO 和 AI 治理, **54 美元** / AI 席位 / 月,按年付費為 45 美元 / AI 席位 / 月;優先支援) 和 **Business Self-Managed**(單節點入門選項,**540 美元** / AI 席位 / 年)。 -兩者都按合同銷售 —— [聯絡銷售](mailto:sales@objectstack.ai)。 +兩者都按合同銷售 —— [聯絡銷售](mailto:sales@objectos.ai)。 想**免費**自託管?那就是 **ObjectOS Community**(僅 MCP 的 AI:自帶模型)。 參見下文的 [ObjectOS Community](#objectos-community)。 @@ -92,7 +92,7 @@ Enterprise**(需許可)。雲是 Free 和 Team;Team 之上的一切都是 證明、SLA 和專屬支援,以及線下 / 發票付款。以**年度許可證**銷售,可選 多年鎖價;不續約時,你的部署會**永久保留最後一個已付費的版本**(你失去 的是更新和支援,絕不是你的系統或資料)。價格按量計算 —— - [聯絡銷售](mailto:sales@objectstack.ai)。 + [聯絡銷售](mailto:sales@objectos.ai)。 **不按節點收費** —— 叢集 / 擴充套件已包含在 Enterprise 中。 @@ -104,9 +104,9 @@ Enterprise**(需許可)。雲是 Free 和 Team;Team 之上的一切都是 | 你需要託管服務上的 **SSO 和 AI 治理** | **Business**,ObjectOS Enterprise 在 ObjectOS Cloud 上的合同選項 | | 你必須在**你自己的單個節點**上執行,並且想要產品內 AI,AI 席位 ≤25 個 | **Business Self-Managed**,ObjectOS Enterprise 的合同選項(單節點入門) | | 你需要**叢集 / 高可用**、**多組織**、**物理隔離**、**SCIM**、合規證明、SLA 或線下付款 | **ObjectOS Enterprise**,完整私有部署 | -| 你自託管 ObjectOS Community,但需要一個**帶商業合同的受支援發行版**(SLA、安全補丁優先、指定升級渠道) | **ObjectOS Runtime Subscription** —— [聯絡銷售](mailto:sales@objectstack.ai) | +| 你自託管 ObjectOS Community,但需要一個**帶商業合同的受支援發行版**(SLA、安全補丁優先、指定升級渠道) | **ObjectOS Runtime Subscription** —— [聯絡銷售](mailto:sales@objectos.ai) | | 你想要**免費自託管**,並通過 MCP 自帶 AI | **ObjectOS Community**(開源) | -| 你需要以 ObjectOS 或 ObjectStack 名義進行 **OEM / 再分發**的權利 | 商業協議 —— [聯絡銷售](mailto:sales@objectstack.ai) | +| 你需要以 ObjectOS 或 ObjectStack 名義進行 **OEM / 再分發**的權利 | 商業協議 —— [聯絡銷售](mailto:sales@objectos.ai) | ## ObjectOS Community [#objectos-community] @@ -179,7 +179,7 @@ ObjectOS Enterprise 會線上校驗許可證;物理隔離的 Enterprise 許可 那就是 **ObjectOS Runtime Subscription** —— 針對 ObjectOS Community 的 支援合同(官方發行版、SLA、安全補丁優先),功能上沒有任何差別。請聯絡 -[sales@objectstack.ai](mailto:sales@objectstack.ai)。 +[sales@objectos.ai](mailto:sales@objectos.ai)。 ### ObjectOS Community 和框架會一直免費嗎? [#will-objectos-community-and-the-framework-always-be-free] diff --git a/content/docs/resources/faq.ja.mdx b/content/docs/resources/faq.ja.mdx index 53131d11..f0d2fd33 100644 --- a/content/docs/resources/faq.ja.mdx +++ b/content/docs/resources/faq.ja.mdx @@ -4,7 +4,7 @@ seoTitle: "よくある質問:セットアップ、マルチテナンシー、 description: ObjectOS についてのよくある質問。はじめ方、データベースとマルチテナンシー、マイグレーション、権限、連携、運用、料金とライセンス。 editions: [community, cloud, enterprise] translation: - source_sha: a04083fa1854e4094b8d7487ba533efd4b0fdc6a14425451ab84b21f739465d7 + source_sha: 1095b17b298288a7fcb1561ef72947d7828f1253690f2039b169e403e6a48a8a guide_rev: 1 mode: auto --- @@ -175,4 +175,4 @@ ObjectOS は、どのフレームワークも求める**基本要素**(RBAC、 ### 人に助けてもらうには? [#where-do-i-get-help-from-humans] -[GitHub Issues](https://github.com/objectstack-ai/objectstack/issues)、コミュニティの Discord、または商用サポートなら **sales@objectstack.ai** へ。 +[GitHub Issues](https://github.com/objectstack-ai/objectstack/issues)、コミュニティの Discord、または商用サポートなら **sales@objectos.ai** へ。 diff --git a/content/docs/resources/faq.zh-Hans.mdx b/content/docs/resources/faq.zh-Hans.mdx index da20d042..9387e88b 100644 --- a/content/docs/resources/faq.zh-Hans.mdx +++ b/content/docs/resources/faq.zh-Hans.mdx @@ -4,7 +4,7 @@ seoTitle: "常见问题:上手、多租户、定价和许可" description: 关于 ObjectOS 的常见问题 —— 上手、数据库与多租户、迁移、权限、集成、运维、定价和许可。 editions: [community, cloud, enterprise] translation: - source_sha: a04083fa1854e4094b8d7487ba533efd4b0fdc6a14425451ab84b21f739465d7 + source_sha: 1095b17b298288a7fcb1561ef72947d7828f1253690f2039b169e403e6a48a8a guide_rev: 1 mode: auto --- @@ -245,4 +245,4 @@ ObjectOS 提供每个框架都要求的**原语**(RBAC、审计、可加密、 ### 我在哪里能得到真人的帮助? [#where-do-i-get-help-from-humans] [GitHub Issues](https://github.com/objectstack-ai/objectstack/issues)、社区 Discord, -或者联系 **sales@objectstack.ai** 获取商业支持。 +或者联系 **sales@objectos.ai** 获取商业支持。 diff --git a/content/docs/resources/faq.zh-Hant.mdx b/content/docs/resources/faq.zh-Hant.mdx index d5285fa3..27f1a4a2 100644 --- a/content/docs/resources/faq.zh-Hant.mdx +++ b/content/docs/resources/faq.zh-Hant.mdx @@ -5,7 +5,7 @@ seoTitle: "常見問題:上手、多租戶、定價和許可" description: 關於 ObjectOS 的常見問題 —— 上手、資料庫與多租戶、遷移、許可權、整合、運維、定價和許可。 editions: [community, cloud, enterprise] translation: - source_sha: a04083fa1854e4094b8d7487ba533efd4b0fdc6a14425451ab84b21f739465d7 + source_sha: 1095b17b298288a7fcb1561ef72947d7828f1253690f2039b169e403e6a48a8a guide_rev: 1 mode: auto --- @@ -246,4 +246,4 @@ ObjectOS 提供每個框架都要求的**原語**(RBAC、審計、可加密、 ### 我在哪裡能得到真人的幫助? [#where-do-i-get-help-from-humans] [GitHub Issues](https://github.com/objectstack-ai/objectstack/issues)、社群 Discord, -或者聯絡 **sales@objectstack.ai** 獲取商業支援。 +或者聯絡 **sales@objectos.ai** 獲取商業支援。 diff --git a/content/docs/resources/support.ja.mdx b/content/docs/resources/support.ja.mdx index 64477178..84456ff5 100644 --- a/content/docs/resources/support.ja.mdx +++ b/content/docs/resources/support.ja.mdx @@ -4,7 +4,7 @@ seoTitle: "サポート:ヘルプ、バグの報告、応答時間" description: どこでヘルプを得るか、バグをどう報告するか、応答の目安。 editions: [community, cloud, enterprise] translation: - source_sha: c91dd5746f73af07b73d9af2e79272ab63df7883b882a67dfcc6329bbc1ffc1a + source_sha: a5293e7259dddd10f95c9ec48a390183bfd2ef049e3391376119ff66c2c59203 guide_rev: 1 mode: auto --- @@ -17,10 +17,10 @@ translation: | バグを見つけた | [GitHub Issues](https://github.com/objectstack-ai/objectstack/issues):バージョン、再現手順、期待した結果と実際の結果を含めてください | | このドキュメントの誤りを見つけた | [docs.objectos.ai の issues](https://github.com/objectstack-ai/docs.objectos.ai/issues):このサイト自身のリポジトリは、ドキュメントの issue だけを受け付けます | | セキュリティの脆弱性を見つけた | **security@objectstack.ai**:公開の issue は作成**しないでください** | -| 商用サポート / SLA が必要 | **sales@objectstack.ai** | +| 商用サポート / SLA が必要 | **sales@objectos.ai** | | ユーザーやメンテナーと話したい | [Discord](https://discord.gg/objectstack)(コミュニティ運営) | | リリースを追いたい | [リリースノート](/docs/resources/changelog#release-notes):各リリースが公開される場所です。通知を受け取るには、[github.com/objectstack-ai/objectstack](https://github.com/objectstack-ai/objectstack) → Releases を Watch してください | -| 有償で機能を実装してほしい | **sales@objectstack.ai**:[商用サポートとサービス](#commercial-support--services)を参照してください | +| 有償で機能を実装してほしい | **sales@objectos.ai**:[商用サポートとサービス](#commercial-support--services)を参照してください | ## よいバグ報告の書き方 [#filing-a-good-bug-report] @@ -60,7 +60,7 @@ ObjectStack チームから提供されるもの: - 仕様に合わせて構築する**カスタムのプラグイン / 機能**。 - **OEM 再配布**:ObjectOS を自社の製品に組み込みます。 -**sales@objectstack.ai** にお問い合わせください。 +**sales@objectos.ai** にお問い合わせください。 ## 貢献する [#contributing-back] diff --git a/content/docs/resources/support.zh-Hans.mdx b/content/docs/resources/support.zh-Hans.mdx index c676f83c..99db6d2d 100644 --- a/content/docs/resources/support.zh-Hans.mdx +++ b/content/docs/resources/support.zh-Hans.mdx @@ -4,7 +4,7 @@ seoTitle: "支持:获取帮助、报告缺陷、响应时间" description: 去哪里获取帮助、如何报告缺陷,以及响应预期。 editions: [community, cloud, enterprise] translation: - source_sha: c91dd5746f73af07b73d9af2e79272ab63df7883b882a67dfcc6329bbc1ffc1a + source_sha: a5293e7259dddd10f95c9ec48a390183bfd2ef049e3391376119ff66c2c59203 guide_rev: 1 mode: auto --- @@ -17,10 +17,10 @@ translation: | 发现了一个缺陷 | [GitHub Issues](https://github.com/objectstack-ai/objectstack/issues) —— 请附上版本、复现步骤、期望结果与实际结果 | | 发现了这些文档中的错误 | [docs.objectos.ai issues](https://github.com/objectstack-ai/docs.objectos.ai/issues) —— 本站自己的仓库只接受文档问题 | | 发现了一个安全漏洞 | **security@objectstack.ai** —— **不要**提交公开 issue | -| 需要商业支持 / SLA | **sales@objectstack.ai** | +| 需要商业支持 / SLA | **sales@objectos.ai** | | 想和用户及维护者交流 | [Discord](https://discord.gg/objectstack)(社区运营) | | 想关注版本发布 | [发布说明](/docs/resources/changelog#release-notes) —— 每个版本发布的地方;要接收通知,请 watch [github.com/objectstack-ai/objectstack](https://github.com/objectstack-ai/objectstack) → Releases | -| 想付费实现某个功能 | **sales@objectstack.ai** —— 参见[商业支持与服务](#commercial-support--services) | +| 想付费实现某个功能 | **sales@objectos.ai** —— 参见[商业支持与服务](#commercial-support--services) | ## 提交一份好的缺陷报告 [#filing-a-good-bug-report] @@ -61,7 +61,7 @@ ObjectStack 团队提供: - 按你的规格构建的**自定义插件 / 能力**。 - **OEM 再分发** —— 把 ObjectOS 嵌入你的产品。 -联系 **sales@objectstack.ai**。 +联系 **sales@objectos.ai**。 ## 回馈贡献 [#contributing-back] diff --git a/content/docs/resources/support.zh-Hant.mdx b/content/docs/resources/support.zh-Hant.mdx index 02be2816..b7242223 100644 --- a/content/docs/resources/support.zh-Hant.mdx +++ b/content/docs/resources/support.zh-Hant.mdx @@ -5,7 +5,7 @@ seoTitle: "支援:獲取幫助、報告缺陷、響應時間" description: 去哪裡獲取幫助、如何報告缺陷,以及響應預期。 editions: [community, cloud, enterprise] translation: - source_sha: c91dd5746f73af07b73d9af2e79272ab63df7883b882a67dfcc6329bbc1ffc1a + source_sha: a5293e7259dddd10f95c9ec48a390183bfd2ef049e3391376119ff66c2c59203 guide_rev: 1 mode: auto --- @@ -18,10 +18,10 @@ translation: | 發現了一個缺陷 | [GitHub Issues](https://github.com/objectstack-ai/objectstack/issues) —— 請附上版本、復現步驟、期望結果與實際結果 | | 發現了這些文件中的錯誤 | [docs.objectos.ai issues](https://github.com/objectstack-ai/docs.objectos.ai/issues) —— 本站自己的倉庫只接受文件問題 | | 發現了一個安全漏洞 | **security@objectstack.ai** —— **不要**提交公開 issue | -| 需要商業支援 / SLA | **sales@objectstack.ai** | +| 需要商業支援 / SLA | **sales@objectos.ai** | | 想和使用者及維護者交流 | [Discord](https://discord.gg/objectstack)(社群運營) | | 想關注版本釋出 | [釋出說明](/docs/resources/changelog#release-notes) —— 每個版本釋出的地方;要接收通知,請 watch [github.com/objectstack-ai/objectstack](https://github.com/objectstack-ai/objectstack) → Releases | -| 想付費實現某個功能 | **sales@objectstack.ai** —— 參見[商業支援與服務](#commercial-support--services) | +| 想付費實現某個功能 | **sales@objectos.ai** —— 參見[商業支援與服務](#commercial-support--services) | ## 提交一份好的缺陷報告 [#filing-a-good-bug-report] @@ -62,7 +62,7 @@ ObjectStack 團隊提供: - 按你的規格構建的**自定義外掛 / 能力**。 - **OEM 再分發** —— 把 ObjectOS 嵌入你的產品。 -聯絡 **sales@objectstack.ai**。 +聯絡 **sales@objectos.ai**。 ## 回饋貢獻 [#contributing-back] diff --git a/content/docs/start/enterprise.ja.mdx b/content/docs/start/enterprise.ja.mdx index f8538773..d03c5a7c 100644 --- a/content/docs/start/enterprise.ja.mdx +++ b/content/docs/start/enterprise.ja.mdx @@ -4,7 +4,7 @@ seoTitle: "ObjectOS Enterprise で始める:ライセンス制、セルフマ description: ObjectOS Enterprise は、自社のインフラストラクチャ上で実行するライセンス制のエディションです。ライセンスの入手方法と、デプロイガイドの出発点を説明します。 editions: [enterprise] translation: - source_sha: 65aa2affdd32ca612f967daaffd1275dc3cb60a61e72bd88b99c97ee9c0f11f2 + source_sha: 8c52a4becd892c980dae49189fc379a8f287109299a3350d1c2040a2595d33be guide_rev: 1 mode: auto --- @@ -13,7 +13,7 @@ translation: ## 1. ライセンスを入手する [#1-get-a-license] -ObjectOS Enterprise は契約により販売されます。[営業にお問い合わせください](mailto:sales@objectstack.ai)。ライセンスにはライセンスされた Enterprise イメージのレジストリ認証情報が付属し、各リリースのリリースノートには実行すべき正確なイメージダイジェストが記載されています。 +ObjectOS Enterprise は契約により販売されます。[営業にお問い合わせください](mailto:sales@objectos.ai)。ライセンスにはライセンスされた Enterprise イメージのレジストリ認証情報が付属し、各リリースのリリースノートには実行すべき正確なイメージダイジェストが記載されています。 ## 2. デプロイする [#2-deploy] diff --git a/content/docs/start/enterprise.zh-Hans.mdx b/content/docs/start/enterprise.zh-Hans.mdx index bc627415..fecf4cb4 100644 --- a/content/docs/start/enterprise.zh-Hans.mdx +++ b/content/docs/start/enterprise.zh-Hans.mdx @@ -4,7 +4,7 @@ seoTitle: "在 ObjectOS Enterprise 上开始:许可授权,自管理" description: ObjectOS Enterprise 是你在自己的基础设施上运行的许可版本 —— 如何获得许可证,以及部署指南从哪里开始。 editions: [enterprise] translation: - source_sha: 65aa2affdd32ca612f967daaffd1275dc3cb60a61e72bd88b99c97ee9c0f11f2 + source_sha: 8c52a4becd892c980dae49189fc379a8f287109299a3350d1c2040a2595d33be guide_rev: 1 mode: auto --- @@ -19,7 +19,7 @@ ObjectOS:产品内 AI、AI 治理和官方支持都在你自己的服务器上 ## 1. 获取许可证 [#1-get-a-license] ObjectOS Enterprise 按合同销售: -[联系销售](mailto:sales@objectstack.ai)。你的许可证附带获得许可的 +[联系销售](mailto:sales@objectos.ai)。你的许可证附带获得许可的 Enterprise 镜像的镜像仓库凭据,每个版本的发布说明都会注明要运行的确切 镜像摘要。 diff --git a/content/docs/start/enterprise.zh-Hant.mdx b/content/docs/start/enterprise.zh-Hant.mdx index fd437230..30931f0f 100644 --- a/content/docs/start/enterprise.zh-Hant.mdx +++ b/content/docs/start/enterprise.zh-Hant.mdx @@ -5,7 +5,7 @@ seoTitle: "在 ObjectOS Enterprise 上開始:許可授權,自管理" description: ObjectOS Enterprise 是你在自己的基礎設施上執行的許可版本 —— 如何獲得許可證,以及部署指南從哪裡開始。 editions: [enterprise] translation: - source_sha: 65aa2affdd32ca612f967daaffd1275dc3cb60a61e72bd88b99c97ee9c0f11f2 + source_sha: 8c52a4becd892c980dae49189fc379a8f287109299a3350d1c2040a2595d33be guide_rev: 1 mode: auto --- @@ -20,7 +20,7 @@ ObjectOS:產品內 AI、AI 治理和官方支援都在你自己的伺服器上 ## 1. 獲取許可證 [#1-get-a-license] ObjectOS Enterprise 按合同銷售: -[聯絡銷售](mailto:sales@objectstack.ai)。你的許可證附帶獲得許可的 +[聯絡銷售](mailto:sales@objectos.ai)。你的許可證附帶獲得許可的 Enterprise 映象的映象倉庫憑據,每個版本的釋出說明都會註明要執行的確切 映象摘要。 From 08e409ee3388fc5906972afab10aa3f83c218270 Mon Sep 17 00:00:00 2001 From: Steedos Date: Sun, 1 Nov 2026 07:13:45 +0000 Subject: [PATCH 14/22] docs(positioning): quote the README's three-edition sentence (#341) objectstack#26148 replaced the README sentence OBJECTOS_DEFINITION quoted ("...the commercial runtime environment built on this stack") with one naming three editions: ObjectOS Community, shipped by the repository, free and self-hosted; ObjectOS Cloud, hosted; ObjectOS Enterprise, self-managed and licensed. - OBJECTOS_DEFINITION quotes README lines 27-31 from "To run it", with three declared changes: "this repository" spelled out as "the ObjectStack repository", the Markdown dropped, and the in-README "(Ship it)" link left out. - OBJECTOS_EDITIONS keeps only the #171 Q2 export clause, naming Cloud and Enterprise instead of "either edition". - POSITIONING_SHORT (152 characters) names the three editions in the README's words. - The index.mdx opening paragraph and description follow, and the zh-Hans and ja siblings are re-translated and restamped; zh-Hant is regenerated. check-positioning passes after a build. Fixes #341 Claude-Session: https://claude.ai/code/session_01QsR2jRsjbApbf83iyTDDXm Co-Authored-By: Claude --- apps/docs/lib/positioning.ts | 51 +++++++++++++++++++++------------- content/docs/index.ja.mdx | 6 ++-- content/docs/index.mdx | 15 +++++----- content/docs/index.zh-Hans.mdx | 11 ++------ content/docs/index.zh-Hant.mdx | 11 ++------ 5 files changed, 49 insertions(+), 45 deletions(-) diff --git a/apps/docs/lib/positioning.ts b/apps/docs/lib/positioning.ts index 444a7d10..30e851da 100644 --- a/apps/docs/lib/positioning.ts +++ b/apps/docs/lib/positioning.ts @@ -3,8 +3,9 @@ * * ## Source of truth * - * `objectstack-ai/objectstack` `README.md` at `main`: lines 7-16 carry the - * headline and the four promises, lines 26-30 the sentence that defines ObjectOS. + * `objectstack-ai/objectstack` `README.md` at `main`: line 7 carries the + * headline, lines 9-10 the four promises, and lines 27-31 the sentence that + * names ObjectOS's three editions (objectstack#26148, docs.objectos.ai#341). * The maintainer's ruling of 2026-10-05 (objectos#171, Q4) makes that README the * single source of the positioning. This repository and www.objectos.ai both * quote it, and neither paraphrases it: when the positioning changes, the README @@ -22,12 +23,22 @@ * reads the literals below, so keep each one on the shape it parses: one * `export const NAME =` followed by a single quoted string. * - * ## The one departure from the README's bytes + * ## The departures from the README's bytes * - * `OBJECTOS_DEFINITION` reads "built on ObjectStack" where the README reads - * "built on this stack". Inside the README the phrase has a referent; on this - * site it has none, so the referent is spelled out. That is the only - * substitution, and it is declared here so nobody corrects it back. + * `OBJECTOS_DEFINITION` starts mid-line, at "To run it," on README line 27; the + * sentence before it is about coding agents, not ObjectOS. From there it keeps + * every word in the README's order, with three changes, declared here so nobody + * corrects them back: + * + * 1. "the ObjectStack repository" where the README reads "this repository". + * Inside the README the phrase has a referent; on this site it has none, so + * the referent is spelled out. + * 2. The README's Markdown is dropped: the code spans around + * `ghcr.io/objectstack-ai/objectstack` and `os start`, and the link on + * "ObjectOS". This text ships as a meta description and a `/llms.txt` line, + * where Markdown would show as raw characters. + * 3. "([Ship it](#ship-it))" after "free and self-hosted" is left out. It is a + * link to a section of the README, which has no target here. * * ## No imports * @@ -44,18 +55,20 @@ export const ONTOLOGY_HEADLINE = 'The ontology is the software.'; export const ONTOLOGY_PROMISE = 'One executable business ontology. AI writes it, the runtime runs it, agents operate it, you own it.'; -/** README lines 27-30: what ObjectOS is, with "this stack" spelled out (see above). */ +/** README lines 27-31: the three editions, with the three changes declared above. */ export const OBJECTOS_DEFINITION = - "Want the same loop hosted, in the browser, nothing to install? That's ObjectOS, the commercial runtime environment built on ObjectStack."; + 'To run it, the ObjectStack repository ships ObjectOS Community — the ghcr.io/objectstack-ai/objectstack image, os start and the Console, free and self-hosted — while ObjectOS Cloud is the hosted edition and ObjectOS Enterprise the self-managed, licensed one.'; /** - * The edition clause. Not in the README: fixed by the maintainer's rulings on - * objectos#171 — Q1, ObjectOS still ships a self-managed edition, and Q2, a - * Cloud tenant can export its ontology and run it on the open runtime — and - * quoted verbatim by www.objectos.ai as well. + * The export clause. Not in the README: fixed by the maintainer's ruling on + * objectos#171, Q2, that a Cloud tenant can export its ontology and run it on + * the open runtime. It keeps the words this constant carried before #341, + * with "either edition" spelled out as the two editions it meant, because the + * definition above now names three. Q1, that ObjectOS still ships a + * self-managed edition, is now said by the README's sentence itself. */ export const OBJECTOS_EDITIONS = - 'ObjectOS runs hosted in the browser with nothing to install (ObjectOS Cloud) or self-managed on your own infrastructure (ObjectOS Enterprise), and on either edition you can export your ontology and run it on the open-source ObjectStack runtime.'; + 'On either ObjectOS Cloud or ObjectOS Enterprise, you can export your ontology and run it on the open-source ObjectStack runtime.'; /** * The positioning paragraph every machine-facing surface carries, in this order @@ -72,11 +85,11 @@ export const POSITIONING = [ /** * The positioning in 160 characters or fewer, for the `/docs` meta description - * (objectos#299). `POSITIONING` is 511, and a search snippet cut it off inside + * (objectos#299). `POSITIONING` is 517, and a search snippet cut it off inside * the headline, before the word "ObjectOS". So this one leads with ObjectOS and - * the two editions. It is built from the words above: the README's definition, - * the edition names, and "you own it" from the promise. It is not a fifth - * README quote. The full paragraph stays the page's opening paragraph. + * its three editions. It is built from the words above: each edition's words + * in the README's sentence, and "you own it" from the promise. It is not a + * fifth README quote. The full paragraph stays the page's opening paragraph. */ export const POSITIONING_SHORT = - 'ObjectOS is the commercial runtime environment built on ObjectStack, hosted (ObjectOS Cloud) or self-managed (ObjectOS Enterprise). You own the ontology.'; + 'ObjectOS Community is free and self-hosted, ObjectOS Cloud the hosted edition, ObjectOS Enterprise the self-managed, licensed one. You own the ontology.'; diff --git a/content/docs/index.ja.mdx b/content/docs/index.ja.mdx index baaf9d33..bbb07f51 100644 --- a/content/docs/index.ja.mdx +++ b/content/docs/index.ja.mdx @@ -1,15 +1,15 @@ --- title: はじめに seoTitle: "ドキュメント:開始、構築、デプロイ、運用" -description: "ObjectOS は ObjectStack 上に構築された商用ランタイム環境で、ホスト型(ObjectOS Cloud)またはセルフマネージド(ObjectOS Enterprise)で動作します。オントロジーはあなたのものです。" +description: "ObjectOS Community は無料のセルフホスト版、ObjectOS Cloud はホスト型のエディション、ObjectOS Enterprise はセルフマネージドのライセンス制のエディションです。オントロジーはあなたのものです。" editions: [community, cloud, enterprise] translation: - source_sha: 0347fa621f4342212be72ecb78497ccea72ca3490d850f45dc5b91549d81cf22 + source_sha: 266a61f0cec5ff11f2f82d9b2d731ec9cf61556722d41eeb9b49ed83e5d27997 guide_rev: 1 mode: auto --- -オントロジーこそがソフトウェアです。実行可能なひとつのビジネスオントロジー。AI が書き、ランタイムが実行し、エージェントが操作し、あなたが所有します。同じループをブラウザ上のホスト型で、何もインストールせずに使いたいですか?それが ObjectOS、ObjectStack 上に構築された商用ランタイム環境です。ObjectOS は、何もインストールせずにブラウザ上のホスト型で動作するか(ObjectOS Cloud)、あなた自身のインフラストラクチャ上でセルフマネージドで動作し(ObjectOS Enterprise)、どちらのエディションでもオントロジーをエクスポートして、オープンソースの ObjectStack ランタイムで実行できます。 +オントロジーこそがソフトウェアです。実行可能なひとつのビジネスオントロジー。AI が書き、ランタイムが実行し、エージェントが操作し、あなたが所有します。それを実行するために、ObjectStack リポジトリは ObjectOS Community(ghcr.io/objectstack-ai/objectstack イメージ、os start、Console からなる、無料のセルフホスト版)を提供し、ObjectOS Cloud はホスト型のエディション、ObjectOS Enterprise はセルフマネージドのライセンス制のエディションです。ObjectOS Cloud と ObjectOS Enterprise のどちらでも、オントロジーをエクスポートして、オープンソースの ObjectStack ランタイムで実行できます。 ビジネスに必要なもの(ヘルプデスク、承認フロー、CRM)を組み込みの [AI Builder](/docs/build/ai-builder) に説明するか、テンプレートをインストールすると、それが書いたオントロジーは即座に稼働します。REST API、生成された画面、認証、RBAC、監査ログ、ファイルストレージ、バックグラウンドジョブ、Webhook、そしてエージェントが呼び出せる MCP ツールとして公開されたすべてのオブジェクトです。各変更は小さく読みやすい差分で、実行前に人が承認します。 diff --git a/content/docs/index.mdx b/content/docs/index.mdx index cbad72dd..bcc9f8fa 100644 --- a/content/docs/index.mdx +++ b/content/docs/index.mdx @@ -1,17 +1,18 @@ --- title: Introduction seoTitle: "Documentation: Start, Build, Deploy, Operate" -description: "ObjectOS is the commercial runtime environment built on ObjectStack, hosted (ObjectOS Cloud) or self-managed (ObjectOS Enterprise). You own the ontology." +description: "ObjectOS Community is free and self-hosted, ObjectOS Cloud the hosted edition, ObjectOS Enterprise the self-managed, licensed one. You own the ontology." editions: [community, cloud, enterprise] --- The ontology is the software. One executable business ontology. AI writes -it, the runtime runs it, agents operate it, you own it. Want the same loop -hosted, in the browser, nothing to install? That's ObjectOS, the commercial -runtime environment built on ObjectStack. ObjectOS runs hosted in the browser -with nothing to install (ObjectOS Cloud) or self-managed on your own -infrastructure (ObjectOS Enterprise), and on either edition you can export -your ontology and run it on the open-source ObjectStack runtime. +it, the runtime runs it, agents operate it, you own it. To run it, the +ObjectStack repository ships ObjectOS Community — the +ghcr.io/objectstack-ai/objectstack image, os start and the Console, free and +self-hosted — while ObjectOS Cloud is the hosted edition and ObjectOS +Enterprise the self-managed, licensed one. On either ObjectOS Cloud or +ObjectOS Enterprise, you can export your ontology and run it on the +open-source ObjectStack runtime. Describe what the business needs to the built-in [AI Builder](/docs/build/ai-builder) — a helpdesk, an approval flow, a CRM diff --git a/content/docs/index.zh-Hans.mdx b/content/docs/index.zh-Hans.mdx index 06f3d872..bb6f8891 100644 --- a/content/docs/index.zh-Hans.mdx +++ b/content/docs/index.zh-Hans.mdx @@ -1,20 +1,15 @@ --- title: 简介 seoTitle: "文档:开始、构建、部署、运维" -description: "ObjectOS 是构建在 ObjectStack 之上的商业运行时环境,可托管(ObjectOS Cloud)或自管理(ObjectOS Enterprise)。本体归你所有。" +description: "ObjectOS Community 免费且自托管,ObjectOS Cloud 是托管版本,ObjectOS Enterprise 是自管理、需许可的版本。本体归你所有。" editions: [community, cloud, enterprise] translation: - source_sha: 0347fa621f4342212be72ecb78497ccea72ca3490d850f45dc5b91549d81cf22 + source_sha: 266a61f0cec5ff11f2f82d9b2d731ec9cf61556722d41eeb9b49ed83e5d27997 guide_rev: 1 mode: auto --- -本体就是软件。一个可执行的业务本体:AI 编写它,运行时运行它,Agent -操作它,你拥有它。想要同样的闭环,托管在浏览器里、什么都不用安装? -那就是 ObjectOS —— 构建在 ObjectStack 之上的商业运行时环境。ObjectOS -既可以托管运行在浏览器中、无需任何安装(ObjectOS Cloud),也可以自管理 -运行在你自己的基础设施上(ObjectOS Enterprise);无论哪个版本,你都可以 -导出你的本体,并在开源的 ObjectStack 运行时上运行它。 +本体就是软件。一个可执行的业务本体:AI 编写它,运行时运行它,Agent 操作它,你拥有它。为了运行它,ObjectStack 仓库提供 ObjectOS Community —— ghcr.io/objectstack-ai/objectstack 镜像、os start 和 Console,免费且自托管 —— 而 ObjectOS Cloud 是托管版本,ObjectOS Enterprise 是自管理、需许可的版本。无论在 ObjectOS Cloud 还是 ObjectOS Enterprise 上,你都可以导出你的本体,并在开源的 ObjectStack 运行时上运行它。 向内置的 [AI Builder](/docs/build/ai-builder) 描述业务需要什么 —— 一个 服务台、一条审批流程、一个 CRM —— 或者安装一个模板,它写出的本体会立即 diff --git a/content/docs/index.zh-Hant.mdx b/content/docs/index.zh-Hant.mdx index e62da6c1..66d35577 100644 --- a/content/docs/index.zh-Hant.mdx +++ b/content/docs/index.zh-Hant.mdx @@ -2,20 +2,15 @@ # @generated zh-Hant from zh-Hans -- do not edit. Edit the English source, then regenerate: pnpm --filter @objectos/docs gen:zh-hant title: 簡介 seoTitle: "文件:開始、構建、部署、運維" -description: "ObjectOS 是構建在 ObjectStack 之上的商業執行時環境,可託管(ObjectOS Cloud)或自管理(ObjectOS Enterprise)。本體歸你所有。" +description: "ObjectOS Community 免費且自託管,ObjectOS Cloud 是託管版本,ObjectOS Enterprise 是自管理、需許可的版本。本體歸你所有。" editions: [community, cloud, enterprise] translation: - source_sha: 0347fa621f4342212be72ecb78497ccea72ca3490d850f45dc5b91549d81cf22 + source_sha: 266a61f0cec5ff11f2f82d9b2d731ec9cf61556722d41eeb9b49ed83e5d27997 guide_rev: 1 mode: auto --- -本體就是軟體。一個可執行的業務本體:AI 編寫它,執行時執行它,Agent -操作它,你擁有它。想要同樣的閉環,託管在瀏覽器裡、什麼都不用安裝? -那就是 ObjectOS —— 構建在 ObjectStack 之上的商業執行時環境。ObjectOS -既可以託管執行在瀏覽器中、無需任何安裝(ObjectOS Cloud),也可以自管理 -執行在你自己的基礎設施上(ObjectOS Enterprise);無論哪個版本,你都可以 -匯出你的本體,並在開源的 ObjectStack 執行時上執行它。 +本體就是軟體。一個可執行的業務本體:AI 編寫它,執行時執行它,Agent 操作它,你擁有它。為了執行它,ObjectStack 倉庫提供 ObjectOS Community —— ghcr.io/objectstack-ai/objectstack 映象、os start 和 Console,免費且自託管 —— 而 ObjectOS Cloud 是託管版本,ObjectOS Enterprise 是自管理、需許可的版本。無論在 ObjectOS Cloud 還是 ObjectOS Enterprise 上,你都可以匯出你的本體,並在開源的 ObjectStack 執行時上執行它。 向內建的 [AI Builder](/docs/build/ai-builder) 描述業務需要什麼 —— 一個 服務檯、一條審批流程、一個 CRM —— 或者安裝一個模板,它寫出的本體會立即 From cfe6ce3c95b42806ab2d8470f6ffce36cfd79522 Mon Sep 17 00:00:00 2001 From: Steedos Date: Mon, 2 Nov 2026 01:45:41 +0000 Subject: [PATCH 15/22] docs(i18n): re-sync editions/compare and editions/license after #407 (#418) #407 added Team's annual price ($20 / AI seat / month billed annually) to the Price row of editions/compare and editions/license. This adds the same to the zh-Hans and ja Price cells, in the annual-price wording each locale uses on cloud/plans-and-seats, restamps the four pages and regenerates zh-Hant. check-translations: zh-Hans and ja 0 stale, 0 missing. Fixes #418 Claude-Session: https://claude.ai/code/session_01QsR2jRsjbApbf83iyTDDXm Co-Authored-By: Claude --- content/docs/editions/compare.ja.mdx | 4 ++-- content/docs/editions/compare.zh-Hans.mdx | 4 ++-- content/docs/editions/compare.zh-Hant.mdx | 4 ++-- content/docs/editions/license.ja.mdx | 4 ++-- content/docs/editions/license.zh-Hans.mdx | 4 ++-- content/docs/editions/license.zh-Hant.mdx | 4 ++-- 6 files changed, 12 insertions(+), 12 deletions(-) diff --git a/content/docs/editions/compare.ja.mdx b/content/docs/editions/compare.ja.mdx index bfcf0726..85eb6324 100644 --- a/content/docs/editions/compare.ja.mdx +++ b/content/docs/editions/compare.ja.mdx @@ -4,7 +4,7 @@ seoTitle: "ObjectOS エディションの比較:Community、Free、Team、Ente description: ObjectOS の各エディションとプランに含まれるものを 1 行ずつ。Community、Cloud Free、Cloud Team、Enterprise、そして各違いがどこで強制されるか。 editions: [community, cloud, enterprise] translation: - source_sha: 453d01cdf9083450d82f8221495bfac52b798f6ccb9ac8ffbbc5796920086128 + source_sha: c29b5a5ce5faa612a8294abd954b87c34bd3edbd3f148cca865cecd1df36badf guide_rev: 1 mode: auto --- @@ -18,7 +18,7 @@ ObjectOS は 3 つのエディションを持つひとつの製品です。**Obj | | **Community** | **Cloud Free** | **Cloud Team** | **Enterprise** | |---|---|---|---|---| | 提供形態 | セルフマネージド | ホスト型 | ホスト型 | セルフマネージド | -| 料金 | 無料(Apache-2.0) | 無料 | $24 / AI シート / 月 | 契約による | +| 料金 | 無料(Apache-2.0) | 無料 | $24 / AI シート / 月、または年払いで $20 / AI シート / 月 | 契約による | | ファイルストレージ | 自前([ストレージ](/docs/configure/storage)) | 環境ごとに 1 GB | 環境ごとに 20 GB | 自前([ストレージ](/docs/configure/storage)) | | 開発環境 | デプロイした数だけ | —(本番のみ) | 2 つ、さらに AI シートごとに 1 つ | デプロイした数だけ | | MCP リクエスト | デプロイで設定 | 20 / 分、1,000 / 日 | 120 / 分、1 日の上限なし | デプロイで設定 | diff --git a/content/docs/editions/compare.zh-Hans.mdx b/content/docs/editions/compare.zh-Hans.mdx index 82b4d7be..99bdd056 100644 --- a/content/docs/editions/compare.zh-Hans.mdx +++ b/content/docs/editions/compare.zh-Hans.mdx @@ -4,7 +4,7 @@ seoTitle: "ObjectOS 版本对比:Community、Free、Team、Enterprise" description: 逐行列出每个 ObjectOS 版本和套餐包含什么 —— Community、Cloud Free、Cloud Team 和 Enterprise —— 以及每项差异在哪里强制执行。 editions: [community, cloud, enterprise] translation: - source_sha: 453d01cdf9083450d82f8221495bfac52b798f6ccb9ac8ffbbc5796920086128 + source_sha: c29b5a5ce5faa612a8294abd954b87c34bd3edbd3f148cca865cecd1df36badf guide_rev: 1 mode: auto --- @@ -23,7 +23,7 @@ ObjectOS 是一个产品、三个版本。**ObjectOS Community** 是你自己运 | | **Community** | **Cloud Free** | **Cloud Team** | **Enterprise** | |---|---|---|---|---| | 交付方式 | 自管理 | 托管 | 托管 | 自管理 | -| 价格 | 免费(Apache-2.0) | 免费 | 24 美元 / AI 席位 / 月 | 按合同 | +| 价格 | 免费(Apache-2.0) | 免费 | 24 美元 / AI 席位 / 月,或按年付费 20 美元 / AI 席位 / 月 | 按合同 | | 文件存储 | 你自己的([存储](/docs/configure/storage)) | 每个环境 1 GB | 每个环境 20 GB | 你自己的([存储](/docs/configure/storage)) | | 开发环境 | 你部署多少就有多少 | —(仅生产环境) | 两个,外加每个 AI 席位一个 | 你部署多少就有多少 | | MCP 请求 | 由你的部署设定 | 每分钟 20 次,每天 1,000 次 | 每分钟 120 次,无每日上限 | 由你的部署设定 | diff --git a/content/docs/editions/compare.zh-Hant.mdx b/content/docs/editions/compare.zh-Hant.mdx index 392bf6ba..965c463b 100644 --- a/content/docs/editions/compare.zh-Hant.mdx +++ b/content/docs/editions/compare.zh-Hant.mdx @@ -5,7 +5,7 @@ seoTitle: "ObjectOS 版本對比:Community、Free、Team、Enterprise" description: 逐行列出每個 ObjectOS 版本和套餐包含什麼 —— Community、Cloud Free、Cloud Team 和 Enterprise —— 以及每項差異在哪裡強制執行。 editions: [community, cloud, enterprise] translation: - source_sha: 453d01cdf9083450d82f8221495bfac52b798f6ccb9ac8ffbbc5796920086128 + source_sha: c29b5a5ce5faa612a8294abd954b87c34bd3edbd3f148cca865cecd1df36badf guide_rev: 1 mode: auto --- @@ -24,7 +24,7 @@ ObjectOS 是一個產品、三個版本。**ObjectOS Community** 是你自己執 | | **Community** | **Cloud Free** | **Cloud Team** | **Enterprise** | |---|---|---|---|---| | 交付方式 | 自管理 | 託管 | 託管 | 自管理 | -| 價格 | 免費(Apache-2.0) | 免費 | 24 美元 / AI 席位 / 月 | 按合同 | +| 價格 | 免費(Apache-2.0) | 免費 | 24 美元 / AI 席位 / 月,或按年付費 20 美元 / AI 席位 / 月 | 按合同 | | 檔案儲存 | 你自己的([儲存](/docs/configure/storage)) | 每個環境 1 GB | 每個環境 20 GB | 你自己的([儲存](/docs/configure/storage)) | | 開發環境 | 你部署多少就有多少 | —(僅生產環境) | 兩個,外加每個 AI 席位一個 | 你部署多少就有多少 | | MCP 請求 | 由你的部署設定 | 每分鐘 20 次,每天 1,000 次 | 每分鐘 120 次,無每日上限 | 由你的部署設定 | diff --git a/content/docs/editions/license.ja.mdx b/content/docs/editions/license.ja.mdx index 73c52566..32077c95 100644 --- a/content/docs/editions/license.ja.mdx +++ b/content/docs/editions/license.ja.mdx @@ -3,7 +3,7 @@ title: ライセンスと料金 description: ObjectOS は 3 つのエディションを持つひとつの製品です。Community(オープンソース、無料)、Cloud、Enterprise。それぞれのライセンス形態と、ObjectStack フレームワークとの関係を説明します。 editions: [community, cloud, enterprise] translation: - source_sha: d526aff1a5e15ece6edf6d7c4a0f01127d620227c07d322183728d081c36444e + source_sha: 5fb0cf25d5b71e734f09f632ec483b34232ee0f0af706dd9bfa525ecdc2f0b23 guide_rev: 1 mode: auto --- @@ -33,7 +33,7 @@ ObjectOS Community は無料です。2 つの商用エディションには、 |---|---|---|---|---| | エディション | ObjectOS Community | ObjectOS Cloud | ObjectOS Cloud | ObjectOS Enterprise | | 提供形態 | **セルフマネージド** | クラウド | クラウド | **セルフマネージド(プライベートデプロイ)** | -| 料金 | **無料**(Apache-2.0) | **無料** | **$24** / AI シート / 月 | 個別見積もり(ボリューム):[営業にお問い合わせください](mailto:sales@objectos.ai) | +| 料金 | **無料**(Apache-2.0) | **無料** | **$24** / AI シート / 月、または年払いで $20 / AI シート / 月 | 個別見積もり(ボリューム):[営業にお問い合わせください](mailto:sales@objectos.ai) | | UI 内の AI(AI Builder +「データに質問する」) | MCP のみ(モデルは持ち込み) | お試し | ✓ | ✓ | | AI ガバナンス(アクションの監査、ガードレール、権限のスコープ設定) | — | — | — | ✓ | | クラスタリング / HA、マルチ組織のセルフホスト、エアギャップ、SCIM | — | — | — | ✓ | diff --git a/content/docs/editions/license.zh-Hans.mdx b/content/docs/editions/license.zh-Hans.mdx index 6b162d70..f137be0f 100644 --- a/content/docs/editions/license.zh-Hans.mdx +++ b/content/docs/editions/license.zh-Hans.mdx @@ -3,7 +3,7 @@ title: 许可与定价 description: ObjectOS 是一个产品、三个版本 —— Community(开源,免费)、Cloud 和 Enterprise —— 每个版本如何授权,以及它们与 ObjectStack 框架的关系。 editions: [community, cloud, enterprise] translation: - source_sha: d526aff1a5e15ece6edf6d7c4a0f01127d620227c07d322183728d081c36444e + source_sha: 5fb0cf25d5b71e734f09f632ec483b34232ee0f0af706dd9bfa525ecdc2f0b23 guide_rev: 1 mode: auto --- @@ -44,7 +44,7 @@ ObjectOS Community 免费。两个商业版本使用一张价目表、两种交 |---|---|---|---|---| | 版本 | ObjectOS Community | ObjectOS Cloud | ObjectOS Cloud | ObjectOS Enterprise | | 交付方式 | **自管理** | 云 | 云 | **自管理(私有部署)** | -| 价格 | **免费**(Apache-2.0) | **免费** | **24 美元** / AI 席位 / 月 | 定制(按量)—— [联系销售](mailto:sales@objectos.ai) | +| 价格 | **免费**(Apache-2.0) | **免费** | **24 美元** / AI 席位 / 月,或按年付费 20 美元 / AI 席位 / 月 | 定制(按量)—— [联系销售](mailto:sales@objectos.ai) | | UI 内 AI(AI Builder + "问你的数据") | 仅 MCP(自带模型) | 体验版 | ✓ | ✓ | | AI 治理(动作审计、护栏、权限范围限定) | — | — | — | ✓ | | 集群 / 高可用、多组织自托管、物理隔离、SCIM | — | — | — | ✓ | diff --git a/content/docs/editions/license.zh-Hant.mdx b/content/docs/editions/license.zh-Hant.mdx index b744c0e4..709eb04f 100644 --- a/content/docs/editions/license.zh-Hant.mdx +++ b/content/docs/editions/license.zh-Hant.mdx @@ -4,7 +4,7 @@ title: 許可與定價 description: ObjectOS 是一個產品、三個版本 —— Community(開源,免費)、Cloud 和 Enterprise —— 每個版本如何授權,以及它們與 ObjectStack 框架的關係。 editions: [community, cloud, enterprise] translation: - source_sha: d526aff1a5e15ece6edf6d7c4a0f01127d620227c07d322183728d081c36444e + source_sha: 5fb0cf25d5b71e734f09f632ec483b34232ee0f0af706dd9bfa525ecdc2f0b23 guide_rev: 1 mode: auto --- @@ -45,7 +45,7 @@ ObjectOS Community 免費。兩個商業版本使用一張價目表、兩種交 |---|---|---|---|---| | 版本 | ObjectOS Community | ObjectOS Cloud | ObjectOS Cloud | ObjectOS Enterprise | | 交付方式 | **自管理** | 雲 | 雲 | **自管理(私有部署)** | -| 價格 | **免費**(Apache-2.0) | **免費** | **24 美元** / AI 席位 / 月 | 定製(按量)—— [聯絡銷售](mailto:sales@objectos.ai) | +| 價格 | **免費**(Apache-2.0) | **免費** | **24 美元** / AI 席位 / 月,或按年付費 20 美元 / AI 席位 / 月 | 定製(按量)—— [聯絡銷售](mailto:sales@objectos.ai) | | UI 內 AI(AI Builder + "問你的資料") | 僅 MCP(自帶模型) | 體驗版 | ✓ | ✓ | | AI 治理(動作審計、護欄、許可權範圍限定) | — | — | — | ✓ | | 叢集 / 高可用、多組織自託管、物理隔離、SCIM | — | — | — | ✓ | From 4cdb4386dace6a7f1bcdf7f9c8f8e2f61832f4da Mon Sep 17 00:00:00 2001 From: Steedos Date: Mon, 2 Nov 2026 02:04:35 +0000 Subject: [PATCH 16/22] docs(architecture): ObjectOS layer row in three-edition terms (#417) The layer table on architecture still called ObjectOS "the commercial runtime environment built on the framework" with two editions, the definition objectstack#26148 retired and #416 removed from the positioning constants. The row now uses only positioning.ts's terms: ObjectOS Community free and self-hosted, ObjectOS Cloud the hosted edition, ObjectOS Enterprise the self-managed, licensed one. zh-Hans and ja use the wording their index.mdx carries since #416; both are restamped and zh-Hant is regenerated. check-positioning rule (c) now lists "commercial runtime environment" as a stale sentence, with a fixture, so the phrase cannot come back to an English source. Fixes #417 Claude-Session: https://claude.ai/code/session_01QsR2jRsjbApbf83iyTDDXm Co-Authored-By: Claude --- .github/scripts/check-positioning.mjs | 5 +++-- content/docs/architecture.ja.mdx | 4 ++-- content/docs/architecture.mdx | 2 +- content/docs/architecture.zh-Hans.mdx | 4 ++-- content/docs/architecture.zh-Hant.mdx | 4 ++-- 5 files changed, 10 insertions(+), 9 deletions(-) diff --git a/.github/scripts/check-positioning.mjs b/.github/scripts/check-positioning.mjs index ba46a0c6..d77c9065 100644 --- a/.github/scripts/check-positioning.mjs +++ b/.github/scripts/check-positioning.mjs @@ -41,6 +41,7 @@ const STALE = [ /[Dd]oes\s+not\s+phone\s+home/, /ObjectOS\s+is\s+distributed\s+under\s+the\s+Apache/, // ObjectOS only: the open ObjectStack runtime is, and may say so /[Cc]ustomer-hosted\s+runtime/, + /[Cc]ommercial\s+runtime\s+environment/, // the two-edition definition objectstack#26148 retired (#341, #417) ]; const OPEN_SOURCE = /Open[\s-]+source,\s+Apache-2\.0/i; // checked inside the glossary's ObjectOS entry only @@ -166,7 +167,7 @@ const A_BAD = { }; const B_BAD = ['ObjectStack Protocol', 'ObjectStack Documentation', 'Object OS', 'objectOS', 'ObjectOs']; const C_OK = 'No seats, no license server. Does ObjectOS phone home?\n\n```\nObjectOS is a self-hosted runtime\n```\n\n{/* was: never phones home */}\n'; -const C_BAD = 'ObjectOS is a self-hosted\nruntime. It never phones home, does not call home, never calls home.\n\nNo license server. Fully\nself-contained, inside your firewall.\n'; +const C_BAD = 'ObjectOS is a self-hosted\nruntime. It never phones home, does not call home, never calls home.\n\nNo license server. Fully\nself-contained, inside your firewall. The commercial runtime\nenvironment built on the framework.\n'; const LEGAL_OK = "const content = {\n en: {\n text: 'ObjectOS Cloud is hosted. The open-source ObjectStack runtime has no telemetry, no license check, and no update ping.',\n },\n 'zh-Hans': {\n text: 'customer-hosted runtime; does not phone home',\n },\n};\n"; const LEGAL_BAD = " en: {\n text: 'ObjectOS is distributed under the Apache License 2.0. ObjectOS is a customer-hosted\nruntime that does not phone home.',\n },\n"; const glossary = (entry) => [GLOSSARY, `### ObjectOS\n\n${entry}\n\n### ObjectStack\n\nOpen source, Apache-2.0.\n`]; @@ -176,7 +177,7 @@ const CASES = [ ['(b) ObjectOS, the host and the package scope', () => ruleB([['a.html', 'Intro | ObjectOS, docs.objectos.ai, @objectos/docs']]), 0], ['(b) the five wrong spellings, one file each', () => ruleB(B_BAD.map((s, i) => [`${i}.html`, `

${s} boots.

`])), 5], ['(c) list form, a question, a fenced quote, a comment', () => ruleC([glossary('Commercial. Not open source.'), ['a.mdx', C_OK]]), 0], - ['(c) the eight stale sentences, three wrapped', () => ruleC([glossary('The runtime. Open\nsource, Apache-2.0.'), ['a.mdx', C_BAD]]), 8], + ['(c) the nine stale sentences, four wrapped', () => ruleC([glossary('The runtime. Open\nsource, Apache-2.0.'), ['a.mdx', C_BAD]]), 9], ['(c) a legal page: a true en entry; its stale zh-Hans entry is not read', () => ruleC([glossary('Commercial.'), [LEGAL[0], englishEntry(LEGAL_OK)]]), 0], ['(c) a legal page: the three licence sentences, one wrapped; a page with no en entry', () => ruleC([glossary('Commercial.'), [LEGAL[0], englishEntry(LEGAL_BAD)], [LEGAL[1], englishEntry('export default 1;\n')]]), 4], ]; diff --git a/content/docs/architecture.ja.mdx b/content/docs/architecture.ja.mdx index 0b2b36f8..e5a88fa4 100644 --- a/content/docs/architecture.ja.mdx +++ b/content/docs/architecture.ja.mdx @@ -4,7 +4,7 @@ seoTitle: "アーキテクチャ:何が動き、データがどこにあるか description: 実際に何を動かすことになるのか。導入するかどうかを評価しているエンジニアのために。 editions: [community, cloud, enterprise] translation: - source_sha: 9292459ed8a30885f3b5c660fb772187d5d1edb8ead66c12839ab7900dcbef3f + source_sha: 2ba24bbe881fd5788bce400a2ab8042ab41ee849a2af902d99573d2b2cfdb083 guide_rev: 1 mode: auto --- @@ -96,7 +96,7 @@ ObjectOS runtime |---|---|---| | **フレームワーク**(`@objectstack/*`) | オープンソースのカーネル、ObjectQL、プラグイン、ドライバー | npm。ビルド時に取り込まれます | | **コントロールプレーン**(任意) | コンパイル済みの `objectstack.json` アーティファクトを公開します。ホスト型の ObjectOS Cloud を使うことも、自前で運用することも、まったく使わないこともできます | あなたの CI、私たちのクラウド、またはあなたのノートパソコン | -| **ObjectOS** | フレームワーク上に構築された商用ランタイム環境 | **ObjectOS Cloud**(私たちが運用)または**あなたのインフラストラクチャ**(ObjectOS Enterprise) | +| **ObjectOS** | ObjectOS Community は無料のセルフホスト版、ObjectOS Cloud はホスト型のエディション、ObjectOS Enterprise はセルフマネージドのライセンス制のエディションです | セルフホスト(**ObjectOS Community**)、ホスト型(**ObjectOS Cloud**)、またはセルフマネージド(**ObjectOS Enterprise**) | 単一のアプリを出荷するなら、コントロールプレーンは不要です。CI で `objectstack.config.ts → dist/objectstack.json` をコンパイルし、その JSON をイメージに入れて出荷します。複数のデプロイメントがインストールするアプリを公開する場合は、コントロールプレーンがそのカタログの置き場所になります。 diff --git a/content/docs/architecture.mdx b/content/docs/architecture.mdx index 753b4074..9510db4e 100644 --- a/content/docs/architecture.mdx +++ b/content/docs/architecture.mdx @@ -134,7 +134,7 @@ want to know where the artifact comes from: |---|---|---| | **Framework** (`@objectstack/*`) | Open-source kernel, ObjectQL, plugins, drivers | npm — pulled in at build time | | **Control plane** (optional) | Publishes compiled `objectstack.json` artifacts; you can use the hosted ObjectOS Cloud, run your own, or skip it entirely | Your CI, our cloud, or your laptop | -| **ObjectOS** | The commercial runtime environment built on the framework | **ObjectOS Cloud** (we operate it) or **your infrastructure** (ObjectOS Enterprise) | +| **ObjectOS** | ObjectOS Community is free and self-hosted, ObjectOS Cloud the hosted edition, ObjectOS Enterprise the self-managed, licensed one | Self-hosted (**ObjectOS Community**), hosted (**ObjectOS Cloud**) or self-managed (**ObjectOS Enterprise**) | If you're shipping a single app, you don't need a control plane — compile `objectstack.config.ts → dist/objectstack.json` in your CI and diff --git a/content/docs/architecture.zh-Hans.mdx b/content/docs/architecture.zh-Hans.mdx index 4abfcff2..ed327ad8 100644 --- a/content/docs/architecture.zh-Hans.mdx +++ b/content/docs/architecture.zh-Hans.mdx @@ -4,7 +4,7 @@ seoTitle: "架构:运行什么,数据在哪里" description: 你实际在运行的是什么 —— 写给正在评估是否引入它的工程师。 editions: [community, cloud, enterprise] translation: - source_sha: 9292459ed8a30885f3b5c660fb772187d5d1edb8ead66c12839ab7900dcbef3f + source_sha: 2ba24bbe881fd5788bce400a2ab8042ab41ee849a2af902d99573d2b2cfdb083 guide_rev: 1 mode: auto --- @@ -126,7 +126,7 @@ API 密钥进行认证,同样的权限检查约束着它的工具调用能读 |---|---|---| | **框架**(`@objectstack/*`) | 开源的内核、ObjectQL、插件、驱动 | npm —— 在构建时引入 | | **控制平面**(可选) | 发布编译好的 `objectstack.json` 产物;你可以使用托管的 ObjectOS Cloud、自己运行一个,或者完全不用 | 你的 CI、我们的云,或者你的笔记本 | -| **ObjectOS** | 构建在框架之上的商业运行时环境 | **ObjectOS Cloud**(由我们运维)或**你的基础设施**(ObjectOS Enterprise) | +| **ObjectOS** | ObjectOS Community 免费且自托管,ObjectOS Cloud 是托管版本,ObjectOS Enterprise 是自管理、需许可的版本 | 自托管(**ObjectOS Community**)、托管(**ObjectOS Cloud**)或自管理(**ObjectOS Enterprise**) | 如果你只交付一个应用,就不需要控制平面 —— 在你的 CI 中把 `objectstack.config.ts → dist/objectstack.json` 编译好,然后把 JSON 放进 diff --git a/content/docs/architecture.zh-Hant.mdx b/content/docs/architecture.zh-Hant.mdx index 6cad3261..b804fb27 100644 --- a/content/docs/architecture.zh-Hant.mdx +++ b/content/docs/architecture.zh-Hant.mdx @@ -5,7 +5,7 @@ seoTitle: "架構:執行什麼,資料在哪裡" description: 你實際在執行的是什麼 —— 寫給正在評估是否引入它的工程師。 editions: [community, cloud, enterprise] translation: - source_sha: 9292459ed8a30885f3b5c660fb772187d5d1edb8ead66c12839ab7900dcbef3f + source_sha: 2ba24bbe881fd5788bce400a2ab8042ab41ee849a2af902d99573d2b2cfdb083 guide_rev: 1 mode: auto --- @@ -127,7 +127,7 @@ API 金鑰進行認證,同樣的許可權檢查約束著它的工具呼叫能 |---|---|---| | **框架**(`@objectstack/*`) | 開源的核心、ObjectQL、外掛、驅動 | npm —— 在構建時引入 | | **控制平面**(可選) | 釋出編譯好的 `objectstack.json` 產物;你可以使用託管的 ObjectOS Cloud、自己執行一個,或者完全不用 | 你的 CI、我們的雲,或者你的筆記本 | -| **ObjectOS** | 構建在框架之上的商業執行時環境 | **ObjectOS Cloud**(由我們運維)或**你的基礎設施**(ObjectOS Enterprise) | +| **ObjectOS** | ObjectOS Community 免費且自託管,ObjectOS Cloud 是託管版本,ObjectOS Enterprise 是自管理、需許可的版本 | 自託管(**ObjectOS Community**)、託管(**ObjectOS Cloud**)或自管理(**ObjectOS Enterprise**) | 如果你只交付一個應用,就不需要控制平面 —— 在你的 CI 中把 `objectstack.config.ts → dist/objectstack.json` 編譯好,然後把 JSON 放進 From 9abc331039343c6a780b5cf9e0505ed276052931 Mon Sep 17 00:00:00 2001 From: Steedos Date: Mon, 2 Nov 2026 04:17:40 +0000 Subject: [PATCH 17/22] docs(templates): remove the five retired templates from the catalog and entry pages (#421) On ObjectStack 17.7 the scaffolder refuses todo, compliance, content, contracts and procurement as retired, yet the docs listed them as templates and catalog apps. Per the ruling on #334 Q5 they are removed, and build/templates' "--template todo is refused as retired" stays as the one mention. - build/templates: seoTitle and description name helpdesk, hr and project; the five catalog rows and the three pick-table rows that pointed at them are gone. - index: the marketplace example names Helpdesk only. - start/community and build/marketplace: the same five rows leave their app tables, and the template clone example uses helpdesk. - build/index names none of the five and is untouched. zh-Hans and ja get the same removals and are restamped; zh-Hant is regenerated. Fixes #421 Claude-Session: https://claude.ai/code/session_01QsR2jRsjbApbf83iyTDDXm Co-Authored-By: Claude --- content/docs/build/marketplace.ja.mdx | 7 +------ content/docs/build/marketplace.mdx | 5 ----- content/docs/build/marketplace.zh-Hans.mdx | 7 +------ content/docs/build/marketplace.zh-Hant.mdx | 7 +------ content/docs/build/templates.ja.mdx | 14 +++----------- content/docs/build/templates.mdx | 12 ++---------- content/docs/build/templates.zh-Hans.mdx | 14 +++----------- content/docs/build/templates.zh-Hant.mdx | 14 +++----------- content/docs/index.ja.mdx | 4 ++-- content/docs/index.mdx | 4 ++-- content/docs/index.zh-Hans.mdx | 4 ++-- content/docs/index.zh-Hant.mdx | 4 ++-- content/docs/start/community.ja.mdx | 9 ++------- content/docs/start/community.mdx | 7 +------ content/docs/start/community.zh-Hans.mdx | 9 ++------- content/docs/start/community.zh-Hant.mdx | 9 ++------- 16 files changed, 29 insertions(+), 101 deletions(-) diff --git a/content/docs/build/marketplace.ja.mdx b/content/docs/build/marketplace.ja.mdx index 1c70423d..71e54cbf 100644 --- a/content/docs/build/marketplace.ja.mdx +++ b/content/docs/build/marketplace.ja.mdx @@ -4,7 +4,7 @@ seoTitle: "マーケットプレイス:出来合いのアプリをインスト description: コードを書かずに、稼働中の ObjectOS に出来合いのアプリをインストールします。 editions: [community, cloud, enterprise] translation: - source_sha: 5fb581df2aa59854381bb78c50049fa3203dd3c3ded12d2e39d88d4997ff7e68 + source_sha: 61cb22e52d4e87c459e99c476993624cf96cb1d6869a260af71706494e69cb92 guide_rev: 1 mode: auto --- @@ -66,12 +66,7 @@ You ─→ ObjectOS ─→ Marketplace tab ─→ pick app ─→ Install | アプリ | 得られるもの | |---|---| -| **Todo** | 汎用のタスクとプロジェクトの管理 | -| **Contracts** | AI による条項抽出付きの契約ライフサイクル管理(CLM) | -| **Procurement** | ベンダー、発注書、3 点照合 | -| **Compliance** | SOC 2 / ISO 27001 の統制 + 証跡の収集 | | **Helpdesk** | AI ファーストのカスタマーサポートのチケット管理 | -| **Content** | 編集カレンダー + チャネル ROI | | **HR** | 名簿、組織図、休暇 | | **Project** | プロジェクト / タスク / マイルストーンの管理 | diff --git a/content/docs/build/marketplace.mdx b/content/docs/build/marketplace.mdx index 59cbdfb7..4937ca74 100644 --- a/content/docs/build/marketplace.mdx +++ b/content/docs/build/marketplace.mdx @@ -73,12 +73,7 @@ These apps are ready to install with one click: | App | What it gives you | |---|---| -| **Todo** | Universal task and project tracker | -| **Contracts** | Contract lifecycle (CLM) with AI clause extraction | -| **Procurement** | Vendors, purchase orders, 3-way match | -| **Compliance** | SOC 2 / ISO 27001 controls + evidence collection | | **Helpdesk** | AI-first customer support ticketing | -| **Content** | Editorial calendar + channel ROI | | **HR** | Directory, org chart, time-off | | **Project** | Project / task / milestone tracking | diff --git a/content/docs/build/marketplace.zh-Hans.mdx b/content/docs/build/marketplace.zh-Hans.mdx index 9502932d..207d08ac 100644 --- a/content/docs/build/marketplace.zh-Hans.mdx +++ b/content/docs/build/marketplace.zh-Hans.mdx @@ -4,7 +4,7 @@ seoTitle: "市场:安装和发布现成的应用" description: 无需编写代码,即可将现成应用安装到运行中的 ObjectOS。 editions: [community, cloud, enterprise] translation: - source_sha: 5fb581df2aa59854381bb78c50049fa3203dd3c3ded12d2e39d88d4997ff7e68 + source_sha: 61cb22e52d4e87c459e99c476993624cf96cb1d6869a260af71706494e69cb92 guide_rev: 1 mode: auto --- @@ -66,12 +66,7 @@ You ─→ ObjectOS ─→ Marketplace tab ─→ pick app ─→ Install | 应用 | 提供的能力 | |---|---| -| **Todo** | 通用任务与项目跟踪器 | -| **Contracts** | 带 AI 条款提取的合同生命周期管理(CLM) | -| **Procurement** | 供应商、采购订单、三单匹配 | -| **Compliance** | SOC 2 / ISO 27001 控制项 + 证据收集 | | **Helpdesk** | AI 优先的客户支持工单系统 | -| **Content** | 编辑日历 + 渠道 ROI | | **HR** | 通讯录、组织架构图、休假 | | **Project** | 项目 / 任务 / 里程碑跟踪 | diff --git a/content/docs/build/marketplace.zh-Hant.mdx b/content/docs/build/marketplace.zh-Hant.mdx index ad011f40..56d50a1a 100644 --- a/content/docs/build/marketplace.zh-Hant.mdx +++ b/content/docs/build/marketplace.zh-Hant.mdx @@ -5,7 +5,7 @@ seoTitle: "市場:安裝和釋出現成的應用" description: 無需編寫程式碼,即可將現成應用安裝到執行中的 ObjectOS。 editions: [community, cloud, enterprise] translation: - source_sha: 5fb581df2aa59854381bb78c50049fa3203dd3c3ded12d2e39d88d4997ff7e68 + source_sha: 61cb22e52d4e87c459e99c476993624cf96cb1d6869a260af71706494e69cb92 guide_rev: 1 mode: auto --- @@ -67,12 +67,7 @@ You ─→ ObjectOS ─→ Marketplace tab ─→ pick app ─→ Install | 應用 | 提供的能力 | |---|---| -| **Todo** | 通用任務與專案跟蹤器 | -| **Contracts** | 帶 AI 條款提取的合同生命週期管理(CLM) | -| **Procurement** | 供應商、採購訂單、三單匹配 | -| **Compliance** | SOC 2 / ISO 27001 控制項 + 證據收集 | | **Helpdesk** | AI 優先的客戶支援工單系統 | -| **Content** | 編輯日曆 + 渠道 ROI | | **HR** | 通訊錄、組織架構圖、休假 | | **Project** | 專案 / 任務 / 里程碑跟蹤 | diff --git a/content/docs/build/templates.ja.mdx b/content/docs/build/templates.ja.mdx index 98510551..a97eb09b 100644 --- a/content/docs/build/templates.ja.mdx +++ b/content/docs/build/templates.ja.mdx @@ -1,10 +1,10 @@ --- title: テンプレート -seoTitle: "アプリテンプレート:フォークできる Helpdesk、Contracts、Todo" -description: フォークできるスターターパッケージ。`todo`、`contracts`、`procurement`、`helpdesk` など。 +seoTitle: "アプリテンプレート:フォークできる Helpdesk、HR、Project" +description: フォークできるスターターパッケージ。`helpdesk`、`hr`、`project`。 editions: [community, cloud, enterprise] translation: - source_sha: 463d4f0100a6c89aa409bc10e01a61663dd4d3c6937fe19376fbc7a0e24145f8 + source_sha: b052030c2dd9f6e43f41795ed26eaa013fa71688790c2e263b577dd4db664589 guide_rev: 1 mode: auto --- @@ -20,12 +20,7 @@ translation: | テンプレート | 領域 | フォークして作れるもの | |---|---|---| -| **`todo`** | タスクとプロジェクト | 「何らかの形でグループ化されたやること」のツール全般 | -| **`contracts`** | AI による条項抽出付きの CLM | 承認 + ドキュメント AI | -| **`procurement`** | ベンダー、発注書、3 点照合 | 承認チェーン + 受領 | -| **`compliance`** | SOC 2 / ISO 27001 の統制 | 証跡収集のワークフロー | | **`helpdesk`** | AI ファーストのカスタマーサポート | チケット + SLA + AI コパイロット | -| **`content`** | 編集カレンダー + チャネル ROI | ライフサイクル + メトリクス | | **`hr`** | 名簿、組織図、休暇 | 人を中心としたアプリ | | **`project`** | プロジェクト / タスク / マイルストーンの管理 | プロジェクト管理ツール | @@ -71,10 +66,7 @@ os package publish # → your marketplace | 構築しているもの | フォークするもの | 理由 | |---|---|---| -| 「もの」を追跡する社内ツール全般 | `todo` | すべてのプリミティブを示す最小で最もきれいな例 | -| 承認チェーンのあるもの全般 | `procurement` または `contracts` | 本物の承認プロセスが配線済み | | AI を使う顧客向けのもの全般 | `helpdesk` | エージェント + チケットのコパイロットのパターン | -| 規制業種のワークフロー | `compliance` | 監査 + 証跡 + 統制のマッピング | | 人 / 組織図のアプリ | `hr` | 名簿 + レポートライン | ## AI Builder とテンプレートを一緒に使う [#ai-builder--templates-together] diff --git a/content/docs/build/templates.mdx b/content/docs/build/templates.mdx index f585dc68..4db2b30e 100644 --- a/content/docs/build/templates.mdx +++ b/content/docs/build/templates.mdx @@ -1,7 +1,7 @@ --- title: Templates -seoTitle: "App Templates: Forkable Helpdesk, Contracts, Todo" -description: Forkable starter packages — `todo`, `contracts`, `procurement`, `helpdesk`, and more. +seoTitle: "App Templates: Forkable Helpdesk, HR, Project" +description: Forkable starter packages — `helpdesk`, `hr` and `project`. editions: [community, cloud, enterprise] --- @@ -20,12 +20,7 @@ Templates exist for two reasons: | Template | Domain | Forkable starter for… | |---|---|---| -| **`todo`** | Tasks & projects | Any "things to do, grouped somehow" tool | -| **`contracts`** | CLM with AI clause extraction | Approvals + document AI | -| **`procurement`** | Vendors, POs, 3-way match | Approval chains + receiving | -| **`compliance`** | SOC 2 / ISO 27001 controls | Evidence collection workflows | | **`helpdesk`** | AI-first customer support | Tickets + SLAs + AI co-pilot | -| **`content`** | Editorial calendar + channel ROI | Lifecycle + metrics | | **`hr`** | Directory, org chart, time-off | People-centric apps | | **`project`** | Project / task / milestone tracking | PM tools | @@ -85,10 +80,7 @@ and the polymorphic platform services (`sys_comment`, `sys_attachment`, | If you're building… | Fork this | Why | |---|---|---| -| Any internal tool that tracks "stuff" | `todo` | Smallest, cleanest demonstration of all primitives | -| Anything with approval chains | `procurement` or `contracts` | Real approval processes wired up | | Anything customer-facing with AI | `helpdesk` | Agent + ticket co-pilot pattern | -| A regulated-industry workflow | `compliance` | Audit + evidence + control mapping | | A people / org-chart app | `hr` | Directory + reporting structure | ## AI Builder + templates together diff --git a/content/docs/build/templates.zh-Hans.mdx b/content/docs/build/templates.zh-Hans.mdx index 7af7815d..e0d74460 100644 --- a/content/docs/build/templates.zh-Hans.mdx +++ b/content/docs/build/templates.zh-Hans.mdx @@ -1,10 +1,10 @@ --- title: 模板 -seoTitle: "应用模板:可 fork 的 Helpdesk、Contracts、Todo" -description: 可 fork 的入门包 —— `todo`、`contracts`、`procurement`、`helpdesk` 等等。 +seoTitle: "应用模板:可 fork 的 Helpdesk、HR、Project" +description: 可 fork 的入门包 —— `helpdesk`、`hr` 和 `project`。 editions: [community, cloud, enterprise] translation: - source_sha: 463d4f0100a6c89aa409bc10e01a61663dd4d3c6937fe19376fbc7a0e24145f8 + source_sha: b052030c2dd9f6e43f41795ed26eaa013fa71688790c2e263b577dd4db664589 guide_rev: 1 mode: auto --- @@ -22,12 +22,7 @@ translation: | 模板 | 领域 | 可 fork 作为……的起点 | |---|---|---| -| **`todo`** | 任务与项目 | 任何"要做的事,以某种方式分组"的工具 | -| **`contracts`** | 带 AI 条款提取的合同生命周期管理 | 审批 + 文档 AI | -| **`procurement`** | 供应商、采购订单、三单匹配 | 审批链 + 收货 | -| **`compliance`** | SOC 2 / ISO 27001 控制项 | 证据收集流程 | | **`helpdesk`** | AI 优先的客户支持 | 工单 + SLA + AI 副驾驶 | -| **`content`** | 编辑日历 + 渠道 ROI | 生命周期 + 指标 | | **`hr`** | 通讯录、组织架构图、休假 | 以人为中心的应用 | | **`project`** | 项目 / 任务 / 里程碑跟踪 | 项目管理工具 | @@ -82,10 +77,7 @@ os package publish # → your marketplace | 如果你在构建…… | Fork 这个 | 为什么 | |---|---|---| -| 任何跟踪"东西"的内部工具 | `todo` | 最小、最干净地展示了所有基本元素 | -| 任何带审批链的东西 | `procurement` 或 `contracts` | 接好了真实的审批流程 | | 任何面向客户且带 AI 的东西 | `helpdesk` | Agent + 工单副驾驶模式 | -| 受监管行业的业务流程 | `compliance` | 审计 + 证据 + 控制映射 | | 人员 / 组织架构应用 | `hr` | 通讯录 + 汇报结构 | ## AI Builder 与模板配合使用 [#ai-builder--templates-together] diff --git a/content/docs/build/templates.zh-Hant.mdx b/content/docs/build/templates.zh-Hant.mdx index 214fafae..d13bc8c2 100644 --- a/content/docs/build/templates.zh-Hant.mdx +++ b/content/docs/build/templates.zh-Hant.mdx @@ -1,11 +1,11 @@ --- # @generated zh-Hant from zh-Hans -- do not edit. Edit the English source, then regenerate: pnpm --filter @objectos/docs gen:zh-hant title: 模板 -seoTitle: "應用模板:可 fork 的 Helpdesk、Contracts、Todo" -description: 可 fork 的入門包 —— `todo`、`contracts`、`procurement`、`helpdesk` 等等。 +seoTitle: "應用模板:可 fork 的 Helpdesk、HR、Project" +description: 可 fork 的入門包 —— `helpdesk`、`hr` 和 `project`。 editions: [community, cloud, enterprise] translation: - source_sha: 463d4f0100a6c89aa409bc10e01a61663dd4d3c6937fe19376fbc7a0e24145f8 + source_sha: b052030c2dd9f6e43f41795ed26eaa013fa71688790c2e263b577dd4db664589 guide_rev: 1 mode: auto --- @@ -23,12 +23,7 @@ translation: | 模板 | 領域 | 可 fork 作為……的起點 | |---|---|---| -| **`todo`** | 任務與專案 | 任何"要做的事,以某種方式分組"的工具 | -| **`contracts`** | 帶 AI 條款提取的合同生命週期管理 | 審批 + 文件 AI | -| **`procurement`** | 供應商、採購訂單、三單匹配 | 審批鏈 + 收貨 | -| **`compliance`** | SOC 2 / ISO 27001 控制項 | 證據收集流程 | | **`helpdesk`** | AI 優先的客戶支援 | 工單 + SLA + AI 副駕駛 | -| **`content`** | 編輯日曆 + 渠道 ROI | 生命週期 + 指標 | | **`hr`** | 通訊錄、組織架構圖、休假 | 以人為中心的應用 | | **`project`** | 專案 / 任務 / 里程碑跟蹤 | 專案管理工具 | @@ -83,10 +78,7 @@ os package publish # → your marketplace | 如果你在構建…… | Fork 這個 | 為什麼 | |---|---|---| -| 任何跟蹤"東西"的內部工具 | `todo` | 最小、最乾淨地展示了所有基本元素 | -| 任何帶審批鏈的東西 | `procurement` 或 `contracts` | 接好了真實的審批流程 | | 任何面向客戶且帶 AI 的東西 | `helpdesk` | Agent + 工單副駕駛模式 | -| 受監管行業的業務流程 | `compliance` | 審計 + 證據 + 控制對映 | | 人員 / 組織架構應用 | `hr` | 通訊錄 + 彙報結構 | ## AI Builder 與模板配合使用 [#ai-builder--templates-together] diff --git a/content/docs/index.ja.mdx b/content/docs/index.ja.mdx index bbb07f51..62efb79d 100644 --- a/content/docs/index.ja.mdx +++ b/content/docs/index.ja.mdx @@ -4,7 +4,7 @@ seoTitle: "ドキュメント:開始、構築、デプロイ、運用" description: "ObjectOS Community は無料のセルフホスト版、ObjectOS Cloud はホスト型のエディション、ObjectOS Enterprise はセルフマネージドのライセンス制のエディションです。オントロジーはあなたのものです。" editions: [community, cloud, enterprise] translation: - source_sha: 266a61f0cec5ff11f2f82d9b2d731ec9cf61556722d41eeb9b49ed83e5d27997 + source_sha: a761d9c5d6626f005f40b9463d1126cbc14bdc255df4a692b7d953243fc284f5 guide_rev: 1 mode: auto --- @@ -26,7 +26,7 @@ translation: その後、ObjectOS Cloud と ObjectOS Enterprise は同じ場所へ導きます。サインインして、次のことができます。 - **AI Builder と対話する**:*「サポートチケットを優先度と担当者付きで管理したい」*。AI Builder があなたの[オントロジー](/docs/ontology)、つまりオブジェクトとそのフィールドを、あなたが承認する小さな差分として書くのを見届けます。[構築 → AI Builder](/docs/build/ai-builder) を参照してください。 -- **組み込みのマーケットプレイスからテンプレートをインストールする**(Todo、Contracts、Helpdesk など)と、ワンクリックで本物のアプリが手に入ります。 +- **組み込みのマーケットプレイスからテンプレートをインストールする**(Helpdesk など)と、ワンクリックで本物のアプリが手に入ります。 - **[テンプレート](/docs/build/templates)をフォークする**と、TypeScript ソースを自分の管理下に置けます。同じメタデータを、自分のリポジトリでコーディングエージェントとともに作成します。 ## なぜ …… ではなく ObjectOS なのか [#why-objectos-instead-of-] diff --git a/content/docs/index.mdx b/content/docs/index.mdx index bcc9f8fa..67a4c990 100644 --- a/content/docs/index.mdx +++ b/content/docs/index.mdx @@ -45,8 +45,8 @@ in, and: [ontology](/docs/ontology), the object and its fields, as a small diff you approve. See [Build → AI Builder](/docs/build/ai-builder). -- **Install a template** from the built-in marketplace (Todo, - Contracts, Helpdesk, …) and have a real app in one click. +- **Install a template** from the built-in marketplace (Helpdesk, + …) and have a real app in one click. - **Fork a [template](/docs/build/templates)** if you want TypeScript source under your control — the same metadata, authored in your repo with your coding agent. diff --git a/content/docs/index.zh-Hans.mdx b/content/docs/index.zh-Hans.mdx index bb6f8891..c665ac21 100644 --- a/content/docs/index.zh-Hans.mdx +++ b/content/docs/index.zh-Hans.mdx @@ -4,7 +4,7 @@ seoTitle: "文档:开始、构建、部署、运维" description: "ObjectOS Community 免费且自托管,ObjectOS Cloud 是托管版本,ObjectOS Enterprise 是自管理、需许可的版本。本体归你所有。" editions: [community, cloud, enterprise] translation: - source_sha: 266a61f0cec5ff11f2f82d9b2d731ec9cf61556722d41eeb9b49ed83e5d27997 + source_sha: a761d9c5d6626f005f40b9463d1126cbc14bdc255df4a692b7d953243fc284f5 guide_rev: 1 mode: auto --- @@ -37,7 +37,7 @@ translation: 看着它编写你的[本体](/docs/ontology),也就是对象及其字段,作为一个 由你批准的小 diff。参见 [构建 → AI Builder](/docs/build/ai-builder)。 -- **从内置市场安装一个模板**(Todo、Contracts、Helpdesk ……),一键 +- **从内置市场安装一个模板**(Helpdesk ……),一键 得到一个真正的应用。 - **Fork 一个[模板](/docs/build/templates)**,如果你想把 TypeScript 源码掌握在自己手中 —— 同样的元数据,在你的仓库里由你的编码 Agent diff --git a/content/docs/index.zh-Hant.mdx b/content/docs/index.zh-Hant.mdx index 66d35577..92796a5b 100644 --- a/content/docs/index.zh-Hant.mdx +++ b/content/docs/index.zh-Hant.mdx @@ -5,7 +5,7 @@ seoTitle: "文件:開始、構建、部署、運維" description: "ObjectOS Community 免費且自託管,ObjectOS Cloud 是託管版本,ObjectOS Enterprise 是自管理、需許可的版本。本體歸你所有。" editions: [community, cloud, enterprise] translation: - source_sha: 266a61f0cec5ff11f2f82d9b2d731ec9cf61556722d41eeb9b49ed83e5d27997 + source_sha: a761d9c5d6626f005f40b9463d1126cbc14bdc255df4a692b7d953243fc284f5 guide_rev: 1 mode: auto --- @@ -38,7 +38,7 @@ translation: 看著它編寫你的[本體](/docs/ontology),也就是物件及其欄位,作為一個 由你批准的小 diff。參見 [構建 → AI Builder](/docs/build/ai-builder)。 -- **從內建市場安裝一個模板**(Todo、Contracts、Helpdesk ……),一鍵 +- **從內建市場安裝一個模板**(Helpdesk ……),一鍵 得到一個真正的應用。 - **Fork 一個[模板](/docs/build/templates)**,如果你想把 TypeScript 原始碼掌握在自己手中 —— 同樣的後設資料,在你的倉庫裡由你的編碼 Agent diff --git a/content/docs/start/community.ja.mdx b/content/docs/start/community.ja.mdx index 450a8c0d..d65adfe5 100644 --- a/content/docs/start/community.ja.mdx +++ b/content/docs/start/community.ja.mdx @@ -4,7 +4,7 @@ seoTitle: "os start または os init で ObjectOS Community をローカルで description: "オープンソースのランタイムである ObjectOS Community で、ゼロから動作するアプリまで。ひとつの CLI、ひとつのコマンドで、アカウントも Docker も不要です。" editions: [community] translation: - source_sha: 830910eec853d34ebcd2357928eec4e753013766473391a72b60214c2479ce9e + source_sha: b730f9f4744c61db7f446009aa54953a4881d7d98e9355f789847cda13cac7d7 guide_rev: 1 mode: auto --- @@ -100,12 +100,7 @@ AI が計画を提案し、あなたが承認すると、メタデータが稼 | アプリ | 得られるもの | |---|---| -| Todo | 汎用のタスク & プロジェクト管理 | -| Contracts | AI による抽出付きの契約ライフサイクル | -| Procurement | ベンダー、発注書、3 点照合 | -| Compliance | SOC 2 / ISO 27001 の統制 + 証跡 | | Helpdesk | AI ファーストのカスタマーサポート | -| Content | 編集カレンダー + チャネル ROI | | HR | 名簿、組織図、休暇 | インストール → 再読み込み → そこにあります。オブジェクト、ビュー、権限、シードデータ付きです。再起動は不要です。 @@ -265,7 +260,7 @@ my-app/ ```bash git clone https://github.com/objectstack-ai/templates.git -cd templates/packages/todo +cd templates/packages/helpdesk pnpm install pnpm dev # http://localhost:4002 ``` diff --git a/content/docs/start/community.mdx b/content/docs/start/community.mdx index c5858168..01320753 100644 --- a/content/docs/start/community.mdx +++ b/content/docs/start/community.mdx @@ -134,12 +134,7 @@ Open **http://localhost:3000/_console/**, sign in, and pick an app: | App | What it gives you | |---|---| -| Todo | Universal task & project tracker | -| Contracts | Contract lifecycle with AI extraction | -| Procurement | Vendors, POs, 3-way match | -| Compliance | SOC 2 / ISO 27001 controls + evidence | | Helpdesk | AI-first customer support | -| Content | Editorial calendar + channel ROI | | HR | Directory, org chart, time-off | Install → reload → it's there, with its objects, views, permissions, @@ -333,7 +328,7 @@ Production-shaped starters live in ```bash git clone https://github.com/objectstack-ai/templates.git -cd templates/packages/todo +cd templates/packages/helpdesk pnpm install pnpm dev # http://localhost:4002 ``` diff --git a/content/docs/start/community.zh-Hans.mdx b/content/docs/start/community.zh-Hans.mdx index a40b76ac..d64aaa61 100644 --- a/content/docs/start/community.zh-Hans.mdx +++ b/content/docs/start/community.zh-Hans.mdx @@ -4,7 +4,7 @@ seoTitle: "用 os start 或 os init 在本地运行 ObjectOS Community" description: "在开源运行时 ObjectOS Community 上从零到一个运行中的应用:一个 CLI、一条命令,无需账户,也无需 Docker。" editions: [community] translation: - source_sha: 830910eec853d34ebcd2357928eec4e753013766473391a72b60214c2479ce9e + source_sha: b730f9f4744c61db7f446009aa54953a4881d7d98e9355f789847cda13cac7d7 guide_rev: 1 mode: auto --- @@ -127,12 +127,7 @@ AI 会提出一个计划,你批准,元数据就上线了 —— REST 端点 | 应用 | 它给你什么 | |---|---| -| Todo | 通用的任务与项目跟踪 | -| Contracts | 带 AI 提取的合同生命周期管理 | -| Procurement | 供应商、采购订单、三单匹配 | -| Compliance | SOC 2 / ISO 27001 控制项 + 证据 | | Helpdesk | AI 优先的客户支持 | -| Content | 编辑日历 + 渠道 ROI | | HR | 通讯录、组织架构图、休假 | 安装 → 刷新 → 它就在那里,带着它的对象、视图、权限和种子数据。不需要 @@ -323,7 +318,7 @@ my-app/ ```bash git clone https://github.com/objectstack-ai/templates.git -cd templates/packages/todo +cd templates/packages/helpdesk pnpm install pnpm dev # http://localhost:4002 ``` diff --git a/content/docs/start/community.zh-Hant.mdx b/content/docs/start/community.zh-Hant.mdx index b681f22d..112257be 100644 --- a/content/docs/start/community.zh-Hant.mdx +++ b/content/docs/start/community.zh-Hant.mdx @@ -5,7 +5,7 @@ seoTitle: "用 os start 或 os init 在本地執行 ObjectOS Community" description: "在開源執行時 ObjectOS Community 上從零到一個執行中的應用:一個 CLI、一條命令,無需賬戶,也無需 Docker。" editions: [community] translation: - source_sha: 830910eec853d34ebcd2357928eec4e753013766473391a72b60214c2479ce9e + source_sha: b730f9f4744c61db7f446009aa54953a4881d7d98e9355f789847cda13cac7d7 guide_rev: 1 mode: auto --- @@ -128,12 +128,7 @@ AI 會提出一個計劃,你批准,後設資料就上線了 —— REST 端 | 應用 | 它給你什麼 | |---|---| -| Todo | 通用的任務與專案跟蹤 | -| Contracts | 帶 AI 提取的合同生命週期管理 | -| Procurement | 供應商、採購訂單、三單匹配 | -| Compliance | SOC 2 / ISO 27001 控制項 + 證據 | | Helpdesk | AI 優先的客戶支援 | -| Content | 編輯日曆 + 渠道 ROI | | HR | 通訊錄、組織架構圖、休假 | 安裝 → 重新整理 → 它就在那裡,帶著它的物件、檢視、許可權和種子資料。不需要 @@ -324,7 +319,7 @@ my-app/ ```bash git clone https://github.com/objectstack-ai/templates.git -cd templates/packages/todo +cd templates/packages/helpdesk pnpm install pnpm dev # http://localhost:4002 ``` From 63f5c81b912e3a4a5090e68a5ed53768f26d02ce Mon Sep 17 00:00:00 2001 From: Steedos Date: Mon, 2 Nov 2026 04:34:59 +0000 Subject: [PATCH 18/22] docs(upgrade): JWT key rotation follows the deployment's own procedure (#423) Per the ruling on #334 Q4, the upgrade page's "Rotate the JWT signing keys" step gains one sentence: how the keys are rotated depends on how the deployment supplies them, so follow the deployment's own procedure. It names no mechanism, variable or command. zh-Hans and ja carry the same sentence and are restamped; zh-Hant is regenerated. Q2 and Q3 of the same ruling need no change; the seat measured both pages against it. Fixes #423 Claude-Session: https://claude.ai/code/session_01QsR2jRsjbApbf83iyTDDXm Co-Authored-By: Claude --- content/docs/operate/upgrade.ja.mdx | 4 ++-- content/docs/operate/upgrade.mdx | 4 +++- content/docs/operate/upgrade.zh-Hans.mdx | 5 +++-- content/docs/operate/upgrade.zh-Hant.mdx | 5 +++-- 4 files changed, 11 insertions(+), 7 deletions(-) diff --git a/content/docs/operate/upgrade.ja.mdx b/content/docs/operate/upgrade.ja.mdx index c55ccb0b..b1a77e64 100644 --- a/content/docs/operate/upgrade.ja.mdx +++ b/content/docs/operate/upgrade.ja.mdx @@ -3,7 +3,7 @@ title: アップグレードとロールバック description: データベースをバックアップしたうえで、固定する正確なイメージを変更して、セルフマネージドの ObjectOS デプロイメントをアップグレードまたはロールバックします。ObjectStack の各リリースが求めるオペレーターの手順も扱います。 editions: [community, enterprise] translation: - source_sha: 98d9f60a7e174ca49ba4e63e570cba5e24d158bd80e44ddfc9cc8d36d2fb0d5d + source_sha: 84053d7a6d6aeb5583bd30d31a1c8016563c090e2597bb15ff04ebac45aa292e guide_rev: 1 mode: auto --- @@ -122,7 +122,7 @@ os migrate account-issuer # again: expect zero collisions 最初の起動の後: - **すべてのフローのシークレット**(受信フックの `secret` と `http` ノードの `signingSecret`)**をローテーションします**。起動ログが `sys_flow_credential` に移動したと報告してから行い、署名または検証する人に新しい値を渡してください。 -- **JWT の署名キーをローテーションし、非公開のままにすべき共有リンクを取り消して再発行します。** 以前の値は監査証跡にコピーが残っている可能性があり、アップグレードはそれを書き換えません。 +- **JWT の署名キーをローテーションし、非公開のままにすべき共有リンクを取り消して再発行します。** 以前の値は監査証跡にコピーが残っている可能性があり、アップグレードはそれを書き換えません。署名キーのローテーション方法は、デプロイメントが署名キーをどのように提供しているかによって異なるため、デプロイメント自身の手順に従ってください。 - **アップグレード前に一時停止したフローの実行を、再開、キャンセル、またはパージします。** 保存された変数には、まだ認証情報が平文で残っています。 - **任意。17.7 より前にロールバックしないと決めてから:** `os secret rewrap` を実行してから `--apply` 付きでもう一度実行すると、古いシークレットが新しい形式で再封印されます。アップグレードの過程でこれが実行されることはありません。 - `/api/settings/localization` に書き込むクライアントから、**廃止されたローカライズのキーを削除します**:`date_format`、`time_format`、`number_format`、`first_day_of_week`。いずれかを指定したリクエストは、全体が `400` で拒否されます。 diff --git a/content/docs/operate/upgrade.mdx b/content/docs/operate/upgrade.mdx index 576c0a54..881fd63b 100644 --- a/content/docs/operate/upgrade.mdx +++ b/content/docs/operate/upgrade.mdx @@ -233,7 +233,9 @@ After the first boot: verifies. - **Rotate the JWT signing keys, and revoke and re-mint the share links that must stay private.** Their earlier values may have copies in the audit - trail, which the upgrade does not rewrite. + trail, which the upgrade does not rewrite. How you rotate the signing keys + depends on how your deployment supplies them, so follow your deployment's + own procedure. - **Resume, cancel or purge flow runs paused before the upgrade.** Their stored variables still hold credentials in clear. - **Optional, and only once you will not roll back past 17.7:** diff --git a/content/docs/operate/upgrade.zh-Hans.mdx b/content/docs/operate/upgrade.zh-Hans.mdx index 9c030938..9f193efd 100644 --- a/content/docs/operate/upgrade.zh-Hans.mdx +++ b/content/docs/operate/upgrade.zh-Hans.mdx @@ -3,7 +3,7 @@ title: 升级与回滚 description: 在备份数据库之后,通过更换固定的确切镜像来升级或回滚自管理的 ObjectOS 部署 —— 以及每个 ObjectStack 版本要求运维人员执行的步骤。 editions: [community, enterprise] translation: - source_sha: 98d9f60a7e174ca49ba4e63e570cba5e24d158bd80e44ddfc9cc8d36d2fb0d5d + source_sha: 84053d7a6d6aeb5583bd30d31a1c8016563c090e2597bb15ff04ebac45aa292e guide_rev: 1 mode: auto --- @@ -196,7 +196,8 @@ os migrate account-issuer # again: expect zero collisions 在启动日志报告它已迁移到 `sys_flow_credential` 之后进行,并把新值交给负责签名或 校验的一方。 - **轮换 JWT 签名密钥,并撤销和重新签发必须保持私密的分享链接。**它们之前的值可能 - 在审计轨迹中留有副本,而升级不会改写审计轨迹。 + 在审计轨迹中留有副本,而升级不会改写审计轨迹。如何轮换签名密钥取决于你的部署 + 如何提供这些密钥,因此请按照你的部署自己的流程进行。 - **恢复、取消或清除升级前暂停的流程运行。**它们存储的变量中仍以明文保存着凭据。 - **可选,并且只在你不会回滚到 17.7 之前时执行:**`os secret rewrap`,然后加 `--apply` 再运行一次,以新格式重新封装较旧的密钥。升级路径上没有任何东西会运行它。 diff --git a/content/docs/operate/upgrade.zh-Hant.mdx b/content/docs/operate/upgrade.zh-Hant.mdx index 94be2ac4..98c75913 100644 --- a/content/docs/operate/upgrade.zh-Hant.mdx +++ b/content/docs/operate/upgrade.zh-Hant.mdx @@ -4,7 +4,7 @@ title: 升級與回滾 description: 在備份資料庫之後,通過更換固定的確切映象來升級或回滾自管理的 ObjectOS 部署 —— 以及每個 ObjectStack 版本要求運維人員執行的步驟。 editions: [community, enterprise] translation: - source_sha: 98d9f60a7e174ca49ba4e63e570cba5e24d158bd80e44ddfc9cc8d36d2fb0d5d + source_sha: 84053d7a6d6aeb5583bd30d31a1c8016563c090e2597bb15ff04ebac45aa292e guide_rev: 1 mode: auto --- @@ -197,7 +197,8 @@ os migrate account-issuer # again: expect zero collisions 在啟動日誌報告它已遷移到 `sys_flow_credential` 之後進行,並把新值交給負責簽名或 校驗的一方。 - **輪換 JWT 簽名金鑰,並撤銷和重新簽發必須保持私密的分享連結。**它們之前的值可能 - 在審計軌跡中留有副本,而升級不會改寫審計軌跡。 + 在審計軌跡中留有副本,而升級不會改寫審計軌跡。如何輪換簽名金鑰取決於你的部署 + 如何提供這些金鑰,因此請按照你的部署自己的流程進行。 - **恢復、取消或清除升級前暫停的流程執行。**它們儲存的變數中仍以明文儲存著憑據。 - **可選,並且只在你不會回滾到 17.7 之前時執行:**`os secret rewrap`,然後加 `--apply` 再執行一次,以新格式重新封裝較舊的金鑰。升級路徑上沒有任何東西會執行它。 From 23375c49c794ed871f75e56e7a32b332f8f6cbd9 Mon Sep 17 00:00:00 2001 From: Steedos Date: Mon, 2 Nov 2026 04:56:13 +0000 Subject: [PATCH 19/22] docs(positioning): exporting a Cloud or Enterprise ontology to the open runtime is planned (#334 Q1) No mechanism exports a Cloud or Enterprise tenant's ontology to run on the open-source ObjectStack runtime yet. OBJECTOS_EDITIONS, the index opening paragraph, /llms.txt and 13 sentences across index, security, glossary, why, architecture and ontology now say the export is planned, and keep what is true today: the ontology is ordinary ObjectStack metadata, ObjectStack is Apache-2.0, and ObjectOS Community runs on your own machine. zh-Hans and ja follow, restamped; zh-Hant regenerated. Ruling-ref: objectstack-ai/docs.objectos.ai#334 comment 6568804196 Fixes #425 Claude-Session: https://claude.ai/code/session_01QsR2jRsjbApbf83iyTDDXm Co-Authored-By: Claude --- apps/docs/lib/positioning.ts | 15 ++++++++------- content/docs/architecture.ja.mdx | 4 ++-- content/docs/architecture.mdx | 4 ++-- content/docs/architecture.zh-Hans.mdx | 6 +++--- content/docs/architecture.zh-Hant.mdx | 6 +++--- content/docs/index.ja.mdx | 12 ++++++------ content/docs/index.mdx | 16 ++++++++-------- content/docs/index.zh-Hans.mdx | 14 +++++++------- content/docs/index.zh-Hant.mdx | 14 +++++++------- content/docs/ontology.ja.mdx | 4 ++-- content/docs/ontology.mdx | 4 ++-- content/docs/ontology.zh-Hans.mdx | 6 +++--- content/docs/ontology.zh-Hant.mdx | 6 +++--- content/docs/reference/security.ja.mdx | 4 ++-- content/docs/reference/security.mdx | 4 ++-- content/docs/reference/security.zh-Hans.mdx | 6 +++--- content/docs/reference/security.zh-Hant.mdx | 6 +++--- content/docs/resources/glossary.ja.mdx | 6 +++--- content/docs/resources/glossary.mdx | 8 ++++---- content/docs/resources/glossary.zh-Hans.mdx | 7 ++++--- content/docs/resources/glossary.zh-Hant.mdx | 7 ++++--- content/docs/why.ja.mdx | 8 ++++---- content/docs/why.mdx | 8 ++++---- content/docs/why.zh-Hans.mdx | 10 +++++----- content/docs/why.zh-Hant.mdx | 10 +++++----- 25 files changed, 99 insertions(+), 96 deletions(-) diff --git a/apps/docs/lib/positioning.ts b/apps/docs/lib/positioning.ts index 30e851da..524278af 100644 --- a/apps/docs/lib/positioning.ts +++ b/apps/docs/lib/positioning.ts @@ -61,14 +61,15 @@ export const OBJECTOS_DEFINITION = /** * The export clause. Not in the README: fixed by the maintainer's ruling on - * objectos#171, Q2, that a Cloud tenant can export its ontology and run it on - * the open runtime. It keeps the words this constant carried before #341, - * with "either edition" spelled out as the two editions it meant, because the - * definition above now names three. Q1, that ObjectOS still ships a - * self-managed edition, is now said by the README's sentence itself. + * docs.objectos.ai#334, Q1, that exporting a Cloud or Enterprise tenant's + * ontology to run it on the open runtime is planned, not shipped. Until that + * mechanism ships, the ruling supersedes objectos#171, Q2, which had said a + * tenant can do it today. The first sentence keeps what is true now; the + * second names the export as planned, with no date. Q1 of #171, that ObjectOS + * still ships a self-managed edition, is said by the README's sentence itself. */ export const OBJECTOS_EDITIONS = - 'On either ObjectOS Cloud or ObjectOS Enterprise, you can export your ontology and run it on the open-source ObjectStack runtime.'; + 'Your ontology is ordinary ObjectStack metadata. Exporting it from ObjectOS Cloud or ObjectOS Enterprise to run on the open-source ObjectStack runtime is planned.'; /** * The positioning paragraph every machine-facing surface carries, in this order @@ -85,7 +86,7 @@ export const POSITIONING = [ /** * The positioning in 160 characters or fewer, for the `/docs` meta description - * (objectos#299). `POSITIONING` is 517, and a search snippet cut it off inside + * (objectos#299). `POSITIONING` is 550, and a search snippet cut it off inside * the headline, before the word "ObjectOS". So this one leads with ObjectOS and * its three editions. It is built from the words above: each edition's words * in the README's sentence, and "you own it" from the promise. It is not a diff --git a/content/docs/architecture.ja.mdx b/content/docs/architecture.ja.mdx index e5a88fa4..2dd5745c 100644 --- a/content/docs/architecture.ja.mdx +++ b/content/docs/architecture.ja.mdx @@ -4,7 +4,7 @@ seoTitle: "アーキテクチャ:何が動き、データがどこにあるか description: 実際に何を動かすことになるのか。導入するかどうかを評価しているエンジニアのために。 editions: [community, cloud, enterprise] translation: - source_sha: 2ba24bbe881fd5788bce400a2ab8042ab41ee849a2af902d99573d2b2cfdb083 + source_sha: bbe700e15ebafc61f77d67d087d1cb8632b4ae7bdc28e822dea794e6ae8fa0d1 guide_rev: 1 mode: auto --- @@ -67,7 +67,7 @@ ObjectOS runtime ## データの置き場所 [#where-your-data-lives] -**ObjectOS Enterprise**(この表が記述するセルフマネージドのエディション)では、以下のものはどれもネットワークの外に出ません。**ObjectOS Cloud** では、同じプロセスが代わりに私たちのインフラストラクチャで動作します。どちらのエディションでも、オントロジー自体はあなたのものです。エクスポートして、オープンソースの ObjectStack ランタイムで実行できます。[データレジデンシー](/docs/reference/security#data-residency)には、データの各分類について、どこに保存され、ネットワークの外に出るかどうかが記載されています。 +**ObjectOS Enterprise**(この表が記述するセルフマネージドのエディション)では、以下のものはどれもネットワークの外に出ません。**ObjectOS Cloud** では、同じプロセスが代わりに私たちのインフラストラクチャで動作します。どちらのエディションでも、オントロジー自体は通常の ObjectStack メタデータです。エクスポートしてオープンソースの ObjectStack ランタイムで実行する機能は計画中です。[データレジデンシー](/docs/reference/security#data-residency)には、データの各分類について、どこに保存され、ネットワークの外に出るかどうかが記載されています。 セルフマネージドの ObjectOS はライセンスをオンラインで検証します。Enterprise のエアギャップライセンスはオフラインで検証します。したがって、インターネットにまったくアクセスできないデプロイメントも動作し続けます。サポートされるライセンスとクラウドの姿勢の組み合わせについては、[エアギャップ](/docs/deploy/air-gapped)を参照してください。 diff --git a/content/docs/architecture.mdx b/content/docs/architecture.mdx index 9510db4e..e2de36ce 100644 --- a/content/docs/architecture.mdx +++ b/content/docs/architecture.mdx @@ -91,8 +91,8 @@ one; see [Docker](/docs/deploy/docker). On **ObjectOS Enterprise** — the self-managed edition this table describes — nothing below leaves your network. On **ObjectOS Cloud** the same process runs in our infrastructure instead, and on either edition the ontology -itself is yours: export it and run it on the open-source ObjectStack -runtime. [Data residency](/docs/reference/security#data-residency) lists +itself is ordinary ObjectStack metadata; exporting it to run on the +open-source ObjectStack runtime is planned. [Data residency](/docs/reference/security#data-residency) lists each class of data, where it lives, and whether it leaves your network. Self-managed ObjectOS validates its license online; Enterprise air-gapped diff --git a/content/docs/architecture.zh-Hans.mdx b/content/docs/architecture.zh-Hans.mdx index ed327ad8..368de3f6 100644 --- a/content/docs/architecture.zh-Hans.mdx +++ b/content/docs/architecture.zh-Hans.mdx @@ -4,7 +4,7 @@ seoTitle: "架构:运行什么,数据在哪里" description: 你实际在运行的是什么 —— 写给正在评估是否引入它的工程师。 editions: [community, cloud, enterprise] translation: - source_sha: 2ba24bbe881fd5788bce400a2ab8042ab41ee849a2af902d99573d2b2cfdb083 + source_sha: bbe700e15ebafc61f77d67d087d1cb8632b4ae7bdc28e822dea794e6ae8fa0d1 guide_rev: 1 mode: auto --- @@ -88,8 +88,8 @@ Kafka,也不需要单独的缓存层。等你需要时再加上它们;不必 在 **ObjectOS Enterprise** 上 —— 也就是下面这张表所描述的自管理版本 —— 下列任何内容都不会离开你的网络。在 **ObjectOS Cloud** 上,同样的进程 -改为运行在我们的基础设施中;无论哪个版本,本体本身都归你:导出它并在 -开源的 ObjectStack 运行时上运行。[数据驻留](/docs/reference/security#data-residency) +改为运行在我们的基础设施中;无论哪个版本,本体本身都是普通的 ObjectStack +元数据,把它导出到开源的 ObjectStack 运行时上运行尚在计划中。[数据驻留](/docs/reference/security#data-residency) 列出了每一类数据、它存放在哪里,以及它是否会离开你的网络。 自管理的 ObjectOS 会在线校验许可证;Enterprise 物理隔离许可证则离线 diff --git a/content/docs/architecture.zh-Hant.mdx b/content/docs/architecture.zh-Hant.mdx index b804fb27..efb443d1 100644 --- a/content/docs/architecture.zh-Hant.mdx +++ b/content/docs/architecture.zh-Hant.mdx @@ -5,7 +5,7 @@ seoTitle: "架構:執行什麼,資料在哪裡" description: 你實際在執行的是什麼 —— 寫給正在評估是否引入它的工程師。 editions: [community, cloud, enterprise] translation: - source_sha: 2ba24bbe881fd5788bce400a2ab8042ab41ee849a2af902d99573d2b2cfdb083 + source_sha: bbe700e15ebafc61f77d67d087d1cb8632b4ae7bdc28e822dea794e6ae8fa0d1 guide_rev: 1 mode: auto --- @@ -89,8 +89,8 @@ Kafka,也不需要單獨的快取層。等你需要時再加上它們;不必 在 **ObjectOS Enterprise** 上 —— 也就是下面這張表所描述的自管理版本 —— 下列任何內容都不會離開你的網路。在 **ObjectOS Cloud** 上,同樣的程序 -改為執行在我們的基礎設施中;無論哪個版本,本體本身都歸你:匯出它並在 -開源的 ObjectStack 執行時上執行。[資料駐留](/docs/reference/security#data-residency) +改為執行在我們的基礎設施中;無論哪個版本,本體本身都是普通的 ObjectStack +後設資料,把它匯出到開源的 ObjectStack 執行時上執行尚在計劃中。[資料駐留](/docs/reference/security#data-residency) 列出了每一類資料、它存放在哪裡,以及它是否會離開你的網路。 自管理的 ObjectOS 會線上校驗許可證;Enterprise 物理隔離許可證則離線 diff --git a/content/docs/index.ja.mdx b/content/docs/index.ja.mdx index 62efb79d..359f7dbe 100644 --- a/content/docs/index.ja.mdx +++ b/content/docs/index.ja.mdx @@ -4,12 +4,12 @@ seoTitle: "ドキュメント:開始、構築、デプロイ、運用" description: "ObjectOS Community は無料のセルフホスト版、ObjectOS Cloud はホスト型のエディション、ObjectOS Enterprise はセルフマネージドのライセンス制のエディションです。オントロジーはあなたのものです。" editions: [community, cloud, enterprise] translation: - source_sha: a761d9c5d6626f005f40b9463d1126cbc14bdc255df4a692b7d953243fc284f5 + source_sha: a094a61ace740d1dca8c9558c150f4a779dcbc4827165c989c34ecb9554da791 guide_rev: 1 mode: auto --- -オントロジーこそがソフトウェアです。実行可能なひとつのビジネスオントロジー。AI が書き、ランタイムが実行し、エージェントが操作し、あなたが所有します。それを実行するために、ObjectStack リポジトリは ObjectOS Community(ghcr.io/objectstack-ai/objectstack イメージ、os start、Console からなる、無料のセルフホスト版)を提供し、ObjectOS Cloud はホスト型のエディション、ObjectOS Enterprise はセルフマネージドのライセンス制のエディションです。ObjectOS Cloud と ObjectOS Enterprise のどちらでも、オントロジーをエクスポートして、オープンソースの ObjectStack ランタイムで実行できます。 +オントロジーこそがソフトウェアです。実行可能なひとつのビジネスオントロジー。AI が書き、ランタイムが実行し、エージェントが操作し、あなたが所有します。それを実行するために、ObjectStack リポジトリは ObjectOS Community(ghcr.io/objectstack-ai/objectstack イメージ、os start、Console からなる、無料のセルフホスト版)を提供し、ObjectOS Cloud はホスト型のエディション、ObjectOS Enterprise はセルフマネージドのライセンス制のエディションです。オントロジーは通常の ObjectStack メタデータです。ObjectOS Cloud または ObjectOS Enterprise からエクスポートしてオープンソースの ObjectStack ランタイムで実行する機能は、計画中です。 ビジネスに必要なもの(ヘルプデスク、承認フロー、CRM)を組み込みの [AI Builder](/docs/build/ai-builder) に説明するか、テンプレートをインストールすると、それが書いたオントロジーは即座に稼働します。REST API、生成された画面、認証、RBAC、監査ログ、ファイルストレージ、バックグラウンドジョブ、Webhook、そしてエージェントが呼び出せる MCP ツールとして公開されたすべてのオブジェクトです。各変更は小さく読みやすい差分で、実行前に人が承認します。 @@ -33,9 +33,9 @@ translation: | 今使っているもの | 課題 | ObjectOS が提供するもの | |---|---|---| -| **Retool / Appsmith** | UI ビルダーは優れているが、データは彼らのクラウドにあり、料金はユーザー数に比例して増える | ホスト型(ObjectOS Cloud)またはあなたのネットワーク内(ObjectOS Enterprise)。オープンソースの ObjectStack(Apache-2.0)上に構築されているため、オントロジーは自由にエクスポートできます。シート課金なし、AI シートのみ | -| **Supabase / Firebase** | BaaS は速いがベンダーロックイン。設計上マルチテナント SaaS | 同じ開発体験(自動 API、認証、ストレージ)ですが、定義はあなたのものです。エクスポートしてオープンな ObjectStack ランタイムで実行するか、自社のデータベース上で ObjectOS Enterprise を実行します | -| **Salesforce / NetSuite** | 強力なプラットフォームだが、カスタマイズは苦痛で、シート単価は目が飛び出るほど高い | 馴染みのある語彙(オブジェクト、フィールド、権限セット、共有ルール)ですが、定義は AI が書き、エージェントが操作し、Apache-2.0 ランタイムへエクスポートできるオープンなオントロジーです。ホスト型でもセルフマネージドでも、シート課金なし。閲覧者と AI を使わないユーザーは無料です | +| **Retool / Appsmith** | UI ビルダーは優れているが、データは彼らのクラウドにあり、料金はユーザー数に比例して増える | ホスト型(ObjectOS Cloud)またはあなたのネットワーク内(ObjectOS Enterprise)。オントロジーはオープンソースの ObjectStack(Apache-2.0)の通常のメタデータで、そのランタイムへのエクスポートは計画中です。シート課金なし、AI シートのみ | +| **Supabase / Firebase** | BaaS は速いがベンダーロックイン。設計上マルチテナント SaaS | 同じ開発体験(自動 API、認証、ストレージ)ですが、定義はあなたのものです。自社のデータベース上で ObjectOS Enterprise を、自分のマシン上で ObjectOS Community を実行できます。ObjectOS Cloud からオープンな ObjectStack ランタイムへのエクスポートは計画中です | +| **Salesforce / NetSuite** | 強力なプラットフォームだが、カスタマイズは苦痛で、シート単価は目が飛び出るほど高い | 馴染みのある語彙(オブジェクト、フィールド、権限セット、共有ルール)ですが、定義は AI が書き、エージェントが操作するオープンなオントロジーで、Apache-2.0 の ObjectStack ランタイムの通常のメタデータです。そのランタイムへのエクスポートは計画中です。ホスト型でもセルフマネージドでも、シート課金なし。閲覧者と AI を使わないユーザーは無料です | | **自前で構築(Next + Prisma + NextAuth)** | RBAC、監査、ファイルアップロード、設定、Webhook、ジョブを毎回作り直す | 本来のビジネスロジックを出荷できます。プラットフォームの配管はすでに揃っています | ## 標準で得られるもの [#what-you-get-out-of-the-box] @@ -50,7 +50,7 @@ translation: ## あなたの手元に残るもの [#what-stays-yours] -どちらのエディションでも、オントロジーはあなたのものです。オブジェクト、フィールド、リレーション、アクション、権限、フロー、エージェント定義は通常の ObjectStack メタデータであり、エクスポートしてオープンソースの ObjectStack ランタイムで実行できます。**ObjectOS Enterprise** では、それ以外のものもすべてあなたの手元に残ります。[データレジデンシー](/docs/reference/security#data-residency)には、データの各分類について、どこに保存され、ネットワークの外に出るかどうかが記載されています。 +どちらのエディションでも、オントロジーはあなたのものです。オブジェクト、フィールド、リレーション、アクション、権限、フロー、エージェント定義は通常の ObjectStack メタデータです。それらをエクスポートしてオープンソースの ObjectStack ランタイムで実行する機能は計画中です。**ObjectOS Enterprise** では、それ以外のものもすべてあなたの手元に残ります。[データレジデンシー](/docs/reference/security#data-residency)には、データの各分類について、どこに保存され、ネットワークの外に出るかどうかが記載されています。 セルフマネージドの ObjectOS はライセンスをオンラインで検証します。Enterprise のエアギャップライセンスはオフラインで検証します。したがって、インターネットにアクセスできないネットワークは Enterprise の正式なデプロイ先です。[エアギャップ](/docs/deploy/air-gapped)を参照してください。 diff --git a/content/docs/index.mdx b/content/docs/index.mdx index 67a4c990..a30c2575 100644 --- a/content/docs/index.mdx +++ b/content/docs/index.mdx @@ -10,9 +10,9 @@ it, the runtime runs it, agents operate it, you own it. To run it, the ObjectStack repository ships ObjectOS Community — the ghcr.io/objectstack-ai/objectstack image, os start and the Console, free and self-hosted — while ObjectOS Cloud is the hosted edition and ObjectOS -Enterprise the self-managed, licensed one. On either ObjectOS Cloud or -ObjectOS Enterprise, you can export your ontology and run it on the -open-source ObjectStack runtime. +Enterprise the self-managed, licensed one. Your ontology is ordinary +ObjectStack metadata. Exporting it from ObjectOS Cloud or ObjectOS +Enterprise to run on the open-source ObjectStack runtime is planned. Describe what the business needs to the built-in [AI Builder](/docs/build/ai-builder) — a helpdesk, an approval flow, a CRM @@ -55,9 +55,9 @@ in, and: | You're using | Pain point | What ObjectOS gives you | |---|---|---| -| **Retool / Appsmith** | UI builder is great, but your data sits in their cloud and their pricing scales with users | Hosted (ObjectOS Cloud) or inside your network (ObjectOS Enterprise); built on open-source ObjectStack (Apache-2.0), so the ontology is yours to export; no seat tax — AI seats only | -| **Supabase / Firebase** | Backend-as-a-service is fast but vendor-locked; multi-tenant SaaS by design | Same DX (auto APIs, auth, storage), but the definition is yours: export it and run it on the open ObjectStack runtime, or run ObjectOS Enterprise on your own database | -| **Salesforce / NetSuite** | Powerful platform, painful customization, eye-watering per-seat cost | A familiar vocabulary (objects, fields, permission sets, sharing rules), but the definition is an open ontology that AI writes, agents operate, and you can export to the Apache-2.0 runtime; hosted or self-managed, no seat tax — viewers and non-AI users are free | +| **Retool / Appsmith** | UI builder is great, but your data sits in their cloud and their pricing scales with users | Hosted (ObjectOS Cloud) or inside your network (ObjectOS Enterprise); the ontology is ordinary metadata for open-source ObjectStack (Apache-2.0), with export to that runtime planned; no seat tax — AI seats only | +| **Supabase / Firebase** | Backend-as-a-service is fast but vendor-locked; multi-tenant SaaS by design | Same DX (auto APIs, auth, storage), but the definition is yours: run ObjectOS Enterprise on your own database, or ObjectOS Community on your own machine; export from ObjectOS Cloud to the open ObjectStack runtime is planned | +| **Salesforce / NetSuite** | Powerful platform, painful customization, eye-watering per-seat cost | A familiar vocabulary (objects, fields, permission sets, sharing rules), but the definition is an open ontology that AI writes and agents operate, as ordinary metadata for the Apache-2.0 ObjectStack runtime, with export to it planned; hosted or self-managed, no seat tax — viewers and non-AI users are free | | **Rolling your own (Next + Prisma + NextAuth)** | You rebuild RBAC, audit, file uploads, settings, webhooks, jobs every time | Ship the actual business logic; the platform plumbing is already there | ## What you get out of the box @@ -74,8 +74,8 @@ in, and: On either edition, the ontology: your objects, fields, relations, actions, permissions, flows and agent definitions are ordinary ObjectStack metadata, -and you can export them and run them on the open-source ObjectStack -runtime. On **ObjectOS Enterprise**, everything else stays with you too: +and exporting them to run on the open-source ObjectStack runtime is +planned. On **ObjectOS Enterprise**, everything else stays with you too: [Data residency](/docs/reference/security#data-residency) lists each class of data, where it lives, and whether it leaves your network. diff --git a/content/docs/index.zh-Hans.mdx b/content/docs/index.zh-Hans.mdx index c665ac21..f3396052 100644 --- a/content/docs/index.zh-Hans.mdx +++ b/content/docs/index.zh-Hans.mdx @@ -4,12 +4,12 @@ seoTitle: "文档:开始、构建、部署、运维" description: "ObjectOS Community 免费且自托管,ObjectOS Cloud 是托管版本,ObjectOS Enterprise 是自管理、需许可的版本。本体归你所有。" editions: [community, cloud, enterprise] translation: - source_sha: a761d9c5d6626f005f40b9463d1126cbc14bdc255df4a692b7d953243fc284f5 + source_sha: a094a61ace740d1dca8c9558c150f4a779dcbc4827165c989c34ecb9554da791 guide_rev: 1 mode: auto --- -本体就是软件。一个可执行的业务本体:AI 编写它,运行时运行它,Agent 操作它,你拥有它。为了运行它,ObjectStack 仓库提供 ObjectOS Community —— ghcr.io/objectstack-ai/objectstack 镜像、os start 和 Console,免费且自托管 —— 而 ObjectOS Cloud 是托管版本,ObjectOS Enterprise 是自管理、需许可的版本。无论在 ObjectOS Cloud 还是 ObjectOS Enterprise 上,你都可以导出你的本体,并在开源的 ObjectStack 运行时上运行它。 +本体就是软件。一个可执行的业务本体:AI 编写它,运行时运行它,Agent 操作它,你拥有它。为了运行它,ObjectStack 仓库提供 ObjectOS Community —— ghcr.io/objectstack-ai/objectstack 镜像、os start 和 Console,免费且自托管 —— 而 ObjectOS Cloud 是托管版本,ObjectOS Enterprise 是自管理、需许可的版本。你的本体是普通的 ObjectStack 元数据。从 ObjectOS Cloud 或 ObjectOS Enterprise 导出本体、在开源的 ObjectStack 运行时上运行,目前尚在计划中。 向内置的 [AI Builder](/docs/build/ai-builder) 描述业务需要什么 —— 一个 服务台、一条审批流程、一个 CRM —— 或者安装一个模板,它写出的本体会立即 @@ -47,9 +47,9 @@ translation: | 你正在用 | 痛点 | ObjectOS 给你什么 | |---|---|---| -| **Retool / Appsmith** | UI 构建器很好,但你的数据放在他们的云里,价格随用户数增长 | 托管(ObjectOS Cloud)或在你的网络内(ObjectOS Enterprise);构建在开源的 ObjectStack(Apache-2.0)之上,所以本体由你导出;没有按席位收的税 —— 只收 AI 席位 | -| **Supabase / Firebase** | 后端即服务很快,但被厂商锁定;天生就是多租户 SaaS | 同样的开发体验(自动 API、认证、存储),但定义归你:导出它并在开源的 ObjectStack 运行时上运行,或在你自己的数据库上运行 ObjectOS Enterprise | -| **Salesforce / NetSuite** | 平台强大,定制痛苦,按席位的费用高得吓人 | 熟悉的词汇(对象、字段、权限集、共享规则),但定义是一个开放的本体:AI 编写,Agent 操作,你可以把它导出到 Apache-2.0 运行时;托管或自管理,没有席位税 —— 只读用户和非 AI 用户免费 | +| **Retool / Appsmith** | UI 构建器很好,但你的数据放在他们的云里,价格随用户数增长 | 托管(ObjectOS Cloud)或在你的网络内(ObjectOS Enterprise);本体是开源 ObjectStack(Apache-2.0)的普通元数据,导出到该运行时尚在计划中;没有按席位收的税 —— 只收 AI 席位 | +| **Supabase / Firebase** | 后端即服务很快,但被厂商锁定;天生就是多租户 SaaS | 同样的开发体验(自动 API、认证、存储),但定义归你:在你自己的数据库上运行 ObjectOS Enterprise,或在你自己的机器上运行 ObjectOS Community;从 ObjectOS Cloud 导出到开放的 ObjectStack 运行时尚在计划中 | +| **Salesforce / NetSuite** | 平台强大,定制痛苦,按席位的费用高得吓人 | 熟悉的词汇(对象、字段、权限集、共享规则),但定义是一个开放的本体:AI 编写,Agent 操作,是 Apache-2.0 ObjectStack 运行时的普通元数据,导出到该运行时尚在计划中;托管或自管理,没有席位税 —— 只读用户和非 AI 用户免费 | | **自己从头搭(Next + Prisma + NextAuth)** | 每次都要重做 RBAC、审计、文件上传、设置、Webhook、任务 | 只交付真正的业务逻辑;平台的基础设施已经在那里了 | ## 开箱即得 [#what-you-get-out-of-the-box] @@ -65,8 +65,8 @@ translation: ## 什么始终归你 [#what-stays-yours] 无论哪个版本,本体都归你:你的对象、字段、关系、动作、权限、流程和 -Agent 定义都是普通的 ObjectStack 元数据,你可以导出它们并在开源的 -ObjectStack 运行时上运行。在 **ObjectOS Enterprise** 上,其他一切也都 +Agent 定义都是普通的 ObjectStack 元数据;把它们导出到开源的 ObjectStack +运行时上运行,目前尚在计划中。在 **ObjectOS Enterprise** 上,其他一切也都 留在你这里:[数据驻留](/docs/reference/security#data-residency) 列出了 每一类数据、它存放在哪里,以及它是否会离开你的网络。 diff --git a/content/docs/index.zh-Hant.mdx b/content/docs/index.zh-Hant.mdx index 92796a5b..68b599f6 100644 --- a/content/docs/index.zh-Hant.mdx +++ b/content/docs/index.zh-Hant.mdx @@ -5,12 +5,12 @@ seoTitle: "文件:開始、構建、部署、運維" description: "ObjectOS Community 免費且自託管,ObjectOS Cloud 是託管版本,ObjectOS Enterprise 是自管理、需許可的版本。本體歸你所有。" editions: [community, cloud, enterprise] translation: - source_sha: a761d9c5d6626f005f40b9463d1126cbc14bdc255df4a692b7d953243fc284f5 + source_sha: a094a61ace740d1dca8c9558c150f4a779dcbc4827165c989c34ecb9554da791 guide_rev: 1 mode: auto --- -本體就是軟體。一個可執行的業務本體:AI 編寫它,執行時執行它,Agent 操作它,你擁有它。為了執行它,ObjectStack 倉庫提供 ObjectOS Community —— ghcr.io/objectstack-ai/objectstack 映象、os start 和 Console,免費且自託管 —— 而 ObjectOS Cloud 是託管版本,ObjectOS Enterprise 是自管理、需許可的版本。無論在 ObjectOS Cloud 還是 ObjectOS Enterprise 上,你都可以匯出你的本體,並在開源的 ObjectStack 執行時上執行它。 +本體就是軟體。一個可執行的業務本體:AI 編寫它,執行時執行它,Agent 操作它,你擁有它。為了執行它,ObjectStack 倉庫提供 ObjectOS Community —— ghcr.io/objectstack-ai/objectstack 映象、os start 和 Console,免費且自託管 —— 而 ObjectOS Cloud 是託管版本,ObjectOS Enterprise 是自管理、需許可的版本。你的本體是普通的 ObjectStack 後設資料。從 ObjectOS Cloud 或 ObjectOS Enterprise 匯出本體、在開源的 ObjectStack 執行時上執行,目前尚在計劃中。 向內建的 [AI Builder](/docs/build/ai-builder) 描述業務需要什麼 —— 一個 服務檯、一條審批流程、一個 CRM —— 或者安裝一個模板,它寫出的本體會立即 @@ -48,9 +48,9 @@ translation: | 你正在用 | 痛點 | ObjectOS 給你什麼 | |---|---|---| -| **Retool / Appsmith** | UI 構建器很好,但你的資料放在他們的雲裡,價格隨使用者數增長 | 託管(ObjectOS Cloud)或在你的網路內(ObjectOS Enterprise);構建在開源的 ObjectStack(Apache-2.0)之上,所以本體由你匯出;沒有按席位收的稅 —— 只收 AI 席位 | -| **Supabase / Firebase** | 後端即服務很快,但被廠商鎖定;天生就是多租戶 SaaS | 同樣的開發體驗(自動 API、認證、儲存),但定義歸你:匯出它並在開源的 ObjectStack 執行時上執行,或在你自己的資料庫上執行 ObjectOS Enterprise | -| **Salesforce / NetSuite** | 平臺強大,定製痛苦,按席位的費用高得嚇人 | 熟悉的詞彙(物件、欄位、許可權集、共享規則),但定義是一個開放的本體:AI 編寫,Agent 操作,你可以把它匯出到 Apache-2.0 執行時;託管或自管理,沒有席位稅 —— 只讀使用者和非 AI 使用者免費 | +| **Retool / Appsmith** | UI 構建器很好,但你的資料放在他們的雲裡,價格隨使用者數增長 | 託管(ObjectOS Cloud)或在你的網路內(ObjectOS Enterprise);本體是開源 ObjectStack(Apache-2.0)的普通後設資料,匯出到該執行時尚在計劃中;沒有按席位收的稅 —— 只收 AI 席位 | +| **Supabase / Firebase** | 後端即服務很快,但被廠商鎖定;天生就是多租戶 SaaS | 同樣的開發體驗(自動 API、認證、儲存),但定義歸你:在你自己的資料庫上執行 ObjectOS Enterprise,或在你自己的機器上執行 ObjectOS Community;從 ObjectOS Cloud 匯出到開放的 ObjectStack 執行時尚在計劃中 | +| **Salesforce / NetSuite** | 平臺強大,定製痛苦,按席位的費用高得嚇人 | 熟悉的詞彙(物件、欄位、許可權集、共享規則),但定義是一個開放的本體:AI 編寫,Agent 操作,是 Apache-2.0 ObjectStack 執行時的普通後設資料,匯出到該執行時尚在計劃中;託管或自管理,沒有席位稅 —— 只讀使用者和非 AI 使用者免費 | | **自己從頭搭(Next + Prisma + NextAuth)** | 每次都要重做 RBAC、審計、檔案上傳、設定、Webhook、任務 | 只交付真正的業務邏輯;平臺的基礎設施已經在那裡了 | ## 開箱即得 [#what-you-get-out-of-the-box] @@ -66,8 +66,8 @@ translation: ## 什麼始終歸你 [#what-stays-yours] 無論哪個版本,本體都歸你:你的物件、欄位、關係、動作、許可權、流程和 -Agent 定義都是普通的 ObjectStack 後設資料,你可以匯出它們並在開源的 -ObjectStack 執行時上執行。在 **ObjectOS Enterprise** 上,其他一切也都 +Agent 定義都是普通的 ObjectStack 後設資料;把它們匯出到開源的 ObjectStack +執行時上執行,目前尚在計劃中。在 **ObjectOS Enterprise** 上,其他一切也都 留在你這裡:[資料駐留](/docs/reference/security#data-residency) 列出了 每一類資料、它存放在哪裡,以及它是否會離開你的網路。 diff --git a/content/docs/ontology.ja.mdx b/content/docs/ontology.ja.mdx index ebcec30c..55d56fc3 100644 --- a/content/docs/ontology.ja.mdx +++ b/content/docs/ontology.ja.mdx @@ -4,7 +4,7 @@ seoTitle: "ObjectOS におけるあなたのオントロジー:コア、プロ description: ObjectOS におけるあなたのオントロジーとは何か。ランタイムが実行するコア、その横で作成されるプロジェクション、置き場所、そしてオントロジーでないものを説明します。 editions: [community, cloud, enterprise] translation: - source_sha: 89b7e2e2e35db3cfc1e321a759eade603c86bbf958670a2c0abd7952bb51a8ab + source_sha: ca1fa33231f6faec71367a17c00b189310ba3d03766852c1072b46730f1f2f9a guide_rev: 1 mode: auto --- @@ -45,7 +45,7 @@ translation: | **リポジトリのソース** | 開発者とそのコーディングエージェントが [AI スキル](/docs/build/ai-skills)を使って書くもの:`objectstack.config.ts` とそのメタデータファイル。プルリクエストとしてレビューされます | | **コンパイル済みアーティファクト** | `os compile` が生成するもの:デプロイメントが起動に使う `objectstack.json`。[起動モード](/docs/architecture#boot-modes)を参照してください。公開したものはすべて保管してください([バックアップ](/docs/operate/backup)) | -どの形で作成しても、メタデータは実行される前に同じ[検証ゲート](/docs/resources/glossary#validation-gate)を通過します。どちらのエディションでも、オントロジーはあなたのものです。通常の ObjectStack メタデータであり、エクスポートしてオープンソースの ObjectStack ランタイムで実行できます。 +どの形で作成しても、メタデータは実行される前に同じ[検証ゲート](/docs/resources/glossary#validation-gate)を通過します。どちらのエディションでも、オントロジーはあなたのものです。通常の ObjectStack メタデータであり、エクスポートしてオープンソースの ObjectStack ランタイムで実行する機能は計画中です。 ## オントロジーでないもの [#what-it-is-not] diff --git a/content/docs/ontology.mdx b/content/docs/ontology.mdx index f2975ab4..f3a388b3 100644 --- a/content/docs/ontology.mdx +++ b/content/docs/ontology.mdx @@ -53,8 +53,8 @@ One definition, in three forms: Whichever form you author in, the metadata passes the same [validation gate](/docs/resources/glossary#validation-gate) before it runs. On either edition the ontology is yours: it is ordinary ObjectStack -metadata, and you can export it and run it on the open-source ObjectStack -runtime. +metadata, and exporting it to run on the open-source ObjectStack runtime is +planned. ## What it is not diff --git a/content/docs/ontology.zh-Hans.mdx b/content/docs/ontology.zh-Hans.mdx index a5299ad6..41f55e1a 100644 --- a/content/docs/ontology.zh-Hans.mdx +++ b/content/docs/ontology.zh-Hans.mdx @@ -4,7 +4,7 @@ seoTitle: "ObjectOS 中你的本体:核心、投影、存放位置" description: 在 ObjectOS 上你的本体是什么 —— 运行时运行的核心、在它旁边编写的投影、它存放在哪里,以及它不是什么。 editions: [community, cloud, enterprise] translation: - source_sha: 89b7e2e2e35db3cfc1e321a759eade603c86bbf958670a2c0abd7952bb51a8ab + source_sha: ca1fa33231f6faec71367a17c00b189310ba3d03766852c1072b46730f1f2f9a guide_rev: 1 mode: auto --- @@ -53,8 +53,8 @@ translation: 无论你用哪种形态编写,元数据在运行之前都会通过同一道 [校验关口](/docs/resources/glossary#validation-gate)。 -无论哪个版本,本体都归你:它是普通的 ObjectStack 元数据,你可以导出它 -并在开源的 ObjectStack 运行时上运行。 +无论哪个版本,本体都归你:它是普通的 ObjectStack 元数据,把它导出到开源的 +ObjectStack 运行时上运行尚在计划中。 ## 它不是什么 [#what-it-is-not] diff --git a/content/docs/ontology.zh-Hant.mdx b/content/docs/ontology.zh-Hant.mdx index 873cff8a..f94fd267 100644 --- a/content/docs/ontology.zh-Hant.mdx +++ b/content/docs/ontology.zh-Hant.mdx @@ -5,7 +5,7 @@ seoTitle: "ObjectOS 中你的本體:核心、投影、存放位置" description: 在 ObjectOS 上你的本體是什麼 —— 執行時執行的核心、在它旁邊編寫的投影、它存放在哪裡,以及它不是什麼。 editions: [community, cloud, enterprise] translation: - source_sha: 89b7e2e2e35db3cfc1e321a759eade603c86bbf958670a2c0abd7952bb51a8ab + source_sha: ca1fa33231f6faec71367a17c00b189310ba3d03766852c1072b46730f1f2f9a guide_rev: 1 mode: auto --- @@ -54,8 +54,8 @@ translation: 無論你用哪種形態編寫,後設資料在執行之前都會通過同一道 [校驗關口](/docs/resources/glossary#validation-gate)。 -無論哪個版本,本體都歸你:它是普通的 ObjectStack 後設資料,你可以匯出它 -並在開源的 ObjectStack 執行時上執行。 +無論哪個版本,本體都歸你:它是普通的 ObjectStack 後設資料,把它匯出到開源的 +ObjectStack 執行時上執行尚在計劃中。 ## 它不是什麼 [#what-it-is-not] diff --git a/content/docs/reference/security.ja.mdx b/content/docs/reference/security.ja.mdx index 7f6e2c51..682f3079 100644 --- a/content/docs/reference/security.ja.mdx +++ b/content/docs/reference/security.ja.mdx @@ -3,7 +3,7 @@ title: セキュリティとコンプライアンス description: 何が、どのように保護され、誰が責任を負うのか。セキュリティレビューのために。 editions: [community, cloud, enterprise] translation: - source_sha: f4b8cc8aeeb89ea330e8e0c536e84ad3f27d8bb2ae336f839e9321ab0da0c9a7 + source_sha: aae5afabc645af62cc67892667657f8b1a2de29f400b178bb56231e45b4c2c8d guide_rev: 1 mode: auto --- @@ -16,7 +16,7 @@ ObjectOS は、1 つのデータベースと通信する単一の Node.js プロ ## データレジデンシー [#data-residency] -この表は、セルフマネージドのエディションである **ObjectOS Enterprise** について記述しています。**ObjectOS Cloud** では、同じ種類のデータが私たちがあなたのために運用するインフラストラクチャに置かれます。どちらのエディションでも、オントロジーはオープンソースの ObjectStack ランタイムへエクスポートできます。 +この表は、セルフマネージドのエディションである **ObjectOS Enterprise** について記述しています。**ObjectOS Cloud** では、同じ種類のデータが私たちがあなたのために運用するインフラストラクチャに置かれます。どちらのエディションでも、オントロジーは通常の ObjectStack メタデータです。オープンソースの ObjectStack ランタイムへのエクスポートは計画中です。 | データの種類 | 置き場所 | ネットワークの外に出るか | |---|---|---| diff --git a/content/docs/reference/security.mdx b/content/docs/reference/security.mdx index 55c119ba..3080d5c6 100644 --- a/content/docs/reference/security.mdx +++ b/content/docs/reference/security.mdx @@ -20,8 +20,8 @@ nothing more. This table describes **ObjectOS Enterprise**, the self-managed edition. On **ObjectOS Cloud** the same classes of data live in the infrastructure we -operate for you, and on either edition your ontology is exportable to the -open-source ObjectStack runtime. +operate for you, and on either edition your ontology is ordinary ObjectStack +metadata; exporting it to the open-source ObjectStack runtime is planned. | Data class | Lives in | Leaves your network? | |---|---|---| diff --git a/content/docs/reference/security.zh-Hans.mdx b/content/docs/reference/security.zh-Hans.mdx index 904abaeb..204609d0 100644 --- a/content/docs/reference/security.zh-Hans.mdx +++ b/content/docs/reference/security.zh-Hans.mdx @@ -3,7 +3,7 @@ title: 安全与合规 description: 保护了什么、如何保护、谁负责 —— 面向安全评审。 editions: [community, cloud, enterprise] translation: - source_sha: f4b8cc8aeeb89ea330e8e0c536e84ad3f27d8bb2ae336f839e9321ab0da0c9a7 + source_sha: aae5afabc645af62cc67892667657f8b1a2de29f400b178bb56231e45b4c2c8d guide_rev: 1 mode: auto --- @@ -20,8 +20,8 @@ Enterprise** 上位于**你的**网络中,在 **ObjectOS Cloud** 上位于我 ## 数据驻留 [#data-residency] 下表描述的是自管理版本 **ObjectOS Enterprise**。在 **ObjectOS Cloud** 上,同样 -类别的数据存放在我们为你运维的基础设施中;无论哪个版本,你的本体都可以导出到开源 -的 ObjectStack 运行时。 +类别的数据存放在我们为你运维的基础设施中;无论哪个版本,你的本体都是普通的 +ObjectStack 元数据,把它导出到开源的 ObjectStack 运行时尚在计划中。 | 数据类别 | 存放于 | 是否离开你的网络? | |---|---|---| diff --git a/content/docs/reference/security.zh-Hant.mdx b/content/docs/reference/security.zh-Hant.mdx index da24f536..ce388351 100644 --- a/content/docs/reference/security.zh-Hant.mdx +++ b/content/docs/reference/security.zh-Hant.mdx @@ -4,7 +4,7 @@ title: 安全與合規 description: 保護了什麼、如何保護、誰負責 —— 面向安全評審。 editions: [community, cloud, enterprise] translation: - source_sha: f4b8cc8aeeb89ea330e8e0c536e84ad3f27d8bb2ae336f839e9321ab0da0c9a7 + source_sha: aae5afabc645af62cc67892667657f8b1a2de29f400b178bb56231e45b4c2c8d guide_rev: 1 mode: auto --- @@ -21,8 +21,8 @@ Enterprise** 上位於**你的**網路中,在 **ObjectOS Cloud** 上位於我 ## 資料駐留 [#data-residency] 下表描述的是自管理版本 **ObjectOS Enterprise**。在 **ObjectOS Cloud** 上,同樣 -類別的資料存放在我們為你運維的基礎設施中;無論哪個版本,你的本體都可以匯出到開源 -的 ObjectStack 執行時。 +類別的資料存放在我們為你運維的基礎設施中;無論哪個版本,你的本體都是普通的 +ObjectStack 後設資料,把它匯出到開源的 ObjectStack 執行時尚在計劃中。 | 資料類別 | 存放於 | 是否離開你的網路? | |---|---|---| diff --git a/content/docs/resources/glossary.ja.mdx b/content/docs/resources/glossary.ja.mdx index bb86c915..6e9458e0 100644 --- a/content/docs/resources/glossary.ja.mdx +++ b/content/docs/resources/glossary.ja.mdx @@ -4,7 +4,7 @@ seoTitle: "用語集:プラットフォームの用語、それぞれ 1 つの description: ObjectOS と ObjectStack 全体で使われる語彙。それぞれ 1 つの定義。 editions: [community, cloud, enterprise] translation: - source_sha: 926190d46d41bff6cbbc425cf9ccf45e6fb26dfadfb12a7d791e2606e71163c2 + source_sha: b1ec2b3e700cf10f783e7b984292d020b264c54dd3d411688c21929a06595dbc guide_rev: 1 mode: auto --- @@ -39,7 +39,7 @@ ObjectOS の料金の単位であり、すべてのエディションで唯一 アプリの定義(オブジェクトとフィールド、リレーション、アクション、権限、フロー、そしてエージェントとツールの定義)を、実行可能でバージョン管理されたひとつの全体としたもの。型付きの ObjectStack メタデータとして作成され、推論されるのではなく検証され、ランタイムによって実行されます。ランタイムはそこからデータベース、REST API、UI、MCP ツールを導出します。ビュー、ダッシュボード、アプリ、翻訳はその[プロジェクション](#projection)であり、その一部ではありません。 -これは実行可能なものであり、知識オントロジーではありません。オブジェクトの継承も、公理も、推論器もありません。セマンティックレイヤー(ビジネスを記述するが実行はしない、既存システム上の読み取り専用のマッピング)でもありません。どちらの ObjectOS エディションでもあなたのものです。エクスポートして、オープンソースの ObjectStack ランタイムで実行できます。このサイトでは [ObjectOS におけるあなたのオントロジー](/docs/ontology)を参照してください。完全な説明は ObjectStack ドキュメントの [Business Ontology](https://objectstack.ai/docs/concepts/ontology) にあります。 +これは実行可能なものであり、知識オントロジーではありません。オブジェクトの継承も、公理も、推論器もありません。セマンティックレイヤー(ビジネスを記述するが実行はしない、既存システム上の読み取り専用のマッピング)でもありません。どちらの ObjectOS エディションでもあなたのものです。通常の ObjectStack メタデータであり、エクスポートしてオープンソースの ObjectStack ランタイムで実行する機能は計画中です。このサイトでは [ObjectOS におけるあなたのオントロジー](/docs/ontology)を参照してください。完全な説明は ObjectStack ドキュメントの [Business Ontology](https://objectstack.ai/docs/concepts/ontology) にあります。 ### 機能(Capability) [#capability] @@ -103,7 +103,7 @@ AI エージェントがツールを発見して呼び出すためのオープ ### ObjectOS [#objectos] -ObjectStack 上に構築されたランタイム環境で、3 つのエディションを持つひとつの製品です。**ObjectOS Community** は、objectstack リポジトリで開発され、Apache-2.0 のもとで無料のオープンソースのランタイムと Console です。**ObjectOS Cloud** は、何もインストールせずにブラウザで使えるホスト型です。**ObjectOS Enterprise** は、自社のインフラストラクチャでセルフマネージドで動作するライセンス版です。Cloud と Enterprise は AI シート単位の料金で、どのエディションでもオントロジーをエクスポートしてオープンなランタイムで実行できます。**このドキュメントサイトは ObjectOS のためのものです。** +ObjectStack 上に構築されたランタイム環境で、3 つのエディションを持つひとつの製品です。**ObjectOS Community** は、objectstack リポジトリで開発され、Apache-2.0 のもとで無料のオープンソースのランタイムと Console です。**ObjectOS Cloud** は、何もインストールせずにブラウザで使えるホスト型です。**ObjectOS Enterprise** は、自社のインフラストラクチャでセルフマネージドで動作するライセンス版です。Cloud と Enterprise は AI シート単位の料金です。Cloud または Enterprise のオントロジーをエクスポートしてオープンなランタイムで実行する機能は計画中です。**このドキュメントサイトは ObjectOS のためのものです。** ### ObjectQL [#objectql] diff --git a/content/docs/resources/glossary.mdx b/content/docs/resources/glossary.mdx index 3d758d32..19ef838f 100644 --- a/content/docs/resources/glossary.mdx +++ b/content/docs/resources/glossary.mdx @@ -59,8 +59,8 @@ translations are [projections](#projection) of it, not part of it. It is executable, not a knowledge ontology: no object inheritance, no axioms, no reasoner. Nor is it a semantic layer — a read-only mapping over existing systems that describes a business but does not run it. It is -yours on either ObjectOS edition: export it and run it on the open-source -ObjectStack runtime. On this site, see +yours on either ObjectOS edition: it is ordinary ObjectStack metadata, and +exporting it to run on the open-source ObjectStack runtime is planned. On this site, see [Your ontology in ObjectOS](/docs/ontology); the full account is [Business Ontology](https://objectstack.ai/docs/concepts/ontology) in the ObjectStack docs. @@ -171,8 +171,8 @@ editions: **ObjectOS Community** — the open-source runtime and Console, free under Apache-2.0, developed in the objectstack repository; **ObjectOS Cloud** — hosted in the browser with nothing to install; and **ObjectOS Enterprise** — licensed, self-managed on your own -infrastructure. Cloud and Enterprise are priced per AI seat, and on any -edition you can export your ontology and run it on the open runtime. +infrastructure. Cloud and Enterprise are priced per AI seat; exporting a +Cloud or Enterprise ontology to run on the open runtime is planned. **This documentation site is for ObjectOS.** ### ObjectQL diff --git a/content/docs/resources/glossary.zh-Hans.mdx b/content/docs/resources/glossary.zh-Hans.mdx index d30db347..916c371e 100644 --- a/content/docs/resources/glossary.zh-Hans.mdx +++ b/content/docs/resources/glossary.zh-Hans.mdx @@ -4,7 +4,7 @@ seoTitle: "术语表:平台术语,各有一个定义" description: ObjectOS 和 ObjectStack 中使用的词汇 —— 每个术语一个定义。 editions: [community, cloud, enterprise] translation: - source_sha: 926190d46d41bff6cbbc425cf9ccf45e6fb26dfadfb12a7d791e2606e71163c2 + source_sha: b1ec2b3e700cf10f783e7b984292d020b264c54dd3d411688c21929a06595dbc guide_rev: 1 mode: auto --- @@ -53,7 +53,8 @@ CRM + Helpdesk + Setup)。 它是可执行的,而不是知识本体:没有对象继承,没有公理,没有推理机。它也不是语义层 —— 那是覆盖在现有系统之上的只读映射,描述业务却不运行业务。无论在哪个 ObjectOS -版本上它都属于你:导出它,就能在开源的 ObjectStack 运行时上运行。在本站参见 +版本上它都属于你:它是普通的 ObjectStack 元数据,把它导出到开源的 ObjectStack +运行时上运行尚在计划中。在本站参见 [ObjectOS 中你的本体](/docs/ontology);完整的阐述见 ObjectStack 文档中的 [Business Ontology](https://objectstack.ai/docs/concepts/ontology)。 @@ -143,7 +144,7 @@ ObjectOS 内部的微内核,负责加载插件、持有 DI 容器、分发事 开源的运行时和 Console,在 Apache-2.0 下免费,在 objectstack 仓库中开发; **ObjectOS Cloud** —— 托管在浏览器中,无需安装任何东西;以及 **ObjectOS Enterprise** —— 需许可证,在你自己的基础设施上自管理。Cloud 和 Enterprise 按 AI -席位计价,无论在哪个版本上,你都可以导出你的本体并在开放的运行时上运行它。 +席位计价;把 Cloud 或 Enterprise 上的本体导出到开放的运行时上运行,尚在计划中。 **本文档站点是关于 ObjectOS 的。** ### ObjectQL [#objectql] diff --git a/content/docs/resources/glossary.zh-Hant.mdx b/content/docs/resources/glossary.zh-Hant.mdx index 093d1209..39362857 100644 --- a/content/docs/resources/glossary.zh-Hant.mdx +++ b/content/docs/resources/glossary.zh-Hant.mdx @@ -5,7 +5,7 @@ seoTitle: "術語表:平臺術語,各有一個定義" description: ObjectOS 和 ObjectStack 中使用的詞彙 —— 每個術語一個定義。 editions: [community, cloud, enterprise] translation: - source_sha: 926190d46d41bff6cbbc425cf9ccf45e6fb26dfadfb12a7d791e2606e71163c2 + source_sha: b1ec2b3e700cf10f783e7b984292d020b264c54dd3d411688c21929a06595dbc guide_rev: 1 mode: auto --- @@ -54,7 +54,8 @@ CRM + Helpdesk + Setup)。 它是可執行的,而不是知識本體:沒有物件繼承,沒有公理,沒有推理機。它也不是語義層 —— 那是覆蓋在現有系統之上的只讀對映,描述業務卻不執行業務。無論在哪個 ObjectOS -版本上它都屬於你:匯出它,就能在開源的 ObjectStack 執行時上執行。在本站參見 +版本上它都屬於你:它是普通的 ObjectStack 後設資料,把它匯出到開源的 ObjectStack +執行時上執行尚在計劃中。在本站參見 [ObjectOS 中你的本體](/docs/ontology);完整的闡述見 ObjectStack 文件中的 [Business Ontology](https://objectstack.ai/docs/concepts/ontology)。 @@ -144,7 +145,7 @@ ObjectOS 內部的微核心,負責載入外掛、持有 DI 容器、分發事 開源的執行時和 Console,在 Apache-2.0 下免費,在 objectstack 倉庫中開發; **ObjectOS Cloud** —— 託管在瀏覽器中,無需安裝任何東西;以及 **ObjectOS Enterprise** —— 需許可證,在你自己的基礎設施上自管理。Cloud 和 Enterprise 按 AI -席位計價,無論在哪個版本上,你都可以匯出你的本體並在開放的執行時上執行它。 +席位計價;把 Cloud 或 Enterprise 上的本體匯出到開放的執行時上執行,尚在計劃中。 **本文件站點是關於 ObjectOS 的。** ### ObjectQL [#objectql] diff --git a/content/docs/why.ja.mdx b/content/docs/why.ja.mdx index ababb27b..c0fde2cf 100644 --- a/content/docs/why.ja.mdx +++ b/content/docs/why.ja.mdx @@ -4,7 +4,7 @@ seoTitle: "なぜ ObjectOS なのか:使うべきときと、使うべきで description: 率直な説明。使うべきとき、使うべきでないとき、そして何が違うのか。 editions: [community, cloud, enterprise] translation: - source_sha: 5f5a99346059a4eebaab08952d7d63a45e80b1fef6b6aaf390b849f7de2d5808 + source_sha: ceaa6102b8613f2ea7dc4fcd730876e637747022e146cb9d5640cf1a96caaa78 guide_rev: 1 mode: auto --- @@ -18,7 +18,7 @@ translation: - **実行可能。** オブジェクト、フィールド、リレーション、アクション、権限、フロー、エージェント定義は、ランタイムが実行する、型付きでバージョン管理されたひとつの定義です。REST エンドポイント、生成された画面、RBAC、監査ログ、MCP ツールはすべてそこから導出されます。コード生成のステップも、「説明した」と「稼働した」の間のデプロイパイプラインもありません。 - **AI が書ける。** その定義をファイルごとに手で書く必要はありません。ビジネスに必要なものを組み込みの [AI Builder](/docs/build/ai-builder) に説明してください。AI Builder は少数の監査済みツールを呼び出し、すべての変更は人の承認を待つキューに入り、結果は実際に読める小さな差分になります。 - **エージェントが操作できる。** すべてのオブジェクトと公開されたすべてのアクションは MCP ツールを兼ねるため、エージェントは人と同じ権限、行レベルセキュリティ、監査のもとで稼働中のアプリを操作します。生の SQL も、スクレイピングした UI も使いません。 -- **あなたが所有する。** オントロジーは通常の [ObjectStack](https://github.com/objectstack-ai/objectstack) メタデータで、Apache-2.0 です。どちらのエディションでもエクスポートして、そのオープンソースのランタイムで実行できます。ObjectOS Enterprise では、ランタイムとデータベースもあなたのインフラストラクチャ上に置かれます。 +- **あなたが所有する。** オントロジーは通常の [ObjectStack](https://github.com/objectstack-ai/objectstack) メタデータで、Apache-2.0 です。どちらのエディションからもエクスポートしてそのオープンソースのランタイムで実行する機能は計画中です。ObjectOS Enterprise では、ランタイムとデータベースもあなたのインフラストラクチャ上に置かれます。 説明は以上です。このページの残りは、それが誰に合い、誰に合わないかです。 @@ -80,14 +80,14 @@ translation: | 管理 UI | Console(基本的) | Setup + Account | | RBAC | Postgres RLS による行レベル | RBAC + 行レベル + フィールドレベル、宣言的 | | 監査ログ | 自作 | 正式な機能 | -| ベンダーロックイン | 彼らの認証 + 彼らのストレージ + 彼らのリアルタイム | オントロジーはオープンソースの ObjectStack ランタイムへエクスポートでき、すべてのレイヤーがプラグイン | +| ベンダーロックイン | 彼らの認証 + 彼らのストレージ + 彼らのリアルタイム | オントロジーは通常の ObjectStack メタデータで、オープンソースのランタイムへのエクスポートは計画中。すべてのレイヤーがプラグイン | | 最適な用途 | BaaS が欲しい新規アプリ | 定義を所有する必要があるアプリ。Enterprise ではランタイムも | ### Salesforce / NetSuite / ServiceNow との比較 [#vs-salesforce--netsuite--servicenow] | | Salesforce | ObjectOS | |---|---|---| -| データモデル | オブジェクト + フィールド + リレーションシップ、プラットフォーム内で設定 | オブジェクト、フィールド、リレーションをひとつのオープンなオントロジーに。エクスポート可能で、Apache-2.0 の ObjectStack ランタイムで実行可能 | +| データモデル | オブジェクト + フィールド + リレーションシップ、プラットフォーム内で設定 | オブジェクト、フィールド、リレーションをひとつのオープンなオントロジーに。Apache-2.0 の ObjectStack ランタイムの通常のメタデータで、エクスポートは計画中 | | 権限 | プロファイル + 権限セット + 共有ルール + FLS | 馴染みのある語彙(権限セット、ポジション、共有ルール、FLS)をオントロジーで宣言し、すべての REST 呼び出し、UI クリック、エージェントのツール呼び出しで強制 | | ユーザーあたりのコスト | $150-300/ユーザー/月 | 閲覧者と AI を使わないユーザーは無料。支払うのは AI シートのみ | | カスタマイズ | Apex + Lightning + フロー | TypeScript + フロー | diff --git a/content/docs/why.mdx b/content/docs/why.mdx index f6d30a8e..8f6b7a00 100644 --- a/content/docs/why.mdx +++ b/content/docs/why.mdx @@ -33,8 +33,8 @@ Community**, the open-source runtime): UI. - **You own it.** The ontology is ordinary [ObjectStack](https://github.com/objectstack-ai/objectstack) metadata, - Apache-2.0, and on either edition you can export it and run it on that - open-source runtime. ObjectOS Enterprise also keeps the runtime and the + Apache-2.0, and exporting it from either edition to run on that + open-source runtime is planned. ObjectOS Enterprise also keeps the runtime and the database on your infrastructure. That's the whole pitch. The rest of this page is who that fits and @@ -120,14 +120,14 @@ built on, is on | Admin UI | Console (basic) | Setup + Account | | RBAC | Row-level via Postgres RLS | RBAC + row-level + field-level, declarative | | Audit log | DIY | First-class | -| Vendor lock-in | Their auth + their storage + their realtime | The ontology exports to the open-source ObjectStack runtime; every layer is a plugin | +| Vendor lock-in | Their auth + their storage + their realtime | The ontology is ordinary ObjectStack metadata, with export to the open-source runtime planned; every layer is a plugin | | Best for | New apps that want a BaaS | Apps that need to own their definition — and, on Enterprise, their runtime | ### vs. Salesforce / NetSuite / ServiceNow | | Salesforce | ObjectOS | |---|---|---| -| Data model | Objects + fields + relationships, configured in the platform | Objects, fields and relations in one open ontology — exportable, and runnable on the Apache-2.0 ObjectStack runtime | +| Data model | Objects + fields + relationships, configured in the platform | Objects, fields and relations in one open ontology — ordinary metadata for the Apache-2.0 ObjectStack runtime, with export planned | | Permissions | Profile + permission sets + sharing rules + FLS | A familiar vocabulary — permission sets, positions, sharing rules, FLS — declared in the ontology and enforced on every REST call, UI click and agent tool call | | Per-user cost | $150-300/user/month | Viewers and non-AI users free; you pay for AI seats only | | Customization | Apex + Lightning + flows | TypeScript + flows | diff --git a/content/docs/why.zh-Hans.mdx b/content/docs/why.zh-Hans.mdx index 2b189671..2ffdfcd2 100644 --- a/content/docs/why.zh-Hans.mdx +++ b/content/docs/why.zh-Hans.mdx @@ -4,7 +4,7 @@ seoTitle: "为什么选择 ObjectOS:何时该用,何时不该用" description: 坦诚的介绍 —— 什么时候你应该用它,什么时候不应该,以及它的不同之处。 editions: [community, cloud, enterprise] translation: - source_sha: 5f5a99346059a4eebaab08952d7d63a45e80b1fef6b6aaf390b849f7de2d5808 + source_sha: ceaa6102b8613f2ea7dc4fcd730876e637747022e146cb9d5640cf1a96caaa78 guide_rev: 1 mode: auto --- @@ -33,8 +33,8 @@ Agent 操作它,你拥有它。四个承诺 —— ObjectOS 会在三种形态 绝不是裸 SQL,也绝不是抓取 UI。 - **你拥有它。** 本体是普通的 [ObjectStack](https://github.com/objectstack-ai/objectstack) 元数据, - Apache-2.0 许可,无论哪个版本,你都可以导出它并在那个开源运行时上 - 运行。ObjectOS Enterprise 还会把运行时和数据库留在你的基础设施上。 + Apache-2.0 许可;从任一版本把它导出到那个开源运行时上运行,尚在计划中。 + ObjectOS Enterprise 还会把运行时和数据库留在你的基础设施上。 这就是全部的介绍。本页其余部分讲的是它适合谁、不适合谁。 @@ -112,14 +112,14 @@ Agent 操作它,你拥有它。四个承诺 —— ObjectOS 会在三种形态 | 管理 UI | Console(基础) | Setup + 账户 | | RBAC | 通过 Postgres RLS 实现行级 | RBAC + 行级 + 字段级,声明式 | | 审计日志 | 自己做 | 一等能力 | -| 厂商锁定 | 他们的认证 + 他们的存储 + 他们的实时服务 | 本体可导出到开源的 ObjectStack 运行时;每一层都是插件 | +| 厂商锁定 | 他们的认证 + 他们的存储 + 他们的实时服务 | 本体是普通的 ObjectStack 元数据,导出到开源运行时尚在计划中;每一层都是插件 | | 最适合 | 想要 BaaS 的新应用 | 需要拥有自己定义的应用 —— 在 Enterprise 上还包括自己的运行时 | ### 对比 Salesforce / NetSuite / ServiceNow [#vs-salesforce--netsuite--servicenow] | | Salesforce | ObjectOS | |---|---|---| -| 数据模型 | 对象 + 字段 + 关系,在平台中配置 | 对象、字段和关系在一个开放的本体中 —— 可导出,并可在 Apache-2.0 的 ObjectStack 运行时上运行 | +| 数据模型 | 对象 + 字段 + 关系,在平台中配置 | 对象、字段和关系在一个开放的本体中 —— 是 Apache-2.0 ObjectStack 运行时的普通元数据,导出尚在计划中 | | 权限 | Profile + 权限集 + 共享规则 + FLS | 熟悉的词汇 —— 权限集、岗位、共享规则、FLS —— 在本体中声明,并在每次 REST 调用、UI 点击和 Agent 工具调用时强制执行 | | 每用户成本 | 每用户每月 150–300 美元 | 只读用户和非 AI 用户免费;你只为 AI 席位付费 | | 定制 | Apex + Lightning + 流程 | TypeScript + 流程 | diff --git a/content/docs/why.zh-Hant.mdx b/content/docs/why.zh-Hant.mdx index a6185fd3..cbbe65c0 100644 --- a/content/docs/why.zh-Hant.mdx +++ b/content/docs/why.zh-Hant.mdx @@ -5,7 +5,7 @@ seoTitle: "為什麼選擇 ObjectOS:何時該用,何時不該用" description: 坦誠的介紹 —— 什麼時候你應該用它,什麼時候不應該,以及它的不同之處。 editions: [community, cloud, enterprise] translation: - source_sha: 5f5a99346059a4eebaab08952d7d63a45e80b1fef6b6aaf390b849f7de2d5808 + source_sha: ceaa6102b8613f2ea7dc4fcd730876e637747022e146cb9d5640cf1a96caaa78 guide_rev: 1 mode: auto --- @@ -34,8 +34,8 @@ Agent 操作它,你擁有它。四個承諾 —— ObjectOS 會在三種形態 絕不是裸 SQL,也絕不是抓取 UI。 - **你擁有它。** 本體是普通的 [ObjectStack](https://github.com/objectstack-ai/objectstack) 後設資料, - Apache-2.0 許可,無論哪個版本,你都可以匯出它並在那個開源執行時上 - 執行。ObjectOS Enterprise 還會把執行時和資料庫留在你的基礎設施上。 + Apache-2.0 許可;從任一版本把它匯出到那個開源執行時上執行,尚在計劃中。 + ObjectOS Enterprise 還會把執行時和資料庫留在你的基礎設施上。 這就是全部的介紹。本頁其餘部分講的是它適合誰、不適合誰。 @@ -113,14 +113,14 @@ Agent 操作它,你擁有它。四個承諾 —— ObjectOS 會在三種形態 | 管理 UI | Console(基礎) | Setup + 賬戶 | | RBAC | 通過 Postgres RLS 實現行級 | RBAC + 行級 + 欄位級,宣告式 | | 審計日誌 | 自己做 | 一等能力 | -| 廠商鎖定 | 他們的認證 + 他們的儲存 + 他們的即時服務 | 本體可匯出到開源的 ObjectStack 執行時;每一層都是外掛 | +| 廠商鎖定 | 他們的認證 + 他們的儲存 + 他們的即時服務 | 本體是普通的 ObjectStack 後設資料,匯出到開源執行時尚在計劃中;每一層都是外掛 | | 最適合 | 想要 BaaS 的新應用 | 需要擁有自己定義的應用 —— 在 Enterprise 上還包括自己的執行時 | ### 對比 Salesforce / NetSuite / ServiceNow [#vs-salesforce--netsuite--servicenow] | | Salesforce | ObjectOS | |---|---|---| -| 資料模型 | 物件 + 欄位 + 關係,在平臺中配置 | 物件、欄位和關係在一個開放的本體中 —— 可匯出,並可在 Apache-2.0 的 ObjectStack 執行時上執行 | +| 資料模型 | 物件 + 欄位 + 關係,在平臺中配置 | 物件、欄位和關係在一個開放的本體中 —— 是 Apache-2.0 ObjectStack 執行時的普通後設資料,匯出尚在計劃中 | | 許可權 | Profile + 許可權集 + 共享規則 + FLS | 熟悉的詞彙 —— 許可權集、崗位、共享規則、FLS —— 在本體中宣告,並在每次 REST 呼叫、UI 點選和 Agent 工具呼叫時強制執行 | | 每使用者成本 | 每使用者每月 150–300 美元 | 只讀使用者和非 AI 使用者免費;你只為 AI 席位付費 | | 定製 | Apex + Lightning + 流程 | TypeScript + 流程 | From 48ec6c01f53051bdb60f3489beb015367902f82b Mon Sep 17 00:00:00 2001 From: Steedos Date: Tue, 3 Nov 2026 09:29:39 +0000 Subject: [PATCH 20/22] docs(i18n): translate six cloud and editions pages after one environment per organization, re-sync cloud/organization (zh-Hans, zh-Hant, ja) #428 deleted the zh-Hans, zh-Hant and ja siblings of cloud/apps, domains, environments, plans-and-seats, storage-and-limits and editions/compare. They are translated from the current English: every sentence #428 changed is new, and wording is reused only where the English sentence is unchanged. cloud/organization is re-synced in both locales. zh-Hant regenerated. Part of #429 Claude-Session: https://claude.ai/code/session_01QsR2jRsjbApbf83iyTDDXm Co-Authored-By: Claude --- content/docs/cloud/apps.ja.mdx | 113 +++++++++++++ content/docs/cloud/apps.zh-Hans.mdx | 152 +++++++++++++++++ content/docs/cloud/apps.zh-Hant.mdx | 153 ++++++++++++++++++ content/docs/cloud/domains.ja.mdx | 67 ++++++++ content/docs/cloud/domains.zh-Hans.mdx | 97 +++++++++++ content/docs/cloud/domains.zh-Hant.mdx | 98 +++++++++++ content/docs/cloud/environments.ja.mdx | 72 +++++++++ content/docs/cloud/environments.zh-Hans.mdx | 96 +++++++++++ content/docs/cloud/environments.zh-Hant.mdx | 97 +++++++++++ content/docs/cloud/organization.ja.mdx | 16 +- content/docs/cloud/organization.zh-Hans.mdx | 22 +-- content/docs/cloud/organization.zh-Hant.mdx | 22 +-- content/docs/cloud/plans-and-seats.ja.mdx | 94 +++++++++++ .../docs/cloud/plans-and-seats.zh-Hans.mdx | 120 ++++++++++++++ .../docs/cloud/plans-and-seats.zh-Hant.mdx | 121 ++++++++++++++ content/docs/cloud/storage-and-limits.ja.mdx | 61 +++++++ .../docs/cloud/storage-and-limits.zh-Hans.mdx | 85 ++++++++++ .../docs/cloud/storage-and-limits.zh-Hant.mdx | 86 ++++++++++ content/docs/editions/compare.ja.mdx | 62 +++++++ content/docs/editions/compare.zh-Hans.mdx | 85 ++++++++++ content/docs/editions/compare.zh-Hant.mdx | 86 ++++++++++ 21 files changed, 1775 insertions(+), 30 deletions(-) create mode 100644 content/docs/cloud/apps.ja.mdx create mode 100644 content/docs/cloud/apps.zh-Hans.mdx create mode 100644 content/docs/cloud/apps.zh-Hant.mdx create mode 100644 content/docs/cloud/domains.ja.mdx create mode 100644 content/docs/cloud/domains.zh-Hans.mdx create mode 100644 content/docs/cloud/domains.zh-Hant.mdx create mode 100644 content/docs/cloud/environments.ja.mdx create mode 100644 content/docs/cloud/environments.zh-Hans.mdx create mode 100644 content/docs/cloud/environments.zh-Hant.mdx create mode 100644 content/docs/cloud/plans-and-seats.ja.mdx create mode 100644 content/docs/cloud/plans-and-seats.zh-Hans.mdx create mode 100644 content/docs/cloud/plans-and-seats.zh-Hant.mdx create mode 100644 content/docs/cloud/storage-and-limits.ja.mdx create mode 100644 content/docs/cloud/storage-and-limits.zh-Hans.mdx create mode 100644 content/docs/cloud/storage-and-limits.zh-Hant.mdx create mode 100644 content/docs/editions/compare.ja.mdx create mode 100644 content/docs/editions/compare.zh-Hans.mdx create mode 100644 content/docs/editions/compare.zh-Hant.mdx diff --git a/content/docs/cloud/apps.ja.mdx b/content/docs/cloud/apps.ja.mdx new file mode 100644 index 00000000..217e1ead --- /dev/null +++ b/content/docs/cloud/apps.ja.mdx @@ -0,0 +1,113 @@ +--- +title: アプリ +seoTitle: "ObjectOS Cloud のアプリ:インストール、更新、公開、CLI からのデプロイ" +description: ObjectOS Cloud の環境にアプリをインストールし、更新を確認し、環境のアプリを組織向けのパッケージとして公開し、ローカルでビルドしたアプリを os CLI からデプロイします。 +editions: [cloud] +translation: + source_sha: e13d22274a9273409ca68299e567bdf0fe9183de61ffc745a1bf9c6b1591995c + guide_rev: 1 + mode: auto +--- + +アプリが ObjectOS Cloud の環境に届く方法は 3 つあります。マーケットプレイスまたは組織のレジストリから**インストール**する、環境の中で([AI Builder](/docs/build/ai-builder) を使うか手作業で)**構築**する、または自分のマシンから `os` CLI で**公開**する、のいずれかです。どの方法でも、インストールされるのは[パッケージ](/docs/build/packages)、つまりオブジェクト、ビュー、フローなどをまとめたバージョン付きのバンドルです。 + +## アプリをインストールする [#install-an-app] + +クラウドコンソールで環境の **Settings → Apps** を開き、**Install an app**(**Install Application**)を選びます。アプリを選んでから、次を設定します。 + +- **Include sample data**:パッケージのデモレコードで環境を埋め、すぐに試せるようにします。クリーンな本番環境ではチェックを外したままにします。 +- **Accept additional permissions**:初回のインストールではチェックを外したままにします。これは、以前に付与された権限より多くの権限を求める更新のためのものです([更新を確認する](#check-for-updates)を参照)。 + +アプリは再起動なしで、環境への次のリクエストから表示されます。インストール後のメッセージには、どのように反映されたか(インストール、再インストール、更新、ロールバックのいずれかと、そのバージョン)と、知っておくべきこと(アプリが使う機能のうちプランに含まれないものなど)が表示されます。 + +環境の中からインストールすることもできます。環境の **Marketplace** を開き、アプリを見つけて **Install** を選びます。どちらの方法でも、同じパッケージが同じ環境にインストールされます。[マーケットプレイス](/docs/build/marketplace)を参照してください。 + +インストールは組織のオーナーと管理者が行います。 + +## 更新を確認する [#check-for-updates] + +**Settings → Apps → Check for app updates** は、インストール済みの各アプリを公開されている最新バージョンと比較し、更新があるか、すべてのアプリが最新か、まだ何もインストールされていないかを表示します。 + +アプリを更新するには、もう一度インストールします。すでにインストールされているアプリをインストールすると、その場で公開済みの最新バージョンに移行します。 + +新しいバージョンが、アプリに以前付与されていなかった権限を求める場合、更新は `PERMISSION_RECONSENT_REQUIRED` で拒否され、メッセージに追加される各権限が一覧表示されます。内容を確認してから、**Accept additional permissions** にチェックを入れてもう一度インストールし、権限を付与します。 + +## 環境をパッケージとして公開する [#publish-an-environment-as-a-package] + +**Settings → Apps → Publish as a package**(**Publish to Registry**)は、この環境で構築したアプリを、組織のレジストリにあるパッケージの新しいバージョンとして公開し、そこからインストールできる状態にします。 + +| フィールド | 意味 | +|---|---| +| **App Name** | レジストリに表示される名前。デフォルトは環境の名前です。 | +| **Version** | `1.2.0` のようなセマンティックバージョン。空欄のままにすると、最新バージョンの次のパッチとして公開されます。 | +| **Visibility** | **Private**:自分の組織だけがインストールできます。**Organization**:組織全体で共有されます。 | +| **Description** | アプリ全体として何をするか。 | +| **Release notes** | このバージョンでの変更点。バージョンとともに表示されます。 | +| **Package ID**(詳細設定) | 逆ドメイン形式の識別子。空欄の場合は環境の名前から導出されます。 | + +公開マーケットプレイスへの掲載は、審査を伴う別の手順であり、ここでは提供されません。サイドバーの **Advanced → Packages** に、組織が公開したものがすべて一覧表示されます。 + +## CLI からデプロイする [#deploy-from-the-cli] + +アプリをコードとして(自分のマシン上の ObjectStack プロジェクトとして)開発している場合、`os` CLI でそれを組織に公開し、環境にインストールできます。流れは **ログイン → ビルド → 公開 → インストール** です。 + +必要なものは、ObjectStack プロジェクト([Path B — `os init`](/docs/start/community#path-b--os-init-developer) を参照)、`os` CLI、そして環境を持つ ObjectOS Cloud アカウントです。 + +### 1. ログイン [#1-log-in] + +```bash +os cloud login +``` + +これはブラウザのサインインを開き、クラウドトークンを `~/.objectstack/cloud.json` に保存します。サインインリンクを開く代わりに表示するには `--no-browser` を使います。CI ではログインを省略し、`--token` または `OS_CLOUD_API_KEY` 変数で `os package publish` に API キーを渡します。 + +クラウドログインは、ランタイムにサインインする `os login` とは別のものです。公開には常にクラウドログインが使われます。 + +### 2. ビルド [#2-build] + +```bash +os build +``` + +これはプロジェクトをひとつのアーティファクト `dist/objectstack.json` にコンパイルします。オブジェクト、ビュー、アプリ、ダッシュボード、フロー、サンプルデータが含まれます。後でアップロードされるのはこのアーティファクトだけで、ソースファイル、`node_modules`、ローカルの認証情報がアップロードされることはありません。 + +### 3. 公開 [#3-publish] + +```bash +os package publish +``` + +プロジェクトのルートで実行します。パッケージを組織に登録し(初回のみ。`com.acme.crm` のような逆ドメイン形式のパッケージ id をキーとします)、アーティファクトを新しい不変のバージョンとして公開します。同じバージョンを 2 回公開することはできません。`manifest.version` を上げるか、`--version` を渡します。 + +| フラグ | 目的 | +|---|---| +| `--manifest-id ` | 逆ドメイン形式のパッケージ id。デフォルト:アーティファクトから導出 | +| `--version ` | 公開するバージョン。デフォルト:`manifest.version` | +| `--visibility ` | 誰が表示・インストールできるか。ObjectOS Cloud では新しいパッケージのデフォルトは `org` です。既存のパッケージの公開範囲を維持するにはフラグを省略します | +| `--install` | 新しいバージョンをすぐに環境にインストールします | +| `--env ` | `--install` の対象環境。デフォルト:`os environments switch` で選択した環境 | +| `--seed-sample-data` | インストール時にアーティファクトのサンプルデータを含めます | +| `--note ""` | リリースノート | +| `--submit` | `marketplace` パッケージの新しいバージョンを審査に提出します | + +### 4. インストール [#4-install] + +利用者は環境からインストールします。環境の **Marketplace** を開き、パッケージを見つけて **Install** を選ぶか、[前述](#install-an-app)のクラウドコンソールの **Install an app** を使います。 + +既知の環境にデプロイするパイプラインは、ひとつのコマンドで公開とインストールを行えます。 + +```bash +os package publish --env --install --seed-sample-data +``` + +これは全か無かです。インストールが拒否された場合(その環境にインストールできない、環境が存在しない、またはそのバージョンがその環境で承認されていない)、何も公開されません。コマンドは拒否内容を表示してゼロ以外で終了するため、パイプラインは失敗します。原因を修正し、同じバージョンをもう一度公開してください。 + +### マーケットプレイスへの掲載 [#marketplace-listings] + +`--visibility marketplace` はパッケージを公開カタログの対象にしますが、新しいバージョンはそれぞれ**下書き**として届きます。審査に送るには `--submit` を渡します。プライベートと組織のパッケージは審査が不要で、組織はすぐにインストールできます。 + +## 次へ [#next] + +- [パッケージ](/docs/build/packages):パッケージに含まれるものと、バージョンの仕組み。 +- [マーケットプレイス](/docs/build/marketplace):環境の中からの閲覧とインストール。 +- [CLI リファレンス](/docs/reference/cli):すべての `os` コマンド。 diff --git a/content/docs/cloud/apps.zh-Hans.mdx b/content/docs/cloud/apps.zh-Hans.mdx new file mode 100644 index 00000000..f5774162 --- /dev/null +++ b/content/docs/cloud/apps.zh-Hans.mdx @@ -0,0 +1,152 @@ +--- +title: 应用 +seoTitle: "ObjectOS Cloud 应用:通过 CLI 安装、更新、发布和部署" +description: 将应用安装到 ObjectOS Cloud 环境中、检查更新、把一个环境的应用作为包发布给你的组织,以及通过 os CLI 部署在本地构建的应用。 +editions: [cloud] +translation: + source_sha: e13d22274a9273409ca68299e567bdf0fe9183de61ffc745a1bf9c6b1591995c + guide_rev: 1 + mode: auto +--- + +应用通过三种方式之一进入 ObjectOS Cloud 环境:你从市场或组织的注册表中 +**安装**一个应用,你在环境中**构建**它(使用 [AI Builder](/docs/build/ai-builder) +或手动构建),或者你用 `os` CLI 从自己的机器上**发布**它。 +无论走哪条路,安装的都是一个[包](/docs/build/packages):一个有版本的、 +由对象、视图、流程等组成的集合。 + +## 安装应用 [#install-an-app] + +在云控制台中,打开环境的 **Settings → Apps**,选择 +**Install an app**(**Install Application**)。挑选应用,然后: + +- **Include sample data**(包含示例数据)—— 用包的演示记录填充环境, + 让你可以马上开始探索。对于干净的生产环境,请不要勾选。 +- **Accept additional permissions**(接受额外权限)—— 首次安装时不要勾选。 + 它用于某次更新请求的权限多于此前授予该应用的权限的情况(参见[检查更新](#check-for-updates))。 + +应用会在环境的下一次请求时出现,无需重启。安装后的消息会说明安装的 +结果 —— 已安装、已重新安装、已更新或已回滚,并附带版本号 —— 以及你应当 +知道的任何情况,例如应用使用了你的套餐不包含的某项能力。 + +你也可以在环境内部安装:打开环境的 **Marketplace**(市场), +找到应用并选择 **Install**。两种方式都会把同一个包安装到同一个环境中; +参见[市场](/docs/build/marketplace)。 + +安装仅限组织的所有者和管理员。 + +## 检查更新 [#check-for-updates] + +**Settings → Apps → Check for app updates** 会把每个已安装的应用与 +已发布的最新版本进行比较,并告诉你是有可用更新、所有应用都已是最新, +还是尚未安装任何应用。 + +要更新一个应用,就再安装一次:安装一个已经安装的应用,会将它就地 +升级到已发布的最新版本。 + +如果新版本请求了此前未授予该应用的权限,更新会以 +`PERMISSION_RECONSENT_REQUIRED` 被拒绝,消息中会列出它新增的 +每一项权限。阅读它们,然后勾选 **Accept additional permissions** +再次安装,以授予这些权限。 + +## 将环境发布为包 [#publish-an-environment-as-a-package] + +**Settings → Apps → Publish as a package**(**Publish to Registry**)会获取 +在此环境中构建的应用,并将它们作为组织注册表中某个包的新版本发布, +之后即可从注册表安装。 + +| 字段 | 含义 | +|---|---| +| **App Name** | 在注册表中显示的名称。默认为环境的名称。 | +| **Version** | 语义化版本号,例如 `1.2.0`。留空则在最新版本之后发布下一个补丁版本。 | +| **Visibility** | **Private** —— 只有你的组织可以安装;**Organization** —— 在你的组织内共享。 | +| **Description** | 应用的整体用途。 | +| **Release notes** | 此版本的变更内容;与版本一起显示。 | +| **Package ID**(高级) | 反向域名形式的标识符。留空时,从环境名称派生。 | + +在公共市场上架是一个单独的步骤,需要经过审核;这里不提供该选项。 +侧边栏中的 **Advanced → Packages** 列出了你的组织发布过的所有内容。 + +## 通过 CLI 部署 [#deploy-from-the-cli] + +如果你以代码形式开发应用 —— 在自己机器上的一个 ObjectStack 项目 —— +`os` CLI 会把它发布到你的组织,并可以将它安装到某个环境中。 +流程是**登录 → 构建 → 发布 → 安装**。 + +你需要一个 ObjectStack 项目(参见 +[路径 B —— `os init`](/docs/start/community#path-b--os-init-developer))、 +`os` CLI,以及一个带有环境的 ObjectOS Cloud 账户。 + +### 1. 登录 [#1-log-in] + +```bash +os cloud login +``` + +这会打开浏览器登录,并将云令牌保存在 +`~/.objectstack/cloud.json` 中。使用 `--no-browser` 可以打印登录链接, +而不是打开它。在 CI 中,跳过登录,通过 `--token` 或 `OS_CLOUD_API_KEY` +变量给 `os package publish` 提供一个 API 密钥。 + +云登录与 `os login` 是分开的,后者让你登录到某个运行时; +发布始终使用云登录。 + +### 2. 构建 [#2-build] + +```bash +os build +``` + +这会把项目编译为一个产物 `dist/objectstack.json`:你的 +对象、视图、应用、仪表盘、流程以及任何示例数据。之后只会上传这个产物 +—— 绝不会上传源文件、`node_modules` 或本地凭据。 + +### 3. 发布 [#3-publish] + +```bash +os package publish +``` + +在项目根目录下运行它。它会在你的组织中注册该包 +(只注册一次,以反向域名形式的包 id 为键,例如 `com.acme.crm`),并将 +产物作为一个新的、不可变的版本发布。同一个版本不能发布两次:提高 +`manifest.version` 或传入 `--version`。 + +| 参数 | 用途 | +|---|---| +| `--manifest-id ` | 反向域名形式的包 id。默认:从产物派生 | +| `--version ` | 要发布的版本。默认:`manifest.version` | +| `--visibility ` | 谁可以查看和安装它。在 ObjectOS Cloud 上,新包默认为 `org`;省略此参数则保留已有包的可见性 | +| `--install` | 立即将新版本安装到某个环境中 | +| `--env ` | `--install` 的目标环境。默认:`os environments switch` 选中的那个 | +| `--seed-sample-data` | 安装时包含产物的示例数据 | +| `--note ""` | 发布说明 | +| `--submit` | 将 `marketplace` 包的新版本提交审核 | + +### 4. 安装 [#4-install] + +用户从环境中安装:打开环境的 **Marketplace**,找到你的 +包并选择 **Install** —— 或者使用云控制台中的 **Install an app**,见[上文](#install-an-app)。 + +部署到已知环境的流水线可以用一条命令完成发布和安装: + +```bash +os package publish --env --install --seed-sample-data +``` + +这是全有或全无的。如果安装被拒绝 —— 你可能无权安装到 +该环境、该环境不存在,或该版本未获准用于该环境 —— +则不会发布任何内容:命令会打印拒绝原因并以非零状态退出,因此 +流水线会失败。修复原因后,再次发布同一个版本。 + +### 市场上架 [#marketplace-listings] + +`--visibility marketplace` 让包有资格进入公共目录,但 +每个新版本仍然以**草稿**形式到达。传入 `--submit` 将其送交 +审核。私有包和组织包无需审核,你的组织可以立即安装。 + +## 下一步 [#next] + +- [包](/docs/build/packages) —— 包包含什么,以及版本如何运作。 +- [市场](/docs/build/marketplace) —— 在环境内部浏览和安装。 +- [CLI 参考](/docs/reference/cli) —— 每一个 `os` 命令。 diff --git a/content/docs/cloud/apps.zh-Hant.mdx b/content/docs/cloud/apps.zh-Hant.mdx new file mode 100644 index 00000000..2026e17f --- /dev/null +++ b/content/docs/cloud/apps.zh-Hant.mdx @@ -0,0 +1,153 @@ +--- +# @generated zh-Hant from zh-Hans -- do not edit. Edit the English source, then regenerate: pnpm --filter @objectos/docs gen:zh-hant +title: 應用 +seoTitle: "ObjectOS Cloud 應用:通過 CLI 安裝、更新、釋出和部署" +description: 將應用安裝到 ObjectOS Cloud 環境中、檢查更新、把一個環境的應用作為包釋出給你的組織,以及通過 os CLI 部署在本地構建的應用。 +editions: [cloud] +translation: + source_sha: e13d22274a9273409ca68299e567bdf0fe9183de61ffc745a1bf9c6b1591995c + guide_rev: 1 + mode: auto +--- + +應用通過三種方式之一進入 ObjectOS Cloud 環境:你從市場或組織的登錄檔中 +**安裝**一個應用,你在環境中**構建**它(使用 [AI Builder](/docs/build/ai-builder) +或手動構建),或者你用 `os` CLI 從自己的機器上**釋出**它。 +無論走哪條路,安裝的都是一個[包](/docs/build/packages):一個有版本的、 +由物件、檢視、流程等組成的集合。 + +## 安裝應用 [#install-an-app] + +在雲控制台中,開啟環境的 **Settings → Apps**,選擇 +**Install an app**(**Install Application**)。挑選應用,然後: + +- **Include sample data**(包含示例資料)—— 用包的演示記錄填充環境, + 讓你可以馬上開始探索。對於乾淨的生產環境,請不要勾選。 +- **Accept additional permissions**(接受額外許可權)—— 首次安裝時不要勾選。 + 它用於某次更新請求的許可權多於此前授予該應用的許可權的情況(參見[檢查更新](#check-for-updates))。 + +應用會在環境的下一次請求時出現,無需重啟。安裝後的訊息會說明安裝的 +結果 —— 已安裝、已重新安裝、已更新或已回滾,並附帶版本號 —— 以及你應當 +知道的任何情況,例如應用使用了你的套餐不包含的某項能力。 + +你也可以在環境內部安裝:開啟環境的 **Marketplace**(市場), +找到應用並選擇 **Install**。兩種方式都會把同一個包安裝到同一個環境中; +參見[市場](/docs/build/marketplace)。 + +安裝僅限組織的所有者和管理員。 + +## 檢查更新 [#check-for-updates] + +**Settings → Apps → Check for app updates** 會把每個已安裝的應用與 +已釋出的最新版本進行比較,並告訴你是有可用更新、所有應用都已是最新, +還是尚未安裝任何應用。 + +要更新一個應用,就再安裝一次:安裝一個已經安裝的應用,會將它就地 +升級到已釋出的最新版本。 + +如果新版本請求了此前未授予該應用的許可權,更新會以 +`PERMISSION_RECONSENT_REQUIRED` 被拒絕,訊息中會列出它新增的 +每一項許可權。閱讀它們,然後勾選 **Accept additional permissions** +再次安裝,以授予這些許可權。 + +## 將環境釋出為包 [#publish-an-environment-as-a-package] + +**Settings → Apps → Publish as a package**(**Publish to Registry**)會獲取 +在此環境中構建的應用,並將它們作為組織登錄檔中某個包的新版本釋出, +之後即可從登錄檔安裝。 + +| 欄位 | 含義 | +|---|---| +| **App Name** | 在登錄檔中顯示的名稱。預設為環境的名稱。 | +| **Version** | 語義化版本號,例如 `1.2.0`。留空則在最新版本之後釋出下一個補丁版本。 | +| **Visibility** | **Private** —— 只有你的組織可以安裝;**Organization** —— 在你的組織內共享。 | +| **Description** | 應用的整體用途。 | +| **Release notes** | 此版本的變更內容;與版本一起顯示。 | +| **Package ID**(高階) | 反向域名形式的識別符號。留空時,從環境名稱派生。 | + +在公共市場上架是一個單獨的步驟,需要經過稽核;這裡不提供該選項。 +側邊欄中的 **Advanced → Packages** 列出了你的組織釋出過的所有內容。 + +## 通過 CLI 部署 [#deploy-from-the-cli] + +如果你以程式碼形式開發應用 —— 在自己機器上的一個 ObjectStack 專案 —— +`os` CLI 會把它釋出到你的組織,並可以將它安裝到某個環境中。 +流程是**登入 → 構建 → 釋出 → 安裝**。 + +你需要一個 ObjectStack 專案(參見 +[路徑 B —— `os init`](/docs/start/community#path-b--os-init-developer))、 +`os` CLI,以及一個帶有環境的 ObjectOS Cloud 賬戶。 + +### 1. 登入 [#1-log-in] + +```bash +os cloud login +``` + +這會開啟瀏覽器登入,並將雲令牌儲存在 +`~/.objectstack/cloud.json` 中。使用 `--no-browser` 可以列印登入連結, +而不是開啟它。在 CI 中,跳過登入,通過 `--token` 或 `OS_CLOUD_API_KEY` +變數給 `os package publish` 提供一個 API 金鑰。 + +雲登入與 `os login` 是分開的,後者讓你登入到某個執行時; +釋出始終使用雲登入。 + +### 2. 構建 [#2-build] + +```bash +os build +``` + +這會把專案編譯為一個產物 `dist/objectstack.json`:你的 +物件、檢視、應用、儀表盤、流程以及任何示例資料。之後只會上傳這個產物 +—— 絕不會上傳原始檔、`node_modules` 或本地憑據。 + +### 3. 釋出 [#3-publish] + +```bash +os package publish +``` + +在專案根目錄下執行它。它會在你的組織中註冊該包 +(只註冊一次,以反向域名形式的包 id 為鍵,例如 `com.acme.crm`),並將 +產物作為一個新的、不可變的版本釋出。同一個版本不能釋出兩次:提高 +`manifest.version` 或傳入 `--version`。 + +| 引數 | 用途 | +|---|---| +| `--manifest-id ` | 反向域名形式的包 id。預設:從產物派生 | +| `--version ` | 要釋出的版本。預設:`manifest.version` | +| `--visibility ` | 誰可以檢視和安裝它。在 ObjectOS Cloud 上,新包預設為 `org`;省略此引數則保留已有包的可見性 | +| `--install` | 立即將新版本安裝到某個環境中 | +| `--env ` | `--install` 的目標環境。預設:`os environments switch` 選中的那個 | +| `--seed-sample-data` | 安裝時包含產物的示例資料 | +| `--note ""` | 釋出說明 | +| `--submit` | 將 `marketplace` 包的新版本提交稽核 | + +### 4. 安裝 [#4-install] + +使用者從環境中安裝:開啟環境的 **Marketplace**,找到你的 +包並選擇 **Install** —— 或者使用雲控制台中的 **Install an app**,見[上文](#install-an-app)。 + +部署到已知環境的流水線可以用一條命令完成釋出和安裝: + +```bash +os package publish --env --install --seed-sample-data +``` + +這是全有或全無的。如果安裝被拒絕 —— 你可能無權安裝到 +該環境、該環境不存在,或該版本未獲準用於該環境 —— +則不會發布任何內容:命令會列印拒絕原因並以非零狀態退出,因此 +流水線會失敗。修復原因後,再次釋出同一個版本。 + +### 市場上架 [#marketplace-listings] + +`--visibility marketplace` 讓包有資格進入公共目錄,但 +每個新版本仍然以**草稿**形式到達。傳入 `--submit` 將其送交 +稽核。私有包和組織包無需稽核,你的組織可以立即安裝。 + +## 下一步 [#next] + +- [包](/docs/build/packages) —— 包包含什麼,以及版本如何運作。 +- [市場](/docs/build/marketplace) —— 在環境內部瀏覽和安裝。 +- [CLI 參考](/docs/reference/cli) —— 每一個 `os` 命令。 diff --git a/content/docs/cloud/domains.ja.mdx b/content/docs/cloud/domains.ja.mdx new file mode 100644 index 00000000..c6474cad --- /dev/null +++ b/content/docs/cloud/domains.ja.mdx @@ -0,0 +1,67 @@ +--- +title: ドメイン +seoTitle: "ObjectOS Cloud のドメイン:プラットフォームのサブドメインと独自のドメイン" +description: すべての ObjectOS Cloud のプランにはブランド付きのプラットフォームのサブドメインが含まれます。Team 以上では、TXT レコードで所有を証明し、証明書が発行される独自のドメインを本番環境に追加できます。 +editions: [cloud] +translation: + source_sha: fcc0d9e71e8aaaae766b269c31794d94d261c23e3ffce8428ca13706f0d7ccf5 + guide_rev: 1 + mode: auto +--- + +ObjectOS Cloud の環境には、2 種類のアドレスでアクセスできます。 + +| | **プラットフォームのサブドメイン** | **独自のドメイン** | +|---|---|---| +| 見た目 | プラットフォームのドメイン上の `acme` | `app.acme.com` | +| プラン | Free を含むすべてのプラン | Team 以上 | +| 環境 | 組織の唯一の環境 | 組織の唯一の環境 | +| 数 | いくつでも追加できます | Team では本番環境ごとに 1 つ。契約によりそれ以上 | +| 証明書 | プラットフォーム自身のものでカバーされます | 所有が証明されると発行されます | + +このページのルールは、[cloud#1087](https://github.com/objectstack-ai/cloud/issues/1087)(プラットフォームのサブドメインはすべてのプランで無料)と [cloud#2136](https://github.com/objectstack-ai/cloud/issues/2136)(独自のドメイン)で決定されました。 + +## プラットフォームのサブドメイン [#platform-subdomains] + +環境のアドレスは、プラットフォームのドメイン上の組織の[スラッグ](/docs/cloud/organization#the-organization-slug)です。これはすべてのプランで無料で、自分で選ぶほかのブランド付きのラベルも同じく無料です。 + +変更するには、環境の **Settings → Name and domain** を開き、**Change Hostname** を選びます。ラベルだけを入力します。プラットフォームのドメインは自動で付きます。ラベルは 4〜63 文字の小文字、数字、ダッシュで、両端にダッシュは使えず、2 つ続けることもできません。いくつかの予約語は拒否されます。組織のスラッグで始まる必要はありません。 + +最初のものを置き換えるのではなく 2 つ目のプラットフォームのサブドメインを追加するには、同じセクションの **Add Domain** を使います。環境の **Overview** に表示されるアドレスが、人に伝えるべきアドレスです。 + +## 独自のドメイン [#your-own-domain] + +**Team** 以上では、本番環境は、`app.acme.com` のような、所有するドメインのサブドメインでも応答できます。 + +1. **追加します。** **Settings → Name and domain** で **Add Domain**(または **Change Hostname**)を選び、完全なホスト名を入力します。サブドメイン(少なくとも 3 つのラベル)でなければなりません。`acme.com` のようなルートドメインは拒否されます。`www.acme.com` などのサブドメインを使ってください。 +2. **所有を証明します。** ドメインは **Pending Verification** として作成され、コンソールに公開すべき TXT レコードが表示されます。名前は `_objectos-challenge.` で、値はこのドメインに固有のものです。ホスト名が向けるべき CNAME のターゲットも表示されます。 +3. **確認します。** TXT レコードを公開したら、ドメインで **Verify DNS** を選びます。ObjectOS Cloud はレコードを確認し、それから証明書を要求します。ドメインは **Verified** と **Provisioning Certificate** を経て **Active** になります。途中のステップで止まった場合は、もう一度 **Verify DNS** を選んで先に進めます。 +4. **プライマリにします**(省略可能)。**Set as Primary** は、サインインのリダイレクト、メールのリンク、共有リンクがどのアドレスを使うかを決めます。プラットフォームのサブドメインも並んで機能し続けます。 + +セッションは 1 つのアドレスに属します。プラットフォームのサブドメインと独自のドメインを切り替えると、もう一度サインインすることになります。 + +### うまくいかないとき [#when-something-goes-wrong] + +| 表示されるもの | 理由と対処 | +|---|---| +| `403 CUSTOM_DOMAIN_PLAN_LOCKED` | 組織が Free です。Team にアップグレードしてください。 | +| www またはサブドメインを求める `400 INVALID_FORMAT` | ルートドメインを入力しました。`www.acme.com` のようなサブドメインを使ってください。 | +| `403 CONTACT_SALES_PLAN` | 環境はすでに 1 つのドメインを持っています。複数持つには Enterprise の契約が必要です。 | +| `409 DUPLICATE_VALUE` | 別の環境がすでにそのホスト名を提供しています。 | +| 確認の応答が、TXT レコードがまだ見えないと言う | DNS が伝播していないか、レコードの名前または値が異なります。応答には期待されるレコードが繰り返し示されます。 | +| **Failed** | 証明書を発行できませんでした。CNAME を確認し、もう一度 **Verify DNS** を選んでください。まず所有を証明し直します。 | + +### ダウングレードとアップグレード [#downgrade-and-upgrade] + +ダウングレードは独自のドメインを**一時停止**します。決して解放はしません。ドメインは **Suspended** になって提供を止め、証明書は取り下げられますが、レコードは残ります。それがプライマリだった場合、リンクは影響を受けないプラットフォームのサブドメインにフォールバックします。後でアップグレードすると、CNAME がまだ私たちを向いていれば、ドメインは自動的に再プロビジョニングされます。「N 日後に解放」というものはありません。 + +一時停止されたドメインが、そのホスト名の所有を証明できるほかの誰かを妨げることはありません。別の環境がそれを証明すれば、一時停止されていた主張は放棄されます。 + +### ドメインを削除する [#removing-a-domain] + +ドメインの **Delete** は提供を止め、ホスト名を解放します。環境を完全に削除すると、そのすべてのドメインもあわせて削除されます。 + +## 次へ [#next] + +- [環境](/docs/cloud/environments):本番と開発。 +- [プランと AI シート](/docs/cloud/plans-and-seats):Team が追加するもの。 diff --git a/content/docs/cloud/domains.zh-Hans.mdx b/content/docs/cloud/domains.zh-Hans.mdx new file mode 100644 index 00000000..d6eea699 --- /dev/null +++ b/content/docs/cloud/domains.zh-Hans.mdx @@ -0,0 +1,97 @@ +--- +title: 域名 +seoTitle: "ObjectOS Cloud 域名:平台子域名与你自己的域名" +description: 每个 ObjectOS Cloud 套餐都包含一个品牌化的平台子域名;Team 及以上套餐可以为生产环境添加你自己的域名,通过 TXT 记录证明所有权,证书由平台为你签发。 +editions: [cloud] +translation: + source_sha: fcc0d9e71e8aaaae766b269c31794d94d261c23e3ffce8428ca13706f0d7ccf5 + guide_rev: 1 + mode: auto +--- + +ObjectOS Cloud 上的环境可以通过两类地址访问。 + +| | **平台子域名** | **你自己的域名** | +|---|---|---| +| 形式 | 平台域名上的 `acme` | `app.acme.com` | +| 套餐 | 所有套餐,包括 Free | Team 及以上 | +| 环境 | 组织唯一的那个环境 | 组织唯一的那个环境 | +| 数量 | 想加多少就加多少 | Team 上每个生产环境一个;更多需按合同 | +| 证书 | 由平台自己的证书覆盖 | 证明所有权后为你签发 | + +本页的规则依据 +[cloud#1087](https://github.com/objectstack-ai/cloud/issues/1087)(平台 +子域名在所有套餐上免费)和 +[cloud#2136](https://github.com/objectstack-ai/cloud/issues/2136)(你自己的 +域名)的裁定。 + +## 平台子域名 [#platform-subdomains] + +你的环境的地址是你组织的 +[slug](/docs/cloud/organization#the-organization-slug) 加上平台域名。 +它在所有套餐上都免费,你选择的任何其他品牌化标签也一样。 + +要修改它,打开环境的 **Settings → Name and domain**,选择 +**Change Hostname**。只需输入标签:平台域名会自动为你加上。 +标签由 4 到 63 个小写字母、数字和连字符组成,两端不能是连字符, +也不能有两个连字符相连,少数保留词会被拒绝。它不必 +以你组织的 slug 开头。 + +要添加第二个平台子域名而不是替换第一个,请使用同一部分中的 +**Add Domain**。环境 **Overview** 上显示的地址,就是你应该告诉别人的那个。 + +## 你自己的域名 [#your-own-domain] + +在 **Team** 及以上套餐上,生产环境还可以通过你拥有的某个域名的 +子域名来访问,例如 `app.acme.com`。 + +1. **添加它。** 在 **Settings → Name and domain** 中,选择 **Add Domain**(或 + **Change Hostname**),输入完整的主机名。它必须是子域名 —— + 至少三级标签。像 `acme.com` 这样的根域名会被拒绝:请使用 + `www.acme.com` 或其他子域名。 +2. **证明你拥有它。** 域名创建后处于 **Pending Verification** 状态, + 控制台会显示一条需要发布的 TXT 记录:名称为 + `_objectos-challenge.`,值对该域名唯一。 + 它还会显示你的主机名应指向的 CNAME 目标。 +3. **验证。** TXT 记录发布后,在该域名上选择 **Verify DNS**。 + ObjectOS Cloud 会检查该记录,然后申请证书; + 域名会依次经过 **Verified** 和 **Provisioning Certificate**,最终变为 + **Active**。如果它停在某一步,再次选择 **Verify DNS** 推动它继续。 +4. **设为主域名**(可选)。**Set as Primary** 决定登录重定向、 + 邮件链接和共享链接使用哪个地址。平台子域名 + 在它旁边继续可用。 + +会话只属于一个地址:在平台子域名和 +你自己的域名之间切换,需要重新登录。 + +### 出现问题时 [#when-something-goes-wrong] + +| 你看到的 | 原因,以及该怎么做 | +|---|---| +| `403 CUSTOM_DOMAIN_PLAN_LOCKED` | 组织使用的是 Free 套餐。升级到 Team。 | +| `400 INVALID_FORMAT`,要求使用 www 或子域名 | 你输入的是根域名。请使用子域名,例如 `www.acme.com`。 | +| `403 CONTACT_SALES_PLAN` | 该环境已经有了它唯一的那个域名。多于一个属于 Enterprise 安排。 | +| `409 DUPLICATE_VALUE` | 另一个环境已经在使用该主机名。 | +| 验证回复说 TXT 记录尚不可见 | DNS 尚未传播,或者记录名称或值不一致。回复中会重复给出期望的记录。 | +| **Failed** | 证书无法签发。检查 CNAME 并再次选择 **Verify DNS**;它会先重新证明所有权。 | + +### 降级与升级 [#downgrade-and-upgrade] + +降级会**暂停**你自己的域名;绝不会释放它。域名变为 +**Suspended**,停止提供服务,其证书被撤回,但记录 +仍然保留。如果它是主域名,链接会回退到平台子域名,后者 +不受影响。之后任何一次升级时,只要你的 CNAME 仍指向我们, +域名都会自动重新配置。不存在"N 天后释放"这回事。 + +被暂停的域名不会阻碍其他能够证明该主机名所有权的人: +如果另一个环境证明了所有权,被暂停的认领就会被放弃。 + +### 移除域名 [#removing-a-domain] + +在域名上选择 **Delete** 会使其停止提供服务并释放主机名。永久 +删除环境会连同其所有域名一起移除。 + +## 下一步 [#next] + +- [环境](/docs/cloud/environments) —— 生产环境与开发环境。 +- [套餐与 AI 席位](/docs/cloud/plans-and-seats) —— Team 增加了什么。 diff --git a/content/docs/cloud/domains.zh-Hant.mdx b/content/docs/cloud/domains.zh-Hant.mdx new file mode 100644 index 00000000..7df956f4 --- /dev/null +++ b/content/docs/cloud/domains.zh-Hant.mdx @@ -0,0 +1,98 @@ +--- +# @generated zh-Hant from zh-Hans -- do not edit. Edit the English source, then regenerate: pnpm --filter @objectos/docs gen:zh-hant +title: 域名 +seoTitle: "ObjectOS Cloud 域名:平臺子域名與你自己的域名" +description: 每個 ObjectOS Cloud 套餐都包含一個品牌化的平臺子域名;Team 及以上套餐可以為生產環境新增你自己的域名,通過 TXT 記錄證明所有權,證書由平臺為你簽發。 +editions: [cloud] +translation: + source_sha: fcc0d9e71e8aaaae766b269c31794d94d261c23e3ffce8428ca13706f0d7ccf5 + guide_rev: 1 + mode: auto +--- + +ObjectOS Cloud 上的環境可以通過兩類地址訪問。 + +| | **平臺子域名** | **你自己的域名** | +|---|---|---| +| 形式 | 平臺域名上的 `acme` | `app.acme.com` | +| 套餐 | 所有套餐,包括 Free | Team 及以上 | +| 環境 | 組織唯一的那個環境 | 組織唯一的那個環境 | +| 數量 | 想加多少就加多少 | Team 上每個生產環境一個;更多需按合同 | +| 證書 | 由平臺自己的證書覆蓋 | 證明所有權後為你簽發 | + +本頁的規則依據 +[cloud#1087](https://github.com/objectstack-ai/cloud/issues/1087)(平臺 +子域名在所有套餐上免費)和 +[cloud#2136](https://github.com/objectstack-ai/cloud/issues/2136)(你自己的 +域名)的裁定。 + +## 平臺子域名 [#platform-subdomains] + +你的環境的地址是你組織的 +[slug](/docs/cloud/organization#the-organization-slug) 加上平臺域名。 +它在所有套餐上都免費,你選擇的任何其他品牌化標籤也一樣。 + +要修改它,開啟環境的 **Settings → Name and domain**,選擇 +**Change Hostname**。只需輸入標籤:平臺域名會自動為你加上。 +標籤由 4 到 63 個小寫字母、數字和連字元組成,兩端不能是連字元, +也不能有兩個連字元相連,少數保留詞會被拒絕。它不必 +以你組織的 slug 開頭。 + +要新增第二個平臺子域名而不是替換第一個,請使用同一部分中的 +**Add Domain**。環境 **Overview** 上顯示的地址,就是你應該告訴別人的那個。 + +## 你自己的域名 [#your-own-domain] + +在 **Team** 及以上套餐上,生產環境還可以通過你擁有的某個域名的 +子域名來訪問,例如 `app.acme.com`。 + +1. **新增它。** 在 **Settings → Name and domain** 中,選擇 **Add Domain**(或 + **Change Hostname**),輸入完整的主機名。它必須是子域名 —— + 至少三級標籤。像 `acme.com` 這樣的根域名會被拒絕:請使用 + `www.acme.com` 或其他子域名。 +2. **證明你擁有它。** 域名建立後處於 **Pending Verification** 狀態, + 控制台會顯示一條需要釋出的 TXT 記錄:名稱為 + `_objectos-challenge.`,值對該域名唯一。 + 它還會顯示你的主機名應指向的 CNAME 目標。 +3. **驗證。** TXT 記錄釋出後,在該域名上選擇 **Verify DNS**。 + ObjectOS Cloud 會檢查該記錄,然後申請證書; + 域名會依次經過 **Verified** 和 **Provisioning Certificate**,最終變為 + **Active**。如果它停在某一步,再次選擇 **Verify DNS** 推動它繼續。 +4. **設為主域名**(可選)。**Set as Primary** 決定登入重定向、 + 郵件連結和共享連結使用哪個地址。平臺子域名 + 在它旁邊繼續可用。 + +會話只屬於一個地址:在平臺子域名和 +你自己的域名之間切換,需要重新登入。 + +### 出現問題時 [#when-something-goes-wrong] + +| 你看到的 | 原因,以及該怎麼做 | +|---|---| +| `403 CUSTOM_DOMAIN_PLAN_LOCKED` | 組織使用的是 Free 套餐。升級到 Team。 | +| `400 INVALID_FORMAT`,要求使用 www 或子域名 | 你輸入的是根域名。請使用子域名,例如 `www.acme.com`。 | +| `403 CONTACT_SALES_PLAN` | 該環境已經有了它唯一的那個域名。多於一個屬於 Enterprise 安排。 | +| `409 DUPLICATE_VALUE` | 另一個環境已經在使用該主機名。 | +| 驗證回覆說 TXT 記錄尚不可見 | DNS 尚未傳播,或者記錄名稱或值不一致。回覆中會重複給出期望的記錄。 | +| **Failed** | 證書無法簽發。檢查 CNAME 並再次選擇 **Verify DNS**;它會先重新證明所有權。 | + +### 降級與升級 [#downgrade-and-upgrade] + +降級會**暫停**你自己的域名;絕不會釋放它。域名變為 +**Suspended**,停止提供服務,其證書被撤回,但記錄 +仍然保留。如果它是主域名,連結會回退到平臺子域名,後者 +不受影響。之後任何一次升級時,只要你的 CNAME 仍指向我們, +域名都會自動重新配置。不存在"N 天后釋放"這回事。 + +被暫停的域名不會阻礙其他能夠證明該主機名所有權的人: +如果另一個環境證明了所有權,被暫停的認領就會被放棄。 + +### 移除域名 [#removing-a-domain] + +在域名上選擇 **Delete** 會使其停止提供服務並釋放主機名。永久 +刪除環境會連同其所有域名一起移除。 + +## 下一步 [#next] + +- [環境](/docs/cloud/environments) —— 生產環境與開發環境。 +- [套餐與 AI 席位](/docs/cloud/plans-and-seats) —— Team 增加了什麼。 diff --git a/content/docs/cloud/environments.ja.mdx b/content/docs/cloud/environments.ja.mdx new file mode 100644 index 00000000..b5bf54b7 --- /dev/null +++ b/content/docs/cloud/environments.ja.mdx @@ -0,0 +1,72 @@ +--- +title: 環境 +seoTitle: "ObjectOS Cloud の環境:組織ごとに 1 つ、そのライフサイクル" +description: ObjectOS Cloud のすべての組織は、どのプランでもちょうど 1 つの環境を持ちます。そのアドレス、環境のページ、そして一時停止、アーカイブ、復元、削除がそれぞれデータに何をするか。 +editions: [cloud] +translation: + source_sha: 08490778d91cffbfdd247f3c6448a01998716813aa401b4f19d66def56a51b3d + guide_rev: 1 + mode: auto +--- + +**環境**は、独自のデータベース、ファイル、アプリ、アドレスを持つ、ObjectOS の稼働中のコピー 1 つです。組織のアプリは環境の中にあり、チームはそれを使うために環境にサインインします。 + +**すべての組織は、どのプランでもちょうど 1 つの環境を持ちます。** それが本番環境です。組織をセットアップするときに作成する最初の環境([ObjectOS Cloud で始める](/docs/start/cloud))であり、唯一の環境です。1 つの組織、1 つの環境、多数のアプリ。必要なだけのアプリを、その中にインストールし、構築します。 + +| | **環境** | +|---|---| +| 数 | どのプランでも、組織ごとにちょうど 1 つ | +| アドレス | プラットフォームのドメイン上の組織のスラッグ。Team 以上では[独自のドメイン](/docs/cloud/domains)を付けられます | +| アイドル | 非アクティブによるアーカイブは決してされません | +| 用途 | チームが使うアプリ | + +2 つ目の環境は作成できません。プランの違いは、環境が何を保持し、何を許可するか([ストレージ](/docs/cloud/storage-and-limits)、[AI 利用枠](/docs/cloud/ai-credits-and-limits)、独自のドメイン)にあり、環境の数にはありません。 + +## 複雑なアプリを開発する [#developing-a-complex-app] + +AI Builder とコンソールで足りないアプリは、2 つ目の環境ではなくソースレベルで開発します。`os dev` でローカルに構築して Git で管理し、[パッケージとして公開してインストール](/docs/cloud/apps#deploy-from-the-cli)します。流れ全体は[アプリ](/docs/cloud/apps)を参照してください。 + +## 環境を作成する [#create-the-environment] + +**Environments** で **Create Environment** を選び、名前を付けます。アドレスはプラットフォームが割り当てます。アドレスは後から **Change Hostname**([ドメイン](/docs/cloud/domains))で変更できます。新しい環境は **Provisioning** で始まり、データベースの準備ができると **Active** になります。 + +環境に入るには **Open** を選びます。新しいタブで環境自身のコンソールが、あなたとしてサインインした状態で開きます。 + +## 環境のページ [#the-environment-page] + +各環境には、2 つのタブを持つページがあります。 + +- **Overview**:アドレス、ステータス、プランと種類、インストールされているアプリ、アクセスの設定。折りたたまれた **Features that need a higher plan** の行は、現在のプランに含まれていないものを数え、開くとその一覧を表示します。 +- **Settings**:すべてのアクションが 5 つのセクションにあります。**Apps**、**Plan and billing**、**Name and domain**、**Access and sign-in**([AI エージェントのアクセス](/docs/configure/mcp#on-objectos-cloud)を含む)、**Lifecycle and danger zone** です。 + +環境を変更するアクションは、組織のオーナーと管理者に提示されます。 + +## ライフサイクル [#lifecycle] + +| 状態 | 意味 | データ | +|---|---|---| +| **Active** | リクエストを処理しています | — | +| **Suspended** | 再開するまで、ランタイムへのすべてのトラフィックがブロックされます | 保持されます | +| **Archived** | アクティブな表示から外され、訪問されても起動しなくなります | 誰かが削除するまで保持されます | +| **Failed** | プロビジョニングが完了しませんでした | 何も作成されていません | + +**一時停止と再開。** 一時停止すると、人からも連携からも、環境へのすべてのリクエストがブロックされます。何も削除されず、**Resume** で元どおりに戻ります。 + +**アーカイブと復元。** アーカイブすると、環境は使われなくなります。**Restore** はデータとともに環境を戻し、次の訪問で再び起動します。 + +**削除。** 削除は 2 段階の操作なので、1 回のクリックでデータが失われることは決してありません。 + +1. まだアーカイブされていない環境は、完全な削除を求めた場合でも**アーカイブ**されます。 +2. **アーカイブ済み**の環境を、**Delete permanently if already archived** にチェックを入れて削除すると、そのデータベースとすべてのファイルが一度に破棄され、復旧はできません。 + +本番環境を削除するときは、さらに **Force-delete the production environment** にチェックを入れるよう求められます。プロビジョニングに失敗した環境はデータを持たないので、即座に削除されます。 + +### アーカイブされた環境がどれだけ保持されるか [#how-long-an-archived-environment-is-kept] + +アーカイブされた環境は、データベース、ファイル、ドメインとともに、誰かが削除するまで保持されます。どのプランでも、タイマーで期限が切れることはありません。アーカイブするのは常にあなたの選択で、削除も同じです。データを破棄するのは、上に書いた明示的で完全な **Delete** だけです。 + +## 次へ [#next] + +- [プランと AI シート](/docs/cloud/plans-and-seats):有料プランが追加するもの。 +- [ストレージと上限](/docs/cloud/storage-and-limits):環境ごとのストレージの割り当て。 +- [アプリ](/docs/cloud/apps):環境でアプリをインストール、更新、公開する。 diff --git a/content/docs/cloud/environments.zh-Hans.mdx b/content/docs/cloud/environments.zh-Hans.mdx new file mode 100644 index 00000000..50907e19 --- /dev/null +++ b/content/docs/cloud/environments.zh-Hans.mdx @@ -0,0 +1,96 @@ +--- +title: 环境 +seoTitle: "ObjectOS Cloud 环境:每个组织一个,及其生命周期" +description: 每个 ObjectOS Cloud 组织在每个套餐上都恰好有一个环境 —— 它的地址、环境页面,以及暂停、归档、恢复和删除各自会对数据做什么。 +editions: [cloud] +translation: + source_sha: 08490778d91cffbfdd247f3c6448a01998716813aa401b4f19d66def56a51b3d + guide_rev: 1 + mode: auto +--- + +**环境**是一份正在运行的 ObjectOS 副本,拥有自己的数据库、文件、应用和 +地址。你的组织的应用存在于环境中,你的团队登录到环境来使用它们。 + +**每个组织在每个套餐上都恰好有一个环境。** 它就是生产环境:你在设置组织时 +创建的第一个环境([在 ObjectOS Cloud 上开始](/docs/start/cloud)),也是唯一 +一个。一个组织,一个环境,多个应用:你可以在其中安装和构建所需的任意多个 +应用。 + +| | **环境** | +|---|---| +| 数量 | 每个组织恰好一个,所有套餐都是如此 | +| 地址 | 你的组织 slug 加平台域名;在 Team 及以上可以使用[你自己的域名](/docs/cloud/domains) | +| 闲置 | 从不因不活跃而被归档 | +| 用途 | 你的团队使用的应用 | + +无法创建第二个环境。各套餐的区别在于环境能容纳和允许什么(它的 +[存储](/docs/cloud/storage-and-limits)、它的 +[AI 额度](/docs/cloud/ai-credits-and-limits)、你自己的域名),而不在于有多少个 +环境。 + +## 开发复杂应用 [#developing-a-complex-app] + +如果一个应用需要的超出了 AI Builder 和控制台所能提供的,就在源码层面开发它, +而不是在第二个环境中开发:用 `os dev` 在本地构建它并把它保存在 Git 中,然后 +[把它发布为包并安装](/docs/cloud/apps#deploy-from-the-cli)到你的环境中。完整 +流程见[应用](/docs/cloud/apps)。 + +## 创建环境 [#create-the-environment] + +在 **Environments** 中,选择 **Create Environment** 并为它命名;平台会分配 +地址。地址之后可以用 **Change Hostname** 修改([域名](/docs/cloud/domains))。 +新环境从 **Provisioning**(正在配置)状态开始,数据库就绪后变为 **Active**。 + +要进入环境,选择 **Open**。它会在新标签页中打开该环境自己的控制台,并以 +你的身份登录。 + +## 环境页面 [#the-environment-page] + +每个环境都有一个带两个标签页的页面。 + +- **Overview**(概览)—— 它的地址、状态、套餐和类型、其中安装的应用, + 以及它的访问设置。一行折叠的 **Features that need a higher + plan**,统计当前套餐不包含的功能,展开后列出它们。 +- **Settings**(设置)—— 每一个操作,分为五个部分:**Apps**、**Plan and + billing**、**Name and domain**、**Access and sign-in**(包括 + [AI Agent 访问](/docs/configure/mcp#on-objectos-cloud))和 **Lifecycle and + danger zone**。 + +会改变环境的操作提供给组织的所有者和管理员。 + +## 生命周期 [#lifecycle] + +| 状态 | 含义 | 你的数据 | +|---|---|---| +| **Active**(活跃) | 正在处理请求 | — | +| **Suspended**(已暂停) | 所有运行时流量都被阻止,直到你恢复它 | 保留 | +| **Archived**(已归档) | 从活跃视图中移除;访问时不再启动 | 保留到有人删除它为止 | +| **Failed**(失败) | 配置未完成 | 从未创建 | + +**暂停与恢复运行。** 暂停会阻止对环境的每一个请求,无论来自人还是来自 +集成。不会删除任何东西,**Resume** 会让它恢复原样。 + +**归档与恢复。** 归档让环境停止使用。**Restore** 把它连同数据一起恢复回来; +它会在下次被访问时再次启动。 + +**删除。** 删除分两步进行,因此一次点击永远不会销毁数据: + +1. 尚未归档的环境会被**归档**,即使你要求的是永久删除。 +2. 删除一个**已归档**的环境时勾选 **Delete permanently if already + archived**,会立即销毁它的数据库和所有文件,无法恢复。 + +删除生产环境时,还会要求你勾选 **Force-delete the +production environment**。配置失败的环境不含数据,会被立即删除。 + +### 已归档环境保留多久 [#how-long-an-archived-environment-is-kept] + +已归档的环境会连同它的数据库、文件和域名一起保留,直到有人删除它。在任何 +套餐上都没有到期计时:归档始终由你决定,删除也是。只有上面那个明确的、 +永久的 **Delete** 才会销毁数据。 + +## 下一步 [#next] + +- [套餐与 AI 席位](/docs/cloud/plans-and-seats) —— 付费套餐增加了什么。 +- [存储与限制](/docs/cloud/storage-and-limits) —— 每个环境的存储额度。 +- [应用](/docs/cloud/apps) —— 在环境中安装、更新和发布应用。 diff --git a/content/docs/cloud/environments.zh-Hant.mdx b/content/docs/cloud/environments.zh-Hant.mdx new file mode 100644 index 00000000..359826fb --- /dev/null +++ b/content/docs/cloud/environments.zh-Hant.mdx @@ -0,0 +1,97 @@ +--- +# @generated zh-Hant from zh-Hans -- do not edit. Edit the English source, then regenerate: pnpm --filter @objectos/docs gen:zh-hant +title: 環境 +seoTitle: "ObjectOS Cloud 環境:每個組織一個,及其生命週期" +description: 每個 ObjectOS Cloud 組織在每個套餐上都恰好有一個環境 —— 它的地址、環境頁面,以及暫停、歸檔、恢復和刪除各自會對資料做什麼。 +editions: [cloud] +translation: + source_sha: 08490778d91cffbfdd247f3c6448a01998716813aa401b4f19d66def56a51b3d + guide_rev: 1 + mode: auto +--- + +**環境**是一份正在執行的 ObjectOS 副本,擁有自己的資料庫、檔案、應用和 +地址。你的組織的應用存在於環境中,你的團隊登入到環境來使用它們。 + +**每個組織在每個套餐上都恰好有一個環境。** 它就是生產環境:你在設定組織時 +建立的第一個環境([在 ObjectOS Cloud 上開始](/docs/start/cloud)),也是唯一 +一個。一個組織,一個環境,多個應用:你可以在其中安裝和構建所需的任意多個 +應用。 + +| | **環境** | +|---|---| +| 數量 | 每個組織恰好一個,所有套餐都是如此 | +| 地址 | 你的組織 slug 加平臺域名;在 Team 及以上可以使用[你自己的域名](/docs/cloud/domains) | +| 閒置 | 從不因不活躍而被歸檔 | +| 用途 | 你的團隊使用的應用 | + +無法建立第二個環境。各套餐的區別在於環境能容納和允許什麼(它的 +[儲存](/docs/cloud/storage-and-limits)、它的 +[AI 額度](/docs/cloud/ai-credits-and-limits)、你自己的域名),而不在於有多少個 +環境。 + +## 開發複雜應用 [#developing-a-complex-app] + +如果一個應用需要的超出了 AI Builder 和控制台所能提供的,就在原始碼層面開發它, +而不是在第二個環境中開發:用 `os dev` 在本地構建它並把它儲存在 Git 中,然後 +[把它釋出為包並安裝](/docs/cloud/apps#deploy-from-the-cli)到你的環境中。完整 +流程見[應用](/docs/cloud/apps)。 + +## 建立環境 [#create-the-environment] + +在 **Environments** 中,選擇 **Create Environment** 併為它命名;平臺會分配 +地址。地址之後可以用 **Change Hostname** 修改([域名](/docs/cloud/domains))。 +新環境從 **Provisioning**(正在配置)狀態開始,資料庫就緒後變為 **Active**。 + +要進入環境,選擇 **Open**。它會在新標籤頁中開啟該環境自己的控制台,並以 +你的身份登入。 + +## 環境頁面 [#the-environment-page] + +每個環境都有一個帶兩個標籤頁的頁面。 + +- **Overview**(概覽)—— 它的地址、狀態、套餐和型別、其中安裝的應用, + 以及它的訪問設定。一行摺疊的 **Features that need a higher + plan**,統計當前套餐不包含的功能,展開後列出它們。 +- **Settings**(設定)—— 每一個操作,分為五個部分:**Apps**、**Plan and + billing**、**Name and domain**、**Access and sign-in**(包括 + [AI Agent 訪問](/docs/configure/mcp#on-objectos-cloud))和 **Lifecycle and + danger zone**。 + +會改變環境的操作提供給組織的所有者和管理員。 + +## 生命週期 [#lifecycle] + +| 狀態 | 含義 | 你的資料 | +|---|---|---| +| **Active**(活躍) | 正在處理請求 | — | +| **Suspended**(已暫停) | 所有執行時流量都被阻止,直到你恢復它 | 保留 | +| **Archived**(已歸檔) | 從活躍檢視中移除;訪問時不再啟動 | 保留到有人刪除它為止 | +| **Failed**(失敗) | 配置未完成 | 從未建立 | + +**暫停與恢復執行。** 暫停會阻止對環境的每一個請求,無論來自人還是來自 +整合。不會刪除任何東西,**Resume** 會讓它恢復原樣。 + +**歸檔與恢復。** 歸檔讓環境停止使用。**Restore** 把它連同資料一起恢復回來; +它會在下次被訪問時再次啟動。 + +**刪除。** 刪除分兩步進行,因此一次點選永遠不會銷燬資料: + +1. 尚未歸檔的環境會被**歸檔**,即使你要求的是永久刪除。 +2. 刪除一個**已歸檔**的環境時勾選 **Delete permanently if already + archived**,會立即銷燬它的資料庫和所有檔案,無法恢復。 + +刪除生產環境時,還會要求你勾選 **Force-delete the +production environment**。配置失敗的環境不含資料,會被立即刪除。 + +### 已歸檔環境保留多久 [#how-long-an-archived-environment-is-kept] + +已歸檔的環境會連同它的資料庫、檔案和域名一起保留,直到有人刪除它。在任何 +套餐上都沒有到期計時:歸檔始終由你決定,刪除也是。只有上面那個明確的、 +永久的 **Delete** 才會銷燬資料。 + +## 下一步 [#next] + +- [套餐與 AI 席位](/docs/cloud/plans-and-seats) —— 付費套餐增加了什麼。 +- [儲存與限制](/docs/cloud/storage-and-limits) —— 每個環境的儲存額度。 +- [應用](/docs/cloud/apps) —— 在環境中安裝、更新和釋出應用。 diff --git a/content/docs/cloud/organization.ja.mdx b/content/docs/cloud/organization.ja.mdx index 72ae0d3e..2082c97d 100644 --- a/content/docs/cloud/organization.ja.mdx +++ b/content/docs/cloud/organization.ja.mdx @@ -4,7 +4,7 @@ seoTitle: "ObjectOS Cloud の組織:スラッグ、メンバー、招待、ロ description: ObjectOS Cloud の組織。そのスラッグ、クラウドコンソール、メンバーの招待、5 つのメンバーシップのロール、そしてサインインが環境ではなくクラウドにある理由。 editions: [cloud] translation: - source_sha: 45e832e16685da44f31911d619138580836770640112ee1300fc5cc35796ac0d + source_sha: 5d0d1a9751ee245d48b0c2aba06002c2ec161ee1ead737262e0a9ca5d7b3ef59 guide_rev: 1 mode: auto --- @@ -17,18 +17,18 @@ ObjectOS Cloud では、所有するものはすべて**組織**に属します | サイドバーの項目 | 中身 | ページ | |---|---|---| -| **Home** | 組織の概要:本番環境、アプリ、メンバー、今週の AI 利用枠 | — | -| **Environments** | すべての環境と、その設定とライフサイクル | [環境](/docs/cloud/environments) | +| **Home** | 組織の概要:その環境、アプリ、メンバー、今週の AI 利用枠 | — | +| **Environments** | 組織の唯一の環境と、その設定とライフサイクル | [環境](/docs/cloud/environments) | | **Members** | 組織の人と、保留中の招待 | このページ | | **Billing** | プランの比較とアップグレード | [プランと AI シート](/docs/cloud/plans-and-seats) | | **Advanced → Connected Runtimes** | この組織にリンクされたセルフホストのサーバー | [クラウド接続](/docs/cloud/cloud-connection) | | **Advanced → Packages** | 組織が公開したパッケージ | [アプリ](/docs/cloud/apps) | -各環境にも、その環境自身のアドレスに独自のコンソールがあります。チームがアプリを使うのはそこで、クラウドコンソールはそれらを取り巻く組織を管理する場所です。 +環境にも、それ自身のアドレスに独自のコンソールがあります。チームがアプリを使うのはそこで、クラウドコンソールはそれらを取り巻く組織を管理する場所です。 ## 組織のスラッグ [#the-organization-slug] -**スラッグ**は組織の短い識別子で、サインアップ時に選びます。本番環境のアドレスでもあり、スラッグの後にプラットフォームのドメインが続きます。 +**スラッグ**は組織の短い識別子で、サインアップ時に選びます。環境のアドレスでもあり、スラッグの後にプラットフォームのドメインが続きます。 - 4〜30 文字:小文字、数字、ダッシュ。 - 先頭と末尾にダッシュは使えず、ダッシュを 2 つ続けることもできません。 @@ -42,7 +42,7 @@ ObjectOS Cloud では、所有するものはすべて**組織**に属します 誰かを追加するには、**Invite members** を選び、メールアドレスを入力してロールを選びます。相手は招待を受け取り、それを承諾すると組織のメンバーになります。 -**組織の招待が、その環境に入る唯一の方法です。** 環境には独自の招待もセルフサインアップもありません。ここで招待した全員が組織の環境に入ることができ、環境の中で何ができるかは、その環境の[権限](/docs/configure/permissions)が決めます。 +**組織の招待が、その環境に入る唯一の方法です。** 環境には独自の招待もセルフサインアップもありません。ここで招待した全員が組織の環境に入ることができ、その中で何ができるかは、環境の[権限](/docs/configure/permissions)が決めます。 リストから、組織を管理する人は**メンバーのロールを変更**、**メンバーを削除**、保留中の招待を**再送**または**取り消し**できます。 @@ -62,12 +62,12 @@ ObjectOS Cloud では、所有するものはすべて**組織**に属します ## サインインのある場所 [#where-sign-in-lives] -ObjectOS Cloud では、すべてのアカウントがクラウドのアカウントです。ObjectOS Cloud が人をサインインさせ、環境がその人を受け入れます。環境が各人について保持するのは**認可だけ**、つまりポジション、権限セット、共有です。すべてのホスト型の環境は、どのプランでもデフォルトでこの単一のサインインを使うので、人は ObjectOS Cloud のアカウントで一度サインインし、環境の間を移動できます。 +ObjectOS Cloud では、すべてのアカウントがクラウドのアカウントです。ObjectOS Cloud が人をサインインさせ、環境がその人を受け入れます。環境が各人について保持するのは**認可だけ**、つまりポジション、権限セット、共有です。すべてのホスト型の環境は、どのプランでもデフォルトでこの単一のサインインを使うので、人は ObjectOS Cloud のアカウントで一度サインインし、環境を開けます。 **環境を自社のインフラストラクチャに移す場合。** アカウントは環境ではなく ObjectOS Cloud にあるので、環境とともに移動はしません。セルフマネージドのデプロイメントでは、そこで人に新しい認証情報を発行するか、自社のアイデンティティプロバイダーにバインドしてそれを通じてサインインさせます。[認証](/docs/configure/authentication)を参照してください。 ## 次へ [#next] -- [環境](/docs/cloud/environments):本番と開発、そしてそのライフサイクル。 +- [環境](/docs/cloud/environments):組織の唯一の環境と、そのライフサイクル。 - [プランと AI シート](/docs/cloud/plans-and-seats):Free、Team、Enterprise のそれぞれに含まれるもの。 - [権限](/docs/configure/permissions):環境の中でメンバーができること。 diff --git a/content/docs/cloud/organization.zh-Hans.mdx b/content/docs/cloud/organization.zh-Hans.mdx index 45a26f8b..df97dc2d 100644 --- a/content/docs/cloud/organization.zh-Hans.mdx +++ b/content/docs/cloud/organization.zh-Hans.mdx @@ -4,7 +4,7 @@ seoTitle: "ObjectOS Cloud 组织:slug、成员、邀请和角色" description: 你的 ObjectOS Cloud 组织 —— 它的 slug、云控制台、邀请成员、五种成员角色,以及为什么登录在云端而不是在环境中进行。 editions: [cloud] translation: - source_sha: 45e832e16685da44f31911d619138580836770640112ee1300fc5cc35796ac0d + source_sha: 5d0d1a9751ee245d48b0c2aba06002c2ec161ee1ead737262e0a9ca5d7b3ef59 guide_rev: 1 mode: auto --- @@ -19,19 +19,19 @@ translation: | 侧边栏项 | 包含什么 | 页面 | |---|---|---| -| **Home**(首页) | 组织一览:生产环境、应用、成员、本周的 AI 额度 | — | -| **Environments**(环境) | 每个环境,及其设置和生命周期 | [环境](/docs/cloud/environments) | +| **Home**(首页) | 组织一览:它的环境、应用、成员、本周的 AI 额度 | — | +| **Environments**(环境) | 组织唯一的那个环境,及其设置和生命周期 | [环境](/docs/cloud/environments) | | **Members**(成员) | 组织中的人员及其待处理的邀请 | 本页 | | **Billing**(账单) | 套餐对比,以及升级 | [套餐与 AI 席位](/docs/cloud/plans-and-seats) | | **Advanced → Connected Runtimes** | 关联到这个组织的自托管服务器 | [云连接](/docs/cloud/cloud-connection) | | **Advanced → Packages** | 你的组织已发布的包 | [应用](/docs/cloud/apps) | -每个环境也有自己的控制台,位于该环境自己的地址。你的团队在那里使用应用; +这个环境也有自己的控制台,位于它自己的地址。你的团队在那里使用应用; 云控制台则是你管理应用所在组织的地方。 ## 组织 slug [#the-organization-slug] -**slug** 是组织的简短标识符,在注册时选定。它也是你的生产环境的地址: +**slug** 是组织的简短标识符,在注册时选定。它也是你的环境的地址: slug 后面跟上平台的域名。 - 4 到 30 个字符:小写字母、数字和短横线。 @@ -52,9 +52,9 @@ slug 后面跟上平台的域名。 要添加某人,选择 **Invite members**,输入对方的电子邮件地址并选择一个 角色。对方会收到一份邀请,接受之后就成为组织的成员。 -**组织的邀请是进入其环境的唯一途径。** 环境没有自己的邀请,也没有自助 -注册:你在这里邀请的每个人都能进入组织的环境,而他们在某个环境中能做 -什么,由该环境的[权限](/docs/configure/permissions)决定。 +**组织的邀请是进入其环境的唯一途径。** 这个环境没有自己的邀请,也没有自助 +注册:你在这里邀请的每个人都能进入组织的环境,而他们在其中能做 +什么,由它的[权限](/docs/configure/permissions)决定。 在这些列表中,管理组织的人可以**更改成员的角色**、**移除成员**,以及 **重新发送**或**撤销**待处理的邀请。 @@ -73,7 +73,7 @@ slug 后面跟上平台的域名。 | **External**(外部用户) | 门户用户 —— 供应商或客户的人员 —— 只能看到自己的行以及明确共享给他们的内容;从不属于业务单元树 | 任何能发出邀请的人 | 所有者和管理员就是本节所说的"管理组织的人":他们能看到套餐、升级以及 -会改变某些东西的环境操作。普通成员能看到环境并打开它们,但不会看到他们 +会改变某些东西的环境操作。普通成员能看到环境并打开它,但不会看到他们 无法完成的操作。 ## 登录在哪里进行 [#where-sign-in-lives] @@ -81,7 +81,7 @@ slug 后面跟上平台的域名。 在 ObjectOS Cloud 上,每个账户都是云账户。由 ObjectOS Cloud 让人登录,环境 接收他们:环境为每个人保存的**只有授权** —— 他们的岗位、权限集和共享。 每个托管环境默认都使用这一个登录,在每个套餐上都是如此,因此人们用 -ObjectOS Cloud 账户登录一次,就能在各个环境之间切换。 +ObjectOS Cloud 账户登录一次,就能打开环境。 **把环境迁到你自己的基础设施上。** 因为账户保存在 ObjectOS Cloud 而不是 环境中,它们不会随环境一起迁移。在自管理部署上,你要么在那里为人们签发 @@ -90,6 +90,6 @@ ObjectOS Cloud 账户登录一次,就能在各个环境之间切换。 ## 下一步 [#next] -- [环境](/docs/cloud/environments) —— 生产环境和开发环境,以及它们的生命周期。 +- [环境](/docs/cloud/environments) —— 组织唯一的那个环境及其生命周期。 - [套餐与 AI 席位](/docs/cloud/plans-and-seats) —— Free、Team 和 Enterprise 各自包含什么。 - [权限](/docs/configure/permissions) —— 成员在环境中能做什么。 diff --git a/content/docs/cloud/organization.zh-Hant.mdx b/content/docs/cloud/organization.zh-Hant.mdx index d1b3ae44..317d74f6 100644 --- a/content/docs/cloud/organization.zh-Hant.mdx +++ b/content/docs/cloud/organization.zh-Hant.mdx @@ -5,7 +5,7 @@ seoTitle: "ObjectOS Cloud 組織:slug、成員、邀請和角色" description: 你的 ObjectOS Cloud 組織 —— 它的 slug、雲控制台、邀請成員、五種成員角色,以及為什麼登入在雲端而不是在環境中進行。 editions: [cloud] translation: - source_sha: 45e832e16685da44f31911d619138580836770640112ee1300fc5cc35796ac0d + source_sha: 5d0d1a9751ee245d48b0c2aba06002c2ec161ee1ead737262e0a9ca5d7b3ef59 guide_rev: 1 mode: auto --- @@ -20,19 +20,19 @@ translation: | 側邊欄項 | 包含什麼 | 頁面 | |---|---|---| -| **Home**(首頁) | 組織一覽:生產環境、應用、成員、本週的 AI 額度 | — | -| **Environments**(環境) | 每個環境,及其設定和生命週期 | [環境](/docs/cloud/environments) | +| **Home**(首頁) | 組織一覽:它的環境、應用、成員、本週的 AI 額度 | — | +| **Environments**(環境) | 組織唯一的那個環境,及其設定和生命週期 | [環境](/docs/cloud/environments) | | **Members**(成員) | 組織中的人員及其待處理的邀請 | 本頁 | | **Billing**(賬單) | 套餐對比,以及升級 | [套餐與 AI 席位](/docs/cloud/plans-and-seats) | | **Advanced → Connected Runtimes** | 關聯到這個組織的自託管伺服器 | [雲連線](/docs/cloud/cloud-connection) | | **Advanced → Packages** | 你的組織已釋出的包 | [應用](/docs/cloud/apps) | -每個環境也有自己的控制台,位於該環境自己的地址。你的團隊在那裡使用應用; +這個環境也有自己的控制台,位於它自己的地址。你的團隊在那裡使用應用; 雲控制台則是你管理應用所在組織的地方。 ## 組織 slug [#the-organization-slug] -**slug** 是組織的簡短識別符號,在註冊時選定。它也是你的生產環境的地址: +**slug** 是組織的簡短識別符號,在註冊時選定。它也是你的環境的地址: slug 後面跟上平臺的域名。 - 4 到 30 個字元:小寫字母、數字和短橫線。 @@ -53,9 +53,9 @@ slug 後面跟上平臺的域名。 要新增某人,選擇 **Invite members**,輸入對方的電子郵件地址並選擇一個 角色。對方會收到一份邀請,接受之後就成為組織的成員。 -**組織的邀請是進入其環境的唯一途徑。** 環境沒有自己的邀請,也沒有自助 -註冊:你在這裡邀請的每個人都能進入組織的環境,而他們在某個環境中能做 -什麼,由該環境的[許可權](/docs/configure/permissions)決定。 +**組織的邀請是進入其環境的唯一途徑。** 這個環境沒有自己的邀請,也沒有自助 +註冊:你在這裡邀請的每個人都能進入組織的環境,而他們在其中能做 +什麼,由它的[許可權](/docs/configure/permissions)決定。 在這些列表中,管理組織的人可以**更改成員的角色**、**移除成員**,以及 **重新發送**或**撤銷**待處理的邀請。 @@ -74,7 +74,7 @@ slug 後面跟上平臺的域名。 | **External**(外部使用者) | 門戶使用者 —— 供應商或客戶的人員 —— 只能看到自己的行以及明確共享給他們的內容;從不屬於業務單元樹 | 任何能發出邀請的人 | 所有者和管理員就是本節所說的"管理組織的人":他們能看到套餐、升級以及 -會改變某些東西的環境操作。普通成員能看到環境並開啟它們,但不會看到他們 +會改變某些東西的環境操作。普通成員能看到環境並開啟它,但不會看到他們 無法完成的操作。 ## 登入在哪裡進行 [#where-sign-in-lives] @@ -82,7 +82,7 @@ slug 後面跟上平臺的域名。 在 ObjectOS Cloud 上,每個賬戶都是雲賬戶。由 ObjectOS Cloud 讓人登入,環境 接收他們:環境為每個人儲存的**只有授權** —— 他們的崗位、許可權集和共享。 每個託管環境預設都使用這一個登入,在每個套餐上都是如此,因此人們用 -ObjectOS Cloud 賬戶登入一次,就能在各個環境之間切換。 +ObjectOS Cloud 賬戶登入一次,就能開啟環境。 **把環境遷到你自己的基礎設施上。** 因為賬戶儲存在 ObjectOS Cloud 而不是 環境中,它們不會隨環境一起遷移。在自管理部署上,你要麼在那裡為人們簽發 @@ -91,6 +91,6 @@ ObjectOS Cloud 賬戶登入一次,就能在各個環境之間切換。 ## 下一步 [#next] -- [環境](/docs/cloud/environments) —— 生產環境和開發環境,以及它們的生命週期。 +- [環境](/docs/cloud/environments) —— 組織唯一的那個環境及其生命週期。 - [套餐與 AI 席位](/docs/cloud/plans-and-seats) —— Free、Team 和 Enterprise 各自包含什麼。 - [許可權](/docs/configure/permissions) —— 成員在環境中能做什麼。 diff --git a/content/docs/cloud/plans-and-seats.ja.mdx b/content/docs/cloud/plans-and-seats.ja.mdx new file mode 100644 index 00000000..3e1a5e14 --- /dev/null +++ b/content/docs/cloud/plans-and-seats.ja.mdx @@ -0,0 +1,94 @@ +--- +title: プランと AI シート +seoTitle: "ObjectOS Cloud のプラン:Free、Team、Enterprise と AI シート" +description: ObjectOS Cloud のプラン(Free、Team、Enterprise)、唯一の有料シートである AI シート、アップグレード、解約、シート数の変更の方法、請求元、そしてプランに含まれないものをコンソールのどこで確認できるか。 +editions: [cloud] +translation: + source_sha: 967b649fe678efe9da252655dcecac2adcce15578ade9a9b1cf60d088d29808d + guide_rev: 1 + mode: auto +--- + +ObjectOS Cloud には 3 つのプランがあります。プランは**組織**に属し、その環境に適用されます。料金がかかるのは **AI シート**だけで、組織のそれ以外の全員は無料でアプリを使い、閲覧できます。 + +| | **Free** | **Team** | **Enterprise** | +|---|---|---|---| +| 料金 | $0 | AI シートあたり月額 $24、または年払いで AI シートあたり月額 $20 | 契約による | +| [環境](/docs/cloud/environments) | 1 | 1 | 1 | +| [AI 利用枠](/docs/cloud/ai-credits-and-limits) | 週ごとの利用枠 | AI シートとともに増える、より大きな利用枠と [AI クレジットパック](/docs/cloud/ai-credits-and-limits#buy-ai-credits) | AI シートとともに増える利用枠と AI クレジットパック | +| [環境ごとのストレージ](/docs/cloud/storage-and-limits) | 1 GB | 20 GB | 上限なし | +| [AI エージェントのアクセス(MCP)](/docs/configure/mcp#on-objectos-cloud) | 1 分あたり 20 リクエスト、1 日 1,000 | 1 分あたり 120 リクエスト、1 日の上限なし | 1 分あたり 120 リクエスト、1 日の上限なし | +| ブランド付きのプラットフォームのサブドメイン | ✓ | ✓ | ✓ | +| [独自のドメイン](/docs/cloud/domains) | — | 本番環境ごとに 1 つ | ✓ | +| 承認ワークフロー | — | — | ✓ | +| サインイン | ObjectOS Cloud のサインイン | ObjectOS Cloud のサインイン | ObjectOS Cloud のサインイン。契約により、自社のアイデンティティプロバイダーによるシングルサインオン | +| サポート | コミュニティ | 標準 | 優先 | + +ObjectOS Cloud は[パブリックプレビュー](/docs/editions/public-preview)中です。料金はプレビュー期間の料金であり、変更があれば事前に告知されます。 + +## AI シート [#the-ai-seat] + +**AI シート**は、AI で構築し、データについて AI に質問できるメンバーです。[AI Builder](/docs/build/ai-builder) とアプリ内のアシスタントのことです。これが唯一の有料シートです。AI シートを持たないメンバー、閲覧者、そして [MCP](/docs/configure/mcp) 経由で自分の AI クライアントを使って構築する開発者には料金がかかりません。 + +購入する AI シートの数は組織の設定で、チェックアウト時に選び、[後から変更できます](#change-ai-seats)。それによって 2 つのものの大きさが決まります。 + +- 組織の **AI 利用枠**。シートごとです([AI クレジットと上限](/docs/cloud/ai-credits-and-limits))。 +- 人ごとのシートの割り当てが有効になっている環境で、AI シートを**割り当てられる**人の数。 + +## アップグレード [#upgrade] + +アップグレードは、オーナーまたは管理者が環境のページ(そのヘッダー、または **Settings → Plan and billing**)から行います。 + +1. **Upgrade Plan** を選びます。ダイアログで、プラン(Team)、請求の周期(月払い、または AI シートあたり月額 $20 の年払い)、AI シートの数を尋ねられます。 +2. 新しいタブで安全なチェックアウトが開きます。請求先は 1 つの環境ではなく、組織です。 +3. 支払いが完了すると組織のプランが変わり、その環境が再デプロイなしに新しいプランを取り込みます。 + +組織でまだオンライン決済が利用できない間は、ボタンは **Upgrade to Team** と表示され、代わりに **Billing** を開きます。そこで Team の **Contact sales** ボタンを押すと、私たちとともにアップグレードを始められます。 + +Enterprise は営業担当者が支援します。**Billing** の Enterprise の列にある **Contact sales** を使ってください。 + +## サブスクリプションを管理する [#manage-your-subscription] + +オンラインのチェックアウトで購入した Team プランはサブスクリプションで、オーナーまたは管理者が環境の **Settings → Plan and billing** から管理します。**Current plan** の行にある **Manage subscription** を選ぶと、Paddle のカスタマーポータルが新しいタブで開きます。ポータルでは次のことができます。 + +- サブスクリプションを**解約**する。更新が止まり、支払い済みの期間の終わりまでプランはそのまま使えます。その後、組織は Free に戻り、何も削除されません([ダウングレード](#downgrading))。 +- **支払い方法**を更新する。 +- **取引**を確認し、**請求書**をダウンロードする。 + +サブスクリプションの期間中、**Home** の **Plan and usage** カードには、オーナーと管理者に向けて **Next charge:** とその日付が表示されます。解約後は **Cancels at period end:** と、プランが終了する日が表示されます。 + +**Manage subscription** が表示されるのは Team プランで、オーナーと管理者に対して、オンライン決済が利用できるようになってからです。請求書払いのプランには管理するオンラインのサブスクリプションがありません。Business と Enterprise にはこのボタンが表示されず、請求書払いの Team プランではサブスクリプションがないという応答が返ります。こうしたプランの変更や解約は [sales@objectos.ai](mailto:sales@objectos.ai) にご連絡ください。 + +## AI シートを変更する [#change-ai-seats] + +コンソールではまだ AI シートの数を変更できず、カスタマーポータルでもシート数とプランは変更できません。AI シートを追加または削減するには、オーナーまたは管理者が、組織と必要なシート数を添えて [sales@objectos.ai](mailto:sales@objectos.ai) に連絡してください。私たちがサブスクリプション上で変更します。変更後は、AI 利用枠とシートの割り当て上限の両方が新しい数に従います。 + +## 支払い、請求書、返金 [#payment-invoices-and-refunds] + +コンソールでの購入(Team プランと [AI クレジットパック](/docs/cloud/ai-credits-and-limits#buy-ai-credits))は、私たちの再販業者であり Merchant of Record である **Paddle.com** が販売します。Paddle がチェックアウトを運営し、売上税や VAT を計算し、領収書と請求書を発行します。そのため、カードの利用明細と領収書には ObjectOS ではなく **Paddle** と表示されます。請求書はカスタマーポータルにあります([サブスクリプションを管理する](#manage-your-subscription))。 + +支払いが返金される条件と申請の方法は、www.objectos.ai の[返金・解約ポリシー](https://www.objectos.ai/en/refunds/)に記載されています。 + +## プランに含まれないものを確認する [#see-what-your-plan-leaves-out] + +コンソールの 2 か所で、営業ページを挟まずに確認できます。 + +- **Billing** は 3 つのプランを並べて比較し、現在のプランに **Current plan** の印を付けます。すべてのメンバーが読めますが、そのボタンが表示されるのはオーナーと管理者だけです。 +- 環境の **Overview** タブには、折りたたまれた **Features that need a higher plan: N · View** の行があります。開くと、現在のプランに含まれない各機能が、それを含むプランとともに一覧されます。ロックされた機能がコンソールのほかの場所に現れる場合は、**Team plan and above** のような、そのプランの名前を示す短い印が付き、**Billing** へ移動できます。 + +## ダウングレード [#downgrading] + +下位のプランに下げても、データが削除されることは決してありません。 + +- 環境は動き続け、データも保持されます。アーカイブされた環境は、誰かが削除するまで残ります([環境](/docs/cloud/environments#how-long-an-archived-environment-is-kept))。 +- Free のストレージの割り当てを超えた環境は、すべてのバイトを保持し、読み取りとエクスポートができる状態のまま、アップロードとインポートを受け付けなくなります([ストレージと上限](/docs/cloud/storage-and-limits))。 +- 独自のドメインは解放されずに一時停止され、後でアップグレードすると自動的に戻ります([ドメイン](/docs/cloud/domains#downgrade-and-upgrade))。 + +## Business [#business] + +**Business** は、ホスト型サービスにおける ObjectOS Enterprise の契約オプションで、**Billing** からではなく[営業](/docs/editions/license)が販売します。ObjectOS Cloud では、承認ワークフローを追加します。料金と契約がカバーする内容は[ライセンスと料金](/docs/editions/license)にあります。 + +## 次へ [#next] + +- [エディションの比較](/docs/editions/compare):Community と Enterprise と並べたプラン。 +- [AI クレジットと上限](/docs/cloud/ai-credits-and-limits):AI 利用枠の仕組み。 diff --git a/content/docs/cloud/plans-and-seats.zh-Hans.mdx b/content/docs/cloud/plans-and-seats.zh-Hans.mdx new file mode 100644 index 00000000..f6cc3224 --- /dev/null +++ b/content/docs/cloud/plans-and-seats.zh-Hans.mdx @@ -0,0 +1,120 @@ +--- +title: 套餐与 AI 席位 +seoTitle: "ObjectOS Cloud 套餐:Free、Team、Enterprise 与 AI 席位" +description: ObjectOS Cloud 的套餐 —— Free、Team 和 Enterprise —— AI 席位是唯一付费的席位、如何升级、取消或更改席位、由谁向你收费,以及控制台在哪里显示你的套餐不包含什么。 +editions: [cloud] +translation: + source_sha: 967b649fe678efe9da252655dcecac2adcce15578ade9a9b1cf60d088d29808d + guide_rev: 1 + mode: auto +--- + +ObjectOS Cloud 有三个套餐。套餐属于**组织**,适用于它的环境。只有 +**AI 席位**需要付费:组织中的其他人都可以免费使用和查看应用。 + +| | **Free** | **Team** | **Enterprise** | +|---|---|---|---| +| 价格 | 0 美元 | 24 美元 / AI 席位 / 月,或按年付费 20 美元 / AI 席位 / 月 | 按合同 | +| [环境](/docs/cloud/environments) | 1 | 1 | 1 | +| [AI 额度](/docs/cloud/ai-credits-and-limits) | 每周额度 | 更高的额度,随 AI 席位增长,外加 [AI 点数包](/docs/cloud/ai-credits-and-limits#buy-ai-credits) | 随 AI 席位增长,外加 AI 点数包 | +| [每个环境的存储](/docs/cloud/storage-and-limits) | 1 GB | 20 GB | 不设上限 | +| [AI Agent 访问(MCP)](/docs/configure/mcp#on-objectos-cloud) | 每分钟 20 次请求,每天 1,000 次 | 每分钟 120 次请求,无每日上限 | 每分钟 120 次请求,无每日上限 | +| 品牌平台子域名 | ✓ | ✓ | ✓ | +| [你自己的域名](/docs/cloud/domains) | — | 每个生产环境一个 | ✓ | +| 审批工作流 | — | — | ✓ | +| 登录 | ObjectOS Cloud 登录 | ObjectOS Cloud 登录 | ObjectOS Cloud 登录;按合同提供与你的身份提供商的单点登录 | +| 支持 | 社区 | 标准 | 优先 | + +ObjectOS Cloud 处于[公开预览](/docs/editions/public-preview)阶段: +价格为预览期价格,任何变更都会提前公告。 + +## AI 席位 [#the-ai-seat] + +**AI 席位**是指能够用 AI 构建、并就你的数据向 AI 提问的成员 —— +即使用 [AI Builder](/docs/build/ai-builder) 和应用内助手。它是唯一付费的 +席位。没有 AI 席位的成员、只读用户,以及通过自己的 AI 客户端经 +[MCP](/docs/configure/mcp) 构建的开发者,都不收费。 + +你购买的 AI 席位数量是组织的一项设置,在结账时选定,[之后可以更改](#change-ai-seats)。它决定 +两件事的规模: + +- 组织的 **AI 额度**,按席位计算 + ([AI 点数与限制](/docs/cloud/ai-credits-and-limits)); +- 在开启了按人分配席位的环境中,能被**分配** AI 席位的人数。 + +## 升级 [#upgrade] + +升级由所有者或管理员在某个环境的页面上进行:它的页头,或 +**Settings → Plan and billing**。 + +1. 选择 **Upgrade Plan**。对话框会询问套餐(Team)、计费周期(按月,或 + 按年,每个 AI 席位每月 20 美元)以及 AI 席位数量。 +2. 一个安全结账页面会在新标签页中打开。费用计入你的组织, + 而不是某一个环境。 +3. 付款完成后,组织的套餐随之变更,它的环境会采用新套餐, + 无需重新部署。 + +在你的组织尚未开放在线支付时,按钮显示为 +**Upgrade to Team**,并改为打开 **Billing**,在那里 Team 的 +**Contact sales** 按钮会与我们一起开始升级。 + +Enterprise 由销售协助:在 **Billing** 的 Enterprise 一列点击 **Contact sales**。 + +## 管理你的订阅 [#manage-your-subscription] + +通过在线结账购买的 Team 套餐是一项订阅,由所有者或管理员在某个环境的 **Settings → Plan and billing** 中管理:**Current plan** 一行上的 **Manage subscription** 会在新标签页中打开 Paddle 的客户门户。在门户中你可以: + +- **取消**订阅。订阅不再续费,套餐保留到你已付费周期的结束;之后组织回到 Free,不会删除任何内容([降级](#downgrading)); +- 更新**付款方式**; +- 查看你的**交易记录**并下载**发票**。 + +订阅期间,**Home** 上的 **Plan and usage** 卡片会向所有者和管理员显示 **Next charge:** 及其日期;取消之后,它显示 **Cancels at period end:** 以及套餐结束的日期。 + +**Manage subscription** 只在 Team 套餐上、在在线支付开放后提供给所有者和管理员。按发票计费的套餐没有可管理的在线订阅:Business 和 Enterprise 从不显示该按钮,按发票计费的 Team 套餐会答复它没有在线订阅。此类套餐的更改或取消请通过 [sales@objectos.ai](mailto:sales@objectos.ai) 联系我们。 + +## 更改 AI 席位 [#change-ai-seats] + +控制台目前还不能更改 AI 席位数量,客户门户既不能更改席位数量,也不能更改套餐。要增加或减少 AI 席位,由所有者或管理员写信到 [sales@objectos.ai](mailto:sales@objectos.ai),说明组织以及它应有的席位数量,我们会在你的订阅上进行更改。更改之后,AI 额度和席位分配上限都会随新的数量变化。 + +## 付款、发票与退款 [#payment-invoices-and-refunds] + +控制台中的购买 —— Team 套餐和 [AI 点数包](/docs/cloud/ai-credits-and-limits#buy-ai-credits) —— 由我们的经销商和记录商户(Merchant of Record)**Paddle.com** 售卖。Paddle 负责结账、计算任何销售税或增值税,并开具收据和发票,因此你的银行卡账单上的扣款和收据显示的是 **Paddle**,而不是 ObjectOS。发票在客户门户中([管理你的订阅](#manage-your-subscription))。 + +款项何时可以退款以及如何申请,见 www.objectos.ai 上的[退款与取消政策](https://www.objectos.ai/en/refunds/)。 + +## 查看你的套餐不包含什么 [#see-what-your-plan-leaves-out] + +控制台中有两个地方会告诉你,中间无需经过销售页面: + +- **Billing** 把三个套餐并排对比,并用 **Current plan** 标出你当前 + 所在的套餐。每个成员都能阅读它;只有所有者和管理员能看到其中的按钮。 +- 环境的 **Overview** 标签页上有一行折叠内容, + **Features that need a higher plan: N · View**。展开后会列出当前套餐 + 不包含的每项功能,以及包含它的套餐。 + 当某个锁定功能出现在控制台的其他地方时,它会带一个简短的标记,注明 + 它所属的套餐,例如 **Team plan and above**,点击后进入 + **Billing**。 + +## 降级 [#downgrading] + +降到更低的套餐从不会删除数据: + +- 环境继续运行并保留它的数据;已归档的环境会一直保留,直到有人删除它 + ([环境](/docs/cloud/environments#how-long-an-archived-environment-is-kept))。 +- 超出 Free 存储额度的环境保留每一个字节,仍可读取和导出, + 只是不再接受上传和导入 + ([存储与限制](/docs/cloud/storage-and-limits))。 +- 你自己的域名会被暂停而不是释放,并会在之后升级时自动恢复 + ([域名](/docs/cloud/domains#downgrade-and-upgrade))。 + +## Business [#business] + +**Business** 是 ObjectOS Enterprise 在托管服务上的一个合同选项,由 +[销售](/docs/editions/license)而不是 **Billing** 售卖。在 ObjectOS Cloud +上,它增加了审批工作流。它的价格以及 +合同涵盖的内容见[许可与定价](/docs/editions/license)。 + +## 下一步 [#next] + +- [版本对比](/docs/editions/compare) —— 这些套餐与 Community 和 Enterprise 的并列对比。 +- [AI 点数与限制](/docs/cloud/ai-credits-and-limits) —— AI 额度如何运作。 diff --git a/content/docs/cloud/plans-and-seats.zh-Hant.mdx b/content/docs/cloud/plans-and-seats.zh-Hant.mdx new file mode 100644 index 00000000..8ac30319 --- /dev/null +++ b/content/docs/cloud/plans-and-seats.zh-Hant.mdx @@ -0,0 +1,121 @@ +--- +# @generated zh-Hant from zh-Hans -- do not edit. Edit the English source, then regenerate: pnpm --filter @objectos/docs gen:zh-hant +title: 套餐與 AI 席位 +seoTitle: "ObjectOS Cloud 套餐:Free、Team、Enterprise 與 AI 席位" +description: ObjectOS Cloud 的套餐 —— Free、Team 和 Enterprise —— AI 席位是唯一付費的席位、如何升級、取消或更改席位、由誰向你收費,以及控制台在哪裡顯示你的套餐不包含什麼。 +editions: [cloud] +translation: + source_sha: 967b649fe678efe9da252655dcecac2adcce15578ade9a9b1cf60d088d29808d + guide_rev: 1 + mode: auto +--- + +ObjectOS Cloud 有三個套餐。套餐屬於**組織**,適用於它的環境。只有 +**AI 席位**需要付費:組織中的其他人都可以免費使用和檢視應用。 + +| | **Free** | **Team** | **Enterprise** | +|---|---|---|---| +| 價格 | 0 美元 | 24 美元 / AI 席位 / 月,或按年付費 20 美元 / AI 席位 / 月 | 按合同 | +| [環境](/docs/cloud/environments) | 1 | 1 | 1 | +| [AI 額度](/docs/cloud/ai-credits-and-limits) | 每週額度 | 更高的額度,隨 AI 席位增長,外加 [AI 點數包](/docs/cloud/ai-credits-and-limits#buy-ai-credits) | 隨 AI 席位增長,外加 AI 點數包 | +| [每個環境的儲存](/docs/cloud/storage-and-limits) | 1 GB | 20 GB | 不設上限 | +| [AI Agent 訪問(MCP)](/docs/configure/mcp#on-objectos-cloud) | 每分鐘 20 次請求,每天 1,000 次 | 每分鐘 120 次請求,無每日上限 | 每分鐘 120 次請求,無每日上限 | +| 品牌平臺子域名 | ✓ | ✓ | ✓ | +| [你自己的域名](/docs/cloud/domains) | — | 每個生產環境一個 | ✓ | +| 審批工作流 | — | — | ✓ | +| 登入 | ObjectOS Cloud 登入 | ObjectOS Cloud 登入 | ObjectOS Cloud 登入;按合同提供與你的身份提供商的單點登入 | +| 支援 | 社群 | 標準 | 優先 | + +ObjectOS Cloud 處於[公開預覽](/docs/editions/public-preview)階段: +價格為預覽期價格,任何變更都會提前公告。 + +## AI 席位 [#the-ai-seat] + +**AI 席位**是指能夠用 AI 構建、並就你的資料向 AI 提問的成員 —— +即使用 [AI Builder](/docs/build/ai-builder) 和應用內助手。它是唯一付費的 +席位。沒有 AI 席位的成員、只讀使用者,以及通過自己的 AI 客戶端經 +[MCP](/docs/configure/mcp) 構建的開發者,都不收費。 + +你購買的 AI 席位數量是組織的一項設定,在結賬時選定,[之後可以更改](#change-ai-seats)。它決定 +兩件事的規模: + +- 組織的 **AI 額度**,按席位計算 + ([AI 點數與限制](/docs/cloud/ai-credits-and-limits)); +- 在開啟了按人分配席位的環境中,能被**分配** AI 席位的人數。 + +## 升級 [#upgrade] + +升級由所有者或管理員在某個環境的頁面上進行:它的頁頭,或 +**Settings → Plan and billing**。 + +1. 選擇 **Upgrade Plan**。對話方塊會詢問套餐(Team)、計費週期(按月,或 + 按年,每個 AI 席位每月 20 美元)以及 AI 席位數量。 +2. 一個安全結賬頁面會在新標籤頁中開啟。費用計入你的組織, + 而不是某一個環境。 +3. 付款完成後,組織的套餐隨之變更,它的環境會採用新套餐, + 無需重新部署。 + +在你的組織尚未開放線上支付時,按鈕顯示為 +**Upgrade to Team**,並改為開啟 **Billing**,在那裡 Team 的 +**Contact sales** 按鈕會與我們一起開始升級。 + +Enterprise 由銷售協助:在 **Billing** 的 Enterprise 一列點選 **Contact sales**。 + +## 管理你的訂閱 [#manage-your-subscription] + +通過線上結賬購買的 Team 套餐是一項訂閱,由所有者或管理員在某個環境的 **Settings → Plan and billing** 中管理:**Current plan** 一行上的 **Manage subscription** 會在新標籤頁中開啟 Paddle 的客戶門戶。在門戶中你可以: + +- **取消**訂閱。訂閱不再續費,套餐保留到你已付費週期的結束;之後組織回到 Free,不會刪除任何內容([降級](#downgrading)); +- 更新**付款方式**; +- 檢視你的**交易記錄**並下載**發票**。 + +訂閱期間,**Home** 上的 **Plan and usage** 卡片會向所有者和管理員顯示 **Next charge:** 及其日期;取消之後,它顯示 **Cancels at period end:** 以及套餐結束的日期。 + +**Manage subscription** 只在 Team 套餐上、在線上支付開放後提供給所有者和管理員。按發票計費的套餐沒有可管理的線上訂閱:Business 和 Enterprise 從不顯示該按鈕,按發票計費的 Team 套餐會答覆它沒有線上訂閱。此類套餐的更改或取消請通過 [sales@objectos.ai](mailto:sales@objectos.ai) 聯絡我們。 + +## 更改 AI 席位 [#change-ai-seats] + +控制台目前還不能更改 AI 席位數量,客戶門戶既不能更改席位數量,也不能更改套餐。要增加或減少 AI 席位,由所有者或管理員寫信到 [sales@objectos.ai](mailto:sales@objectos.ai),說明組織以及它應有的席位數量,我們會在你的訂閱上進行更改。更改之後,AI 額度和席位分配上限都會隨新的數量變化。 + +## 付款、發票與退款 [#payment-invoices-and-refunds] + +控制台中的購買 —— Team 套餐和 [AI 點數包](/docs/cloud/ai-credits-and-limits#buy-ai-credits) —— 由我們的經銷商和記錄商戶(Merchant of Record)**Paddle.com** 售賣。Paddle 負責結賬、計算任何銷售稅或增值稅,並開具收據和發票,因此你的銀行卡賬單上的扣款和收據顯示的是 **Paddle**,而不是 ObjectOS。發票在客戶門戶中([管理你的訂閱](#manage-your-subscription))。 + +款項何時可以退款以及如何申請,見 www.objectos.ai 上的[退款與取消政策](https://www.objectos.ai/en/refunds/)。 + +## 檢視你的套餐不包含什麼 [#see-what-your-plan-leaves-out] + +控制台中有兩個地方會告訴你,中間無需經過銷售頁面: + +- **Billing** 把三個套餐並排對比,並用 **Current plan** 標出你當前 + 所在的套餐。每個成員都能閱讀它;只有所有者和管理員能看到其中的按鈕。 +- 環境的 **Overview** 標籤頁上有一行摺疊內容, + **Features that need a higher plan: N · View**。展開後會列出當前套餐 + 不包含的每項功能,以及包含它的套餐。 + 當某個鎖定功能出現在控制台的其他地方時,它會帶一個簡短的標記,註明 + 它所屬的套餐,例如 **Team plan and above**,點選後進入 + **Billing**。 + +## 降級 [#downgrading] + +降到更低的套餐從不會刪除資料: + +- 環境繼續執行並保留它的資料;已歸檔的環境會一直保留,直到有人刪除它 + ([環境](/docs/cloud/environments#how-long-an-archived-environment-is-kept))。 +- 超出 Free 儲存額度的環境保留每一個位元組,仍可讀取和匯出, + 只是不再接受上傳和匯入 + ([儲存與限制](/docs/cloud/storage-and-limits))。 +- 你自己的域名會被暫停而不是釋放,並會在之後升級時自動恢復 + ([域名](/docs/cloud/domains#downgrade-and-upgrade))。 + +## Business [#business] + +**Business** 是 ObjectOS Enterprise 在託管服務上的一個合同選項,由 +[銷售](/docs/editions/license)而不是 **Billing** 售賣。在 ObjectOS Cloud +上,它增加了審批工作流。它的價格以及 +合同涵蓋的內容見[許可與定價](/docs/editions/license)。 + +## 下一步 [#next] + +- [版本對比](/docs/editions/compare) —— 這些套餐與 Community 和 Enterprise 的並列對比。 +- [AI 點數與限制](/docs/cloud/ai-credits-and-limits) —— AI 額度如何運作。 diff --git a/content/docs/cloud/storage-and-limits.ja.mdx b/content/docs/cloud/storage-and-limits.ja.mdx new file mode 100644 index 00000000..cac9a876 --- /dev/null +++ b/content/docs/cloud/storage-and-limits.ja.mdx @@ -0,0 +1,61 @@ +--- +title: ストレージと上限 +seoTitle: "ObjectOS Cloud の上限:環境ごとのストレージと MCP リクエストの上限" +description: ObjectOS Cloud の環境の使用上限。1 GB と 20 GB のストレージの割り当て、いっぱいになった環境が止めるものと決して止めないもの、80% の警告、そしてプランごとの MCP リクエストとドラフトの上限。 +editions: [cloud] +translation: + source_sha: 797d642d8d75df1e4b25114e7b7cc4993b7508100e7cba34d06ab2f826fa7637 + guide_rev: 1 + mode: auto +--- + +各 ObjectOS Cloud の環境には、独自の上限がいくつかあります。このページでは、それぞれの数値が属するプランとともに一覧します。AI 利用枠には専用のページがあります:[AI クレジットと上限](/docs/cloud/ai-credits-and-limits)。 + +| 上限 | Free | Team 以上 | Enterprise | +|---|---|---|---| +| [環境ごとのストレージ](#storage) | 1 GB | 20 GB | 上限なし | +| [1 分あたりの MCP リクエスト](#mcp-limits) | 20 | 120 | 120 | +| [UTC の 1 日あたりの MCP リクエスト](#mcp-limits) | 1,000 | 1 日の上限なし | 1 日の上限なし | +| [UTC の 1 日あたりの MCP 経由の作成の書き込み](#drafts-and-authoring-writes) | 200 | 2,000 | 2,000 | +| [環境ごとの未公開のドラフト](#drafts-and-authoring-writes) | 500 | 500 | 500 | + +## ストレージ [#storage] + +すべての環境には**ストレージの割り当て**があります。Free では **1 GB**、Team では **20 GB** で、**環境ごと**に数えられ、組織が持つ環境は 1 つです。Enterprise 契約にはストレージの数値はありません(プロダクトオーナーの決定、2026-09-08:数値は確定です)。 + +**数えられるもの。** 環境のデータベースと添付ファイルです。使用量はおよそ 1 時間ごとに測り直されるので、大きなアップロードやインポートは 1 時間以内に測定値に現れます。この遅れは意図的なものです。 + +**いっぱいになった環境が止めるもの。** 割り当ての 100% から、2 つのことが拒否されます。 + +- **添付ファイルのアップロード**(ファイルと画像のフィールド) +- レコードの**一括インポート** + +拒否は、コード `STORAGE_LIMIT_REACHED` とアップグレードの方法とともに `403` で返されます。 + +**決して止めないもの。** 単一のレコードの作成、編集、削除。何かを読むこと。エクスポート。そして空き容量を作るための添付ファイルの削除です。環境が割り当てに近づいているせいで、その環境で構築されたアプリを使う人がフォームを保存できなくなることは決してありません。 + +**警告。** **80%** でコンソールにバナーが表示されます。これは警告であって上限ではありません。アップロードとインポートは 100% まで引き続き通ります。 + +**ダウングレードは何も削除しません。** ダウングレードの後で Free の割り当てを超えてしまった環境は、すべてのバイトを保持し、読み取りとエクスポートができる状態のまま、再びアップグレードされるか空き容量ができるまで、アップロードとインポートを受け付けなくなるだけです。 + +## MCP の上限 [#mcp-limits] + +すべての環境の [MCP エンドポイント](/docs/configure/mcp#on-objectos-cloud)が受け付けるリクエストの数は決まっており、その環境に接続しているすべてのエージェントで共有されます。[cloud#3203](https://github.com/objectstack-ai/cloud/issues/3203) で決定されました。 + +- **Free:** 1 分あたり 20 リクエスト、UTC の 1 日あたり 1,000。 +- **Team 以上:** 1 分あたり 120 リクエスト、1 日の上限なし。 + +リクエストは 1 つの MCP メッセージです。ツールの呼び出し、一覧の取得、接続のハンドシェイクの各ステップです。バッチはその中の各メッセージを数え、その日の残りの数に収まらないバッチは丸ごと拒否されます。1 分あたりの割り当ては連続的に補充されるので、1 分あたりの数値までの短い集中した利用は問題ありません。 + +上限を超えると、エンドポイントは `Retry-After` ヘッダー付きの `429 Too Many Requests` で応答し、本文の `error.code` は `RATE_LIMIT_EXCEEDED` です。メッセージには、どの上限に達したか、いつリセットされるかが示され、Free では Team へのアップグレードも案内されます。拒否されたリクエストは実行されておらず、どちらの上限も消費しません。待った後の次のリクエストは通常どおり処理されます。人が操作するエージェントは有料プランの上限を十分に下回ります。上限に達するエージェントは、たいていは同じツールを繰り返し呼び出すループです。 + +## ドラフトと作成の書き込み [#drafts-and-authoring-writes] + +アプリの設計への変更は、公開されるまで**ドラフト**としてステージングされます。環境が保持できる**未公開のドラフトは最大 500 件**で、どのプランでも、どの方法で作られたものでも同じです。それを超えると、さらにドラフトをステージングする変更は、ドラフトが公開または破棄されるまで拒否されます。これは時間でリセットされることはありません。 + +MCP 経由で届く作成の書き込み(メタデータを作成または変更するビルドツール)も、UTC の 1 日ごとに数えられます。Free では **200**、Team 以上では **2,000** です。読み取りとチェックは数えられません。どちらの拒否も、リクエストの上限と同じ `RATE_LIMIT_EXCEEDED` の応答を使い、その数、上限、いつリセットされるかを示します。[cloud#3303](https://github.com/objectstack-ai/cloud/issues/3303) で決定されました。 + +## 次へ [#next] + +- [プランと AI シート](/docs/cloud/plans-and-seats):各プランに含まれるもの。 +- [AI ツールを接続する(MCP)](/docs/configure/mcp#on-objectos-cloud):環境の MCP エンドポイントを有効にする。 diff --git a/content/docs/cloud/storage-and-limits.zh-Hans.mdx b/content/docs/cloud/storage-and-limits.zh-Hans.mdx new file mode 100644 index 00000000..b54045ad --- /dev/null +++ b/content/docs/cloud/storage-and-limits.zh-Hans.mdx @@ -0,0 +1,85 @@ +--- +title: 存储与限制 +seoTitle: "ObjectOS Cloud 限制:每个环境的存储和 MCP 请求限制" +description: ObjectOS Cloud 环境的用量限制 —— 1 GB 和 20 GB 的存储额度、存储满的环境会停止什么以及从不停止什么、80% 警告,以及每个套餐的 MCP 请求限制和草稿限制。 +editions: [cloud] +translation: + source_sha: 797d642d8d75df1e4b25114e7b7cc4993b7508100e7cba34d06ab2f826fa7637 + guide_rev: 1 + mode: auto +--- + +每个 ObjectOS Cloud 环境都有几项自己的限制。本页列出这些限制,以及每个 +数字所属的套餐。AI 额度有它自己的页面: +[AI 点数与限制](/docs/cloud/ai-credits-and-limits)。 + +| 限制 | Free | Team 及以上 | Enterprise | +|---|---|---|---| +| [每个环境的存储](#storage) | 1 GB | 20 GB | 不设上限 | +| [每分钟 MCP 请求数](#mcp-limits) | 20 | 120 | 120 | +| [每个 UTC 日的 MCP 请求数](#mcp-limits) | 1,000 | 无每日上限 | 无每日上限 | +| [每个 UTC 日通过 MCP 的编写写入](#drafts-and-authoring-writes) | 200 | 2,000 | 2,000 | +| [每个环境的未发布草稿](#drafts-and-authoring-writes) | 500 | 500 | 500 | + +## 存储 [#storage] + +每个环境都有一份**存储额度**:Free 上 **1 GB**,Team 上 **20 GB**, +**按环境**计算,而一个组织只有一个环境。Enterprise 合同不设 +存储数字。(产品负责人裁定,2026-09-08:这些数字是最终的。) + +**计入什么。** 环境的数据库加上它的附件。用量大约每小时重新测量一次, +因此一次大的上传或导入会在一小时内反映到读数中;这种延迟是有意为之。 + +**存储满的环境会停止什么。** 从额度的 100% 起,两件事会被拒绝: + +- **附件上传**(文件和图片字段); +- 记录的**批量导入**。 + +拒绝返回 `403`,代码为 `STORAGE_LIMIT_REACHED`,并附上升级的途径。 + +**它从不停止什么。** 创建、编辑或删除单条记录;读取任何内容;导出;以及 +删除附件以释放空间。使用基于该环境构建的应用的人,永远不会因为环境接近 +额度而无法保存表单。 + +**警告。** 达到 **80%** 时,控制台会显示一条横幅。它是警告,不是 +限制:在达到 100% 之前,上传和导入仍会正常进行。 + +**降级不会删除任何东西。** 降级后超出 Free 额度的环境保留每一个字节, +仍可读取和导出,只是不再接受上传和导入,直到再次升级或释放出空间。 + +## MCP 限制 [#mcp-limits] + +每个环境的 [MCP 端点](/docs/configure/mcp#on-objectos-cloud) +接受固定数量的请求,由连接到该环境的所有 Agent 共享。裁定见 +[cloud#3203](https://github.com/objectstack-ai/cloud/issues/3203)。 + +- **Free**:每分钟 20 次请求,每个 UTC 日 1,000 次。 +- **Team 及以上**:每分钟 120 次请求,无每日上限。 + +一次请求就是一条 MCP 消息:一次工具调用、一次列出、连接握手的每一步。 +批处理会计入其中的每一条消息,当天剩余次数容纳不下的批处理会被整体拒绝。 +每分钟额度是持续补充的,因此不超过每分钟数值的短时突发没有问题。 + +超过限制时,端点返回 `429 Too Many Requests` 和 `Retry-After` +头,响应体的 `error.code` 为 `RATE_LIMIT_EXCEEDED`。消息会说明触及了 +哪个限制以及何时重置;在 Free 上还会指向升级到 Team。被拒绝的请求没有 +运行,也不占用任何一个限制,等待之后的下一个请求会正常处理。由人驱动的 +Agent 远低于付费套餐的限制;触及限制的通常是一个反复调用同一工具的循环。 + +## 草稿与编写写入 [#drafts-and-authoring-writes] + +对应用设计的变更在发布之前会暂存为**草稿**。 +一个环境最多容纳 **500 个未发布草稿**,在每个套餐上都是如此,无论它们是 +以哪种方式产生的。超过这个数量后,会再暂存一个草稿的变更会被拒绝,直到 +草稿被发布或丢弃;这一项没有任何时钟会重置。 + +通过 MCP 到达的编写写入 —— 创建或更改元数据的构建工具 —— 也按 UTC 日 +计数:Free 上 **200** 次,Team 及以上 **2,000** 次。读取和检查不计数。 +两种拒绝都使用与请求限制相同的 `RATE_LIMIT_EXCEEDED` 应答,附带计数、限制 +以及何时重置。裁定见 +[cloud#3303](https://github.com/objectstack-ai/cloud/issues/3303)。 + +## 下一步 [#next] + +- [套餐与 AI 席位](/docs/cloud/plans-and-seats) —— 每个套餐包含什么。 +- [连接 AI 工具(MCP)](/docs/configure/mcp#on-objectos-cloud) —— 开启环境的 MCP 端点。 diff --git a/content/docs/cloud/storage-and-limits.zh-Hant.mdx b/content/docs/cloud/storage-and-limits.zh-Hant.mdx new file mode 100644 index 00000000..ab92d1e8 --- /dev/null +++ b/content/docs/cloud/storage-and-limits.zh-Hant.mdx @@ -0,0 +1,86 @@ +--- +# @generated zh-Hant from zh-Hans -- do not edit. Edit the English source, then regenerate: pnpm --filter @objectos/docs gen:zh-hant +title: 儲存與限制 +seoTitle: "ObjectOS Cloud 限制:每個環境的儲存和 MCP 請求限制" +description: ObjectOS Cloud 環境的用量限制 —— 1 GB 和 20 GB 的儲存額度、儲存滿的環境會停止什麼以及從不停止什麼、80% 警告,以及每個套餐的 MCP 請求限制和草稿限制。 +editions: [cloud] +translation: + source_sha: 797d642d8d75df1e4b25114e7b7cc4993b7508100e7cba34d06ab2f826fa7637 + guide_rev: 1 + mode: auto +--- + +每個 ObjectOS Cloud 環境都有幾項自己的限制。本頁列出這些限制,以及每個 +數字所屬的套餐。AI 額度有它自己的頁面: +[AI 點數與限制](/docs/cloud/ai-credits-and-limits)。 + +| 限制 | Free | Team 及以上 | Enterprise | +|---|---|---|---| +| [每個環境的儲存](#storage) | 1 GB | 20 GB | 不設上限 | +| [每分鐘 MCP 請求數](#mcp-limits) | 20 | 120 | 120 | +| [每個 UTC 日的 MCP 請求數](#mcp-limits) | 1,000 | 無每日上限 | 無每日上限 | +| [每個 UTC 日通過 MCP 的編寫寫入](#drafts-and-authoring-writes) | 200 | 2,000 | 2,000 | +| [每個環境的未釋出草稿](#drafts-and-authoring-writes) | 500 | 500 | 500 | + +## 儲存 [#storage] + +每個環境都有一份**儲存額度**:Free 上 **1 GB**,Team 上 **20 GB**, +**按環境**計算,而一個組織只有一個環境。Enterprise 合同不設 +儲存數字。(產品負責人裁定,2026-09-08:這些數字是最終的。) + +**計入什麼。** 環境的資料庫加上它的附件。用量大約每小時重新測量一次, +因此一次大的上傳或匯入會在一小時內反映到讀數中;這種延遲是有意為之。 + +**儲存滿的環境會停止什麼。** 從額度的 100% 起,兩件事會被拒絕: + +- **附件上傳**(檔案和圖片欄位); +- 記錄的**批次匯入**。 + +拒絕返回 `403`,程式碼為 `STORAGE_LIMIT_REACHED`,並附上升級的途徑。 + +**它從不停止什麼。** 建立、編輯或刪除單條記錄;讀取任何內容;匯出;以及 +刪除附件以釋放空間。使用基於該環境構建的應用的人,永遠不會因為環境接近 +額度而無法儲存表單。 + +**警告。** 達到 **80%** 時,控制台會顯示一條橫幅。它是警告,不是 +限制:在達到 100% 之前,上傳和匯入仍會正常進行。 + +**降級不會刪除任何東西。** 降級後超出 Free 額度的環境保留每一個位元組, +仍可讀取和匯出,只是不再接受上傳和匯入,直到再次升級或釋放出空間。 + +## MCP 限制 [#mcp-limits] + +每個環境的 [MCP 端點](/docs/configure/mcp#on-objectos-cloud) +接受固定數量的請求,由連線到該環境的所有 Agent 共享。裁定見 +[cloud#3203](https://github.com/objectstack-ai/cloud/issues/3203)。 + +- **Free**:每分鐘 20 次請求,每個 UTC 日 1,000 次。 +- **Team 及以上**:每分鐘 120 次請求,無每日上限。 + +一次請求就是一條 MCP 訊息:一次工具呼叫、一次列出、連線握手的每一步。 +批處理會計入其中的每一條訊息,當天剩餘次數容納不下的批處理會被整體拒絕。 +每分鐘額度是持續補充的,因此不超過每分鐘數值的短時突發沒有問題。 + +超過限制時,端點返回 `429 Too Many Requests` 和 `Retry-After` +頭,響應體的 `error.code` 為 `RATE_LIMIT_EXCEEDED`。訊息會說明觸及了 +哪個限制以及何時重置;在 Free 上還會指向升級到 Team。被拒絕的請求沒有 +執行,也不佔用任何一個限制,等待之後的下一個請求會正常處理。由人驅動的 +Agent 遠低於付費套餐的限制;觸及限制的通常是一個反覆呼叫同一工具的迴圈。 + +## 草稿與編寫寫入 [#drafts-and-authoring-writes] + +對應用設計的變更在釋出之前會暫存為**草稿**。 +一個環境最多容納 **500 個未釋出草稿**,在每個套餐上都是如此,無論它們是 +以哪種方式產生的。超過這個數量後,會再暫存一個草稿的變更會被拒絕,直到 +草稿被髮布或丟棄;這一項沒有任何時鐘會重置。 + +通過 MCP 到達的編寫寫入 —— 建立或更改後設資料的構建工具 —— 也按 UTC 日 +計數:Free 上 **200** 次,Team 及以上 **2,000** 次。讀取和檢查不計數。 +兩種拒絕都使用與請求限制相同的 `RATE_LIMIT_EXCEEDED` 應答,附帶計數、限制 +以及何時重置。裁定見 +[cloud#3303](https://github.com/objectstack-ai/cloud/issues/3303)。 + +## 下一步 [#next] + +- [套餐與 AI 席位](/docs/cloud/plans-and-seats) —— 每個套餐包含什麼。 +- [連線 AI 工具(MCP)](/docs/configure/mcp#on-objectos-cloud) —— 開啟環境的 MCP 端點。 diff --git a/content/docs/editions/compare.ja.mdx b/content/docs/editions/compare.ja.mdx new file mode 100644 index 00000000..334d8cc1 --- /dev/null +++ b/content/docs/editions/compare.ja.mdx @@ -0,0 +1,62 @@ +--- +title: エディションの比較 +seoTitle: "ObjectOS エディションの比較:Community、Free、Team、Enterprise" +description: ObjectOS の各エディションとプランに含まれるものを 1 行ずつ。Community、Cloud Free、Cloud Team、Enterprise、そして各違いがどこで強制されるか。 +editions: [community, cloud, enterprise] +translation: + source_sha: 8748d2d07adf16e62ea0be463d91d4d21b0766d025e2450512a9170a9217d24a + guide_rev: 1 + mode: auto +--- + +ObjectOS は 3 つのエディションを持つひとつの製品です。**ObjectOS Community** は自分で実行するオープンソースのランタイムです。**ObjectOS Cloud** は同じ製品をあなたのためにホストしたもので、**Free** と **Team** のプランがあります。**ObjectOS Enterprise** は自社のインフラストラクチャ上で実行するライセンス制の製品で、**Business** と**Business Self-Managed** はその下の契約オプションです。料金と契約は[ライセンスと料金](/docs/editions/license)にあります。このページは、それぞれが何を違う形で行うかを説明します。 + +このドキュメントのすべてのページは、タイトルの下にエディションバッジの行を持ち、適用されるエディションを示します。サイドバーは、すべてのエディション向けではないページとグループに同じアイコンで印を付けます。 + +## 比較表 [#the-matrix] + +| | **Community** | **Cloud Free** | **Cloud Team** | **Enterprise** | +|---|---|---|---|---| +| 提供形態 | セルフマネージド | ホスト型 | ホスト型 | セルフマネージド | +| 料金 | 無料(Apache-2.0) | 無料 | $24 / AI シート / 月、または年払いで $20 / AI シート / 月 | 契約による | +| ファイルストレージ | 自前([ストレージ](/docs/configure/storage)) | 環境ごとに 1 GB | 環境ごとに 20 GB | 自前([ストレージ](/docs/configure/storage)) | +| 環境 | デプロイした数だけ | 組織ごとに 1 つ | 組織ごとに 1 つ | デプロイした数だけ | +| MCP リクエスト | デプロイで設定 | 20 / 分、1,000 / 日 | 120 / 分、1 日の上限なし | デプロイで設定 | +| カスタムドメイン | 自前のホスト | — | ✓ | 自前のホスト | +| レコードレベルおよびフィールドレベルのセキュリティ | ✓ | — | ✓ | ✓ | +| UI 内の AI(AI Builder、「データに質問する」) | MCP のみ:モデルは持ち込み | お試し | ✓ | ✓ | +| AI ガバナンス(アクションの監査、ガードレール、権限のスコープ設定) | — | — | — | ✓ | +| 自社の ID プロバイダーによるシングルサインオン | ✓([認証](/docs/configure/authentication)) | — | — | ✓ | +| SCIM | — | — | — | ✓ | +| クラスタリング / 高可用性 | — | — | — | ✓ | +| ひとつのデプロイ上の複数の組織 | — | — | — | ✓ | +| エアギャップ運用 | — | — | — | ✓ | +| サポート | コミュニティ | コミュニティ | スタンダード | SLA + 専任 | + +ObjectOS Cloud では、シングルサインオンと AI ガバナンスは **Business**、すなわちホスト型サービス上の ObjectOS Enterprise の契約オプションに含まれます。セルフマネージドのデプロイでは、Community と Enterprise は同じランタイムを実行します。Community 列にあるものはすべて Enterprise 列にもあります。 + +## 各違いがどこで強制されるか [#where-each-difference-is-enforced] + +比較表には、製品が強制する違いだけを載せています。以下は、このドキュメントですでに詳しく説明しているものです。 + +- **ライセンスが、セルフマネージドのデプロイが何であるかを決めます。** ライセンスがない場合、単一組織のデプロイは Community の動作で実行されます。オープンな MCP サーバーで、AI は持ち込みです。ライセンスがある場合、AI Builder と「データに質問する」が自社のインフラストラクチャ上で利用可能になります。[AI サービス](/docs/configure/ai)を参照してください。 +- **ひとつのデプロイ上の複数の組織にはライセンスが必要です。** ライセンスなしのマルチ組織の体制は起動時に拒否され、ランタイムはトラフィックを処理しません。[ランタイム設定](/docs/configure/runtime)と[トラブルシューティング](/docs/operate/troubleshooting)を参照してください。 +- **エアギャップ運用はライセンスモードです。** 通常のライセンスはコントロールプレーンに対してオンラインで検証されます。エアギャップライセンスはローカルで検証され、デプロイはコントロールプレーンがないことも宣言しなければなりません。機能し得ない組み合わせは起動時に拒否されます。[エアギャップデプロイ](/docs/deploy/air-gapped)を参照してください。 +- **ObjectOS Cloud では、プランは環境ごとに強制されます。** 組織はどのプランでも 1 つの環境を持ちます。容量が満杯の環境は添付ファイルのアップロードと一括インポートを拒否しますが、単一レコードの書き込み、読み取り、エクスポートは決して拒否しません(`403 STORAGE_LIMIT_REACHED`、80% から警告)。MCP エンドポイントはプランのリクエスト上限を超えると `429` を返します。[環境](/docs/cloud/environments)と[ストレージと上限](/docs/cloud/storage-and-limits)を参照してください。 +- **ライセンスが失効してもランタイムは決して停止しません。** Business Self-Managed は有料機能をオフにし、データとランタイムは動作し続けます。フルの Enterprise デプロイは最後に支払ったバージョンを維持します。[ライセンスと料金](/docs/editions/license#faq)を参照してください。 + +## このページはどのエディション向けか [#which-edition-is-this-page-for] + +| バッジ | 意味 | +|---|---| +| Community | ObjectOS Community を自分で実行する場合に当てはまる | +| Cloud | ObjectOS Cloud の Free および Team プランで当てはまる | +| Enterprise | ライセンスを受けたセルフマネージドの ObjectOS Enterprise デプロイで当てはまる | + +デプロイと運用は、2 つのセルフマネージドのエディション、Community と Enterprise 向けです。ObjectOS Cloud では、私たちがデプロイを運用します。 + +## 次へ [#next] + +- [開始](/docs/start/cloud):3 つの入り口。Cloud、Community、Enterprise。 +- [ライセンスと料金](/docs/editions/license):料金、契約、オープンソースライセンス。 +- [パブリックプレビュー](/docs/editions/public-preview):ObjectOS Cloud の現在の段階が、データと連携にとって何を意味するか。 diff --git a/content/docs/editions/compare.zh-Hans.mdx b/content/docs/editions/compare.zh-Hans.mdx new file mode 100644 index 00000000..83f522d9 --- /dev/null +++ b/content/docs/editions/compare.zh-Hans.mdx @@ -0,0 +1,85 @@ +--- +title: 版本对比 +seoTitle: "ObjectOS 版本对比:Community、Free、Team、Enterprise" +description: 逐行列出每个 ObjectOS 版本和套餐包含什么 —— Community、Cloud Free、Cloud Team 和 Enterprise —— 以及每项差异在哪里强制执行。 +editions: [community, cloud, enterprise] +translation: + source_sha: 8748d2d07adf16e62ea0be463d91d4d21b0766d025e2450512a9170a9217d24a + guide_rev: 1 + mode: auto +--- + +ObjectOS 是一个产品、三个版本。**ObjectOS Community** 是你自己运行的开源 +运行时。**ObjectOS Cloud** 是为你托管的同一个产品,有 **Free** 和 **Team** +两个套餐。**ObjectOS Enterprise** 是你在自己的基础设施上运行的许可产品; +**Business** 和 **Business Self-Managed** 是它之下的合同选项。价格与合同见 +[许可与定价](/docs/editions/license);本页讲的是每一个有什么不同。 + +这份文档中的每一页,标题下方都带有一排版本徽章,标明它适用于哪些版本。 +侧边栏用同样的图标标记那些并非适用于所有版本的页面和分组。 + +## 对照表 [#the-matrix] + +| | **Community** | **Cloud Free** | **Cloud Team** | **Enterprise** | +|---|---|---|---|---| +| 交付方式 | 自管理 | 托管 | 托管 | 自管理 | +| 价格 | 免费(Apache-2.0) | 免费 | 24 美元 / AI 席位 / 月,或按年付费 20 美元 / AI 席位 / 月 | 按合同 | +| 文件存储 | 你自己的([存储](/docs/configure/storage)) | 每个环境 1 GB | 每个环境 20 GB | 你自己的([存储](/docs/configure/storage)) | +| 环境 | 你部署多少就有多少 | 每个组织一个 | 每个组织一个 | 你部署多少就有多少 | +| MCP 请求 | 由你的部署设定 | 每分钟 20 次,每天 1,000 次 | 每分钟 120 次,无每日上限 | 由你的部署设定 | +| 自定义域名 | 你自己的主机 | — | ✓ | 你自己的主机 | +| 记录级和字段级安全 | ✓ | — | ✓ | ✓ | +| UI 内 AI(AI Builder、"问你的数据") | 仅 MCP —— 自带模型 | 体验版 | ✓ | ✓ | +| AI 治理(动作审计、护栏、权限范围限定) | — | — | — | ✓ | +| 与你的身份提供商单点登录 | ✓([身份认证](/docs/configure/authentication)) | — | — | ✓ | +| SCIM | — | — | — | ✓ | +| 集群 / 高可用 | — | — | — | ✓ | +| 单个部署承载多个组织 | — | — | — | ✓ | +| 物理隔离运行 | — | — | — | ✓ | +| 支持 | 社区 | 社区 | 标准 | SLA + 专属 | + +在 ObjectOS Cloud 上,单点登录和 AI 治理随 **Business** 提供,它是 +ObjectOS Enterprise 在托管服务上的一个合同选项。在自管理部署上,Community +和 Enterprise 运行同一个运行时:Community 一列中的一切在 Enterprise 一列中 +也都有。 + +## 每项差异在哪里强制执行 [#where-each-difference-is-enforced] + +对照表只列出产品会强制执行的差异。下面这些是本文档已经详细描述过的: + +- **许可证决定一个自管理部署是什么。** 没有许可证时,单组织部署以 + Community 的行为运行 —— 开放的 MCP 服务器,自带 AI。有了许可证, + AI Builder 和"问你的数据"就会在你自己的基础设施上解锁。参见 + [AI 服务](/docs/configure/ai)。 +- **单个部署承载多个组织需要许可证。** 没有许可证的多组织姿态会在启动时 + 被拒绝,运行时不会提供服务。参见[运行时配置](/docs/configure/runtime) + 和[故障排查](/docs/operate/troubleshooting)。 +- **物理隔离运行是一种许可证模式。** 普通许可证会针对控制平面在线校验; + 物理隔离许可证在本地校验,并且部署还必须声明没有控制平面。无法工作的 + 组合会在启动时被拒绝。参见[物理隔离部署](/docs/deploy/air-gapped)。 +- **在 ObjectOS Cloud 上,套餐按环境强制执行。** 每个组织在每个套餐上 + 都有一个环境;存储已满的环境会拒绝附件上传和批量导入, + 但绝不拒绝单条记录的写入、读取或导出(`403 STORAGE_LIMIT_REACHED`,从 80% + 起发出警告);超过套餐的请求限额后,MCP 端点会返回 `429`。参见 + [环境](/docs/cloud/environments)和 + [存储与限制](/docs/cloud/storage-and-limits)。 +- **许可证过期绝不会让运行时停止。** Business Self-Managed 会关闭它的付费 + 功能,保持你的数据和运行时正常工作;完整的 Enterprise 部署会保留最后 + 一个已付费的版本。参见[许可与定价](/docs/editions/license#faq)。 + +## 这一页适用于哪个版本? [#which-edition-is-this-page-for] + +| 徽章 | 含义 | +|---|---| +| Community | 当你自己运行 ObjectOS Community 时成立 | +| Cloud | 在 ObjectOS Cloud 的 Free 和 Team 套餐上成立 | +| Enterprise | 在获得许可的、自管理的 ObjectOS Enterprise 部署上成立 | + +部署和运维适用于两个自管理版本,Community 和 Enterprise:在 ObjectOS +Cloud 上,部署由我们为你运行。 + +## 下一步 [#next] + +- [开始](/docs/start/cloud) —— 三种入门方式:Cloud、Community 或 Enterprise。 +- [许可与定价](/docs/editions/license) —— 价格、合同和开源许可证。 +- [公开预览](/docs/editions/public-preview) —— ObjectOS Cloud 当前阶段对你的数据和集成意味着什么。 diff --git a/content/docs/editions/compare.zh-Hant.mdx b/content/docs/editions/compare.zh-Hant.mdx new file mode 100644 index 00000000..7ee3bf4b --- /dev/null +++ b/content/docs/editions/compare.zh-Hant.mdx @@ -0,0 +1,86 @@ +--- +# @generated zh-Hant from zh-Hans -- do not edit. Edit the English source, then regenerate: pnpm --filter @objectos/docs gen:zh-hant +title: 版本對比 +seoTitle: "ObjectOS 版本對比:Community、Free、Team、Enterprise" +description: 逐行列出每個 ObjectOS 版本和套餐包含什麼 —— Community、Cloud Free、Cloud Team 和 Enterprise —— 以及每項差異在哪裡強制執行。 +editions: [community, cloud, enterprise] +translation: + source_sha: 8748d2d07adf16e62ea0be463d91d4d21b0766d025e2450512a9170a9217d24a + guide_rev: 1 + mode: auto +--- + +ObjectOS 是一個產品、三個版本。**ObjectOS Community** 是你自己執行的開源 +執行時。**ObjectOS Cloud** 是為你託管的同一個產品,有 **Free** 和 **Team** +兩個套餐。**ObjectOS Enterprise** 是你在自己的基礎設施上執行的許可產品; +**Business** 和 **Business Self-Managed** 是它之下的合同選項。價格與合同見 +[許可與定價](/docs/editions/license);本頁講的是每一個有什麼不同。 + +這份文件中的每一頁,標題下方都帶有一排版本徽章,標明它適用於哪些版本。 +側邊欄用同樣的圖示標記那些並非適用於所有版本的頁面和分組。 + +## 對照表 [#the-matrix] + +| | **Community** | **Cloud Free** | **Cloud Team** | **Enterprise** | +|---|---|---|---|---| +| 交付方式 | 自管理 | 託管 | 託管 | 自管理 | +| 價格 | 免費(Apache-2.0) | 免費 | 24 美元 / AI 席位 / 月,或按年付費 20 美元 / AI 席位 / 月 | 按合同 | +| 檔案儲存 | 你自己的([儲存](/docs/configure/storage)) | 每個環境 1 GB | 每個環境 20 GB | 你自己的([儲存](/docs/configure/storage)) | +| 環境 | 你部署多少就有多少 | 每個組織一個 | 每個組織一個 | 你部署多少就有多少 | +| MCP 請求 | 由你的部署設定 | 每分鐘 20 次,每天 1,000 次 | 每分鐘 120 次,無每日上限 | 由你的部署設定 | +| 自定義域名 | 你自己的主機 | — | ✓ | 你自己的主機 | +| 記錄級和欄位級安全 | ✓ | — | ✓ | ✓ | +| UI 內 AI(AI Builder、"問你的資料") | 僅 MCP —— 自帶模型 | 體驗版 | ✓ | ✓ | +| AI 治理(動作審計、護欄、許可權範圍限定) | — | — | — | ✓ | +| 與你的身份提供商單點登入 | ✓([身份認證](/docs/configure/authentication)) | — | — | ✓ | +| SCIM | — | — | — | ✓ | +| 叢集 / 高可用 | — | — | — | ✓ | +| 單個部署承載多個組織 | — | — | — | ✓ | +| 物理隔離執行 | — | — | — | ✓ | +| 支援 | 社群 | 社群 | 標準 | SLA + 專屬 | + +在 ObjectOS Cloud 上,單點登入和 AI 治理隨 **Business** 提供,它是 +ObjectOS Enterprise 在託管服務上的一個合同選項。在自管理部署上,Community +和 Enterprise 運行同一個執行時:Community 一列中的一切在 Enterprise 一列中 +也都有。 + +## 每項差異在哪裡強制執行 [#where-each-difference-is-enforced] + +對照表只列出產品會強制執行的差異。下面這些是本文件已經詳細描述過的: + +- **許可證決定一個自管理部署是什麼。** 沒有許可證時,單組織部署以 + Community 的行為執行 —— 開放的 MCP 伺服器,自帶 AI。有了許可證, + AI Builder 和"問你的資料"就會在你自己的基礎設施上解鎖。參見 + [AI 服務](/docs/configure/ai)。 +- **單個部署承載多個組織需要許可證。** 沒有許可證的多組織姿態會在啟動時 + 被拒絕,執行時不會提供服務。參見[執行時配置](/docs/configure/runtime) + 和[故障排查](/docs/operate/troubleshooting)。 +- **物理隔離執行是一種許可證模式。** 普通許可證會針對控制平面線上校驗; + 物理隔離許可證在本地校驗,並且部署還必須宣告沒有控制平面。無法工作的 + 組合會在啟動時被拒絕。參見[物理隔離部署](/docs/deploy/air-gapped)。 +- **在 ObjectOS Cloud 上,套餐按環境強制執行。** 每個組織在每個套餐上 + 都有一個環境;儲存已滿的環境會拒絕附件上傳和批次匯入, + 但絕不拒絕單條記錄的寫入、讀取或匯出(`403 STORAGE_LIMIT_REACHED`,從 80% + 起發出警告);超過套餐的請求限額後,MCP 端點會返回 `429`。參見 + [環境](/docs/cloud/environments)和 + [儲存與限制](/docs/cloud/storage-and-limits)。 +- **許可證過期絕不會讓執行時停止。** Business Self-Managed 會關閉它的付費 + 功能,保持你的資料和執行時正常工作;完整的 Enterprise 部署會保留最後 + 一個已付費的版本。參見[許可與定價](/docs/editions/license#faq)。 + +## 這一頁適用於哪個版本? [#which-edition-is-this-page-for] + +| 徽章 | 含義 | +|---|---| +| Community | 當你自己執行 ObjectOS Community 時成立 | +| Cloud | 在 ObjectOS Cloud 的 Free 和 Team 套餐上成立 | +| Enterprise | 在獲得許可的、自管理的 ObjectOS Enterprise 部署上成立 | + +部署和運維適用於兩個自管理版本,Community 和 Enterprise:在 ObjectOS +Cloud 上,部署由我們為你執行。 + +## 下一步 [#next] + +- [開始](/docs/start/cloud) —— 三種入門方式:Cloud、Community 或 Enterprise。 +- [許可與定價](/docs/editions/license) —— 價格、合同和開源許可證。 +- [公開預覽](/docs/editions/public-preview) —— ObjectOS Cloud 當前階段對你的資料和整合意味著什麼。 From c836d5992a9334f838a1095f4384a899f738982b Mon Sep 17 00:00:00 2001 From: Steedos Date: Tue, 3 Nov 2026 09:33:43 +0000 Subject: [PATCH 21/22] docs(i18n): follow #431 plan B in zh-Hans, zh-Hant and ja; translate editions/license fresh Re-sync cloud/plans-and-seats and editions/compare to #431's English, and translate editions/license, whose siblings #431 deleted, from the current English, reusing wording only where the English sentence is unchanged. Re-sync configure/mcp, deploy/index, index and start/enterprise. zh-Hant regenerated. Fixes #429 Claude-Session: https://claude.ai/code/session_01QsR2jRsjbApbf83iyTDDXm Co-Authored-By: Claude --- content/docs/cloud/plans-and-seats.ja.mdx | 14 +- .../docs/cloud/plans-and-seats.zh-Hans.mdx | 24 ++- .../docs/cloud/plans-and-seats.zh-Hant.mdx | 24 ++- content/docs/configure/mcp.ja.mdx | 6 +- content/docs/configure/mcp.zh-Hans.mdx | 6 +- content/docs/configure/mcp.zh-Hant.mdx | 6 +- content/docs/deploy/index.ja.mdx | 4 +- content/docs/deploy/index.zh-Hans.mdx | 6 +- content/docs/deploy/index.zh-Hant.mdx | 6 +- content/docs/editions/compare.ja.mdx | 12 +- content/docs/editions/compare.zh-Hans.mdx | 19 +- content/docs/editions/compare.zh-Hant.mdx | 19 +- content/docs/editions/license.ja.mdx | 118 +++++++++++ content/docs/editions/license.zh-Hans.mdx | 190 +++++++++++++++++ content/docs/editions/license.zh-Hant.mdx | 191 ++++++++++++++++++ content/docs/index.ja.mdx | 4 +- content/docs/index.zh-Hans.mdx | 4 +- content/docs/index.zh-Hant.mdx | 4 +- content/docs/start/enterprise.ja.mdx | 4 +- content/docs/start/enterprise.zh-Hans.mdx | 4 +- content/docs/start/enterprise.zh-Hant.mdx | 4 +- 21 files changed, 595 insertions(+), 74 deletions(-) create mode 100644 content/docs/editions/license.ja.mdx create mode 100644 content/docs/editions/license.zh-Hans.mdx create mode 100644 content/docs/editions/license.zh-Hant.mdx diff --git a/content/docs/cloud/plans-and-seats.ja.mdx b/content/docs/cloud/plans-and-seats.ja.mdx index 3e1a5e14..585955e3 100644 --- a/content/docs/cloud/plans-and-seats.ja.mdx +++ b/content/docs/cloud/plans-and-seats.ja.mdx @@ -4,12 +4,12 @@ seoTitle: "ObjectOS Cloud のプラン:Free、Team、Enterprise と AI シー description: ObjectOS Cloud のプラン(Free、Team、Enterprise)、唯一の有料シートである AI シート、アップグレード、解約、シート数の変更の方法、請求元、そしてプランに含まれないものをコンソールのどこで確認できるか。 editions: [cloud] translation: - source_sha: 967b649fe678efe9da252655dcecac2adcce15578ade9a9b1cf60d088d29808d + source_sha: 5ea86b45cfd4491869e8c51ca411f09908bbba788aaa6630e053d96777651469 guide_rev: 1 mode: auto --- -ObjectOS Cloud には 3 つのプランがあります。プランは**組織**に属し、その環境に適用されます。料金がかかるのは **AI シート**だけで、組織のそれ以外の全員は無料でアプリを使い、閲覧できます。 +ObjectOS Cloud には、コンソールで選ぶ **Free** と **Team** の 2 つのプランと、契約による **Enterprise** があります。プランは**組織**に属し、その環境に適用されます。料金がかかるのは **AI シート**だけで、組織のそれ以外の全員は無料でアプリを使い、閲覧できます。メンバー、レコード、オブジェクトの数に上限を設けるプランはありません。 | | **Free** | **Team** | **Enterprise** | |---|---|---|---| @@ -20,7 +20,9 @@ ObjectOS Cloud には 3 つのプランがあります。プランは**組織** | [AI エージェントのアクセス(MCP)](/docs/configure/mcp#on-objectos-cloud) | 1 分あたり 20 リクエスト、1 日 1,000 | 1 分あたり 120 リクエスト、1 日の上限なし | 1 分あたり 120 リクエスト、1 日の上限なし | | ブランド付きのプラットフォームのサブドメイン | ✓ | ✓ | ✓ | | [独自のドメイン](/docs/cloud/domains) | — | 本番環境ごとに 1 つ | ✓ | -| 承認ワークフロー | — | — | ✓ | +| [承認ワークフロー](/docs/build/automation/approvals) | — | ✓ | ✓ | +| [スケジュールと相対時間のフロー](/docs/build/automation/flows) | — | ✓ | ✓ | +| [レコードレベルおよびフィールドレベルのセキュリティ](/docs/configure/permissions) | ✓ | ✓ | ✓ | | サインイン | ObjectOS Cloud のサインイン | ObjectOS Cloud のサインイン | ObjectOS Cloud のサインイン。契約により、自社のアイデンティティプロバイダーによるシングルサインオン | | サポート | コミュニティ | 標準 | 優先 | @@ -57,7 +59,7 @@ Enterprise は営業担当者が支援します。**Billing** の Enterprise の サブスクリプションの期間中、**Home** の **Plan and usage** カードには、オーナーと管理者に向けて **Next charge:** とその日付が表示されます。解約後は **Cancels at period end:** と、プランが終了する日が表示されます。 -**Manage subscription** が表示されるのは Team プランで、オーナーと管理者に対して、オンライン決済が利用できるようになってからです。請求書払いのプランには管理するオンラインのサブスクリプションがありません。Business と Enterprise にはこのボタンが表示されず、請求書払いの Team プランではサブスクリプションがないという応答が返ります。こうしたプランの変更や解約は [sales@objectos.ai](mailto:sales@objectos.ai) にご連絡ください。 +**Manage subscription** が表示されるのは Team プランで、オーナーと管理者に対して、オンライン決済が利用できるようになってからです。請求書払いのプランには管理するオンラインのサブスクリプションがありません。Enterprise にはこのボタンが表示されず、請求書払いの Team プランではサブスクリプションがないという応答が返ります。こうしたプランの変更や解約は [sales@objectos.ai](mailto:sales@objectos.ai) にご連絡ください。 ## AI シートを変更する [#change-ai-seats] @@ -84,9 +86,9 @@ Enterprise は営業担当者が支援します。**Billing** の Enterprise の - Free のストレージの割り当てを超えた環境は、すべてのバイトを保持し、読み取りとエクスポートができる状態のまま、アップロードとインポートを受け付けなくなります([ストレージと上限](/docs/cloud/storage-and-limits))。 - 独自のドメインは解放されずに一時停止され、後でアップグレードすると自動的に戻ります([ドメイン](/docs/cloud/domains#downgrade-and-upgrade))。 -## Business [#business] +## Enterprise [#enterprise] -**Business** は、ホスト型サービスにおける ObjectOS Enterprise の契約オプションで、**Billing** からではなく[営業](/docs/editions/license)が販売します。ObjectOS Cloud では、承認ワークフローを追加します。料金と契約がカバーする内容は[ライセンスと料金](/docs/editions/license)にあります。 +**Enterprise** は **Billing** からではなく契約で販売されます。ホスト型サービス上で、自社のアイデンティティプロバイダーによるシングルサインオン、AI ガバナンス、上限のないストレージ、優先サポートを提供します。カバーする内容とセルフマネージドのオプションは[ライセンスと料金](/docs/editions/license)にあります。ObjectOS Cloud に Business プランはありません。 ## 次へ [#next] diff --git a/content/docs/cloud/plans-and-seats.zh-Hans.mdx b/content/docs/cloud/plans-and-seats.zh-Hans.mdx index f6cc3224..ed73ddfa 100644 --- a/content/docs/cloud/plans-and-seats.zh-Hans.mdx +++ b/content/docs/cloud/plans-and-seats.zh-Hans.mdx @@ -4,13 +4,15 @@ seoTitle: "ObjectOS Cloud 套餐:Free、Team、Enterprise 与 AI 席位" description: ObjectOS Cloud 的套餐 —— Free、Team 和 Enterprise —— AI 席位是唯一付费的席位、如何升级、取消或更改席位、由谁向你收费,以及控制台在哪里显示你的套餐不包含什么。 editions: [cloud] translation: - source_sha: 967b649fe678efe9da252655dcecac2adcce15578ade9a9b1cf60d088d29808d + source_sha: 5ea86b45cfd4491869e8c51ca411f09908bbba788aaa6630e053d96777651469 guide_rev: 1 mode: auto --- -ObjectOS Cloud 有三个套餐。套餐属于**组织**,适用于它的环境。只有 -**AI 席位**需要付费:组织中的其他人都可以免费使用和查看应用。 +ObjectOS Cloud 有两个在控制台中选择的套餐,**Free** 和 **Team**,以及按合同 +提供的 **Enterprise**。套餐属于**组织**,适用于它的环境。只有 **AI 席位** +需要付费:组织中的其他人都可以免费使用和查看应用,而且没有任何套餐限制成员、 +记录或对象的数量。 | | **Free** | **Team** | **Enterprise** | |---|---|---|---| @@ -21,7 +23,9 @@ ObjectOS Cloud 有三个套餐。套餐属于**组织**,适用于它的环境 | [AI Agent 访问(MCP)](/docs/configure/mcp#on-objectos-cloud) | 每分钟 20 次请求,每天 1,000 次 | 每分钟 120 次请求,无每日上限 | 每分钟 120 次请求,无每日上限 | | 品牌平台子域名 | ✓ | ✓ | ✓ | | [你自己的域名](/docs/cloud/domains) | — | 每个生产环境一个 | ✓ | -| 审批工作流 | — | — | ✓ | +| [审批工作流](/docs/build/automation/approvals) | — | ✓ | ✓ | +| [定时和相对时间流程](/docs/build/automation/flows) | — | ✓ | ✓ | +| [记录级和字段级安全](/docs/configure/permissions) | ✓ | ✓ | ✓ | | 登录 | ObjectOS Cloud 登录 | ObjectOS Cloud 登录 | ObjectOS Cloud 登录;按合同提供与你的身份提供商的单点登录 | | 支持 | 社区 | 标准 | 优先 | @@ -70,7 +74,7 @@ Enterprise 由销售协助:在 **Billing** 的 Enterprise 一列点击 **Conta 订阅期间,**Home** 上的 **Plan and usage** 卡片会向所有者和管理员显示 **Next charge:** 及其日期;取消之后,它显示 **Cancels at period end:** 以及套餐结束的日期。 -**Manage subscription** 只在 Team 套餐上、在在线支付开放后提供给所有者和管理员。按发票计费的套餐没有可管理的在线订阅:Business 和 Enterprise 从不显示该按钮,按发票计费的 Team 套餐会答复它没有在线订阅。此类套餐的更改或取消请通过 [sales@objectos.ai](mailto:sales@objectos.ai) 联系我们。 +**Manage subscription** 只在 Team 套餐上、在在线支付开放后提供给所有者和管理员。按发票计费的套餐没有可管理的在线订阅:Enterprise 从不显示该按钮,按发票计费的 Team 套餐会答复它没有在线订阅。此类套餐的更改或取消请通过 [sales@objectos.ai](mailto:sales@objectos.ai) 联系我们。 ## 更改 AI 席位 [#change-ai-seats] @@ -107,12 +111,12 @@ Enterprise 由销售协助:在 **Billing** 的 Enterprise 一列点击 **Conta - 你自己的域名会被暂停而不是释放,并会在之后升级时自动恢复 ([域名](/docs/cloud/domains#downgrade-and-upgrade))。 -## Business [#business] +## Enterprise [#enterprise] -**Business** 是 ObjectOS Enterprise 在托管服务上的一个合同选项,由 -[销售](/docs/editions/license)而不是 **Billing** 售卖。在 ObjectOS Cloud -上,它增加了审批工作流。它的价格以及 -合同涵盖的内容见[许可与定价](/docs/editions/license)。 +**Enterprise** 按合同售卖,而不是通过 **Billing**:在托管服务上提供与你的 +身份提供商的单点登录、AI 治理、不设上限的存储和优先支持。它涵盖的内容以及 +自管理的选项见[许可与定价](/docs/editions/license)。ObjectOS Cloud 上没有 +Business 套餐。 ## 下一步 [#next] diff --git a/content/docs/cloud/plans-and-seats.zh-Hant.mdx b/content/docs/cloud/plans-and-seats.zh-Hant.mdx index 8ac30319..db45b431 100644 --- a/content/docs/cloud/plans-and-seats.zh-Hant.mdx +++ b/content/docs/cloud/plans-and-seats.zh-Hant.mdx @@ -5,13 +5,15 @@ seoTitle: "ObjectOS Cloud 套餐:Free、Team、Enterprise 與 AI 席位" description: ObjectOS Cloud 的套餐 —— Free、Team 和 Enterprise —— AI 席位是唯一付費的席位、如何升級、取消或更改席位、由誰向你收費,以及控制台在哪裡顯示你的套餐不包含什麼。 editions: [cloud] translation: - source_sha: 967b649fe678efe9da252655dcecac2adcce15578ade9a9b1cf60d088d29808d + source_sha: 5ea86b45cfd4491869e8c51ca411f09908bbba788aaa6630e053d96777651469 guide_rev: 1 mode: auto --- -ObjectOS Cloud 有三個套餐。套餐屬於**組織**,適用於它的環境。只有 -**AI 席位**需要付費:組織中的其他人都可以免費使用和檢視應用。 +ObjectOS Cloud 有兩個在控制台中選擇的套餐,**Free** 和 **Team**,以及按合同 +提供的 **Enterprise**。套餐屬於**組織**,適用於它的環境。只有 **AI 席位** +需要付費:組織中的其他人都可以免費使用和檢視應用,而且沒有任何套餐限制成員、 +記錄或物件的數量。 | | **Free** | **Team** | **Enterprise** | |---|---|---|---| @@ -22,7 +24,9 @@ ObjectOS Cloud 有三個套餐。套餐屬於**組織**,適用於它的環境 | [AI Agent 訪問(MCP)](/docs/configure/mcp#on-objectos-cloud) | 每分鐘 20 次請求,每天 1,000 次 | 每分鐘 120 次請求,無每日上限 | 每分鐘 120 次請求,無每日上限 | | 品牌平臺子域名 | ✓ | ✓ | ✓ | | [你自己的域名](/docs/cloud/domains) | — | 每個生產環境一個 | ✓ | -| 審批工作流 | — | — | ✓ | +| [審批工作流](/docs/build/automation/approvals) | — | ✓ | ✓ | +| [定時和相對時間流程](/docs/build/automation/flows) | — | ✓ | ✓ | +| [記錄級和欄位級安全](/docs/configure/permissions) | ✓ | ✓ | ✓ | | 登入 | ObjectOS Cloud 登入 | ObjectOS Cloud 登入 | ObjectOS Cloud 登入;按合同提供與你的身份提供商的單點登入 | | 支援 | 社群 | 標準 | 優先 | @@ -71,7 +75,7 @@ Enterprise 由銷售協助:在 **Billing** 的 Enterprise 一列點選 **Conta 訂閱期間,**Home** 上的 **Plan and usage** 卡片會向所有者和管理員顯示 **Next charge:** 及其日期;取消之後,它顯示 **Cancels at period end:** 以及套餐結束的日期。 -**Manage subscription** 只在 Team 套餐上、在線上支付開放後提供給所有者和管理員。按發票計費的套餐沒有可管理的線上訂閱:Business 和 Enterprise 從不顯示該按鈕,按發票計費的 Team 套餐會答覆它沒有線上訂閱。此類套餐的更改或取消請通過 [sales@objectos.ai](mailto:sales@objectos.ai) 聯絡我們。 +**Manage subscription** 只在 Team 套餐上、在線上支付開放後提供給所有者和管理員。按發票計費的套餐沒有可管理的線上訂閱:Enterprise 從不顯示該按鈕,按發票計費的 Team 套餐會答覆它沒有線上訂閱。此類套餐的更改或取消請通過 [sales@objectos.ai](mailto:sales@objectos.ai) 聯絡我們。 ## 更改 AI 席位 [#change-ai-seats] @@ -108,12 +112,12 @@ Enterprise 由銷售協助:在 **Billing** 的 Enterprise 一列點選 **Conta - 你自己的域名會被暫停而不是釋放,並會在之後升級時自動恢復 ([域名](/docs/cloud/domains#downgrade-and-upgrade))。 -## Business [#business] +## Enterprise [#enterprise] -**Business** 是 ObjectOS Enterprise 在託管服務上的一個合同選項,由 -[銷售](/docs/editions/license)而不是 **Billing** 售賣。在 ObjectOS Cloud -上,它增加了審批工作流。它的價格以及 -合同涵蓋的內容見[許可與定價](/docs/editions/license)。 +**Enterprise** 按合同售賣,而不是通過 **Billing**:在託管服務上提供與你的 +身份提供商的單點登入、AI 治理、不設上限的儲存和優先支援。它涵蓋的內容以及 +自管理的選項見[許可與定價](/docs/editions/license)。ObjectOS Cloud 上沒有 +Business 套餐。 ## 下一步 [#next] diff --git a/content/docs/configure/mcp.ja.mdx b/content/docs/configure/mcp.ja.mdx index 34196ed3..9c429d6c 100644 --- a/content/docs/configure/mcp.ja.mdx +++ b/content/docs/configure/mcp.ja.mdx @@ -3,7 +3,7 @@ title: AI ツールを接続する(MCP) description: Claude Code、Claude Desktop、または任意の MCP クライアントを ObjectOS アプリに向け、エージェントにあなたの権限モデルのもとでデータを扱わせます。 editions: [community, cloud, enterprise] translation: - source_sha: 284d38d7199dbc99e3df09c43ffc520333a1fff28e22d0681d8b885d554bf1e0 + source_sha: 0bec90d540bb424e11d1cedf6c0532227a9ce328717d2448f1c7fdc8b8291017 guide_rev: 1 mode: auto --- @@ -177,9 +177,9 @@ What objects does this app have, and what fields does the main one carry? 読み取りと `verify_build` は書き込みとして数えられません。どちらかの上限を超えると、ツールの呼び出しは `RATE_LIMIT_EXCEEDED`、その数、そして何でリセットされるかとともに拒否されます。書き込みは UTC の翌日に、ドラフトは公開または破棄でリセットされます。 -> **フローが拒否されるのはなぜ?** エージェントがここでは構築できないものを使っており、拒否の理由がそれを示します。Free でのスケジュールまたは相対時間のフロー、承認ワークフローがプランに含まれていない場合の承認ステップ、またはソースで構築して[パッケージ](/docs/build/packages)として公開する種類です。 +> **フローが拒否されるのはなぜ?** エージェントがここでは構築できないものを使っており、拒否の理由がそれを示します。Free でのスケジュールまたは相対時間のフロー、Free での承認ステップ、またはソースで構築して[パッケージ](/docs/build/packages)として公開する種類です。 -エージェントが構築するのは、レコードの変更またはボタンで開始するフローで、レコードの作成、更新、削除、割り当て、判断、ループ、待機のステップから構成されます。スケジュールと相対時間のフローは Team 以上で、承認ステップはプランに[承認ワークフロー](/docs/cloud/plans-and-seats)が含まれている場合に構築できます。スクリプト、Webhook、API で起動するフローと画面フロー、そしてスクリプト、Webhook、API、ジョブ、メールテンプレート、翻訳、テーマ、プラグイン、エージェント、スキル、データソースの種類は、どのプランでもソースで構築します。 +エージェントが構築するのは、レコードの変更またはボタンで開始するフローで、レコードの作成、更新、削除、割り当て、判断、ループ、待機のステップから構成されます。スケジュールと相対時間のフローは Team 以上で、承認ステップも Team 以上で構築できます([プラン](/docs/cloud/plans-and-seats))。スクリプト、Webhook、API で起動するフローと画面フロー、そしてスクリプト、Webhook、API、ジョブ、メールテンプレート、翻訳、テーマ、プラグイン、エージェント、スキル、データソースの種類は、どのプランでもソースで構築します。 ### 上限 [#limits] diff --git a/content/docs/configure/mcp.zh-Hans.mdx b/content/docs/configure/mcp.zh-Hans.mdx index fd282adb..84f3ff56 100644 --- a/content/docs/configure/mcp.zh-Hans.mdx +++ b/content/docs/configure/mcp.zh-Hans.mdx @@ -3,7 +3,7 @@ title: 接入 AI 工具(MCP) description: 把 Claude Code、Claude Desktop 或任意 MCP 客户端指向你的 ObjectOS 应用,让 Agent 在你的权限模型约束下处理你的数据。 editions: [community, cloud, enterprise] translation: - source_sha: 284d38d7199dbc99e3df09c43ffc520333a1fff28e22d0681d8b885d554bf1e0 + source_sha: 0bec90d540bb424e11d1cedf6c0532227a9ce328717d2448f1c7fdc8b8291017 guide_rev: 1 mode: auto --- @@ -177,9 +177,9 @@ Agent 还可以**构建应用**:创建和修改它的对象、字段、视图 读取和 `verify_build` 不计为写入。超过任一上限后,工具调用会以 `RATE_LIMIT_EXCEEDED` 被拒绝,并附上计数和重置条件:写入在下一个 UTC 日重置,草稿在发布或丢弃后重置。 -> **为什么我的流程被拒绝?**它用到了 Agent 在这里无法构建的东西,拒绝信息会指出是哪一项:Free 上的定时或相对时间流程、套餐不包含审批工作流时的审批步骤,或者一种需在源码中构建并作为[包](/docs/build/packages)发布的类型。 +> **为什么我的流程被拒绝?**它用到了 Agent 在这里无法构建的东西,拒绝信息会指出是哪一项:Free 上的定时或相对时间流程、Free 上的审批步骤,或者一种需在源码中构建并作为[包](/docs/build/packages)发布的类型。 -Agent 可以构建由记录变更或按钮启动的流程,使用创建、更新和删除记录、赋值、判断、循环和等待步骤。定时和相对时间流程在 Team 及以上可以构建,审批步骤则在套餐包含[审批工作流](/docs/cloud/plans-and-seats)时可以构建。脚本、Webhook、API 触发的流程和屏幕流程,以及 script、webhook、API、job、邮件模板、翻译、主题、插件、agent、skill 和数据源这些类型,在任何套餐上都在源码中构建。 +Agent 可以构建由记录变更或按钮启动的流程,使用创建、更新和删除记录、赋值、判断、循环和等待步骤。定时和相对时间流程在 Team 及以上可以构建,审批步骤也在 Team 及以上可以构建([套餐](/docs/cloud/plans-and-seats))。脚本、Webhook、API 触发的流程和屏幕流程,以及 script、webhook、API、job、邮件模板、翻译、主题、插件、agent、skill 和数据源这些类型,在任何套餐上都在源码中构建。 ### 上限 [#limits] diff --git a/content/docs/configure/mcp.zh-Hant.mdx b/content/docs/configure/mcp.zh-Hant.mdx index b9c322e4..dc29d413 100644 --- a/content/docs/configure/mcp.zh-Hant.mdx +++ b/content/docs/configure/mcp.zh-Hant.mdx @@ -4,7 +4,7 @@ title: 接入 AI 工具(MCP) description: 把 Claude Code、Claude Desktop 或任意 MCP 客戶端指向你的 ObjectOS 應用,讓 Agent 在你的許可權模型約束下處理你的資料。 editions: [community, cloud, enterprise] translation: - source_sha: 284d38d7199dbc99e3df09c43ffc520333a1fff28e22d0681d8b885d554bf1e0 + source_sha: 0bec90d540bb424e11d1cedf6c0532227a9ce328717d2448f1c7fdc8b8291017 guide_rev: 1 mode: auto --- @@ -178,9 +178,9 @@ Agent 還可以**構建應用**:建立和修改它的物件、欄位、檢視 讀取和 `verify_build` 不計為寫入。超過任一上限後,工具呼叫會以 `RATE_LIMIT_EXCEEDED` 被拒絕,並附上計數和重置條件:寫入在下一個 UTC 日重置,草稿在釋出或丟棄後重置。 -> **為什麼我的流程被拒絕?**它用到了 Agent 在這裡無法構建的東西,拒絕資訊會指出是哪一項:Free 上的定時或相對時間流程、套餐不包含審批工作流時的審批步驟,或者一種需在原始碼中構建並作為[包](/docs/build/packages)釋出的型別。 +> **為什麼我的流程被拒絕?**它用到了 Agent 在這裡無法構建的東西,拒絕資訊會指出是哪一項:Free 上的定時或相對時間流程、Free 上的審批步驟,或者一種需在原始碼中構建並作為[包](/docs/build/packages)釋出的型別。 -Agent 可以構建由記錄變更或按鈕啟動的流程,使用建立、更新和刪除記錄、賦值、判斷、迴圈和等待步驟。定時和相對時間流程在 Team 及以上可以構建,審批步驟則在套餐包含[審批工作流](/docs/cloud/plans-and-seats)時可以構建。指令碼、Webhook、API 觸發的流程和螢幕流程,以及 script、webhook、API、job、郵件模板、翻譯、主題、外掛、agent、skill 和資料來源這些型別,在任何套餐上都在原始碼中構建。 +Agent 可以構建由記錄變更或按鈕啟動的流程,使用建立、更新和刪除記錄、賦值、判斷、迴圈和等待步驟。定時和相對時間流程在 Team 及以上可以構建,審批步驟也在 Team 及以上可以構建([套餐](/docs/cloud/plans-and-seats))。指令碼、Webhook、API 觸發的流程和螢幕流程,以及 script、webhook、API、job、郵件模板、翻譯、主題、外掛、agent、skill 和資料來源這些型別,在任何套餐上都在原始碼中構建。 ### 上限 [#limits] diff --git a/content/docs/deploy/index.ja.mdx b/content/docs/deploy/index.ja.mdx index aad5c9d8..ca419ff2 100644 --- a/content/docs/deploy/index.ja.mdx +++ b/content/docs/deploy/index.ja.mdx @@ -4,12 +4,12 @@ seoTitle: "デプロイ:セルフマネージドの ObjectOS、Community と E description: 自社のインフラストラクチャで ObjectOS を実行します。オープンな Community イメージとライセンスされた Enterprise イメージ、ひとつのランタイム、ひとつの設定の契約、そしてライセンスが追加するものを説明します。 editions: [community, enterprise] translation: - source_sha: 8e3a6c8cf20d9cbca8dbf4e4162996b6398eecf09e17b90912fd9914ec86e3f6 + source_sha: 58a24b6ac97029ee1e3b5771fb6126075b96fe0c022bea1b5147e4066862462b guide_rev: 1 mode: auto --- -ObjectOS にはセルフマネージドのエディションが 2 つあり、デプロイ方法は同じです。**ObjectOS Community** はオープンソースのランタイムイメージで、**ObjectOS Enterprise** はライセンスされたイメージです。後者は、シングルノードの Business Self-Managed としても、完全な Enterprise デプロイメントとしても実行できます。どちらも同じランタイムを実行し、同じ設定(データベース、認証シークレット、シークレットキー)を読み込みます。違いは、イメージの入手元、アプリの組み込み方、ライセンスで有効になるものです。このセクションの各ページは両方を対象に一度だけ書かれており、ライセンスされたイメージがより多くを行う箇所では、最後に **Enterprise で追加されるもの** のセクションがあります。 +ObjectOS にはセルフマネージドのエディションが 2 つあり、デプロイ方法は同じです。**ObjectOS Community** はオープンソースのランタイムイメージで、**ObjectOS Enterprise** はライセンスされたイメージです。後者は、シングルノードの Enterprise Single-Node としても、完全な Enterprise デプロイメントとしても実行できます。どちらも同じランタイムを実行し、同じ設定(データベース、認証シークレット、シークレットキー)を読み込みます。違いは、イメージの入手元、アプリの組み込み方、ライセンスで有効になるものです。このセクションの各ページは両方を対象に一度だけ書かれており、ライセンスされたイメージがより多くを行う箇所では、最後に **Enterprise で追加されるもの** のセクションがあります。 ## 2 つのイメージ [#the-two-images] diff --git a/content/docs/deploy/index.zh-Hans.mdx b/content/docs/deploy/index.zh-Hans.mdx index a1faac65..c7d6ae24 100644 --- a/content/docs/deploy/index.zh-Hans.mdx +++ b/content/docs/deploy/index.zh-Hans.mdx @@ -4,14 +4,14 @@ seoTitle: "部署:自管理 ObjectOS,社区版和企业版" description: 在你自己的基础设施上运行 ObjectOS —— 开放的社区版镜像或需许可证的企业版镜像,同一个运行时、同一份配置契约,以及许可证额外带来什么。 editions: [community, enterprise] translation: - source_sha: 8e3a6c8cf20d9cbca8dbf4e4162996b6398eecf09e17b90912fd9914ec86e3f6 + source_sha: 58a24b6ac97029ee1e3b5771fb6126075b96fe0c022bea1b5147e4066862462b guide_rev: 1 mode: auto --- ObjectOS 有两个自管理版本,它们的部署方式相同。**ObjectOS Community** 是开源 -的运行时镜像;**ObjectOS Enterprise** 是需许可证的镜像,可以作为 Business -Self-Managed 运行在单节点上,也可以作为完整的企业版部署。两者运行同一个运行时, +的运行时镜像;**ObjectOS Enterprise** 是需许可证的镜像,可以作为 Enterprise +Single-Node 运行在单节点上,也可以作为完整的企业版部署。两者运行同一个运行时, 读取同一份配置:一个数据库、一个认证密钥和一个加密密钥。不同之处在于镜像从哪里 来、应用如何进入,以及许可证解锁什么。本节的每一页都同时为两者编写一次,并以 **企业版额外提供**一节结尾,说明需许可证的镜像能多做什么。 diff --git a/content/docs/deploy/index.zh-Hant.mdx b/content/docs/deploy/index.zh-Hant.mdx index 960c5f55..2c441bef 100644 --- a/content/docs/deploy/index.zh-Hant.mdx +++ b/content/docs/deploy/index.zh-Hant.mdx @@ -5,14 +5,14 @@ seoTitle: "部署:自管理 ObjectOS,社群版和企業版" description: 在你自己的基礎設施上執行 ObjectOS —— 開放的社群版映象或需許可證的企業版映象,同一個執行時、同一份配置契約,以及許可證額外帶來什麼。 editions: [community, enterprise] translation: - source_sha: 8e3a6c8cf20d9cbca8dbf4e4162996b6398eecf09e17b90912fd9914ec86e3f6 + source_sha: 58a24b6ac97029ee1e3b5771fb6126075b96fe0c022bea1b5147e4066862462b guide_rev: 1 mode: auto --- ObjectOS 有兩個自管理版本,它們的部署方式相同。**ObjectOS Community** 是開源 -的執行時映象;**ObjectOS Enterprise** 是需許可證的映象,可以作為 Business -Self-Managed 執行在單節點上,也可以作為完整的企業版部署。兩者運行同一個執行時, +的執行時映象;**ObjectOS Enterprise** 是需許可證的映象,可以作為 Enterprise +Single-Node 執行在單節點上,也可以作為完整的企業版部署。兩者運行同一個執行時, 讀取同一份配置:一個數據庫、一個認證金鑰和一個加密金鑰。不同之處在於映象從哪裡 來、應用如何進入,以及許可證解鎖什麼。本節的每一頁都同時為兩者編寫一次,並以 **企業版額外提供**一節結尾,說明需許可證的映象能多做什麼。 diff --git a/content/docs/editions/compare.ja.mdx b/content/docs/editions/compare.ja.mdx index 334d8cc1..dcd80477 100644 --- a/content/docs/editions/compare.ja.mdx +++ b/content/docs/editions/compare.ja.mdx @@ -4,12 +4,12 @@ seoTitle: "ObjectOS エディションの比較:Community、Free、Team、Ente description: ObjectOS の各エディションとプランに含まれるものを 1 行ずつ。Community、Cloud Free、Cloud Team、Enterprise、そして各違いがどこで強制されるか。 editions: [community, cloud, enterprise] translation: - source_sha: 8748d2d07adf16e62ea0be463d91d4d21b0766d025e2450512a9170a9217d24a + source_sha: c6448701566dbd6b54b9f0a7ffde7c6822406e18cdb07be8ee88a50d77588ee8 guide_rev: 1 mode: auto --- -ObjectOS は 3 つのエディションを持つひとつの製品です。**ObjectOS Community** は自分で実行するオープンソースのランタイムです。**ObjectOS Cloud** は同じ製品をあなたのためにホストしたもので、**Free** と **Team** のプランがあります。**ObjectOS Enterprise** は自社のインフラストラクチャ上で実行するライセンス制の製品で、**Business** と**Business Self-Managed** はその下の契約オプションです。料金と契約は[ライセンスと料金](/docs/editions/license)にあります。このページは、それぞれが何を違う形で行うかを説明します。 +ObjectOS は 3 つのエディションを持つひとつの製品です。**ObjectOS Community** は自分で実行するオープンソースのランタイムです。**ObjectOS Cloud** は同じ製品をあなたのためにホストしたもので、**Free** と **Team** のプランがあります。**ObjectOS Enterprise** は契約で販売されるライセンス制の製品で、ホスト型サービス上、シングルノードの **Enterprise Single-Node** ライセンス、またはフルのプライベートデプロイとして提供されます。ObjectOS Cloud に Business プランはありません。料金と契約は[ライセンスと料金](/docs/editions/license)にあります。このページは、それぞれが何を違う形で行うかを説明します。 このドキュメントのすべてのページは、タイトルの下にエディションバッジの行を持ち、適用されるエディションを示します。サイドバーは、すべてのエディション向けではないページとグループに同じアイコンで印を付けます。 @@ -23,7 +23,9 @@ ObjectOS は 3 つのエディションを持つひとつの製品です。**Obj | 環境 | デプロイした数だけ | 組織ごとに 1 つ | 組織ごとに 1 つ | デプロイした数だけ | | MCP リクエスト | デプロイで設定 | 20 / 分、1,000 / 日 | 120 / 分、1 日の上限なし | デプロイで設定 | | カスタムドメイン | 自前のホスト | — | ✓ | 自前のホスト | -| レコードレベルおよびフィールドレベルのセキュリティ | ✓ | — | ✓ | ✓ | +| レコードレベルおよびフィールドレベルのセキュリティ | ✓ | ✓ | ✓ | ✓ | +| 承認ワークフロー | ✓ | — | ✓ | ✓ | +| スケジュールと相対時間のフロー | ✓ | — | ✓ | ✓ | | UI 内の AI(AI Builder、「データに質問する」) | MCP のみ:モデルは持ち込み | お試し | ✓ | ✓ | | AI ガバナンス(アクションの監査、ガードレール、権限のスコープ設定) | — | — | — | ✓ | | 自社の ID プロバイダーによるシングルサインオン | ✓([認証](/docs/configure/authentication)) | — | — | ✓ | @@ -33,7 +35,7 @@ ObjectOS は 3 つのエディションを持つひとつの製品です。**Obj | エアギャップ運用 | — | — | — | ✓ | | サポート | コミュニティ | コミュニティ | スタンダード | SLA + 専任 | -ObjectOS Cloud では、シングルサインオンと AI ガバナンスは **Business**、すなわちホスト型サービス上の ObjectOS Enterprise の契約オプションに含まれます。セルフマネージドのデプロイでは、Community と Enterprise は同じランタイムを実行します。Community 列にあるものはすべて Enterprise 列にもあります。 +ObjectOS Cloud では、自社のアイデンティティプロバイダーによるシングルサインオンと AI ガバナンスは、ホスト型サービス上の **Enterprise** 契約に含まれます。Enterprise Single-Node ライセンスは、製品内の AI、AI ガバナンス、シングルサインオンを 1 つのノードで提供し、フルのプライベートデプロイを必要とするもの(クラスタリング、複数の組織、SCIM、エアギャップ運用、階層セキュリティ)は含みません。セルフマネージドのデプロイでは、Community と Enterprise は同じランタイムを実行します。Community 列にあるものはすべて Enterprise 列にもあります。 ## 各違いがどこで強制されるか [#where-each-difference-is-enforced] @@ -43,7 +45,7 @@ ObjectOS Cloud では、シングルサインオンと AI ガバナンスは **B - **ひとつのデプロイ上の複数の組織にはライセンスが必要です。** ライセンスなしのマルチ組織の体制は起動時に拒否され、ランタイムはトラフィックを処理しません。[ランタイム設定](/docs/configure/runtime)と[トラブルシューティング](/docs/operate/troubleshooting)を参照してください。 - **エアギャップ運用はライセンスモードです。** 通常のライセンスはコントロールプレーンに対してオンラインで検証されます。エアギャップライセンスはローカルで検証され、デプロイはコントロールプレーンがないことも宣言しなければなりません。機能し得ない組み合わせは起動時に拒否されます。[エアギャップデプロイ](/docs/deploy/air-gapped)を参照してください。 - **ObjectOS Cloud では、プランは環境ごとに強制されます。** 組織はどのプランでも 1 つの環境を持ちます。容量が満杯の環境は添付ファイルのアップロードと一括インポートを拒否しますが、単一レコードの書き込み、読み取り、エクスポートは決して拒否しません(`403 STORAGE_LIMIT_REACHED`、80% から警告)。MCP エンドポイントはプランのリクエスト上限を超えると `429` を返します。[環境](/docs/cloud/environments)と[ストレージと上限](/docs/cloud/storage-and-limits)を参照してください。 -- **ライセンスが失効してもランタイムは決して停止しません。** Business Self-Managed は有料機能をオフにし、データとランタイムは動作し続けます。フルの Enterprise デプロイは最後に支払ったバージョンを維持します。[ライセンスと料金](/docs/editions/license#faq)を参照してください。 +- **ライセンスが失効してもランタイムは決して停止しません。** Enterprise Single-Node は有料機能をオフにし、データとランタイムは動作し続けます。フルの Enterprise デプロイは最後に支払ったバージョンを維持します。[ライセンスと料金](/docs/editions/license#faq)を参照してください。 ## このページはどのエディション向けか [#which-edition-is-this-page-for] diff --git a/content/docs/editions/compare.zh-Hans.mdx b/content/docs/editions/compare.zh-Hans.mdx index 83f522d9..b472caba 100644 --- a/content/docs/editions/compare.zh-Hans.mdx +++ b/content/docs/editions/compare.zh-Hans.mdx @@ -4,15 +4,16 @@ seoTitle: "ObjectOS 版本对比:Community、Free、Team、Enterprise" description: 逐行列出每个 ObjectOS 版本和套餐包含什么 —— Community、Cloud Free、Cloud Team 和 Enterprise —— 以及每项差异在哪里强制执行。 editions: [community, cloud, enterprise] translation: - source_sha: 8748d2d07adf16e62ea0be463d91d4d21b0766d025e2450512a9170a9217d24a + source_sha: c6448701566dbd6b54b9f0a7ffde7c6822406e18cdb07be8ee88a50d77588ee8 guide_rev: 1 mode: auto --- ObjectOS 是一个产品、三个版本。**ObjectOS Community** 是你自己运行的开源 运行时。**ObjectOS Cloud** 是为你托管的同一个产品,有 **Free** 和 **Team** -两个套餐。**ObjectOS Enterprise** 是你在自己的基础设施上运行的许可产品; -**Business** 和 **Business Self-Managed** 是它之下的合同选项。价格与合同见 +两个套餐。**ObjectOS Enterprise** 是按合同售卖的许可产品:可以在托管服务上,可以是单节点的 +**Enterprise Single-Node** 许可证,也可以是完整的私有部署。ObjectOS Cloud 上 +没有 Business 套餐。价格与合同见 [许可与定价](/docs/editions/license);本页讲的是每一个有什么不同。 这份文档中的每一页,标题下方都带有一排版本徽章,标明它适用于哪些版本。 @@ -28,7 +29,9 @@ ObjectOS 是一个产品、三个版本。**ObjectOS Community** 是你自己运 | 环境 | 你部署多少就有多少 | 每个组织一个 | 每个组织一个 | 你部署多少就有多少 | | MCP 请求 | 由你的部署设定 | 每分钟 20 次,每天 1,000 次 | 每分钟 120 次,无每日上限 | 由你的部署设定 | | 自定义域名 | 你自己的主机 | — | ✓ | 你自己的主机 | -| 记录级和字段级安全 | ✓ | — | ✓ | ✓ | +| 记录级和字段级安全 | ✓ | ✓ | ✓ | ✓ | +| 审批工作流 | ✓ | — | ✓ | ✓ | +| 定时和相对时间流程 | ✓ | — | ✓ | ✓ | | UI 内 AI(AI Builder、"问你的数据") | 仅 MCP —— 自带模型 | 体验版 | ✓ | ✓ | | AI 治理(动作审计、护栏、权限范围限定) | — | — | — | ✓ | | 与你的身份提供商单点登录 | ✓([身份认证](/docs/configure/authentication)) | — | — | ✓ | @@ -38,8 +41,10 @@ ObjectOS 是一个产品、三个版本。**ObjectOS Community** 是你自己运 | 物理隔离运行 | — | — | — | ✓ | | 支持 | 社区 | 社区 | 标准 | SLA + 专属 | -在 ObjectOS Cloud 上,单点登录和 AI 治理随 **Business** 提供,它是 -ObjectOS Enterprise 在托管服务上的一个合同选项。在自管理部署上,Community +在 ObjectOS Cloud 上,与你的身份提供商的单点登录和 AI 治理随托管服务上的 +**Enterprise** 合同提供。Enterprise Single-Node 许可证在单个节点上提供产品内 +AI、AI 治理和单点登录,不包含需要完整私有部署的功能:集群、多个组织、SCIM、 +物理隔离运行和层级安全。在自管理部署上,Community 和 Enterprise 运行同一个运行时:Community 一列中的一切在 Enterprise 一列中 也都有。 @@ -63,7 +68,7 @@ ObjectOS Enterprise 在托管服务上的一个合同选项。在自管理部署 起发出警告);超过套餐的请求限额后,MCP 端点会返回 `429`。参见 [环境](/docs/cloud/environments)和 [存储与限制](/docs/cloud/storage-and-limits)。 -- **许可证过期绝不会让运行时停止。** Business Self-Managed 会关闭它的付费 +- **许可证过期绝不会让运行时停止。** Enterprise Single-Node 会关闭它的付费 功能,保持你的数据和运行时正常工作;完整的 Enterprise 部署会保留最后 一个已付费的版本。参见[许可与定价](/docs/editions/license#faq)。 diff --git a/content/docs/editions/compare.zh-Hant.mdx b/content/docs/editions/compare.zh-Hant.mdx index 7ee3bf4b..52d767c0 100644 --- a/content/docs/editions/compare.zh-Hant.mdx +++ b/content/docs/editions/compare.zh-Hant.mdx @@ -5,15 +5,16 @@ seoTitle: "ObjectOS 版本對比:Community、Free、Team、Enterprise" description: 逐行列出每個 ObjectOS 版本和套餐包含什麼 —— Community、Cloud Free、Cloud Team 和 Enterprise —— 以及每項差異在哪裡強制執行。 editions: [community, cloud, enterprise] translation: - source_sha: 8748d2d07adf16e62ea0be463d91d4d21b0766d025e2450512a9170a9217d24a + source_sha: c6448701566dbd6b54b9f0a7ffde7c6822406e18cdb07be8ee88a50d77588ee8 guide_rev: 1 mode: auto --- ObjectOS 是一個產品、三個版本。**ObjectOS Community** 是你自己執行的開源 執行時。**ObjectOS Cloud** 是為你託管的同一個產品,有 **Free** 和 **Team** -兩個套餐。**ObjectOS Enterprise** 是你在自己的基礎設施上執行的許可產品; -**Business** 和 **Business Self-Managed** 是它之下的合同選項。價格與合同見 +兩個套餐。**ObjectOS Enterprise** 是按合同售賣的許可產品:可以在託管服務上,可以是單節點的 +**Enterprise Single-Node** 許可證,也可以是完整的私有部署。ObjectOS Cloud 上 +沒有 Business 套餐。價格與合同見 [許可與定價](/docs/editions/license);本頁講的是每一個有什麼不同。 這份文件中的每一頁,標題下方都帶有一排版本徽章,標明它適用於哪些版本。 @@ -29,7 +30,9 @@ ObjectOS 是一個產品、三個版本。**ObjectOS Community** 是你自己執 | 環境 | 你部署多少就有多少 | 每個組織一個 | 每個組織一個 | 你部署多少就有多少 | | MCP 請求 | 由你的部署設定 | 每分鐘 20 次,每天 1,000 次 | 每分鐘 120 次,無每日上限 | 由你的部署設定 | | 自定義域名 | 你自己的主機 | — | ✓ | 你自己的主機 | -| 記錄級和欄位級安全 | ✓ | — | ✓ | ✓ | +| 記錄級和欄位級安全 | ✓ | ✓ | ✓ | ✓ | +| 審批工作流 | ✓ | — | ✓ | ✓ | +| 定時和相對時間流程 | ✓ | — | ✓ | ✓ | | UI 內 AI(AI Builder、"問你的資料") | 僅 MCP —— 自帶模型 | 體驗版 | ✓ | ✓ | | AI 治理(動作審計、護欄、許可權範圍限定) | — | — | — | ✓ | | 與你的身份提供商單點登入 | ✓([身份認證](/docs/configure/authentication)) | — | — | ✓ | @@ -39,8 +42,10 @@ ObjectOS 是一個產品、三個版本。**ObjectOS Community** 是你自己執 | 物理隔離執行 | — | — | — | ✓ | | 支援 | 社群 | 社群 | 標準 | SLA + 專屬 | -在 ObjectOS Cloud 上,單點登入和 AI 治理隨 **Business** 提供,它是 -ObjectOS Enterprise 在託管服務上的一個合同選項。在自管理部署上,Community +在 ObjectOS Cloud 上,與你的身份提供商的單點登入和 AI 治理隨託管服務上的 +**Enterprise** 合同提供。Enterprise Single-Node 許可證在單個節點上提供產品內 +AI、AI 治理和單點登入,不包含需要完整私有部署的功能:叢集、多個組織、SCIM、 +物理隔離執行和層級安全。在自管理部署上,Community 和 Enterprise 運行同一個執行時:Community 一列中的一切在 Enterprise 一列中 也都有。 @@ -64,7 +69,7 @@ ObjectOS Enterprise 在託管服務上的一個合同選項。在自管理部署 起發出警告);超過套餐的請求限額後,MCP 端點會返回 `429`。參見 [環境](/docs/cloud/environments)和 [儲存與限制](/docs/cloud/storage-and-limits)。 -- **許可證過期絕不會讓執行時停止。** Business Self-Managed 會關閉它的付費 +- **許可證過期絕不會讓執行時停止。** Enterprise Single-Node 會關閉它的付費 功能,保持你的資料和執行時正常工作;完整的 Enterprise 部署會保留最後 一個已付費的版本。參見[許可與定價](/docs/editions/license#faq)。 diff --git a/content/docs/editions/license.ja.mdx b/content/docs/editions/license.ja.mdx new file mode 100644 index 00000000..db97c855 --- /dev/null +++ b/content/docs/editions/license.ja.mdx @@ -0,0 +1,118 @@ +--- +title: ライセンスと料金 +description: ObjectOS は 3 つのエディションを持つひとつの製品です。Community(オープンソース、無料)、Cloud、Enterprise。それぞれのライセンス形態と、ObjectStack フレームワークとの関係を説明します。 +editions: [community, cloud, enterprise] +translation: + source_sha: 32388e7b58b1b2a02d23d2ffc641867011e628c961d3b1ebccfb0dd20c99d037 + guide_rev: 1 + mode: auto +--- + +## ひとつの製品、3 つのエディション [#one-product-three-editions] + +ObjectOS は **ObjectStack アプリケーションの公式ランタイム環境**で、3 つのエディションがあります。**ObjectOS Community**(オープンソース、セルフホスト、無料)、**ObjectOS Cloud**(私たちが運用)、**ObjectOS Enterprise**(商用ライセンスのもとであなたが運用)です。ObjectStack は、3 つのエディションが実行するプロトコル、SDK、CLI、フレームワークの名前です。 + +{/* + Naming, decided under #79 and re-confirmed on #107: "Console UI" here and in + the Apache-2.0 list further down names the *component* — the shipped browser + bundle, the `@objectstack/console` package, the same spelling architecture.mdx + and configure/system-settings.mdx were deliberately kept at. #79 retired + "Console" as the name of the end-user surface (a reader opens ObjectOS, not + "the Console") but kept the names of things the product ships, and a license + enumerates artifacts rather than surfaces. Both occurrences on this page are + therefore deliberate — do not rewrite them to "the UI" or to "ObjectOS". +*/} + +オープンソースの部分には 2 つの名前と 1 つのライセンスがあります。**[ObjectStack フレームワーク](https://github.com/objectstack-ai/objectstack)**(Apache-2.0)はプロトコル、カーネル、SDK、CLI です。**ObjectOS Community** はそこから構築されたオープンソースのランタイムと Console UI です。本番用のランタイムイメージ、MCP サーバー、権限と共有、監査、あらゆるプロトコル機能など、**独自のアプリケーションを構築、実行、セルフホスト**するために必要なものすべてが無料で、開発と本番の間に機能の制限はありません。そのコードは同じ objectstack リポジトリにあります。ObjectOS Cloud と ObjectOS Enterprise は、その仕組みの上に**組み込みの AI** と**公式に運用 / サポートされる**プラットフォームが欲しいときに購入するものです。 + +## エディション [#editions] + +ObjectOS Community は無料です。2 つの商用エディションには、ひとつの料金表と 2 つの提供形態があり、**AI シート**が唯一の課金単位です。 + +| | **Community** | **Free** | **Team** | **Enterprise** | +|---|---|---|---|---| +| エディション | ObjectOS Community | ObjectOS Cloud | ObjectOS Cloud | ObjectOS Enterprise | +| 提供形態 | **セルフマネージド** | クラウド | クラウド | 契約によるクラウド、または**セルフマネージド**(シングルノードまたはプライベートデプロイ) | +| 料金 | **無料**(Apache-2.0) | **無料** | **$24** / AI シート / 月、または年払いで $20 / AI シート / 月 | 個別見積もり(ボリューム):[営業にお問い合わせください](mailto:sales@objectos.ai) | +| UI 内の AI(AI Builder +「データに質問する」) | MCP のみ(モデルは持ち込み) | お試し | ✓ | ✓ | +| AI ガバナンス(アクションの監査、ガードレール、権限のスコープ設定) | — | — | — | ✓ | +| クラスタリング / HA、マルチ組織のセルフホスト、エアギャップ、SCIM | — | — | — | ✓ | +| サポート | コミュニティ | コミュニティ | スタンダード | SLA + 専任 | + +ObjectOS Cloud は **Free** と **Team** で、Business プランはありません。Team にはメンバー、レコード、オブジェクトの数の上限がありません。Team を超えるものはすべて **Enterprise** 契約で、その唯一の価格付きのエントリーは **Enterprise Single-Node**(旧 Business Self-Managed)です。シングルノードで **$540** / AI シート / 年、10〜25 AI シート向けです。[営業にお問い合わせください](mailto:sales@objectos.ai)。 + +**無料で**セルフホストしたいですか?それが **ObjectOS Community** です(MCP のみの AI:モデルは持ち込み)。下の [ObjectOS Community](#objectos-community) を参照してください。 + +**オープンな仕組み、クローズドなインテリジェンス。** データをモデル化しアプリを実行するために必要なものはすべてオープンソースです(ObjectStack フレームワーク上の ObjectOS Community)。Cloud と Enterprise は、その上に*組み込みのインテリジェンス*(製品内の AI Builder と「データに質問する」アシスタント。ガバナンスと監査付き)を重ね、さらに運用のスケールと公式サポートを加えます。 + +**支払うのは AI シートだけです。** 課金されるシートは **AI シート**だけです。閲覧者、AI を使わないアプリユーザー、MCP 上で構築する開発者は無料で、ユーザーごとのシート課金はありません(ユーザーあたり $150〜300 の既存製品とは明確に対照的です)。 + +## クラウドかセルフマネージドか [#cloud-or-self-managed] + +セルフマネージドの ObjectOS は、**ObjectOS Community**(無料)または **ObjectOS Enterprise**(ライセンス制)です。Cloud は Free と Team で、Team より上はすべて Enterprise の契約です。 + +- **Cloud(Free / Team)**:フルホスト型、セルフサービス。料金にはホスティングと十分な月間 AI 利用枠が含まれます(モデルは私たちが実行します)。 +- **Enterprise**:契約により販売されるライセンス制の ObjectOS で、3 つの形があります。 + - **ObjectOS Cloud 上**:ホスト型サービス上の、自社のアイデンティティプロバイダーによるシングルサインオン(OIDC / SAML)と AI ガバナンス(アクションの監査、ガードレール、権限のスコープ設定)、上限のないストレージ、優先サポート。料金は契約によります。 + - **Enterprise Single-Node**:シングルノードのエントリーオプションで、旧 Business Self-Managed と同じ条件です。**10〜25 AI シート**向けの**シングルノード Docker ライセンス**です($540/AI シート/年、年額)。自社のインフラストラクチャ上で UI 内の AI、AI ガバナンス、シングルサインオンを利用でき、**モデル / キーは持ち込み**です(LLM のコストは自分で支払います。プラットフォームの AI 請求や従量課金はありません)。オンラインで検証されるライセンス、カード払い、スタンダードサポート。ライセンスが失効しても、ランタイムは動作し続け、データはそのまま残ります。有料機能がオフになるだけです(使えなくなることは決してありません)。名前と契約には、含まれないものが明記されており、そのすべてにフルのプライベートデプロイが必要です。クラスタリング / HA / マルチノード、エアギャップまたはオフラインのライセンス、ひとつのデプロイ上の複数の組織、SCIM と ID ライフサイクル、階層セキュリティ、更新しない場合の最後に支払ったバージョンの維持、オフライン / 銀行振込での支払いと複数年契約、優先 / SLA / 専任サポート、エンタープライズコネクタ、コンプライアンスの証明、データレジデンシー、そして 25 を超える AI シートです。 + - **フルのプライベートデプロイ**:それを超えるすべてのもの。クラスタリング / HA / マルチノード、マルチ組織のセルフホスト、データレジデンシーと**エアギャップ**運用、SCIM と ID ライフサイクル、コンプライアンスの証明、SLA と専任サポート、オフライン / 請求書払い。複数年の価格固定オプション付きの**年間ライセンス**として販売されます。更新しない場合、デプロイは**最後に支払ったバージョンを永続的に維持**します(失うのはアップデートとサポートであり、システムやデータではありません)。料金はボリュームベースです。[営業にお問い合わせください](mailto:sales@objectos.ai)。 + +**ノードごとの課金はありません**。クラスタリング / スケールは Enterprise に含まれます。 + +## それぞれが適するとき [#when-you-might-want-each] + +| シナリオ | 選ぶもの | +|---|---| +| プラットフォームを**ホストして運用してほしい** | ObjectOS Cloud(Free → Team) | +| ホスト型サービスで**自社のアイデンティティプロバイダーによる SSO と AI ガバナンス**が必要 | ObjectOS Cloud 上の **ObjectOS Enterprise**、契約による | +| **自社のシングルノード**で実行しなければならず、製品内の AI が欲しい、25 AI シート以下 | **Enterprise Single-Node**、ObjectOS Enterprise のシングルノードのエントリーオプション | +| **クラスタリング / HA**、**マルチ組織**、**エアギャップ**、**SCIM**、コンプライアンスの証明、SLA、オフライン払いが必要 | **ObjectOS Enterprise**、フルのプライベートデプロイ | +| ObjectOS Community をセルフホストしているが、**商用契約付きのサポートされたディストリビューション**(SLA、セキュリティパッチの優先対応、指名エスカレーション)が必要 | **ObjectOS Runtime Subscription**:[営業にお問い合わせください](mailto:sales@objectos.ai) | +| **無料のセルフホスト**で、MCP 経由で AI を持ち込みたい | **ObjectOS Community**(オープンソース) | +| ObjectOS または ObjectStack の名前で **OEM / 再配布**の権利が必要 | 商用契約:[営業にお問い合わせください](mailto:sales@objectos.ai) | + +## ObjectOS Community [#objectos-community] + +**ObjectOS Community**(ランタイムイメージと Console UI)と、その土台である **ObjectStack フレームワーク**は、[Apache License, Version 2.0](https://www.apache.org/licenses/LICENSE-2.0) のもとでライセンスされています。コピーレフトなし、明示的な特許許諾、永久に無料。シートも、利用ティアも、ライセンスサーバーも、キーも、テレメトリもありません。ノート PC、自社のサーバー、顧客のサーバー、1000 ポッドのクラスターのどこで実行しても、ライセンスは同じです。そこでの AI の経路はオープンな **MCP サーバー**です。自分の Claude Code(または任意の MCP クライアント)をデプロイに向ければ、自分のモデルでデータをクエリし操作できます。 + +Apache-2.0 であるもの(objectstack リポジトリ内):ランタイムイメージ、すべての`@objectstack/*` npm パッケージ(ランタイム、プラグイン、サービス、ドライバー、アダプター、CLI、クライアント SDK)、templates リポジトリ、そして Console UI(それが提供する Account アプリを含む)。ドキュメントは CC-BY-4.0 です。 + +全文:[LICENSE](https://github.com/objectstack-ai/objectstack/blob/main/LICENSE) + +## 商標 [#trademarks] + +「ObjectOS」と ObjectOS のロゴは**商標**であり、どのコードライセンスの対象でもありません。自社の製品が ObjectOS / ObjectStack の*上に構築されている*、または*互換性がある*と事実に即して述べることはできます。自社の製品名、会社名、ドメイン名にこれらの名前やロゴを使うには書面による許可が必要です。[TRADEMARK.md](https://github.com/objectstack-ai/docs.objectos.ai/blob/main/TRADEMARK.md) を参照してください。 + +## サードパーティのコンポーネント [#third-party-components] + +ObjectOS は ObjectStack フレームワークと、いくつかの上流のオープンソースプロジェクト(Node.js、Hono、Zod、Better Auth、AI SDK など)の上に構築されています。それぞれに独自のライセンスが付属し、すべて商用利用と互換性のある Apache-2.0、MIT、BSD 系の寛容なライセンスです。完全な一覧は、各リリースとともに公開される SBOM を参照してください。 + +## よくある質問 [#faq] + +### ObjectOS はオープンソースですか? [#is-objectos-open-source] + +**ObjectOS Community** はオープンソースです。ランタイムと Console は Apache-2.0 で無料、そのもととなる ObjectStack フレームワークと並んで [objectstack リポジトリ](https://github.com/objectstack-ai/objectstack)でオープンに開発されています。**ObjectOS Cloud**と **ObjectOS Enterprise** は商用エディションで、同じ仕組みの上に組み込みの AI、ホスティングと運用、SSO、サポートを加えたものです。 + +### 顧客に販売するクローズドソースの SaaS で ObjectStack を使えますか? [#can-i-use-objectstack-in-a-closed-source-saas-i-sell-to-my-customers] + +はい。Apache-2.0 にはコピーレフトもロイヤリティもありません。コードを共有する必要はなく、製品が利益を上げても支払うものはありません。 + +### 支払いなしで ObjectOS をセルフホストできますか? [#can-i-self-host-objectos-without-paying] + +はい。それが **ObjectOS Community** です。同じオープンな仕組みをセルフホストし、AI は MCP のみ(モデルは持ち込み)です。*ライセンス制*のセルフマネージドエディションは ObjectOS Enterprise で、その 2 つのセルフマネージドのオプション(Enterprise Single-Node、またはフルの Enterprise デプロイ)はどちらも、製品内の AI、AI ガバナンス、商用サポートを追加します。 + +### 更新しないとソフトウェアは動かなくなりますか? [#does-the-software-stop-working-if-i-dont-renew] + +使えなくなることは決してありません。Enterprise Single-Node は無料の仕組みの動作に戻ります(有料機能はオフになり、データとランタイムは動作し続けます)。フルの Enterprise デプロイは**最後に支払ったバージョンを永続的に**維持します。失うのはアップデート、新しい AI 機能、サポートであり、システムではありません。 + +### ObjectOS は外部に通信しますか? [#does-objectos-phone-home] + +ObjectOS Enterprise はライセンスをオンラインで検証します。エアギャップの Enterprise ライセンスはオフラインで検証します。ObjectOS Community にはテレメトリも、ライセンスチェックも、アップデートの確認通信もありません。 + +### ObjectOS Community に契約上の保証が欲しい場合は? [#what-if-i-want-a-contractual-warranty-on-objectos-community] + +それが **ObjectOS Runtime Subscription** です。ObjectOS Community に対するサポート契約(公式ディストリビューション、SLA、セキュリティパッチの優先対応)で、機能の違いはまったくありません。[sales@objectos.ai](mailto:sales@objectos.ai) にお問い合わせください。 + +### ObjectOS Community とフレームワークはずっと無料ですか? [#will-objectos-community-and-the-framework-always-be-free] + +はい。Apache-2.0 の許諾は取り消し不能であり、すでにリリースされたものはすべてリリース時のライセンスのままです。 diff --git a/content/docs/editions/license.zh-Hans.mdx b/content/docs/editions/license.zh-Hans.mdx new file mode 100644 index 00000000..f537e4c2 --- /dev/null +++ b/content/docs/editions/license.zh-Hans.mdx @@ -0,0 +1,190 @@ +--- +title: 许可与定价 +description: ObjectOS 是一个产品、三个版本 —— Community(开源,免费)、Cloud 和 Enterprise —— 每个版本如何授权,以及它们与 ObjectStack 框架的关系。 +editions: [community, cloud, enterprise] +translation: + source_sha: 32388e7b58b1b2a02d23d2ffc641867011e628c961d3b1ebccfb0dd20c99d037 + guide_rev: 1 + mode: auto +--- + +## 一个产品,三个版本 [#one-product-three-editions] + +ObjectOS 是 **ObjectStack 应用的官方运行时环境**,有三个版本: +**ObjectOS Community**(开源、自托管、免费)、**ObjectOS Cloud**(由我们 +运维)和 **ObjectOS Enterprise**(由你在商业许可下运维)。ObjectStack 是这 +三个版本所运行的协议、SDK、CLI 和框架的名称。 + +{/* + Naming, decided under #79 and re-confirmed on #107: "Console UI" here and in + the Apache-2.0 list further down names the *component* — the shipped browser + bundle, the `@objectstack/console` package, the same spelling architecture.mdx + and configure/system-settings.mdx were deliberately kept at. #79 retired + "Console" as the name of the end-user surface (a reader opens ObjectOS, not + "the Console") but kept the names of things the product ships, and a license + enumerates artifacts rather than surfaces. Both occurrences on this page are + therefore deliberate — do not rewrite them to "the UI" or to "ObjectOS". +*/} + +开源这部分有两个名字、一个许可证。 +**[ObjectStack 框架](https://github.com/objectstack-ai/objectstack)** +(Apache-2.0)是协议、内核、SDK 和 CLI;**ObjectOS Community** 是由它构建 +的开源运行时和 Console UI —— 生产级运行时镜像、MCP 服务器、权限与共享、 +审计、每一项协议能力 —— **构建、运行和自托管你自己的应用**所需的一切, +免费,开发与生产之间没有功能关卡。它的代码位于同一个 objectstack 仓库中。 +当你想在这套机制之上获得**嵌入式 AI** 和一个**官方运维 / 官方支持**的平台 +时,你购买的就是 ObjectOS Cloud 和 ObjectOS Enterprise。 + +## 版本 [#editions] + +ObjectOS Community 免费。两个商业版本使用一张价目表、两种交付方式, +**AI 席位**是唯一的计价单位。 + +| | **Community** | **Free** | **Team** | **Enterprise** | +|---|---|---|---|---| +| 版本 | ObjectOS Community | ObjectOS Cloud | ObjectOS Cloud | ObjectOS Enterprise | +| 交付方式 | **自管理** | 云 | 云 | 按合同在云上,或**自管理**(单节点或私有部署) | +| 价格 | **免费**(Apache-2.0) | **免费** | **24 美元** / AI 席位 / 月,或按年付费 20 美元 / AI 席位 / 月 | 定制(按量)—— [联系销售](mailto:sales@objectos.ai) | +| UI 内 AI(AI Builder + "问你的数据") | 仅 MCP(自带模型) | 体验版 | ✓ | ✓ | +| AI 治理(动作审计、护栏、权限范围限定) | — | — | — | ✓ | +| 集群 / 高可用、多组织自托管、物理隔离、SCIM | — | — | — | ✓ | +| 支持 | 社区 | 社区 | 标准 | SLA + 专属 | + +ObjectOS Cloud 就是 **Free** 和 **Team**;没有 Business 套餐。Team 不限制成员、 +记录或对象的数量。Team 之上的一切都是 **Enterprise** 合同,它唯一标价的入门 +选项是 **Enterprise Single-Node**(原 Business Self-Managed):单个节点上 +**540 美元** / AI 席位 / 年,适用于 10–25 个 AI 席位 —— +[联系销售](mailto:sales@objectos.ai)。 + +想**免费**自托管?那就是 **ObjectOS Community**(仅 MCP 的 AI:自带模型)。 +参见下文的 [ObjectOS Community](#objectos-community)。 + +**开放的机制,封闭的智能。** 建模数据和运行应用所需的一切都是开源的 +(ObjectOS Community,基于 ObjectStack 框架)。Cloud 和 Enterprise 在其上 +叠加了*嵌入式智能* —— 产品内的 AI Builder 和"问你的数据"助手,经过治理 +和审计 —— 再加上运营规模和官方支持。 + +**你只为 AI 席位付费。** 唯一计费的席位是 **AI 席位**;只读用户、非 AI 的 +应用用户以及通过 MCP 构建的开发者都免费,没有按用户收取的席位税(与那些 +每用户 150–300 美元的老牌厂商形成鲜明对比)。 + +## 云还是自管理 [#cloud-or-self-managed] + +自管理的 ObjectOS 是 **ObjectOS Community**(免费)或 **ObjectOS +Enterprise**(需许可)。云是 Free 和 Team;Team 之上的一切都是 Enterprise +合同。 + +- **云(Free / Team)** —— 完全托管,自助开通。价格包含托管和一份充裕的 + 每月 AI 额度(模型由我们运行)。 +- **Enterprise** —— 需许可的 ObjectOS,按合同销售,有三种形态: + - **在 ObjectOS Cloud 上** —— 托管服务上与你的身份提供商的单点登录(OIDC + / SAML)和 AI 治理(动作审计、护栏、权限范围限定),不设上限的存储, + 优先支持。按合同定价。 + - **Enterprise Single-Node** —— 单节点入门选项,原 Business + Self-Managed,条款不变:适用于 **10–25 个 AI 席位**的**单节点 Docker + 许可证**(540 美元/AI 席位/年,按年):在你自己的基础设施上提供 UI 内 + AI、AI 治理和单点登录,**自带模型 / 密钥**(你自己承担 LLM 成本 —— 没有 + 平台 AI 账单或计量),在线校验的许可证,刷卡支付,标准支持。如果许可证 + 过期,运行时会继续运行,你的数据保持完整 —— 只是付费功能会关闭(它永远 + 不会变砖)。它的名称和合同写明了它不包含的内容,这些都需要完整私有部署: + 集群 / 高可用 / 多节点、物理隔离或离线许可证、单个部署承载多个组织、SCIM + 和身份生命周期、层级安全、不续约时保留最后一个已付费的版本、线下 / 电汇 + 付款和多年期合同、优先 / SLA / 专属支持、企业连接器、合规证明、数据驻留, + 以及超过 25 个 AI 席位。 + - **完整私有部署** —— 适用于超出上述范围的一切:集群 / 高可用 / 多节点、 + 多组织自托管、数据驻留和**物理隔离**运行、SCIM 和身份生命周期、合规 + 证明、SLA 和专属支持,以及线下 / 发票付款。以**年度许可证**销售,可选 + 多年锁价;不续约时,你的部署会**永久保留最后一个已付费的版本**(你失去 + 的是更新和支持,绝不是你的系统或数据)。价格按量计算 —— + [联系销售](mailto:sales@objectos.ai)。 + +**不按节点收费** —— 集群 / 扩展已包含在 Enterprise 中。 + +## 什么时候选哪个 [#when-you-might-want-each] + +| 场景 | 选择 | +|---|---| +| 你希望平台**由别人托管和运维** | ObjectOS Cloud(Free → Team) | +| 你需要托管服务上**与你的身份提供商的 SSO 和 AI 治理** | ObjectOS Cloud 上的 **ObjectOS Enterprise**,按合同 | +| 你必须在**你自己的单个节点**上运行,并且想要产品内 AI,AI 席位 ≤25 个 | **Enterprise Single-Node**,ObjectOS Enterprise 的单节点入门选项 | +| 你需要**集群 / 高可用**、**多组织**、**物理隔离**、**SCIM**、合规证明、SLA 或线下付款 | **ObjectOS Enterprise**,完整私有部署 | +| 你自托管 ObjectOS Community,但需要一个**带商业合同的受支持发行版**(SLA、安全补丁优先、指定升级渠道) | **ObjectOS Runtime Subscription** —— [联系销售](mailto:sales@objectos.ai) | +| 你想要**免费自托管**,并通过 MCP 自带 AI | **ObjectOS Community**(开源) | +| 你需要以 ObjectOS 或 ObjectStack 名义进行 **OEM / 再分发**的权利 | 商业协议 —— [联系销售](mailto:sales@objectos.ai) | + +## ObjectOS Community [#objectos-community] + +**ObjectOS Community** —— 运行时镜像和 Console UI —— 以及构建它的 +**ObjectStack 框架**,均采用 +[Apache License, Version 2.0](https://www.apache.org/licenses/LICENSE-2.0) +授权:没有 copyleft,有明确的专利授权,永久免费 —— 没有席位,没有用量 +档位,没有许可证服务器,没有密钥,没有遥测。在你的笔记本、你的服务器、 +你客户的服务器或一个 1000 个 Pod 的集群上运行它;许可证在任何情况下都 +一样。你在那里的 AI 路径是开放的 **MCP 服务器**:把你自己的 Claude Code +(或任何 MCP 客户端)指向你的部署,它就能用你自己的模型查询和操作你的 +数据。 + +Apache-2.0 授权的内容(位于 objectstack 仓库中):运行时镜像、所有 +`@objectstack/*` npm 包(运行时、插件、服务、驱动、适配器、CLI、客户端 +SDK)、templates 仓库,以及 Console UI,包括它提供的 Account 应用。 +文档采用 CC-BY-4.0。 + +全文:[LICENSE](https://github.com/objectstack-ai/objectstack/blob/main/LICENSE) + +## 商标 [#trademarks] + +"ObjectOS"和 ObjectOS 标志是**商标**,不受任何代码许可证的覆盖。你可以 +如实地说你的产品*构建于* ObjectOS / ObjectStack 之上或*兼容* ObjectOS / +ObjectStack;在你自己的产品、公司或域名中使用这些名称或标志需要书面许可。 +参见 [TRADEMARK.md](https://github.com/objectstack-ai/docs.objectos.ai/blob/main/TRADEMARK.md)。 + +## 第三方组件 [#third-party-components] + +ObjectOS 构建在 ObjectStack 框架和若干上游开源项目(Node.js、Hono、Zod、 +Better Auth、AI SDK ……)之上。每个组件都带有自己的许可证 —— 全部是 +Apache-2.0、MIT 或 BSD 风格的宽松许可证,兼容商业使用。完整清单见每个 +版本随附发布的 SBOM。 + +## 常见问题 [#faq] + +### ObjectOS 是开源的吗? [#is-objectos-open-source] + +**ObjectOS Community** 是:运行时和 Console 采用 Apache-2.0,免费,并在 +[objectstack 仓库](https://github.com/objectstack-ai/objectstack)中公开 +开发,与构建它们的 ObjectStack 框架放在一起。**ObjectOS Cloud** 和 +**ObjectOS Enterprise** 是商业版本 —— 在同一套机制之上提供嵌入式 AI、 +托管与运维、SSO 和支持。 + +### 我能在卖给客户的闭源 SaaS 中使用 ObjectStack 吗? [#can-i-use-objectstack-in-a-closed-source-saas-i-sell-to-my-customers] + +可以。Apache-2.0 没有 copyleft,也没有版税 —— 你不需要公开你的代码, +即使你的产品赚了钱,你也不欠任何费用。 + +### 我能不付费自托管 ObjectOS 吗? [#can-i-self-host-objectos-without-paying] + +可以 —— 那就是 **ObjectOS Community**:同样开放的机制,自托管,AI 仅通过 +MCP(自带模型)。*需许可*的自管理版本是 ObjectOS Enterprise,它的两个 +自管理选项(Enterprise Single-Node,或完整的 Enterprise 部署)都会 +增加产品内 AI、AI 治理和商业支持。 + +### 如果我不续约,软件会停止工作吗? [#does-the-software-stop-working-if-i-dont-renew] + +它永远不会变砖。Enterprise Single-Node 会降级为免费机制的行为(付费功能 +关闭;你的数据和运行时继续工作)。完整的 Enterprise 部署会**永久保留最后 +一个已付费的版本** —— 你失去的是更新、新的 AI 能力和支持,而不是你的 +系统。 + +### ObjectOS 会"回传数据"吗? [#does-objectos-phone-home] + +ObjectOS Enterprise 会在线校验许可证;物理隔离的 Enterprise 许可证离线 +校验。ObjectOS Community 没有遥测,没有许可证检查,也没有更新探测。 + +### 如果我想为 ObjectOS Community 获得合同担保怎么办? [#what-if-i-want-a-contractual-warranty-on-objectos-community] + +那就是 **ObjectOS Runtime Subscription** —— 针对 ObjectOS Community 的 +支持合同(官方发行版、SLA、安全补丁优先),功能上没有任何差别。请联系 +[sales@objectos.ai](mailto:sales@objectos.ai)。 + +### ObjectOS Community 和框架会一直免费吗? [#will-objectos-community-and-the-framework-always-be-free] + +会。Apache-2.0 的授予不可撤销,所有已经发布的内容都会保持发布时的许可。 diff --git a/content/docs/editions/license.zh-Hant.mdx b/content/docs/editions/license.zh-Hant.mdx new file mode 100644 index 00000000..336cee1a --- /dev/null +++ b/content/docs/editions/license.zh-Hant.mdx @@ -0,0 +1,191 @@ +--- +# @generated zh-Hant from zh-Hans -- do not edit. Edit the English source, then regenerate: pnpm --filter @objectos/docs gen:zh-hant +title: 許可與定價 +description: ObjectOS 是一個產品、三個版本 —— Community(開源,免費)、Cloud 和 Enterprise —— 每個版本如何授權,以及它們與 ObjectStack 框架的關係。 +editions: [community, cloud, enterprise] +translation: + source_sha: 32388e7b58b1b2a02d23d2ffc641867011e628c961d3b1ebccfb0dd20c99d037 + guide_rev: 1 + mode: auto +--- + +## 一個產品,三個版本 [#one-product-three-editions] + +ObjectOS 是 **ObjectStack 應用的官方執行時環境**,有三個版本: +**ObjectOS Community**(開源、自託管、免費)、**ObjectOS Cloud**(由我們 +運維)和 **ObjectOS Enterprise**(由你在商業許可下運維)。ObjectStack 是這 +三個版本所執行的協議、SDK、CLI 和框架的名稱。 + +{/* + Naming, decided under #79 and re-confirmed on #107: "Console UI" here and in + the Apache-2.0 list further down names the *component* — the shipped browser + bundle, the `@objectstack/console` package, the same spelling architecture.mdx + and configure/system-settings.mdx were deliberately kept at. #79 retired + "Console" as the name of the end-user surface (a reader opens ObjectOS, not + "the Console") but kept the names of things the product ships, and a license + enumerates artifacts rather than surfaces. Both occurrences on this page are + therefore deliberate — do not rewrite them to "the UI" or to "ObjectOS". +*/} + +開源這部分有兩個名字、一個許可證。 +**[ObjectStack 框架](https://github.com/objectstack-ai/objectstack)** +(Apache-2.0)是協議、核心、SDK 和 CLI;**ObjectOS Community** 是由它構建 +的開源執行時和 Console UI —— 生產級執行時映象、MCP 伺服器、許可權與共享、 +審計、每一項協議能力 —— **構建、執行和自託管你自己的應用**所需的一切, +免費,開發與生產之間沒有功能關卡。它的程式碼位於同一個 objectstack 倉庫中。 +當你想在這套機制之上獲得**嵌入式 AI** 和一個**官方運維 / 官方支援**的平臺 +時,你購買的就是 ObjectOS Cloud 和 ObjectOS Enterprise。 + +## 版本 [#editions] + +ObjectOS Community 免費。兩個商業版本使用一張價目表、兩種交付方式, +**AI 席位**是唯一的計價單位。 + +| | **Community** | **Free** | **Team** | **Enterprise** | +|---|---|---|---|---| +| 版本 | ObjectOS Community | ObjectOS Cloud | ObjectOS Cloud | ObjectOS Enterprise | +| 交付方式 | **自管理** | 雲 | 雲 | 按合同在雲上,或**自管理**(單節點或私有部署) | +| 價格 | **免費**(Apache-2.0) | **免費** | **24 美元** / AI 席位 / 月,或按年付費 20 美元 / AI 席位 / 月 | 定製(按量)—— [聯絡銷售](mailto:sales@objectos.ai) | +| UI 內 AI(AI Builder + "問你的資料") | 僅 MCP(自帶模型) | 體驗版 | ✓ | ✓ | +| AI 治理(動作審計、護欄、許可權範圍限定) | — | — | — | ✓ | +| 叢集 / 高可用、多組織自託管、物理隔離、SCIM | — | — | — | ✓ | +| 支援 | 社群 | 社群 | 標準 | SLA + 專屬 | + +ObjectOS Cloud 就是 **Free** 和 **Team**;沒有 Business 套餐。Team 不限制成員、 +記錄或物件的數量。Team 之上的一切都是 **Enterprise** 合同,它唯一標價的入門 +選項是 **Enterprise Single-Node**(原 Business Self-Managed):單個節點上 +**540 美元** / AI 席位 / 年,適用於 10–25 個 AI 席位 —— +[聯絡銷售](mailto:sales@objectos.ai)。 + +想**免費**自託管?那就是 **ObjectOS Community**(僅 MCP 的 AI:自帶模型)。 +參見下文的 [ObjectOS Community](#objectos-community)。 + +**開放的機制,封閉的智慧。** 建模資料和執行應用所需的一切都是開源的 +(ObjectOS Community,基於 ObjectStack 框架)。Cloud 和 Enterprise 在其上 +疊加了*嵌入式智慧* —— 產品內的 AI Builder 和"問你的資料"助手,經過治理 +和審計 —— 再加上運營規模和官方支援。 + +**你只為 AI 席位付費。** 唯一計費的席位是 **AI 席位**;只讀使用者、非 AI 的 +應用使用者以及通過 MCP 構建的開發者都免費,沒有按使用者收取的席位稅(與那些 +每使用者 150–300 美元的老牌廠商形成鮮明對比)。 + +## 雲還是自管理 [#cloud-or-self-managed] + +自管理的 ObjectOS 是 **ObjectOS Community**(免費)或 **ObjectOS +Enterprise**(需許可)。雲是 Free 和 Team;Team 之上的一切都是 Enterprise +合同。 + +- **雲(Free / Team)** —— 完全託管,自助開通。價格包含託管和一份充裕的 + 每月 AI 額度(模型由我們執行)。 +- **Enterprise** —— 需許可的 ObjectOS,按合同銷售,有三種形態: + - **在 ObjectOS Cloud 上** —— 託管服務上與你的身份提供商的單點登入(OIDC + / SAML)和 AI 治理(動作審計、護欄、許可權範圍限定),不設上限的儲存, + 優先支援。按合同定價。 + - **Enterprise Single-Node** —— 單節點入門選項,原 Business + Self-Managed,條款不變:適用於 **10–25 個 AI 席位**的**單節點 Docker + 許可證**(540 美元/AI 席位/年,按年):在你自己的基礎設施上提供 UI 內 + AI、AI 治理和單點登入,**自帶模型 / 金鑰**(你自己承擔 LLM 成本 —— 沒有 + 平臺 AI 賬單或計量),線上校驗的許可證,刷卡支付,標準支援。如果許可證 + 過期,執行時會繼續執行,你的資料保持完整 —— 只是付費功能會關閉(它永遠 + 不會變磚)。它的名稱和合同寫明瞭它不包含的內容,這些都需要完整私有部署: + 叢集 / 高可用 / 多節點、物理隔離或離線許可證、單個部署承載多個組織、SCIM + 和身份生命週期、層級安全、不續約時保留最後一個已付費的版本、線下 / 電匯 + 付款和多年期合同、優先 / SLA / 專屬支援、企業聯結器、合規證明、資料駐留, + 以及超過 25 個 AI 席位。 + - **完整私有部署** —— 適用於超出上述範圍的一切:叢集 / 高可用 / 多節點、 + 多組織自託管、資料駐留和**物理隔離**執行、SCIM 和身份生命週期、合規 + 證明、SLA 和專屬支援,以及線下 / 發票付款。以**年度許可證**銷售,可選 + 多年鎖價;不續約時,你的部署會**永久保留最後一個已付費的版本**(你失去 + 的是更新和支援,絕不是你的系統或資料)。價格按量計算 —— + [聯絡銷售](mailto:sales@objectos.ai)。 + +**不按節點收費** —— 叢集 / 擴充套件已包含在 Enterprise 中。 + +## 什麼時候選哪個 [#when-you-might-want-each] + +| 場景 | 選擇 | +|---|---| +| 你希望平臺**由別人託管和運維** | ObjectOS Cloud(Free → Team) | +| 你需要託管服務上**與你的身份提供商的 SSO 和 AI 治理** | ObjectOS Cloud 上的 **ObjectOS Enterprise**,按合同 | +| 你必須在**你自己的單個節點**上執行,並且想要產品內 AI,AI 席位 ≤25 個 | **Enterprise Single-Node**,ObjectOS Enterprise 的單節點入門選項 | +| 你需要**叢集 / 高可用**、**多組織**、**物理隔離**、**SCIM**、合規證明、SLA 或線下付款 | **ObjectOS Enterprise**,完整私有部署 | +| 你自託管 ObjectOS Community,但需要一個**帶商業合同的受支援發行版**(SLA、安全補丁優先、指定升級渠道) | **ObjectOS Runtime Subscription** —— [聯絡銷售](mailto:sales@objectos.ai) | +| 你想要**免費自託管**,並通過 MCP 自帶 AI | **ObjectOS Community**(開源) | +| 你需要以 ObjectOS 或 ObjectStack 名義進行 **OEM / 再分發**的權利 | 商業協議 —— [聯絡銷售](mailto:sales@objectos.ai) | + +## ObjectOS Community [#objectos-community] + +**ObjectOS Community** —— 執行時映象和 Console UI —— 以及構建它的 +**ObjectStack 框架**,均採用 +[Apache License, Version 2.0](https://www.apache.org/licenses/LICENSE-2.0) +授權:沒有 copyleft,有明確的專利授權,永久免費 —— 沒有席位,沒有用量 +檔位,沒有許可證伺服器,沒有金鑰,沒有遙測。在你的筆記本、你的伺服器、 +你客戶的伺服器或一個 1000 個 Pod 的叢集上執行它;許可證在任何情況下都 +一樣。你在那裡的 AI 路徑是開放的 **MCP 伺服器**:把你自己的 Claude Code +(或任何 MCP 客戶端)指向你的部署,它就能用你自己的模型查詢和操作你的 +資料。 + +Apache-2.0 授權的內容(位於 objectstack 倉庫中):執行時映象、所有 +`@objectstack/*` npm 包(執行時、外掛、服務、驅動、介面卡、CLI、客戶端 +SDK)、templates 倉庫,以及 Console UI,包括它提供的 Account 應用。 +文件採用 CC-BY-4.0。 + +全文:[LICENSE](https://github.com/objectstack-ai/objectstack/blob/main/LICENSE) + +## 商標 [#trademarks] + +"ObjectOS"和 ObjectOS 標誌是**商標**,不受任何程式碼許可證的覆蓋。你可以 +如實地說你的產品*構建於* ObjectOS / ObjectStack 之上或*相容* ObjectOS / +ObjectStack;在你自己的產品、公司或域名中使用這些名稱或標誌需要書面許可。 +參見 [TRADEMARK.md](https://github.com/objectstack-ai/docs.objectos.ai/blob/main/TRADEMARK.md)。 + +## 第三方元件 [#third-party-components] + +ObjectOS 構建在 ObjectStack 框架和若干上游開源專案(Node.js、Hono、Zod、 +Better Auth、AI SDK ……)之上。每個元件都帶有自己的許可證 —— 全部是 +Apache-2.0、MIT 或 BSD 風格的寬鬆許可證,相容商業使用。完整清單見每個 +版本隨附釋出的 SBOM。 + +## 常見問題 [#faq] + +### ObjectOS 是開源的嗎? [#is-objectos-open-source] + +**ObjectOS Community** 是:執行時和 Console 採用 Apache-2.0,免費,並在 +[objectstack 倉庫](https://github.com/objectstack-ai/objectstack)中公開 +開發,與構建它們的 ObjectStack 框架放在一起。**ObjectOS Cloud** 和 +**ObjectOS Enterprise** 是商業版本 —— 在同一套機制之上提供嵌入式 AI、 +託管與運維、SSO 和支援。 + +### 我能在賣給客戶的閉源 SaaS 中使用 ObjectStack 嗎? [#can-i-use-objectstack-in-a-closed-source-saas-i-sell-to-my-customers] + +可以。Apache-2.0 沒有 copyleft,也沒有版稅 —— 你不需要公開你的程式碼, +即使你的產品賺了錢,你也不欠任何費用。 + +### 我能不付費自託管 ObjectOS 嗎? [#can-i-self-host-objectos-without-paying] + +可以 —— 那就是 **ObjectOS Community**:同樣開放的機制,自託管,AI 僅通過 +MCP(自帶模型)。*需許可*的自管理版本是 ObjectOS Enterprise,它的兩個 +自管理選項(Enterprise Single-Node,或完整的 Enterprise 部署)都會 +增加產品內 AI、AI 治理和商業支援。 + +### 如果我不續約,軟體會停止工作嗎? [#does-the-software-stop-working-if-i-dont-renew] + +它永遠不會變磚。Enterprise Single-Node 會降級為免費機制的行為(付費功能 +關閉;你的資料和執行時繼續工作)。完整的 Enterprise 部署會**永久保留最後 +一個已付費的版本** —— 你失去的是更新、新的 AI 能力和支援,而不是你的 +系統。 + +### ObjectOS 會"回傳資料"嗎? [#does-objectos-phone-home] + +ObjectOS Enterprise 會線上校驗許可證;物理隔離的 Enterprise 許可證離線 +校驗。ObjectOS Community 沒有遙測,沒有許可證檢查,也沒有更新探測。 + +### 如果我想為 ObjectOS Community 獲得合同擔保怎麼辦? [#what-if-i-want-a-contractual-warranty-on-objectos-community] + +那就是 **ObjectOS Runtime Subscription** —— 針對 ObjectOS Community 的 +支援合同(官方發行版、SLA、安全補丁優先),功能上沒有任何差別。請聯絡 +[sales@objectos.ai](mailto:sales@objectos.ai)。 + +### ObjectOS Community 和框架會一直免費嗎? [#will-objectos-community-and-the-framework-always-be-free] + +會。Apache-2.0 的授予不可撤銷,所有已經發布的內容都會保持釋出時的許可。 diff --git a/content/docs/index.ja.mdx b/content/docs/index.ja.mdx index 359f7dbe..f0a8ace4 100644 --- a/content/docs/index.ja.mdx +++ b/content/docs/index.ja.mdx @@ -4,7 +4,7 @@ seoTitle: "ドキュメント:開始、構築、デプロイ、運用" description: "ObjectOS Community は無料のセルフホスト版、ObjectOS Cloud はホスト型のエディション、ObjectOS Enterprise はセルフマネージドのライセンス制のエディションです。オントロジーはあなたのものです。" editions: [community, cloud, enterprise] translation: - source_sha: a094a61ace740d1dca8c9558c150f4a779dcbc4827165c989c34ecb9554da791 + source_sha: 04e89e54c0323cd21afa4f489ef3c18ee796bb3978263e3410f4853edb98047a guide_rev: 1 mode: auto --- @@ -20,7 +20,7 @@ translation: | やりたいこと | すること | |---|---| | ObjectOS を、何もインストールせずに | **ObjectOS Cloud**、あなたのためのホスト型です。最初のアプリを構築するには Free プランで十分です。[ObjectOS Cloud で始める](/docs/start/cloud)を参照してください | -| ObjectOS を、自社のインフラストラクチャ上でライセンスを受けて | **ObjectOS Enterprise** は、シングルノードの Business Self-Managed オプション以上で、ライセンスされた Enterprise イメージをあなたのサーバー上で実行します。[ObjectOS Enterprise で始める](/docs/start/enterprise)を参照してください | +| ObjectOS を、自社のインフラストラクチャ上でライセンスを受けて | **ObjectOS Enterprise** は、Enterprise Single-Node オプション以上で、ライセンスされた Enterprise イメージをあなたのサーバー上で実行します。[ObjectOS Enterprise で始める](/docs/start/enterprise)を参照してください | | ObjectOS を、自分のマシン上で無料で | **ObjectOS Community** はオープンソースのランタイムです。`npm i -g @objectstack/cli && os start` で SQLite データベースとともに設定なしで起動します。[ObjectOS Community をローカルで実行する](/docs/start/community)を参照してください | その後、ObjectOS Cloud と ObjectOS Enterprise は同じ場所へ導きます。サインインして、次のことができます。 diff --git a/content/docs/index.zh-Hans.mdx b/content/docs/index.zh-Hans.mdx index f3396052..c49e4b2f 100644 --- a/content/docs/index.zh-Hans.mdx +++ b/content/docs/index.zh-Hans.mdx @@ -4,7 +4,7 @@ seoTitle: "文档:开始、构建、部署、运维" description: "ObjectOS Community 免费且自托管,ObjectOS Cloud 是托管版本,ObjectOS Enterprise 是自管理、需许可的版本。本体归你所有。" editions: [community, cloud, enterprise] translation: - source_sha: a094a61ace740d1dca8c9558c150f4a779dcbc4827165c989c34ecb9554da791 + source_sha: 04e89e54c0323cd21afa4f489ef3c18ee796bb3978263e3410f4853edb98047a guide_rev: 1 mode: auto --- @@ -28,7 +28,7 @@ translation: | 你想要 …… | 这样做 | |---|---| | 用 ObjectOS,什么都不装 | **ObjectOS Cloud**,为你托管 —— Free 套餐就足够构建你的第一个应用。参见[在 ObjectOS Cloud 上开始](/docs/start/cloud) | -| 在你自己的基础设施上运行 ObjectOS,获得授权许可 | **ObjectOS Enterprise**,从单节点的 Business Self-Managed 选项起步,在你的服务器上运行获得许可的 Enterprise 镜像 —— 参见[在 ObjectOS Enterprise 上开始](/docs/start/enterprise) | +| 在你自己的基础设施上运行 ObjectOS,获得授权许可 | **ObjectOS Enterprise**,从 Enterprise Single-Node 选项起步,在你的服务器上运行获得许可的 Enterprise 镜像 —— 参见[在 ObjectOS Enterprise 上开始](/docs/start/enterprise) | | 在你自己的机器上免费运行 ObjectOS | **ObjectOS Community**,开源运行时:`npm i -g @objectstack/cli && os start` 会用 SQLite 数据库、零配置启动它 —— 参见[在本地运行 ObjectOS Community](/docs/start/community) | 之后,ObjectOS Cloud 和 ObjectOS Enterprise 会把你带到同一个地方 —— 登录,然后: diff --git a/content/docs/index.zh-Hant.mdx b/content/docs/index.zh-Hant.mdx index 68b599f6..0777181f 100644 --- a/content/docs/index.zh-Hant.mdx +++ b/content/docs/index.zh-Hant.mdx @@ -5,7 +5,7 @@ seoTitle: "文件:開始、構建、部署、運維" description: "ObjectOS Community 免費且自託管,ObjectOS Cloud 是託管版本,ObjectOS Enterprise 是自管理、需許可的版本。本體歸你所有。" editions: [community, cloud, enterprise] translation: - source_sha: a094a61ace740d1dca8c9558c150f4a779dcbc4827165c989c34ecb9554da791 + source_sha: 04e89e54c0323cd21afa4f489ef3c18ee796bb3978263e3410f4853edb98047a guide_rev: 1 mode: auto --- @@ -29,7 +29,7 @@ translation: | 你想要 …… | 這樣做 | |---|---| | 用 ObjectOS,什麼都不裝 | **ObjectOS Cloud**,為你託管 —— Free 套餐就足夠構建你的第一個應用。參見[在 ObjectOS Cloud 上開始](/docs/start/cloud) | -| 在你自己的基礎設施上執行 ObjectOS,獲得授權許可 | **ObjectOS Enterprise**,從單節點的 Business Self-Managed 選項起步,在你的伺服器上執行獲得許可的 Enterprise 映象 —— 參見[在 ObjectOS Enterprise 上開始](/docs/start/enterprise) | +| 在你自己的基礎設施上執行 ObjectOS,獲得授權許可 | **ObjectOS Enterprise**,從 Enterprise Single-Node 選項起步,在你的伺服器上執行獲得許可的 Enterprise 映象 —— 參見[在 ObjectOS Enterprise 上開始](/docs/start/enterprise) | | 在你自己的機器上免費執行 ObjectOS | **ObjectOS Community**,開源執行時:`npm i -g @objectstack/cli && os start` 會用 SQLite 資料庫、零配置啟動它 —— 參見[在本地執行 ObjectOS Community](/docs/start/community) | 之後,ObjectOS Cloud 和 ObjectOS Enterprise 會把你帶到同一個地方 —— 登入,然後: diff --git a/content/docs/start/enterprise.ja.mdx b/content/docs/start/enterprise.ja.mdx index d03c5a7c..7473261e 100644 --- a/content/docs/start/enterprise.ja.mdx +++ b/content/docs/start/enterprise.ja.mdx @@ -4,12 +4,12 @@ seoTitle: "ObjectOS Enterprise で始める:ライセンス制、セルフマ description: ObjectOS Enterprise は、自社のインフラストラクチャ上で実行するライセンス制のエディションです。ライセンスの入手方法と、デプロイガイドの出発点を説明します。 editions: [enterprise] translation: - source_sha: 8c52a4becd892c980dae49189fc379a8f287109299a3350d1c2040a2595d33be + source_sha: abe6fa64f3101ed8df26acf837a707952971665ea5626794fc428c958ea55d11 guide_rev: 1 mode: auto --- -**ObjectOS Enterprise** は、商用ライセンスのもとで、あなたが運用するインフラストラクチャ上で動作する ObjectOS です。製品内の AI、AI ガバナンス、公式のサポートを自社のサーバー上で利用でき、フルのプライベートデプロイでは、クラスタリング、ひとつのデプロイ上の複数の組織、SCIM、エアギャップ運用も利用できます。完全な一覧は[エディションの比較](/docs/editions/compare)を、シングルノードの **Business Self-Managed** 以上の契約オプションは[ライセンスと料金](/docs/editions/license)を参照してください。 +**ObjectOS Enterprise** は、商用ライセンスのもとで、あなたが運用するインフラストラクチャ上で動作する ObjectOS です。製品内の AI、AI ガバナンス、公式のサポートを自社のサーバー上で利用でき、フルのプライベートデプロイでは、クラスタリング、ひとつのデプロイ上の複数の組織、SCIM、エアギャップ運用も利用できます。完全な一覧は[エディションの比較](/docs/editions/compare)を、**Enterprise Single-Node** 以上の契約オプションは[ライセンスと料金](/docs/editions/license)を参照してください。 ## 1. ライセンスを入手する [#1-get-a-license] diff --git a/content/docs/start/enterprise.zh-Hans.mdx b/content/docs/start/enterprise.zh-Hans.mdx index fecf4cb4..d4f78bd0 100644 --- a/content/docs/start/enterprise.zh-Hans.mdx +++ b/content/docs/start/enterprise.zh-Hans.mdx @@ -4,7 +4,7 @@ seoTitle: "在 ObjectOS Enterprise 上开始:许可授权,自管理" description: ObjectOS Enterprise 是你在自己的基础设施上运行的许可版本 —— 如何获得许可证,以及部署指南从哪里开始。 editions: [enterprise] translation: - source_sha: 8c52a4becd892c980dae49189fc379a8f287109299a3350d1c2040a2595d33be + source_sha: abe6fa64f3101ed8df26acf837a707952971665ea5626794fc428c958ea55d11 guide_rev: 1 mode: auto --- @@ -13,7 +13,7 @@ translation: ObjectOS:产品内 AI、AI 治理和官方支持都在你自己的服务器上;在完整的 私有部署上,还有集群、单个部署承载多个组织、SCIM 和物理隔离运行。完整 列表参见[版本对比](/docs/editions/compare),合同选项参见 -[许可与定价](/docs/editions/license),从单节点的 **Business Self-Managed** +[许可与定价](/docs/editions/license),从 **Enterprise Single-Node** 起步。 ## 1. 获取许可证 [#1-get-a-license] diff --git a/content/docs/start/enterprise.zh-Hant.mdx b/content/docs/start/enterprise.zh-Hant.mdx index 30931f0f..2af4d491 100644 --- a/content/docs/start/enterprise.zh-Hant.mdx +++ b/content/docs/start/enterprise.zh-Hant.mdx @@ -5,7 +5,7 @@ seoTitle: "在 ObjectOS Enterprise 上開始:許可授權,自管理" description: ObjectOS Enterprise 是你在自己的基礎設施上執行的許可版本 —— 如何獲得許可證,以及部署指南從哪裡開始。 editions: [enterprise] translation: - source_sha: 8c52a4becd892c980dae49189fc379a8f287109299a3350d1c2040a2595d33be + source_sha: abe6fa64f3101ed8df26acf837a707952971665ea5626794fc428c958ea55d11 guide_rev: 1 mode: auto --- @@ -14,7 +14,7 @@ translation: ObjectOS:產品內 AI、AI 治理和官方支援都在你自己的伺服器上;在完整的 私有部署上,還有叢集、單個部署承載多個組織、SCIM 和物理隔離執行。完整 列表參見[版本對比](/docs/editions/compare),合同選項參見 -[許可與定價](/docs/editions/license),從單節點的 **Business Self-Managed** +[許可與定價](/docs/editions/license),從 **Enterprise Single-Node** 起步。 ## 1. 獲取許可證 [#1-get-a-license] From 41850477a99cabcd4dce61b0032b4e175a42b82b Mon Sep 17 00:00:00 2001 From: Steedos Date: Tue, 3 Nov 2026 14:11:13 +0000 Subject: [PATCH 22/22] chore(upstream): the cloud pin moves by hand; the bump workflow moves only objectstack Maintainer ruling on #433: .cloud-sha is updated by hand when the docs are aligned with production, with no repository_dispatch from cloud and no UPSTREAM_BUMP_TOKEN for cloud. AGENTS.md 'Upstream pins' now gives the steps: the full SHA from cloud's v* tag or its deploy-cloud-prod run (the health header has only 8 characters), and the git log of CHANGELOG.md and .changeset/ pasted into the PR body. bump-upstream-pin.mjs refuses --upstream cloud with those steps, and its self-test proves the refusal; --check still validates both pins by format alone. The workflow offers only objectstack, and its token message no longer asks for cloud read access. objectstack's bump and its token requirement are unchanged. Fixes #433 Claude-Session: https://claude.ai/code/session_01QsR2jRsjbApbf83iyTDDXm Co-Authored-By: Claude --- .github/scripts/bump-upstream-pin.mjs | 73 +++++++++++++++++------- .github/workflows/bump-upstream-docs.yml | 50 ++++++++-------- AGENTS.md | 12 +++- 3 files changed, 87 insertions(+), 48 deletions(-) diff --git a/.github/scripts/bump-upstream-pin.mjs b/.github/scripts/bump-upstream-pin.mjs index cb34ec9d..04688d3a 100644 --- a/.github/scripts/bump-upstream-pin.mjs +++ b/.github/scripts/bump-upstream-pin.mjs @@ -1,7 +1,8 @@ #!/usr/bin/env node /** - * Upstream pins — move one of `.objectstack-sha` / `.cloud-sha` and write the - * pull-request body that lists what changed upstream since the previous pin. + * Upstream pins — check both `.objectstack-sha` and `.cloud-sha`, and move the + * objectstack pin, writing the pull-request body that lists what changed + * upstream since the previous pin. The cloud pin is moved by hand (below). * * ## Why this exists * @@ -12,18 +13,29 @@ * pass misses. A pin turns it into a bounded one: each file at the repository * root holds the one upstream commit the site was last aligned to, and every * alignment is a review of the upstream commits and changed paths since that - * commit. This script computes that range; `bump-upstream-docs.yml` runs it - * and opens the pull request whose body it writes. + * commit. For objectstack this script computes that range; + * `bump-upstream-docs.yml` runs it and opens the pull request whose body it + * writes. * * ## When a pin moves * * objectstack on a published `@objectstack/cli` release — the commit its * release tag `@objectstack/cli@VERSION` names. With no `--sha`, - * the release is npm's `latest` dist-tag. - * cloud after a successful cloud production deploy — the commit that - * deploy serves, never a merge to cloud's `main`. There is no - * default: the deploy supplies `--sha`, and the run refuses - * without one. + * the release is npm's `latest` dist-tag. This script moves it. + * cloud BY HAND, when someone refreshes the docs to match production — + * not on every cloud release (maintainer ruling, + * docs.objectos.ai#433). The person writes the full SHA of the + * commit production serves (cloud's `v*` tag, or its + * deploy-cloud-prod run; the health header's 8-character + * `x-objectstack-build-sha` only identifies it) and pastes + * `git log OLD..NEW -- CHANGELOG.md .changeset/` from a local + * cloud checkout into the pull-request body. No workflow, dispatch + * or token moves it, and this script refuses `--upstream cloud`: + * cloud is private and this repository holds no token to read it. + * AGENTS.md "Upstream pins" has the steps. + * + * `--check` validates both pin files the same way, by format alone; it reads + * neither upstream, so a hand-edited `.cloud-sha` passes it like any other. * * ## The pin file * @@ -31,8 +43,8 @@ * accepted value is the placeholder `unpinned`, for an upstream that has never * been pinned (`.cloud-sha` ships with it, because cloud is a private * repository this site's maintainers could not read when the pins were added). - * A range cannot start at the placeholder, so the first bump of an unpinned - * upstream only records the commit and says so; the next bump is the first + * A range cannot start at the placeholder, so the first move of an unpinned + * pin only records the commit and lists nothing; the next one is the first * bounded diff. A missing file, an empty one, an abbreviated SHA or a branch * name is refused — a pin that cannot be resolved to one commit bounds nothing. * @@ -41,8 +53,8 @@ * - the new commit is not a descendant of the current pin — the range * `OLD..NEW` would silently drop whatever `OLD` has that `NEW` lacks, and * the review would read a diff that is not the change; - * - the upstream cannot be read — cloud is private and needs `UPSTREAM_TOKEN`; - * - a cloud bump with no `--sha`. + * - the upstream cannot be read; + * - a bump of an upstream whose pin is moved by hand (cloud). * * A bump to the commit already pinned is not an error: it writes nothing, * reports `changed=false`, and the workflow opens no pull request. @@ -62,7 +74,7 @@ * * node .github/scripts/bump-upstream-pin.mjs --check * Validate both pin files. Exit 1 naming each bad one. - * node .github/scripts/bump-upstream-pin.mjs --upstream objectstack|cloud \ + * node .github/scripts/bump-upstream-pin.mjs --upstream objectstack \ * [--sha SHA] --body FILE [--git-dir DIR] * Resolve, fetch (blobless) into DIR, write the new pin and the body. * Writes `changed`, `old`, `new`, `short`, `label` and `title` to $GITHUB_OUTPUT @@ -79,19 +91,25 @@ import { spawnSync } from 'node:child_process'; const ROOT = resolve(dirname(fileURLToPath(import.meta.url)), '../..'); -/** The two upstreams. `paths` is what the alignment review reads. */ +/** + * The two upstreams. `paths` is what the alignment review reads. `byHand` marks + * a pin this script checks but never moves (docs.objectos.ai#433): its paths are + * the ones the person moving it lists with `git log` in the pull-request body. + */ const UPSTREAMS = { objectstack: { repo: 'objectstack-ai/objectstack', pinFile: '.objectstack-sha', paths: ['content/docs', 'docs/releases', 'CHANGELOG.md'], release: '@objectstack/cli', + byHand: false, }, cloud: { repo: 'objectstack-ai/cloud', pinFile: '.cloud-sha', paths: ['CHANGELOG.md', '.changeset'], release: null, + byHand: true, }, }; @@ -124,6 +142,17 @@ function parseUpstream(name) { return UPSTREAMS[name]; } +/** An upstream this script may move: declared, and not moved by hand. */ +function bumpable(name) { + const up = parseUpstream(name); + if (up.byHand) { + throw new Refusal( + `${up.pinFile} is moved by hand, not by this script (docs.objectos.ai#433): write the full SHA production serves and paste \`git log OLD..NEW -- ${up.paths.join(' ')}\` from a local checkout into the pull-request body — see AGENTS.md "Upstream pins"`, + ); + } + return up; +} + /** A `--sha` / dispatch-payload value: absent, or a full SHA. Never a ref name. */ function parseShaInput(value) { const v = (value ?? '').trim(); @@ -265,7 +294,7 @@ function readPinFile(root, up) { async function bump(opts) { const name = opts.upstream; - const up = parseUpstream(name); + const up = bumpable(name); const oldPin = readPinFile(opts.root, up); const url = `https://github.com/${up.repo}.git`; const env = gitEnv(process.env.UPSTREAM_TOKEN); @@ -274,9 +303,6 @@ async function bump(opts) { let source = 'supplied by the run that requested this bump'; let target = null; if (!newSha) { - if (!up.release) { - throw new Refusal(`a ${name} bump needs --sha: the commit its production deploy serves (there is no default)`); - } const version = await latestRelease(up.release); const tag = `${up.release}@${version}`; const ls = git(['ls-remote', url, `refs/tags/${tag}`, `refs/tags/${tag}^{}`], { env }); @@ -294,8 +320,7 @@ async function bump(opts) { const wants = kind === 'range' ? [newSha, oldPin.sha] : [newSha]; const fetched = git(['fetch', '--quiet', '--filter=blob:none', url, ...wants], { gitDir, env, allowFail: true }); if (fetched.status !== 0) { - const hint = name === 'cloud' && !process.env.UPSTREAM_TOKEN ? ' — cloud is private: set UPSTREAM_TOKEN' : ''; - throw new Refusal(`could not fetch ${up.repo} at ${wants.join(', ')}${hint}: ${(fetched.stderr || '').trim().split('\n').pop()}`); + throw new Refusal(`could not fetch ${up.repo} at ${wants.join(', ')}: ${(fetched.stderr || '').trim().split('\n').pop()}`); } git(['cat-file', '-e', `${newSha}^{commit}`], { gitDir }); @@ -433,6 +458,10 @@ function selfTest() { for (const bad of ['', 'objectui', 'toString', '__proto__', undefined]) { expectRefusal(`upstream: ${JSON.stringify(bad)}`, () => parseUpstream(bad), 'unknown upstream'); } + // Only objectstack is bumped here; the cloud pin is moved by hand (#433), and the refusal says how. + if (bumpable('objectstack') !== UPSTREAMS.objectstack) fail('bump: objectstack is not bumpable'); + expectRefusal('bump: cloud', () => bumpable('cloud'), 'moved by hand'); + expectRefusal('bump: cloud names the git log to paste', () => bumpable('cloud'), 'git log OLD..NEW -- CHANGELOG.md .changeset'); // The pin a missing file refuses is the real reader, against a real (temporary) tree. const empty = mkdtempSync(join(tmpdir(), 'pin-selftest-')); @@ -489,7 +518,7 @@ function selfTest() { process.exitCode = 1; return; } - console.log(`✓ self-test: ${total} pin/input case(s), upstream names, tag resolution, plan, body bounds and token carriage`); + console.log(`✓ self-test: ${total} pin/input case(s), upstream names, the hand-moved cloud pin, tag resolution, plan, body bounds and token carriage`); } /* ------------------------------------------------------------------ main -- */ diff --git a/.github/workflows/bump-upstream-docs.yml b/.github/workflows/bump-upstream-docs.yml index 60cd70be..510561f2 100644 --- a/.github/workflows/bump-upstream-docs.yml +++ b/.github/workflows/bump-upstream-docs.yml @@ -1,45 +1,45 @@ name: Bump upstream docs pin -# Moves ONE upstream pin — `.objectstack-sha` or `.cloud-sha` — and opens a -# pull request whose body lists the upstream commits and changed paths since -# the previous pin. That body is the alignment review's input: the site is -# checked against a bounded diff instead of a periodic re-read of both corpora. -# The rules for when each pin moves, and what the body lists, are in the header -# of `.github/scripts/bump-upstream-pin.mjs`; AGENTS.md has the short form. +# Moves the objectstack pin, `.objectstack-sha`, and opens a pull request whose +# body lists the upstream commits and changed paths since the previous pin. +# That body is the alignment review's input: the site is checked against a +# bounded diff instead of a periodic re-read of the corpus. The rules are in the +# header of `.github/scripts/bump-upstream-pin.mjs`; AGENTS.md has the short form. # # objectstack on a published `@objectstack/cli` release. With no `sha`, the # run pins the commit tagged with npm's `latest` release. -# cloud after a successful cloud production deploy, to the commit that -# deploy serves. `sha` is required; the run refuses without it. +# +# The cloud pin, `.cloud-sha`, is NOT moved here: it is moved by hand when the +# docs are refreshed to match production (maintainer ruling, +# docs.objectos.ai#433), and the helper refuses `upstream: cloud`. AGENTS.md +# "Upstream pins" has the steps. This workflow still checks its format. # # Triggers: `workflow_dispatch` by hand, or `repository_dispatch` of type -# `bump-upstream-docs` with `client_payload: { upstream, sha }` — the shape a -# deploy or release workflow elsewhere sends. On a pull request that touches the -# pins, the helper or this file, the `pins` job runs the helper's self-test and -# checks both pin files. +# `bump-upstream-docs` with `client_payload: { upstream: objectstack, sha }` — +# the shape a release workflow elsewhere sends. On a pull request that touches +# the pins, the helper or this file, the `pins` job runs the helper's self-test +# and checks both pin files by format alone; it reads neither upstream. # # ⛔ One secret, `UPSTREAM_BUMP_TOKEN`, and the bump refuses to start without -# it. It is used for two things `GITHUB_TOKEN` cannot do here: -# - read `objectstack-ai/cloud`, a private repository (contents: read there); -# - push the bump branch and open the pull request (contents: write and -# pull-requests: write here). A pull request opened with `GITHUB_TOKEN` -# starts no `pull_request` workflows — GitHub suppresses them to prevent -# recursive runs — so CI would never run on the bump, and whether this -# repository lets Actions open pull requests at all is a repository setting. +# it. It pushes the bump branch and opens the pull request (contents: write and +# pull-requests: write here), which `GITHUB_TOKEN` cannot do usefully: a pull +# request it opens starts no `pull_request` workflows — GitHub suppresses them +# to prevent recursive runs — so CI would never run on the bump, and whether +# this repository lets Actions open pull requests at all is a repository +# setting. on: workflow_dispatch: inputs: upstream: - description: Which pin to move + description: Which pin to move (the cloud pin is moved by hand, see AGENTS.md) type: choice - options: [objectstack, cloud] + options: [objectstack] required: true sha: description: >- - Full 40-character commit SHA to pin. Required for cloud (the commit its - production deploy serves). Leave empty for objectstack to pin npm's - latest @objectstack/cli release. + Full 40-character commit SHA to pin. Leave empty to pin npm's latest + @objectstack/cli release. type: string required: false repository_dispatch: @@ -96,7 +96,7 @@ jobs: UPSTREAM_BUMP_TOKEN: ${{ secrets.UPSTREAM_BUMP_TOKEN }} run: | if [ -z "$UPSTREAM_BUMP_TOKEN" ]; then - echo "::error title=NOT CONFIGURED::The repository secret UPSTREAM_BUMP_TOKEN is not set. It needs contents: read on objectstack-ai/cloud and contents: write + pull-requests: write on this repository. GITHUB_TOKEN is not a substitute: it cannot read cloud, and a pull request it opens runs no CI." + echo "::error title=NOT CONFIGURED::The repository secret UPSTREAM_BUMP_TOKEN is not set. It needs contents: write + pull-requests: write on this repository. GITHUB_TOKEN is not a substitute: a pull request it opens runs no CI. (The cloud pin needs no token: it is moved by hand, see AGENTS.md.)" exit 1 fi diff --git a/AGENTS.md b/AGENTS.md index 033e8d05..70b0235d 100644 --- a/AGENTS.md +++ b/AGENTS.md @@ -103,7 +103,17 @@ node .github/scripts/check-translations.mjs --worklist # what the next pass wil ## Upstream pins -`.objectstack-sha` and `.cloud-sha` at the repository root each hold one full commit SHA: the commit of `objectstack-ai/objectstack` and of `objectstack-ai/cloud` this site was last aligned to. The objectstack pin moves when an `@objectstack/cli` release is published, to the commit its release tag names; the cloud pin moves after a successful cloud production deploy, to the commit that deploy serves — never on a merge to cloud's `main`. ⛔ Don't edit a pin by hand: `.github/workflows/bump-upstream-docs.yml` (run by hand, or a `repository_dispatch` of type `bump-upstream-docs` with `{ upstream, sha }`) moves one pin and opens a PR whose body lists the upstream commits and changed paths since the previous pin — objectstack: `content/docs`, `docs/releases`, `CHANGELOG.md`; cloud: `CHANGELOG.md`, `.changeset/`. That list is the alignment review's input: update the English pages it affects before the pin lands. `.cloud-sha` holds the placeholder `unpinned` until its first bump, which records a commit and lists nothing. The rules live in the header of `.github/scripts/bump-upstream-pin.mjs`. +`.objectstack-sha` and `.cloud-sha` at the repository root each hold one full commit SHA: the commit of `objectstack-ai/objectstack` and of `objectstack-ai/cloud` this site was last aligned to. What changed upstream between the old pin and the new one is the alignment review's input: update the English pages it affects before the pin lands. + +**The objectstack pin** moves when an `@objectstack/cli` release is published, to the commit its release tag names. ⛔ Don't edit it by hand: `.github/workflows/bump-upstream-docs.yml` (run by hand, or a `repository_dispatch` of type `bump-upstream-docs` with `{ upstream: "objectstack", sha }`) moves it and opens a PR whose body lists the upstream commits and changed paths since the previous pin in `content/docs`, `docs/releases` and `CHANGELOG.md`. Opening that PR needs the repository secret `UPSTREAM_BUMP_TOKEN`. + +**The cloud pin moves by hand** (maintainer ruling, #433): when someone refreshes the docs to match production, not on every cloud release. No workflow, dispatch or token moves it. To move it: + +1. Take the full 40-character SHA of the commit production serves: `git rev-parse vX.Y.Z^{commit}` on cloud's `v*` release tag, or the commit of cloud's `deploy-cloud-prod` run. The `x-objectstack-build-sha` header of `https://cloud.objectos.ai/api/v1/health` has only the first 8 characters: it tells you which commit, but it is not a pin. +2. Write that SHA to `.cloud-sha` as the file's only line. +3. In the PR body, paste the output of `git log .. -- CHANGELOG.md .changeset/`, run in a local cloud checkout. That list is the alignment review's input. The first hand update, from the placeholder `unpinned`, has no previous commit, so it lists nothing. + +On a PR that touches a pin, the `pins` job checks the format only (a full lowercase SHA, or `unpinned`) and reads neither upstream. The rules live in the header of `.github/scripts/bump-upstream-pin.mjs`. ## Commands