# 表とデータの更新

基盤のデータは、表（collection）に入っています。表は、列（項目）と行（1件分のデータ）でできています。このページでは、表を読み、行を追加・更新・削除する方法を説明します。

基盤には、v1の顧客が定義する表と、v2の業務表を扱うAPIがあります。パスや版の意味が違うため、使う系列を混ぜずに実装します。選び方は、[共通ルール](concepts.md)にあります。

操作は、利用者の権限（またはserviceの承認）の範囲で、行います。権限がない表や列は、見えず、書けません。

## 読み取りから始める

1. 利用できる表の一覧を取得します（次の例はv1）。
2. 表の定義（definition）を読みます。画面に表示する名前（ラベル）とは別に、変わらない項目のID（field ID）と、型、権限を保持します。
3. 検索の条件、`sort`、`cursor`を指定して、行を取得します。応答の列は、現在の権限で、絞り込まれています。

```http
GET /v1/tables
GET /v1/tables/work_notes
POST /v1/tables/work_notes/query
```

`work_notes`は、説明用の表の名前です。実際に使える表は、対象の利用環境の一覧で確認します。

v2の系列では、次のように読み取ります。

```http
GET /v2/tables
GET /v2/tables/work_notes
POST /v2/tables/work_notes/query
GET /v2/tables/work_notes/rows/{rowId}
```

応答の`schema_version`と、行の`version`を保存します。書き込みで使います。

## 行を追加・更新する

[HTTP・実行例](examples.md)に、次の完全なHTTPのリクエストと応答があります。

- v1: 表の一覧、検索、batch（まとめての更新）
- v2: 表の定義、作成、更新、削除、復元、関連、`If-Match`

書き込みのbatchには、`Authorization`、`Content-Type`、`Idempotency-Key`を付けます。本文には、現在の`schema_version`と、操作ごとの`version`を指定します。

- v1の新しい行のidは、クライアントが作ります。v2では、基盤が作ります。混同しないでください。
- 省略、`null`、空文字は、別の値として扱われます。

## ヘッダーの値は、どこから得るか

| ヘッダー | 値 |
| --- | --- |
| `Idempotency-Key` | 書き込みの操作ごとに、新しく作る。8〜128文字の`-`、英数字、`_`。service申請では、UUID |
| `X-Parent-Version`（画像の操作） | 画像のpolicyで返る、親の行の版 |
| `X-Schema-Version`（画像の操作） | 表の定義の`schema_version`（policyや行の取得で得た値） |
| `If-Match` | 次の操作が要求します。表の定義の更新（`PUT /v2/tables/{collection}`）、関連の設定（`PUT /v2/tables/{collection}/access`）、画像の操作、v1のケース（ジョブ）の更新（`PATCH /v1/jobs/{id}`）。`"0"`のように、版を二重引用符で囲みます。画像の新規は`"0"`です |

v2の行の更新と削除（batch）では、`If-Match`は使いません。本文の`version`に、取得した行の版を指定します。

## 版と再送のキー

更新の競合を防ぎ、二重の実行を防ぐために、次の値を使います。

| 値 | 意味 |
| --- | --- |
| `schema_version` | 列や型など、表の定義の版 |
| 行の`version` | その行の更新の競合を確認する版 |
| `If-Match` | 操作の仕様が要求する、期待する版 |
| `Idempotency-Key` | 同じ操作の再送を見分けるキー |

更新と削除は、取得した現在の版と、操作の内容を固定して送ります。通信が途切れたときは、結果が不明のことがあります。同じ操作を別のキーで作り直す前に、状態を確認します。412が返ったときは、対象を再取得し、差分を利用者に確認してから、次の操作を決めます。詳しくは、[競合・再送・復帰](reliability.md)にあります。

## v2の表の定義

v2の表は、`PUT /v2/tables/{collection}`で定義します。本文の形は、APIリファレンスの`WorkspaceDefine`です。同じOpenAPIにある`Field`・`Define`・`Definition`は、v1の表（`/v1/tables/…`）の形で、型が5つ、役割が3つに限られています。v2の表では、`Workspace`で始まる形を見てください。

1つの表の列は、64までです。

### IDの決まりと、使えない名前

- 表・列・役割・アプリのIDは、`^[a-z][a-z0-9_-]{0,47}$`の形です。英小文字で始め、英小文字・数字・`_`・`-`で、48文字までです。この形に合っていても、`constructor`と`prototype`は使えません。
- 列のIDに、`id`・`owner_id`・`version`・`status`・`closed`は使えません。行そのものが持つ項目の名前です。
- 役割の名前に、`owner`は使えません。`owner`は、列の`read`・`write`で、行を作った人を表す名前です（下の「列の権限と、行を作った人」）。
- 1つの列の`read`と`write`に並べられる役割は、それぞれ32までです。`write`に並べた役割は、`read`にも並べます。

