GOV-008 Redmine 登錄規格與 Workflow(專案/CR/Issue 追蹤)
| 項目 |
內容 |
| 文件編號 |
GOV-008 |
| 版本 |
1.2(2026-10-17 擴充 §12~§15+§16 補 GAPS 缺口評定規則(CR-050 裁定)) |
| 狀態 |
已實作(2026-10-17;Redmine 6.1 + PostgreSQL 18,ops/redmine/) |
| 依據 |
ops/redmine/README.md(單一真實來源原則)、HANDOVER §📊 任務追蹤總表、GOV-006、CR-046(本規格之觸發) |
| 範圍 |
本專案(cardcore)之全部工作項目、CR、Issue、需求(FR/NFR/POC) 於 Redmine 之登錄、命名、狀態流轉、進度計算、Dashboard、角色所有權、郵件與成果歸檔 |
1. 定位(不可違反)
| 用途 |
工具 |
角色 |
| 任務狀態/完成率/決策留痕 |
HANDOVER §📊 任務追蹤總表+GOV-006
|
唯一權威(進 git,可 diff/審計) |
| CR 內容/影響分析/裁定 |
docs/05-change-requests/CR-0xx_*.md |
唯一權威 |
| 協作/分派/視覺化/通知 |
Redmine |
鏡像/協作層(本規格所管) |
★ 任何以 Redmine 內容「覆蓋」文件敘述之行為,一律視為缺陷。
決議形成後必須回寫文件並 commit,再於 Redmine 貼上「已回寫 + commit hash」。
2. 編碼與命名(Issue 編碼)
2.1 原則:沿用既有文件編號,不另創第二套編號
| 類型 |
Issue 編碼 |
Subject 格式 |
來源(權威) |
| 變更請求 |
CR-0xx |
[CR-046] <CR 標題> |
docs/05-change-requests/CR-0xx_*.md 之檔名 |
| 工作項 |
TASK-A<nnn> |
[TASK-A269] <工作項標題> |
HANDOVER §3.A 之 #A-269
|
| 里程碑 |
EPIC-P1 |
[EPIC-P1] Phase-1 文件基線… |
HANDOVER §3.A 之彙總 |
| 缺陷(預留) |
ISSUE-<nnn> |
[ISSUE-001] <症狀> |
新開(Redmine 內建立後回寫文件) |
| 需求(預留) |
REQ-<FR/NFR> |
[REQ-FR-3.1] <需求> |
GOV-002/RFP 編號 |
為何沿用:Issue 與文件一對一可追溯(Redmine [CR-046] ↔ CR-046_*.md ↔ HANDOVER #A-…);
另立編號會產生「兩套真相」與對照成本(GOV-006 開頭警告之同一件事)。
2.2 Subject 規則
- 前綴
[編碼] 必須為 subject 開頭(同步器以此為冪等鍵;不可改為其他位置)。
- 長度上限 255(Redmine 限制);超過時截斷,完整標題留在 description。
- 不在 subject 放狀態(狀態由 Status 欄位承載,避免雙重真相)。
3. 字典(Tracker/Status/Priority)
3.1 Tracker(語意對映,非工具預設)
| id |
名稱 |
用途 |
| 1 |
CR |
變更請求(含 Epic 里程碑) |
| 2 |
Task |
工作項(對應 #A-xxx) |
| 3 |
Issue |
缺陷/異常(預留) |
| 4 |
Requirement |
需求項(預留,對應 FR/NFR) |
3.2 Status(含本專案特有之 Parked)
| id |
名稱 |
結案態 |
語意 |
| 1 |
New |
— |
已登錄、未開工/待排 |
| 2 |
In Progress |
— |
施工中 |
| 3 |
Resolved |
— |
已完成待驗(文件已回寫、待覆核) |
| 4 |
Feedback |
— |
待裁定/待外部輸入(需他方決策或資料) |
| 5 |
Closed |
✅ |
已結案(文件已 commit) |
| 6 |
Parked |
— |
擱置(本階段不做,紀錄完整保留;CR-046 即此態) |
| 7 |
Rejected |
✅ |
不做/駁回 |
★ Parked 與 Feedback 之差異:Feedback=等別人(可推進,缺輸入);Parked=本階段主動不做(不再追)。
此區分讓 Dashboard 的「未結案」不被擱置項污染。
3.3 Priority
| id |
名稱 |
對映 |
| 1 |
P0-Urgent |
阻塞交付/客戶硬性要求(CR-046、CR-045、CR-047、CR-048) |
| 2 |
P1-High |
主要 CR |
| 3 |
P2-Normal |
一般工作項(預設) |
| 4 |
P3-Low |
加分項 |
4. 關係模型
[CR-046](CR,Parked,version=CR-046 全鏈路(擱置))
├── [TASK-A258] 認列→錄取→指令 (Task,Closed)
├── [TASK-A259] 指令派發+rewards 消費 (Task,Closed)
├── …(共 22 個子項,A-248~A-269)
└── [TASK-A269] 排除項參數化+ledger 歸屬(Task,Closed)
[EPIC-P1](CR,Closed,version=Phase-1 文件基線)── 彙總 A-001~A-247(237 項)
-
CR 為 parent、工作項為 child(Redmine
parent_issue_id)——反映「CR 底下工作項」之真實結構。
-
不逐筆登錄 A-001~A-247:237 筆已完成之歷史工作項以
EPIC-P1 彙總,避免 Dashboard 被歷史噪音淹沒
(需要明細時查 HANDOVER §3.A,該處才是權威)。
5. Workflow(狀態流轉)
┌──────────── Feedback(待裁定/待外部)
│ ▲
New ──► In Progress ──► Resolved ──► Closed
│ │
└───────────┴──► Parked(擱置,可回復至 In Progress)
└──► Rejected(不做)
-
本期:Workflow 對所有 Role × Tracker × (old→new) 全允許(
bootstrap.rb 建 980 條),
目的為 admin 維運順暢;對外開放前必須收斂為實際流程(例:僅 Manager 可 Closed)。
- ★ API 限制(實測):Redmine 對
status_id 之 REST 更新受 workflow 檢查且會靜默忽略
(PUT 回 204 但狀態不變)→ 狀態一律由 ops/redmine/apply_status.rb(runner)套用;
內容(subject/description/priority/version/done_ratio)走 API。
6. 完工比率(done_ratio)
| Status |
done_ratio |
說明 |
| New |
0 |
未開工 |
| In Progress |
50 |
施工中(粗估;細估以子項比例為準) |
| Feedback |
30 |
等輸入,已做部分 |
| Parked |
20 |
擱置(已做之部分保留) |
| Resolved |
90 |
完成待驗 |
| Closed |
100 |
結案 |
-
專案層進度=各 issue
done_ratio 之算術平均(本期實測 61.7%,71 筆)。
⚠️ 此為工作量指標,非「交付完成度」——CR-046 之 AC 11 未閉環,不得以 61.7% 對外宣稱進度。
- 若需加權(P0 權重 ×3),以 Redmine 之外部報表計算;本規格不內建權重(避免黑箱)。
7. 版本/里程碑
| id |
名稱 |
狀態 |
內容 |
| 1 |
Phase-1 文件基線 |
open(★ 刻意不關閉) |
文件基線+已結案 CR(20 筆) |
| 2 |
CR-046 全鏈路(擱置) |
open |
CR-046+22 個工作項(23 筆) |
| 3 |
Backlog |
open |
未結案/待排(28 筆) |
★ closed version 不可被指派(實測 422 Target version is not included in the list)
→ 已完成里程碑保持 open,於名稱標示「已完成」即可;關閉時機為「不再新增 issue 時」。
8. Dashboard(可直接使用)
| # |
用途 |
URL |
| ① |
全部未結案 |
http://localhost:8080/projects/cardcore/issues?set_filter=1&status_id=o |
| ② |
CR-046 全鏈路(含 22 子項) |
http://localhost:8080/projects/cardcore/issues?set_filter=1&status_id=*&fixed_version_id=2 |
| ③ |
待裁定/待外部 |
http://localhost:8080/projects/cardcore/issues?set_filter=1&status_id=4 |
| ④ |
專案總覽(Redmine 內建) |
http://localhost:8080/projects/cardcore |
| ⑤ |
CR-046 樹狀(含子項) |
http://localhost:8080/issues/247 |
- 上述 URL 已實測 200。可直接加入書籤;亦可在 UI「儲存查詢」後出現在側欄
(★ Redmine 6 之 Saved Query 經 API/runner 建立有 filters 序列化相容問題,本期未自動建立——UI 手動一次即可)。
-
建議看的兩個數字:① 未結案數(應持續下降);②
Parked 數(擱置項應有明確解除條件)。
9. 同步機制(工具)
| 檔案 |
作用 |
用法 |
ops/redmine/bootstrap.rb |
一次性初始化(字典/專案/版本/Role/Workflow);冪等
|
docker cp → rails runner
|
ops/redmine/sync.py |
由文件鏡像建立/更新 issue(冪等,以 [前綴] 比對);--dry-run/--apply/--emit-status-map
|
REDMINE_API_KEY=… python3 ops/redmine/sync.py --apply |
ops/redmine/apply_status.rb |
套用狀態(繞過 API 之 workflow 限制) |
先 --emit-status-map /tmp/map.json,再 runner |
標準流程(每次文件變更後):
cd cardcore
export REDMINE_URL=http://localhost:8080
export REDMINE_API_KEY=<金鑰> # Redmine → 我的帳戶 → API 存取金鑰
python3 ops/redmine/sync.py --apply --emit-status-map /tmp/redmine_status_map.json
docker cp /tmp/redmine_status_map.json cr-redmine:/tmp/redmine_status_map.json
docker cp ops/redmine/apply_status.rb cr-redmine:/tmp/apply_status.rb
docker exec cr-redmine bundle exec rails runner /tmp/apply_status.rb
實測結果(2026-10-17):71 筆(CR 49/Task 22);狀態 Closed 42/New 26/In Progress 1/
Feedback 1/Parked 1(CR-046);平均 done_ratio 61.7%;同步器重跑 0 新增/71 更新(冪等成立)。
10. 已知限制(誠實揭露)
| # |
限制 |
影響 |
對策 |
| 1 |
REST API 之 status_id 受 workflow 檢查而靜默忽略
|
狀態無法由 API 設定 |
以 apply_status.rb 套用(本規格 §5) |
| 2 |
closed version 不可指派 |
已關閉里程碑無法歸版 |
里程碑保持 open(§7) |
| 3 |
Saved Query 之 filters 序列化在 Redmine 6 有相容問題 |
側欄查詢未自動建立 |
以 URL 代替(§8)+UI 手動儲存 |
| 4 |
Workflow 目前全允許
|
非正式流程 |
對外開放前收斂(§5) |
| 5 |
A-001~A-247 未逐筆登錄 |
無單項追蹤 |
以 EPIC-P1 彙總;明細查 HANDOVER |
| 6 |
Redmine 為鏡像,非權威 |
不可在 Redmine 改狀態當真相 |
§1 原則;回寫文件+commit |
| 7 |
多個 Agent 共用同一信箱,而 Redmine 之 email 欄位唯一 |
無法為每個 Agent 設真實信箱 |
Redmine 內建使用者採 <login>@cardcore.local;真實信箱以 §13 對映表為權威 |
| 8 |
Redmine 映像之 REDMINE_SMTP_* 僅在首次佈署產生 configuration.yml |
事後改 env 不生效 |
已直接寫入容器內 config/configuration.yml(本規格 §13.2;SIT 覆寫後須回寫範本) |
| 9 |
郵件主旨之角色前綴解析後才知歸屬 |
主旨不合慣例即無法路由 |
mail_intake.py fail-closed 略過並記錄,不猜
|
12. 需求註冊(RFP → FR/NFR/POC)
12.1 定位
客戶 RFP(FR 68 項/NFR 874 項/POC 17 項)是baseline;我方目標是真正落地的微服務系統。
故需求既保留客戶編號,也掛上落地對映(承作服務/設計依據/API/驗收測試/WBS 階段/Owner)。
12.2 來源(權威=版本受控文件)
| 類別 |
檔案 |
筆數 |
| 客戶 FR 原文 |
proposal_v2/sources/FR.md |
68 |
| FR 追蹤清單 |
docs/01-brd/BRD-002(由 tools/gen_traceability.py 產生) |
68 |
| NFR 追蹤清單 |
docs/01-brd/BRD-003 §3(小節層級) |
60 小節/874 項 |
| POC 驗收情境 |
docs/01-brd/BRD-004 §2 |
17 項 |
| 需求追溯矩陣 |
docs/00-governance/GOV-004 |
四問追溯 |
12.3 編碼
| 前綴 |
例 |
說明 |
[FR-<群組碼>-<n>] |
[FR-SYS-1]、[FR-RWD-5.1]
|
群組碼 SYS/COM/RWD/AUT/ACQ/ISS/DEB |
[NFR-<B.n>-<小節名>] |
[NFR-B.1-監控機制] |
B.1 基礎設施/B.2 系統規格/B.3 微服務雲原生/B.4 公司能力 |
[POC-<nn>] |
[POC-01] |
依 BRD-004 §2 序號 |
12.4 註冊工具(冪等)
export REDMINE_API_KEY=…
python3 ops/redmine/req_register.py --dry-run
python3 ops/redmine/req_register.py --apply
⚠️ 只由文件推導議題;Redmine 內容不反向覆蓋文件(§1)。
13. 角色、信箱與 Email 慣例
13.1 角色與信箱對映(權威)
| 角色 |
Redmine 登入 |
真實信箱 |
| Project Executive(BEAM PMO) |
miui.amber |
<信箱已遮蔽> |
| Lead Architect(開發團隊) |
lead.architect |
<信箱已遮蔽> |
| DBA Agent |
dba.agent |
<信箱已遮蔽> |
| Business Analyst Agent |
ba.agent |
<信箱已遮蔽> |
| SA/SD Agent |
sasd.agent |
<信箱已遮蔽> |
| Data Analyst Agent |
data.analyst |
<信箱已遮蔽> |
| UI/UX Agent |
uiux.agent |
<信箱已遮蔽> |
| Java Coder Agent |
coder.agent |
<信箱已遮蔽> |
| Security Architect Agent |
security.arch |
<信箱已遮蔽> |
| QA/QC Agent |
qaqc.agent |
<信箱已遮蔽> |
| TestBOT |
testbot |
<信箱已遮蔽> |
⚠️ 共用信箱 vs 唯一信箱:多個 Agent 共用 <信箱已遮蔽>(後端依主旨前綴 parsing),
而 Redmine email 欄位唯一 → Redmine 內建使用者採「不可投遞之內部位址」<login>@cardcore.local,
真實信箱以此表為權威(不造假信箱)。
13.2 郵件寄送(本地可驗證)
- 本地以 MailHog(
cr-mailhog;預覽 http://localhost:8025)離線收件,不對外投遞;
SIT/UAT/PRD 以環境變數覆寫 REDMINE_SMTP_* 為真實 SMTP。
- 寄件者:
[email protected](Setting.mail_from);Setting.default_users_hide_mail=1(收件人互不可見)。
- 來信處理:
Setting.mail_handler_api_enabled=1(Redmine 內建 MailHandler;
餵入方式 POST /mail_handler 或 rake redmine:email:receive_imap)。
- 工具:
ops/redmine/configure_mail.rb(設定+送測試信;測試信須真送到 MailHog 才算數)。
13.3 主旨前綴慣例(後端 parsing)
- 格式:
<角色名> - <任務描述>,例 Lead Architect - 指派執行開發授權系統任務。
- 前綴必須為 §13.1 之角色名;一封信只做一件事;單號/編號寫在描述中(例
CR-049、A-271)。
- 解析工具:
ops/redmine/mail_intake.py(含 --selftest)——不合慣例即 fail-closed 略過,不猜。
14. WBS 階段 Dashboard
14.1 階段(對映 GOV-006 §1)
| # |
階段 |
Redmine 版本 |
判定來源 |
| 1 |
文件基線與需求註冊 |
Phase-1 文件基線與需求註冊 |
req_register.py |
| 2 |
平台與基礎建設 |
Phase-2 平台與基礎建設 |
平台/橫切/依賴版本 |
| 3 |
領域服務 R1 |
Phase-3 領域服務 R1 |
FR 批次 R1 |
| 4 |
領域服務 R2/R3 與參數極大化 |
Phase-4 領域服務 R2/R3 與參數極大化 |
FR 批次 R2/R3、活動相關 |
| 5 |
WebUI 作業台 |
Phase-5 WebUI 作業台 |
前端/頁面 |
| 6 |
橫切品質關卡 |
Phase-6 橫切品質關卡 |
掃描/CI/依賴修補 |
| 7 |
測試與 POC 驗收 |
Phase-7 測試與 POC 驗收 |
POC/TRP/TRR |
14.2 歸檔規則(ops/redmine/wbs_phases.py,可重跑)
- 需求類(FR/NFR/POC):依交付批次/分組自動入階段;
-
子任務沿用父議題階段(
CR-046 交付列車之工作項即此例);
- 關鍵字規則兜底;規則未判定 → 改列
Backlog 並列印清單供人工複核(不留在模糊狀態)。
14.3 進度判讀
-
Closed 比率=階段議題結案比例;平均 done_ratio=工作量指標,非交付完成度。
- 交付完成度以
HANDOVER §📊 任務追蹤總表 為準(Redmine 不自行宣告)。
15. 執行過程記錄與成果歸檔
15.1 三層記載
| 層 |
載體 |
放什麼 |
頻率 |
| 決策層 |
Issue note |
單一決策點、裁定、阻塞與解除 |
每個關鍵決策 |
| 敘事層 |
Wiki ExecutionLog-<CR/TASK>
|
完整執行敘事(症狀→假設→查證→修正→驗證) |
任務結案一次 |
| 證據層 |
Issue 附件 |
截圖、證據檔、產出文件 |
每次有結果 |
15.2 編碼慣例
- Issue note 首行:
[EXEC] <階段>|<結論>,例
[EXEC] E2E-P3|cap 截斷失敗:used=600 estimated=617 cap=1000 → 查證為 relay 未派發。
- Wiki 執行紀錄頁命名對齊議題單號:
ExecutionLog-CR-049、ExecutionLog-A-271。
- 附件命名:
<單號>_<內容>_<YYYYMMDD>.<ext>,例 CR-049_E2E-evidence_20261017.txt。
15.3 成果上傳工具
export REDMINE_API_KEY=…
python3 ops/redmine/attach.py --issue CR-049 --files docs/08-evidence/….txt
python3 ops/redmine/attach.py --task A-271 --files out.png
- ⚠️ 上傳端點之
Content-Type 必須為 application/octet-stream(帶 text/plain 會 406——實測)。
- 預設同時寫入一則 Issue note(
[EXEC] 成果附件+來源路徑),讓右側卡片可追到單號。
15.4 Wiki 頁面(導覽層)
首頁|需求註冊|WBS階段Dashboard|角色與信箱對映|執行過程與成果歸檔|工具與腳本
(由 ops/redmine/seed_wiki.rb 建立/更新;權威仍在文件)。
11. 修訂記錄
| 版本 |
說明 |
| 1.0 |
2026-10-17:初版。依 BEAM PMO 指示「系統性登錄(編碼/命名/Workflow/完工比率)」建立;含字典、關係模型、Workflow、done_ratio 規則、版本策略、Dashboard URL、同步工具與六項已知限制。實測 71 筆登錄完成。 |
| 1.1 |
2026-10-17:擴充 §12 需求註冊(RFP→FR 68/NFR 60 小節/POC 17,共 145 筆進 Requirement tracker,保留客戶編號+落地對映)、§13 角色與信箱(Project Executive+10 Agent;真實信箱對映表;MailHog離線 SMTP;<角色名> - <任務> 主旨慣例與 fail-closed 解析)、§14 WBS 階段 Dashboard(Phase-1~7 與歸檔規則)、§15 執行過程與成果歸檔(三層記載+attach.py+Wiki)、§10 新增限制 7~9。 |
| 1.2 |
2026-10-17:§16.1 補「GAPS 已揭露缺口 → In Progress(即使三重證據齊備)」評定規則;§16.3 兩筆漂移標記已依 CR-050 裁定完成對映誠實化,並揭露「卡片級查詢實為 RFP 已列(FR §2.4(1))」待 BEAM PMO 覆核(CR-050 §4)。 |
16. 需求議題之落地狀態評定(可證偽)
BEAM PMO 2026-10-17 決定(選項 (c)):依「對應服務是否已實作」逐項評定 145 筆需求。
★ 狀態不是感受——每一筆皆由可重跑、可查核的事實推導,且評定寫入議題 note(判定依據),
讓 Dashboard 上任一狀態都能回答「憑什麼」。
16.1 評定規則
| 類別 |
條件 |
狀態 |
依據 |
| FR(R0) |
承作服務=—(流程/文件/實績類) |
Feedback 30 |
不由程式承作;交付物見 TRP-001
|
| FR(橫切) |
主要 API 以 —( 開頭,平台模組已實作 |
Closed 100 |
platform/common→common-* 模組群/platform/gateway→api-gateway
|
| FR(具名 API) |
路徑存在於 contracts/openapi/<svc>.yaml(路徑模板比對)+服務 test 檔 > 0 |
Closed 100 |
契約+實作+測試三重證據 |
| FR(具名 API) |
契約缺路徑,或測試檔 = 0 |
In Progress 50 |
部分落地 |
FR(GAPS 已揭露缺口) |
登錄於 gen_traceability.GAPS(CR-050 裁定) |
In Progress 50 |
★ 即使三重證據齊備亦不得 Closed——FR 內已列之子需求未交付前不宣稱完成(反假綠) |
| NFR 小節 |
設計依據文件已具備 |
In Progress 50 |
★ 設計已備 ≠ 已驗證;逐節驗證證據待補登(TRP-002) |
| POC |
對應服務已實作 |
In Progress 50 |
POC 需依 BRD-004 逐情境 DEMO/API 演示;未演示前不宣稱通過 |
服務層級品質佐證:TRP-004(17 領域服務行覆蓋 90.92%、失敗 0/0)。
16.2 兩項重要修正(皆為「假綠/假紅」之修正)
-
概稱 → 實際目錄:追溯對映之
platform/common/platform/gateway 非實際目錄名,
已對映至 common-* 模組群/api-gateway(backend/ 目錄結構為權威)。
-
路徑模板比對:比對前將
{參數} 正規化為 {}——
追溯對映寫 {id}、契約寫 {accountId} 屬同一路徑;字串精確比對會造成假 In Progress。
16.3 評定結果(2026-10-17)
| 狀態 |
筆數 |
說明 |
| Closed |
51 |
FR——契約+實作+測試三重證據齊備 |
| In Progress |
79 |
2 FR(真實缺口)+60 NFR(設計已備未驗證)+17 POC(待演示) |
| Feedback |
15 |
R0 流程/文件/實績類 |
FR 真實缺口(契約 ↔ 追溯對映漂移,2 筆)——★ 已依 CR-050 裁定完成對映誠實化(2026-10-17):
| FR |
原對映 API |
裁定後對映 |
說明 |
ACQ-4.3 |
GET /api/v1/merchant-statements |
—(未涵蓋:商店對帳單待另立 CR,CR-050) |
RFP FR §4.3 商店對帳單未承作;merchant-settlements 為 ACQ-4.2「請款」語意不可混用(拒絕方案 A 之改對映——避免假綠) |
ISS-2.4 |
GET /api/v1/cards/{id}/limits(stale,CR-043 已清除) |
GET /api/v1/accounts/{accountId}/limits |
帳戶級實際已交付;卡片級(RFP FR §2.4(1) 明列)以 GAPS 揭露,待另立 CR |
★ 執行中之新發現(待 BEAM PMO 覆核,CR-050 §4):RFP FR.md §2.4(1) 原文明列
「歸戶、持卡人、卡片調額/查詢」——卡片級查詢實為 RFP 已列需求,
此前「預期需求(未列 RFP)」之定性與 RFP 原文不符,建議更正 GOV-006 2.4.4 定性。
→ 宜立 CR 裁定(補端點或改對映),不在本規格擅自改對映。
16.4 重跑
export REDMINE_API_KEY=…
python3 ops/redmine/req_assess.py --apply --emit-status-map /tmp/req-status.json
# 狀態須由 runner 套用(REST API 對 status_id 靜默忽略,見 §10 #1)