# TeamWorks 様 確認事項（第2回）— D-Watch ビューアー実装

**作成: 2026-09-03 / 作成者: DFA**
**対象DDL: `clean_watch_20260902.sql`（2026-09-02 受領）**

第1回（`D-Watch_実DDL照合結果_20260903`）に続く確認事項です。
**第1回の A-1〜A-3 / B-1〜B-3 についてはご回答をいただきました。ありがとうございました。**
受け止めと対応は末尾の「参考: 第1回のご回答で解決した事項」に記載しています。

今回の本題は、**DDLを正としてビューアーのデータ取得層を実装しようとした結果、
取得元が特定できなかった項目**（Q1・Q2）です。

**★Q1 と Q2 は、この2件が解決しないと該当画面が実装できません。★**
両方とも「DDLに該当カラムが見当たらない」という種類の問い合わせです。
**すでに存在するのに私どもが見落としている可能性**もありますので、その場合は
テーブル名・カラム名をご指摘いただければ十分です。

---

## Q1 ★最優先★ D-Security 画面のデータ取得元

### 状況

ビューアーには D-Security 用の画面が2つあります。

| 画面 | 内容 |
|---|---|
| **F-06 D-Secログ** | D-S制御盤（デバイス）の一覧と通信状態 |
| **F-07 D-Secアラート** | セキュリティ解除・通信断のアラート一覧 |

受領したDDL（39テーブル）を確認したところ、**これらに直接対応する名前のテーブルが
見当たりませんでした**（`ds_devices` / `ds_alerts` のような名前のテーブルはありません）。

候補として次の5テーブルがあると考えています。

| テーブル | 主なカラム |
|---|---|
| `controls` | `serial_number` / `facility_id` / `section_id` / `status`(tinyint unsigned, default 0) / `inactive` / `verified_at` / `deleted_at` |
| `control_reports` | `control_id` / `facility_id` / `section_id` / `serial_number` / `reported_at` |
| `control_error_histories` | `control_id` / `facility_id` / `section_id` / `status`(tinyint unsigned) / `comment` / `occurred_at` / `responded_at` / `resolved_at` |
| `security_statuses` | `facility_id` / `section_id` / `status`(tinyint unsigned, default 1) / `reported_at` |
| `security_status_histories` | `facility_id` / `section_id` / `status`(tinyint unsigned) / `reported_at` |

### Q1-1. D-Secログ画面（デバイス一覧）

画面に出す項目と、私どもの想定を並べます。**想定が合っているかご確認ください。**

| 画面の項目 | 想定している取得元 | 確認したいこと |
|---|---|---|
| デバイスのシリアル | `controls.serial_number` | これで合っていますか |
| 施設名 | `controls.facility_id` → `facilities.facility_name` | |
| **通信状態（正常 / 通信断 / 異常）** | **不明** | ★下記 Q1-2★ |
| **最終通信日時** | `control_reports.reported_at` の最新？ | `control_reports` は**定期的な生存報告**という理解で合っていますか。報告の間隔はどれくらいですか |
| 備考 | **不明** | デバイスごとの備考を持つカラムはありますか（無ければ画面から落とします） |

### Q1-2. ★`controls.status` のコード値定義をご教示ください★

`controls.status` は `tinyint unsigned` / 既定値 0 ですが、**取りうる値と意味が分かりません。**
0 / 1 / 2 … がそれぞれ何を表すかをご教示ください。

あわせて、画面に出したい **3状態（正常 / 通信断 / 異常）**の判定方法を確認させてください。

- 「異常」は `controls.status` から判定できますか
- **「通信断」は `control_reports.reported_at` からの経過時間**で判定する想定でよいですか。
  その場合、**何分（何時間）で通信断とみなすか**の運用上の基準はありますか
  （現在のサンプルデータでは「6時間以上通信なし」としていますが、根拠のない仮の値です）

### Q1-3. D-Secアラート画面

`control_error_histories` が実体だと考えています。**カラムの対応が下記で合っているかご確認ください。**

| 画面の項目 | 想定している取得元 | 確認したいこと |
|---|---|---|
| 検知日時 | `control_error_histories.occurred_at` | |
| 施設名 | `facility_id` → `facilities.facility_name` | |
| 清掃エリア名 | `section_id` → `sections.section_name` | |
| デバイスのシリアル | `control_id` → `controls.serial_number` | |
| 対応状況（未対応 / 対応中 / 完了） | `control_error_histories.status` | ★**コード値定義をご教示ください**★ |
| メモ | `control_error_histories.comment` | |
| 対応日時 / 解決日時 | `responded_at` / `resolved_at` | |
| **アラート種別（セキュリティ解除 / 通信断）** | **不明** | ★下記★ |
| **詳細（アラートの本文）** | **不明** | ★下記★ |

**★確認したいこと2点★**

1. **アラート種別**（「セキュリティ解除されたまま」なのか「通信断」なのか）を
   区別するカラムがありますか。`control_error_histories` には種別を表すカラムが見当たりません。
   `status` が種別を兼ねているのでしょうか、それとも別テーブルでしょうか
