本卡屬 FR-163(母卡見「母卡」欄),批 1。專案總覽的 control-tree 已經把每個任務的證據帶出來,但只有名稱/型別/來源/網址,證據視圖還要上傳者、時間、能預覽下載的檔案 uid。只改 BE repo,不開端點、不加 migration。
專案總覽頁載入時打一次 GET /ssp/<ssp_uid>/control-tree,回整棵「群組 → 控制項 → 評估目標 → 任務」,每個任務底下有 evidences[]。FR-163 的證據視圖就吃這棵樹攤平成表,不另開端點(design D9)。但現在每筆證據只有六個鍵,畫面要的「誰上傳、什麼時候、點了能預覽下載、連結要顯示標題不是網址」都沒有。
首腦核對:
infra/readmodel/oscal/ssp_control_implementation_query.py:184-199 get_file_link_evidences_by_job_ids:SELECT 只有 je.id, je.job_execution_id, je.evidence_type, je.source, je.ref_id, je.reference_url, je.classification_run_id, uf.file_name;已 LEFT JOIN public.upload_files uf,加 uf.uid/uf.size 不用多 JOIN。app/oscal/service/ssp_control_implementation_service.py:549-562:組 dict 的地方,name 對 LINK 退到 reference_url(因為沒撈 description)。infra/flow_engine/models/job_evidence.py:uid(String 50 PK)、description、created_user/created_at(繼承 BaseModel)都在表上。created_user 必配 created_user_name(nickname),在 app service 層批次轉,canonical helper 是 common/util/audit_nickname.py 的 enrich_audit_nickname_objs(查不到補 None、不回填帳號)。src/utils/evidenceMapper.js 的 mapFileEvidence 讀 e.file?.uid/e.file?.size/e.created_user/e.created_at,mapLinkEvidence 讀 e.description/e.reference_url——tree 補的鍵名對齊這份(扁平版),FE 卡才能一套 mapper 走到底。~/Projects/Billows/Audit-Manager/compliance-manager-be/infra/readmodel/oscal/ssp_control_implementation_query.py:184-199 SELECT 加欄
~/Projects/Billows/Audit-Manager/compliance-manager-be/app/oscal/service/ssp_control_implementation_service.py:549-562 dict 加鍵;函式結尾前 enrich
~/Projects/Billows/Audit-Manager/compliance-manager-be/common/util/audit_nickname.py enrich_audit_nickname_objs(reuse,不要再寫一支)
① SQL 加欄(get_file_link_evidences_by_job_ids):SELECT 加 je.uid, je.description, je.created_user, je.created_at, uf.uid AS file_uid, uf.size AS file_size。其餘不動(is_deleted = FALSE、evidence_type IN ('FILE','LINK')、ORDER BY 照舊)。
② dict 加鍵(job["evidences"].append({...})):補 "uid", "description", "file_uid"(None 時給 None 不給空字串), "file_size", "created_user", "created_at"(ISO 字串,照該 service 其他時間欄位的序列化方式)。name 的退回順序改成 file_name or description or reference_url or ""——LINK 有標題就顯示標題。既有六個鍵不改名不刪(抽屜與規劃頁還在讀)。
③ nickname enrich:build_control_tree_by_ssp_id 回傳前,把所有 evidences dict 收成一個 list 丟 enrich_audit_nickname_objs(...) 一次(批次查,不要在迴圈裡逐筆查)。照 app/flow_control/service/ar_objective_app_service.py:170 的用法。
先查再寫:grep -rn "enrich_audit_nickname" app/oscal/ 看該 service 是否已有 enrich 的呼叫點可以順便帶上;有就併進去,不要兩處各 enrich 一次。
不強制新 unit test(碎片規模)。若 test/ 下已有打 get_file_link_evidences_by_job_ids 或 control-tree 的測試檔,跑該檔確認沒弄壞:grep -rln "control_tree\|control-tree" test/ | head。
GET http://localhost:8000/api/1.0/ssp/<ssp_uid>/control-tree(帶 JWT),找到那個任務的 evidences[]。