Newer
Older
client_dwatch / docs / handoff / 指示書L_マスタ画面3枚とinspectionsの一時非表示.md

指示書L — マスタ画面3枚(F-08 / F-09 / F-10)と inspections の一時非表示(D-079 項3)

項目 内容
実行環境 ★Cursor 内の Claude が実装します★(.claude/commands/d-watch.md の役割分担表を参照) → 実際にはユーザーの直接指示によりClaude Code(Sonnet 5。監督役+opusサブエージェント委譲)が実行した(2026-09-08)
実行状態 ★完了(2026-09-08。D-084)★。段階0〜11すべて実施。段階10(ブラウザ確認)はcurl代替のため一部未確認
実行順 ★指示書K / 指示書I とはコードのファイルが重なりません★(K は lib/reports/ lib/theme-status.ts lib/judge/advice.ts 系、I は lib/auth/ proxy.ts 系)。★ただし d-watch-api.yaml と docs/decisions.md / docs/handoff.md は3本とも触ります★。★同時に走らせないこと★
取得する決定番号 ★着手直前に grep -n "^### D-0" docs/decisions.md で最終番号を確認すること★。★★本指示書の作成中(2026-09-08 18:11)に、別セッションが D-083(本指示書作成のための調査結果)を追記しました。したがって最初の空き番号は D-084 です★★。★指示書K(D-079 を予定→すでに別作業で使用済み)と指示書I が先に走るとさらに繰り上がります★。★2026-09-07 に D-068 の二重採番が実際に起きています。必ず自分で確認してください★
前提 ★D-079 項3★(docs/decisions.md:2146 以降。他メンバーとの合意。作業順序の1番目) / ★D-032★(:198。system の限定スコープ) / ★D-031★(:194。点検記録は P1 スコープ) / ★D-053★(:330。機能しないUIを出さない) / ★D-060★(:403。end_time は整形済み文字列) / ★D-080★(:2202。contract は10桁文字列) / ★D-072 項7★(:1052。点検記録は最後)
段階数 ★12段階★(段階0〜段階11)
着手前の基準 npm test が ★22ファイル / 461テスト 全パス★、npx tsc --noEmit エラー0、npm run lint 0(★2026-09-08 実測。Vitest 4.1.11★)。着手直前に自分で実行して実測値を基準にすること
作成 2026-09-08(作成時点の決定事項最終番号 D-082)

実行後はこの表と、文書末尾の「実行状態」表を更新してください。

★この指示書を読んでいるあなたへ★ .claude/commands/d-watch.md に「実装は Cursor 側、Claude Code は指示書作成まで」とありますが、 これは2つの環境の役割分担です。Cursor の中で動いている Claude は実装担当です。 この指示書を渡されたなら、調査や改訂ではなく実装を行ってください。


★★着手前にユーザーへ確認すること(2件)★★

★この2件はどちらも「YAML に無いものを画面に出すかどうか」という契約の話です。★ ★先に決めないと、段階1(API契約の修正)の内容が変わります。実装を始める前に必ず確認してください。★

★確認1 — system 画面のスコープ★

# 事実
1 ★D-032(docs/decisions.md:198-201)は「表示設定」と「運用設定」の2つを実装対象としている★
2 ★しかし d-watch-api.yaml に「表示設定」「運用設定」のエンドポイントは1本も無い★。あるのは /settings/advice(:554-599)だけで、★これは実装済み★(app/api/settings/advice/route.ts)
3 ★「表示設定」(ダッシュボードの表示項目 ON/OFF。d-watch-mock.jsx:1182-1217)は、設定の永続化とダッシュボード側の読み取り対応の両方が必要★で、★本作業(マスタ画面3枚)の範囲を超えます★

★当方の推奨スコープ(この指示書はこれで書いています)★

# 内容
1 ★「運用設定」タブのみ★を作る
2 ★読み取り専用★。閾値(完了率 90/70/10、事前チェック 60分/30分、エスカレーション L2=2日/L3=3日)を ★lib/config/ から読んで表示する★(★ハードコード禁止★。CLAUDE.md §7)
3 アドバイス文言の一覧を ★GET /api/settings/advice(実装済み)★ から取得して表示する
4 ★画面に「編集は P1 後半で対応します」と明示する★
5 ★「表示設定」タブは作らない★

★理由★: ★D-053(docs/decisions.md:330-334)が「機能しない絞り込みUIを画面に出さない」と定めています★。 「固定の選択肢だけがあって何も起きないUIは、不具合と区別できない」というのがその理由です。 ★動かないトグルやテキストボックスを並べるのは D-053 に抵触します。★ ★一方、「読み取り専用です」と明示した表示は抵触しません★ — 何も起きないのではなく、何も起きないことが宣言されているためです。

★この方針で問題ないかを着手前に確認してください。★ ★編集まで作るなら、先に d-watch-api.yaml に「表示設定」「運用設定」のエンドポイントを追加する必要があります★ (CLAUDE.md §6-1「API契約を変えたくなったら、先に d-watch-api.yaml を直す」)。その場合この指示書の段階1と段階6を書き直してください。

★確認2 — facilities の検索ボックスと API パラメータの食い違い(★調査で新たに判明★)★

★モックの検索ボックスは1つですが、YAML のクエリパラメータは3つに分かれています。そのままでは繋がりません。★

側 実際の姿
★モック(d-watch-mock.jsx:977)★ ★入力欄は1つ★(placeholder = 施設名 / シリアル / 住所)。:998-1002 のフィルタは ★施設名 / 都道府県 / 住所 / シリアル / メーカー / 機種 の6項目を OR で★ 部分一致させている
★YAML(d-watch-api.yaml:739-753)★ ★facility_name / serial / address の3パラメータ★。一覧APIのパラメータは通常 ★AND★ で組む

★1つの入力欄の値を3つのパラメータに同時に入れると、AND になって「施設名にも住所にもシリアルにも同じ文字列が含まれる施設」しかヒットしません(=ほぼ常に0件)。★ ★これは「検索が壊れている」ように見える挙動です。★

★当方の推奨(この指示書はこれで書いています)★: ★q パラメータを /facilities に追加する★

# 内容
1 ★q を追加★ — ★施設名 / 都道府県 / 住所 / シリアル / メーカー / 機種 を OR で部分一致★(モックの挙動そのまま)
2 ★既存の facility_name / serial / address は残す★。3つは互いに AND、q はそれらと AND(q 内部だけが OR)。★画面は q だけを使う★
3 ★前例がある★ — /ds-devices の q(d-watch-api.yaml:613-616「施設名 or D-S制御盤シリアル番号(部分一致)」)と /inspections の q(:815-818)。★既存2本と同じ形にするので新しい概念は増えません★

★q を足す=API契約の変更です。段階1(YAML を先に直す段階)で行ってください★(CLAUDE.md §6-1)。 ★この方針で問題ないかを着手前に確認してください。★ ★もし「YAML を増やしたくない」なら、代案は「画面の入力欄を3つに分ける(モックから外れる)」ですが、CLAUDE.md §5 は「モックが画面レイアウトの正」としているため、★当方は推奨しません★。★どちらを採るにせよ、採った理由を段階11 で記録すること★。★/schedules も同じ問題を抱えています(facility_name / serial の2つ。:773-781)。同じ判断を適用すること★


この指示書の位置づけ

★D-079 項3(他メンバーとの合意。docs/decisions.md:2146-2179)で、作業順序の1番目に置かれたものです。★

1. プレースホルダ画面(facilities / schedules / system)
   ★inspections はメニューから隠してください★

★理由(メンバーの言)★: メニューを開いて空画面が出るのはデモで印象を損なう。 ★デモの目標は9月中に PPIH 向け★(同 :2155)。

★調査で判明したこと — これは「作る」ではなく「差し替える」作業です★

★4画面はすでに PlaceholderScreen で、いずれも5行しかありません★(実測):

app/(dashboard)/facilities/page.tsx    → <PlaceholderScreen title="施設ロボットマスタ" />
app/(dashboard)/schedules/page.tsx     → <PlaceholderScreen title="スケジュール管理" />
app/(dashboard)/system/page.tsx        → <PlaceholderScreen title="システム管理" />
app/(dashboard)/inspections/page.tsx   → <PlaceholderScreen title="点検記録" />

したがって本作業は ★「プレースホルダを作る」ではなく「プレースホルダを実装済み画面に置き換える」★ です。

★材料はほぼ揃っています(実測)★

材料 状態
API契約 ★d-watch-api.yaml:731(/facilities)/ :768(/schedules)に定義済み★
TS型 ★lib/types/index.ts:317-322(RobotSummary)/ :324-347(Facility)/ :349-360(Schedule)★
fixtures ★lib/fixtures/facilities.ts 12件 / lib/fixtures/schedules.ts 13件★
db.facilities() / db.schedules() ★lib/db/index.ts:99-104 に fixtures 実装あり(全件返す)★。インターフェース宣言は :60-61
GET /api/settings/advice ★実装済み★(app/api/settings/advice/route.ts)
閾値の設定値 ★lib/config/index.ts に全部ある★(GRADE_THRESHOLDS / ESCALATION_THRESHOLDS / PRECHECK_MINUTES_BEFORE)
★不足しているもの★ ★API ルート2本(app/api/facilities/route.ts / app/api/schedules/route.ts)と画面3枚★

★app/api/ に facilities / schedules / inspections のルートは存在しません★(実測。あるのは clean-logs / dashboard / ds-alerts / ds-devices / prechecks / reports / settings の7つ)。


★禁止事項(この指示書の全段階に効きます)★