| 型 | 値 |
| --- | --- |
| `text` | 文字。4,096文字まで |
| `number` | 数 |
| `money_jpy` | 円の金額。整数 |
| `date` | 日付。`YYYY-MM-DD` |
| `time` | 時刻。`HH:MM:SS` |
| `duration` | 時間の長さ。秒の整数 |
| `boolean` | はい・いいえ |
| `choice` | 決めた選択肢の1つ。選択肢は300まで |
| `case_ref` | ケースを指す。値は、ケースの`id`（UUID）で、表示用の番号ではありません |
| `asset_ref` | 画像・添付の入れ物。値はbatchで書かず、[画像・添付](media.md)の操作で結びつけます |

`text`の値に、U+0000（NUL）の文字を含めることはできません。含めて送ると、500（`INTERNAL_CONTRACT_VIOLATION`）で拒否されます。元のデータから取り込むときは、送る前に取り除きます。

1つのセルには、文字・数・真偽・`null`のどれか1つが入ります。1つのセルに、複数の値は入りません。複数の値は、別の表の行に分けます。

### 必須、保存の状態、締め

- 列ごとに、必須（`required`）を決めます。
- 行は、必須の列が空でも保存できる`draft`と、必須の列を検査する`committed`の、どちらかで保存します。業務の進み具合（受注・納品など）は、これとは別の列で持ちます。
- 行を締める（`close`）と、変更できなくなります。締める・締めを外す（`reopen`）には、どちらも理由が必要です。締めてよいかは、権限の`can_close`で決まります。

### 自動で計算する列

`duration`の列は、同じ行の開始と終了の`time`の列から、自動で計算できます（`computed`。日をまたぐ場合は`overnight`）。そのほかの式（合計・税込・率など）の列はありません。アプリで計算します。

### 列の権限と、行を作った人

- 列ごとに、読める役割（`read`）と書ける役割（`write`）を並べます。役割の名前は、業務に合わせて決めます（例: `sales`、`accounting`）。
- `owner`は、その行を作った人を表します。担当者や作業者とは別です。取り込み（import）で入れた行は、取り込んだ人が`owner`になります。そのため、見る範囲が`own`の利用者には、管理者など、ほかの人が取り込んだ行は見えません。
- 利用者には、表ごとに役割と、見る範囲（`read_scope`: `own`＝自分が作った行、`all`）と、書く範囲（`write_scope`: `none`・`own`・`all`）を与えます。役割は表ごとの名前で、1人が1つの表で持てる役割は1つです。手順は、[アプリの登録と運用](tutorial.md)の「利用者に権限を与える」にあります。
- 列の値で、書ける行を分けることはできません（例: 「部署」の列が自分の部署の行だけを書ける、という設定はありません）。分けたいときは、表を分けるか、書ける役割を絞ります。
- 列の権限は、利用者に与えた役割ごとに決まります。画面ごとに変えることはできません。集計も、読める列でしかできません。
- 行を削除するには、削除の範囲（[アプリの登録と運用](tutorial.md)の「利用者に権限を与える」）に加えて、その行の、自動で計算する列を除く、すべての列に書く権限が必要です。足りないときは、`FIELD_NOT_WRITABLE`で拒否されます。

### 行がある表の定義を変える

- 行がある表でも、列の`read`・`write`の役割は、足すことも減らすこともできます。
- 行がある表では、列を消すこと、必須（`required`）の列を足すこと、今ある列の型・選択肢・必須・自動で計算する設定を変えることは、できません。409（`STATE_CONFLICT`）で拒否されます。
- アプリに登録した表の定義は、持ち主のアプリの`version`を1つ上げたmanifestで、計画と適用をして変えます。手順は、[アプリの登録と運用](tutorial.md)の「アプリを計画して登録する」にあります。

## アプリと共有の表

- 1つのアプリに登録できる表は、32までです。アプリが持つ表（`owned`）と、ほかのアプリの表を使う共有の表（`shared`）の、両方を数えます。依存先（`dependencies`）も、32までです。
- 共有の表は、manifestに、持ち主のアプリの表の定義と、まったく同じ定義を書きます。列の役割の名前も、持ち主の定義に合わせます。違うときは、409（`STATE_CONFLICT`）で拒否されます。
- 共有の表の持ち主のアプリと、依存先のアプリが、使える状態（`active`）でないと、登録できません。
- 持ち主のアプリが表の定義を変えた後に、共有しているアプリを更新するときは、新しい定義をmanifestに書きます。

## ケースと番号

