作業時間追跡 仕様書
タイマー・手動ログ・工数サマリー
ステータス: Draft / 作成日: 2026-05-27 PR #2 — 依存: コア
1. データモデル
1.1 time_logs
pub struct Model {
pub id: Uuid,
pub task_id: Uuid,
pub user_id: Uuid,
pub logged_minutes: i32, // 分単位で保持(表示時に h/m 変換)
pub logged_at: NaiveDate, // 作業日
pub note: Option<String>,
pub created_at: DateTimeUtc,
}
1.2 task_timers(アクティブタイマー)
タイマー Stop 時に
(now() - started_at)をlogged_minutesとしてtime_logsに INSERT し、task_timersレコードを削除する。
2. マイグレーション
CREATE TABLE time_logs (
id UUID PRIMARY KEY,
task_id UUID NOT NULL REFERENCES tasks(id) ON DELETE CASCADE,
user_id UUID NOT NULL REFERENCES users(id) ON DELETE CASCADE,
logged_minutes INT NOT NULL CHECK (logged_minutes > 0),
logged_at DATE NOT NULL,
note TEXT,
created_at TIMESTAMPTZ NOT NULL DEFAULT now()
);
CREATE TABLE task_timers (
task_id UUID NOT NULL REFERENCES tasks(id) ON DELETE CASCADE,
user_id UUID NOT NULL REFERENCES users(id) ON DELETE CASCADE,
started_at TIMESTAMPTZ NOT NULL DEFAULT now(),
PRIMARY KEY (task_id, user_id)
);
CREATE INDEX idx_time_logs_task ON time_logs(task_id);
CREATE INDEX idx_time_logs_user_date ON time_logs(user_id, logged_at);
3. API
POST /tasks/{id}/time-logs
{
"logged_minutes": 90,
"logged_at": "2026-05-27",
"note": "設計レビュー対応"
}
POST /tasks/{id}/timer/stop レスポンス
{
"id": "uuid",
"logged_minutes": 47,
"logged_at": "2026-05-27",
"note": null
}
GET /tasks/{id}/time-logs/summary
{
"estimated_minutes": 180,
"actual_minutes": 90,
"remaining_minutes": 90,
"is_over": false,
"by_user": [
{ "user_id": "uuid", "name": "田中", "minutes": 60 },
{ "user_id": "uuid", "name": "鈴木", "minutes": 30 }
]
}
GET /tasks/{id}/timer/status
{
"is_running": true,
"started_at": "2026-05-27T10:30:00Z",
"elapsed_minutes": 25
}
4. フロントエンド(Phase B)
タイマーウィジェット(タスク詳細右ペイン)
見積 3h
実績 1h30m
[▶ 開始] または [⏹ 00:25:14 停止]
- 起動中はリアルタイム経過時間を表示(polling or SSE)
- 停止時に任意のメモを入力してからログ保存できる