コメント・アクティビティ 仕様書

スレッドコメント・@メンション・変更履歴の自動記録

ステータス: Draft / 作成日: 2026-05-27 PR #4 — 依存: コア


1. データモデル

1.1 task_comments

pub struct Model {
    pub id: Uuid,
    pub task_id: Uuid,
    pub user_id: Uuid,
    pub body: String,                     // Markdown(@メンション含む)
    pub parent_comment_id: Option<Uuid>,  // スレッド返信(1 段のみ)
    pub created_at: DateTimeUtc,
    pub updated_at: DateTimeUtc,
    pub deleted_at: Option<DateTimeUtc>,  // ソフトデリート
}
カラム 制約
id UUID PK
task_id UUID NOT NULL, FK→tasks CASCADE
user_id UUID NOT NULL, FK→users CASCADE
body TEXT NOT NULL
parent_comment_id UUID NULLABLE, FK→task_comments SET NULL
created_at TIMESTAMPTZ NOT NULL DEFAULT now()
updated_at TIMESTAMPTZ NOT NULL DEFAULT now()
deleted_at TIMESTAMPTZ NULLABLE

1.2 task_activities

タスクへのあらゆる変更を自動記録する監査ログ。アプリ層から明示的に書き込む。

カラム 制約 説明
id UUID PK  
task_id UUID NOT NULL, FK→tasks CASCADE  
user_id UUID NULLABLE, FK→users SET NULL NULL = システム操作
event_type VARCHAR NOT NULL 下表参照
payload JSONB NOT NULL 変更前後の値
created_at TIMESTAMPTZ NOT NULL DEFAULT now()  

event_type 一覧:

ペイロード例
task_created {}
status_changed { "from": "Backlog", "to": "In Review" }
priority_changed { "from": "medium", "to": "high" }
assignee_added { "user_id": "uuid", "role": "primary" }
assignee_removed { "user_id": "uuid" }
deadline_changed { "field": "hard_deadline", "from": "...", "to": "..." }
comment_added { "comment_id": "uuid" }
relation_added { "type": "blocks", "target_seq_id": 55 }
relation_removed { "type": "blocks", "target_seq_id": 55 }
label_added { "label_id": "uuid", "name": "bug" }
label_removed { "label_id": "uuid", "name": "bug" }
sprint_changed { "from": "Sprint 2", "to": "Sprint 3" }
archived / unarchived {}
github_pr_linked { "pr_number": 87, "title": "..." }
github_pr_merged { "pr_number": 87 }

2. マイグレーション

CREATE TABLE task_comments (
    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,
    body TEXT NOT NULL,
    parent_comment_id UUID REFERENCES task_comments(id) ON DELETE SET NULL,
    created_at TIMESTAMPTZ NOT NULL DEFAULT now(),
    updated_at TIMESTAMPTZ NOT NULL DEFAULT now(),
    deleted_at TIMESTAMPTZ
);

CREATE TABLE task_activities (
    id UUID PRIMARY KEY,
    task_id UUID NOT NULL REFERENCES tasks(id) ON DELETE CASCADE,
    user_id UUID REFERENCES users(id) ON DELETE SET NULL,
    event_type VARCHAR NOT NULL,
    payload JSONB NOT NULL,
    created_at TIMESTAMPTZ NOT NULL DEFAULT now()
);

CREATE INDEX idx_comments_task ON task_comments(task_id, created_at)
    WHERE deleted_at IS NULL;
CREATE INDEX idx_activities_task ON task_activities(task_id, created_at DESC);

3. @メンション処理

コメント本文中の @ユーザー名 をサーバー側でパースし、通知を生成する。

パース対象: @username 形式(アルファベット・数字・_・- を含む)
1. body から正規表現で @mention を抽出
2. username でユーザーを検索
3. 見つかった場合 → notifications テーブルに type=mentioned で挿入
   (通知システムは PR #5 で実装。本 PR では mention 抽出のみ行い、
    通知テーブルが存在しない場合は INSERT をスキップする)

4. API

コメント

メソッド パス 説明
GET /tasks/{id}/comments コメント一覧(スレッド構造、新着順)
POST /tasks/{id}/comments 投稿
PUT /tasks/{id}/comments/{cid} 編集(投稿者本人のみ)
DELETE /tasks/{id}/comments/{cid} ソフトデリート(投稿者 or テナントオーナー)

POST リクエスト:

{
  "body": "この件は @tanaka さんに確認してください。",
  "parent_comment_id": null
}

GET レスポンス(スレッド構造):

{
  "comments": [
    {
      "id": "uuid",
      "user": { "id": "uuid", "name": "田中" },
      "body": "設計は完了しました。",
      "replies": [
        {
          "id": "uuid",
          "user": { "id": "uuid", "name": "鈴木" },
          "body": "レビュー依頼します。",
          "created_at": "2026-05-27T12:00:00Z"
        }
      ],
      "created_at": "2026-05-27T11:00:00Z",
      "updated_at": "2026-05-27T11:00:00Z",
      "is_deleted": false
    }
  ]
}

削除済みコメントは "body": null, "is_deleted": true で返す(返信があれば親は残す)。

アクティビティ

メソッド パス 説明
GET /tasks/{id}/activities 変更履歴一覧(新着順)

レスポンス:

{
  "activities": [
    {
      "id": "uuid",
      "event_type": "status_changed",
      "user": { "id": "uuid", "name": "田中" },
      "payload": { "from": "Backlog", "to": "In Review" },
      "created_at": "2026-05-27T11:00:00Z"
    }
  ]
}

5. フロントエンド(Phase B)

タスク詳細のタイムライン

コメントとアクティビティを時系列に混在表示する。

──── アクティビティ ──────────────────────────────
  田中 が優先度を変更: medium → high    11:00

──── コメント ────────────────────────────────────
  🧑 田中  11:10
  設計は完了しました。
    └ 🧑 鈴木  11:15
      レビュー依頼します。

──── アクティビティ ──────────────────────────────
  システム が PR #87 をリンク           11:20

コンポーネント

コンポーネント ファイル
TaskTimeline components/tasks/TaskTimeline.vue
TaskCommentForm components/tasks/TaskCommentForm.vue
TaskActivityItem components/tasks/TaskActivityItem.vue