# HIBI — 要件定義書 兼 Claude Code 実装指示書

**版数** 1.0（DBレス構成 / 記事埋め込み型デモ）／ **作成日** 2026-08-24 ／ **発行** ソウゾウ合同会社
**用途** SEO記事「【デモで試せる】Claude Codeで日報アプリを自作する方法と費用｜動画つき資料【2026年】」に組み込む実演デモ

---

## このドキュメントの使い方（Claude Code へ）

これ1枚が、規約・仕様・タスクのすべて。リポジトリ直下に `CLAUDE.md` として置き、毎回読み込むこと。

- **実装は「12. 実装タスク」の順に進める。フェーズを飛ばさない。**
- 各タスクの括弧内は要件ID。着手前に該当章を読むこと。
- **仕様がここに書かれていない場合は、推測で実装せず質問する。**
- スコープ外（3章 Won't have）は、思いついても実装しない。
- 「デモだから」を理由に品質を落とす判断はしない。
- **この領域だけの特別ルール：入力を増やす機能を提案しない。** 日報アプリの失敗はすべて「書くのが面倒」から始まる。機能追加を思いついたら、**まず「入力項目を増やさずに実現できるか」を考えること**（1章）。

> **姉妹プロジェクトとの関係**
> HIREBASE（求人）／ RELATE（顧客管理）／ CASTA（動画配信）／ FIELDPIN（位置情報）／ KANADE（音楽）／ MIWAKE（画像認識）／ KAMIWAZA（美容室予約）／ KURA（在庫管理）／ TOKIWA（勤怠・シフト）に続くシリーズ。**並べて「同じテンプレ」と思われた時点で失敗。**
> **RELATE / KURA / TOKIWA との差別化に注意。**4本とも「業務システム」だが、
> RELATE＝罫線と等幅数字で表を読ませる（藍・高密度）／ KURA＝各行に在庫の水位バー（ティール＋アンバー・縦長数字）／ TOKIWA＝各行に24時間帯（インディゴ＋コーラル・大きな時刻）／
> **HIBI＝1画面1カラムの縦書き文章。テキストが主役。余白が広く、密度は最も低い。（墨＋若草）**
> **HIBI だけは「読み書きするアプリ」であり、表を読ませない。** 8章参照。

---

## 目次

