本卡屬 FR-144(母卡 CM-2837),稽核計畫清單改成依專案分組展開的後端半邊。決策者 2026-10-17 看過分組雛形後裁「直接取代平列版」。會改碼,FE 由 FR-144.4 接。
清單頁要改成「一個專案一列、點開看每一次」。現在後端是一頁 20 個稽核次在分頁,同一個專案的三次可能被切在兩頁,前端分組會分不完整。所以分頁單位要改成專案:一頁回 10 個專案,每個專案帶它全部符合條件的稽核次,前端只負責畫。
infra/readmodel/audit/audit_plan_list_query.py:125-139 list_page:現在 ranked CTE 一列一稽核次 LIMIT/OFFSET
infra/readmodel/audit/audit_plan_list_query.py:26-36 _SORT_SQL/_DEFAULT_ORDER:現在排的是稽核次
app/readmodel/service/audit_plan_list_service.py:16-33 list_my_audit_plans
api/project/serializers/audit_plan_list.py response schema
api/project/routes/audit_plan_list_route.py POST /audit-plans/my/list
雛形(排序鍵、目前這一次、預設展開的判斷都在裡面): BE docs/features/FR-144-2610-my-audit-plans-sidebar-entry/prototype/my-audit-plans-grouped.html(BE 根 python3 -m http.server,右上可切回平列版)
ranked CTE(一列一稽核次、已套狀態與搜尋篩選),外面再包一層:proj AS (SELECT project_id, ... 目前這一次的各欄 ... FROM ranked GROUP BY project_id)。「目前這一次」用 DISTINCT ON (project_id) ... ORDER BY project_id, status_rank, plan_due NULLS LAST, pass_id DESC 取。status_rank 必須是 audit_planning 0、auditing 1、pending_reverify 2、remediation 3、closed 4——開工先核 _ROW_SELECT 的 status_rank 是否已是這個順序,不是就改。proj 層做:ORDER BY <專案層排序> LIMIT :limit OFFSET :offset,count(*) OVER () 是專案數。排序鍵取目前這一次的欄位(_SORT_SQL 各鍵照舊名,只是作用在 proj 層);預設 status_rank, plan_due NULLS LAST, project_id。ranked 裡的全部稽核次(同一組篩選),依 round_no, pass_no(由舊到新)排,Python 組回每個專案。稽核人員/經理照現行 _attach_people 批次補到每個稽核次。data 改成專案陣列,每筆 {project_uid, project_name, framework, pass_total(該專案全部可見稽核次數,不套狀態與搜尋), passes:[…現行一列的全部欄位…], current_pass_uid};meta 照 ResponseMetaSchema(total=專案數)+status_counts(仍算稽核次,現行 _status_counts 不動)。pass_total 給前端判「只有一次就不展開」與「共 N 次稽核」;passes.length < pass_total 就是有篩選(前端印「符合篩選 M 次」)。