# monaka: DKIM 署名基盤ゾーン（Cloudflare 委任＋自動 TXT）

**対象**: monaka 運用者（`monaka-app.com` の DNS・Cloudflare・アプリサーバ `.env` を扱う人）  
**目的**: 利用者が「送信ドメイン認証」でドメインを追加するたびに、**手で TXT を足さず**、署名基盤ホスト（`MONAKA_DKIM_SIGNING_HOSTNAME`、例: `dkim.tools.monaka-app.com`）配下の **DKIM 公開鍵 TXT** を Cloudflare API で自動登録する。

**この手順書の方針**: 「どのサービスの **どの画面のどこ** を見るか」を省略しない。推測で別メニューに入らないこと。

**送信ドメイン認証まわりの共通方針（繰り返し）**: 利用者に **サーバの `.env` を触らせない**。運用側の既定は **`config/putage.php` とデプロイ**で揃える。短い正本は **`docs/mail-auth-ops-defaults.md`**。

### 説明・チャットでの運用ルール（AI・社内どちらでも）

運用者へ手順を伝えるとき（チャット・Slack・チケット・口頭）は、**次を必ずセットで書く**。「どこを見るか」だけ省略しないこと。

| 必須に含めること | 例 |
|------------------|-----|
| **サービス名** | Cloudflare／お名前.com／アプリサーバ |
| **画面にたどり着く経路** | 左メニュー「アカウント ホーム」→ 中央の「ドメイン」カード |
| **見るラベル・ボタン名** | 「ドメインを追加」「概要」「ネームサーバー」「DNS → レコード」 |
| **成功／失敗の見え方** | 一覧に `tools.monaka-app.com` が出る／地球アイコンと「ドメインを追加」だけなら **まだゾーン無し** |

**禁止例**: 「Cloudflare で確認して」「DNS を見て」だけ書いて終わらせない。

---

## 全体像（B案：影響範囲が小さい委任）

1. Cloudflare に **ゾーン `tools.monaka-app.com`** がある（**ダッシュボードのサイト一覧**に表示される）。
2. お名前.com 側で **`tools` の NS 委任** → Cloudflare のネームサーバ 2 本を指定する。
3. アプリ `.env` に API トークンとゾーン名を設定し、`monaka:dkim-sync-cloudflare` で TXT を載せる。
4. 以後は認証ドメイン追加時に自動 upsert。

---

## Cloudflare：どこを見るか・どこに入らないか（最重要）

UI は日本語／英語でラベルが違うことがあります。**見ている場所が違うと毎回不毛になる**ので、次で照合する。

### やってはいけない場所（今回の作業とは別）

| 見ている場所 | なぜダメか |
|--------------|------------|
| 左メニュー **ドメイン → 登録** | Cloudflare でドメインを **購入／レジストラ登録**する画面。**DNSゾーン管理とは別**。 |
| 右上 **＋ 追加 → Pages / Workers / R2** など | アプリホスト／サーバレス。**DNS委任・TXT自動登録の本体ではない**。 |
| **ドメインを接続**ウィザードに **`tools.monaka-app.com`** だけ入力 | **サブドメインだけは拒否**され、「ルートドメインを」と言われる。**B案ではウィザードは使わない**（ゾーンは API で作成する）。 |

### 正しい見る場所一覧（チェックリスト）

#### A. ゾーン `tools.monaka-app.com` が **もう存在するか** 確認する（手順の「1」相当）

**見る場所（Cloudflare）**:

1. ブラウザで Cloudflare にログインする。
2. 左サイドバーで **アカウント ホーム**（英語 UI では **Account home**）をクリックする。  
   ※ 複数アカウントがある場合は、右上またはサイドバーで **対象アカウント** が monaka 用になっていることを確認する。
3. メインエリアの **ドメイン一覧**（カード／表でドメイン名が並ぶ領域）を見る。  
   - 日本語 UI では画面上部〜中央に **「ドメイン」という見出しの白いカード**があり、その中にサイト一覧が載る構成になっていることがある。  
   - **ここに `tools.monaka-app.com` と書かれた行／カードがあるか**を確認する。

**空の状態の見分け（スクショでよくあるパターン）**:

**見る場所**: 左 **アカウント ホーム** のまま、メインの **「ドメイン」カード**だけを見る。

**この見た目ならゾーンはまだ無い**:

- カードタイトルが **「ドメイン」**
- 中央に **地球のワイヤーフレームアイコン**
- 文言に **「お客様のサイトを、より高速かつ安全に」** のような説明
- ボタンが **「ドメインを追加」** だけで、その **上や下にドメイン名の一覧行が無い**

→ **ゾーン `tools.monaka-app.com` は未作成**。この **`ドメインを追加` ボタンは押さない**（ウィザードに入り、`tools.monaka-app.com` は入力できない。**B案では API でゾーン作成**する）。

**判定**:

- **一覧に `tools.monaka-app.com` がある** → ゾーン作成済み。**ネームサーバー確認**へ進む（下記 B）。
- **上記の空カードだけ**、または **`tools.monaka-app.com` が一覧に無い** → まだゾーンが無い。本文書の **「ゾーン作成（API）」** を実行する（ウィザードでは作成しない）。

#### B. ネームサーバー（NS）の **2 本**を確認する（お名前.com に書く値）

**見る場所（Cloudflare）**:

1. 左サイドバー **アカウント ホーム** でドメイン一覧から **`tools.monaka-app.com` をクリック**して、そのゾーンのダッシュボードへ入る。
2. 右カラムまたは画面上部付近の **概要**（英語 **Overview**）を開く（ゾーンを開いた直後が概要であることが多い）。
3. **ネームサーバー**（英語 **Nameservers**）に **ホスト名が 2 行**出ている。その **2 本まるごと**をメモする（例: `xxxx.ns.cloudflare.com`）。