1. [プロジェクト概要](#1-プロジェクト概要)
2. [アーキテクチャ方針](#2-アーキテクチャ方針)
3. [スコープ定義](#3-スコープ定義)
4. [ロールとデモ切替](#4-ロールとデモ切替)
5. [画面一覧とユーザーフロー](#5-画面一覧とユーザーフロー)
6. [機能要件](#6-機能要件)
7. [データ設計](#7-データ設計)
8. [デザイン要件](#8-デザイン要件)
9. [技術要件・ディレクトリ構成](#9-技術要件ディレクトリ構成)
10. [非機能要件](#10-非機能要件)
11. [費用設計](#11-費用設計)
12. [実装タスク](#12-実装タスク)
13. [受入基準](#13-受入基準)

---

# 1. プロジェクト概要

## 背景と目的

「日報アプリを作りたい」という相談は、**実装が最も簡単で、失敗率が最も高い**という珍しい組み合わせを持つ。

作るのは簡単だ。フォームがあって、保存されて、一覧で見られればいい。1週間で作れる。

**しかし3ヶ月後、誰も書いていない。**

この領域には、**最初に共有すべき事実が3つある。**

### 事実①：日報アプリは「作れないから失敗する」のではない。**続かないから失敗する**

失敗の原因は技術ではなく、次の3つに集約される。

| 原因 | 実態 |
|---|---|
| **書くのが面倒** | 項目が多い、毎回ゼロから書く、スマホで書けない |
| **書いても読まれない** | 上司が見ていない、反応がない、提出しても何も起きない |
| **何のために書くか分からない** | 監視のために書かされている感覚。書く側に利益がない |

> **日報アプリの要件定義で最初に決めるべきは、画面でも項目でもない。**
> **「誰が、何のために読むのか」である。** 読み手が決まらなければ、書く項目も決まらない。

### 事実②：「日報」は3つの別の目的が混ざっている

多くの日報が破綻するのは、**目的の違う情報を1つのフォームに詰め込むから**。

| 目的 | 誰が読む | 必要な情報 | 頻度 |
|---|---|---|---|
| **① 報告**（何をしたか） | 上司・チーム | 実施内容、進捗、時間 | 日次 |
| **② 相談**（困っている） | 上司 | 課題、判断が必要なこと | 発生時 |
| **③ 蓄積**（学びを残す） | 本人・後任・全社 | 気づき、ノウハウ、失敗の記録 | 週次でも十分 |

**①を毎日、③を週次、②は発生時——本来はこの粒度が違う。** すべてを毎日書かせると、③が形骸化して「特になし」が並ぶ。

HIBI は**この3つを構造として分け、①は最小の手数で、②は目立つように、③は無理をさせない**設計にする。

### 事実③：入力を減らす機能だけが、日報を生き残らせる

だから HIBI の機能はすべて「**入力を減らす**」か「**読まれるようにする**」のどちらかに寄与しなければならない。

| 入力を減らす | 読まれるようにする |
|---|---|
| テンプレート／前日のコピー | 一覧での既読・未読 |
| 選択式の項目（自由記述を最小に） | コメント・リアクション |
| 過去の実績からのサジェスト | 未提出者のリマインド |
| 下書きの自動保存 | チームのタイムライン |
| 音声入力の許容 | 週次のまとめ自動生成 |
| **提出はワンタップ** | **読み手の返信を促す設計** |

**入力項目を増やす機能は、原則として採用しない。** これがこのプロジェクトの設計方針であり、記事の主張でもある。

| 目的 | 内容 |
|---|---|
| 実装力の証明 | テンプレート・下書き・コメント・既読管理・集計・検索・オフラインまで、実運用に耐える構造を見せる |
| **期待値の正常化** | **「日報は作れる。続かないのが問題」**を実物で示す。入力の手数を数字で可視化する |
| 運用設計力の証明 | **提出率・返信率・入力時間**をダッシュボードで示す。「運用が回っているか」を測れることを示す |
| 費用判断の材料 | **既製サービス・チャットツールとの比較**、自作が正当化される条件を示す |

## プロダクト定義

| 項目 | 内容 |
|---|---|
| プロダクト名 | HIBI（日々）※仮称 |
| 一言定義 | 書く手数を最小にし、読まれる仕組みを持たせた日報・週報アプリ |
| 想定業態 | 営業チーム、現場作業（建設・設備）、店舗、士業、開発チーム、教育・研修 |
| 提供形態 | レスポンシブWebアプリ（PWA）。**フロントエンド完結（サーバー側の永続化なし）** |
| 主戦場 | **書き手はスマホ**（現場で、移動中に、就業直前に書かれる）。**読み手はPC** |
| 想定利用者 | 記事の読者。登録なしで、書き手側と読み手側の両方を体験できる |

## プロダクトコンセプト

> **「書く時間を、90秒に。」**
>
> HIBI は日報の入力時間を計測し、画面に表示する。テンプレート、前日のコピー、選択式項目、サジェスト——すべては**その秒数を縮めるためにある**。そして書かれた日報には必ず読み手の痕跡（既読・コメント）が残る。書くのが速く、読まれるなら、日報は続く。

## デモとしての成功条件

1. **入力時間が見える** — 日報を書くと「入力 1分12秒」と表示され、平均と比較される
2. **手数が減る体験ができる** — 「前日をコピー」を押すと、大半が埋まった状態から始まる
3. **3つの目的が分かれている** — 報告・相談・蓄積が別のブロックとして構造化されている
4. **読まれた痕跡が残る** — 既読者のアバター、コメント、リアクションが日報に付く
5. **運用が測れる** — 提出率・返信率・平均入力時間がダッシュボードに出る
6. **ロールで見え方が変わる** — メンバーは自分とチーム、管理者は全社。個人の評価情報は分離
7. **リセットできる** — 誰が触った後でも初期状態に戻せる

---

# 2. アーキテクチャ方針

## 基本方針

**バックエンドとデータベースを持たない。すべてブラウザ内で完結させる。**

| 一般的な構成 | 本プロジェクト |
|---|---|
| PostgreSQL | シードデータ + ブラウザ内ストア |
| 認証・SSO | デモ用ロール切替（ワンクリック） |
| REST / GraphQL API | ストア上の同期的な操作 |
| メール・Slack・LINE通知 | **送信内容のプレビュー表示**で再現 |
| 全文検索（Elasticsearch等） | **ブラウザ内の全文検索**（自前実装） |
| ファイルストレージ | IndexedDB（画像は端末内） |
| **入力時間の計測** | **これは本物。** 実際に計測して表示する |
| **週次まとめの自動生成** | **これも本物。** ルールベースで実際に組み立てる |

## なぜこの構成にするか

- **LPデモとして最適** — 訪問者は登録もログインもせずに、全機能を即座に触れる
- **書いた内容が外に出ない** — 日報は業務の機密。データを預からないことが訴求になる
- **開発速度** — 認証・APIの実装が不要になり、**入力体験と読まれる仕組みの作り込みに全時間を投下できる**
- **運用コストゼロ** — Vercel の静的配信のみ

## 入力時間の計測（**このプロジェクト固有の中核**）

**「書く時間を90秒に」を主張するなら、それを測らなければならない。**

```
入力セッションの計測
  開始：新規作成 or 編集画面を開いた瞬間
  一時停止：タブが非表示になった／30秒以上操作がない
  再開：操作が再開された
  終了：提出 or 離脱
  → activeSeconds（実際に手を動かしていた秒数）を記録
```

| ID | 規約 |
|---|---|
| MEA-01 | **入力時間は「アクティブな秒数」を計測すること。** タブを離れていた時間、30秒以上の無操作は含めない |
| MEA-02 | 計測を `lib/metrics/input-timer.ts` に集約し、**コンポーネント側でタイマーを持たないこと** |
| MEA-03 | **計測していることを書き手に隠さないこと。** 入力中に経過時間を控えめに表示する（監視ではなく、短さの実感のため） |
| MEA-04 | **計測結果を個人の評価に使わせない設計にすること。** 管理者画面では**チーム平均と分布のみ**を表示し、個人別のランキングを作らない（4章 SCP-04） |
| MEA-05 | 計測は下書き保存・提出のたびに累積すること（複数回に分けて書くケースに対応） |

**MEA-04 は重要。** 入力時間を個人評価に使えるようにすると、日報アプリが監視ツールになり、事実①の「監視のために書かされている感覚」を強化してしまう。**測るのは運用改善のためであり、人を測るためではない。**

## 週次まとめの自動生成（**入力を減らす機能の核**）

事実②で「③蓄積は週次でよい」と書いた。だが週報を別途書かせると入力が増える。**だから日報から自動で組み立てる。**

```
週次まとめの生成（ルールベース。AIを使わない）
  ① その週の日報を収集
  ② 「実施内容」から、同じタグ・案件のものをグループ化
  ③ 「進捗」の数値項目を合算
  ④ 「課題・相談」を未解決のものだけ抽出
  ⑤ 「気づき」をそのまま列挙
  ⑥ 未提出日を明示
  → 下書きとして提示し、本人が追記・修正して提出
```

| ID | 規約 |
|---|---|
| SUM-01 | **週次まとめはルールベースで生成すること。** 外部AIを呼ばない（キー管理が不要／データが外に出ない） |
| SUM-02 | **生成結果は必ず下書きとし、本人が確認・修正してから提出すること。** 自動提出しない |
| SUM-03 | 生成に使った日報を**リンクで辿れるようにすること**（根拠の可視化） |
| SUM-04 | **生成できなかった項目を明示すること**（「今週は気づきの記入が0件でした」） |
| SUM-05 | 生成ロジックを `lib/summary/` に集約し、純粋関数とすること |

## 差し替え可能性の担保

**データアクセスは必ず `lib/repo/` のリポジトリ層を経由すること。** コンポーネントからストアを直接触らない。

```
[ コンポーネント ]
        ↓  呼ぶのはこの層だけ
[ lib/repo/*.ts ]   ← 全メソッドを async にしておく
        ↓
[ lib/search/ ]     ← 全文検索（純粋関数）
[ lib/summary/ ]    ← 週次まとめ生成（純粋関数）
[ lib/metrics/ ]    ← 提出率・返信率・入力時間（純粋関数）
[ lib/store/*.ts ]  ← Zustand + persist（localStorage）
        ↓
[ lib/seed/*.ts ]   ← 初期データ
```

リポジトリの各メソッドは、中身が同期処理でも **`async` で定義し、`await` で呼ぶ**。実案件へ転用する際、リポジトリの実装だけをAPI呼び出しに差し替えれば、UI層は一行も変更せずに済む。

## 記事への組み込み

| 段 | 配置 | 中身 |
|---|---|---|
| ① 記事内インライン | 記事の冒頭〜中盤、`<iframe>` | **日報の入力フォーム + 入力時間タイマー + 「前日をコピー」ボタン。** 実際に打てて、秒数が出る |
| ② 全画面デモ | 「全画面で試す」カード → **別タブ** | アプリ全体（タイムライン・コメント・週次まとめ・提出率ダッシュボード） |

**記事内で見せるのは「書くのがどれだけ速いか」だけに絞る。** これが事実③そのものであり、スクロール中に体験できる唯一のことになる。

| ID | 要件 |
|---|---|
| EMB-01 | 記事内 iframe は `loading="lazy"` とし、ビューポート接近まで読み込まないこと |
| EMB-02 | 埋め込みモードのJS初期バンドルは 60KB以下（gzip後）とすること |
| EMB-03 | 埋め込み iframe が記事の LCP 要素にならないこと |
| EMB-04 | **埋め込みモードで実際に入力でき、入力時間が計測されて表示されること**（これが主役） |
| EMB-05 | **「前日をコピー」を押すと、大半が埋まった状態になり、残り入力が明示されること**（「あと2項目」） |
| EMB-06 | 埋め込みモードで提出はできること。ただし**アプリ内遷移はせず**、「全画面で続きを見る」を `target="_blank"` で提示すること |
| EMB-07 | 埋め込みモードでカメラ・位置情報を呼ばないこと |
| EMB-08 | GA4 で計測すること：`demo_open` / `report_submitted`（**提出した**）／`copy_yesterday_used`（**前日コピーを使った**）／`input_seconds`（**入力秒数の分布**）／`comment_posted` / `summary_generated` / `role_switch` / `doc_download` / `form_click` / `line_click` |
| EMB-09 | **`input_seconds` は最重要指標。** 読者が実際に何秒で書けたかの分布は、記事の主張を裏付ける実データになる |
| EMB-10 | **入力された日報の本文を GA4 に送らないこと。** 送るのは秒数・項目数などのメタ情報のみ |
| EMB-11 | `?embed=1` のURLは `noindex` とすること。デモ本体は固有の title / description を持つこと |

## 永続化の範囲

| 対象 | 挙動 |
|---|---|
| シードデータ（メンバー・チーム・テンプレート・過去3ヶ月の日報・コメント） | 初期投入。テンプレートは編集可能 |
| **日報・下書き・コメント・リアクション・既読・週次まとめ** | localStorage に保存。**リロードしても残る** |
| **入力時間の計測結果** | localStorage に保存 |
| 添付画像 | IndexedDB（Blob）。**サーバーには送らない** |
| リセット | 「デモをリセット」で localStorage / IndexedDB をクリア |

**擬似ディレイ** は 150〜400ms。ただし**入力・下書き保存・提出・検索は 100ms以下**とし、ディレイを入れない（入力でもたつくのは、このアプリで最も致命的な体験）。

---

# 3. スコープ定義

## 書く（メンバー）

| ID | 機能 | 概要 | 優先度 |
|---|---|---|---|
| F-W01 | **日報の作成・提出** | テンプレートに沿った入力。**提出はワンタップ** | Must |
| F-W02 | **前日をコピー** | 前回の内容を引き継いで開始。**変わった部分だけ直す** | Must |
| F-W03 | **入力時間の表示** | 入力中の経過時間と、提出後の所要時間・平均との比較 | Must |
| F-W04 | **下書きの自動保存** | 入力停止から2秒後に保存。**アプリを閉じても失われない** | Must |
| F-W05 | 選択式項目 | 案件・作業種別・進捗ステータスは選択式（自由記述を最小に） | Must |
| F-W06 | **サジェスト** | 過去の入力から、案件名・作業内容・よく使う語句を候補表示 | Must |
| F-W07 | **課題・相談ブロック** | 報告と分離。**入れると読み手側で目立つ** | Must |
| F-W08 | 気づき・学びブロック | 任意入力。**空でも提出できる**（無理をさせない） | Must |
| F-W09 | 数値項目 | 訪問件数・作業時間・進捗率など。テンプレートで定義 | Must |
| F-W10 | 画像添付 | 現場写真など。端末内で圧縮 | Should |
| F-W11 | 音声入力の許容 | ブラウザの音声入力を妨げないこと（専用実装はしない） | Should |
| F-W12 | 提出後の編集 | 一定時間内（既定30分）は自分で編集可。以降は編集履歴が残る | Must |
| F-W13 | **未提出のリマインド** | 提出時刻を過ぎたら通知（プレビュー表示で再現） | Must |
| F-W14 | オフライン作成 | 圏外でも書けて、復帰時に同期 | Should |
| F-W15 | **週次まとめの生成** | 日報から自動生成した下書きを、確認・修正して提出（2章） | Must |

## 読む・返す（メンバー・上司）

| ID | 機能 | 概要 | 優先度 |
|---|---|---|---|
| F-R01 | **チームのタイムライン** | 日付順のカード。**未読が明確**。フィルタ（メンバー・案件・課題あり） | Must |
| F-R02 | **日報の詳細** | 本文、数値、画像、既読者、コメント、リアクション | Must |
| F-R03 | **コメント** | 返信。メンション。**書き手に通知** | Must |
| F-R04 | **リアクション** | 1タップの反応（確認した／いいね／助かった）。**コメントより軽い反応の道を用意** | Must |
| F-R05 | **既読管理** | 誰が読んだかを日報に表示。**書き手に「読まれた」が見える** | Must |
| F-R06 | **課題の一覧** | 「課題・相談」がある日報だけを抽出。未対応／対応中／解決 | Must |
| F-R07 | 全文検索 | 本文・コメント・案件名を横断検索。期間・メンバーで絞り込み | Must |
| F-R08 | 個人のタイムライン | 特定メンバーの日報を時系列で。成長の記録として読む | Should |
| F-R09 | 通知センター | コメント、メンション、未読、未提出 | Must |
| F-R10 | 日報のエクスポート | 期間指定でCSV／Markdown出力 | Should |

## 運用を測る・整える（管理者）

| ID | 機能 | 概要 | 優先度 |
|---|---|---|---|
| F-A01 | **運用ダッシュボード** | **提出率・返信率・平均入力時間・未読率**。運用が回っているかを測る | Must |
| F-A02 | **提出状況** | メンバー×日付のグリッド。提出済／未提出／遅延 | Must |
| F-A03 | **返信率** | 上司ごとの返信率・平均返信時間。**読まれていないチームを検出** | Must |
| F-A04 | **入力時間の分布** | チーム平均、分布、テンプレート別。**個人別ランキングは作らない**（MEA-04） | Must |
| F-A05 | **テンプレート管理** | 項目の追加・削除・並び替え・必須設定。**項目数と推定入力時間を表示** | Must |
| F-A06 | 提出ルールの設定 | 提出期限、対象曜日、リマインド時刻、編集可能時間 | Must |
| F-A07 | チーム・メンバー管理 | チーム編成、上司の割当、権限 | Must |
| F-A08 | 案件・作業種別マスタ | 選択式項目の選択肢 | Must |
| F-A09 | 集計・レポート | 数値項目の期間集計、案件別、メンバー別 | Should |
| F-A10 | 通知文面の設定 | リマインド・コメント通知の文面 | Should |
| F-A11 | 操作ログ | 誰がいつ何を編集・削除したか | Should |

## 共通・基盤

| ID | 機能 | 概要 | 優先度 |
|---|---|---|---|
| F-C01 | ロール切替 | メンバー／上司（チームリーダー）／管理者 をワンクリック切替 | Must |
| F-C02 | 埋め込みモード | `?embed=1` で入力フォーム + タイマー（2章） | Must |
| F-C03 | 記事への導線 | 元記事へのリンク、資料ダウンロード、問い合わせ | Must |
| F-C04 | デモリセット | localStorage / IndexedDB をクリア | Must |
| F-C05 | PWA | ホーム画面追加、オフライン起動 | Should |
| F-C06 | ガイドツアー | 初回訪問時に「何を試せるか」を3ステップで案内 | Should |

## 対象外（Won't have）

| 項目 | 理由 |
|---|---|
| データベース・バックエンドAPI | 2章の方針に基づく |
| 本物の認証・SSO | ロール切替で代替 |
| 実際のメール・Slack・LINE送信 | プレビュー表示で再現 |
| **AIによる日報の自動要約・添削** | **週次まとめはルールベースで実装**（SUM-01）。AI連携は11章で費用論点として扱う |
| Slack / Teams / チャットツールとのAPI連携 | **11章で「そもそもチャットで足りるか」の論点として扱う** |
| 勤怠・工数管理としての利用 | **日報に工数を書かせるのは入力増になる。** TOKIWA（勤怠）の領域 |
| 承認ワークフロー（多段承認） | **日報に承認は不要。** コメントと既読で足りる。要望が出たら別途見積 |
| 人事評価との連携・評価スコア化 | **意図的に対象外**（MEA-04 の方針。監視ツール化を避ける） |
| 個人別の入力時間ランキング | **意図的に対象外**（MEA-04） |
| 多言語UI | 日本語のみ |
| ネイティブアプリ | PWAで対応 |

> **スコープリスク：** 日報は「あれも書かせたい」が最も起きやすい領域。**項目追加の要望は必ず来る。** そのとき「項目を1つ増やすと、入力時間が何秒増え、提出率が何%下がるか」を議論できる状態を作ることが、このプロジェクトの目的。**F-A05 のテンプレート管理画面に「項目数と推定入力時間」を表示させているのはこのため。**

---

# 4. ロールとデモ切替

## ロール定義

| ロールID | 名称 | 見えるデータ | 特徴的な権限 |
|---|---|---|---|
| `member` | メンバー | **自分の日報と、所属チームの日報** | 作成・提出・編集（時間内）、コメント、リアクション |
| `leader` | 上司（チームリーダー） | **自チーム全員** | 上記 + チームの提出状況・返信率の確認、リマインド送信 |
| `admin` | 管理者 | **全社** | 上記 + テンプレート管理・提出ルール・全社ダッシュボード・操作ログ |

## データスコープと項目スコープ

| ID | 要件 |
|---|---|
| SCP-01 | **データスコープ（見える行）と項目スコープ（見える列）を、ともに `lib/repo/_scope.ts` に集約すること** |
| SCP-02 | **コンポーネント側で `role === 'member'` のような分岐を書かないこと** |
| SCP-03 | **メンバーは他チームの日報を一切取得できないこと。** リポジトリが空配列を返すこと |
| SCP-04 | **個人別の入力時間を、本人以外に返さないこと。** 上司・管理者にはチーム平均と分布のみを返す（MEA-04） |
| SCP-05 | 「課題・相談」ブロックは、**書き手が「上司のみ」に限定できること。** 限定された場合、チームの他メンバーには表示しないこと |

**SCP-04 と SCP-05 が、このデモの倫理設計。** 日報アプリは容易に監視ツールになるため、**データの返し方の段階で防ぐ。**

## ロールを跨ぐ体験（必ず動くようにする）

1. **メンバーで日報を書いて提出** → 上司に切替 → **タイムラインに未読として現れ、課題ありのバッジが付いている**
2. **上司がコメントする** → メンバーに切替 → **通知が来ており、日報に既読者とコメントが付いている**
3. **メンバーが「前日をコピー」で書く** → **入力時間が前回より短くなり、「前回より38秒短縮」と表示される**
4. **上司が返信をサボる** → 管理者に切替 → **返信率ダッシュボードでそのチームの返信率が下がっている**
5. **管理者がテンプレートに項目を3つ追加** → メンバーに切替 → **入力項目が増え、推定入力時間が伸びている**
6. **メンバーが週次まとめを生成** → **その週の日報から自動で組み立てられ、根拠の日報にリンクが張られている**
7. **メンバーが「課題・相談」を上司のみに限定** → 別のメンバーに切替 → **その部分が表示されていない**

**3番と5番が、このデモの核心。** 事実③（入力を減らす機能だけが生き残らせる）が体験として成立する瞬間。

## デモ切替バー（F-C01）

画面上部に常時表示する固定バー。**埋め込みモードでは非表示。**

- 現在のロールと氏名・チームの表示、3ロールの切替
- メンバーロール時：3名から操作主体を選択（**毎日書く人／たまに書かない人／新人** を用意）
- **デモ内の現在日時**（シードが相対日付のため基準を示す）
- 「デモをリセット」ボタン（確認ダイアログ付き）
- 元記事へ戻るリンク
- 「これはデモです。書いた内容は送信されません」の明示

**デザイン上の扱い：** プロダクト本体が明るく余白の広い読み書きのUIなので、切替バーは**濃い墨色の帯**にして明確に区別する。

---

# 5. 画面一覧とユーザーフロー

全28画面。画面IDはディレクトリ構成と 1:1 で対応させる。

## 書く（メンバー）

| 画面ID | 画面名 | パス | 主要要素 |
|---|---|---|---|
| SC-001 | **ホーム** | `/` | 今日の日報（未提出なら大きく促す）、未読件数、コメント通知、今週のまとめ状況 |
| SC-010 | **日報の作成** | `/reports/new` | テンプレート項目、**入力時間タイマー**、前日コピー、下書き自動保存 |
| SC-011 | **日報の編集** | `/reports/[id]/edit` | 同UI。編集可能時間の残りを表示 |
| SC-012 | 提出完了 | モーダル | **入力時間と平均との比較**、次のアクション（チームを読む） |
| SC-013 | 下書き一覧 | `/reports/drafts` | 書きかけの日報、最終編集日時 |
| SC-020 | **自分の日報一覧** | `/reports/mine` | 時系列カード、提出状況、既読数、コメント数 |
| SC-021 | 日報の詳細（自分） | `/reports/[id]` | 本文、数値、画像、**既読者のアバター**、コメント、リアクション |
| SC-030 | **週次まとめの生成** | `/weekly/new` | 生成された下書き、**根拠の日報へのリンク**、追記・修正、提出 |
| SC-031 | 週次まとめ一覧 | `/weekly` | 過去の週報、提出状況 |
| SC-040 | 通知センター | `/notifications` | コメント、メンション、未読、未提出リマインド |
| SC-900 | 埋め込みモード | `/?embed=1` | **入力フォーム + タイマー + 前日コピー**（2章） |

## 読む・返す

| 画面ID | 画面名 | パス | 主要要素 |
|---|---|---|---|
| SC-100 | **チームのタイムライン** | `/team` | 日付順カード、**未読の明示**、フィルタ（メンバー／案件／課題あり／未読のみ） |
| SC-101 | 日報の詳細（他人） | `/team/reports/[id]` | 本文、**課題ブロックの強調**、既読者、コメント欄、リアクション |
| SC-102 | **課題の一覧** | `/team/issues` | 課題・相談がある日報の抽出。未対応／対応中／解決、経過日数 |
| SC-103 | **メンバーのタイムライン** | `/team/members/[id]` | 特定メンバーの日報を時系列で。提出率、最近の傾向 |
| SC-110 | **検索** | `/search` | 全文検索、期間・メンバー・案件で絞り込み、ハイライト表示 |
| SC-120 | エクスポート | `/export` | 期間指定、CSV／Markdown、プレビュー |

## 運用を測る・整える（上司・管理者）

| 画面ID | 画面名 | パス | 主要要素 |
|---|---|---|---|
| SC-200 | **運用ダッシュボード** | `/admin` | **提出率・返信率・平均入力時間・未読率**の4指標と推移 |
| SC-201 | **提出状況** | `/admin/submissions` | メンバー×日付グリッド、提出済／未提出／遅延、**リマインド送信** |
| SC-202 | **返信率** | `/admin/response` | 上司別の返信率・平均返信時間、**返信されていない日報の抽出** |
| SC-203 | **入力時間の分布** | `/admin/input-time` | チーム平均、ヒストグラム、テンプレート別。**個人別ランキングなし** |
| SC-210 | **テンプレート管理** | `/admin/templates` | 項目の追加・削除・並び替え・必須設定、**項目数と推定入力時間の表示** |
| SC-211 | テンプレートのプレビュー | モーダル | 書き手から見える実画面 |
| SC-220 | 提出ルールの設定 | `/admin/settings/rules` | 提出期限、対象曜日、リマインド時刻、編集可能時間 |
| SC-221 | チーム・メンバー管理 | `/admin/members` | チーム編成、上司の割当、権限 |
| SC-222 | 案件・作業種別マスタ | `/admin/masters` | 選択式項目の選択肢、並び順 |
| SC-223 | 通知文面の設定 | `/admin/settings/notifications` | リマインド・コメント通知の文面 |
| SC-230 | 数値集計レポート | `/admin/reports` | 数値項目の期間集計、案件別、メンバー別 |
| SC-240 | 操作ログ | `/admin/logs` | 操作者・日時・対象・内容の検索 |

## 主要フロー

### フローA：記事の読者が「書く速さ」を体験する（**最重要**）

```
SEO記事を読んでいる
   ↓
記事内の埋め込み（SC-900）
┌────────────────────────────────────────────────────────┐
│  2026-08-24（月）の日報                    ⏱ 0:00      │
│                                                        │
│  案件          [ ▼ 選択してください        ]            │
│  作業種別      [ ▼ 選択してください        ]            │
│  進捗          [ ○順調 ○やや遅れ ○遅延 ]                │
│  実施内容      [                          ]            │
│  課題・相談    [                    ] （任意）          │
│  気づき        [                    ] （任意）          │
│                                                        │
│  [ 前日をコピー ]              [ 提出する ]             │
└────────────────────────────────────────────────────────┘
   ↓
何か打ち始める
   ↓  ★ タイマーが動き出す（⏱ 0:07 …）
「前日をコピー」を押す
   ↓  ★ 案件・作業種別・実施内容の大半が埋まる
   ★ 「あと2項目で提出できます」と表示される
   ↓
残りを埋めて「提出する」
   ↓
┌────────────────────────────────────────────────────────┐
│  提出しました                                           │
│                                                        │
│      入力時間  1分12秒                                 │
│                                                        │
│  前日をコピーしなかった場合の平均：3分48秒               │
│  → 2分36秒 短縮できました                              │
│                                                        │
│  [ 全画面でチームの日報を読む ]                          │
└────────────────────────────────────────────────────────┘
   ↓
「全画面で試す」→ 別タブ
   ↓
SC-100 チームのタイムライン ── ★ 8名の日報が並び、未読が明確
   ↓
SC-101 日報の詳細 ── コメントを書いてみる
   ↓
ロール切替「管理者」→ SC-203 入力時間の分布
   ↓  ★ チーム平均 2分14秒。前日コピー利用時は 1分22秒
SC-210 テンプレート管理 ── ★ 項目を3つ追加すると推定入力時間が +45秒 と表示される
   ↓
資料ダウンロード or 元記事に戻る
```

### フローB：書いたら読まれる（**事実①の「読まれない」を潰す**）

```
【メンバー：田中】SC-010 日報の作成
  実施内容を書く
  ★ 「課題・相談」に「A社の見積、値引き幅の判断をお願いしたいです」と書く
  ★ 公開範囲を「上司のみ」に設定（SCP-05）
   ↓
提出
   ↓
【上司】SC-100 チームのタイムライン
  ★ 田中の日報カードに「未読」と「課題あり」のバッジが付いている
  ★ 課題ありは他のカードより視覚的に前に出る
   ↓
SC-101 日報の詳細
  ★ 「課題・相談」ブロックが強調表示され、上司のみに見えている旨が表示される
   ↓
コメントを書く：「値引きは8%まで可。それ以上は要相談」
   ↓
【メンバー：別の人】SC-100 タイムライン
  ★ 田中の日報は読めるが、「課題・相談」ブロックは表示されない（SCP-05）
   ↓
【メンバー：田中】SC-001 ホーム
  ★ 通知：「上司さんがコメントしました」
   ↓
SC-021 日報の詳細
  ★ 既読者のアバターが3名分ついている
  ★ コメントが付いている
  ★ リアクション「確認した」が2件
   ↓
★ ここで伝わること：
  「書いたら、読まれた痕跡が返ってくる。だから次も書く」
```

### フローC：運用が回っているかを測る

```
【管理者】SC-200 運用ダッシュボード
  提出率      87%  （先週 91% ▼）
  返信率      42%  （先週 58% ▼）★ 悪化
  平均入力時間 2分14秒
  未読率      31%  ★ 高い
   ↓
★ 「提出率は高いが、返信率が下がり未読が溜まっている」
   → 書かせているのに読んでいない状態
   ↓
SC-202 返信率
  ★ 上司別に表示
    山田（営業1課）  返信率 71% / 平均返信 4時間
    佐藤（営業2課）  返信率 18% / 平均返信 3日  ★ 赤で強調
  ★ 「返信されていない日報 24件」の一覧へ
   ↓
SC-201 提出状況 ── メンバー×日付のグリッド
  ★ 特定の曜日（金曜）に未提出が集中している
  ★ リマインド時刻が18:00だが、金曜は早く帰るため間に合っていない
   ↓
SC-220 提出ルールの設定
  ★ 金曜のリマインド時刻を16:00に変更
   ↓
SC-210 テンプレート管理
  ★ 項目数 9個／推定入力時間 3分20秒 と表示されている
  ★ 「気づき」を必須から任意に変更 → 推定 2分40秒 に
   ↓
【メンバー】★ 入力項目が減り、提出しやすくなっている
   ↓
（1週間後）SC-200 ダッシュボード
  ★ 提出率 87% → 94%、返信率 42% → 65%
   ↓
★ ここで伝わること：
  「日報アプリは作って終わりではない。運用を測って、調整して初めて回る」
```

---

# 6. 機能要件

各要件はテスト仕様書の項目と1:1で対応する。「〜できること」の粒度で、判定可能な形で記述している。

## 6.1 入力体験（**このデモの心臓部**）

| ID | 要件 | 優先 |
|---|---|---|
| FR-101 | **入力時間を計測すること。** タブが非表示の時間、30秒以上の無操作は除外すること（MEA-01） | P1 |
| FR-102 | **計測を `lib/metrics/input-timer.ts` に集約し、コンポーネント側でタイマーを持たないこと**（MEA-02） | P1 |
| FR-103 | **入力中に経過時間を控えめに表示すること**（MEA-03）。**大きく表示して急かさないこと** | P1 |
| FR-104 | 提出完了時に、**入力時間とチーム平均・自分の平均との比較を表示すること** | P1 |
| FR-105 | **複数回に分けて書いた場合、入力時間を累積すること**（MEA-05） | P1 |
| FR-106 | **「前日をコピー」で、前回提出した内容を引き継いで開始できること。** 引き継ぐ項目はテンプレートごとに設定できること | P1 |
| FR-107 | 前日コピー後、**「あと N項目で提出できます」と残りを明示すること** | P1 |
| FR-108 | **下書きを入力停止から2秒後に自動保存すること。** 保存状態を画面上で示すこと | P1 |
| FR-109 | **アプリを閉じて再訪しても、下書きが復元されること** | P1 |
| FR-110 | 選択式項目（案件・作業種別・進捗）を提供し、**自由記述を最小にすること** | P1 |
| FR-111 | **サジェスト**：過去の入力から、案件名・作業内容・よく使う語句を候補表示すること | P1 |
| FR-112 | **提出はワンタップとし、確認ダイアログを出さないこと**（提出後の編集で担保する） | P1 |
| FR-113 | 必須項目が未入力の場合、**提出ボタンの直上に不足項目を列挙すること**（押してからエラーを出さない） | P1 |
| FR-114 | 数値項目をテンプレートで定義でき、**キーボードがテンキーで開くこと**（`inputMode="numeric"`） | P1 |
| FR-115 | 画像を添付でき、**端末内で圧縮（長辺1600px・JPEG品質80）してから保持すること** | P2 |
| FR-116 | **ブラウザの音声入力を妨げないこと**（テキストエリアに独自のキーハンドラを被せない） | P2 |
| FR-117 | 提出後、**既定30分間は自分で編集できること。** それ以降の編集は履歴を残すこと | P1 |
| FR-118 | **オフラインでも作成・下書き保存・提出ができ、復帰時に同期すること** | P2 |
| FR-119 | **入力・下書き保存・提出が 100ms以下で完了すること。擬似ディレイを入れないこと** | P1 |

## 6.2 日報の構造（3つの目的の分離）

| ID | 要件 | 優先 |
|---|---|---|
| FR-201 | 日報を**「報告」「課題・相談」「気づき・学び」の3ブロックで構造化すること**（1章 事実②） | P1 |
| FR-202 | **「課題・相談」は空でも提出でき、入力があると読み手側で強調表示されること** | P1 |
| FR-203 | **「気づき・学び」は任意入力とし、空での提出を妨げないこと。** 催促の文言を出さないこと | P1 |
| FR-204 | **「課題・相談」の公開範囲を「チーム全体／上司のみ」から選べること**（SCP-05） | P1 |
| FR-205 | 「上司のみ」を選んだ場合、**チームの他メンバーには当該ブロックを表示しないこと。** リポジトリの段階で除外すること | P1 |
| FR-206 | 「課題・相談」に**対応状態（未対応／対応中／解決）を持たせ、読み手側で更新できること** | P1 |
| FR-207 | テンプレートの項目種別として、テキスト／長文テキスト／単一選択／複数選択／数値／日付／チェックボックス／画像 に対応すること | P1 |
| FR-208 | 項目ごとに、必須／任意、前日コピーの対象／非対象 を設定できること | P1 |

## 6.3 週次まとめ（**入力を減らす機能の核**）

| ID | 要件 | 優先 |
|---|---|---|
| FR-301 | **その週の日報から、週次まとめの下書きを自動生成すること**（2章 SUM） | P1 |
| FR-302 | **生成はルールベースで行い、外部AIを呼ばないこと**（SUM-01） | P1 |
| FR-303 | 生成内容：**実施内容のグループ化／数値項目の合算／未解決の課題の抽出／気づきの列挙／未提出日の明示** | P1 |
| FR-304 | **生成結果は必ず下書きとし、本人が確認・修正してから提出すること。自動提出しないこと**（SUM-02） | P1 |
| FR-305 | **生成に使った日報へのリンクを表示すること**（根拠の可視化）(SUM-03) | P1 |
| FR-306 | **生成できなかった項目を明示すること**（「今週は気づきの記入が0件でした」）(SUM-04) | P1 |
| FR-307 | 週次まとめの生成ロジックを `lib/summary/` に集約し、純粋関数とすること（SUM-05） | P1 |
| FR-308 | 週の起算曜日を設定できること | P2 |
| FR-309 | 週次まとめにも既読・コメントが付けられること | P2 |

## 6.4 読む・返す

| ID | 要件 | 優先 |
|---|---|---|
| FR-401 | チームのタイムラインを日付順のカードで表示し、**未読を明確に区別すること** | P1 |
| FR-402 | フィルタを提供すること（メンバー／案件／**課題あり**／**未読のみ**／期間） | P1 |
| FR-403 | **課題ありの日報を、視覚的に前に出すこと**（バッジ + 枠線）。件数をタイムライン上部に表示すること | P1 |
| FR-404 | **既読を記録し、日報詳細に既読者のアバターを表示すること。** 書き手からも見えること | P1 |
| FR-405 | **既読は日報を一定時間（既定3秒）表示したときに記録すること。** スクロールで通過しただけで既読にしないこと | P1 |
| FR-406 | **コメントを投稿でき、書き手に通知されること**（通知はプレビュー表示で再現） | P1 |
| FR-407 | コメントでメンションでき、対象者に通知されること | P2 |
| FR-408 | **リアクション（確認した／いいね／助かった）を1タップで付けられること。** コメントより軽い反応の道を用意すること | P1 |
| FR-409 | SC-102 課題の一覧で、**課題がある日報だけを抽出し、対応状態と経過日数を表示すること** | P1 |
| FR-410 | **未対応のまま一定日数（既定3日）経過した課題を強調表示すること** | P1 |
| FR-411 | SC-103 メンバーのタイムラインで、特定メンバーの日報を時系列に表示し、提出率を併記すること | P2 |
| FR-412 | **全文検索**：本文・コメント・案件名を横断検索し、**ヒット箇所をハイライト表示すること** | P1 |
| FR-413 | 検索は期間・メンバー・案件・課題ありで絞り込めること。**URLクエリに反映すること** | P1 |
| FR-414 | **検索が 100ms以下で完了すること**（日報1,500件規模） | P1 |
| FR-415 | 期間指定で CSV／Markdown をエクスポートできること | P2 |

## 6.5 運用の計測（**このデモの差別化要素**）

| ID | 要件 | 優先 |
|---|---|---|
| FR-501 | **運用ダッシュボードに4指標を表示すること：提出率／返信率／平均入力時間／未読率**。前週比を併記すること | P1 |
| FR-502 | **提出率** = 提出済み日報数 ÷ 提出対象日数（対象曜日・在籍期間を考慮）で算出すること | P1 |
| FR-503 | **返信率** = コメントまたはリアクションが1件以上付いた日報数 ÷ 提出日報数 で算出すること | P1 |
| FR-504 | **未読率** = 未読の日報数 ÷ 閲覧対象日報数 で算出すること | P1 |
| FR-505 | SC-201 提出状況を、**メンバー×日付のグリッドで表示すること**（提出済／未提出／遅延／対象外） | P1 |
| FR-506 | グリッドから**未提出者へのリマインドを送れること**（プレビュー表示で再現） | P1 |
| FR-507 | **提出が集中して落ちている曜日・時刻を検出して提示すること**（フローC） | P2 |
| FR-508 | SC-202 返信率を**上司別に表示し、平均返信時間を併記すること** | P1 |
| FR-509 | **返信されていない日報を抽出できること。** 経過日数順に並べられること | P1 |
| FR-510 | SC-203 入力時間を**チーム平均・ヒストグラム・テンプレート別**で表示すること | P1 |
| FR-511 | **個人別の入力時間ランキングを作らないこと。個人別の入力時間を本人以外に返さないこと**（MEA-04, SCP-04） | P1 |
| FR-512 | **前日コピーを使った場合と使わなかった場合の入力時間を比較表示すること** | P1 |
| FR-513 | 数値項目の期間集計を、案件別・メンバー別で表示すること | P2 |

## 6.6 テンプレート・設定

| ID | 要件 | 優先 |
|---|---|---|
| FR-601 | テンプレートの項目を追加・削除・並び替えできること（ドラッグ + **キーボード操作**） | P1 |
| FR-602 | **項目数と推定入力時間をテンプレート管理画面に常時表示すること**（3章のスコープリスク対策） | P1 |
| FR-603 | **推定入力時間は、項目種別ごとの実測平均から算出すること**（自由記述は長く、選択式は短い） | P1 |
| FR-604 | **項目を追加・削除すると、推定入力時間が即座に更新されること** | P1 |
| FR-605 | テンプレートを書き手視点でプレビューできること | P1 |
| FR-606 | テンプレートをチーム別に割り当てられること | P2 |
| FR-607 | テンプレート変更時、**過去の日報は当時の構造で表示されること**（項目を消しても過去分は消えない） | P1 |
| FR-608 | 提出ルールを設定できること：提出期限、対象曜日、リマインド時刻、編集可能時間 | P1 |
| FR-609 | **曜日ごとにリマインド時刻を変えられること**（フローC） | P2 |
| FR-610 | チーム編成・上司の割当・権限を管理できること | P1 |
| FR-611 | 案件・作業種別マスタを管理できること。**使用件数を表示し、未使用の選択肢を検出すること** | P2 |
| FR-612 | 通知文面（リマインド・コメント通知）を編集でき、差し込み変数を使えること | P2 |
| FR-613 | 日報の編集・削除・テンプレート変更を操作ログに記録すること | P2 |

## 6.7 デモ基盤

| ID | 要件 | 優先 |
|---|---|---|
| FR-701 | 3ロールをワンクリックで切り替えられること | P1 |
| FR-702 | **データスコープと項目スコープを `lib/repo/_scope.ts` に集約すること**（SCP-01, SCP-02） | P1 |
| FR-703 | **メンバーは他チームの日報を一切取得できないこと**（SCP-03） | P1 |
| FR-704 | **個人別の入力時間を本人以外に返さないこと**（SCP-04） | P1 |
| FR-705 | **「上司のみ」の課題ブロックを、対象外のメンバーに返さないこと**（SCP-05） | P1 |
| FR-706 | 「デモをリセット」で localStorage / IndexedDB をクリアすること | P1 |
| FR-707 | 日報・下書き・コメント・既読・入力時間がリロード後も保持されること | P1 |
| FR-708 | デモ内の現在日時を切替バーに表示すること | P2 |
| FR-709 | ロール権限外の画面では案内画面から切り替えられること。素の404を出さないこと | P1 |
| FR-710 | 権限で不可の操作はボタンを非活性にし、理由をツールチップで示すこと | P1 |
| FR-711 | 元記事へ戻るリンクと資料ダウンロードを常設すること | P1 |
| FR-712 | 初回訪問時に3ステップのガイドツアーを表示し、「今後表示しない」を選べること | P2 |
| FR-713 | **埋め込みモード**：入力フォーム + タイマー + 前日コピーを表示し、提出はできるが**アプリ内遷移をせず**、カメラ・位置情報を呼ばないこと（EMB-04〜07） | P1 |

---

# 7. データ設計

## 型定義（`lib/types/`）

```ts
// ---- 組織・メンバー ----
type Team = { id: string; name: string; leaderId: string; templateId: string }

type Member = {
  id: string
  name: string                  // ★ 架空
  teamId: string
  role: 'member' | 'leader' | 'admin'
  avatarUrl: string
  joinedAt: string
  isActive: boolean
}

// ---- テンプレート ----
type FieldType = 'text' | 'textarea' | 'select' | 'multiselect' | 'number' | 'date' | 'checkbox' | 'image'

type TemplateField = {
  id: string
  label: string
  type: FieldType
  block: 'report' | 'issue' | 'insight'   // ★ 3つの目的（FR-201）
  options?: string[]                       // select / multiselect
  masterKey?: 'project' | 'work_type'      // マスタから選択肢を取る
  unit?: string                            // number
  isRequired: boolean
  copyFromPrevious: boolean                // ★ 前日コピーの対象（FR-106）
  placeholder?: string
  helpText?: string
  inputMode?: 'text' | 'numeric'           // FR-114
  sortOrder: number
  // ★ 推定入力時間の算出に使う（FR-603）
  estimatedSeconds: number
}

type Template = {
  id: string
  version: number                          // ★ 過去の日報は当時の構造で表示（FR-607）
  name: string
  fields: TemplateField[]
  teamIds: string[]
  effectiveFrom: string
  // --- 算出値（保存しない）---
  // fieldCount, estimatedTotalSeconds は lib/metrics で算出
}

// ---- ★★★ 日報（このプロジェクトの中核）★★★ ----
type ReportStatus = 'draft' | 'submitted'

type Report = {
  id: string
  memberId: string
  reportDate: string            // YYYY-MM-DD
  templateId: string
  templateVersion: number       // ★ 当時の構造で表示するため（FR-607）
  status: ReportStatus
  // --- 本文（テンプレート項目のID → 値）---
  values: Record<string, FieldValue>
  // --- ★ 課題・相談の扱い（FR-204〜206）---
  issue?: {
    hasIssue: boolean
    visibility: 'team' | 'leader_only'    // ★ SCP-05
    resolutionStatus: 'open' | 'in_progress' | 'resolved'
    resolvedBy?: string
    resolvedAt?: string
  }
  // --- 添付 ---
  imageIds: string[]            // IndexedDB のキー
  // --- ★ 入力時間の計測（MEA-01, MEA-05）---
  inputMetrics: {
    activeSeconds: number       // 累積のアクティブ入力秒数
    sessionCount: number        // 何回に分けて書いたか
    usedCopyPrevious: boolean   // ★ 前日コピーを使ったか（FR-512）
    firstOpenedAt: string
    submittedAt?: string
  }
  // --- 提出 ---
  submittedAt?: string
  isLate: boolean               // 提出期限を過ぎたか
  // --- 編集履歴（FR-117）---
  editHistory: { at: string; by: string; changedFieldIds: string[] }[]
  createdAt: string
  updatedAt: string
}

type FieldValue = string | number | boolean | string[] | null

// ---- 反応（★ 「読まれた」を成立させる）----
type ReadReceipt = {
  id: string
  reportId: string
  memberId: string
  readAt: string                // ★ 3秒以上表示で記録（FR-405）
}
type Reaction = {
  id: string
  reportId: string
  memberId: string
  kind: 'confirmed' | 'good' | 'helpful'   // 確認した / いいね / 助かった
  createdAt: string
}
type Comment = {
  id: string
  reportId: string
  memberId: string
  body: string
  mentionedMemberIds: string[]
  createdAt: string
  editedAt?: string
}

// ---- 週次まとめ ----
type WeeklySummary = {
  id: string
  memberId: string
  weekStart: string             // YYYY-MM-DD
  weekEnd: string
  status: 'generated' | 'submitted'
  // --- 生成結果（SUM）---
  generated: {
    groupedActivities: { key: string; label: string; items: string[]; sourceReportIds: string[] }[]
    numericTotals: { fieldId: string; label: string; total: number; unit?: string }[]
    openIssues: { reportId: string; body: string; daysOpen: number }[]
    insights: { reportId: string; body: string }[]
    missingDates: string[]      // ★ 未提出日（SUM-04）
    notes: string[]             // ★ 生成できなかった項目の説明（SUM-04）
  }
  // --- 本人の追記・修正 ---
  edited: { retrospective: string; nextWeekPlan: string }
  submittedAt?: string
  generatedAt: string
}

// ---- 設定 ----
type SubmissionRule = {
  id: string
  teamId?: string               // 未指定なら全社
  targetWeekdays: number[]      // 提出対象の曜日
  deadlineMin: number           // 提出期限（0:00からの分数。1080 = 18:00）
  reminders: { weekday: number; atMin: number }[]   // ★ 曜日別のリマインド（FR-609）
  editableMinutes: number       // 提出後の編集可能時間（既定30）
  weekStartsOn: number
}

type MasterItem = {
  id: string
  key: 'project' | 'work_type'
  name: string
  isActive: boolean
  sortOrder: number
  // 算出値：usageCount（FR-611）
}

// ---- 通知 ----
type Notification = {
  id: string
  targetMemberId: string
  kind: 'comment' | 'mention' | 'reaction' | 'unread_reminder' | 'submit_reminder' | 'issue_stale'
  title: string
  body: string
  link: string
  previewMessage?: { channel: 'email' | 'slack' | 'line'; subject?: string; body: string }  // ★ 送信しない
  readAt?: string
  createdAt: string
}

// ---- 運用指標（★ 算出値。ストアに保存しない）----
type OpsMetrics = {
  scope: { teamId?: string; from: string; to: string }
  submissionRate: number        // FR-502
  responseRate: number          // FR-503
  unreadRate: number            // FR-504
  avgInputSeconds: number
  // --- 比較 ---
  prevSubmissionRate: number
  prevResponseRate: number
  prevUnreadRate: number
  prevAvgInputSeconds: number
}
type SubmissionGrid = {
  members: { memberId: string; name: string }[]
  dates: string[]
  cells: Record<string, 'submitted' | 'late' | 'missing' | 'not_required'>  // `${memberId}:${date}`
}
type ResponseByLeader = {
  leaderId: string
  name: string
  responseRate: number
  avgResponseHours: number
  unrespondedReportIds: string[]
}
type InputTimeDistribution = {
  teamAvgSeconds: number
  histogram: { fromSec: number; toSec: number; count: number }[]
  byTemplate: { templateId: string; name: string; avgSeconds: number; fieldCount: number }[]
  withCopyAvgSeconds: number    // ★ FR-512
  withoutCopyAvgSeconds: number
  // ★ 個人別は含めない（MEA-04, SCP-04）
}

// ---- 監査 ----
type AuditLog = {
  id: string
  actorId: string
  action: 'edit_report' | 'delete_report' | 'update_template' | 'update_rule' | 'send_reminder'
  targetType: string
  targetId: string
  changes: { field: string; before: unknown; after: unknown }[]
  createdAt: string
}
```

## 入力時間の計測（**7章の中核**）

```ts
// lib/metrics/input-timer.ts — コンポーネントはこのフックだけを使う（MEA-02）
const IDLE_THRESHOLD_MS = 30_000

export function createInputTimer() {
  let activeMs = 0
  let lastTick: number | null = null

  const onActivity = () => {
    const now = Date.now()
    if (lastTick !== null) {
      const delta = now - lastTick
      // ★ 30秒以上の無操作は加算しない（MEA-01）
      if (delta < IDLE_THRESHOLD_MS) activeMs += delta
    }
    lastTick = now
  }

  const onHidden = () => { lastTick = null }   // ★ タブ非表示中は加算しない
  const onVisible = () => { lastTick = Date.now() }

  return {
    onActivity, onHidden, onVisible,
    getActiveSeconds: () => Math.round(activeMs / 1000),
    // ★ 既存の累積に足し込む（複数回に分けて書くケース。MEA-05）
    merge: (prevSeconds: number) => prevSeconds + Math.round(activeMs / 1000),
  }
}
```

```ts
// lib/metrics/estimate.ts — テンプレートの推定入力時間（FR-603）
// 項目種別ごとの実測平均（シードの実データから算出した係数）
const SECONDS_BY_TYPE: Record<FieldType, number> = {
  select: 4, multiselect: 8, checkbox: 3, date: 6, number: 8,
  text: 15, textarea: 45, image: 20,
}

export function estimateInputSeconds(fields: TemplateField[]): number {
  return fields
    .filter(f => f.isRequired)                      // 任意項目は加算しない
    .reduce((sum, f) => sum + (f.estimatedSeconds || SECONDS_BY_TYPE[f.type]), 0)
}
```

## シードデータ（`lib/seed/`）

| ファイル | 内容 | 件数 |
|---|---|---|
| `teams.ts` `members.ts` | チーム4（営業2・現場1・本部1）、メンバー（**書く頻度に差をつける**） | チーム4 / 22名 |
| `templates.ts` | テンプレート3種（営業用・現場用・開発用）。**バージョン2つ持つものを1つ**（FR-607 の実演用） | 3件 |
| `masters.ts` | 案件18・作業種別12（**未使用の選択肢を2つ混ぜる**） | 30件 |
| `reports.ts` | **日報（過去3ヶ月・22名分）。入力時間の実データを持たせる** | 約1,500件 |
| `comments.ts` | コメント（**返信率に差をつける。返信の薄い上司を1名作る**） | 約620件 |
| `reactions.ts` `readReceipts.ts` | リアクション・既読（**未読が溜まっている状態を作る**） | 約2,800件 |
| `weeklySummaries.ts` | 週次まとめ（提出済み／未生成を混在） | 約120件 |
| `submissionRules.ts` | 提出ルール（**金曜のリマインドが遅い設定にしておく**。フローC の実演用） | 2件 |

**シード作成のルール（品質を左右する）**

- **実在企業名・実在人名を使わない。** 架空のメンバー名・案件名で構成する
- **氏名を「メンバーA」のようなダミーにしない。** 実在しそうな架空名にする
- **日報の本文を、業種の世界観を持つ実在しそうな文章にする。** 「本日の業務を行いました」のようなダミーを1件も残さない。**ここが手抜きだとデモ全体が死ぬ。日報アプリのデモは本文の質がそのまま説得力になる**
- **本文の長さに幅を持たせる。** 3行の人、10行の人、箇条書きの人が混在すること
- **入力時間の実データを持たせる。** 30秒〜8分の分布。**前日コピー利用時は明確に短く**（FR-512 が意味を持つように）
- **課題・相談が書かれている日報を1割程度作る。** うち数件を「上司のみ」に設定（SCP-05 の実演用）
- **未対応のまま3日以上経過した課題を数件作る**（FR-410 の実演用）
- **返信率に差をつける。** 返信の薄い上司を1名作り、返信されていない日報を20件以上残す（フローCの実演用）
- **未読が溜まっている状態を作る**（未読率30%程度）
- **未提出の日を作る。** 特に**金曜に未提出が集中している状態**にする（フローCの実演用）
- **「気づき」が空の日報を多く作る。** 任意項目が形骸化する実態を再現する（そしてそれが正常であることを示す）
- **提出が遅延した日報を混ぜる**（`isLate: true`）
- 日付は**現在日時からの相対で生成する。固定日付を埋め込まない**
- 日報は**提出対象曜日にのみ存在すること**（土日に日報が並んでいると嘘に見える）

## ストアとリポジトリ

```
lib/
├── types/  seed/
├── metrics/                    # ★ 純粋関数 + タイマー
│   ├── input-timer.ts          # ★ 入力時間の計測（MEA-02）
│   ├── estimate.ts             # ★ テンプレートの推定入力時間（FR-603）
│   ├── submission.ts           # 提出率（FR-502）
│   ├── response.ts             # 返信率・平均返信時間（FR-503, FR-508）
│   ├── unread.ts               # 未読率（FR-504）
│   ├── distribution.ts         # 入力時間の分布（FR-510, FR-512）
│   └── patterns.ts             # 提出が落ちる曜日・時刻の検出（FR-507）
├── summary/                    # ★ 週次まとめ生成。純粋関数のみ
│   ├── generate.ts             # SUM-05
│   ├── group.ts                # 実施内容のグループ化
│   └── totals.ts               # 数値項目の合算
├── search/                     # ★ 全文検索。純粋関数のみ
│   ├── index.ts                # 転置インデックスの構築
│   ├── query.ts                # 検索とスコアリング
│   ├── highlight.ts            # ヒット箇所のハイライト
│   └── normalize.ts            # ひらがな/カタカナ/半角全角の正規化
├── storage/                    # IndexedDB（画像）
├── query/                      # 絞り込み・ソート
├── store/  { session, data, settings, draft, sync, ui }
└── repo/                       # ★ コンポーネントが触るのはここだけ
    ├── _delay.ts
    ├── _scope.ts               # ★ データスコープ + 項目スコープ（SCP-01〜05）
    ├── reports.ts  drafts.ts  comments.ts  reactions.ts  reads.ts
    ├── weekly.ts  templates.ts  masters.ts  rules.ts
    ├── metrics.ts  search.ts  members.ts  notifications.ts  logs.ts
```

**リポジトリ層の規約（厳守）**

- 全メソッドを `async` で定義する。中身が同期でも例外なく
- 戻り値は `{ ok: true; data: T } | { ok: false; error: string }` に統一する
- **コンポーネントから Zustand ストアを直接参照しない。** 読み取りも書き込みもリポジトリ経由
- **入力時間の計測を `lib/metrics/input-timer.ts` に集約する。** コンポーネントで `setInterval` を持たない（MEA-02）
- **週次まとめの生成を `lib/summary/` に集約し、純粋関数とする**（SUM-05）
- **`lib/metrics/` `lib/summary/` `lib/search/` は純粋関数のみ。** ストア・DOM に依存させず、**`new Date()` を内部で呼ばない**
- **スコープ適用（`_scope.ts`）を全メソッドが必ず通す。** ここが実案件で権限制御に置き換わる箇所
- **個人別の入力時間を本人以外に返さない**（SCP-04）
- **「上司のみ」の課題ブロックを、対象外のメンバーに返さない**（SCP-05）
- 派生値（提出率・返信率・未読率・推定入力時間）はストアに保存せず算出する
- **入力・下書き保存・提出・検索に擬似ディレイを入れない**（FR-119）

```ts
// lib/repo/_scope.ts — 「上司のみ」の課題を除外する（SCP-05, FR-205）
export function scopeReport(report: Report, viewer: Member): Report | null {
  // 他チームは一切返さない（SCP-03）
  if (viewer.role === 'member' && report.teamId !== viewer.teamId) return null

  const isSelf = report.memberId === viewer.id
  const isLeaderOfWriter = viewer.role !== 'member' && isInScope(viewer, report)

  // ★ 「上司のみ」の課題ブロックは、本人と上司以外には含めない
  if (report.issue?.visibility === 'leader_only' && !isSelf && !isLeaderOfWriter) {
    return { ...report, issue: undefined, values: omitIssueFields(report.values) }
  }
  // ★ 個人別の入力時間は本人以外に返さない（SCP-04）
  if (!isSelf) return { ...report, inputMetrics: undefined as never }
  return report
}
```

---

# 8. デザイン要件

## アートディレクション

**「業務システムの中で、唯一の読み書きするアプリ」**

HIBI が扱うのは表ではなく**文章**である。日報は読まれるために書かれ、読み手は集中して読む。だから HIBI は**姉妹プロジェクトの中で最も密度が低く、余白が広く、1カラム**でできている。

- **1画面1カラム。** サイドバーに情報を詰めない。読むときは文章だけを見せる
- **本文が主役。** 15px・行間1.9。**日報の本文が読みやすいことが最優先**
- **色はほぼ使わない。** 例外は「課題あり」と「未読」の2つだけ
- **入力フォームに枠を描かない。** 下線と余白で区切る。**「書類に記入する」感覚を作らない**

> **姉妹プロジェクトとの差別化（最重要）**
> RELATE / KURA / TOKIWA は「表を読ませる高密度の業務システム」。**HIBI は文章を読み書きさせるアプリで、密度は真逆。**
> 4本を並べたとき、**HIBI だけが余白の広い1カラム**であることが一目で分かること。
> 配色も分ける：RELATE＝藍／ KURA＝ティール＋アンバー／ TOKIWA＝インディゴ＋コーラル／ **HIBI＝墨＋若草（低彩度の緑）**。

## カラートークン

```css
:root {
  /* 紙に近い、わずかに温かい白 */
  --paper:     #FAFAF8;   /* ページ背景 */
  --panel:     #FFFFFF;   /* カード・本文の地 */
  --panel-alt: #F2F2EE;   /* 区切り・引用 */
  --line:      #E5E5DF;   /* 罫線（極めて控えめに） */

  --ink-900:   #1C1D1A;   /* 本文（純黒にしない。長文を読ませるため） */
  --ink-600:   #5B5D57;   /* 補助テキスト */
  --ink-400:   #93958D;   /* ラベル・非活性 */

  --accent:    #4A6B3F;   /* 主要CTA（若草。低彩度） */
  --accent-d:  #3A5531;
  --accent-50: #EBF0E8;

  /* ★ 色を使う例外は2つだけ */
  --issue:     #A85B2B;   /* 課題あり（テラコッタ） */
  --issue-bg:  #F6EDE6;
  --unread:    #4A6B3F;   /* 未読（若草の点） */

  /* 状態（控えめに） */
  --st-draft:   #93958D;
  --st-late:    #A8892B;
  --st-missing: #A85B2B;

  /* 反応 */
  --reaction-bg: #F2F2EE;
}
```

**配色ルール**

- **色を使う箇所を2つに限定する：「課題あり」と「未読」。** それ以外は無彩色 + 若草のアクセントのみ
- **提出済み・未提出をバッジの色で塗り分けない。** テキストと位置で示す（一覧が色だらけになるのを防ぐ）
- **入力時間の表示に色を使わない。** 数字を大きくするだけ。**速い/遅いを色で評価しない**（MEA-04 の精神）
- チーム・メンバーに固有色を割り当てない。アバターで識別する

## タイポグラフィ

| 役割 | 書体 | 用途 |
|---|---|---|
| **本文** | **Noto Sans JP 400**（`line-height: 1.9`） | **日報の本文。これが主役** |
| 見出し | Noto Sans JP 700 | 画面タイトル、セクション |
| 日付・数値 | Roboto Mono 500（`tabular-nums`） | 日付、入力時間、提出率 |

| トークン | サイズ | 用途 |
|---|---|---|
| page-title | 22px / 700 | 画面タイトル |
| card-title | 16px / 700 | 日報カードの見出し（氏名 + 日付） |
| **body** | **15px / 400・行間1.9** | **日報の本文。他3本（13px）より大きい** |
| label | 11px / 700（`letter-spacing:.06em`） | 項目ラベル |
| meta | 12px / 400 | 提出時刻、既読数 |
| **timer** | 15px / 500 Mono | 入力中の経過時間（**控えめに**。MEA-03） |
| **input-result** | 30px / 500 Mono | 提出完了時の入力時間（**ここは大きく**） |

**本文15px・行間1.9 が HIBI の視覚的な指紋。** RELATE / KURA / TOKIWA はすべて13px の高密度。**HIBI だけが「読ませるための組版」を持つ。**

## レイアウトとスペーシング

| 項目 | 定義 |
|---|---|
| スペーシング | 4pxベース：4 / 8 / 12 / 16 / 24 / 32 / 48 / 64 |
| **アプリシェル** | **1カラム。** 上部にヘッダー（56px）、下部にタブナビ（モバイル）。**サイドバーを持たない**（管理画面のみ例外） |
| **コンテンツ最大幅** | **本文 680px**（1行 36〜42文字）。タイムライン 760px。**画面幅いっぱいに広げない** |
| 日報カード | 上下 24px の余白。カード間は罫線1本のみ（囲まない） |
| **入力フォーム** | **項目間 32px。** ラベルは上、入力は下線のみ。**枠で囲まない** |
| 提出ボタン | モバイルは下部固定（56px高）。**セーフエリアを考慮** |
| 角丸 | 4px（ボタン・入力）／2px（バッジ）／999px（アバター・リアクション） |
| 影 | **使わない。** 罫線と余白で階層を表現する |

## 主要コンポーネント仕様

| コンポーネント | 仕様 |
|---|---|
| **入力フォーム**（最重要） | 1カラム。ラベル（label）+ 入力（下線のみ）。**項目間32px。** 選択式はチップ状のボタン群（セレクトボックスを避け、タップ数を減らす） |
| **入力タイマー** | 画面右上に控えめに `⏱ 1:12`（timer サイズ、`--ink-400`）。**大きくしない、色を付けない、急かさない**（MEA-03） |
| **「前日をコピー」ボタン** | フォーム上部。押すと**埋まった項目に一瞬だけ若草の背景が走る**（何が埋まったか分かる）。押下後に「あと2項目」と表示 |
| **残り項目インジケータ** | 提出ボタンの直上。「あと2項目：進捗、実施内容」。**押してからエラーを出さない**（FR-113） |
| **提出完了モーダル** | `input-result`（30px Mono）で入力時間。その下に平均との比較。**「短縮できました」を出すが、遅い場合は何も言わない** |
| **3ブロックの構造** | 「報告」「課題・相談」「気づき・学び」を**罫線と見出しで分ける**。課題ブロックには公開範囲のセレクトを併置。**気づきには「空でも提出できます」を明示** |
| **日報カード**（タイムライン） | アバター + 氏名 + 日付（Mono）／本文の冒頭3行／数値項目のチップ／**未読は左端に若草の点**／**課題ありは `--issue-bg` の細い帯 + バッジ**／既読数・コメント数 |
| **課題ブロック（詳細）** | `--issue-bg` の地 + 左端に `--issue` の2px帯。対応状態のセレクト。**「上司のみに公開」の場合は鍵アイコンとその旨を表示** |
| **既読者の表示** | アバターを重ねて横並び（最大5 + 「他N名」）。**書き手側の詳細画面にも同じものを出す**（読まれたことが見える） |
| **リアクション** | 3種のチップ。押すと自分のアバターが小さく付く。**コメントより先に、押しやすい位置に置く** |
| **コメント欄** | 本文の直下。**折りたたまない。** 投稿ボタンは常時表示（コメントの摩擦を減らす） |
| **週次まとめの生成結果** | セクションごとに「生成された内容」+ **根拠の日報へのリンク（日付のチップ）**。生成できなかった項目は `--ink-400` で理由を明示 |
| **提出状況グリッド** | メンバー×日付。セルは ● 提出／◐ 遅延／○ 未提出／− 対象外。**色ではなく記号で区別**（A11Y-04） |
| **4指標カード** | ラベル（label）／数値（Mono・大）／前週比（符号 + pt）。**悪化した指標のみ `--issue` で符号を色付け** |
| **入力時間ヒストグラム** | 横軸=秒数帯、縦軸=件数。**個人名を出さない**（MEA-04）。前日コピーあり/なしの2系列 |
| **テンプレート管理** | 項目リスト（D&D並び替え）＋ **画面上部に「項目数 9／推定入力時間 3分20秒」を常時表示。** 項目を追加すると即座に更新される |
| 空状態 | 「まだ日報がありません」／「条件に一致する日報はありません」を出し分け |
| スケルトン | カード形状。**本文3行分の高さを確保**してレイアウトシフトを防ぐ |
| デモ切替バー | **濃い墨色の帯**。余白の広いアプリ本体と明確に区別する |

## インタラクション要件

| ID | 要件 |
|---|---|
| IX-01 | **入力の反応が 100ms以下であること。** 文字入力で1フレームでも落ちないこと |
| IX-02 | **下書き保存が入力を妨げないこと**（保存中に入力がブロックされない） |
| IX-03 | **提出は1タップ。確認ダイアログを出さない**（FR-112） |
| IX-04 | 選択式項目は**チップのタップで選択完了**（セレクトを開かせない） |
| IX-05 | テキストエリアは**内容に応じて自動で高さが伸びること**（スクロールバーを出さない） |
| IX-06 | `⌘Enter` / `Ctrl+Enter` で提出、`Esc` で下書き保存して閉じる |
| IX-07 | タイムラインは**キーボードで移動できること**（`↑↓` カード移動、`Enter` 詳細、`R` リアクション） |
| IX-08 | **既読は3秒以上表示で記録する。** スクロールで通過しただけで既読にしない（FR-405） |
| IX-09 | コメント投稿・リアクションは楽観的更新とし、失敗時のみロールバックすること |
| IX-10 | 検索は入力から**300msのデバウンス後に実行し、結果が100ms以下で返ること** |
| IX-11 | **編集・削除は5秒間「元に戻す」を表示すること** |

## モーション

| 対象 | duration | 内容 |
|---|---|---|
| **前日コピーの適用** | 400ms | **埋まった項目に若草の背景が一度だけ走る。** 何が埋まったか分かること |
| **提出完了** | 300ms | モーダルのフェード + 入力時間のカウントアップ |
| ホバー・フォーカス | 100ms | 色のみ |
| カードの既読化 | 240ms | 左端の点がフェードアウト |
| リアクション | 180ms | アバターが小さくポップして付く |
| コメント投稿 | 200ms | 下から差し込む |
| テキストエリアの伸長 | なし | **アニメーションさせない**（入力の邪魔になる） |
| トースト | 160ms | 下から |

`prefers-reduced-motion: reduce` 時は全アニメーションを無効化する。

## アクセシビリティ（WCAG 2.1 AA）

| ID | 要件 |
|---|---|
| A11Y-01 | コントラスト比は通常4.5:1以上。**本文は7:1を目標とする**（長文を読ませるため） |
| A11Y-02 | 全ての操作をキーボードのみで完遂できること |
| A11Y-03 | **テンプレート管理のD&Dにキーボード代替を用意すること**（FR-601） |
| A11Y-04 | **提出状況を色のみで伝えないこと。** 記号（●◐○−）とテキストを併記すること |
| A11Y-05 | **「課題あり」「未読」を色のみで伝えないこと。** アイコンとテキストを併記すること |
| A11Y-06 | フォーカスリングは2px・オフセット2pxで常時可視。`outline:none` の単独使用禁止 |
| A11Y-07 | フォームの各入力に `label` を関連付け、エラーは `aria-describedby` と `role="alert"` で読み上げること |
| A11Y-08 | **不足項目の案内を `aria-live="polite"` で通知すること**（FR-113） |
| A11Y-09 | 下書きの自動保存を `aria-live="polite"` で控えめに通知すること |
| A11Y-10 | 提出完了と入力時間を `aria-live="polite"` で読み上げること |
| A11Y-11 | モーダルはフォーカストラップ + Esc で閉じる + 起動元へフォーカス復帰 |
| A11Y-12 | **入力時間ヒストグラムを表としても読めるようにマークアップすること** |
| A11Y-13 | タップ領域は最小44×44px。**提出ボタンは56px** |
| A11Y-14 | フォントサイズ200%指定でも、入力フォームと日報の本文が読めること |

## ライティング規約

| 原則 | 例 |
|---|---|
| **書く負担を減らす言葉で** | ○「気づいたことがあれば。空のままでも提出できます」／×「気づき・学びを記入してください（必須）」 |
| **不足は押す前に伝える** | ○「あと2項目：進捗、実施内容」／× 提出後に「必須項目が未入力です」 |
| **入力時間を評価しない** | ○「入力時間 1分12秒」／×「速いですね！」「時間がかかっています」 |
| **読まれたことを伝える** | ○「山田さん、佐藤さん、他1名が読みました」／×「既読 3」 |
| **課題は目立たせるが煽らない** | ○「相談があります」／×「緊急」「至急対応」 |
| **リマインドは責めない** | ○「今日の日報がまだ提出されていません」／×「未提出です。速やかに提出してください」 |
| 空状態を区別する | データ0件：「まだ日報がありません。今日の分から始めましょう」／絞り込み0件：「条件に一致する日報はありません」+ 条件解除 |
| システム語を使わない | ○「この相談は解決しました」／×「statusをresolvedに更新」 |

---

# 9. 技術要件・ディレクトリ構成

## 技術スタック（固定・勝手に変更しない）

| レイヤ | 技術 | 備考 |
|---|---|---|
| フレームワーク | Next.js 15（App Router）／ TypeScript strict | |
| スタイリング | Tailwind CSS + CSS Variables | トークンは CSS 変数で定義 |
| UIコンポーネント | shadcn/ui（Radix UI基盤） | a11y要件を自前実装せずに満たす |
| 状態管理 | Zustand + persist | localStorage に永続化 |
| **入力時間の計測** | **自前実装**（`lib/metrics/input-timer.ts`） | ライブラリを入れない。数十行 |
| **全文検索** | **自前実装**（`lib/search/`） | **Fuse.js 等を入れない。** 転置インデックス + 日本語正規化は自前で書ける。**これが記事の技術パートの見せ場になる** |
| **週次まとめ生成** | **自前実装**（`lib/summary/`） | **AIを呼ばない**（SUM-01） |
| テキストエリア | 自前実装（自動高さ調整） | react-textarea-autosize を入れない（数行で書ける） |
| D&D | dnd-kit | テンプレート項目の並び替え。**キーボード対応必須** |
| グラフ | Recharts（動的import） | 運用ダッシュボードのみ |
| フォーム | React Hook Form + Zod | |
| 画像 | IndexedDB（idb）+ Canvas で圧縮 | browser-image-compression を入れない |
| CSV / Markdown | Papa Parse / 自前実装 | |
| 日付 | date-fns（ja locale） | タイムゾーンは Asia/Tokyo 固定 |
| PWA | next-pwa | オフライン作成（FR-118） |
| アイコン | lucide-react | |
| ホスティング | Vercel | |
| テスト | Vitest / Playwright / axe-core | |

**上記以外のライブラリを入れる前に必ず提案し、承認を得ること。特に全文検索ライブラリ、リッチテキストエディタ、AI SDK の導入は禁止。**

> **リッチテキストエディタを入れない理由：** 日報に装飾は不要であり、エディタを入れると**バンドルが数百KB増え、入力の反応が落ちる**。プレーンテキスト + 改行 + 箇条書き（`- ` 記法の表示側変換）で足りる。**IX-01（入力の反応100ms以下）を守るための判断。**

## ディレクトリ構成

```
/
├── CLAUDE.md
├── app/
│   ├── layout.tsx                  # 1カラムシェル（ヘッダー + タブナビ + デモ切替バー）
│   ├── page.tsx                    # SC-001 ホーム / SC-900（?embed=1）
│   ├── reports/                    # SC-010〜021
│   ├── weekly/                     # SC-030, 031
│   ├── notifications/              # SC-040
│   ├── team/                       # SC-100〜103
│   ├── search/  export/            # SC-110, 120
│   ├── admin/                      # SC-200〜240
│   └── dev/components/
├── components/
│   ├── editor/                     # ★ 最重要
│   │   ├── ReportForm.tsx          # 1カラムの入力フォーム
│   │   ├── FieldRenderer.tsx        # 項目種別ごとの描画
│   │   ├── ChipSelect.tsx          # 選択式（セレクトを使わない）
│   │   ├── AutoTextarea.tsx        # 自動高さ調整
│   │   ├── InputTimerBadge.tsx     # ★ 控えめなタイマー（MEA-03）
│   │   ├── CopyPreviousButton.tsx  # ★ 前日コピー
│   │   ├── MissingFieldsHint.tsx   # ★ 残り項目（FR-113）
│   │   ├── SubmitResultModal.tsx   # ★ 入力時間の結果
│   │   └── useDraftAutosave.ts
│   ├── report/                     # ReportCard, IssueBlock, ReadReceipts, ReactionBar, CommentList
│   ├── weekly/                     # SummaryDraft, SourceReportLinks
│   ├── ops/                        # MetricCard, SubmissionGrid, ResponseTable, InputTimeHistogram
│   ├── template/                   # FieldList, EstimateBadge（★ 項目数と推定時間）
│   ├── demo/                       # RoleSwitcher, ResetButton, GuideTour, BackToArticle
│   └── layout/
├── lib/
│   ├── types/ seed/ store/ repo/
│   ├── metrics/                    # ★ 計測。純粋関数 + タイマー
│   ├── summary/                    # ★ 週次まとめ生成。純粋関数
│   ├── search/                     # ★ 全文検索。純粋関数
│   ├── storage/ query/ validation/ utils/
├── docs/
│   └── daily-report-checklist.md   # 資料PDFの元原稿（日報の目的整理シート）
├── e2e/
└── public/
```

## コーディング規約

- TypeScript strict。`any` 禁止。やむを得ない場合は `unknown` + 型ガード
- ファイル名は kebab-case、コンポーネントは PascalCase
- 1ファイル300行を超えたら分割を検討する
- **コンポーネントから Zustand ストアを直接参照しない。必ず `lib/repo/` 経由**
- **入力時間の計測を `lib/metrics/input-timer.ts` に集約する。** コンポーネントで `setInterval` を持たない（MEA-02）
- **`lib/metrics/` `lib/summary/` `lib/search/` は純粋関数のみ。** ストア・DOM に依存させず、**`new Date()` を内部で呼ばない**
- **入力の反応速度を最優先する。** 入力中に重い処理（検索インデックス更新・集計）を走らせない。**下書き保存も入力をブロックしない**（IX-02）
- **個人別の入力時間を本人以外に返さない**（SCP-04）。**この判定をコンポーネントに書かない**
- 派生値（提出率・返信率・未読率・推定入力時間）をストアに保存しない
- **入力を増やす機能を提案しない。** 機能追加は「入力を減らす」か「読まれるようにする」に寄与すること（1章 事実③）
- コミットは1タスクごと。メッセージに要件IDを含める
  例：`feat(editor): 前日コピーで埋まった項目をハイライト (FR-106)`

---

# 10. 非機能要件

| ID | 要件 | 目標値 |
|---|---|---|
| NFR-01 | **文字入力の反応** | **1フレームも落とさない（100ms以下）** |
| NFR-02 | 下書きの自動保存 | 50ms以下、**入力をブロックしないこと** |
| NFR-03 | **提出から完了表示まで** | **200ms以下** |
| NFR-04 | **全文検索**（日報1,500件 + コメント620件） | **100ms以下** |
| NFR-05 | 検索インデックスの初期構築 | 300ms以下（初回のみ、非同期で構築し入力をブロックしない） |
| NFR-06 | 週次まとめの生成 | 300ms以下 |
| NFR-07 | 運用指標の算出（22名 × 3ヶ月） | 150ms以下 |
| NFR-08 | 一覧の絞り込み・並び替え | 100ms以下 |
| NFR-09 | タイムラインのスクロール | 60fps維持（仮想スクロール） |
| NFR-10 | LCP（モバイル4G相当） | 2.0秒以下 |
| NFR-11 | INP | 200ms以下 |
| NFR-12 | CLS | 0.1以下。**日報カードの本文3行分の高さを最初から確保すること** |
| NFR-13 | 埋め込みモードの初期JSバンドル（gzip後） | 60KB以下 |
| NFR-14 | アプリ本体の初期JSバンドル（gzip後） | **180KB以下**（グラフは動的import。**姉妹プロジェクトより厳しく設定する。入力の速さが命だから**） |
| NFR-15 | Lighthouse | Performance 95 / Accessibility 95 以上 |
| NFR-16 | 対応環境 | iOS Safari 16以降、Android Chrome 最新、PC Chrome / Edge / Safari / Firefox 最新2バージョン |
| NFR-17 | localStorage の容量上限に達した場合、警告を表示し、**古い月の日報を要約して圧縮すること**（データを破損させない） | — |

## セキュリティ・プライバシー

| ID | 要件 |
|---|---|
| SEC-01 | **入力された日報の本文・氏名・画像を一切外部に送信しないこと。** localStorage / IndexedDB にのみ保存すること |
| SEC-02 | この事実を、入力画面・デモ切替バーで明示すること |
| SEC-03 | **GA4 に日報の本文を送らないこと**（EMB-10）。送るのは秒数・項目数などのメタ情報のみ |
| SEC-04 | ユーザー入力（本文・コメント）をサニタイズすること。**`- ` の箇条書き変換以外のHTMLを許可しないこと** |
| SEC-05 | 「デモをリセット」ですべてのデータが消えることを明示し、実際に消えること |
| SEC-06 | **個人別の入力時間が、本人以外のロールで取得できないことをテストで保証すること**（SCP-04） |

## 運用設計上の注意（**この領域固有**）

**日報アプリは容易に監視ツールになる。** 実装の段階でそれを防ぐ。

| ID | 要件 |
|---|---|
| ETH-01 | **個人別の入力時間ランキングを実装しないこと**（MEA-04, FR-511） |
| ETH-02 | **入力時間の速い/遅いを色や評価文言で示さないこと** |
| ETH-03 | **提出率を個人の評価指標として提示しないこと。** 提出状況グリッドは「誰にリマインドするか」のための運用画面であり、評価画面ではない旨を画面上に明記すること |
| ETH-04 | **リマインドの文言を責める調子にしないこと**（ライティング規約） |
| ETH-05 | **「課題・相談」の公開範囲を書き手が選べること**（SCP-05）。書き手の心理的安全を仕様で守る |
| ETH-06 | 位置情報・スクリーンショット・操作ログによる**書き手の監視機能を実装しないこと** |

> **実案件への転用時の注意（デモ本体の要件ではない。商談で聞かれた際に説明できるよう記録）**
>
> **① 日報は「導入」より「運用設計」に工数がかかる。** 項目を決める会議、読む担当を決める運用、リマインドの設計。**開発費より運用設計の合意形成の方が時間を食う**
>
> **② 日報の内容は労務トラブルの証拠になりうる。** 長時間労働の記録、ハラスメントの記述などが残る。**保存期間とアクセス権限の設計が必要**
>
> **③ 人事評価に使うなら、その旨を事前に明示する必要がある。** 「報告のため」と言って集めた情報を評価に使うのは、運用として問題になりやすい
>
> **④ 監視色が強いと必ず形骸化する。** 「特になし」が並ぶ日報に価値はない。**書き手に利益がある設計（自分の記録が残る、相談が返ってくる）が持続の条件**
>
> **本デモはデータをサーバーに送信しないため、②③の義務は発生しない。**「デモである」旨は画面上に常時明示する

---

# 11. 費用設計

**記事の主題の半分は「費用」。この章は実装要件であると同時に、記事本文の原稿素材でもある。**

## 日報アプリだけの特殊事情：**そもそも作らなくていいかもしれない**

他のテーマと違い、日報には**「Excelでもチャットでもできる」**という現実がある。**この記事で最初に答えるべきは「いくらか」ではなく——**

> **「日報アプリを、そもそも作る必要があるのか」**

正直にそう問うことが、結果的に信頼を生む。

## まず、作らない選択肢を並べる

| 手段 | 向くケース | 限界 |
|---|---|---|
| **チャット（Slack / Teams / LINE WORKS）に投稿** | **10名以下。すぐ始めたい** | **流れて消える。** 検索性が低い、集計できない、未読管理がない |
| Googleフォーム + スプレッドシート | 20名程度。集計したい | **読み手の体験が悪い。** コメントできない、既読が分からない |
| Notion / Kibela 等のドキュメントツール | 蓄積を重視するチーム | **入力の手数が多い。** 集計が弱い |
| **既製の日報SaaS** | 30〜100名。標準的な運用 | 月額×人数。項目のカスタマイズに限界 |
| **自作** | 下記の①〜⑤に該当する場合 | 開発費 + 運用設計 + 保守 |

**「まずチャットで始めて、限界が来たら考える」が最も合理的なケースが多い。** 記事にはこれを明記する。

## 自作が正当化される5つのケース

| ケース | 内容 |
|---|---|
| **① 数値を集計して業務に使いたい** | 訪問件数・施工数・売上見込みを日報から集計し、そのまま管理指標にしたい |
| **② 既存システムと繋ぎたい** | 顧客管理・案件管理・勤怠と日報を一体化したい（**日報から二重入力をなくす**） |
| **③ 業種特有の項目・帳票が必要** | 建設の作業日報、介護の記録、点検記録など、**法令や取引先要求で形式が決まっている** |
| **④ 人数が多く、人数課金が重い** | 100名超で、月額×人数が積み上がっている |
| **⑤ 現場のITリテラシーに合わせた極端な簡略化が必要** | 「3タップで終わる」レベルまで削りたい。**既製サービスの画面では無理** |

**⑤は見落とされやすいが、現場系の業種で最も多い動機。** 既製サービスは汎用性のために項目が多く、**現場の人が使わない**。

**逆に、①〜⑤のどれにも当てはまらないなら、チャットか既製サービスを使うべき。**

## 損益分岐の計算式

```
既製サービスの年間コスト
  = 月額単価 × 人数 × 12
  ( + オプション：集計機能・API連携 )

回収年数 = （開発費 + 運用設計費）÷（既製サービス年間コスト − 自作の年間運用費 − 年間保守費）
```

| 規模 | 人数 | 判断 |
|---|---|---|
| 小 | 〜20名 | **チャットか無料ツールで十分。** 自作は回収できない |
| 中 | 30〜100名 | **①②③⑤に該当するなら検討価値あり** |
| 大 | 100名超 | **人数課金が効いてくる。** ただし運用設計の工数も増える |

## 最も見落とされる費用：**運用設計の工数**

**日報アプリの導入で最も工数を食うのは、実装ではなく「何を書かせるか」の合意形成。**

- 項目を決める会議（**関係者が増えるほど項目が増える**）
- 「誰が読むか」を決める（**ここが決まらないと項目が決まらない**）
- リマインドと督促の運用を決める
- **既存の日報（紙・Excel・メール）からの移行**

**そして導入後、必ず項目を増やしたくなる。** そのとき「項目を1つ増やすと入力時間が何秒増え、提出率が何%下がるか」を議論できないと、**日報は肥大化して死ぬ。**

**HIBI がテンプレート管理画面に「項目数と推定入力時間」を常時表示しているのは、この会議のためにある**（FR-602）。**資料PDFの「日報の目的整理シート」も、この工数を前倒しするために作る。**

## AI連携は「あとで足す」でよい

「AIで日報を要約したい」「AIが添削してほしい」は必ず出る要望。だが——

| | AI連携なし（本デモ） | AI連携あり |
|---|---|---|
| 週次まとめ | **ルールベースで生成できる**（SUM-01） | 自然な文章になる |
| 費用 | **ゼロ** | **1件ごとに課金。日報数 × 人数 × 日数 で積み上がる** |
| データの扱い | **外に出ない** | 日報の本文を外部APIに送る（**業務情報の流出リスクの検討が必要**） |
| 実装 | 数十行 | プロキシ（バックエンド）が必要 |

```
AI要約の月額 = 1件あたりの単価 × 人数 × 月間営業日数
例：50名 × 20日 = 1,000件/月
```

**まずルールベースで作り、必要になったらAIを足す。** この順序が費用とリスクの両面で合理的。**そしてルールベースでも「根拠の日報にリンクが張られる」という、AIにはない透明性がある**（SUM-03）。

## Webで足りるか、ネイティブが必要か

**日報は、Webで足りる領域。**

| やりたいこと | Web（PWA） | ネイティブ |
|---|---|---|
| 日報の作成・提出 | **できる** | できる |
| オフラインでの作成 | **できる**（PWA） | できる |
| 写真の添付 | **できる** | できる |
| **提出リマインドのプッシュ通知** | 限定的 | **できる** |
| 音声入力 | **できる**（OS標準のキーボード） | できる |

**判断の目安：** リマインドのプッシュ通知を重視するなら、**LINE公式アカウントやチャットツールへの通知**が現実的な代替（アプリ開発より圧倒的に安い）。**日報アプリのためにネイティブアプリを作る必要はほぼない。**

## デモ自体の運用コストを実測して記事に載せる

| ID | 要件 |
|---|---|
| COST-01 | デモ公開後、月次で「デモ起動数・提出数・ホスティング費用」を記録すること |
| COST-02 | **`input_seconds` の分布を集計し、記事に掲載すること。**「読者の中央値は何秒だったか」は、主張を裏付ける最強のデータになる（EMB-09） |
| COST-03 | **`copy_yesterday_used` の利用率と、利用時/非利用時の入力時間差を記録すること** |
| COST-04 | 記録した実測値を記事に掲載し、**確認日を明記すること** |
| COST-05 | **既製日報サービス・AI APIの価格は変動するため、この文書に金額を書き込まない。** 記事執筆時点で公式ページを確認し、確認日を明記すること |

**「このデモを触った読者の入力時間の中央値は 1分34秒でした」**——この一文が、どんな機能説明よりも強い。

---

# 12. 実装タスク

**この順に進める。フェーズを飛ばさない。** 完了時は `[x]` に更新する。

## Phase 0 — 基盤と計測エンジン（4日）

### 0-1. 初期化
- [ ] Next.js 15 / TypeScript strict / App Router / Tailwind で初期化
- [ ] ESLint / Prettier / husky（pre-commit で lint + typecheck）
- [ ] 9章のディレクトリ構成を作成

### 0-2. `lib/metrics/`（**このプロジェクトの心臓部**）
- [ ] **`input-timer.ts`：入力時間の計測**（7章のコード参照）(MEA-01, MEA-02)
- [ ] **`estimate.ts`：テンプレートの推定入力時間**（FR-603）
- [ ] `submission.ts`：提出率（対象曜日・在籍期間を考慮）(FR-502)
- [ ] `response.ts`：返信率・平均返信時間（FR-503, FR-508）
- [ ] `unread.ts`：未読率（FR-504）
- [ ] `distribution.ts`：入力時間の分布、**前日コピーあり/なしの比較**（FR-510, FR-512）
- [ ] `patterns.ts`：提出が落ちる曜日・時刻の検出（FR-507）
- [ ] **`new Date()` を内部で呼ばない。現在時刻は引数で受け取る**
- [ ] **単体テストを網羅的に書く。以下を必ず含めること：**
  - [ ] **タブ非表示中の時間が入力時間に加算されないこと**（最重要）
  - [ ] **30秒以上の無操作が加算されないこと**
  - [ ] **複数セッションに分けた場合、累積されること**（MEA-05）
  - [ ] **推定入力時間が、項目の追加・削除で正しく変わること**
  - [ ] **任意項目が推定入力時間に加算されないこと**
  - [ ] 提出率が対象曜日と在籍期間を正しく考慮すること
  - [ ] 返信率がコメントとリアクションの両方を数えること
  - [ ] **前日コピーあり/なしの入力時間差が正しく算出されること**

### 0-3. `lib/search/`（**自前実装。記事の技術パートの見せ場**）
- [ ] `normalize.ts`：ひらがな／カタカナ／半角全角の正規化
- [ ] `index.ts`：転置インデックスの構築（**非同期・入力をブロックしない**）
- [ ] `query.ts`：検索とスコアリング
- [ ] `highlight.ts`：ヒット箇所のハイライト
- [ ] **単体テストを書く。表記ゆれが吸収されること**
- [ ] **日報1,500件 + コメント620件で検索が 100ms以下**をベンチマークで確認（NFR-04）

### 0-4. `lib/summary/`（週次まとめ生成。純粋関数）
- [ ] `group.ts`：実施内容のグループ化（タグ・案件で束ねる）
- [ ] `totals.ts`：数値項目の合算
- [ ] **`generate.ts`：週次まとめの生成**（SUM-01〜05, FR-303）
- [ ] **未解決の課題だけを抽出すること／未提出日を明示すること／生成できなかった項目を明示すること**
- [ ] **根拠の日報IDを必ず含めること**（SUM-03）
- [ ] **単体テストを書く。日報が0件の週でも壊れないこと**

### 0-5. 型とシード
- [ ] `lib/types/` に7章の型定義をすべて実装
- [ ] `lib/seed/` の全ファイル
- [ ] **日報の本文を、業種の世界観を持つ実在しそうな文章にする。ダミー文を1件も残さない**（最重要）
- [ ] **入力時間の実データを持たせる。前日コピー利用時は明確に短く**
- [ ] **課題・相談を1割程度、うち数件を「上司のみ」に設定**
- [ ] **未対応3日以上の課題、返信の薄い上司、未読の溜まり、金曜の未提出集中を作る**
- [ ] **「気づき」が空の日報を多く作る**（任意項目の実態を再現）
- [ ] **テンプレートのバージョンを2つ持つものを1つ作る**（FR-607 の実演用）
- [ ] 日報は提出対象曜日にのみ存在すること（土日に並べない）
- [ ] 日付は現在日時からの相対で生成する

### 0-6. ストアとリポジトリ
- [ ] `lib/store/{session,data,settings,draft,sync,ui}.ts` を Zustand + persist で実装
- [ ] **`lib/repo/_scope.ts` を最初に実装する**（7章のコード参照）(SCP-01〜05)
- [ ] `lib/repo/` の全モジュール。全メソッド async、Result型、スコープ適用
- [ ] **スコープの単体テストをこの時点で書く：**
  - [ ] **メンバーが他チームの日報を取得できないこと**（SCP-03）
  - [ ] **個人別の入力時間が本人以外に返らないこと**（SCP-04, SEC-06）
  - [ ] **「上司のみ」の課題ブロックが、対象外のメンバーに返らないこと**（SCP-05）
- [ ] **入力・下書き保存・提出・検索に擬似ディレイを入れない**（FR-119）

### 0-7. デザインシステム
- [ ] `app/globals.css` にカラートークンを CSS 変数で定義（**色を使うのは「課題あり」と「未読」の2つだけ**）
- [ ] `tailwind.config.ts` から CSS 変数を参照するよう theme を拡張
- [ ] フォント（Noto Sans JP / Roboto Mono）を `next/font` で最適化
- [ ] **本文 15px・行間1.9・最大幅680px のタイポグラフィを定義**（8章）
- [ ] **1カラムのアプリシェル**（ヘッダー + タブナビ。**サイドバーを持たない**）
- [ ] shadcn/ui を導入し、トークンに合わせて上書き
- [ ] 共通コンポーネント：`AutoTextarea`（自動高さ、**アニメーションなし**）／`ChipSelect`（セレクトを使わない）／`EmptyState`（2種の出し分け）／`Skeleton`（**本文3行分の高さを確保**）
- [ ] `prefers-reduced-motion` の対応
- [ ] **`/dev/components` にコンポーネントカタログを作成**

### 0-8. デモ基盤
- [ ] `RoleSwitcher`（3ロール + メンバーの3ペルソナ選択）(FR-701)
- [ ] デモ切替バー（**濃い墨色の帯**）+ 「これはデモです。書いた内容は送信されません」（SEC-02）
- [ ] 「デモをリセット」(FR-706)／ロール権限外アクセス時の案内画面（FR-709）
- [ ] 元記事リンク・資料ダウンロード（FR-711）

### Phase 0 完了チェック
- [ ] **`lib/metrics/` のテストが全パターン通る**
- [ ] **「タブを離れた時間・30秒無操作が入力時間に入らない」がテストで検証済み**
- [ ] **「個人別の入力時間が本人以外に返らない」がテストで検証済み**
- [ ] **「上司のみの課題が対象外メンバーに返らない」がテストで検証済み**
- [ ] 検索が100ms以下
- [ ] `/dev/components` で本文の組版（15px・行間1.9・680px）が正しく表示される

---

## Phase 1 — 入力体験（4日・**最重要フェーズ**）

### 1-1. 入力フォーム
- [ ] `ReportForm.tsx`：**1カラム、項目間32px、枠で囲まない**（8章）
- [ ] `FieldRenderer.tsx`：8種の項目種別に対応（FR-207）
- [ ] **`ChipSelect.tsx`：選択式をチップのタップで完了**（セレクトを開かせない）(IX-04)
- [ ] `AutoTextarea.tsx`：自動高さ調整。**伸長をアニメーションさせない**（IX-05）
- [ ] 数値項目は `inputMode="numeric"`（FR-114）
- [ ] **3ブロック（報告／課題・相談／気づき）の構造**（FR-201）
- [ ] **「気づき」に「空のままでも提出できます」を明示**（FR-203）
- [ ] **課題ブロックに公開範囲のセレクトを併置**（FR-204）
- [ ] **ブラウザの音声入力を妨げないこと**（独自キーハンドラを被せない）(FR-116)

### 1-2. 入力時間の計測と表示
- [ ] `InputTimerBadge.tsx`：**画面右上に控えめに表示。大きくしない、色を付けない**（MEA-03, FR-103）
- [ ] `useDraftAutosave.ts`：**入力停止から2秒後に保存。入力をブロックしない**（FR-108, IX-02）
- [ ] 保存状態の表示、`aria-live` での控えめな通知（A11Y-09）
- [ ] **アプリを閉じて再訪しても下書きが復元されること**（FR-109）
- [ ] **入力時間の累積**（複数セッション）(FR-105)

### 1-3. 前日コピーと残り項目
- [ ] **`CopyPreviousButton.tsx`：前回内容の引き継ぎ**（FR-106）
- [ ] **埋まった項目に若草の背景が一度だけ走るアニメーション**（400ms）
- [ ] **`MissingFieldsHint.tsx`：提出ボタン直上に「あと N項目：〜」**（FR-107, FR-113）
- [ ] `aria-live="polite"` での通知（A11Y-08）
- [ ] `ChipSelect` へのサジェスト（過去の入力から候補）(FR-111)

### 1-4. 提出
- [ ] **提出はワンタップ。確認ダイアログなし**（FR-112, IX-03）
- [ ] `⌘Enter` で提出、`Esc` で下書き保存して閉じる（IX-06）
- [ ] **`SubmitResultModal.tsx`：入力時間（30px Mono）+ 平均との比較**（FR-104）
- [ ] **短縮できた場合は伝え、遅い場合は何も言わない**（ライティング規約）
- [ ] 提出後30分の編集可能（FR-117）／編集履歴（FR-117）
- [ ] SC-013 下書き一覧／SC-001 ホーム
- [ ] 画像添付（Canvas で圧縮、IndexedDB）(FR-115)

### 1-5. 埋め込みモード
- [ ] **SC-900 埋め込みモード：入力フォーム + タイマー + 前日コピー**（FR-713, 2章）
- [ ] **実際に入力でき、入力時間が計測され、提出後に秒数が表示されること**（EMB-04）
- [ ] **前日コピーで「あと2項目」が出ること**（EMB-05）
- [ ] 提出はできるが**アプリ内遷移をしない**。「全画面で続きを見る」を `target="_blank"`（EMB-06）
- [ ] カメラ・位置情報を呼ばない（EMB-07）
- [ ] 初期バンドル 60KB以下を実測（NFR-13）

### Phase 1 完了チェック
- [ ] **フローAが完走する**（埋め込みで書く → 前日コピー → 提出 → 入力時間が出る）
- [ ] **文字入力が1フレームも落ちない**（NFR-01）
- [ ] **下書き保存が入力をブロックしない**（IX-02）
- [ ] **前日コピーで入力時間が明確に短くなる**
- [ ] タブを離れて戻っても入力時間が正しい

---

## Phase 2 — 読む・返す（4日）

### 2-1. タイムライン
- [ ] SC-100 チームのタイムライン：**日付順カード、1カラム760px**（FR-401）
- [ ] `ReportCard.tsx`：**未読は左端に若草の点／課題ありは細い帯 + バッジ**（FR-403, A11Y-05）
- [ ] フィルタ（メンバー／案件／課題あり／未読のみ／期間）(FR-402)
- [ ] 仮想スクロール、60fps（NFR-09）
- [ ] **キーボード操作**（`↑↓` `Enter` `R`）(IX-07)

### 2-2. 詳細と反応
- [ ] SC-101 / SC-021 日報の詳細（**本文680px、行間1.9**）
- [ ] `IssueBlock.tsx`：**課題ブロックの強調 + 対応状態のセレクト + 「上司のみ」の鍵表示**（FR-206）
- [ ] **`ReadReceipts.tsx`：既読者のアバターを重ねて表示。書き手側にも出す**（FR-404）
- [ ] **既読は3秒以上表示で記録**（FR-405, IX-08）
- [ ] **`ReactionBar.tsx`：3種のチップ。コメントより先に、押しやすい位置**（FR-408）
- [ ] `CommentList.tsx`：**折りたたまない。投稿ボタンは常時表示**（FR-406）
- [ ] メンション（FR-407）／楽観的更新（IX-09）
- [ ] SC-040 通知センター（**通知はプレビュー表示**）

### 2-3. 課題と検索
- [ ] SC-102 課題の一覧：**対応状態と経過日数**（FR-409）
- [ ] **未対応3日以上の強調**（FR-410）
- [ ] SC-103 メンバーのタイムライン（FR-411）
- [ ] SC-110 検索：**ハイライト表示、300msデバウンス、100ms以下**（FR-412〜414, IX-10）
- [ ] 絞り込みのURLクエリ反映（FR-413）
- [ ] SC-120 エクスポート（CSV／Markdown）(FR-415)

### Phase 2 完了チェック
- [ ] **フローBが完走する**（課題を書く → 上司が読む → コメント → 書き手に既読とコメントが見える）
- [ ] **4章「ロールを跨ぐ体験」の1・2・7が動作する**
- [ ] **「上司のみ」の課題が、対象外メンバーの画面に表示されない**
- [ ] 検索が100ms以下でハイライト付きで返る

---

## Phase 3 — 週次まとめ（2日）

- [ ] SC-030 週次まとめの生成画面
- [ ] **生成された下書きをセクションごとに表示**（実施内容／数値合計／未解決の課題／気づき／未提出日）
- [ ] **`SourceReportLinks.tsx`：根拠の日報へのリンク（日付チップ）**（SUM-03, FR-305）
- [ ] **生成できなかった項目を `--ink-400` で明示**（SUM-04, FR-306）
- [ ] 本人の追記欄（振り返り／来週の予定）
- [ ] **必ず下書き。自動提出しない**（SUM-02, FR-304）
- [ ] SC-031 週次まとめ一覧
- [ ] 週次まとめへの既読・コメント（FR-309）
- [ ] 週の起算曜日の設定（FR-308）

### Phase 3 完了チェック
- [ ] **4章「ロールを跨ぐ体験」の6が動作する**
- [ ] 日報が0件の週でも生成が壊れない
- [ ] **根拠の日報にリンクが張られている**

---

## Phase 4 — 運用の計測とテンプレート管理（4日）

### 4-1. 運用ダッシュボード
- [ ] SC-200 **4指標カード（提出率・返信率・平均入力時間・未読率）+ 前週比**（FR-501）
- [ ] **悪化した指標のみ符号を色付け**（8章）
- [ ] SC-201 **提出状況グリッド：メンバー×日付、記号で区別**（FR-505, A11Y-04）
- [ ] **リマインド送信（プレビュー表示）**（FR-506）
- [ ] **提出が落ちる曜日・時刻の検出と提示**（FR-507）
- [ ] **「これは評価画面ではなく運用画面です」の旨を明記**（ETH-03）
- [ ] SC-202 **返信率：上司別、平均返信時間、返信されていない日報の抽出**（FR-508, FR-509）
- [ ] SC-203 **入力時間の分布：チーム平均、ヒストグラム、テンプレート別、前日コピー比較**（FR-510, FR-512）
- [ ] **個人別ランキングを作らない。表としても読めるようにする**（FR-511, A11Y-12）
- [ ] SC-230 数値集計レポート（FR-513）

### 4-2. テンプレートと設定
- [ ] SC-210 テンプレート管理：項目の追加・削除・**D&D並び替え + キーボード操作**（FR-601, A11Y-03）
- [ ] **`EstimateBadge.tsx`：画面上部に「項目数 N／推定入力時間 M分S秒」を常時表示**（FR-602）
- [ ] **項目を追加・削除すると即座に更新されること**（FR-604）
- [ ] SC-211 書き手視点のプレビュー（FR-605）
- [ ] チーム別のテンプレート割当（FR-606）
- [ ] **テンプレート変更後も、過去の日報が当時の構造で表示されること**（FR-607）
- [ ] SC-220 提出ルール：期限・対象曜日・**曜日別リマインド時刻**・編集可能時間（FR-608, FR-609）
- [ ] SC-221 チーム・メンバー管理（FR-610）
- [ ] SC-222 案件・作業種別マスタ（**使用件数と未使用の検出**）(FR-611)
- [ ] SC-223 通知文面の設定（FR-612）
- [ ] SC-240 操作ログ（FR-613）

### Phase 4 完了チェック
- [ ] **フローCが完走する**（返信率の悪化に気づく → 未提出の曜日集中を発見 → リマインド時刻とテンプレートを調整）
- [ ] **4章「ロールを跨ぐ体験」の4と5が動作する**
- [ ] **テンプレートに項目を追加すると推定入力時間が伸びる**
- [ ] **個人別の入力時間ランキングがどこにも存在しない**

---

## Phase 5 — オフライン・記事統合・仕上げ（3日）

### 5-1. オフライン
- [ ] Service Worker / PWA マニフェスト／オフライン検知とバナー
- [ ] **オフラインでの作成・下書き保存・提出と未同期バッジ**（FR-118）
- [ ] オンライン復帰時の自動同期
- [ ] localStorage 上限時の圧縮処理（NFR-17）

### 5-2. 記事統合
- [ ] 記事側の埋め込みコードを作成し、**実際の記事ページで動作確認**（EMB-01〜07）
- [ ] **埋め込みで「実際に書けて、秒数が出る」ことを複数ブラウザで確認**
- [ ] 記事の Core Web Vitals を埋め込み前後で比較検証
- [ ] 「全画面で試す」カードの設置
- [ ] 資料PDF（**日報の目的整理シート**・損益分岐計算シート）の作成とダウンロード導線
- [ ] 元記事リンク・問い合わせ導線
- [ ] GA4 イベント設定。**`input_seconds` と `copy_yesterday_used` を必ず含める**（EMB-08, EMB-09）
- [ ] **GA4 に日報の本文を送っていないことを確認**（EMB-10, SEC-03）
- [ ] `?embed=1` を `noindex` に、デモ本体の title / description / OGP（EMB-11）

### 5-3. 体験の総点検
- [ ] 4章「ロールを跨ぐ体験」の7パターンをすべて手動で確認
- [ ] 全28画面を開き、**空の画面が1つもないこと**を確認
- [ ] **日報の本文にダミー文が1件も残っていないことを確認**
- [ ] 空状態（データ0件／絞り込み0件）の出し分けを確認
- [ ] **ETH-01〜06 の倫理要件をすべて確認**（個人別ランキングがない、評価に使えない、監視機能がない）
- [ ] ガイドツアーを実装（FR-712）

### 5-4. アクセシビリティ監査
- [ ] axe-core を全画面に実行し、Critical / Serious を0件に
- [ ] **本文のコントラスト比が7:1以上であることを実測**（A11Y-01）
- [ ] **「課題あり」「未読」「提出状況」が色のみで伝えられていないことを確認**（A11Y-04, A11Y-05）
- [ ] キーボードのみで全画面・入力・タイムライン・テンプレート管理を完遂
- [ ] スクリーンリーダーで不足項目の案内と提出完了が読み上げられることを確認
- [ ] フォントサイズ200%での確認（A11Y-14）

### 5-5. パフォーマンス
- [ ] グラフを動的import に切り出し、**初期バンドルを180KB以下に**（NFR-14）
- [ ] **文字入力で1フレームも落ちないことを実測**（NFR-01）
- [ ] **提出200ms以下、検索100ms以下、週次まとめ生成300ms以下を実測**（NFR-03, NFR-04, NFR-06）
- [ ] タイムラインのスクロール60fpsを実測（NFR-09）
- [ ] Lighthouse で Performance 95 / Accessibility 95（NFR-15）

### 5-6. 公開と記録
- [ ] Playwright で フローA・B・C の E2E
- [ ] Vitest：`lib/metrics` `lib/summary` `lib/search` `_scope` のカバレッジ85%以上
- [ ] `/dev/components` を本番で非公開に
- [ ] Vercel へデプロイ
- [ ] **`input_seconds` の分布と `copy_yesterday_used` の利用率の記録を開始**（COST-01〜03）
- [ ] 解説動画（3分）の収録：**前日コピーで書く → 入力時間1分12秒 → 上司が読んでコメント → 既読が見える → テンプレートに項目追加で推定時間が伸びる → 返信率ダッシュボード**
- [ ] 各フェーズのキャプチャを整理し、記事の「方法」パートの素材にまとめる

---

**合計 21営業日（約4週間）**／1名専任 + レビュー体制。

> **工数配分の意図：** Phase 1（入力体験）に4日を割いているのは、**このアプリの価値が入力の速さに集約されている**から。前日コピー、チップ選択、下書き自動保存、残り項目の提示、入力時間の計測——**どれ1つ欠けても「書くのが面倒」に戻る。**
> Phase 4（運用の計測）に4日を割いているのは、**「日報アプリは作って終わりではない」という記事の主張を、機能として証明する部分**だから。提出率・返信率・推定入力時間が測れることが、他の日報アプリとの差になる。

---

# 13. 受入基準

1. 6章の優先度 P1 の要件がすべて実装され、テストで合格していること
2. 5章の主要フローA・B・Cが、エンドツーエンドで完走すること
3. 4章「ロールを跨ぐ体験」の7パターンがすべて動作すること
4. **文字入力で1フレームも落ちず、下書き保存が入力をブロックしないこと**
5. **入力時間が計測され、タブ非表示中と30秒以上の無操作が加算されていないこと**
6. **複数回に分けて書いた場合、入力時間が累積されること**
7. **「前日をコピー」で大半の項目が埋まり、「あと N項目」が明示されること**
8. **提出後に入力時間が表示され、平均との比較が出ること。遅い場合に評価的な文言が出ないこと**
9. **提出がワンタップで、確認ダイアログが出ないこと。不足項目が押す前に提示されること**
10. **日報が「報告／課題・相談／気づき」の3ブロックで構造化されていること**
11. **「気づき」が空でも提出でき、催促の文言が出ないこと**
12. **「課題・相談」の公開範囲を書き手が選べ、「上司のみ」の場合に対象外メンバーへ返らないこと**（リポジトリの段階で除外）
13. **既読が3秒以上の表示で記録され、書き手側にも既読者が表示されること**
14. **課題ありの日報が視覚的に前に出て、未対応3日以上が強調されること**
15. **週次まとめが日報から自動生成され、根拠の日報にリンクが張られ、必ず下書きであること**
16. **生成できなかった項目が明示されること**
17. **全文検索が100ms以下で、ヒット箇所がハイライトされること**（自前実装であること）
18. **運用ダッシュボードに提出率・返信率・平均入力時間・未読率の4指標と前週比が出ること**
19. **テンプレート管理に「項目数と推定入力時間」が常時表示され、項目の追加・削除で即座に更新されること**
20. **個人別の入力時間ランキングが、どの画面にも存在しないこと。個人別の入力時間が本人以外に返らないこと**
21. **提出状況グリッドに「評価画面ではない」旨が明記されていること**
22. **メンバーが他チームの日報を一切取得できないこと**
23. **テンプレート変更後も、過去の日報が当時の構造で表示されること**
24. 初期バンドルが180KB以下、Lighthouse Performance 95以上であること
25. **日報の本文にダミー文（「本日の業務を行いました」等）が1件も存在しないこと**
26. **日報の本文・氏名・画像が外部に一切送信されていないこと**（DevTools と GA4 のイベントで確認）
27. 全28画面のいずれにも空の状態がなく、リアルなデータが表示されていること
28. **本文のコントラスト比が7:1以上であること**
29. **「課題あり」「未読」「提出状況」が色のみで伝えられていないこと**
30. axe-core で Critical / Serious の指摘が0件であること
31. データアクセスがすべて `lib/repo/` を経由し、**入力時間の計測が `lib/metrics/input-timer.ts` に集約されていること**
32. **RELATE / KURA / TOKIWA と並べたときに、明確に別のプロダクトとして見えること**（1カラム・広い余白・15px本文が効いていること）

---

# 判断に迷ったときのルール

1. **仕様がこの文書にない場合は、実装せずに質問する。** 推測で作らない
2. **入力を増やす機能を提案しない。** 機能追加は「入力を減らす」か「読まれるようにする」に寄与すること。**これがこのプロジェクトで最も重要なルール**
3. **入力の反応速度を最優先する。** 入力中に重い処理を走らせない。下書き保存も入力をブロックしない
4. **入力時間で人を評価させない。** 個人別ランキングを作らない。本人以外に個人別の値を返さない（ETH-01, SCP-04）
5. **提出率を評価指標として提示しない。** 運用画面であることを明記する（ETH-03）
6. **リマインドで責めない。** 文言を厳しくしない（ETH-04）
7. **書き手の心理的安全を仕様で守る。**「課題・相談」の公開範囲を書き手が選べること（ETH-05）
8. **監視機能を実装しない。** 位置情報・スクリーンショット・操作の記録による書き手の監視はしない（ETH-06）
9. **週次まとめはルールベースで、必ず下書き。** AIを呼ばない、自動提出しない
10. **リッチテキストエディタを入れない。** バンドルと入力速度を守る
11. **全文検索を自前で書く。** ライブラリを入れない。これが記事の技術パートの見せ場
12. **日報の本文にダミー文を残さない。** このデモは本文の質がそのまま説得力になる
13. スコープ外（3章 Won't have）は実装しない。**特に承認ワークフロー・工数管理・AI添削は入力増につながる**
14. 「デモだから」を理由に品質を落とす判断はしない
15. **RELATE / KURA / TOKIWA のトークン・コンポーネントをコピーしない。** HIBI だけが1カラム・広い余白・15px本文