- ケースを作ると、決めた系列の番号が振られます（`POST /v2/cases`）。番号の頭・桁・期間（年など）は、採番の設定（`PUT /v2/number-series/{series}/{period}`）で決めます。期間が変わったときは、新しい期間の設定で切り替えます。
- 今ある番号は、振り直さずに取り込めます（`POST /v2/cases/import`。取り込みの権限と`Idempotency-Key`が必要です）。
- ケースが持つのは、番号・件名・状態です。そのほかの情報は、業務表の行に置き、`case_ref`の列でケースを指します。表どうしは、表示用の番号ではなく、ケースの`id`でつなぎます。
- ケースの件名を変える操作は、ありません。変わる可能性がある名前は、業務表の列に置きます。

## 関連（親と子）と所属

- 子の表を、親の表に結びつけます（子の表の`PUT /v2/tables/{collection}/access`）。行どうしは、子の表の`text`の列に、親の行の`id`を持ってつなぎます。1対1（`one`）か1対多（`many`）で、1段までです。親は、v2の業務表の行です。ケースではありません。
- 所属の方式（`mode`が`members`）では、親の行ごとに、見てよい人（所属者）を登録できます（親の表の`PUT /v2/tables/{collection}/members/{scopeId}/{actorId}`。`scopeId`は親の行の`id`）。読むだけの所属者も登録できます。所属者にしても、親と子の表の権限と、列の権限は、別に必要です。
- 新しい親の行と、それを指す子の行を、1つの要求で作ることはできません。親を作ってから、子を作ります。
- 関連（`access`）、所属（`members`）、複数の表のまとめての更新（`POST /v2/transactions`）、行の変更のevents（`POST /v2/tables/{collection}/events`）は、0.7では試験提供の印がある機能です。利用環境で有効になっている場合に使えます。どれも利用者のログインで使う操作で、serviceでは使えません。
- transactionは、最大8表（同じ表は1回まで）、合わせて100操作までです。1つでも失敗すると、すべての変更が反映されません。
- eventsは、行が作られた・更新された・削除されたという印を、アプリが取りに行く形（pull型）です。Webhookのように、基盤からアプリへ送る仕組みではありません。続きを読む位置の印（`cursor`）は、24時間で使えなくなります。権限が変わったときも使えなくなり（409 `CURSOR_STALE`）、先頭から読み直します。関連・所属の設定（policy）が変わったときは、変わる前のイベントは届かないため、先頭から読み直すだけでは今の状態になりません。`query`で今の行を取り直します。同じイベントを2回受け取ることがあるので、イベントのIDで重複を除きます。

## 上限

表ごとの上限は、表の定義の応答（`GET /v2/tables/{collection}`）の`limits`で返ります。

- 1回の書き込み（batch）は100操作まで、1回の読み取りは199行までです。
- 取り込み（`POST /v2/tables/{collection}/import`）は、batchと同じ本文の形で、1回100操作までです。書き込みの権限に加えて、取り込みの権限（`can_import`）が必要です。
- 1回のリクエストには、処理の時間の上限があります。行の多い表では、操作の多いbatchや取り込みが上限を超えて、503（`TX_ABORT_UNCONFIRMED`など）になることがあります。反映されたかは、行の再取得で確かめます。同じキーと本文で再送すると、反映済みなら前回の結果が返り、未反映なら同じ大きさのまま改めて実行されるため、また上限を超えることがあります。未反映を確かめたうえで、1回の操作の数を減らして送り直すときは、本文が変わるので、新しいキーを使います。詳しくは、[競合・再送・復帰](reliability.md)にあります。
- 利用者が見られる範囲の全体が、25,000行・32MiBのどちらかを超えると、検索も集計もできなくなります。絞り込みでは避けられません。行が増え続ける表は、年度ごとに表を分けるなど、先に決めておきます。

## 変更の確認と、記録

- `GET /v2/tables/{collection}/changes`は、表が変わったかを確かめる版だけを返します。
- `POST /v2/tables/{collection}/events`は、どの行が、どの版で、作られた・更新された・削除されたかを返します。誰が、どの値に変えたかは返しません。行の内容は、改めて取得します。
- 誰が、いつ、何に、どんな操作をしたかは、管理者が`POST /v2/organization/activity`で確認できます。業務の値や、変更の前後は返しません。

## v2の業務表、関連、ごみ箱

v2では、業務表、ケース、関連（表どうしの親子の関係）、transaction（複数の表のまとめての更新）、履歴、ごみ箱と復元の操作を提供します。パスとschemaは、[APIリファレンス](../openapi.json)で、「業務表・ケース」または「関連・所属」を選んで確認します。通しの手順は、[アプリの登録と運用](tutorial.md)にあります。

削除と、原本の物理的な削除は、同じ意味ではありません。ごみ箱、添付の解除、外部の原本の保持を、区別して扱います。

## CSVとAIからの更新

現在の取込MCPは、登録されたデータの形式に対して、CSVの検査、差分の計画、確認の後の反映、照合、出力を行います。計画を作っただけでは、業務表に反映されません。詳しくは、[MCPの導入](mcp.md)にあります。
