# 機能設計書 46-mDNS パブリッシュ

## 概要

本ドキュメントは、OpenCodeにおけるmDNS（Multicast DNS）パブリッシュ機能の設計を記述する。ローカルネットワーク上でOpenCodeサーバーを自動発見できるようにするサービスディスカバリー機能を提供する。

### 本機能の処理概要

mDNSパブリッシュ機能は、Bonjour/Zeroconfプロトコルを使用して、ローカルネットワーク上でOpenCodeサーバーの存在を広告する。これにより、同一ネットワーク上のクライアントがIPアドレスやポート番号を手動で設定することなく、自動的にOpenCodeサーバーを発見できるようになる。

**業務上の目的・背景**：開発者がモバイルデバイスや他のマシンからOpenCodeサーバーに接続する際、IPアドレスとポート番号を手動で確認・入力する必要があった。mDNSにより、`opencode.local` のようなホスト名で自動的にサーバーを発見でき、セットアップの手間が大幅に削減される。特にiOSアプリやリモートターミナルからの接続時に便利である。

**機能の利用シーン**：
- モバイルアプリからのOpenCodeサーバー接続
- ローカルネットワーク上の他のマシンからの接続
- 開発環境でのサーバー自動検出
- IoTデバイスやスマートデバイスとの連携

**主要な処理内容**：
1. Bonjour サービスの初期化
2. HTTPサービスとしてmDNSレコードの公開
3. サービス名・ポート・ホスト名の広告
4. サーバー停止時のサービス取り下げ

**関連システム・外部連携**：
- bonjour-service: mDNS/DNS-SD実装ライブラリ
- Bonjour (macOS), Avahi (Linux): OSのmDNSレスポンダー

**権限による制御**：設定ファイルの `server.mdns: true` で有効化。loopbackアドレス（127.0.0.1, localhost）では無効。

## 関連画面

| 画面No | 画面名 | 関連種別 | 関連する操作・処理 |
|--------|--------|----------|------------------|
| - | - | - | 画面関連なし（インフラストラクチャ機能） |

## 機能種別

インフラストラクチャ / サービスディスカバリー

## 入力仕様

### 入力パラメータ

| パラメータ名 | 型 | 必須 | 説明 | バリデーション |
|-------------|-----|-----|------|---------------|
| port | number | Yes | 公開するHTTPポート番号 | 正の整数 |
| domain | string | No | mDNSドメイン名（デフォルト: opencode.local） | 有効なホスト名 |

### 入力データソース

- Server.listen() からの呼び出し
- 設定ファイル（server.mdns, server.mdnsDomain）

## 出力仕様

### 出力データ

本機能は直接的な出力データを持たない。ネットワーク上にmDNSレコードを公開する。

### 公開されるmDNSレコード

| レコード種別 | 値 | 説明 |
|------------|-----|------|
| サービス名 | opencode-{port} | 一意なサービス名 |
| サービスタイプ | _http._tcp | HTTPサービス |
| ホスト名 | opencode.local（またはカスタム） | 接続先ホスト名 |
| ポート | {port} | HTTPポート番号 |
| TXTレコード | path: "/" | ルートパス |

### 出力先

- ローカルネットワーク（mDNSマルチキャスト）

## 処理フロー

### 処理シーケンス

```
1. 公開条件チェック
   ├─ server.mdns 設定確認
   ├─ ポート番号確認
   └─ loopbackアドレス確認

2. サービス公開
   ├─ Bonjour インスタンス作成
   ├─ サービス名構築（opencode-{port}）
   └─ bonjour.publish() 呼び出し

3. イベントハンドリング
   ├─ "up" イベント: 公開成功ログ
   └─ "error" イベント: エラーログ

4. サービス取り下げ（サーバー停止時）
   ├─ bonjour.unpublishAll()
   └─ bonjour.destroy()
```

### フローチャート

```mermaid
flowchart TD
    A[Server.listen] --> B{mdns設定有効?}
    B -->|No| C[スキップ]
    B -->|Yes| D{port有効?}
    D -->|No| C
    D -->|Yes| E{loopback?}
    E -->|Yes| F[警告ログ出力]
    F --> C
    E -->|No| G[MDNS.publish]
    G --> H[Bonjour作成]
    H --> I[bonjour.publish]
    I --> J{成功?}
    J -->|Yes| K["up"イベント: ログ出力]
    J -->|No| L["error"イベント: エラーログ]
    L --> M[クリーンアップ]
    K --> N[公開継続]
```

## ビジネスルール

### 業務ルール

| ルールNo | ルール名 | 内容 | 適用条件 |
|---------|---------|------|---------|
| BR-46-01 | loopback無効 | 127.0.0.1, localhost, ::1 では公開しない | 公開条件チェック時 |
| BR-46-02 | ポート重複防止 | 同一ポートでの二重公開を防止 | 公開時 |
| BR-46-03 | 自動取り下げ | サーバー停止時に自動的にサービスを取り下げ | サーバー停止時 |
| BR-46-04 | デフォルトドメイン | domain未指定時は "opencode.local" を使用 | 公開時 |

