- 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>
120 lines
2.9 KiB
Markdown
120 lines
2.9 KiB
Markdown
## Context
|
|
|
|
automation spec 定義週報須包含:已完成、進行中、逾期、阻礙中、下週預計任務清單。現行實作僅提供數量統計與部分摘要。
|
|
|
|
## Goals / Non-Goals
|
|
|
|
**Goals:**
|
|
- 週報內容包含完整任務清單
|
|
- 新增阻礙中任務清單
|
|
- 新增下週預計完成任務清單
|
|
|
|
**Non-Goals:**
|
|
- 不實作週報自訂欄位篩選
|
|
- 不實作週報匯出 PDF/Excel
|
|
|
|
## Decisions
|
|
|
|
### 1. 週報內容結構
|
|
|
|
**Decision:** 擴充 content JSON 結構
|
|
|
|
**Current:**
|
|
```json
|
|
{
|
|
"summary": { "completed_count": 5, "in_progress_count": 3, ... },
|
|
"projects": [
|
|
{
|
|
"completed_tasks": [{"id": "...", "title": "..."}], // 限制 5 筆
|
|
"overdue_tasks": [...] // 限制 5 筆
|
|
}
|
|
]
|
|
}
|
|
```
|
|
|
|
**Proposed:**
|
|
```json
|
|
{
|
|
"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 表關聯
|
|
|
|
```python
|
|
# 取得有未解除阻礙的任務
|
|
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 在下週一至週日
|
|
|
|
```python
|
|
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 |
|