# 禁止 理由
1 ★モックの実在の店舗名・住所・電話番号・氏名・メールをコピーすること★ CLAUDE.md §7 / D-043。★d-watch-mock.jsx:54-63 の ROBOTS 9件は実在の値★(MEGAドンキ渋谷本店 / 渋谷区宇田川町28-6 / 03-5428-4086 / shibuya@donki.co.jp 等)。★1文字もコピーしないこと★。★必ず lib/fixtures/facilities.ts を使う★(架空値に置換済み)。★d-watch-mock.jsx:81-88 の INSPECTIONS 7件にも実在の人名・店舗名が入っています★(段階1-6 参照。★今回は使いませんが、目に入るので明記しておきます★)
2 ★lib/fixtures/schedules.ts に active: true のスケジュールを追加すること★ ★ダッシュボードの既定表示が異常系になります★。詳細は ★段階3 の地雷警告★ を必ず読むこと
3 ★既存の active: true スケジュールの削除・無効化・weekdays の書き換え★ 同上。特に補完ペア(id23↔id30 / id25↔id26)
4 ★id: 24 の削除★ ★唯一の active: false★(lib/fixtures/schedules.ts:94-105)。判定ロジックの確認に使う(同ファイル :17-18 / :46-47)
5 ★動かないUIを画面に出すこと★ D-053。★モックの 📥 インポート / + 新規追加 ボタン(d-watch-mock.jsx:978-979)は onClick の無い飾り★。★運用設定の入力欄も同じ★
6 ★閾値(90 / 70 / 10、60分 / 30分、L2=2日 / L3=3日)をハードコードすること★ CLAUDE.md §7。★必ず lib/config/ から読む★
7 ★customers.contract を参照すること★ CLAUDE.md §7 / D-010。★facilities.contract のみが正★
8 ★contract を数値として比較すること★ ★D-080★。★varchar(10) の文字列で桁位置がサービスに対応★。Number("0000000000") は例外を出さずに 0 になるので、★全施設が「契約なし」になってもエラーもテスト失敗も出ません★
9 ★lib/db/ の prismaSource に手を付けること★ 実DB接続は別作業。notImplemented のままにする
10 ★点検記録(inspections)の実装に手を出すこと★ ★D-072 項7★(docs/decisions.md:1052-1058)。★写真の置き場所・バケット・署名URLが未決★。先に作ると「写真が表示できない画面」ができる
11 ★git add -A を使うこと★ 過去に別作業の途中ファイルを巻き込む事故が起きています。★必ずファイルパスを明示★
12 ★メインDBへの書き込み★ CLAUDE.md §7 / D-042。今回そもそも書き込みは発生しません
13 ★components/layout/PlaceholderScreen.tsx を削除すること★ ★inspections がまだ使っています★(段階7 で inspections は残す)

作業の順序(★崩さないこと★)

段階 内容 コミット
段階0 前提の確認(★読むだけ★) コミットなし
段階1 ★API契約を直す★(d-watch-api.yaml)+ 型を足す 段階1で1コミット
段階2 GET /api/facilities を作る(+ lib/facilities/query.ts + テスト) 段階2で1コミット
段階3 GET /api/schedules を作る(+ lib/schedules/query.ts + テスト)★地雷あり★ 段階3で1コミット
段階4 施設ロボットマスタ画面(F-08) 段階4で1コミット
段階5 スケジュール管理画面(F-09) 段階5で1コミット
段階6 運用設定画面(F-10、★読み取り専用★) 段階6で1コミット
段階7 inspections をメニューから隠す 段階7で1コミット
段階8 i18n 段階8で1コミット
段階9 テスト(★段階ごとに実行済みのはず。ここは最終確認★) コミットなし
段階10 ブラウザで動作確認 コミットなし
段階11 記録と push 段階11で1コミット + push

★段階ごとに npx tsc --noEmit / npm run lint / npm test を実行し、通ってからコミットすること★(D-050。docs/decisions.md:308)。


段階0 — 前提の確認(★読むだけ・コミットなし★)

読むもの

資料 何を読むか
docs/spec.md:90-96 ★F-08 施設ロボットマスタ(参照のみ)★。★:95「登録・更新はD-Security側の画面で行うため、D-WatchはGETのみ」★
docs/spec.md:98-101 ★F-09 スケジュール(参照のみ)★。「Pudu Cloud由来。変更はPudu Cloud管理画面で行う」
docs/spec.md:103-109 ★F-10 システム管理(P1限定スコープ)★。サブタブごとの扱いの表
docs/decisions.md:194-196(D-031) 点検記録は P1 スコープ。★隠すのはデモまでの一時対応であって、スコープは変えない★
docs/decisions.md:198-201(D-032) system の限定スコープ。★実装する = 表示設定 / 運用設定★、★実装しない = 通知設定 / 顧客管理 / グループ管理★、★スコープ外 = ユーザー管理 / 権限管理 / 監査ログ★
docs/decisions.md:330-334(D-053) ★機能しない絞り込みUIを画面に出さない★。「固定の選択肢だけがあって何も起きないUIは、不具合と区別できない」
docs/decisions.md:403-412(D-060) ★Schedule.end_time は「翌04:30」の整形済み文字列で返す★。2830 → "翌04:30"
docs/decisions.md:1052-1058(D-072 項7) ★点検記録は最後★。写真の置き場所・バケット・期限付き署名URLが未決
docs/decisions.md:2146-2179(D-079 項3) ★本作業の発端★。★:2171「schedules の fixtures 地雷は、プレースホルダ画面の指示書に必ず入れる」★/★:2173「inspections は『デモまで一時的に隠す』で正しい。D-031 のスコープは変えない」★
docs/decisions.md:2202-2245(D-080) ★facilities.contract は10桁文字列★。★数値比較禁止★
docs/fixtures.md:165-178(§7) 施設ロボットマスタの用意すべきケース
docs/fixtures.md:180-198(§8) ★スケジュールの補完ペア設計★。段階3 の地雷の一次資料
docs/fixtures.md:235-268(§12) ★ダッシュボードの日付ごとの期待値表★。★当日は planned=10 / completed=9 / anomaly 出ない★
CLAUDE.md §4.1 / §4.6 / §6-1 / §7 / §9.3 / §9.4 判定閾値 / 契約フラグ / YAMLが先 / 禁止事項 / API規約 / 判定ロジックのテスト

★雛形として読むもの(実装の作法を写す先)★

ファイル 何の雛形か
★app/(dashboard)/alerts/page.tsx(5行)★ ★ページの雛形★。"use client" は付けず、Screen コンポーネントを1つ返すだけ
★components/features/alerts/AlertsScreen.tsx(208行)★ ★画面の雛形★。"use client" / useTheme() / apiFetch / loading・error・0件 の3分岐(:148-153)/ CSS Modules
components/features/alerts/AlertsScreen.module.css ★CSS Modules の雛形★。★色は var(--tx-d) 等の CSS変数で書く★(app/globals.css:1-40)。★インラインの色が要るときだけ THEME_TOKENS[theme] を使う★(AlertsScreen.tsx:48)
★app/api/ds-devices/route.ts★ ★APIルートの雛形★。withRequestId / parseXxxQuery の422 / logApiError の500 / meta の組み立て
★lib/ds-devices/query.ts★ ★クエリ純粋関数の雛形★。parseDsDeviceQuery / filterDsDevicesByQ(:58-68。★大文字小文字を無視した部分一致★)/ sortDsDevices
★lib/ds-devices/__tests__/query.test.ts★ ★テストの雛形★。row(overrides) ヘルパ + describe ごとの分割
app/api/prechecks/route.ts / lib/prechecks/query.ts 同上のもう1例(ds-devices と見比べて共通の作法を掴む)

★踏まないでほしい地雷(先に頭に入れること)★

# 内容
1 ★lib/fixtures/schedules.ts に active: true を足すとダッシュボードが壊れます★。★段階3 の地雷警告を必ず読んでから触ること★
2 ★cwd のドライブレターは必ず大文字 C:\★。小文字だと Vitest が全滅します(既知の罠)
3 ★--reporter=basic は Vitest 4 で削除済み★。使うとロードに失敗しても exit 0 になり、★壊れていることに気づけません★。素の npm test を使うこと
4 ★lint は npm run lint(= eslint)★。★next lint は Next 16 で削除済み★
5 決定番号は追記直前に最終番号を確認する。★2026-09-07 に D-068 の二重採番が実際に起きました★
6 ★d-watch-mock.jsx:54-63 の ROBOTS は実在の店舗情報★。★見た瞬間にコピーしたくなる形をしていますが、絶対に使わないこと★

段階0の完了条件

  • 上の資料を読んだこと
  • git status がクリーンであること
  • ★着手前にユーザーへ確認すること(2件)の回答を得たこと★
  • npm test / npx tsc --noEmit / npm run lint を実行し、★実測値を控えたこと★ (作成時点の基準は 22ファイル / 461テスト / tsc 0 / lint 0。古くなっている可能性があります)
  • ★コミットしない★

段階1 — API契約を直す(d-watch-api.yaml)+ 型を足す

★CLAUDE.md §6-1「API契約を変えたくなったら、先に d-watch-api.yaml を直す」に従い、この段階を最初に置きます。★ 実装だけ変えて YAML と乖離させないためです。

1-1. ★Schedule スキーマに facility_id が無い★

d-watch-api.yaml:1361-1375:

    Schedule:                                                            # :1361
      type: object
      description: モックのSCHED(s/f/d/st/en/on)に対応
      properties:
        id: { type: integer, example: 21 }
        serial_number: { type: string, example: "8111R5628060011" }
        facility_name: { type: string, example: "バリューマート渋谷本店" }
        weekdays:
          type: string
          example: "1111111"
          description: 日月火水木金土(清掃する曜日=1)。link_schedules同様の7桁形式
        weekdays_label: { type: string, example: "毎日", description: 表示用ラベル(サーバ生成) }
        start_time: { type: string, example: "02:00" }
        end_time: { type: string, example: "03:00" }
        active: { type: boolean }

★facility_id がありません。★ しかし ★lib/types/index.ts:352 には facility_id: number があり、fixtures 13件すべてが値を持っています★。 ★YAML に追加してください★(serial_number の後、facility_name の前が自然):

        facility_id: { type: integer, example: 1 }

