# 仕組み

> 送信データが通過するすべてのチェックを順番に、それぞれが返しうる応答とあわせて説明します。

`/f/<formId>` への送信は、すべて同じパイプラインを通ります。コストの低いチェックから先に実行するので、大量送信や存在しないフォームへの送信にはほとんどコストがかかりません。最初に失敗したチェックが応答を決めます。

パイプライン（順番どおり）:

1. IP 大量送信ガード: フォームを検索する前に、1 つの IP から全フォーム合計で 1 分あたり最大 600 件。超えると `429 rate_limited`。
2. フォームの検索: 存在しない、削除済み、無効なフォームは `404 not_found`。
3. フォームのレート制限: フォームのプリセットで、訪問者の IP ごととフォームごとにカウント。超えると `429 rate_limited`。
4. 一時停止中のフォームは `403 form_paused`。
5. ボディの解析: urlencoded、multipart、JSON で、最大 256 KB。失敗すると `415`、`400 invalid_body`、`413 payload_too_large`、`422 too_deep`、`422 files_not_supported` のいずれか。
6. API キー（`Authorization` ヘッダーが送られた場合）。失敗すると `403 forbidden` または `403 origin_not_allowed`。
7. 許可ドメイン: 他のサイトからの送信はスパムとして保存されるか、`403 origin_not_allowed` になります。
8. 人間確認: 失敗すると `403 challenge_required` または `403 captcha_failed`。ブラウザーからのフォーム送信には、代わりに確認ページが表示されます。
9. フィールドのバリデーション: 失敗すると `422 validation_failed`。
10. スパムスコア: スコアが 5 以上ならスパムとして保存されますが、応答は成功として返します。
11. 冪等性: 同じキーが繰り返されると最初の応答を再送するか、`409` または `422` になります。
12. 月間の使用量: 上限を大きく超えている場合は `429 quota_exceeded`。
13. 保存: 送信 ID 付きの `201`、ブラウザーからの送信には `303` リダイレクト。その後、Webhook、通知メール、ダッシュボードのリアルタイム更新が続きます。

## 各ステージの役割

### 何よりも先にレート制限

レート制限はボディを読む前に実行されます。大量送信ガード（IP ごとに 1 分あたり 600 件）はフォームの検索よりも前に動くので、大量送信がデータベースに届くことはありません。フォーム独自のルールは検索の直後に実行されます。拒否されたリクエストは許容量を消費しません。正確な数値は[レート制限](https://ikiform.com/ja/docs/rate-limits.md)にあります。

### 解析

ボディは urlencoded、multipart、JSON として解析されます。テキストは UTF-8 としてデコードされ、NFC に正規化され、CRLF は LF に変換され、制御文字は削除されます。`_` で始まる名前は `_redirect` や `_subject` などの予約済みの指示で、回答として保存されることはありません。[HTML フォーム](https://ikiform.com/ja/docs/html.md#reserved-fields)を参照してください。

### 送信元の判定

`Authorization: Bearer` ヘッダーは任意です。`submissions:write` スコープを持つシークレットキー（`ik_sk_`）は、許可ドメインのチェックと Ikiform の人間確認をスキップします。公開可能キー（`ik_pub_`）は、キーに登録されたドメインからのみ使えます。キーがない場合は、`Origin` で送信を判定します。

### スパム

スパムがエラーになることはありません。スパムモードで許可ドメインのポリシーに違反した送信や、スコアが 5 以上の送信は、ステータス `spam` で保存され、本物の送信と同じ成功の応答を返すので、ボットは何も学べません。スパムは Webhook もメールも送らず、使用量にもカウントされません。[スパム対策](https://ikiform.com/ja/docs/spam.md)を参照してください。

### 保存と配信

送信データ、その Webhook の配信、通知メールは 1 回のデータベースバッチで書き込まれ、キューに渡されます。Webhook の配信やメールが応答を遅くすることはなく、配信なしで送信データだけが保存されることもありません。

## JSON かリダイレクトか

同じエンドポイントが、ブラウザーにはページで、コードには JSON で応答します。Ikiform はリクエストごとに判断します:

| リクエスト | 応答 |
| --- | --- |
| `Accept` に `application/json` が含まれる | JSON |
| ボディが JSON | JSON |
| `Sec-Fetch-Mode: navigate`（通常のフォーム送信） | リダイレクトまたはホストされたページ |
| それ以外の `Sec-Fetch-Mode`（`fetch` からの `cors` など） | JSON |
| `Sec-Fetch-Mode` がなく、`Accept` に `text/html` が含まれる | リダイレクトまたはホストされたページ |
| それ以外すべて（curl など） | JSON |

JSON モードでは、成功すると `201 { "ok": true, "id": "sub_..." }` を返します。ページモードでは成功すると `303` リダイレクトになり、エラー時はフィールドの問題をラベルごとに一覧にした、ホストされたエラーページを表示します。

## 送信データの保存後

| 内容 | タイミング | 詳細 |
| --- | --- | --- |
| Webhook | 数秒後。約 3 日間リトライ | [Webhook](https://ikiform.com/ja/docs/webhooks.md) |
| 通知メール | 数秒後（フォームで通知がオンの場合） | フォームごとに 1 時間あたり 50 通まで（作成から 7 日未満のワークスペースは 10 通）。それを超えると 1 時間ごとのダイジェスト 1 通 |
| ダッシュボード | すぐに、リアルタイムで | スパムはスパムフィルターの下に表示 |
| REST API | すぐに | [REST API](https://ikiform.com/ja/docs/api.md) |

> パスワード、カード番号、シードフレーズのようなフィールド名を含む送信データがあるフォームにはフラグが付き、通知メールは確認のため保留されます。フォームバックエンドで認証情報を集めないでください。

## ID

| ID | 形式 | メモ |
| --- | --- | --- |
| フォーム | `frm_xxxxxxxxxxxxxxxx` | `frm_` に続くランダムな 16 文字。公開情報で、フォームの action の URL に含まれます。 |
| 送信データ | `sub_01k7v2c9t3e8m5q4x6z0a1b2c3` | `sub_` に続く 26 文字で、時刻順に並びます。 |
| Webhook の配信 | `dlv_...` | `webhook-id` として送られ、リトライしても変わりません。 |
| リクエスト | `req_...` | すべてのレスポンスに `X-Request-Id` ヘッダーが付きます。サポートに問い合わせるときに伝えてください。 |

**201** (`JSON での成功`)

```json
{ "ok": true, "id": "sub_01k7v2c9t3e8m5q4x6z0a1b2c3" }
```

**303** (`ブラウザーでの成功`)

```http
HTTP/1.1 303 See Other
Location: https://example.com/thanks
X-Request-Id: req_01k7v2c9t3e8m5q4x6z0a1b2c3
```
