Files
PROJECT-CONTORL/openspec/changes/fix-weekly-report/design.md
beabigegg 10db2c9d1f feat: implement audit trail alignment (soft delete & permission audit)
- Task Soft Delete:
  - Add is_deleted, deleted_at, deleted_by fields to Task model
  - Convert DELETE to soft delete with cascade to subtasks
  - Add include_deleted query param (admin only)
  - Add POST /api/tasks/{id}/restore endpoint
  - Exclude deleted tasks from subtask_count

- Permission Change Audit:
  - Add user.role_change event (high sensitivity)
  - Add user.admin_change event (critical, triggers alert)
  - Add PATCH /api/users/{id}/admin endpoint
  - Add role.permission_change event type

- Append-Only Enforcement:
  - Add DB triggers for audit_logs immutability (manual for production)
  - Migration 008 with graceful trigger failure handling

- Tests: 11 new soft delete tests (153 total passing)
- OpenSpec: fix-audit-trail archived, fix-realtime-notifications & fix-weekly-report proposals added

🤖 Generated with [Claude Code](https://claude.com/claude-code)

Co-Authored-By: Claude Opus 4.5 <noreply@anthropic.com>
2025-12-30 06:58:30 +08:00

2.9 KiB

Context

automation spec 定義週報須包含:已完成、進行中、逾期、阻礙中、下週預計任務清單。現行實作僅提供數量統計與部分摘要。

Goals / Non-Goals

Goals:

  • 週報內容包含完整任務清單
  • 新增阻礙中任務清單
  • 新增下週預計完成任務清單

Non-Goals:

  • 不實作週報自訂欄位篩選
  • 不實作週報匯出 PDF/Excel

Decisions

1. 週報內容結構

Decision: 擴充 content JSON 結構

Current:

{
  "summary": { "completed_count": 5, "in_progress_count": 3, ... },
  "projects": [
    {
      "completed_tasks": [{"id": "...", "title": "..."}],  // 限制 5 筆
      "overdue_tasks": [...]  // 限制 5 筆
    }
  ]
}

Proposed:

{
  "summary": {
    "completed_count": 5,
    "in_progress_count": 3,
    "overdue_count": 2,
    "blocked_count": 1,
    "next_week_count": 4,
    "total_tasks": 15
  },
  "projects": [
    {
      "project_id": "uuid",
      "project_title": "Project Name",
      "completed_tasks": [
        {"id": "...", "title": "...", "completed_at": "ISO8601", "assignee_name": "..."}
      ],
      "in_progress_tasks": [
        {"id": "...", "title": "...", "assignee_name": "...", "due_date": "ISO8601"}
      ],
      "overdue_tasks": [
        {"id": "...", "title": "...", "due_date": "ISO8601", "days_overdue": 3}
      ],
      "blocked_tasks": [
        {"id": "...", "title": "...", "blocker_reason": "...", "blocked_since": "ISO8601"}
      ],
      "next_week_tasks": [
        {"id": "...", "title": "...", "due_date": "ISO8601", "assignee_name": "..."}
      ]
    }
  ]
}

2. 阻礙任務識別

Decision: 查詢 Blocker 表關聯

# 取得有未解除阻礙的任務
blocked_task_ids = db.query(Blocker.task_id).filter(
    Blocker.resolved_at.is_(None)
).subquery()

blocked_tasks = db.query(Task).filter(
    Task.project_id.in_(project_ids),
    Task.id.in_(blocked_task_ids)
).all()

3. 下週預計任務

Decision: due_date 在下週一至週日

next_week_start = week_end  # 本週末 = 下週初
next_week_end = next_week_start + timedelta(days=7)

next_week_tasks = db.query(Task).filter(
    Task.project_id.in_(project_ids),
    Task.due_date >= next_week_start,
    Task.due_date < next_week_end,
    Task.status.not_in(["done", "completed"])
).all()

4. 任務明細欄位

Decision: 包含以下欄位供顯示

任務類型 額外欄位
completed completed_at (updated_at), assignee_name
in_progress assignee_name, due_date
overdue due_date, days_overdue
blocked blocker_reason, blocked_since
next_week due_date, assignee_name

Risks / Trade-offs

Risk Mitigation
大量任務導致 content JSON 過大 評估後續加入分頁或限制
阻礙查詢需 JOIN 使用 subquery 減少 N+1