このファイルは Cursor / Claude Code が最初に読むプロジェクトコンテキストです。 実装前に必ず全文を読んでください。 特に「4. 確定仕様」と「7. 禁止事項」は仕様のズレが直接バグになる箇所です。
セッション開始時に自動注入される全社共通の作業ルールと、本ファイルの記述が衝突した場合は 以下を優先する。
仕様が不明なら止まる。 全社ルールの「自動モード中は許可待ちで止まらない」は権限確認についての取り決めであり、 仕様の不明点には適用しない。§7 の通り、推測で実装せず確認を求める。 判定基準・閾値・API契約の不明点は特に危険(仕様のズレが直接バグになる)。
判定ロジックは「期待値表の確定 → テスト作成 → 実装」の順を崩さない。 実装を分担・委譲する場合も、期待値表の確定は分担しない(§4.3 / §6.2)。 境界値(完了率 90.0 / 90.1 / 70.0 / 70.1 / 10.0 / 9.9 / 0 / 未実施、 および 89.5 → 表示90% だが判定は ○)は本ファイル §9.4 の表を正とする。
日本語を含む成果物には日本語フォントを明示する。 欧文フォント(Geist 等)は日本語グリフを持たないため、指定しないと フォールバックで中国語フォントに落ち、漢字が中華字形で表示される。 app/globals.css のフォントスタックを正とし、日本語フォントを外さない。
D-Watch(DFAロボット監視システム) は、店舗等に配置された清掃ロボットの稼働を監視するSaaSビューアーです。
P1スコープ | 項目 | 範囲 | |---|---| | 対象顧客 | 株式会社ドン・キホーテのみ | | ロボットメーカー | PUDU Roboticsのみ(KeenonはP2以降。Whiz iは機能的に劣るため取り扱わない) | | 対応機種 | PUDU CC1のみ(将来候補: PUDU MT1 / Keenon C30 / C40。lib/config/index.ts の ROBOT_MODELS が正。D-087) | | 利用者 | DFA社内のみ(顧客アカウントはP2以降) | | セキュリティ会社 | SECOMのみ |
| 領域 | 担当 |
|---|---|
| MySQLデータベース本体(設計・構築・運用) | TeamWorks(外部エンジニア会社) |
| データ収集処理(Pudu Cloudポーリング/コールバック、D-S制御盤報告のDB書き込み) | TeamWorks |
| サマリ集計バッチ(顧客/店舗/障害サマリ) | TeamWorks |
| APIサーバー + ビューアー(本リポジトリ) | DFA(内製) |
| 点検記録機能(独自データストア・写真管理) | DFA(内製) |
| 当期(進行中の週/月/年)のレポート集計 | DFA(内製) |
| ★サーバー・ネットワークの用意と構築保守★(本番のアプリVM / DB / テスト環境) | ★TeamWorks★(D-143) |
★DFA が作るのはビューアー(本リポジトリ)だけです★(2026-09-16 ユーザー確認。D-143)。 ★サーバーを契約し費用を払うのは DFA ですが、構築・保守は TeamWorks です★。 ★D-100 項5 の「DFA が構築するのはアプリ側(VM)」は誤りなので従わないこと★ (★ただし TeamWorks 側の明示確認は未取得。第9回 Q12-1 で照会中★)。
重要: メインDBのスキーマ変更・データ投入処理は本プロジェクトの仕事ではありません。 DBは基本的に読み取り専用で、書き込みは後述の4カラム(robot_error_reports は error_list_id を含む5カラム)のみです。
「APIサーバー」の意味: 本アプリ内の API ルート(app/api/)を指します。TeamWorks が API を 提供するわけではありません。DB へは Prisma で直接アクセスし、間に外部サービスは入りません。 画面はブラウザから自アプリの API ルートを呼び、その中で Prisma が DB を読みます(D-046)。
| 項目 | 採用 |
|---|---|
| フレームワーク | Next.js(App Router、React + APIルート一体型) |
| 言語 | TypeScript(フロント・API共通) |
| DBアクセス | Prisma(MySQL) |
| メインDB | MariaDB 10.11(TeamWorks管理・DFAはスキーマを変更しない)。MySQL互換だが同一ではない。★下の注記★を必ず読むこと(D-100) |
| 点検記録ストア | SQLite + オブジェクトストレージ(メインDBとは完全に分離) |
| 認証 | P1は簡易トークン認証 + IP制限(社内利用のみ)。★IP制限は X-Forwarded-For の末尾を見る(nginx が追記する。D-077 項5)。先頭は詐称可能なので絶対に使わない★ |
| インフラ | アプリ: さくらのクラウド VM(レンタルサーバではない。Node.js常駐が必要なため)。DB: さくらインターネットのデータベースアプライアンス(PostgreSQL か MariaDB の2択のため MariaDB)。★アプリ(VM)とDB(アプライアンス)が別サービスという理解だが、明示の確認は未取得★(D-100)。★用意・構築保守はいずれも TeamWorks★(D-143。第9回 Q12-1〜Q12-6 で照会中) |
| 開発用データ | lib/fixtures/ のサンプルデータ(環境変数 USE_FIXTURES で実DBと切替) |
★メインDBについての注記★(根拠: D-100。TeamWorks 回答 2026-09-10)
- ★なるべく MySQL 互換の SQL を使う★
- ★★MariaDB 特有の DML を使いたい場合は、その箇所を TeamWorks に知らせること★★
- ★ローカル検証環境は MySQL 8.4(
dwatch_local)。本番は MariaDB 10.11 なので、 ★ローカルで通っても本番で通らない可能性がある★。生SQL($queryRaw/$executeRaw)を 書くときは特に注意する★(現状、アプリコードに生SQLは1件も無い。すべて Prisma のクエリビルダ経由)★★接続先についての注記★★(D-152。2026-10-01 ユーザー確認)
- ★★
133.125.238.144/clean_watchは ステージング★★。★本番DBは別にある★(2026-10-01 ユーザー回答 「これはステージングです、本番は他にあります」)- ★★D-148(「本番DBそのもの」2026-09-17)は破棄★★。★第9回までの文書の「ステージング」「テスト環境」という呼称は ★正しかった★(D-148 項1 の「誤り」という訂正のほうが誤りだった)
- ★★2026-09-30 23:25〜10-01 00:09(JST)に実データが入った★★(2026-10-01 実測・先方投入。読み取りのみ)。 ★当方のダミー(
scripts/seed-local-db.ts由来)は消えている★。facilitiesは ★ドン・キホーテの実店舗10件+本社★。- ★★DB に入っている時刻の値は、列の型(TIMESTAMP / DATETIME)によらず JST の壁時計の値★★ (ユーザー指摘 2026-10-01「データベース上の時間は全てJSTに変換済みです」。★実測で確認★:
robots.updated_atの最新が生の値で 15:00、そのときの JST が 15:17・DB のNOW()が 06:17。生の値が UTC なら9時間後の未来になり、ありえない)。 ★生の値に9時間を足さないこと★。
- ★★2026-10-02 TeamWorks 回答(第10回 N-14・N-6c)★★: ★それまでサーバーの時計は UTC(
@@system_time_zone = UTC)で、 一部のテーブルはフレームワークの機能を切って書いていたため、current_timestamp()の既定値で UTC の値が入っていた★。 ★DB の既定のタイムゾーンを 'Asia/Tokyo' に変え、データを再登録済み★(先方の申告。★当方の再実測は未了★ — 10-02 は認証エラーで接続できず)。 ★先方の結論: 「timezone を JST で統一したので、以降はズレは生じない」★- ★当時の9時間ずれの正体★:
control_reports.reported_atは ★UTC で書かれていた★(N-14a)。robot_error_reports.errored_atは ★正しい JST の値で、ずれていたのはcreated_at(UTC)の側★(N-14b)。 ★旧記述の「errored_atは二重補正・エラー検知時刻は9時間遅く出る」は誤り★- ★アプリのコードは変えない★(2026-10-02 調査): アダプタは
dateStrings: trueで、サーバーが返した文字列を UTC とみなすだけ。 ★サーバーが JST になったことで、TIMESTAMP 列も JST の文字列で返り、fromDbJst()の前提どおりになる★。 ★残る危険は、再登録されなかった古い TIMESTAMP 行だけ★(そこだけ +9時間に見える)。★再実測で確かめること★- ★一度「TIMESTAMP は UTC で返るので +9時間」と誤って書き(9c175a2)取り消した(d540335)経緯あり★。★推測で9時間ずらさないこと★ ★
clean_timetables/clean_schedules/clean_status_historiesは0行★、clean_task_reportsは2行(どちらもclean_timetable_idが NULL)。★サーバー本体は昨日と同一★(@@hostname一致)- ★帰結★: ★予定が0行なので、清掃詳細ログ・ダッシュボード・アラートは空★。★総清掃面積だけは実績を直接集計するので2回と出る★ (画面どうしで食い違う。★詳細ログを予定起点・実績起点・両方のどれにするかは、データが入ってから検討★。D-151 項7) ★以上は 2026-10-01 時点★。★2026-10-06 は予定が入り始め(先方投入中。予定と実績はまだつながっていない。D-158 末尾)、 ダッシュボードは「各清掃エリアの直近の清掃(7日以内)」(D-159)で11エリアを出した★(先方投入。
docs/handoff.md追記61)- ★
robot_error_reports.serial_numberの実値★(2026-10-19 監督の SELECT・先方投入): セキュリティ(SECURITY_ON)・清掃開始失敗(NOT_STARTED)の行は ★---★(第11回 P-8 の回答は0)。★serial_numberの値やrobot_id IS NULLで区分を見分けない —error_typeで見分ける★(D-180 項5)。どちらに揃うかは TeamWorks に照会予定(指示書AX §12-1-2)- ★接続元の制限・TLS(第9回12章)は★検証段階のため保留。顧客へ配布するときに検討する★(ユーザー判断 2026-10-01)。 ★セキュリティの強化はリリース直前にまとめて行う★(ユーザー判断 2026-10-01。D-154)。★その時の対象★: 接続元の制限・TLS(または閉域)、★ステージングDBのパスワード変更★(コメントに実物が入っていた。履歴に残る)、★
ALLOW_ALL_WHEN_EMPTYを拒否に倒すか許可リストを入れる★(lib/config/allowed-ips.ts)、★ログインの試行回数制限と cookie の中身★(lib/auth/cookie.ts)、★制御盤のログ中継(作ったら): 読めるのはログのフォルダだけ・読み取り専用・制御盤ごとの認証★/★許可リストを入れると店舗の制御盤(/api/ds-agent/)が弾かれる — 店舗の IP を載せるか、その経路だけ IP 制限を外してトークン必須にするか★(D-179。未実装)/★CSP を入れるならapp/layout.tsxの<head>のインラインスクリプト(表示設定の復元。D-183)に nonce が要る★ ★第10回では照会しない★。★本番を組むときは、アプリとDBを閉域でつなぐか、DBに TLS を入れるかのどちらかが要る★- ★★ステージングには、4カラム(
status/comment/responded_at/resolved_at)の UPDATE を書き込んでよい★★ (ユーザー指示 2026-10-01「書き込んでよい」)。★実データ(ドン・キホーテのエラー行)の対応状況が書き換わることを承知のうえ★。 ★4カラム以外への書き込みは引き続き禁止★(§7。権限も無い)。★例外はrobot_error_reports.error_list_idだけ★(下の「DB接続アカウント」。D-184)。★scripts/seed-local-db.tsは★ステージングに絶対に向けない★ (テーブルを消してから入れ直すため、実データが消える。lib/db/local-guard.tsがdwatch_local以外を拒否する)- ★旧: 「本番DBへは書き込まない(2026-09-17)」「書き込んで安全な環境ができるまで着手しない」★ — D-152 で解除
robot_error_reports / control_error_histories の status, comment, responded_at, resolved_at のみ UPDATE 可
robot_error_reports.error_list_id(エラー内容。error_lists.id)★(D-184。2026-10-27 ユーザー回答「すでに更新権限があると思う」。 ★SHOW GRANTS での確認は未了★ — ステージングに接続できないため)。★control_error_histories には無い列★この4カラム(robot_error_reports は error_list_id を含む5カラム)以外への書き込みコードを書かないでください。権限エラーになります。 ★error_list_id を書くのはエラー一覧の PATCH /errors/{error_id}/status だけ★(事前チェックの /prechecks と D-Sec の保存は4カラムのまま。lib/db/robot-error-write.ts)。
ここに書かれた数値・ロジックは TeamWorks との合意事項です。 変更したくなった場合は勝手に変えず、
docs/decisions.mdを確認し、必要なら合意を取り直してください。
清掃完了率にもとづく4段階判定。閾値は設定値として外出しする(ハードコード禁止)。
| 判定 | 条件 |
|---|---|
| ◎ | 完了率 90%以上 |
| ○ | 完了率 70%以上 |
| △ | 完了率 10%以上 70%未満 |
| × | 完了率 10%未満、または未実施 |
★境界はすべて「上のランクに入る」★(ユーザー指示 2026-09-16「◯、×は90%以上のように境はふくめてください」。D-139)。 90.0 は ◎、70.0 は ○。★× の境界だけは「10%未満」のまま★(同日「10%未満を×としてください」で確定)なので、10.0 は △。 ★D-020b(境界はすべて下のランクに落ちる)は破棄★。
稼働率 = 正常終了(status = 4)の回数 ÷ 清掃予定回数 × 100 ← ★第11回 P-6=A(2026-10-05)★ 出発成功率 = 開始できた回数(レポート行がある回数)÷ 清掃予定回数 × 100 ← ★時刻の条件なし(P-6=A)★ 清掃完了率 = Σ 1回ごとの完了率 ÷ 1回ごとの完了率が null でない清掃の回数 ← ★1回ごとの完了率 = min(clean_area ÷ task_area × 100, 100) を小数第1位までで切り捨て★ エラー発生率 = エラー発生回数 ÷ 清掃予定回数 × 100 ← ★分母は予定回数(P-6=B)★
★3つの率はサマリ(operation_ratio / launch_ratio / error_ratio)と同じ式★(第11回 P-6。ユーザー指示 2026-10-05「合わせてください」。D-158)。★旧: 稼働率 = 実施回数 ÷ 予定・出発成功率 = 定刻出発回数 ÷ 予定(実際は同じ値になっていた)・エラー発生率 = ÷ 実施回数★。実装は指示書AU
★清掃完了率は「1回ごとの面積比(上限100・小数第1位まで切り捨て)」の単純平均★(★ユーザー判断 2026-10-02「一旦B」。D-155★)。 ★TeamWorks のサマリと同じ式★(第10回 N-3 の回答)。★clean_task_reports.clean_ratio 列は使わない★(先方が「計算式が間違っている。訂正したら回答する」)
clean_ratio 列もこの式と同じ値になる。2026-10-05。D-158)。★D-151 の「clean_ratio 列の単純平均」は破棄★。 ★切り替えが1関数で済むよう、1回ごとの完了率を決める関数は1つにする★(lib/judge/kpi.ts。指示書AS)clean_area は★同じ場所を複数回清掃した面積の総和★(N-4)なので、面積比は清掃の網羅率ではない。 ユーザー提供CSV 189行では ★clean_area > task_area が 129行(68.3%)で、これらは全部 100% になる★。★◎が多めに出る★precheck = 0)に対応する行と、予定外のタスク★。★事前チェックの回は別の1件として数えない★。
clean_timetable_id が 0 か NULL)も1件として数える(A案)★★(ユーザー指示 2026-10-29「エラー一覧以外も、予定外タスクを計算して出すようにしてください」「割合はA案で」。指示書BG): 予定外1件 = 清掃予定回数 +1・開始できた回数 +1・status = 4 なら正常終了 +1・1回ごとの完了率を平均に入れる。予定外のエラー(clean_timetable_id が 0 か NULL)もエラー発生回数・エラー内訳に入れる(期間は errored_at ?? created_at)。 予定外の期間の振り分けは started_at(実際に始めた時刻)。★予定外は未実施・結果待ちにならない★task_area が 0 の行は、1回ごとの完了率を 0% とする★(第11回 P-5=B。2026-10-05。実装は指示書AU)。★旧(D-155 の暫定): null として分子にも分母にも入れない★0.57 / 1 * 100 は 56.99999… になる。★切り捨ての前に誤差を吸収すること★(期待値表は指示書AS)lib/dashboard/aggregate.ts の computeSummary())成功率 = 成功 ÷ (成功 + 失敗 + 未実施) × 100 ← ★結果待ちは分母に入れない★。分母0なら null(画面は「-」)
| 区分 | 数える清掃 | 成功率での扱い |
|---|---|---|
| 成功 | 清掃結果(clean_task_reports の行)があり、判定が ◎○ |
分子・分母 |
| 失敗 | 清掃結果があり、判定が △×(★出発した清掃だけ★。未実施を二重に数えないため) | 分母 |
| 未実施(=出発失敗) | 清掃結果が無く、予定の終了+RESULT_WAIT_MINUTES(120分)を過ぎた |
分母 |
| 結果待ち | 清掃結果が無く、予定の開始 ≤ 今 < 予定の終了+120分 | 入れない(件数だけ出す) |
DASHBOARD_LATEST_RUN.lookbackDays)で予定の終了を過ぎた本清掃のうち、開始が最新のもの(D-159)。日付を指定したときは、その日の本清掃すべてclean_timetable_id が NULL か 0)も1件として数える★(指示書BG。2026-10-29)。直近モードの候補は開始=started_at・終了=ended_at(null なら開始)。成功か失敗のどちらかになり、未実施・結果待ちにはならない。同じ清掃エリアで開始が同時刻なら予定のある行を採る(lib/dashboard/latest-run.ts の preferOnTie())schedule_progress)= 対象日に出発した件数 ÷ 対象日の予定件数 × 100(予定件数0なら null)。★対象日は、日付を指定しないとき日本時間の前日、指定したときはその日★(ユーザー判断 2026-10-29「B」 — 清掃結果は前夜の分なので、今日の予定で数えない)。 ★予定件数は予定の表(clean_timetables / clean_timetable_histories の本清掃)の行数★。★clean_schedules の曜日の設定は使わない★(旧。2026-10-29 ステージングで今日の予定が 7件 対 5件と食い違った)。結果待ち・未実施は予定件数にだけ入る。★対象日に始まった(started_at)予定外タスクは予定件数にも出発件数にも1件ずつ入る(A案。指示書BG)★。応答の schedule_progress.date が対象日。lib/dashboard/aggregate.ts の scheduleProgressTargetDate() / computeScheduleProgress()。★要レスキュー・セキュリティのバナーは当日のまま★91%)// ✅ 正しい const grade = judgeGrade(rawRate); // 生値で判定 const display = Math.round(rawRate); // 表示用に丸める // ❌ 間違い(89.5%が丸めで90%になり、本当は○なのに◎になる) const rounded = Math.round(rawRate); const grade = judgeGrade(rounded);
| 事象 | 判定条件 |
|---|---|
| 清掃開始 | RobotWorkStatusコールバック(清掃開始)受信、またはポーリングでステータスが「清掃中」に変化 |
| 清掃終了 | タスク実行結果(タスクレポート)の受信 |
| 清掃失敗 | 予定開始時刻 + 猶予30分を経過してもタスク開始が確認できない(未実施)、またはタスクレポートが中断で返る |
猶予30分は暫定値。設定値として外出しする。
★レポートがまだ無い清掃は「結果待ち」★(ユーザー判断 2026-10-07。D-173): 予定の開始 ≤ 今 < 予定の終了+RESULT_WAIT_MINUTES(120)のあいだは失敗に数えない(lib/clean-logs/result-pending.ts の1本。API は CleanLogItem.result_pending)。過ぎたら出発失敗(未実施)。★上の「猶予30分」(LAUNCH_GRACE_MINUTES)はコードで使っていない★(D-091)
★事前チェックの結果も有無も、成功・失敗の判定に使わない★(ユーザー指示 2026-10-07「事前チェックを行っていない清掃や事前チェックが失敗した清掃でも本清掃が成功していれば成功にしてください」。D-170 / D-048)。判定は本清掃のレポート行の有無と完了率だけ。lib/dashboard/__tests__/aggregate.test.ts が見張っている
★「タスクレポートが中断で返る」は、いまは判定に使っていない★(ユーザー判断 2026-10-02。D-155 項2)。clean_task_reports.status(2 清掃中断 / 3 清掃キャンセル / 5 清掃異常終了)は★表示名として出すだけ★で、◎○△× は完了率で決め、未実施(出発失敗)は★レポート行の有無★で決める(§4.7)。★実データが入ってから見直す★
| レベル | 条件 | 想定対応 |
|---|---|---|
| L1 | 初回の問題 | 現場へ連絡(障害物確認・ブラシ清掃・再起動等) |
| L2 | 2日連続 | 現場責任者へのヒアリング・運用手順の再教育・消耗品交換 |
| L3 | 3日以上連続 | DFAオンサイト訪問・マップ再作成・機体交換検討 |
| # | 条件 | アドバイス |
|---|---|---|
| R1 | 出発失敗(初回) | 事前チェックのアラート内容を確認 |
| R2 | 完了率×(10%未満) | 現場の通路状況+ロボット状態を確認 |
| R3 | 同一施設で2日以上連続(出発失敗 or △以下) | 現場責任者に状況をヒアリング |
| R4 | 同一施設で3日以上連続(出発失敗 or △以下) | DFAオンサイト訪問を検討 |
「連続」はカレンダー日ではなく「スケジュール存在日の連続」で数えます。清掃予定がない日は連続を途切れさせません。
★予定外のタスクも、その施設のその日(started_at)の結果に入れる★(指示書BG。2026-10-29)— 連続日数・L1〜L3・要レスキュー・連続問題施設のすべて。★予定外だけの日も「スケジュール存在日」★(完了率 70 未満なら問題日、以上なら連続が切れる)。★予定外は未実施にならない★ので、要レスキューの「未実施の連続」は予定外だけの日で切れる。清掃詳細ログの予定外の行の連続日数は施設×日付で引く(consecutiveProblemDaysByFacilityDate())
facilities.contract のみが正。★varchar(10) の文字列★であり、★数値ではない★(D-080)
1 にする★0000000000 = 未設定(既定値) / 1000000000 = D-Securityのみ / 0100000000 = D-Watchのみ / ★1100000000 = 両方★Number("0000000000") は例外を出さずに 0 になり、 contract === 3 のような比較は絶対に真にならない。結果として ★全施設が「契約なし」になりメニューが全部消えるが、例外もテスト失敗も出ない★boolean(monitoring_enabled / d_security_enabled)への変換は ★lib/format/ か lib/config/ の純粋関数1箇所に閉じ込め、桁位置をハードコードしない★(D-080)customers.contract は削除依頼済み。参照してはいけませんcontract という列は2つあります★★(2026-09-17 実測。prisma/schema.prisma:141 と :571。行番号は 2026-10-05 時点)
facilities.contract★(:141)= ★これが正★clean_schedules.contract★(:571)= ★読まないこと★。★型も既定値も facilities と同一★ (varchar(10) / "0000000000")なので、★取り違えても型エラーにならない★。 ★現在のアプリは読んでいない(正しい状態)★components/layout/AppShell.tsx は全メニューを無条件に描く)。★P2 で作る。顧客に使わせる前に必ず入れる★(ユーザー判断 2026-10-06。D-160 追記4)| 種別 | 実行タイミング | 対象 |
|---|---|---|
| 週次 | 毎週日曜 6:00 | 前週(日曜〜土曜) |
| 月次 | 毎月1日 6:00 | 前月 |
| 年次 | 毎年1月1日 6:00 | 前年 |
2026/8/6週(08-30〜08-31) と 2026/9/1週(09-01〜09-05) の2行month / week が 0 かどうかで判別する(week=0 が月次、month=0 AND week=0 が年次。 第5回 X-2 は TeamWorks 承認済み。D-074 項3。2026-09-08)。week=0 は予約値なので、API の week は 1 以上のみ受け付ける★customer_summaries / facility_summaries(率4列)/ facility_error_summaries★ | | ★直近・昨日・当期の清掃実績★ | ★clean_task_reports★ | | 清掃の予定 | ★clean_timetables と clean_timetable_histories の両方★(precheck = 0 が本清掃)。★同じ id は clean_timetables 側を採る★(履歴の id は本表の id のコピー。D-158 項4・指示書AU 段階3b。読み口は lib/db/timetable-source.ts の1か所) | | ★エラー(制御盤のエラーも含めて)★ | ★robot_error_reports に集約★(★制御盤・セキュリティ・清掃開始失敗のエラーも入る(第11回 P-8〜P-10。D-158)★。★先方の DDL で robot_id は NULL 可になったが、Prisma は未 db pull(NOT NULL のまま)★。読み取りは lib/db/robot-error-select.ts で robot_id / robot を読まない(指示書AU 段階0)。★D-Sec アラートは robot_error_reports のうち error_type が D-S_CONTROL_FAILURE の行だけ(完全一致。SECURITY_ON・NOT_STARTED は出さない)を読み、対応状況・備考はエラー一覧と同じ PATCH /errors/{error_id}/status で書く(D-180)★。★control_error_histories は読まない★。★削除済み(deleted_at が NULL でない)の施設・清掃エリアの行は、エラー一覧(meta.total も)にも D-Sec アラート(summary・ダッシュボードも)にも出さず、その PATCH は404(U8。D-180 項11)★。★施設名・分類の解決は従来どおり deleted_at で絞らない(指示書AX 罠7)★。★区分(ロボット/制御盤/セキュリティ/清掃開始失敗)を画面に作るのは次フェーズ★。★全行(削除済みの施設・清掃エリアの行を除く。U8)の一覧と4カラムの更新はエラー一覧(/errors。D-160・指示書AW)★) |
clean_status_histories は読まない★(clean_task_reports に一本化。テーブル自体は TeamWorks の管理下なので残る)periodOfSummaryRow()(lib/db/report-mapping.ts)は month も見ること★ — week===0 だけで判定すると ★年次行が月次に化けて混入し、重複検知で500になる★clean_task_reports の行が無いこと★。clean_task_reports には clean_error 相当の列が無い。★「出発失敗」と「未実施」は同じ扱い★(ユーザー確認 2026-09-30)clean_task_reports.status は表示名に変換して表示する★(第10回 N-2 で TeamWorks が定義。D-155): 0 清掃開始前 / 1 清掃中 / 2 清掃中断 / 3 清掃キャンセル / 4 清掃正常終了 / 5 清掃異常終了。★表に無い値(CSV実測の 6 など)は生値のまま出す★(「その他」に潰さない。§4.8 と同じ考え方)。★判定には使わない★(中断・異常終了でも完了率で ◎○△× を出す。ユーザー判断 2026-10-02。§4.4 の「中断で返る=失敗」は実データを見て見直す)clean_task_reports.clean_timetable_id は nullable★。CSV実測では189行すべて NULL。 ★NULL は「予定外のタスク」(下の項目。第10回 N-1 で TeamWorks も同意)★で、★欠損ではない★。★2026-10-29 から今の期間の集計・清掃詳細ログ・ダッシュボード・清掃エリアに1件として入れる(§4.2・指示書BG)★(旧: 完了率・実施回数には入れない。D-155 項3)。 ★旧: 「NULL は TeamWorks が今後埋める前提」(2026-09-30)は、10-01 のユーザー回答で取り下げ★clean_task_reports は 2026-10-01 に2行入った★(それまでは0行。2026-09-30 実測で update_time が NULL=作成以来一度も書かれていなかった)。clean_timetable_id が NULL の行は「予定外のタスク」★★(ユーザー回答 2026-10-01「清掃予定をサーバーで決められるものは 今後 clean_timetable_id が発行されるが、予定外のタスクは NULL になる」)。★NULL は欠損ではなく、実在する清掃★clean_timetable_id が 0 の行も「予定外のタスク」★★(TeamWorks 回答 2026-10-27「clean_timetable_id が0以外は予定/実行済タスクになりますし, 0は予定外タスクになります」。 clean_task_reports と robot_error_reports の両方)。★NULL も引き続き予定外★。★判定は lib/db/timetable-link.ts の scheduledTimetableId() 1本★(=== null / { not: null } を直書きしない)。 ★予定タスクを持つのは clean_timetables / clean_statuses / clean_timetable_histories / clean_status_histories の4表★(同回答。アプリが予定として読むのは clean_timetables / clean_timetable_histories の2表)。 ★事前チェックの回(precheck ≠ 0)には clean_task_reports / robot_error_reports の行が入らず、clean_statuses / clean_status_histories は clean_status=2・clean_status_trans=0・clean_error=0 になる予定★(同回答)。★事前チェックの表示の仕様は変えない★(ユーザー指示 2026-10-27「この仕様から特に変更はない」 — 事前チェックの回に紐づく robot_error_reports を失敗として出す)clean_task_reports.started_at に入る値★★(ユーザー回答 2026-10-05「A」で確定): ★予定のある清掃は予定の clean_timetables.start_at と同じ値★、★予定外のタスクは実際に清掃を始めた時刻★。★過去形の列(started_at / ended_at 等)は実施後に書かれる★(2026-10-01 ユーザー回答) 例: 9/30 23:50 の予定が 10/1 00:10 に始まっても started_at は 9/30 23:50。★帰結: 期間の振り分けは、レポート当期(予定の start_at)・総清掃面積(started_at)・サマリ(第10回 N-9=A started_at)で一致する★。★予定のある清掃の実際の開始時刻は、この列からは分からない★(定刻出発の判定には使えない)。★旧: 「started_at は実際に清掃を始めた時刻」(10-01)は、予定外のタスクについてだけ正しい★ ★2行ともどちらも clean_timetable_id が NULL、status は 4★(2026-10-01 実測・先方投入。§3 の接続先注記も参照)task_count(予定回数)/ launch_count / error_count はあるが、★実施回数の列が無い★★ (prisma/schema.prisma:694-696 / :728-730。2026-10-05 時点)。 ★率は4つとも実在する★(operation_ratio / launch_ratio / clean_ratio / error_ratio)lib/format/period.ts の weekOfMonth() だけにするrobot_error_reports.error_type も robots.status も、DBから来た値をそのまま表示する★other に寄せる」は破棄★robots.status = -200(LostLoaction)→「LostLocation」の変換もしない★ (D-070 でそう確定していたが取り下げ。「-200 が LostLocation である」という事実認識は取り下げない。 取り下げるのは画面に出す前に変換する実装方針だけ)docs/handoff/analysis/error-type-mapping.md は参考資料。実装の下敷きではない★EmergencyStop)がそのまま出る。それが意図した挙動★lib/theme-status.ts の色分けは日本語6文字列の完全一致なので、生値では全部グレーに フォールバックする★| 資料 | 何の正か |
|---|---|
d-watch-api.yaml |
API契約の正。エンドポイント・JSONスキーマ・enum・エラー形式 |
docs/spec.md |
機能一覧と開発フェーズの正。何をどの順で作るか |
docs/decisions.md |
決定事項とその理由の正。「なぜこの仕様か」を遡る時に読む |
docs/fixtures.md |
サンプルデータの正。DB接続前の開発で必ず用意するケース一覧 |
モック(d-watch-mock.jsx) |
画面レイアウト・文言・遷移の正。フロント実装はこれを移植する |
| 清掃ロボット監視テーブル定義書(28テーブル) | DBスキーマの正。Prismaスキーマの突き合わせ先 |
| UI仕様書 v6.0 | 画面ごとの詳細仕様。モックで迷った時の裏付け |
| 要件定義書 P1 v2.2 | 全体要件・Phase A/B/Cの線引き。★DFA側の想定であり、TeamWorks の DB との整合は保証されない。型・値域・カラム名は実DDLが正★(2026-09-08 ユーザー指示。D-074 / D-057)。所在: Google Drive の「D-Watch / D-Security 要件定義書 (P1)」1thSYHk-ODCht-K4WqFlCP-Es2OyAz4Wj。★PHP/Laravel と書かれているが実装は Next.js(D-046)。トークン期限の記述も現行方針では禁止。古い箇所がある★ |
| 運用ガイド | 誰がいつどう使うか。UXの判断に迷った時に読む |
資料間で矛盾があったら、上の表の「正」に従ってください。それでも解決しない場合は実装を止めて確認を求めてください(推測で埋めない)。
d-watch-api.yaml を直す。 実装だけ変えてYAMLと乖離させないlib/fixtures/ のサンプルデータで行う。 実DBの完成を待たない。
USE_FIXTURES で fixtures / Prisma を切り替える。画面側のコードは切替を意識しないdocs/fixtures.md を参照(境界値・異常系を先に仕込む)scripts/seed-local-db.ts / lib/fixtures/)」/「先方投入」/ 「構造(information_schema / SHOW / EXPLAIN)」のどれかを書く。出所を書けない数字は 「実測」と呼ばない。
docs/handoff/テストDBのデータ出所_20260917.md)docs/decisions.md D-111 項7(:6683-6689。2026-09-11)が5日前に予告していた — 「テストDBでは判定できない: 本番のデータ量 / サマリバッチの実挙動 / 本番の time_zone 設定」。 表はあったのに守られなかったprisma db pull で取り込むだけ。 db pull 実施前の prisma/schema.prisma 手書きは対象外、D-056参照)robot_error_reports は error_list_id を含む5カラム。D-184)以外へのDB書き込みcustomers.contract の参照(削除依頼済み。facilities.contract を使う)git add -A の使用(過去に別作業の途中ファイルを巻き込む事故が起きている。 ★必ずファイルパスを明示する★)| 用語 | 意味 |
|---|---|
| 清掃エリア(sections) | 施設内の清掃対象区域。旧称「区画」。「清掃エリア」に統一 |
| 施設(facilities) | ロボットが配置される店舗・拠点。旧称「店舗」 |
| D-Sデバイス / D-S制御盤 | セキュリティ会社システムと制御サーバ間を中継する物理デバイス |
| 事前チェック | 清掃開始の60分前/30分前にロボット状態を確認する仕組み |
| Pudu Cloud | PUDU Robotics のクラウドAPI。ロボット状態・タスク結果の取得元 |
P1の前提: 1清掃エリア = 1ロボット。 テーブル構造は複数台対応可能ですが、P1ではこの前提で実装します。
app/
(dashboard)/ 画面。モックの画面IDに合わせる
dashboard/ detail-log/ alerts/ ds-logs/ ds-alerts/
facilities/ inspections/ reports/ schedules/ system/
api/ APIルート
clean-logs/
route.ts
export/route.ts
[id]/advice/route.ts
[id]/areas/route.ts
settings/
advice/route.ts
components/
ui/ Pill, FilterButton, GradeBadge 等の共通部品
features/ 画面固有のコンポーネント(例: detail-log/)
layout/ AppShell 等
theme/ ThemeProvider
lib/
judge/ ★判定ロジック(◎○△×、L1〜L3、KPI計算、丸め)+ __tests__/
fixtures/ サンプルデータ(DB接続前の開発用。docs/fixtures.md 参照)
db/ USE_FIXTURES で fixtures / Prisma を切り替える
config/ 閾値等の設定値
clean-logs/ 清掃ログ関連のクエリ
settings/ 運用設定(アドバイス等)
types/ 型定義。YAMLのスキーマ名と揃える
format/ 表示整形(日時等)
docs/ spec.md, decisions.md, fixtures.md 等
prisma/schema.prisma db pull実施後は生成物を正とし手で書き換えない(D-056)。実施前は定義書ベースで手書き
d-watch-api.yaml API契約
d-watch-mock.jsx 画面レイアウト・文言・遷移の正
detail-log/)CleanLogTable.tsx)lib/types/ に集約し、YAMLのスキーマ名と揃える(CleanLogItem, PrecheckItem 等)any 禁止。型が不明ならYAMLのスキーマから起こす{ error: { code, message, details? } } で統一meta: { total, page, per_page } を返す.env.local。認証情報を絶対にコミットしないlib/judge/)lib/config/ から読む。ハードコード禁止lib/fixtures/)USE_FIXTURES で fixtures / Prisma を切り替える。画面側は切替を意識しないd-watch-mock.jsx)の画面レイアウト・文言・遷移を正とするThis version has breaking changes — APIs, conventions, and file structure may all differ from your training data. Read the relevant guide in node_modules/next/dist/docs/ (resolved from this file's directory; in monorepos the next package may not be visible from the repo root) before writing any code. Heed deprecation notices.
This block is written and re-added by next dev — verify at node_modules/next/dist/server/lib/generate-agent-files.js. Removing it from a diff only re-creates the uncommitted change; committing it with your work keeps the tree clean.