この 2 本が、お名前.com で **`tools` に設定する NS レコードの値**になる。

#### C. DNS レコード（TXT が載ったか）を確認する

**見る場所（Cloudflare）**:

1. ゾーン **`tools.monaka-app.com`** を開いた状態で、左メニュー **DNS** → **レコード**（英語 **DNS → Records**）。
2. 一覧に **`タイプ TXT`** で、**名前** が `{セレクター}.dkim.tools.monaka-app.com`（またはゾーン相対で `{セレクター}.dkim`）のレコードが増えているか確認する。  
   ※ アプリの `php artisan monaka:dkim-sync-cloudflare` 実行後に現れる。

#### D. API トークンを発行／確認する

**見る場所（Cloudflare）**:

1. 右上の **プロフィールアイコン** をクリック。
2. **マイプロフィール**（英語 **My Profile**）。
3. タブ **API トークン**（英語 **API Tokens**）。
4. **トークンを作成** または既存トークンの一覧で **権限** を確認する。

（権限の細かい選び方は後述「API トークン」。）

---

## Cloudflare：ゾーン作成（B案／ウィザードは使わない）

ダッシュボードの **ドメインを接続** は **`tools.monaka-app.com` を入力できない**（ルートのみ許可のため）。  
**ゾーン `tools.monaka-app.com` は API で作成する**。

前提:

- **Account ID**: Cloudflare の **アカウント ホーム** で対象アカウントを選び、右サイドバーまたは概要に出る **アカウント ID** をコピーする。  
  または **マイプロフィール → API → アカウントの詳細** で確認できることがある。

コマンド例（トークンと Account ID は自分の値に差し替え。**値はチャットやチケットに貼らない**）:

```bash
export CF_TOKEN='APIトークン文字列'
export CF_ACCOUNT_ID='アカウントID'

curl -sS -X POST "https://api.cloudflare.com/client/v4/zones" \
  -H "Authorization: Bearer ${CF_TOKEN}" \
  -H "Content-Type: application/json" \
  --data "{\"name\":\"tools.monaka-app.com\",\"account\":{\"id\":\"${CF_ACCOUNT_ID}\"},\"jump_start\":false}"
```

レスポンス JSON で `"success": true` と、`result.name_servers` に **NS が 2 本**あれば成功。その NS をお名前.com に書く。

作成後、**アカウント ホームのドメイン一覧**に `tools.monaka-app.com` が現れることを **必ず目視確認**する（上記 A）。

---

## Cloudflare：API トークン（権限の目安）

**マイプロフィール → API トークン → カスタムトークンを作成** で最低限:

| 権限の並び（例） | 用途 |
|------------------|------|
| **ゾーン → DNS → 編集** | DKIM の TXT を upsert／削除するため **必須**。 |
| **ゾーン → ゾーン → 読み取り** | Zone ID 取得のため **推奨**。 |

**ゾーン リソース**:

- ゾーン未作成時は **すべてのゾーン** にして作成〜動作確認してよい。  
- **`tools.monaka-app.com` が一覧に出たあと**、セキュリティのためトークンを **作り直し**、**特定のゾーン → tools.monaka-app.com のみ** に絞ることを推奨。

---

## お名前.com（モムー DNS 等）側：サブドメイン委任（どこを触るか）

**見る場所**:

1. お名前.com にログイン。
2. **ドメイン設定** / **DNS設定** / **ネームサーバー設定** など、**`monaka-app.com` の DNS レコードを編集する画面**を開く（サービス名はレジストラのメニュー表記に従う）。

**追加するレコード**:

| タイプ | 名前（ホスト） | 値 |
|--------|----------------|-----|
| **NS** | **`tools`**（画面によっては `tools.monaka-app.com`） | Cloudflare **概要**に表示された **NS 2 本** |

保存後、ターミナルで:

```bash
dig NS tools.monaka-app.com +short
```

**Cloudflare の NS が返るまで待つ**（数分〜最大24時間）。

---

## アプリサーバ（Laravel）側

`.env`（名前のみ。値は各環境で設定）:

- `MONAKA_DKIM_SIGNING_HOSTNAME=dkim.tools.monaka-app.com`（CNAME 先のホスト名と一致させる）
- `MONAKA_CLOUDFLARE_ZONE_NAME=tools.monaka-app.com`
- `MONAKA_CLOUDFLARE_API_TOKEN=...`（API トークン）
- `MONAKA_CLOUDFLARE_DKIM_AUTO_PUBLISH=true`

```bash
php artisan config:clear
php artisan monaka:dkim-sync-cloudflare
```

動作:

- `target_type=mail` の `custom_domains` が **新規作成**された直後、Cloudflare の TXT（名前はゾーン相対で `{selector}.dkim`、フル `FQDN` は `{selector}.dkim.tools.monaka-app.com`）を **作成または更新**する。
- 行削除時は、対応する TXT を **削除**しようとする（失敗時はログに残る）。

---

## 手動フォールバック

API が使えない・障害時:

```bash
php artisan monaka:dkim-signing-zone-export
```

出力を権威 DNS に手登録する。

---

## 制約

- `MONAKA_DKIM_SIGNING_HOSTNAME` は **`MONAKA_CLOUDFLARE_ZONE_NAME` 配下**である必要がある（例: ゾーン `tools.monaka-app.com`、ホスト `dkim.tools.monaka-app.com`）。否则 `MonakaCloudflareDkimService` は相対レコード名を計算できない。
- DNS 伝播待ち（数分〜最大24時間）は残る。画面の「設定確認」はあくまで **当該サーバからの参照**。