2. **アラートの詳細文**（例:「セキュリティ復帰失敗」）はどこに入りますか。
   `comment` は運用担当が書き込む欄という理解なので、**検知側が書く詳細**とは別だと考えています

### Q1-4. `security_statuses` / `security_status_histories` の位置づけ

`security_statuses.status` は `tinyint unsigned` / **既定値 1** です。

- **コード値定義をご教示ください**（0 / 1 / 2 … が何を表すか。既定値が 1 である理由も）
- このテーブルは**セキュリティの現在状態**を持つもので、
  「解除されたまま戻っていない」という状態は**ここから判定する**という理解で合っていますか
- `security_status_histories` は `security_statuses` の変更履歴という理解で合っていますか

---

## Q2 ★最優先★ 事前チェック（60分前 / 30分前）時点のロボット状態

### 状況

ダッシュボードと清掃詳細ログに、**清掃開始の60分前と30分前のロボットの状態**を
並べて表示する欄があります。表示する値は次の6種類です。

> 待機中 / 充電中 / ハンドルアップ / 緊急停止 / オフライン / セキュリティ有効

**この「60分前時点の状態」「30分前時点の状態」を、後から参照できるテーブルが見当たりません。**

私どもが確認した範囲では次のとおりです。

| テーブル・カラム | 状況 |
|---|---|
| `robots.status`（smallint, default 0） | ロボットの**現在**の状態と思われる。**過去の値は残らない** |
| `section_robot_statuses.robot_status`（smallint, default 0） | 同上。定義書の備考も「現時点では未確定」となっており、`robots.status` からの算出ルールが不明 |
| `clean_timetables.precheck` | 0: 本清掃 / 1: 1回目 / 2: 2回目（第1回 B-1 でご回答いただいた内容）。**事前チェックの「タイミング」は分かるが、そのときの「状態」がどこにも無い** |
| `robot_instruct_histories` | 指示の履歴であり、状態のスナップショットではないと理解しています |

### 確認したいこと

1. **★事前チェック時点のロボット状態は、どのテーブルのどのカラムに記録されますか。★**
   記録されない場合は、**現状では画面に出せない**ことになるため、その旨をご教示ください
   （その場合は当該欄を P2 以降に送るか、別の表現に変える判断をします）
2. **`robots.status`（smallint）のコード値定義をご教示ください。**
   上記6種類との対応が分かる形でお願いします。
   なお `robots.clean_status` については第1回 A-2 で
   「0: 清掃前 / 1: 清掃中 / 2: 清掃終了(セキュリティ有効) / -1: 清掃完了(セキュリティ無効)」と
   ご回答いただいていますが、**`status` のほうは未回答**です
3. `section_robot_statuses.robot_status` を配下の `robots.status` から算出するルールは
   **決まりましたか**（定義書の備考は「現時点では未確定」のままです）

---

## Q3 `clean_schedules.weeks` の曜日の並び順

`clean_schedules.weeks` は `varchar(7)` で、曜日ごとの実施有無を7桁で持つ理解です。

**左から順に「日・月・火・水・木・金・土」で合っていますか。**
それとも「月・火・水・木・金・土・日」でしょうか。

画面には「毎日」「月水金」のようなラベルで表示するため、**並び順を取り違えると
別の曜日として表示されます**（例: `1000000` を日曜と読むか月曜と読むか）。

あわせて、`1` が実施・`0` が非実施で合っていますか。

---

## Q4 ステータス系カラムのコード値定義（まとめ）

Q1 / Q2 と重複しますが、**コード値の定義が不明なカラムを一覧にします。**
第1回で `clean_statuses.clean_status` と `clean_timetables.precheck` はご回答いただきました。
**残りは次の5つです。**

| # | テーブル.カラム | 型 | 既定値 |
|---|---|---|---|
| 1 | `robots.status` | smallint | 0 |
| 2 | `section_robot_statuses.robot_status` | smallint | 0 |
| 3 | `controls.status` | tinyint unsigned | 0 |
| 4 | `control_error_histories.status` | tinyint unsigned | 0 |
| 5 | `security_statuses.status` / `security_status_histories.status` | tinyint unsigned | 1 / なし |

**`robot_error_reports.status`（tinyint unsigned, default 0）**についても、
画面では「未対応 / 対応中 / 完了」の3状態で扱う想定ですが、
**コード値の対応をご教示ください**（`control_error_histories.status` と同じ体系ですか）。

---

## C. 第1回のご回答を受けた追加確認（3件）

第1回について**ご回答をいただきありがとうございました。** すべて反映しています。
そのうえで、**確認させていただきたい点が3件**あります。

### C-1. A-3（contact 系の型）は DDL 側を修正いただけますか

いただいたご回答:

> contact_type は両テーブルとも tiny int. email は両テーブルとも varchar(100) で定義してください.

現在いただいている DDL（`clean_watch_20260902.sql`）は**まだ食い違ったまま**です。

