作成: 2026-09-16 / ブランチ: develop(2aaf606 時点) / 調査のみ。コードは1行も変更していない
docs/decisions.md の D-142 項8 の J-6(docs/decisions.md:11232 付近) 「UI差分まとめ 第3章8件が『仕様』か『不具合』か」に答えるための材料です。
docs/UI差分まとめ_20260915.md:206-222 の8件docs/decisions.md に D-143 として残してくださいfile:line / grep コマンド / git blame)。推測の箇所は「推測」と明記しました| # | 内容 | 判定 | 一言 |
|---|---|---|---|
| 1 | 「未対応」の対訳キー衝突 | ★不具合★ | 2026-09-09 に別画面のために足したキーが、7日前から使われていた同じ日本語を巻き込んだ。記録は「登録済みであることを確認した」だけ |
| 2 | ダッシュボードの「判定 ?」ボタンが死んでいる | ★不具合★ | D-053 に真正面から反する。onToggleGradeInfo={() => {}} を渡しているだけで、直すのは2行 |
| 3 | ダッシュボードの清掃ログ表が4列 | ★不具合★ | docs/spec.md:32 が「機種・シリアル列を省略」=8列と書いている。★落ちている4列のデータはAPIに全部入っている★ |
| 4 | サイドバーの未対応件数バッジが無い | ★判断が要る★ | モックにはあるが docs/spec.md:140 は要求していない。件数は取れるが、共通レイアウトに初めてデータ取得を持ち込むことになる |
| 5 | D-Secアラート「通信断」の色が赤→アンバー | ★判断が要る★ | モックの赤は「トークン期限だけを橙にする」分岐の裏返し。その種別が D-030 で消えた今、単純に戻すのが正しいとは限らない |
| 6 | コンパクト表で行展開アドバイスが無効 | ★判断が要る★ | 実装が根拠にしている「規約」は★どの資料にも存在しない★(grep 0件)。一方 docs/spec.md の F-01 にも行展開は載っていない。資料同士が食い違う |
| 7 | D-Secアラートの期間フィルタが無い | ★判断が要る★ | モックの日付欄は★飾り★(onChange なし)。足すには先に d-watch-api.yaml を直す必要がある(新規パラメータ2つ) |
| 8 | アラート画面のバッテリー残量行 | ★意図した仕様★ | ★記録あり★。D-105 項5 が「画面の残量表示の経路を残す」と明記。第3章の「記録なし」は誤り |
内訳: 不具合 3件 / 意図した仕様 1件 / 判断が要る 4件
lib/i18n.ts は★キーが日本語原文★の1階層の辞書です(lib/i18n.ts:363-366 の translate() は完全一致でしか引かない)。そのため★同じ日本語を別の意味で使うと必ず衝突します★。
// lib/i18n.ts:159-160 // 対応機種レジストリ(lib/config/index.ts の ROBOT_MODELS)に無い機種のバッジ(指示書N) 未対応: "Unsupported",
t("未対応") の呼び出しは★3箇所★(実測):
| 場所 | 意味 | EN表示 | 正しい英語 |
|---|---|---|---|
components/features/ds-alerts/DsAlertsScreen.tsx:141 |
数値カード「未対応」=★未処理のアラート件数★ | Unsupported |
Open |
components/features/ds-alerts/DsAlertsScreen.tsx:289 |
ステータスバッジ「未対応」=★未処理★ | Unsupported |
Open |
components/features/facilities/FacilitiesScreen.tsx:180 |
機種バッジ「未対応」=★サポート外の機種★ | Unsupported |
Unsupported(正しい) |
実害: EN表示で、D-Secアラートの「未処理の警報が3件」が「非対応が3件」に化けます。 ★状態の意味が逆どころか別カテゴリになる★ので、英語で運用する担当者は件数の意味を取り違えます。
d-watch-mock.jsx は自前の辞書(:129-147)を持ちます。★モック側に 未対応 の対訳エントリはありません★ (grep -n '"未対応"' d-watch-mock.jsx → 辞書行にヒットなし。:189 / :901 の状態文字列のみ)。 つまり★モックでは EN でも「未対応」と日本語のまま出ており、誤訳は実装側で新たに生まれた★ものです。
$ grep -n "Unsupported" docs/decisions.md 11216:例: ★「未対応」の対訳キー衝突で英語表示が `Unsupported`(非対応)になる★ /
唯一のヒットは D-142(2026-09-16)が★本件を「これから振り分ける宿題」として引用している箇所★で、 決定ではありません。
代わりに、衝突が★見落とされた瞬間★の記録があります(D-087 = 指示書N の検証節):
docs/decisions.md:3084
および`t("未対応")`が`lib/i18n.ts`に登録済みであることをコードレビューで確認したのみ
git blame で時系列が確定します:
| コミット | 日付 | 内容 |
|---|---|---|
d59fecb |
2026-09-02 | DsAlertsScreen.tsx:141 / :289 が t("未対応") を使い始める(当時は辞書に無く EN でも和文=実害なし) |
7a68a4d |
2026-09-09 | 指示書N が lib/i18n.ts:160 に 未対応: "Unsupported" を追加 → ★7日前からあった別画面を巻き込んだ★ |
D-087 の検証文は「登録済みであることを確認した」=★自分が足したキーを確認しただけ★で、 ★他画面が同じキーを使っていないかは見ていません★。
docs/spec.md / UI仕様書に対訳の規定はありません。d-watch-api.yaml にも該当なし。
CLAUDE.md §9.6「JP/EN切替の器を壊さない」に反する★キーを日本語原文にしたまま2つの意味を区別することは、いまの translate() では不可能★です。 どちらかの呼び出し側を変える必要があります。推奨は★D-Secアラート側の文言を変えない方針★ (モックの文言は「未対応」で、CLAUDE.md §5 でモックが文言の正)なので、 ★機種バッジ側のキーを変える★のが副作用が小さいです。
| 触るファイル | 変更 |
|---|---|
lib/i18n.ts:159-160 |
未対応 を削除し、"未対応(機種)": "Unsupported" 等の★一意なキー★に置き換え。さらに 未対応: "Open" を D-Secアラート用に登録 |
components/features/facilities/FacilitiesScreen.tsx:180 |
t("未対応") → t("未対応(機種)")。★Pill に渡すのは t() の戻り値なので、日本語表示が「未対応(機種)」に変わってしまう★ → ★方式A(t("...").replace())ではなく、表示用の日本語を別に持つ必要がある★(§10 の質問Q1) |
components/features/ds-alerts/DsAlertsScreen.tsx:141,289 |
変更不要(キーはそのまま、対訳が Open になる) |
lib/i18n.ts を直接検証するテストは★0件★ (grep -l "i18n\|translate" **/*.test.ts → lib/prechecks/__tests__/label.test.ts と lib/db/__tests__/report-mapping.test.ts のみで、どちらも 未対応 を扱わない)。 lib/facilities/__tests__/query.test.ts:677-694 は isSupportedModel() の判定だけを見ており★文言に依存しない★c.wn / THEME_TOKENS 由来で文言と独立)ボタンは★compact で隠されていません★(CleanLogTable.tsx:110-120):
<th className={styles.th} style={{ textAlign: "center" }}>
{t("判定")}{" "}
<button type="button" className={styles.helpBtn} onClick={onToggleGradeInfo} aria-label="判定基準">
?
</button>
</th>
一方ダッシュボードは★空の関数と false を渡しています★(DashboardScreen.tsx:152-162):
<CleanLogTable
rows={logs}
compact
...
showGradeInfo={false}
onToggleGradeInfo={() => {}}
onToggleRow={() => {}}
onOpenAreas={() => {}}
/>
凡例本体は CleanLogTable.tsx:123-152 にあり showGradeInfo でしか開きません。 ★つまり「押しても何も起きない」のは仕様上の制約ではなく、状態を持たせていないだけ★です。
d-watch-mock.jsx:301 の ? は★トップレベルの showGradeInfo(:171)★を切り替えます。 LogTable は compact の有無で分岐しないので、★ダッシュボード(:508)でも詳細ログ(:573)でも同じように開きます★。
$ grep -n "showGradeInfo\|凡例" docs/decisions.md 10864:- 画面の凡例(`CleanLogTable.tsx` / `SystemScreen.tsx`)が「◎90%超」「○70%超」のままだった
唯一のヒットは D-139 項8(文言を「超」→「以上」に直した話)で、★ボタンの有効/無効には触れていません★。 docs/spec.md にも記述なし。
D-053(docs/decisions.md:333-337)の本文:
- 決定: グループ・会社の絞り込み
<select>は、マスタが揃うまで画面から削除する- 理由: 固定の選択肢だけがあって何も起きないUIは、不具合と区別できないため
D-053 が「消す」を選んだのは★機能させるためのデータ(マスタ)が存在しなかったから★です。 本件は★データも凡例本体も既にあり、必要なのは useState 1つ★なので、前提が違います。
同じ趣旨がもう1箇所、lib/i18n.ts:320-321 に明文化されています:
★★
disabledだけにして理由を出さないことはしない★★ — 押せないボタンは、理由が書いていないと不具合と区別がつかない(D-053 と同じ理由)
したがって D-053 と整合するのは★「機能させる」★です。 「消す」も D-053 の文言だけ見れば整合しますが、CLAUDE.md §5(モックが画面レイアウト・ 文言・遷移の正)に反します。モックには ? があり、押すと開きます。
| 触るファイル | 変更 |
|---|---|
components/features/dashboard/DashboardScreen.tsx |
const [showGradeInfo, setShowGradeInfo] = useState(false) を足し、:158-159 の false / () => {} を差し替える(★実質2行★) |
components/features/detail-log/CleanLogTable.tsx |
変更不要 |
t() を通していません★ (CleanLogTable.tsx:126 判定基準(タスク完了率): / :142 (閾値はシステム設定で変更可能))。 ★開けるようにすると、EN表示で和文の塊が新たに1つ増えます★。 同じ凡例が詳細ログでも開くので★これは既存の抜けであって本件が作る問題ではありません★が、 直すなら同じコミットで対訳を足すのが自然です(辞書に足すのは2キー)CleanLogTable.module.css の .legend* を使い、色は CSS 変数。追加作業なしCleanLogTable.tsx:74-106 が !compact && で★6列を落としています★:
| 列 | compact |
|---|---|
| 施設名 | 出す |
| 機種 | ★落とす★ |
| シリアル | ★落とす★ |
| 日付 | ★落とす★ |
| 予定 | 出す |
| 1h前ST | ★落とす★ |
| 30分前ST | ★落とす★ |
| 出発 | ★落とす★ |
| 完了率 | 出す |
| 判定 | 出す |
CleanLogTable.tsx:24 の docstring も「4列表示にする(施設名/予定時刻/完了率/判定のみ)」と 自認しています。
★あります。表示していないだけです。★
ダッシュボードは★詳細ログとまったく同じ API・同じ型★を使っています:
DashboardScreen.tsx:38-46 — apiFetch<ListResponse<CleanLogItem>>("/api/clean-logs?result=problem&date_from=…&per_page=5")lib/types/index.ts:202 の CleanLogItem。落ちている列に対応するフィールドが★全部入っています★:| 落ちている列 | CleanLogItem のフィールド |
定義位置 |
|---|---|---|
| 日付 | scheduled_at(ISO8601 +09:00) |
lib/types/index.ts:209 |
| 1h前ST | status_1h |
lib/types/index.ts:216 |
| 30分前ST | status_30m |
lib/types/index.ts:217 |
| 出発 | departed |
lib/types/index.ts:223 |
| (機種) | model_name |
lib/types/index.ts:206 |
| (シリアル) | serial_number |
lib/types/index.ts:207 |
app/api/dashboard/route.ts は関係ありません(コンパクト版ログは GET /dashboard に含まれない 契約です。d-watch-api.yaml:219 / docs/spec.md:36)。★APIを1本も変えずに列を戻せます。★
d-watch-mock.jsx:285-303 の LogTable は★compact で 機種(:290)と シリアル(:291)の 2列だけ★を落とします。:508 がダッシュボードで compact={true}。→ ★8列★。
docs/spec.md:32 - 清掃詳細ログ(コンパクト版。機種・シリアル列を省略)
CLAUDE.md §5 で docs/spec.md は★機能一覧の正★です。モックと spec.md が★一致して8列★と 言っており、実装だけが4列です。
$ grep -n "コンパクト版" docs/decisions.md docs/spec.md d-watch-api.yaml docs/decisions.md:10191 (D-137。「コンパクト版ログを二重に作るな」という API 契約の話) docs/spec.md:32 (8列=機種・シリアルのみ省略) docs/spec.md:36 (API再利用の話) d-watch-api.yaml:219 (API契約の話) d-watch-api.yaml:313 (D-137 が上に抵触しない旨)
★列数を減らした決定は1件もありません。★ git blame では 47f2df4(2026-08-30「F-01 ダッシュボード画面を実装」)の初回実装から4列で、 docstring の理由(「ダッシュボードではアドバイスを一切出さない規約のため」)は★#6 と同じ 出所不明の「規約」★です(§7 参照)。
モックと docs/spec.md が一致し、記録が無く、データは揃っている。3条件そろっています。
| 触るファイル | 変更 |
|---|---|
components/features/detail-log/CleanLogTable.tsx |
!compact && を★日付・1h前ST・30分前ST・出発の4列から外す★(機種・シリアルは落としたまま)。colSpan={compact ? 4 : 10}(:156 / :205)を★compact ? 8 : 10 に直す★ — ★これを忘れると空表示の行が詰まる★ |
CleanLogTable.module.css:1-5 が .table { min-width: 1000px }、 DashboardScreen.module.css:75-77 が .tableWrap { overflow-x: auto }。 ★横スクロールで収まるので CSS 変更は不要★(モックも minWidth: compact ? 700 : 1000 で同じ考え方)日付(lib/i18n.ts:27)・予定(:28)・出発(:29)は ★対訳済み★。1h前ST / 30分前ST は★モックも実装も t() を通していない生文字列★ (CleanLogTable.tsx:94 / :99)= EN でも和文。★詳細ログでも同じなので本件では変えない★1h前ST / 30分前ST は Pill + statusColor()。 D-077(生値表示)により実DBでは英語識別子が入り、lib/theme-status.ts:26-30 の仕様どおり ★全部グレーにフォールバック★します。★ダッシュボードにグレーのPillが2列並ぶ★のは 「意図した挙動」(CLAUDE.md §4.8)ですが、見え方が変わるので §10 の質問Q3に出しましたcomponents/layout/AppShell.tsx に★バッジの受け口自体がありません★:
:8-34 は { href, id, label } の3キーのみ(badge に相当するものが無い)NavItem(:36-53)は href / label / active だけを受け取るAppShell は★1本もデータ取得をしていません★(useTheme() と usePathname() のみ)d-watch-mock.jsx:188 const unresPre = PRECHK.filter(function (a) { return !a.ok; }).length;
d-watch-mock.jsx:189 const unresDsa = dsaState.filter(function (a) { return a.st === "未対応" || a.st === "対応中"; }).length;
d-watch-mock.jsx:372 { id: "alert", label: t("🔔 アラート"), badge: unresPre },
d-watch-mock.jsx:378 { id: "dsalert", label: t("⚠ D-Secアラート"), badge: unresDsa },
d-watch-mock.jsx:391 {props.badge > 0 && <span style={{ ... background: c.ng, ... }}>{props.badge}</span>}
赤いバッジが2箇所(アラート/D-Secアラート)。0件のときは出しません。
| バッジ | 取得元 | 根拠 |
|---|---|---|
| アラート | GET /prechecks の summary.unresolved(未解消+対応中) |
d-watch-api.yaml:1754-1757、D-054(docs/decisions.md:339) |
| D-Secアラート | GET /ds-alerts の summary.pending + summary.in_progress |
app/api/ds-alerts/route.ts:69、DsAlertsScreen.tsx:141-142 |
★モックの unresDsa(未対応+対応中)とちょうど同じ定義★です。値の意味合わせは不要。
$ grep -n "未対応件数\|件数バッジ" docs/decisions.md (0件) $ grep -n "サイドバー" docs/decisions.md 10367, 10374, 10488, 10506, 10519, 10522, 10566, 10591 ← すべて D-137 の「スクロール」の話
docs/spec.md:140 * task: : 共通レイアウト(サイドバー10画面ナビ、ダーク/ライト、JP/EN切替の器)
★バッジは要求されていません★。モックにはあるが spec.md には無い、という状態です。
CLAUDE.md §5)に従えば足すべきdocs/spec.md は要求していない★実装コストの実態★(これがユーザー判断の材料):
AppShell は app/(dashboard)/layout.tsx 配下の★全10画面で常に描画される★/prechecks と /ds-alerts)d-watch-api.yaml に存在しない★ → 既存2本を per_page=1 で叩いて summary だけ使う(items は捨てる)か、 契約に GET /badges のような1本を足すか| 触るファイル | 変更 |
|---|---|
components/layout/AppShell.tsx |
メニュー定義に badge を足し、NavItem に受け口を足し、useEffect で2本フェッチ |
components/layout/AppShell.module.css |
.navBadge を追加(モック :391 相当。background: var(--ng)) |
d-watch-api.yaml |
★1本足す案を採る場合のみ★(CLAUDE.md §6-1: 先にYAMLを直す) |
lib/i18n.ts |
不要(数字だけ) |
var(--ng) を使えば両対応(lib/theme.ts:16 dark #ef4444 / :35 light #dc2626)// components/features/ds-alerts/DsAlertsScreen.tsx:36-38
function typeColor(c: ThemeTokens, type: DsAlertType): string {
return type === "disconnected" ? c.wn : c.ng;
}
c.wn はアンバー(lib/theme.ts:14 dark #f59e0b / :33 light #d97706)。 この色は★Pill(:264)とカード左端の帯(:259 borderLeftColor)の2箇所★で使われます。
// d-watch-mock.jsx:946 var tpCol = a.type === "トークン期限" ? c.wn : c.ng;
★モックでアンバーだったのは「トークン期限」だけ★で、「通信断」と「セキュリティ無効」は どちらも c.ng(赤)でした。
つまり実装は、★D-030 で消えた「トークン期限」の色を、残った「通信断」に付け替えた★形です。 意図的な付け替えなのか、条件式を機械的に書き換えた結果なのかは★コミットからは読み取れません★ (d59fecb 2026-09-02「feat: F-07 D-Secアラート一覧を実装 (D-050)」の初回実装から現在の形)。
$ grep -n "バッジの色" docs/decisions.md 146: (アドバイスの行バッジの色。無関係) 237: (判定バッジの色分け。無関係) $ grep -n "通信断" docs/decisions.md 351, 497, 498, 505, 1138, 1168, 1170, 1778, 1795, 1925, 9720, 9721, 9875 → すべて「2状態化」「判定ロジック」「ソート順」の話。★色に触れた行は1つも無い★
lib/db/index.ts:1533 の dsAlerts() は★alert_type に常に "disconnected" を入れます★ (:1520-1531 の docstring: security_off に対応するカラムが DB に無い。D-090 項3-9)。
★帰結: 実DB接続時、この画面のカードは★★全部アンバー★★になり、赤は1件も出ません。★ 「セキュリティ無効(=赤=重大)」という対比が画面から消えているため、 ★色で重要度を判断する運用が成立していません★。
docs/decisions.md:497-498(D-065)は★「異常=通信断は同じもの」★と確定しており、 D-Secログ画面では★異常=ng(赤)★で描かれています(DsLogScreen.tsx:308 の tone="ng")。 ★同じ事象が2画面で違う色★になっているのは、どちらかに揃えるべき論点です| 触るファイル | 変更 |
|---|---|
components/features/ds-alerts/DsAlertsScreen.tsx:36-38 |
1行(c.wn → c.ng、または typeColor() ごと削除して常に c.ng) |
lib/ds-alerts/__tests__/query.test.ts は絞り込み・ソートのみ検証)THEME_TOKENS 経由なので両対応のままdocs/decisions.md に記録を残すこと★(次に突き合わせた人が同じ問いを立てるため)// components/features/detail-log/CleanLogTable.tsx:162 const hasAdvice = !compact && (r.grade === "△" || r.grade === "×");
hasAdvice が false なので、行の onClick(:171)も ▼ の表示(:197-199)も出ません。 ダッシュボード側は onToggleRow={() => {}} / expandedId={null} / adviceById={{}} を 渡しています(DashboardScreen.tsx:155-161)。
根拠として docstring(CleanLogTable.tsx:25)にこう書かれています:
ダッシュボードではアドバイスを一切出さない規約のため、compact 時は行クリック・アドバイス展開も無効化する。
$ grep -n "アドバイスを一切\|ダッシュボードではアドバイス" docs/decisions.md docs/spec.md docs/handoff.md docs/変更点まとめ_20260914.md (0件) $ grep -n "行展開" docs/decisions.md 7973:(★ダーク/ライトの見た目・JP/EN の切替・CSVの中身・行展開・備考編集★) → D-120 の「目視確認が要る項目」の列挙。方針ではない
git blame によれば docstring は 47f2df4(2026-08-30、F-01 初回実装)で書かれたもので、 ★実装者の自己申告であり、どの資料にも裏付けがありません★。
d-watch-mock.jsx:311(LogTable 内):
var hasAdvice = r.g === "△" || r.g === "×";
★compact で分岐していません★。展開行の colSpan にだけ compact ? 8 : 10 が入っており (:331)、★compact でも展開する前提で書かれています★。
docs/spec.md:29-36 F-01 ダッシュボード - 清掃詳細ログ(コンパクト版。機種・シリアル列を省略) ← 行展開の記述なし docs/spec.md:43-52 F-02 清掃詳細ログ - **行展開アドバイス(Phase A)**: △×行クリックで R1〜R4 の推定原因とアクションを表示
★行展開は F-02 の機能として書かれており、F-01 の箇条書きには出てきません。★ ただしこれは「F-01 では禁止」と書いてあるわけではなく、★ブロックの列挙に含まれていない★だけです。
docs/spec.md(機能一覧の正)の F-01 には載っていない★資料が正面から食い違うので、CLAUDE.md §5 の最後の指示「それでも解決しない場合は ★実装を止めて確認を求める★」に該当します。
★運用上の意味★: ダッシュボードは「昨夜の結果を10分で把握」する画面(docs/spec.md:12)で、 表示されるのは★当日の △× 上位5件のみ★(DashboardScreen.tsx:38-43 の result=problem / per_page=5)。★問題行しか出ない表で理由が見られない★のは導線として不自然、というのが 「直す」側の論拠です。「直さない」側の論拠は「ダッシュボードは要約に徹し、 理由は『全項目 →』で F-02 に飛ぶ」という切り分け(DashboardScreen.tsx:36-37 のコメント)。
| 触るファイル | 変更 |
|---|---|
components/features/detail-log/CleanLogTable.tsx:162 |
!compact && を外す |
components/features/dashboard/DashboardScreen.tsx |
expandedId / adviceById / adviceLoadingId の state と、GET /api/clean-logs/{id}/advice の取得を足す(★DetailLogScreen.tsx の実装をそのまま移植できる★) |
colSpan を compact ? 4 : 10 から直すこと★(:205)。#3 を先に直すなら compact ? 8 : 10app/api/clean-logs/[id]/__tests__/route.test.ts は既にあり、 ★APIは変更不要★CleanLogTable.tsx:37-51 の「🔴 レベル3 — DFA介入を検討」等)は ★t() を通していない★ため EN で和文。詳細ログでも同じ既存の抜け:210-214 に「該当するアドバイスはありません」があり、 ダッシュボードでもこの経路が出ますDsAlertsScreen.tsx:86-97 が組み立てるクエリは★日付を含みません★:
type / status / group_id・customer_id(分類) / per_page / page
サーバ側 lib/ds-alerts/query.ts:46-82 の parseDsAlertQuery() も date_from / date_to を ★読みません★(TYPE_FILTERS / STATUS_FILTERS / parseMasterIdFilters / page / per_page のみ)。
d-watch-mock.jsx:916-921 に日付入力が2つあります。ただし★飾りです★:
<input type="date" defaultValue="2026-03-20" ... /> // :918 — onChange なし <span>〜</span> <input type="date" defaultValue="2026-03-27" ... /> // :920 — onChange なし
★絞り込みロジック(:937-945)は日付を一切参照していません。★ 第3章の「期間の絞り込みが無い」は正しい指摘ですが、★モック側も動いてはいなかった★点は 記録しておく価値があります(docs/UI差分まとめ_20260915.md:138 は「あり」としか書いていません)。
$ grep -n "D-Secアラート.*期間\|ds-alerts.*date\|期間の絞り込み\|期間フィルタ" docs/decisions.md (0件)
d-watch-api.yaml:1131-1149(/ds-alerts の parameters):
GroupId / CustomerId / type / status / Page / PerPage
★date_from / date_to がありません。★ CLAUDE.md §6-1「API契約を変えたくなったら、先に d-watch-api.yaml を直す」に従い、 ★実装より先に YAML を直す必要があります★(= 1行の修正では済まない)。
比較: GET /prechecks は date_from / date_to を持ち、フィルタの前例もあります (lib/prechecks/query.ts:65-69 の検証、:119-127 の filterPrechecksByDate())。 ★同じ形をそのまま写せます。★
docs/decisions.md:9550-9560(D-132 項7)が★実測で結論を出しています★:
★結論:
/facilities/schedules/ds-devices/ds-alertsは降ろす価値がない。★/ds-alerts| ★20行★
app/api/ds-alerts/route.ts:64-74 と同じくメモリ内で絞る形で足せます。 (lib/db/index.ts:1533 の dsAlerts() は毎回全件読みですが、★D-132 で「そのままでよい」と 判断済み★なので本件の論点ではありません)
detected_at 降順固定(lib/ds-alerts/query.ts:110-117)+ ページ送りがあるので、直近のものは1ページ目に出ます。一方で★対応状況の更新(PATCH)が 未実装(更新用アカウント未発行)★なので、★status=open の既定表示に古いアラートが 永遠に溜まり続けます★ — ここが「期間で絞りたい」の実需です| 触るファイル | 変更 |
|---|---|
d-watch-api.yaml(:1131 付近) |
date_from / date_to を parameters に追加(/prechecks の定義をコピー) |
lib/ds-alerts/query.ts |
DsAlertQuery に dateFrom / dateTo、検証(422)、filterDsAlertsByDate() を追加 |
app/api/ds-alerts/route.ts:70-73 |
日付フィルタを type/status と同じ層に差し込む。★summary より後(分類より後)★に置くこと — ★summary の母集団を変えるかどうかが設計判断★(§10 の質問Q5) |
components/features/ds-alerts/DsAlertsScreen.tsx |
日付入力2つ。★既定値は空=全期間★(AlertsScreen と揃える。docs/UI差分まとめ_20260915.md:87)。★変更時に setPage(1)★(D-120 の規則) |
lib/ds-alerts/__tests__/query.test.ts |
★テスト追加が要る★(filterPrechecksByDate のテストが手本) |
lib/i18n.ts |
開始日 / 終了日 は★既存★(:347-348)。追加不要 |
lib/ds-alerts/__tests__/query.test.ts は既存分が★壊れません★ (既定値が「絞らない」なので)AlertsScreen.module.css の .dateGroup を写す// components/features/alerts/AlertsScreen.tsx:285-290
{item.battery_level !== null && (
<div className={styles.batteryLine}>
{t("残量")} {item.battery_level}%
</div>
)}
★null ガードがあるので、実DBでは1件も描画されません★(DOMにも出ません)。 USE_FIXTURES=true のときだけ表示されます。
★モックにこの行はありません★(d-watch-mock.jsx の PRECHK カードに残量の表示なし)。 第3章の分類どおり「モックに無いが追加した」項目です。
★記録は2件、どちらも明示的です。★
(1) D-105 項5(docs/decisions.md:5596-5604) — 「なぜ null にしたか」と★「なぜ画面の行は残すか」★:
docs/decisions.md:5596 #### 5. ★★`battery_level` は常に `null`(D-090 項8 の解決)★★ docs/decisions.md:5597 - ★★実DB経由では全件 `null`★★(実測。27件すべて `null`) docs/decisions.md:5599 - ★理由★: `robots.battery` は現在値のみで履歴が無いため… docs/decisions.md:5602 - ★fixtures には値が入ったまま★(画面の残量表示の経路を残すため)。 docs/decisions.md:5603 ★`USE_FIXTURES` の true / false で差が出るのは**想定内**★
(2) D-114(docs/decisions.md:7138) — TeamWorks 第8回の回答で★恒久化★:
docs/decisions.md:7138 - ★A9-1: バッテリー残量の履歴は残さない★ → ★★`battery_level` は恒久的に `null` で確定★★
★★残す★★です。根拠は D-105 項5 の一文:
★fixtures には値が入ったまま★(★画面の残量表示の経路を残すため★)
★「経路を残す」と明示的に書かれている★ので、行を消すことは決定の意図に反します。 補強材料:
CLAUDE.md §9.5 — ★「fixtures はDB接続後も削除しない(テスト・デモ用)」★USE_FIXTURES の true / false で差が出るのは想定内」★d-watch-api.yaml の PrecheckItem にも battery_level を★意図的に足してある★(D-105 項5)★ただし docs/UI差分まとめ_20260915.md:89 / :244 の「★記録なし★」は事実に反します。★ この2行の訂正が必要です(本文書に基づき「D-105 項5 / D-114」と書き換える)。
★コード変更は不要★。文書のみ:
| 触るファイル | 変更 |
|---|---|
docs/UI差分まとめ_20260915.md:89 |
根拠欄を「★記録なし★」→「D-105 項5(経路を残すと明記)/D-114(null で恒久確定)」 |
docs/UI差分まとめ_20260915.md:244 |
第4章の行を削除(記録が存在するため) |
第2章(docs/UI差分まとめ_20260915.md:196-203)は EN の抜けを 「D-Secログ/D-Secアラート/読み込み中/ログイン画面」と書いていますが、 ★components/** の t() 呼び出しを全部拾って辞書と突き合わせた★ところ、 ★ダッシュボードとアラート画面にも抜けがあります★(第2章に記載なし):
| 画面 | 辞書に無いキー | 位置 |
|---|---|---|
| ★ダッシュボード★ | 成功 / 失敗 / 未実施 / 成功率 / 予定時刻経過・実績なし / 全項目 → |
DashboardScreen.tsx:101,107,113,114,122,148 |
| ★アラート(F-03)★ | 未解消 / 解消済み / 合計 / 要対応 / 対応完了 / 全アラート / 未解消のみ / 解消 / 対応中 / スケジュール開始前のエラー検知と出発失敗 / 該当するアラートはありません |
AlertsScreen.tsx:138,142,143,144,231,251,260,298,303,308 |
★ダッシュボードは「ログイン後の最初の画面」(docs/spec.md:12)★なので、 EN に切り替えると★最初に見る4枚の数値カードが全部和文★になります。
要対応 が★意味の違う2箇所★で使われています(どちらも現在は辞書に無く和文のまま):
| 位置 | 意味 |
|---|---|
components/features/alerts/AlertsScreen.tsx:142 |
未解消アラートのカードの補助文(★人が対応すべき件数★) |
components/features/ds-logs/DsLogScreen.tsx:308 |
異常デバイスのカードの補助文(★機器が異常★) |
★追加1 を直すときに 要対応: "Action Required" のように素直に足すと、#1 とまったく同じ構造で 2画面を巻き込みます。★ 先に方針(§11 段階1)を決めてから足すこと。
なお 注意 は ReportsScreen.tsx:394(施設ステータス)と SystemScreen.tsx:67,446 (アドバイスのレベル1)の2系統で共用されています。今は両方 "Caution" で成立していますが、 ★同じ構造のリスクを抱えています★。
lib/i18n.ts:126-129:
他: "View ", "件を表示 →": " more →", 全: "View all ", "施設を表示 →": " facilities →",
★4つとも使用箇所0件★(実測。grep -rn 't("他")' components/ app/ lib/ 等はいずれも lib/i18n.ts:120 のコメント行しかヒットしない)。lib/i18n.ts:122-123 が ★自分で警告しています★:
★注意★
他/全のような1文字キーは他画面の文言と衝突しやすい
★全 は特に危険★で、誰かが t("全") と書いた瞬間に EN で View all になります。 lib/i18n.ts:111-112 に「使わなかった方は画面実装が固まった時点で削除してよい」とあり、 ★方式A(全{n}施設を表示 →)が確定しているので削除条件は満たしています★。
D-Sec ログ★lib/i18n.ts:36 の "D-Sec ログ": "D-Sec Logs" は★使用箇所0件★。 h1 が「D-Secログ」(半角スペースなし。DsLogScreen.tsx:301)に変わったためです。 第1章 1-6(docs/UI差分まとめ_20260915.md:121)が「副作用で英語表示の対訳が当たらない」と 書いているのと同じ事象ですが、★辞書側にも死んだキーが残っている★点は未記載でした。
translate() はキー=日本語原文なので、2つの意味を区別するには★片方のキーを変える★しかありません。 キーを変えると★日本語表示もそのキーの文字列になります★(Pill text={t(...)} に渡すため)。
| 案 | JA表示(施設マスタの機種バッジ) | JA表示(D-Secアラート) | EN | 備考 |
|---|---|---|---|---|
| ★案A★ | 「未対応」のまま | 「未対応」のまま | 機種=Unsupported / アラート=Open |
★translate() に「画面ID」等の第2キーを足す必要がある★(i18n の仕組みを変える) |
| 案B | ★「未対応機種」★ | 「未対応」のまま | 機種=Unsupported model / アラート=Open |
★仕組みは変えない★。JA表示が1語増える(D-087 の「色だけでなく必ず文字を出す」には反しない) |
| 案C | 「未対応」のまま | ★「未処理」★ | 機種=Unsupported / アラート=Open |
★モックの文言(「未対応」)から外れる★。CLAUDE.md §5 に抵触 |
★この選択をするとこうなる★:
lib/i18n.ts の translate() の引数が増え、★t() の呼び出し約180箇所すべてが 影響範囲の候補★になります(実際に直すのは2箇所でも、レビュー範囲が全画面になる)★推奨は案B★(仕組みを変えず、モックの文言から外れるのは機種バッジ側=そもそもモックに無い要素)。
§3 のとおり D-053 とも CLAUDE.md §5 とも整合するのは「機能させる」です。
★この選択をするとこうなる★: ダッシュボードで ? を押すと表の下に凡例が開きます。 凡例は t() を通していないので★EN でも「判定基準(タスク完了率): ◎ 90%以上 …」と和文★で出ます。 同じコミットで対訳を足すか(2キー)、和文のままにするかを決めてください。
docs/spec.md:32 は「機種・シリアル列を省略」なので★文面どおりなら戻す★のですが、 D-077(エラー種別を変換しない)の帰結として★実DBでは英語識別子がグレーのPillで並びます★。
★この選択をするとこうなる★:
| 案 | ダッシュボードの見え方 |
|---|---|
| ★全4列戻す(spec.md どおり)★ | 「日付 / 予定 / ★Standby. / EmergencyStop★ / ✓✗ / 完了率 / 判定」。★ST2列がグレー一色★(lib/theme-status.ts:26-30 の仕様どおり) |
| ST 2列だけ落とす | 「日付 / 予定 / 出発 / 完了率 / 判定」の★6列★。spec.md から1歩外れるので★記録が要る★ |
★D-098(docs/decisions.md:4349)でエラーが無いときの status_1h は Standby.(原文どおり)と 確定しています★ので、正常な行は「Standby.」がずらりと並びます。
★この選択をするとこうなる★:
/prechecks と /ds-alerts)docs/decisions.md に残ります★選択肢★: (a) 今すぐ足す / (b) ★PATCH が実装できるようになってから足す★(そのとき D-143 に条件付きで記録) / (c) 足さない
D-054 と指示書AK の設計では、★type / status は「見え方」なので summary に効かせない★、 ★分類(group/customer)は「母集団」なので summary に効かせる★、という区別があります (app/api/ds-alerts/route.ts:58-69)。★期間はどちらなのかが未定義★です。
★この選択をするとこうなる★:
| 案 | 「2026-09-01〜09-10」を指定したとき |
|---|---|
| ★母集団扱い(分類と同じ)★ | 数値カードが★その期間の未対応/対応中/対応済み★になる。一覧と数字が一致する |
| 見え方扱い(type/status と同じ) | 数値カードは★全期間のまま★。一覧は10日分だけ。★「未対応 27」と書いてあるのに3件しか出ない★ |
★母集団扱いを推奨★(「期間を選ぶ」は明らかに対象を選ぶ操作なので、見え方扱いは誤読を招く)。
★この選択をするとこうなる★:
disconnected しか 出ないため)。D-Secログの「異常=赤」と揃いますdocs/decisions.md に理由を残すこと★★この選択をするとこうなる★:
GET /api/clean-logs/{id}/advice が1本走ります★。エリア別モーダルも開けるようになりますCleanLogTable.tsx:25 の docstring から★「規約のため」を削除★し、 「D-143 で確定」と書き換えてください(★存在しない根拠を引用したままにしない★)docs/handoff/指示書AN_総清掃面積の画面を作る.md の書式に合わせ、 ★段階ごとに1コミット★、★番号順に実行★、各段階で npx tsc --noEmit / npm run lint / npm test を通す前提です。
★段階1・3・5・6・7 は Q1〜Q7 の回答が無いと着手できません★(CLAUDE.md §0-1「仕様が不明なら止まる」)。 ★段階0 と段階2 だけは判断不要で先に進められます★。
| 段階 | 内容 | 前提となる判断 | コミット単位の理由 |
|---|---|---|---|
| ★段階0★ | ★文書の訂正のみ★。docs/UI差分まとめ_20260915.md:89 / :244 の「記録なし」を「D-105 項5 / D-114」に直す(#8) |
★不要★ | ★コード0行★。混ぜると「文書だけ直したコミット」が追えなくなる |
| ★段階1★ | ★#1 対訳キー衝突の解消★(lib/i18n.ts + FacilitiesScreen.tsx 1行) |
★Q1★ | ★実害のある不具合を単独で追えるようにする★。revert したくなったときに他と混ざらない |
| ★段階2★ | ★#2 死んだボタンを機能させる★(DashboardScreen.tsx に useState 1つ) |
★Q2(推奨で確定なら不要)★ | 2行。★D-053 違反の解消という単一の理由★ |
| ★段階3★ | ★#3 コンパクト表の列を戻す★(CleanLogTable.tsx の !compact と colSpan) |
★Q3★ | ★colSpan の直し漏れが起きやすい★ので、他と混ぜず単独で目視確認する |
| ★段階4★ | ★追加1・追加2 の EN 抜けを埋める★(ダッシュボード6キー・アラート11キー。★要対応 は段階1 の方針に従う★) |
★Q1(要対応 の扱いが同型)★ |
★辞書だけの変更★。段階1 の方式が決まっていないと同じ地雷を踏む |
| ★段階5★ | ★#5 「通信断」の色★(1行)+ docs/decisions.md への記録 |
★Q6★ | ★1行だが決定の記録が本体★。混ぜると記録が埋もれる |
| ★段階6★ | ★#6 行展開★(実装する場合のみ。しない場合は★docstring の訂正だけ★) | ★Q7★ | ★段階3 の colSpan に依存する★ので必ず後 |
| ★段階7★ | ★#7 期間フィルタ★。★7-1 YAML → 7-2 query.ts + テスト → 7-3 ルート → 7-4 画面★の4コミットに割る |
★Q5★ | ★CLAUDE.md §6-1(YAMLが先)★。テストを実装より先に置く(§6-2) |
| ★段階8★ | ★#4 サイドバーのバッジ★(足す場合のみ) | ★Q4★ | ★共通レイアウトに初めてフェッチを入れる★ので、他と混ぜると全画面の回帰が切り分けられない |
| ★段階9★ | ★追加3・追加4 の死んだ辞書キー4+1件を削除★ | ★不要★ | 掃除。★段階4 の後★(足す作業と消す作業を同じコミットに入れない) |
| ★段階10★ | ★docs/decisions.md に D-143 として8件の振り分けを記録★+ docs/UI差分まとめ_20260915.md 第3章・第4章の更新 |
— | ★記録が最後★(実際にやったことを書くため) |
colSpan の依存)CLAUDE.md §6-1)docs/decisions.md への記録とセット★ — 記録が無いから今回の調査が発生したgit add -A を使わない★(CLAUDE.md §7)d-watch-mock.jsx(資料。docs/UI差分まとめ_20260915.md:262)/ lib/judge/** / prisma/** / docs/handoff/TeamWorks確認事項_第9回_20260915.md / docs/handoff/セキュリティ申し送り_20260916.md / docs/handoff/pdf/** / README.md / docs/code-map.md
# 決定の位置(★番号順に並んでいないので必ずこれで取る★。最新は D-142)
grep -n "^### D-" docs/decisions.md
# #1
grep -rn "未対応" components/ lib/ app/ --include=*.tsx --include=*.ts
grep -n "Unsupported" docs/decisions.md # → 11216(D-142 の引用のみ)
git blame -L 158,161 --date=short lib/i18n.ts
git blame -L 141,141 --date=short components/features/ds-alerts/DsAlertsScreen.tsx
# #2
grep -n "showGradeInfo\|凡例" docs/decisions.md # → 10864 のみ(文言の話)
# #3
grep -n "コンパクト版" docs/decisions.md docs/spec.md d-watch-api.yaml
sed -n '202,260p' lib/types/index.ts # CleanLogItem に全フィールドがある
# #4
grep -n "未対応件数\|件数バッジ" docs/decisions.md # → 0件
grep -n "サイドバー" docs/decisions.md # → すべて D-137(スクロール)
# #5
grep -n "バッジの色" docs/decisions.md # → 146 / 237(どちらも別物)
sed -n '946,947p' d-watch-mock.jsx
# #6
grep -n "アドバイスを一切\|ダッシュボードではアドバイス" docs/decisions.md docs/spec.md docs/handoff.md docs/変更点まとめ_20260914.md # → 0件
grep -n "行展開" docs/decisions.md # → 7973 のみ(目視項目の列挙)
# #7
grep -n "D-Secアラート.*期間\|ds-alerts.*date\|期間フィルタ" docs/decisions.md # → 0件
sed -n '1131,1149p' d-watch-api.yaml # parameters に日付が無い
# #8
grep -n "battery_level" docs/decisions.md # → D-105 項5(5596-5604)/ D-114(7138)
# 追加1(EN の抜け)— t() のキーを全部拾って辞書と突き合わせる
grep -rno 't("[^"]*")' components/ --include=*.tsx