SOUZOHSPECS

業務システム ・ HIBI

日報・週報

書く時間を、90秒に。前回をコピーして変わった分だけ直す日報

v1.0・作成 2026-08-24

  1. 要件定義書を保存する

    パソコンに hibi-app のようなフォルダを作り、その中に保存します。

    要件定義書.md として保存

  2. ChatGPT で画面イメージを作る デザインにこだわりたい人

    ChatGPT に要件定義書を添付して、下の文を送ります。雰囲気のところは、好きな言葉に書きかえてください。

    ChatGPT に送る
    添付の要件定義書は、これから作るアプリ「日報・週報」のものです。
    このアプリのいちばん大事な画面を、デザイン画像にしてください。
    実際のアプリのように、文字やボタンまで入れてください。
    雰囲気:(例:やさしい/高級感/ポップ/シンプル など、好きな言葉で)

    気に入るまで「もっと明るく」「ボタンを大きく」のように直してもらい、できた画像を保存します。ほかの画面も欲しければ、同じように作ってもらえます。

  3. Claude Code に渡して「作って」と頼む

    Claude のデスクトップアプリで「Code」タブを開き、「Select folder」から hibi-app を選びます。画面イメージがある人は、入力欄に画像をドラッグして貼りつけてから、下の文を送ります。詳しく

    Claude Code に送る(画像あり)
    @要件定義書.md をもとに、このアプリを作ってください。
    デザインは添付の画像に合わせてください。
    Claude Code に送る(画像なし)
    @要件定義書.md をもとに、このアプリを作ってください。

    作り終わるまで、しばらくかかります。途中で「許可しますか」と聞かれたら、内容を見て許可してください。

  4. 動かして確かめる・直す

    できたら、実際に画面を開いて触ります。直してほしいところは、スクリーンショットを貼りつけて、言葉で伝えれば大丈夫です。

    Claude Code に送る
    アプリを起動して、ブラウザで開けるようにしてください。
    Claude Code に送る
    (画面名)で(操作)をすると(今の動き)になります。
    (こうなってほしい動き)にしてください。
    Claude Code に送る
    このエラーを直してください。
    
    (ここにエラーの文をそのまま貼る)
  5. 途中で止まったら 必要なときだけ

    要件定義書が長いので、一度で作りきれないことがあります。そのときは新しい会話で、こう送ります。

    Claude Code に送る
    @要件定義書.md の続きを作ってください。
    まず、どこまでできているかを確かめてから進めてください。

    それでも進まないときは、30分無料相談でお手伝いします。公式LINEからのご相談もどうぞ。

    1段階ずつ頼みたいとき(全6段階)

    要件定義書には、作る順番が Phase 0〜5 で書かれています。止まりやすいときは、1つずつ頼むと確実です。

    Phase 0基盤と計測エンジン
    Claude Code に送る
    @要件定義書.md の「実装タスク」にある Phase 0 を作ってください。
    Phase 1入力体験
    Claude Code に送る
    @要件定義書.md の「実装タスク」にある Phase 1 を作ってください。
    Phase 2読む・返す
    Claude Code に送る
    @要件定義書.md の「実装タスク」にある Phase 2 を作ってください。
    Phase 3週次まとめ
    Claude Code に送る
    @要件定義書.md の「実装タスク」にある Phase 3 を作ってください。
    Phase 4運用の計測とテンプレート管理
    Claude Code に送る
    @要件定義書.md の「実装タスク」にある Phase 4 を作ってください。
    Phase 5オフライン・記事統合・仕上げ
    Claude Code に送る
    @要件定義書.md の「実装タスク」にある Phase 5 を作ってください。
  6. 自分用に変える・公開する 必要な人だけ

    Claude Code に送る
    この要件定義書は、記事に埋め込むデモ用に書かれています。
    自分の会社で実際に使えるように変えたいです。外したほうがいいところと、残したほうがいいところを教えてください。
    Claude Code に送る
    このアプリをインターネットに公開したいです。
    無料でできる方法を、1手順ずつ案内してください。

準備や、うまくいかないときの対処は 作り方ガイド にまとめています。分からないときは 30分無料相談 へどうぞ。

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. プロジェクト概要
  2. アーキテクチャ方針
  3. スコープ定義
  4. ロールとデモ切替
  5. 画面一覧とユーザーフロー
  6. 機能要件
  7. データ設計
  8. デザイン要件
  9. 技術要件・ディレクトリ構成
  10. 非機能要件
  11. 費用設計
  12. 実装タスク
  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/

// ---- 組織・メンバー ----
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章の中核

// 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),
  }
}
// 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)
// 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=墨+若草(低彩度の緑)

カラートークン

: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 400line-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-describedbyrole="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.tsx1カラム、項目間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_secondscopy_yesterday_used を必ず含める(EMB-08, EMB-09)
  • GA4 に日報の本文を送っていないことを確認(EMB-10, SEC-03)
  • ?embed=1noindex に、デモ本体の 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本文

FREE CONSULTATION

分からないときは、お気軽に30分無料相談へ

途中で止まった、エラーが消えない、自社向けに作り変えたい。どんなことでも大丈夫です。

日程を決めて話す

代表の西澤と直接お話しできます。空いている日時を選ぶだけで予約できます。

代表 西澤と話す日程を選ぶ

まずは問い合わせる

要件定義書がほしい方・ご相談は公式LINEから。メールでのお問い合わせはフォームから。