| カラム | ご回答 | 現在の DDL |
|---|---|---|
| `customer_contacts.contact_type` | tinyint | **bigint unsigned** |
| `facility_contacts.contact_type` | tinyint | tinyint unsigned（一致） |
| `customer_contacts.email` | varchar(100) | varchar(100)（一致） |
| `facility_contacts.email` | varchar(100) | **varchar(255)** |

こちらは**実DDL を正としてスキーマを機械的に取り込む運用**にしているため、
**DDL 側を直していただく前提**で認識が合っているかを確認させてください。

1. **DDL 側を修正いただけるという理解で合っていますか**
   （こちらは修正後の DDL を `prisma db pull` で取り込みます）
2. 反映の目安時期をお知らせください

### C-2. B-1 / B-2 / B-3 の修正を含む DDL をいつ頂けますか

ご回答で、**外部キー3本（B-1）・インデックス1本（B-2）・timestamp の DEFAULT（B-3）**を
後から追加いただけると伺いました。

こちらは受領した DDL を `prisma db pull` で**機械的に取り込む運用**にしているため、
修正が入るたびに DDL を頂き直す必要があります。

1. 上記の修正（**C-1 の contact 系も含めて**）がまとまった段階で、**DDL を再度いただけますか**
2. 目安の時期をお知らせください
3. **A-2 の auto_increment も同じ修正に含まれる**という理解で合っていますか。
   現在の DDL では `clean_status_histories.id` / `clean_timetable_histories.id` に
   AUTO_INCREMENT が付いていません

### C-3. API が画面に返す ID は error_id で確定してよいですか

いただいたご回答:

> とりあえず error_id を主キーと位置付け対応する予定です.
> ちなみに id も error_id もアルファベットを含んでいるので, 数値型にすることはできません.

このご回答を受けて、こちらは **API の `PrecheckItem.id` を number から string へ変更し、
値には `error_id` を入れる**方針で進めます。

1. **この方針で問題ないですか**
2. 「運用を以て最終的な回答を求める」とのことでしたが、
   **後で `id` 側に一意制約が付く可能性はありますか。**
   付く可能性があるのであれば、切り替えられる形で実装しておきます

---

## D. 継続（1件）

第1回でお願いしたもののうち、**まだ動きがないもの**です。

| 内容 | 状態 |
|---|---|
| **DB更新用アカウントの発行**（`robot_error_reports` / `control_error_histories` の `status` / `comment` / `responded_at` / `resolved_at` のみ UPDATE 可） | **継続** |

---

## 参考: 第1回のご回答で解決した事項

**回答不要です。** こちらの受け止めと対応を記載しますので、
認識に相違があればご指摘ください。

| # | ご回答 | こちらの対応 |
|---|---|---|
| **A-1** | error_id を主キーと位置付けて対応する予定。id も error_id も英字を含むため数値型にはできない | `PrecheckItem.id` を **number → string** に変更し、値は `error_id` にします。`PATCH /prechecks/{id}/status` の設計に着手できます（C-3 で最終確認） |
| **A-2** | 採番はデータベース。auto_increment で採番する。元テーブルと履歴テーブルは**1対1** | ビューアーはこの2テーブルを参照しないため、実装への影響はありません。DDL への AUTO_INCREMENT 追加を C-2 で確認しています |
| **A-3** | contact_type は両テーブルとも tinyint、email は両テーブルとも varchar(100) | DDL への反映を C-1 で確認しています。反映後の DDL を `db pull` で取り込みます |
| **B-1** | 制約（外部キー3本）は後から追加する | **孤児行を想定した実装はやめます。** 追加後の DDL に合わせます |
| **B-2** | インデックスも後から追加する。現状は20施設弱 | 承知しました。**当面の性能懸念は小さい**と理解しました |
| **B-3** | プログラム側で明示的に対応しているが、指摘どおり DEFAULT を追加する（created_at: 新規作成時、updated_at: 新規作成時／更新時） | 追加後の DDL に合わせます |

### 受領DDLの確認により解決していた事項

次の2件は、受領した DDL を確認したところ**既に満たされていました。** 対応不要です。

| 内容 | 確認結果 |
|---|---|
| `responded_at` / `resolved_at` のカラム追加 | **`robot_error_reports` / `control_error_histories` の両方に既に存在します**（いずれも `datetime` NULL可）。綴りも `responded_at` で正しくなっています |
| D-Secアラートへの書き込み可否 | 実体が `control_error_histories` であれば、**既に更新可4カラムに含まれています**。追加の権限は不要という理解です（Q1-3 で実体の確認をお願いしています） |

---

## 補足: 当方で判断して進める項目（回答不要）

参考までに、**ご回答を待たずに DFA 側で決めて進めるもの**を挙げます。
認識に相違があればご指摘ください。

- **`clean_schedules` に `serial_number` が無い**件 → `sections` 経由で `robots` を引きます。
  P1 は「1清掃エリア = 1ロボット」の前提のため一意に定まります
- **`clean_schedules.end_time` が 24〜29時を取る**件（第1回 B-5 で回答済み）→
  画面表示は「翌04:30」の形にします
