# 稽核事件查詢 Runbook — 誰做了什麼、何時做的

> 給原廠／管理者：如何從 DB 查出「誰、做了什麼專案進度行為、何時」的時間線。
> 本期（FR-033）只提供 SQL 查詢；尚無查詢 API / UI。

---

## 0. 先搞懂：兩套 log 看哪一個

| 想查的東西 | 看哪張表 | 為什麼 |
|---|---|---|
| **業務事件時間線**（誰推進流程、誰完成任務、誰改問卷狀態）| `public.system_logs` | 語意明確，一筆一事件，含 event_code |
| 某人某時打了哪支 HTTP API（含 request body）| `public.api_logs` | 全自動記錄每個 request，但要靠 path/body 解讀 |
| 登入 / 登出 / 使用者管理 | `public.system_logs` | 既有 audit event |

**多數稽核需求看 `system_logs`。** 以下 SQL 以它為主。

---

## 1. `system_logs` 欄位對照

| 欄位 | 意義 | 對應問題 |
|------|------|---------|
| `act_time` | 事件發生時間 | **何時** |
| `user_uid` | 操作者 UUID | **誰** |
| `user_name` | 操作者暱稱（nickname）| **誰**（人看得懂）|
| `event_code` | 事件碼（見 §2）| **做了哪類事** |
| `message` | `[AUDIT:...] key=value` 結構化訊息 | **做了什麼**（含 project_id / task_uid 等）|
| `level` | INFO / WARNING / ERROR | — |
| `method` / `func_name` / `line_no` / `path` | 程式位置（debug 用）| — |

> 保留期：**180 天**（按 `act_time` 月分區）。`api_logs` 為 90 天。

---

## 2. 事件碼（event_code）對照

| event_code | 意義 | 來源 |
|---|---|---|
| 4624 / 4625 | 登入失敗 / 成功 | 既有 |
| 4634 | 登出 | 既有 |
| 6050 | 流程推進請求 | 既有 STAGE_ADVANCE |
| 6051 | 流程推進成功 | 既有 |
| 6052 | 流程**退回**成功 | 既有 |
| 6053 | 推進中止（warning）| 既有 |
| 6054 | 推進被擋 | 既有 |
| **6060** | **任務完成** | FR-033 |
| **6061** | **任務指派 / 批次指派** | FR-033 |
| **6062** | **任務改派** | FR-033 |
| **6063** | **任務退回指派** | FR-033 |
| **6070** | **問卷狀態變更**（送審/通過/退回，看 `from_status→to_status`）| FR-033 |

> 問卷狀態碼：0=未填寫, 1=編輯中, 2=待審核, 3=補充說明, 9=完成。
> 例：`from_status=1 to_status=2` = 送審；`from_status=2 to_status=3` = 審核退回補件；`to_status=9` = 審核通過完成。

---

## 3. 連線資訊

| 環境 | Host | Port | DB | 帳號 |
|------|------|------|-----|------|
| DEV | `192.168.50.188` | `25432` | `guidant_ai_dev` | `cmmgr`（密碼查 `.env` `DB_SECRET`）|
| STG | `192.168.50.188` | `25432` | `guidant_ai_stg` | 同上 |
| POC | `192.168.50.189` | `25432` | `guidant_ai_poc` | 同上 |

```bash
# 連線範例（密碼請查 .env，勿寫進任何檔案）
PGPASSWORD='<查 .env DB_SECRET>' psql -h 192.168.50.188 -p 25432 -U cmmgr -d guidant_ai_dev
```

---

## 4. 查詢範例（可直接複製）

### 4.1 某段時間內，誰做了哪些專案進度行為（總時間線）

```sql
SELECT act_time, user_name, event_code, message
FROM public.system_logs
WHERE event_code IN ('6051','6052','6060','6061','6062','6063','6070')
  AND act_time >= '2026-06-01 00:00:00'
  AND act_time <  '2026-06-05 00:00:00'
ORDER BY act_time;   -- 時間正序 = 時間線
```

### 4.2 查特定使用者做了什麼（依暱稱）

```sql
SELECT act_time, event_code, message
FROM public.system_logs
WHERE user_name = '王小明'
  AND act_time >= now() - interval '30 days'
ORDER BY act_time DESC;
```

### 4.3 查某個專案的完整進度時間線

```sql
-- 任務指派/完成的 message 帶 project_id；流程推進/問卷狀態用 task_uid 串
SELECT act_time, user_name, event_code, message
FROM public.system_logs
WHERE message LIKE '%project_id=88%'
  AND event_code IN ('6060','6061','6062','6063')
ORDER BY act_time;
```

### 4.4 查某張任務（task_uid）誰指派、誰改派、誰退回、誰完成

```sql
SELECT act_time, user_name, event_code, message
FROM public.system_logs
WHERE message LIKE '%task_uid=ef34%'   -- 換成實際 task_uid
ORDER BY act_time;
```

### 4.5 查某份問卷的狀態變更歷程（送審→退回→通過）

```sql
SELECT act_time, user_name, message
FROM public.system_logs
WHERE event_code = '6070'
  AND message LIKE '%task_survey_uid=gh56%'   -- 換成實際 task_survey_uid
ORDER BY act_time;
```

### 4.6 查所有「退回」動作（流程退回 + 問卷退回補件）

```sql
SELECT act_time, user_name, event_code, message
FROM public.system_logs
WHERE event_code = '6052'                              -- 流程退回
   OR (event_code = '6070' AND message LIKE '%to_status=3%')  -- 問卷審核退回補件
ORDER BY act_time DESC;
```

### 4.7 用 HTTP log 反查（補充手段，當 system_logs 不夠時）

```sql
-- 知道誰在何時打了某支 API（90 天內）
SELECT act_time, user_name, method, url, duration
FROM public.api_logs
WHERE url LIKE '%/jobs/batch-complete%'
  AND act_time >= now() - interval '7 days'
ORDER BY act_time DESC;
```

---

## 5. 已知限制（誠實告知）

- **無 tenant 欄位**：`system_logs` 不含 `tenant_id`，無法直接按租戶過濾；需用 `user_name` / message 內的 project_id 間接區分。
- **Socket.IO 協同編輯不記**：問卷逐字協作（`on_update`）刻意不埋點（量太大）；只記狀態轉換。
- **本期無查詢 API / UI**：只能走 SQL。若客戶要 UI 時間線，需另開 feature 做 system_logs 查詢 route。
- **既有未補的行為**：本 FR 補的是「專案進度」核心行為；其他模組（如資產盤點 CRUD）若日後要稽核，照 `common/util/audit_log.py` + 新增 EventCode 同樣方式埋點即可。

---

## 6. 如何擴充（給未來 dev）

要替新行為加稽核：

1. `common/enum/event_code.py` 加一個 EventCode（依現有序號往後）
2. service 層該行為發生處呼叫 `audit(logger, "<EVENT_NAME>", EventCode.XXX, key=value, ...)`
3. logger 用 `logging.getLogger(__name__)`（須是 `app`/`api`/`infra`/`domain`/`common` 子 logger 才會寫進 DB）
4. 寫測試：`.__wrapped__` 繞過 `@transaction` + `caplog` 斷言（參考 `test/test_audit_event_instrumentation.py`）
5. 本 runbook §2 事件碼對照表補一列