★「型と fixtures にあるものが YAML に無い」は、YAML を正とすると実装のほうが違反している状態です。★ ★実装側を削るのではなく YAML に足すのは、facility_id が「施設別の絞り込み」に将来必要になるためです★ (DsDevice(:1254-1258)も同じ形で facility_id と facility_name の両方を持っています)。

1-2. ★q パラメータを追加する(★確認2 の回答が「推奨どおり」だった場合★)★

★確認2 でユーザーが q の追加を承認した場合のみ実施してください。★

/facilities(:739-753)に追加:

        - name: q
          in: query
          schema: { type: string }
          description: 施設名 or 都道府県 or 住所 or シリアル番号 or メーカー or 機種(部分一致・大文字小文字を区別しない)

/schedules(:773-781)に追加:

        - name: q
          in: query
          schema: { type: string }
          description: 施設名 or シリアル番号(部分一致・大文字小文字を区別しない)

★既存の facility_name / serial / address は消さないこと★。 ★description に「画面の検索欄は q を使う。個別パラメータは互いに AND、q は個別パラメータと AND(q の内部だけが OR)」と明記すること★。 ★この AND / OR の関係を書いておかないと、次に触る人が必ず迷います。★

1-3. ★Facility / Schedule / Meta を実装と突き合わせる★

★facility_id 以外にも食い違いが無いか、必ず自分の目で突き合わせてください。★

YAML TS 突き合わせ結果(★作成時点の実測★)
Facility(:1337-1359) lib/types/index.ts:324-347 ★一致★(id / facility_name / prefecture / address / phone / manager_name / charger_name / email / monitoring_enabled / d_security_enabled / robots)
Facility.robots[](:1352-1359) RobotSummary(:317-322) ★一致★(id / maker / model / serial_number)
Schedule(:1361-1375) :349-360 ★facility_id だけ不足★ → 1-1 で追加
Meta(:1004-1009) lib/types/index.ts の Meta total / page / per_page。★一覧APIは必ずこれを返す★(CLAUDE.md §9.3)

★突き合わせて新たな食い違いを見つけたら、この表に追記したうえで直し、段階11 で記録すること。★

1-4. ★AdviceSetting の TS 型が存在しない(★調査で判明★)★

★d-watch-api.yaml:1229-1252 に AdviceSetting スキーマがありますが、lib/types/index.ts に対応する型がありません★(実測。grep -n "AdviceSetting" lib/types/index.ts が 0件)。 app/api/settings/advice/route.ts の GET は ★インラインのオブジェクトリテラル★ を返しています。

★CLAUDE.md §9.3「APIレスポンスは必ず型を定義してから実装する」に従い、lib/types/index.ts に AdviceSetting を追加してください★(段階6 の画面がこれを使います)。 ★YAML の :1229-1252 に合わせること★:

フィールド 型
rule `"R1" \ "R2" \ "R3" \ "R4" \ "B1" \ "B2" \ "B3"`
phase `"A" \ "B"`
level `1 \ 2 \ 3`
icon string
title string
text string
actions string[]
condition string(★発火条件の説明。編集不可★)
customized boolean(既定値から変更されているか)

★AdviceRuleId は lib/config/advice-rules.ts:16 にすでにあります★。★lib/types/ から lib/config/ を import するか、型を再定義するかは、既存の依存方向に合わせて判断してください★(★どちらにせよ2箇所に別々の union を書かないこと★)。

★ルート側(app/api/settings/advice/route.ts の GET)を、この型を返すように注釈すること★。★ロジックは変えないこと★ — 型注釈を足すだけです。

1-5. ★既知の不整合として記録するもの(★今回は直さない★)★

★InspectionDetail.photos の項目名が YAML と TS で食い違っています。★

側 実際の姿
★YAML(d-watch-api.yaml:1402-1405)★ ★item_type★ / enum: [brush, dust_box, filter, squeegee, suction_hose, waste_tank, brush_back](★英語 enum★)
★TS(lib/types/index.ts:364-377)★ ★item★ / `InspectionItemName = "ブラシ" \ "ダストボックス" \ ...`(★日本語リテラル★)

★キー名も値の形も違います。★ ★今回は inspections を実装しないので直しません★(禁止事項10 / D-072 項7)。 ★段階11 で「既知の不整合として未解決のまま残っている」ことを docs/decisions.md に記録してください。★ ★点検記録に着手する人が、実装を始める前にこれを解決する必要があります。★

1-6. ★★d-watch-api.yaml に実在の人名が漏れている(★調査で判明。ついでに直すこと★)★★

★d-watch-api.yaml の2箇所に、実在の人名がそのまま example として書かれています★(実測):

行 内容
★d-watch-api.yaml:861★ inspector_name: { type: string, maxLength: 100, example: "香原秀俊" }
★d-watch-api.yaml:1383★ inspector_name: { type: string, example: "香原秀俊" }

★出所は d-watch-mock.jsx:81-88 の INSPECTIONS 7件★(★点検者名が全件この名前。実在の店舗名も入っています★)。 ★CLAUDE.md §7「モックに残っている実在の住所・電話番号をそのまま使うこと」の禁止に該当します★(D-043 と同趣旨)。

★この段階で d-watch-api.yaml を開いているので、ついでにダミー名へ置換してください★(例: "点検 太郎")。 ★2行だけの変更で、inspections の実装には一切踏み込みません★(禁止事項10 に抵触しません)。 ★d-watch-mock.jsx 側は書き換えないこと**★ — ★モックは「画面レイアウト・文言・遷移の正」として保存されている資料で、本作業の対象外です★。 ★段階11 で「YAML の inspector_name の example をダミー名に置換した」ことを記録すること★。

段階1の完了条件

  • ★d-watch-api.yaml の Schedule に facility_id があること★(grep -n "facility_id" d-watch-api.yaml で Schedule 配下にヒットすること)
  • ★確認2 が承認された場合★: /facilities と /schedules に q があり、★AND / OR の関係が description に書かれていること★
  • ★lib/types/index.ts に AdviceSetting があること★
  • ★InspectionDetail.photos の不整合を直していないこと★(記録するだけ。★直すと段階11 の記録と矛盾します★)
  • ★grep -n "香原" d-watch-api.yaml が 0件であること★(1-6)
  • npx tsc --noEmit エラー0 / npm run lint 0 / npm test 全パス(★この段階ではまだ全部通るはず★)
  • ★ここで1コミット★(D-050)

段階2 — GET /api/facilities を作る

2-1. 作るもの

ファイル 内容
★新規★ app/api/facilities/route.ts ルート本体。★雛形は app/api/ds-devices/route.ts★
★新規★ lib/facilities/query.ts ★フィルタ・ページングの純粋関数★。★雛形は lib/ds-devices/query.ts★
★新規★ lib/facilities/__tests__/query.test.ts テスト。★雛形は lib/ds-devices/__tests__/query.test.ts★

★必ず ds-devices / prechecks の現物を開いて、エラー形式・meta・ログの作法を写してください。★ ★この指示書に書いてある形と現物が違ったら、★現物が正★です(この指示書のほうが古い可能性があります)。★

2-2. ★フィルタとページングは API ルート側で組む★

★db.facilities()(lib/db/index.ts:99-101)は全件返すだけです。★ これは意図した設計で、lib/db/index.ts:50-54 にこう書かれています:

データソースが実装すべきインターフェース。 フィルタや集計はこの層では行わず、APIルート側で組み立てます (実DB接続時にクエリへ落とすときの差分を小さくするため)。

★この方針に従ってください。lib/db/ にフィルタを足さないこと。★

★注記(実測)★: ★prismaSource 側(lib/db/index.ts:153-164)は facilities / schedules / inspections / inspectionDetail のいずれも notImplemented() です★。 ★したがって今回作る API ルート2本は USE_FIXTURES のときだけ動きます★。★これは意図した状態です★(実DB接続は別作業。禁止事項9)。 ★prismaSource を実装しようとしないこと。段階11 で「実DB接続時には別途 prismaSource の実装が要る」ことを申し送りとして記録してください。★

2-3. クエリパラメータ

パラメータ 挙動
q ★施設名 / 都道府県 / 住所 / シリアル / メーカー / 機種 を OR で部分一致★(★確認2 で承認された場合★)
facility_name 施設名の部分一致
serial ★robots[].serial_number を横断して部分一致★(下記 2-4)
address 住所の部分一致
page / per_page PAGINATION(lib/config/index.ts)の defaultPerPage: 50 / maxPerPage: 200。★不正値でも422にせず既定値・上限へ丸める★(parseDsDeviceQuery と同じ挙動)

★大文字小文字を無視した部分一致にすること★(モックの挙動。d-watch-mock.jsx:998-1002 が .toLowerCase() している)。 ★filterDsDevicesByQ(lib/ds-devices/query.ts:59-68)がそのまま雛形になります。★

2-4. ★serial は施設が持つロボットを横断する★

★施設は0台〜3台のロボットを持ちます。★ serial の部分一致は ★どれか1台でも一致すればその施設をヒットさせる★ 形にしてください。

// イメージ(実装は任せます)
items.filter((f) => f.robots.some((r) => r.serial_number.toLowerCase().includes(needle)))

★robots が空配列の施設で落ちないこと★ — some() は空配列に対して false を返すので自然に安全ですが、★テストで固定してください★(lib/fixtures/facilities.ts の ★id12(フレッシュタウン湖畔店)が robots: []★)。

2-5. meta を返す

★一覧APIは必ず meta: { total, page, per_page } を返す★(CLAUDE.md §9.3)。 ★total は「フィルタ後・ページング前」の件数★(app/api/ds-devices/route.ts の const total = sorted.length; と同じ)。