### 計算ロジック

サービス名の構築：
```typescript
const name = `opencode-${port}`
```

## データベース操作仕様

本機能はデータベースを操作しない。

## エラー処理

### エラーケース一覧

| エラーコード | エラー種別 | 発生条件 | 対処方法 |
|------------|----------|---------|---------|
| - | publish失敗 | mDNS公開に失敗 | エラーログ出力、bonjour破棄 |
| - | サービスエラー | ランタイムエラー | エラーログ出力 |

### リトライ仕様

リトライは実装されていない。エラー発生時はログ出力のみ。

## トランザクション仕様

トランザクション管理なし。

## パフォーマンス要件

- mDNSマルチキャストは低オーバーヘッド
- サービス公開・取り下げは即座に反映

## セキュリティ考慮事項

- ローカルネットワーク内でのみ発見可能
- サーバー自体の認証設定は別途必要
- 信頼できないネットワークでの使用は注意

## 備考

- macOSではBonjour、LinuxではAvahiがmDNSレスポンダーとして動作
- Windowsでは追加ソフトウェア（iTunes, Bonjour Print Services等）が必要な場合あり
- bonjour-service ライブラリを使用

---

## コードリーディングガイド

本機能を理解するために参照すべきファイルと、推奨する読み解き順序を以下に示す。

### 推奨読解順序

#### Step 1: データ構造を理解する

mDNS設定の構造を理解する。

| 順序 | ファイル | パス | 読解ポイント |
|-----|---------|------|-------------|
| 1-1 | config.ts | `packages/opencode/src/config/config.ts` | Server設定スキーマ（946-958行目）でmdns, mdnsDomain確認 |

**読解のコツ**: mdns: boolean で有効/無効、mdnsDomain: string でカスタムドメイン指定。

#### Step 2: エントリーポイントを理解する

mDNS公開の呼び出し元を把握する。

| 順序 | ファイル | パス | 読解ポイント |
|-----|---------|------|-------------|
| 2-1 | server.ts | `packages/opencode/src/server/server.ts` | listen関数（603-613行目）でのMDNS.publish呼び出し |

**主要処理フロー**:
1. **603-608行目**: shouldPublishMDNS の条件判定
2. **609-610行目**: 条件を満たす場合 MDNS.publish 呼び出し
3. **611-612行目**: loopbackの場合警告ログ
4. **616-618行目**: サーバー停止時に MDNS.unpublish 呼び出し

#### Step 3: mDNS実装を理解する

MDNSモジュールの実装を把握する。

| 順序 | ファイル | パス | 読解ポイント |
|-----|---------|------|-------------|
| 3-1 | mdns.ts | `packages/opencode/src/server/mdns.ts` | publish関数（10-45行目） |
| 3-2 | mdns.ts | `packages/opencode/src/server/mdns.ts` | unpublish関数（47-59行目） |

**主要処理フロー**:
- **10-12行目**: 同一ポートの二重公開防止
- **14-16行目**: ホスト名とサービス名構築
- **17-24行目**: bonjour.publish() でサービス公開
- **26-28行目**: "up" イベントハンドラ
- **30-32行目**: "error" イベントハンドラ
- **35-43行目**: エラー時のクリーンアップ
- **47-59行目**: unpublish - サービス取り下げ

### プログラム呼び出し階層図

```
Server.listen(opts)
    │
    └─ shouldPublishMDNS判定
           │
           ├─ MDNS.publish(port, domain)
           │      │
           │      ├─ new Bonjour()
           │      │
           │      └─ bonjour.publish({name, type, host, port, txt})
           │             │
           │             ├─ on("up") - ログ出力
           │             └─ on("error") - エラー処理
           │
           └─ server.stop()
                  │
                  └─ MDNS.unpublish()
                         │
                         ├─ bonjour.unpublishAll()
                         └─ bonjour.destroy()
```

### データフロー図

```
[入力]               [処理]                    [出力]

port, domain
       │
       ▼
MDNS.publish()
       │
       ▼
Bonjour.publish() ───▶ mDNSマルチキャスト
       │                     │
       ▼                     ▼
イベントハンドラ        ネットワーク上で発見可能
```

### 関連ファイル一覧

| ファイル | パス | 種別 | 役割 |
|---------|------|------|------|
| mdns.ts | `packages/opencode/src/server/mdns.ts` | ソース | mDNS公開/取り下げ実装 |
| server.ts | `packages/opencode/src/server/server.ts` | ソース | mDNS呼び出し元 |
| config.ts | `packages/opencode/src/config/config.ts` | ソース | Server設定スキーマ |