★/facilities に summary はありません★(d-watch-api.yaml:754-765 は items と meta だけ)。 ★SummaryListResponse ではなく items + meta のレスポンス型を使うこと★(lib/types/index.ts の既存の一覧レスポンス型を確認してから決めること)。

2-6. 並び順

★YAML にもモックにも並び順の指定がありません。★ ★id の昇順で安定させてください★(sortDsDevices が「安定化のためだけの規則」として serial_number 昇順にしているのと同じ趣旨)。 ★理由を関数の docstring に書くこと★ — 「運用上の優先度を表すものではなく、画面の順序がリロードで変わらないようにするための規則」。

2-7. テスト(★期待値表を先に作ること★。CLAUDE.md §9.4)

# ケース 期待
1 ★0件★(空配列を渡す) [] / meta.total = 0。★落ちない★
2 ★1件★ そのまま返る
3 ★部分一致(施設名)★ メガバリュー で複数ヒット
4 ★大文字小文字違い★ 8111r で 8111R5628060011 にヒットする
5 ★該当なし★ [] / meta.total = 0
6 ★ページング境界★ per_page=5 で page=1 / page=2 / page=3(★最終ページが端数になること★)/ 範囲外の page=99 は [] だが ★meta.total は全件数のまま★
7 ★ロボット0台の施設★ serial 検索で落ちない・ヒットしない
8 ★複数台の施設★ 3台のうち3台目のシリアルで検索してもヒットする(lib/fixtures/facilities.ts の ★id7 が3台★)
9 ★q の OR★ 住所の文字列で検索して施設名が違う施設がヒットする
10 ★複数パラメータの AND★ facility_name と address を同時に指定して、両方満たす施設だけが残る
11 ★per_page の丸め★ per_page=9999 → 200(maxPerPage)/ per_page=0 → 1 / page=-1 → 1

★テストは fixtures ではなく row(overrides) ヘルパで組んだ合成データで書くこと★(lib/ds-devices/__tests__/query.test.ts:11-21 の作法)。 ★fixtures に依存すると、fixtures を1件足しただけでテストが落ちます。★

段階2の完了条件

  • app/api/facilities/route.ts / lib/facilities/query.ts / lib/facilities/__tests__/query.test.ts が存在すること
  • ★lib/db/index.ts に変更が入っていないこと★(git diff --stat lib/db/ が空)
  • ★期待値表の11ケースがテストに入っていること★
  • npx tsc --noEmit エラー0 / npm run lint 0 / npm test 全パス(★テスト数が増えていること★)
  • ★ここで1コミット★

段階3 — GET /api/schedules を作る

★★★この段階には地雷があります。実装より先に 3-3 を読んでください★★★

3-1. 作るもの

ファイル 内容
★新規★ app/api/schedules/route.ts 段階2 と同じ形
★新規★ lib/schedules/query.ts フィルタ・ページングの純粋関数
★新規★ lib/schedules/__tests__/query.test.ts テスト

3-2. クエリパラメータ

パラメータ 挙動
q ★施設名 / シリアル を OR で部分一致★(★確認2 で承認された場合★)
facility_name 施設名の部分一致
serial ★serial_number の部分一致★(★Schedule は1レコードに1シリアルなので、段階2 のような横断は不要★)
page / per_page 段階2 と同じ

並び順は ★id の昇順★(段階2 と同じ理由)。

3-3. ★★★地雷 — lib/fixtures/schedules.ts に active: true を追加しないこと★★★

★この地雷は「エラーも出ず、テストも通るのに、ダッシュボードの既定表示が異常系になる」タイプです。★ ★D-079 項3(docs/decisions.md:2171)が「この指示書に必ず入れる」と名指しした項目です。★

何が起きるのか

★lib/dashboard/aggregate.ts:93 の1行がダッシュボードの「清掃予定件数」です★:

// lib/dashboard/aggregate.ts:89-93
const dow = weekdayIndex(date);
const planned =
  dow === null
    ? 0
    : schedules.filter((s) => s.active && s.weekdays[dow] === "1").length;   // :93

★施設を区別しない、フラットな件数カウントです。★ どの施設のログかは一切参照しません。

一方 lib/fixtures/clean-logs.ts の当日分は ★曜日に関係なく毎日必ず10行★ 生成されます(実行日からの相対生成)。 ★この2つを常に一致させるために、fixtures は「どの曜日でも planned = 10 になる」よう設計されています。★

構成 内訳
補完ペア① ★id25(平日のみ 0111110)+ id26(土日のみ 1000001)★ → 全曜日を過不足なくカバー → ★常に合計1件★
補完ペア② ★id23(月水金 0101010)+ id30(日火木土 1010101、id23 の反転)★ → ★常に合計1件★
毎日(1111111) id21 / id22 / id27 / id28 / id29 / id31 / id32 / id33 の ★8件★
★合計★ ★1 + 1 + 8 = 10。どの曜日でも常に10件★

何をすると壊れるのか

操作 症状
★active: true を1件追加する★ ★planned が 11 になる★。当日ログは10行のまま → 画面が ★「9 / 11 完了」★ と出る(components/features/dashboard/ScheduleProgressCard.tsx:25-27 が {completed} / {planned} 完了 を描画)。さらに ★app/api/dashboard/route.ts:84-92 の data.anomaly warn が出続けます★
★曜日パターン付きで active: true を追加する★ ★その曜日に当たった日だけ症状が出ます★。★一番タチが悪い★ — 実装した日には再現せず、数日後に「なぜか壊れている」状態で発見されます
★既存の active: true を削除・無効化する★ ★planned が 9 以下になる★。同じく anomaly が出ます
★補完ペアの weekdays を書き換える★ ★曜日によって planned が変動します★。id23↔id30 / id25↔id26 の対応が崩れるため
★id24 を削除する★ ★planned は変わりません(active: false なので)が、★唯一の無効スケジュール★ が消えて判定ロジックの確認ケースが失われます★

★安全な操作★

操作 可否
★active: false の追加★ ★何件でも安全★。s.active が先に false になるため planned に寄与しません
フィールドの追加(facility_id など) 安全
start_time / end_time / weekdays_label の変更 安全(planned は active と weekdays しか見ていないため)

★番人★

★lib/fixtures/__tests__/schedules.test.ts(59行)が番人です。★

行 内容
:29 describe("fixtures の不変条件: schedules と clean-logs の当日行数(D-050)")
:36 test("前提: 当日分の清掃ログが1件以上存在する")
:41 ★7曜日分をループで生成するテスト★ — 「◯曜日: 有効スケジュールの該当件数が当日の清掃ログ行数と一致する」
★合計★ ★8テスト★(前提1 + 7曜日)

★lib/fixtures/schedules.ts を変更したら必ず npm test を実行し、この8テストが通ることを確認してください。★

★参照先の書き方に注意★

★この設計を説明するときに「D-050」と書かないでください。★

番号 実際の内容
docs/decisions.md:308 の D-050 ★「検証(型チェック・lint・テスト)が通った時点で作業ブランチにコミットする」★ — ★補完ペア設計とは無関係★
lib/fixtures/schedules.ts のコメント内の「D-050」 ★補完ペア設計を指している★(:21 / :83 / :108 / :121 / :170 / :184 / :197 / :209)

★番号で参照すると必ず混乱します。★ ★参照するなら docs/fixtures.md §8(:180-198)と §12(:235-268)を使ってください。★ ★既存コメント内の「D-050」表記は、今回の作業では書き換えないこと★(本作業の範囲外で、差分が増えるだけです)。

3-4. ★DB 側の注意(将来の prismaSource 実装者向け。★今回は実装しません★)★

★今回 prismaSource には手を付けません(禁止事項9)★が、 ★lib/schedules/query.ts の docstring に次の4点を書き残してください。★ ★実DB接続時に「型エラーもテスト失敗も出ないまま静かに壊れる」箇所だからです。★

# 内容
1 ★論理が反転している★ — prisma/schema.prisma:512 の CleanSchedule.inactive(Int @default(0)。★0 = 有効★)。API/TS は active: boolean。★active: Boolean(row.inactive) と書くと全件反転します★。正しくは active: row.inactive === 0
2 ★カラム名が違う★ — DB は weeks(prisma/schema.prisma:504、VarChar(7))、API/TS は weekdays
3 ★時刻は HHMM の4桁文字列★(prisma/schema.prisma:506 / :509)。★end_time の「時」は 24〜29 を取りうる★("2830" = 翌日4:30)。★素朴な HH:MM パースは壊れます★。★API は D-060 に従い "翌04:30" の整形済み文字列で返す★
4 ★weekdays_label は DB に存在しません★。★サーバ側で weeks から生成する必要があります★

3-5. テスト(★期待値表★)

# ケース 期待
1 ★0件★ [] / meta.total = 0
2 ★1件★ そのまま返る
3 ★部分一致(施設名)★ ヒットする
4 ★大文字小文字違い★ 8111r で 8111R... にヒット
5 ★該当なし★ []
6 ★ページング境界★ 段階2 の #6 と同じ
7 ★active: false の行も返る★ ★一覧は有効・無効の両方を返す★(画面が「有効」列で見せ分ける。★API 側でフィルタしないこと★)
8 ★q の OR★ シリアルの一部で検索して施設名が違う行がヒット
9 ★per_page の丸め★ 段階2 の #11 と同じ

段階3の完了条件

  • app/api/schedules/route.ts / lib/schedules/query.ts / lib/schedules/__tests__/query.test.ts が存在すること
  • ★git diff --stat lib/fixtures/schedules.ts が空であること★(★この段階では fixtures を1文字も触っていないはず★)
  • ★lib/fixtures/__tests__/schedules.test.ts の8テストが全部通ること★
  • ★3-4 の4点が lib/schedules/query.ts の docstring に書かれていること★
  • ★期待値表の9ケースがテストに入っていること★
  • npx tsc --noEmit エラー0 / npm run lint 0 / npm test 全パス(★テスト数が増えていること★)
  • ★ここで1コミット★

段階4 — 施設ロボットマスタ画面(F-08)

4-1. 作るもの

ファイル 内容
★新規★ components/features/facilities/FacilitiesScreen.tsx 画面本体
★新規★ components/features/facilities/FacilitiesScreen.module.css スタイル
★差し替え★ app/(dashboard)/facilities/page.tsx PlaceholderScreen → FacilitiesScreen

page.tsx は ★app/(dashboard)/alerts/page.tsx と同じ5行の形★ にしてください。

4-2. ★モックの現物を正とする★(CLAUDE.md §5)

★d-watch-mock.jsx:971-1035 を実際に開いて写してください。★ 以下は要点です。

要素 内容
h1 ★施設ロボットマスタ★(:975)。★サブタイトルなし★(AlertsScreen.tsx:98 のような subtitle は付けない)
検索input ★1つ★。placeholder = ★施設名 / シリアル / 住所★(:977)
表の列(★10列・原文のまま★。:986-995) ★施設名 / 都道府県 / 住所 / 電話番号 / 責任者名 / 担当者名 / メール / 監視 / D-Sec / ロボット(メーカー / 機種 / シリアル)★
監視 列(:1013) ★true → ○(緑 c.ok)/ false → ー(c.txM)★。中央寄せ・fontSize 16
D-Sec 列(:1014) ★true → ○(★シアン c.ac★)/ false → ー(c.txM)★
ロボット列(:1015-1025) ★1台1行★。★メーカーをピル(Pill)★ / ★機種は通常テキスト★ / ★シリアルは monospace★
フッタ(:1032) ★全{n}施設★
横スクロール(:983-984) ★minWidth: 1300 相当の表を overflow-x: auto で包む★
施設名 fontWeight: 600(:1006)
メール ★monospace・fontSize 11★(:1012)
行 verticalAlign: top(:1005。★ロボット複数台のとき先頭行に揃うようにするため★)

★色は CSS変数(var(--ok) / var(--ac) / var(--tx-m) 等)で書くこと★(app/globals.css:1-40)。 ★Pill は color を文字列で受け取る(components/ui/Pill.tsx)ので、メーカーのピルだけは THEME_TOKENS[theme].pr を渡してください★(AlertsScreen.tsx:48, 166 が前例)。

4-3. ★★📥 インポート と + 新規追加 ボタンは実装しないこと★★

事実 出典
★登録・更新は D-Security 側の画面で行うため、D-Watch は GET のみ★ ★docs/spec.md:95★ / d-watch-api.yaml:736
★モックのボタンには onClick がありません★ ★d-watch-mock.jsx:978-979★(★飾りです★)
★動かないボタンを出すのは D-053 に抵触します★ docs/decisions.md:330-334

★ボタン自体を出さないこと。★ ★グレーアウトして置いておくのも駄目です★ — 「あるのに使えない」は「不具合と区別できない」の典型です。

4-4. ★★実在の個人情報を絶対に使わないこと★★

★d-watch-mock.jsx:54-63 の ROBOTS 9件は、実在の店舗名・住所・電話番号・メールです。★

例: MEGAドンキ渋谷本店 / 渋谷区宇田川町28-6 / 03-5428-4086 / shibuya@donki.co.jp

★1文字もコピーしないこと★(CLAUDE.md §7 / D-043)。 ★必ず lib/fixtures/facilities.ts を使ってください★ — こちらは架空値に置換済みです:

メガバリューマート中央本店 / 東京都○○区1-2-3 / 03-0000-0001 / store001@example.com

★画面のプレビュー用のダミー、コメント内の例、テストの期待値、いずれにも使わないこと。★

4-5. 0件時の表示

★モックには0件の分岐がありません。★ ★AlertsScreen.tsx:151-153 の作法に倣ってください★:

{!loading && !error && items.length === 0 && (
  <div className={styles.empty}>{t("該当する施設はありません")}</div>
)}

★loading / error / 0件 / データあり の4分岐すべてを作ること★(AlertsScreen.tsx:148-205 が全部の例です)。

4-6. データ取得

  • ★apiFetch(lib/api/client.ts)を使う★。エラーは ApiFetchError の serverMessage を優先し、無ければ既定文言(AlertsScreen.tsx:78-81)
  • ★per_page は PAGINATION.maxPerPage(200)を渡す★(AlertsScreen.tsx:64 と同じ。★fixtures は12件なので1ページに収まります★)
  • ★検索は q を送る★(★確認2 で承認された場合★)
  • ★フッタの「全{n}施設」は meta.total を使うこと★(items.length ではありません。★ページングが入ったときに嘘の数字になります★)

段階4の完了条件

  • /facilities が PlaceholderScreen でなくなっていること
  • ★grep -rn "MEGAドンキ\|ドンキ\|donki.co.jp\|宇田川町\|03-5428" components/features/facilities/ が 0件★
  • ★grep -n "インポート\|新規追加" components/features/facilities/ が 0件★
  • 0件時の表示があること
  • npx tsc --noEmit エラー0 / npm run lint 0 / npm test 全パス
  • ★ここで1コミット★

段階5 — スケジュール管理画面(F-09)

5-1. 作るもの

ファイル 内容
★新規★ components/features/schedules/SchedulesScreen.tsx 画面本体
★新規★ components/features/schedules/SchedulesScreen.module.css スタイル
★差し替え★ app/(dashboard)/schedules/page.tsx PlaceholderScreen → SchedulesScreen

5-2. ★モックの現物★(d-watch-mock.jsx:1037-1069)

要素 内容
h1 ★スケジュール管理★(:1041)
★注意★ ★ナビのラベルは 📅 スケジュール(components/layout/AppShell.tsx:22)で、h1 と一致しません★。★これはモックどおりです★(モックのナビも 📅 スケジュール、h1 は スケジュール管理)。★揃えないこと★
検索input placeholder = ★施設名 / シリアル★(:1042)
表の列(★5列★。:1047-1051) ★シリアル / 施設名 / 曜日 / 時間 / 有効★
シリアル ★monospace・fontSize 12★(:1057)
時間 ★{start_time} - {end_time}★(:1060)
有効 列(:1061) ★on → ●(緑 c.ok)/ off → ○(★赤 c.ng★)★。★fontSize 18・中央寄せ★
無効行 ★行全体 opacity: 0.5★(:1056)
★ボタン・行クリック★ ★無し。完全な参照専用★
★フッタ★ ★モックには無い★。★付けないこと★(施設マスタと違って 全{n}件 の表示はモックに存在しません)

5-3. ★曜日 は weekdays_label を出す★

★weekdays(7桁の "1111111")を画面で解釈しないこと。★ ★weekdays_label(サーバ生成の表示用ラベル。"毎日" / "月水金" / "平日のみ" / "土日のみ" / "日火木土")をそのまま出してください。★

★理由★: CLAUDE.md §9.6「判定結果はAPIから受け取る。フロントで再計算しない」と同じ趣旨です。 ★7桁の解釈ロジックが画面とサーバの2箇所にあると、曜日の起点(日曜始まり)がズレたときに片方だけ直る事故が起きます。★

5-4. ★end_time をパースしないこと★

★end_time は「翌04:30」のような整形済み文字列で来ます★(★D-060★。docs/decisions.md:403-412)。

DB の値 API が返す値
0300 "03:00"
2830 ★"翌04:30"★

★画面で時刻をパースして計算しないこと。★ ★{start_time} - {end_time} と並べるだけです。★ ★fixtures には日跨ぎのケースがあります★ — ★id27(メガバリューマート港南総本店)が start_time: "23:30" / end_time: "00:30"★(lib/fixtures/schedules.ts:133-143)。 ★この行が「23:30 - 00:30」と表示されて崩れないことを、段階10 で目視確認してください。★

5-5. 0件時の表示

段階4 と同じ作法(AlertsScreen.tsx:151-153)。

段階5の完了条件

  • /schedules が PlaceholderScreen でなくなっていること
  • ★weekdays の7桁を画面で解釈していないこと★(grep -n "weekdays\[" components/features/schedules/ が 0件)
  • ★end_time をパース・計算していないこと★(grep -n "split(\":\")\|parseInt\|Number(" components/features/schedules/ を見て、時刻の計算が無いこと)
  • 無効行が opacity: 0.5 になっていること
  • 0件時の表示があること
  • npx tsc --noEmit エラー0 / npm run lint 0 / npm test 全パス
  • ★ここで1コミット★

段階6 — 運用設定画面(F-10、★読み取り専用★)

★着手前確認1 の結果に従ってください。以下は当方の推奨スコープ(運用設定のみ・読み取り専用)での手順です。★

6-1. 作るもの

ファイル 内容
★新規★ components/features/system/SystemScreen.tsx 画面本体
★新規★ components/features/system/SystemScreen.module.css スタイル
★差し替え★ app/(dashboard)/system/page.tsx PlaceholderScreen → SystemScreen

6-2. ★タブは「運用設定」1つだけ★

★モックは9タブありますが(d-watch-mock.jsx:1156-1166)、D-032(docs/decisions.md:198-201)で実装対象は2つだけです。★

タブ D-032 での扱い 今回
表示設定 ★実装する★ ★作らない★(確認1。永続化とダッシュボード側の対応が本作業の範囲を超えるため。★P1 後半の宿題として段階11 で記録★)
★運用設定★ ★実装する★ ★作る(読み取り専用)★
通知設定 / 顧客管理 / グループ管理 ★実装しない★(D-Security側画面を流用) 作らない
ユーザー管理 / 権限管理 / 監査ログ ★スコープ外★(P2以降) 作らない

★タブが1つしかないなら、タブUIそのものを出さないことも検討してください。★ ★1つしか選べないタブ列は「他にもあるはずなのに無い」という誤解を生みます。★ ★当方の推奨は「タブUIを出さず、h1 システム管理 の下にセクション見出し 運用設定 を置く」★ですが、★判断は実装者に委ねます。採った形を段階11 で記録すること★。

6-3. ★モックの既知のバグ — ops タブが二重定義されている★

★モックの system にはバグがあります。実装前に知っておいてください。★

箇所 内容
d-watch-mock.jsx:1158 { id: "ops", label: t("運用設定") } ★1回目★
★d-watch-mock.jsx:1164★ ★{ id: "ops", label: t("運用設定") } 2回目(同じ id)★
d-watch-mock.jsx:1221 {sysTab === "ops" && ( ★本文1回目★
★d-watch-mock.jsx:1628★ ★{sysTab === "ops" && ( 本文2回目★

★React は同じ条件の分岐を2つとも描画するので、モックでは運用設定のカードが縦に2つ並びます。★ ★どちらかに寄せる必要があります。★

★当方の推奨は :1628 側です★:

理由 内容
1 ★カード1枚に3セクションが統合されている★(:1630 が1枚のカード、その中に事前チェック / 判定閾値 / エスカレーション)。:1221 側はカードが分かれている
2 ★× グレードに「上記未満」表記がある★(:1670)。:1221 側にはこの配慮が無い
3 ★「変更はDFAシステム管理者のみ」の注記がある★(:1633)。★権限の話が入っている=後から書かれたように見える★

★ただし、どちらが正かはモックからは判断できません。★ ★「推奨」であって「確定」ではないことを理解したうえで採用し、採った側を段階11 で記録してください。★

6-4. ★★閾値をハードコードしないこと★★

★CLAUDE.md §7 の禁止事項です。必ず lib/config/ から読んでください。★

★lib/config/index.ts の実際のエクスポート名を自分で読んで確認すること。★ ★作成時点の実測は次のとおりです★:

表示するもの 読む先 作成時点の値
事前チェック 第1回 / 第2回 ★PRECHECK_MINUTES_BEFORE★ [60, 30] as const
◎ の閾値 ★GRADE_THRESHOLDS.excellent★ 90
○ の閾値 ★GRADE_THRESHOLDS.good★ 70
△ の閾値 ★GRADE_THRESHOLDS.poor★ 10
Lv2 の連続日数 ★ESCALATION_THRESHOLDS.level2Days★ 2
Lv3 の連続日数 ★ESCALATION_THRESHOLDS.level3Days★ 3

★PRECHECK_MINUTES_BEFORE は配列です★。★「第1回 = [0]、第2回 = [1]」と決め打ちせず、配列を map して「第{i+1}回チェック: {n}分前」と描くほうが安全です★(将来3回になっても壊れません)。

6-5. ★★閾値の文言 — モックの「以上」をそのまま写さないこと★★(★調査で判明★)

★モックと確定仕様が食い違っています。★

側 ◎ ○ △ ×
★モック(d-watch-mock.jsx:1660-1663)★ ★90 以上★ ★70 以上★ 10 以上 上記未満
★CLAUDE.md §4.1(★確定仕様★)★ ★90% 超★ ★70% 超★ ★10% 以上 70% 以下★ 10% 未満、または未実施
★lib/config/index.ts のコメント(★実装★)★ ★「この値を超えると ◎(90.0 は ○ になる)」★ ★「この値を超えると ○(70.0 は △ になる)」★ 「この値を下回ると ×(10.0 は △ のまま。D-020b)」 —

★CLAUDE.md §5 の「モックが文言の正」より、§4.1 の確定仕様が上位です。★ ★画面には「90% 超」「70% 超」「10% 以上」と書いてください。★ ★モックの「以上」を写すと、90.0% が ◎ に見える誤った説明になります。★ ★この判断を段階11 で記録すること。★

6-6. 表示内容(★すべて読み取り専用★)

セクション 内容
★事前チェック設定★ 第1回 60分前 / 第2回 30分前(★PRECHECK_MINUTES_BEFORE から★)。説明「清掃開始予定時刻の何分前にロボット状態をチェックするか」
★完了率の判定閾値★ ◎ 90% 超 / ○ 70% 超 / △ 10% 以上 / × 上記未満(★6-5 の文言★)。★GradeBadge(components/ui/GradeBadge.tsx)が使えるか確認すること★
★アドバイス エスカレーション閾値★ Lv2 = 2日以上連続 / Lv3 = 3日以上連続。★注記「『連続』はカレンダー日ではなくスケジュール存在日の連続」を必ず入れること★(★D-026★。docs/decisions.md:122。CLAUDE.md §4.5 も同旨)
★アドバイス文言の一覧★ 下記 6-7

6-7. ★アドバイス文言の一覧★

★GET /api/settings/advice(実装済み)から取得してください。★ ★レスポンスは { items: AdviceSetting[] }★(段階1-4 で型を足しています)。7件(R1〜R4 / B1〜B3)が返ります。

フィールド 表示
rule ルールID(R1 等)
icon / level アイコンとレベルバッジ(level は 1=注意 / 2=警告 / 3=重大。lib/config/advice-rules.ts:22)
title 見出し
text 推定原因
actions 推奨アクション(★配列なのでリストで出す★)
★condition★ ★発火条件。「編集不可」であることを画面に明示すること★(d-watch-api.yaml:1246-1249「発火条件の説明(編集不可)」/ lib/config/advice-rules.ts:30)
customized 既定値から変更されているか。★「編集済み」バッジに使えます★

★GET だけを使うこと。PATCH(d-watch-api.yaml:572-599)は今回使いません。★ ★lib/config/advice-rules.ts を画面から直接 import しないこと★ — ★API は既定値に運用設定の編集内容を重ねて返します★(app/api/settings/advice/route.ts の loadAdviceRules())。★設定ファイルを直接読むと、編集済みの文言が画面に出なくなります。★

★注意★: ★指示書K の段階7-B が lib/config/advice-rules.ts:111(B2)と :121(B3)の condition 文字列を書き換えます★。 ★この画面は API 経由で読むので影響を受けませんが、★指示書K を先に実行した場合は表示される文言が変わります★。★不具合ではありません。★

6-8. ★「編集は P1 後半で対応します」と明示する★

★画面のどこか(見出しの近く、または各セクションの上)に明示してください。★

★この画面は現在★参照のみ★です。設定値の編集は P1 後半で対応します。★

★動かないトグル・入力欄・保存ボタンを置かないこと★(D-053)。 ★モックの <input type="number">(:1643 / :1648 / :1668 / :1684 / :1689)は ★defaultValue だけで onChange も保存先も無い飾り★ です。★値をテキストとして表示してください。★

段階6の完了条件

  • /system が PlaceholderScreen でなくなっていること
  • ★grep -nE "\b(90|70|10|60|30)\b" components/features/system/SystemScreen.tsx に閾値の数値リテラルが無いこと★(★すべて lib/config/ 由来★。★CSS の px 値は対象外なので .module.css は除いて確認すること★)
  • ★「90% 超」「70% 超」と表示されていること★(★「90% 以上」ではない★。6-5)
  • ★「『連続』はスケジュール存在日の連続」の注記があること★(D-026)
  • ★condition が「編集不可」と明示されていること★
  • ★「編集は P1 後半で対応します」が画面に出ていること★
  • ★<input> / <button>(保存系)を1つも置いていないこと★
  • ★「表示設定」タブを作っていないこと★
  • npx tsc --noEmit エラー0 / npm run lint 0 / npm test 全パス
  • ★ここで1コミット★

段階7 — inspections をメニューから隠す

7-1. 直すのは1行だけ

★components/layout/AppShell.tsx:12★:

const MENU_MONITORING = [
  { href: "/detail-log", id: "detailLog", label: "📋 清掃詳細ログ" },
  { href: "/alerts", id: "alert", label: "🔔 アラート" },
  { href: "/reports", id: "report", label: "📈 レポート" },
  { href: "/inspections", id: "inspection", label: "🔧 点検記録" },   // ★:12 この行★
] as const;

7-2. ★削除ではなくコメントアウトし、理由をコメントで残すこと★

★復活させるときに、何を復活させればよいかが1行で分かる形にしてください。★

  // ★デモまで一時的に隠す(D-079 項3)★
  //   D-031 の「点検記録は P1 スコープ」は変えていない。
  //   写真ストア(バケット・期限付き署名URL)が未着手のため画面が成立しないため(D-072 項7)。
  //   ★復活させるときはこの1行のコメントを外すだけでよい★
  //   (`app/(dashboard)/inspections/page.tsx` と `lib/i18n.ts:14` は残してある)。
  // { href: "/inspections", id: "inspection", label: "🔧 点検記録" },

7-3. ★残すもの★

対象 理由
★app/(dashboard)/inspections/page.tsx★ ★直URLでは到達可能なままにする。これは意図した状態です★(メニューから消すだけで、スコープからは外していないため)
★lib/i18n.ts:14 の "🔧 点検記録": "🔧 Inspections"★ ★復活させるときに要ります★
★lib/i18n.ts:39 の 点検記録: "Inspection Records"★ ★同上★(page.tsx が PlaceholderScreen title="点検記録" で使っています)
★components/layout/PlaceholderScreen.tsx★ ★inspections がまだ使っています★(禁止事項13)
★lib/fixtures/inspections.ts / db.inspections()★ 触らない

7-4. ★型エラーは出ません★

★MENU_MONITORING は as const の配列リテラルです。★ ★この1行を消しても、要素数に依存した型は無く、m.id は key にしか使われていないため型エラーは出ません★(AppShell.tsx を読んで確認してください)。 ★逆に言えば、消したことをコンパイラは教えてくれません。段階10 の目視確認が唯一の検証です。★

段階7の完了条件

  • ★npm run dev 相当の環境でメニューに「🔧 点検記録」が出ないこと★(★段階10 で確認★)
  • ★app/(dashboard)/inspections/page.tsx が残っていること★
  • ★lib/i18n.ts:14 と :39 が残っていること★
  • ★コメントに「D-079 項3」「D-031 のスコープは変えない」「D-072 項7」の3つが書かれていること★
  • npx tsc --noEmit エラー0 / npm run lint 0 / npm test 全パス
  • ★ここで1コミット★

段階8 — i18n

8-1. ★新しく追加した文言をすべて lib/i18n.ts の EN に足す★

★lib/i18n.ts はキーが日本語原文のフラット辞書1枚です。完全一致でしか引けません。★ ★キーに無い文言は原文(日本語)のまま出ます — エラーにはならないので、★足し忘れに気づけません★。

8-2. ★すでに定義済みのもの(★重複キーを作らないこと★)★

分類 キー 行
メニューラベル 🔧 点検記録 / 🏢 施設ロボットマスタ / 📅 スケジュール / ⚙ システム管理 ★:14 / :17 / :18 / :19★
セクション見出し モニタリング / 設定 ★:20 / :21★
画面タイトル 施設ロボットマスタ / スケジュール管理 / システム管理 / 点検記録 ★:36 / :37 / :38 / :39★
その他 準備中 ★:50★
表の列(★流用できるもの★) 施設名 / シリアル / 機種 ★:22 / :24 / :23★
数値混じり 全{n}施設を表示 → ★:95★

★上のキーを再定義しないこと。★ ★オブジェクトリテラルの重複キーは後勝ちで上書きされ、lint が拾わない可能性があります。★ ★足す前に必ず grep -n "キー名" lib/i18n.ts で確認してください。★

8-3. ★足す必要があるもの(★実測。着手時に再確認すること★)★

画面 足す必要があるキーの例
F-08 都道府県 / 住所 / 電話番号 / 責任者名 / 担当者名 / メール / 監視 / D-Sec / ロボット(メーカー / 機種 / シリアル) / 該当する施設はありません
F-09 曜日 / 時間 / 有効 / 該当するスケジュールはありません
F-10 運用設定 / 事前チェック設定 / 完了率の判定閾値 / アドバイス エスカレーション閾値 / 分前 / 日以上連続 / 編集不可 / 編集済み / 推定原因 / 推奨アクション / 発火条件 / 編集は P1 後半で対応します ほか

★この表は網羅ではありません。★ ★実装した文言を自分で洗い出してください。★ ★t() を通していない日本語リテラルが画面に残っていないかを、実装後に目で確認すること。★

8-4. ★数値が混ざる文言はキーにできない★

★translate() はキーの完全一致でしか引けません。★ ★全12施設 をキーにはできません。★

★方式A(プレースホルダ + replace)を使ってください★(lib/i18n.ts:78-99 にこの2方式の説明とトレードオフが書いてあります。★方式A が推奨★):

t("全{n}施設").replace("{n}", String(meta.total))

★全{n}施設を表示 →(:95)はすでにありますが、全{n}施設 はありません(実測)。★ ★追加が必要かを実装時に確認してください★ — フッタの文言をどちらにするかで変わります(★モックのフッタは 全{n}施設★)。

★方式B(t("全") + n + t("施設"))は使わないこと★ — ★全 のような1文字キーは他画面の文言と衝突します★(lib/i18n.ts:92-93 の警告)。

段階8の完了条件

  • ★lib/i18n.ts に重複キーが無いこと★(grep -o '^ "\?[^":]*"\?:' lib/i18n.ts | sort | uniq -d が 0件、程度の確認でよい)
  • ★3画面で t() を通していない日本語リテラルが無いこと★(★見出し・列名・空表示・注記すべて★)
  • ★数値混じりの文言が方式A になっていること★
  • npx tsc --noEmit エラー0 / npm run lint 0 / npm test 全パス
  • ★ここで1コミット★

段階9 — テスト(最終確認)

★段階ごとに実行しているはずなので、ここは最終確認です。★

npx tsc --noEmit
npm run lint
npm test

見るべきテスト

ファイル 内容
★lib/facilities/__tests__/query.test.ts(★新規★)★ 段階2 の期待値表11ケース
★lib/schedules/__tests__/query.test.ts(★新規★)★ 段階3 の期待値表9ケース
★lib/fixtures/__tests__/schedules.test.ts★ ★7曜日分 + 前提1 = 8テスト★。★地雷を踏んでいないことの検証★
lib/dashboard/__tests__/aggregate.test.ts planned の集計。★念のため★

★踏まないでほしい地雷★

# 内容
1 ★cwd のドライブレターは大文字 C:\ でなければ全く動きません★。vitest run の出力に RUN v4.x C:/Users/... と大文字で出ているか確認すること
2 ★--reporter=basic は Vitest 4 で削除済みです★。使うと ★ロードに失敗しても exit 0 になり、壊れていることに気づけません★。素の npm test を使うこと
3 ★lint は npm run lint(= eslint)★。★next lint は Next 16 で削除済み★
4 ★テスト数が減っていないこと★。基準は作成時点で ★22ファイル / 461テスト★(★着手直前の実測値を基準にすること★)。★段階2 と段階3 で増えるのが期待値★

段階9の完了条件

  • 上の3コマンドがすべて通ること
  • ★テスト数が着手前の実測値から増えていること★(★新規2ファイル分★)
  • ★コミットしない★(段階1〜8 で済んでいるはず。差分が出たならどの段階の漏れかを特定してその段階に足す)

段階10 — ブラウザで動作確認

★npm run dev を直接叩かず、Browser pane の preview_start を使ってください。★ (★.claude/launch.json に設定が無ければ作ること。runtimeExecutable: "npm" / runtimeArgs: ["run", "dev"] / port: 3000★)

確認する画面

/facilities / /schedules / /system / ★/dashboard(★地雷を踏んでいないかの確認★)★

確認項目

# 項目
1 ★3画面が実際に表示されること★(★「準備中」が出ないこと★)
2 ★検索が動くこと★ — 施設名(メガバリュー)/ シリアル(8111R、★小文字 8111r でも★)/ 住所(○○区)の部分一致
3 ★/facilities のフッタが 全12施設 であること★(fixtures 12件)
4 ★ロボット3台の施設(メガバリューマート緑野店)が3行で出ること★ / ★ロボット0台の施設(フレッシュタウン湖畔店)で崩れないこと★
5 ★/schedules で id27 が 23:30 - 00:30 と出ること★(日跨ぎ) / ★無効行(id24)が薄く表示されること★
6 ★/system の閾値が 90 / 70 / 10 / 60 / 30 / 2 / 3 で出ること★ / ★アドバイス7件(R1〜R4 / B1〜B3)が出ること★
7 ★★/dashboard が「9 / 10 完了」のままであること★★ — ★11 や 6 になっていたら段階3 の地雷を踏んでいます★
8 ★メニューに「🔧 点検記録」が出ていないこと★
9 ★/inspections に直URLで飛べること★(「準備中」が出る。★これが意図した状態★)
10 ★ダーク / ライト 両方で崩れないこと★
11 ★JP / EN 切替で英語が出ること★(★列名・見出し・空表示すべて★)
12 ★コンソールにエラーが出ていないこと★(read_console_messages)
13 ★★data.anomaly の warn が出ていないこと★★(preview_logs。★出たら地雷★)
14 ★横スクロールが /facilities の表の中だけで起きること★(★body 全体が横に伸びないこと★)

段階10の完了条件

  • 上の14項目すべてを確認したこと
  • ★#7 と #13 は特に重要★。★どちらか一方でも異常なら、lib/fixtures/schedules.ts の差分を git diff で確認すること★
  • ★コミットしない★

段階11 — 記録と push

11-1. docs/decisions.md に新しい決定を追記する

★着手直前に grep -n "^### D-0" docs/decisions.md で最終番号を確認すること★ (★本指示書の作成時点(2026-09-08)の最終は D-082(:2390)★。★最初の空き番号は D-083★。★ただし指示書K / 指示書I が先に走ると繰り上がります★)。

記録すべきもの:

# 内容
1 指示書L を実行した。★3画面(F-08 / F-09 / F-10)を実装し PlaceholderScreen から差し替えた★
2 ★system の実装スコープ(運用設定のみ・読み取り専用)と、そう決めた理由★(★D-053 に抵触しないため / 表示設定は永続化とダッシュボード側の対応が要り本作業の範囲を超えるため★)
3 ★「表示設定」タブを作らなかったこと★。★D-032 では実装対象なので、P1 後半に残る宿題である★ことを明記する
4 ★モックの ops タブ二重定義(d-watch-mock.jsx:1158 / :1164、本文 :1221 / :1628)のうちどちらを採ったか★と、その理由
5 ★閾値の文言をモックの「以上」ではなく確定仕様の「超」にしたこと★(★CLAUDE.md §4.1 が §5 の「モックが文言の正」より上位★。段階6-5)
6 ★モックの 📥 インポート / + 新規追加 ボタンを実装しなかったこと★(★docs/spec.md:95 で GET のみ / モックのボタンは onClick の無い飾り / D-053★)
7 ★inspections を隠したのは一時対応で、D-031 の P1 スコープは変えていないこと★。★復活手順(AppShell.tsx:12 のコメントを外すだけ)★
8 ★d-watch-api.yaml の Schedule に facility_id を追加したこと★(型と fixtures には既にあった)
9 ★q パラメータを追加したかどうか(確認2 の結果)と、AND / OR の関係★。★追加しなかった場合は、検索欄をどう扱ったか★
10 ★lib/types/index.ts に AdviceSetting を追加したこと★(YAML にはあったが TS に無かった。CLAUDE.md §9.3)
11 ★InspectionDetail.photos の item_type(YAML :1402)vs item(TS :373)の不整合が未解決で残っていること★。★点検記録に着手する前に解決が必要★
12 ★★契約フラグ(facilities.contract)によるメニュー表示制御は未実装のままであること★★。★CLAUDE.md §4.6 が「契約のないセクションはメニューごと非表示」と定めているが、★メニューは施設横断のグローバルUIなので「どの施設の契約か」が決まらない★。★P1 では全メニューを表示したままにする★。★この論点そのものを記録すること★(★P2 で顧客アカウントが入ったときに、顧客単位で判定できるようになる★)
13 ★lib/fixtures/schedules.ts を一切変更していないこと★と、★その理由(planned の補完ペア設計。D-079 項3 の申し送り)★
14 ★d-watch-api.yaml:861 / :1383 の inspector_name の example にあった実在の人名をダミー名に置換したこと★(CLAUDE.md §7 / D-043。段階1-6)
15 ★実DB接続時には prismaSource(lib/db/index.ts:153-164)の facilities / schedules の実装が別途必要であること★。★lib/schedules/query.ts の docstring に書いた4つの罠(inactive の反転 / weeks vs weekdays / HHMM の24〜29 / weekdays_label はDBに無い)を申し送ること★
16 docs/architecture.md:66-70 の実装状況表を最新化したこと
17 実測値(npm test のファイル数・テスト数 / npx tsc --noEmit / npm run lint)

11-2. ★既存の誤記を直す★

箇所 内容
★docs/architecture.md:66-70★ ★画面の実装状況の表が古い★(実測)。★:66 alerts/ / :67 reports/ / :69 ds-logs/ ds-alerts/ が「プレースホルダ」と書かれているが、★いずれも実装済み★(D-069 ほか)。★:70 の facilities/ schedules/ system/ は本作業で実装済みになる★。★実際にプレースホルダとして残るのは :68 の inspections/ だけ★。★この5行をまとめて直すこと★
★docs/fixtures.md:169★ 「契約フラグ4パターン \ ★0:未設定 / 1:D-Securityのみ / 2:D-Watchのみ / 3:両方★」 — ★D-080 で訂正された古い表現★。★10桁文字列(0000000000 / 1000000000 / 0100000000 / 1100000000)に書き換えること★

11-3. docs/handoff.md に追記する

  • ★末尾に追記を1つ追加★(作成時点の最新は ★追記19★。★着手時に確認すること★)
  • ★冒頭の「最新の追記」ポインタ(:6-8 付近)も更新すること★
  • ★次にやることを更新する★ — ★inspections は D-072 項7 のとおり最後★
  • ★申し送りを書く★:
    • ★「表示設定」タブが P1 後半の宿題として残っていること(D-032)★
    • ★契約フラグによるメニュー表示制御が未実装であること(CLAUDE.md §4.6。判定単位が決まらないため)★
    • ★InspectionDetail.photos の不整合★
    • ★lib/schedules/query.ts の docstring に書いた DB 側の4つの罠(inactive の反転 / weeks vs weekdays / HHMM の24〜29 / weekdays_label はDBに無い)★
    • ★docs/handoff/analysis/prismaSource実装前チェックリスト.md があれば、そちらにも4つの罠を足すこと★

11-4. コミットと push

★git add は明示的にファイルパスを指定すること。git add -A は禁止★ (過去に別作業の途中ファイルを巻き込む事故が起きています)。

git status                       # 何が変わったか目で確認する
git add docs/decisions.md docs/handoff.md docs/fixtures.md
git add "docs/handoff/指示書L_マスタ画面3枚とinspectionsの一時非表示.md"
git commit -m "docs: 指示書L完了(D-0XX)を記録する"
git push origin develop
  • ★main へは push しないこと★。CLAUDE.md §6-5 のとおり main へのマージは PR 経由で、もう1人のレビューを通してから行います
  • --force は使わないこと
  • ★403 が出たら、無理に回避せずユーザーへ報告してください★ (認証情報を画面に出すコマンドを実行しないこと。git credential fill は禁止)

push 後に確認すること:

git log --oneline -1 origin/develop   # ローカルの HEAD と同じコミットか
git status -sb                        # 1行目に ahead/behind が無いか

★この2つを段階11 の記録に実測値として書き足すこと。★

段階11の完了条件

  • docs/decisions.md に新しい決定(★着手直前に確認した番号★)が追記されていること
  • ★記録すべきもの17項目がすべて書かれていること★(★特に #3 / #11 / #12 の「宿題として残る」3件★)
  • docs/fixtures.md:169 の契約フラグ表現が10桁文字列に直っていること
  • docs/architecture.md:66-70 の実装状況表が直っていること
  • docs/handoff.md の末尾に追記があり、冒頭のポインタも更新されていること
  • ★origin/develop へ push 済みで、git status -sb に ahead/behind が無いこと★
  • 文書末尾の「実行状態」表が埋まっていること

★やらないこと★

対象 理由
★点検記録(inspections)の画面実装★ ★D-072 項7★。写真の置き場所・バケット・期限付き署名URLが未決(禁止事項10)
★InspectionDetail.photos の item_type / item 不整合の修正★ ★今回 inspections を実装しないため★。★記録だけする(段階1-5 / 段階11 #11)★
★「表示設定」タブ★ 確認1。★永続化とダッシュボード側の対応が要り、本作業の範囲を超える★。★P1 後半の宿題として記録する★
★運用設定の編集機能★ ★YAML にエンドポイントが無い★。作るなら ★先に d-watch-api.yaml を直す★(CLAUDE.md §6-1)
★📥 インポート / + 新規追加 ボタン★ docs/spec.md:95 で GET のみ。★モックのボタンは飾り★。D-053
★lib/fixtures/schedules.ts の変更★ ★段階3 の地雷★。★active: true の追加・既存の削除・weekdays の書き換えすべて禁止★
★lib/db/ の prismaSource の実装★ 実DB接続は別作業。notImplemented のまま(禁止事項9)
★lib/db/ へのフィルタ処理の追加★ ★lib/db/index.ts:50-54 の設計方針★。フィルタは API ルート側
★契約フラグによるメニュー表示制御★ ★判定単位(どの施設の契約か)が決まらない★。★P1 では全メニューを表示したままにし、論点を記録する★(段階11 #12)
★components/layout/PlaceholderScreen.tsx の削除★ ★inspections がまだ使っています★
★app/(dashboard)/inspections/page.tsx の削除★ ★直URLでの到達は意図した状態★
★lib/i18n.ts:14 / :39 の点検記録エントリの削除★ ★復活させるときに要ります★
★メインDBへの書き込み★ CLAUDE.md §7 / D-042
★customers.contract の参照★ CLAUDE.md §7 / D-010。★facilities.contract のみが正★

完了条件(全体)

  1. ★着手前確認2件の回答を得たこと★(system のスコープ / q パラメータ)
  2. 段階0〜11 をすべて実施したこと
  3. npx tsc --noEmit エラー0 / npm run lint 0
  4. npm test 全パス。★テスト数が着手前の実測値から増えていること★(作成時点の基準: 22ファイル / 461テスト)
  5. ★/facilities /schedules /system が PlaceholderScreen でなくなっていること★ (grep -rn "PlaceholderScreen" "app/(dashboard)/" が ★inspections にしかヒットしないこと★)
  6. ★app/api/facilities/route.ts と app/api/schedules/route.ts が存在すること★
  7. ★lib/facilities/query.ts と lib/schedules/query.ts が純粋関数で、テストがあること★
  8. ★git diff --stat lib/fixtures/schedules.ts が空であること★(★地雷を踏んでいない★)
  9. ★/dashboard が「9 / 10 完了」で、data.anomaly の warn が出ないこと★
  10. ★メニューに「🔧 点検記録」が出ないこと★。★app/(dashboard)/inspections/page.tsx は残っていること★
  11. ★grep -rn "MEGAドンキ\|donki.co.jp\|宇田川町\|03-5428" components/ lib/facilities/ lib/schedules/ が 0件★
  12. ★components/features/system/SystemScreen.tsx に閾値の数値リテラルが無いこと★(lib/config/ から読んでいる)
  13. ★d-watch-api.yaml の Schedule に facility_id があること★
  14. ★lib/types/index.ts に AdviceSetting があること★
  15. ★3画面でダーク/ライト・JP/EN が壊れていないこと★(段階10 で目視)
  16. ★grep -n "香原" d-watch-api.yaml が 0件であること★(段階1-6)
  17. docs/decisions.md / docs/handoff.md / docs/fixtures.md / docs/architecture.md の更新
  18. ★origin/develop へ push 済み★(★main へは push しない★)
  19. 文書末尾の「実行状態」表を更新した

実行状態

段階 状態 コミット
★着手前の確認(system スコープ / q パラメータ)★ ★済(両方とも指示書の推奨どおり採用)★ —
段階0 前提の確認 済 (コミットなし)
段階1 API契約を直す + 型を足す 済 a666dcf
段階2 GET /api/facilities 済 6bba958
段階3 GET /api/schedules(★地雷あり★) 済(地雷回避済み) 6df83e9
段階4 施設ロボットマスタ画面(F-08) 済 5d3fe60
段階5 スケジュール管理画面(F-09) 済 896e428
段階6 運用設定画面(F-10・読み取り専用) 済 d6741a3
段階7 inspections をメニューから隠す 済 2f768ba
段階8 i18n 済 6f1b509
段階9 テスト 済(24ファイル/530テスト全パス) (コミットなし)
段階10 ブラウザで動作確認 ★一部実施★(curl+APIレスポンスで代替。クライアント描画・テーマ・JP/EN切替・コンソールは未確認) (コミットなし)
段階11 記録と push 済 このコミット + push

実行日: 2026-09-08 取得した決定番号: D-084 着手前の実測値: 22ファイル / 461テスト / tsc 0 / lint 0(Vitest 4.1.11) system の実装スコープ: 運用設定のみ・読み取り専用(確認1。指示書の推奨どおり採用) q パラメータ: /facilities と /schedules に追加(確認2。指示書の推奨どおり採用) 完了後の実測値: 24ファイル / 530テスト / tsc 0 / lint 0 詳細: docs/decisions.md D-084 / docs/handoff.md 追記20 を参照