FR-047 SSP 子頁 field-level 化 + 規劃頁深化 — 換 session 交接(2026-07-06)

§1

🧭 原始需求(WHY,先懂再動)

user 要的是給新人開發 / 追蹤用的「詳細規格書」,不是概覽。核心原則(user 原話):

「你都用 CRUD 帶過,但是要 CRUD 到哪裡、用哪些 API、畫面欄位是怎樣,都沒寫工程師怎麼開發?怎麼追蹤?這是一份詳細規格書,希望得到詳細的參考資訊,而不是敷衍帶過。」

所以每個功能要到 field-level:每個畫面欄位(label / 型別 / 必填 / 列舉值 / disabled 條件 / 存哪個 DB 欄或 props 鍵)、每支 API(method + path + 逐欄 request/response 表)、每個 error code、DB jsonb 內部結構。「CRUD 帶過」「指向 GAI-SD-02」= 不合格

合格範本已寫好 → 讀 docs/specs/v1.8.0/project-management/project-ssp-inventory.md(資產頁,§5 逐欄表單 / §6 完整 request-response 欄位表 / §9 jsonb 結構 / §12 逐坑)。

§2

§0 冷接自檢 gate(動手前先答)

  1. 為什麼 SSP 編輯器要拆 5 個子頁?→ 答:元件·授權·資產是同一 UI tab 但 3 個不同實體 / API,要詳細就各自一頁;單位+人員是同一 /parties API 只差 type 過濾,合一頁避免重複 drift。
  2. schema 事實來源是哪個檔?→ 答:scripts/deliverables/out/db_schema.json不是 docs/system-design/.../tbls/*.md,那份會 drift,本 session 已踩到:元件 tbls 版寫 ssp_id/component_type/leveraged_authorization_uid 欄,db_schema.json 才是 system_implementation_id/uuid/type,且 leveraged_authorization_uid 在 props 不是欄位)。
  3. 可以 commit / push 嗎?→ 答:branch = main,本 session 全部未 commit,等 user 明示才 commit,push 永遠等 user。build 出的 html/ 依規則先不 commit。
  4. 走哪個 skill?→ writing-feature-specs(13 節模板 + 事實來源紀律 + build 驗證)。

§3

Session 已完成(都在 working tree,未 commit,branch main)

本 session 是「FR-047 手冊可讀性/詳細化」大 arc,做了六大塊(詳見對應頁):

  1. §6 API 格式一致化(30 頁):全站 §6 endpoint 清單改表格、request/response 改欄位表(不再擠散文)。
  2. UC 全展開(18 核心頁):每個有實質後端邏輯的功能補完整 UC + 流程圖,~22 個新 UC + 圖;忠實紀律(endpoint/error code 抄該頁、沒寫用中性字)。
  3. UC 缺口補圖(4 張):UC-PL-03(Drive 同步)、UC-CI-02(中斷連線)、UC-RA-02(對帳)、UC-PO-03(開始執行任務)。
  4. project-settings 退役 + 內容遷移project-settings.md 刪除(route 已孤兒,內容併入規劃頁);基本資訊/參與人員 → 規劃頁 UC-PP-09(含 ⚠️ PUT /grc/project 無角色守門安全 finding 搬進 §12 坑 11);cloud-integrations.md 5 處「專案設定頁」措辭修正。
  5. 3 個新子頁evidence/document-pool.md(程序書池,Tab4)、evidence/project-cloud-integration.md(專案雲端 verify-repair,Tab5)、project-management/project-ssp-edit.md(SSP 編輯器 hub,Tab1)。
  6. NAV 調序project-ap-list(稽核輪次清單)移到 project-overview 前(照下鑽動線);規劃頁 §5 加「六個 Tab 對照表」(每 Tab 指向真頁,0 死指標)。
  7. SSP 編輯器 5 子頁(進行中):pilot project-ssp-inventory.md 已寫完驗證;其餘 4 頁待寫(見待辦 A)。

驗證狀態:全部 build ✅(58 頁)、自查敏感資訊/「GRC 系統」= 0、新圖 error code 逐一比對防杜撰、斷圖 0。


§4

待辦(下個 session 執行,按序)

A. 完成 SSP 編輯器其餘 4 子頁(facts 已蒐集驗證,直接寫)

範本 = project-ssp-inventory.md(已寫好的第 5 頁)。放 docs/specs/v1.8.0/project-management/

待寫頁 實體 / API FE 元件
project-ssp-basic.md 系統特性 /system-characteristic SspBasicSection.vue
project-ssp-parties.md 參與方 /parties(單位+人員合一) ModuleFramePartiesPanel.vue
project-ssp-components.md 元件 /components SspComponentsLeveragedInventoryTab.vue
project-ssp-leveraged.md 利用授權 /leveraged 同上

已驗證 facts(本 session 5 隻 Explore agent 掃出 + 對 db_schema.json/routes.json/BE code 核過,直接用不必重跑):

共用(4 頁都適用)

  • 權限:require_participant(讀)/ require_manager(寫 = manager + AP=planning)。碼:GRC_403051(GRC_NOT_PROJECT_MANAGER)、GRC_412028(GRC_SSP_EDIT_AP_NOT_ACTIVE,AP 關閉/封存)。
  • gate:canEdit = apStatus==='planning' && role==='manager';launch-audit 後 living SSP 凍結唯讀。
  • endpoint 全在 /ssp/{ssp_uid}/...(已驗 routes.json 存在);表全在 oscal schema(已驗 db_schema.json)。
  • pattern:FE apiBase 切 ssp vs module-frame;共用 ModuleFrame*Service mapper;props jsonb = [{name,value}] 非破壞性合併;無 socket;composable cache(useSsp*)。

① project-ssp-basic(系統特性,1:1 upsert)

  • endpoint GET/PUT /ssp/{uid}/system-characteristic
  • FE 表單 8 欄(SspBasicSection.vue):name(範圍名稱,InputText,必填→system_name) / system_identifier(範圍識別碼→system_ids[0].id jsonb) / security_sensitivity_level(安全分類等級,Dropdown low·moderate·high,預設 high) / target_type(範圍類型→props[target-type]) / status(運行狀態,Dropdown active·under-development·disposition·other——FE 只 4 種,DB status_state 有 5 種缺 under-major-modification) / owner_uid(範圍負責人,Dropdown searchable userMenu→props[owner-uid]) / scope_description(授權邊界描述,Textarea→authorization_boundary_description) / description(描述,Textarea)。
  • serializer:SspSystemCharacteristicUpdateSchema(全欄 allow_none,route strip None)/ SspSystemCharacteristicResponseSchema
  • DB oscal.ssp_system_characteristics(ssp_id UNIQUE 1:1):system_name/system_name_short/description/security_sensitivity_level/date_authorized/system_ids(jsonb)/status_state(varchar40)/status_remarks/authorization_boundary_description/authorization_boundary_props(jsonb)/props(jsonb: target-type + owner-uid)。
  • props 非破壞性合併;FE 空值 → placeholder(fips 預設 high、status 預設 active)。
  • 檔:route api/oscal/routes/ssp/ssp_system_characteristic_route.py、serializer api/oscal/serializers/ssp/ssp_system_characteristic_inproject.py、service app/oscal/service/ssp_system_characteristic_app_service.py、mapper app/module_frame/service/module_frame_system_characteristic_service.py

② project-ssp-parties(參與方,單位+人員合一頁)

  • endpoint GET/POST /ssp/{uid}/parties、PUT/DELETE .../parties/{party_uuid}party-type prop = organization / person 過濾。
  • DataTable:名稱/職稱、角色(Tag)、email、phone、address、鉤稽狀態、action。
  • Dialog 欄位:matched_user_id/matched_org_unit_id(鉤稽,Dropdown person→userMenu·org→orgUnitMenu,選填) / role(Dropdown 9 OSCAL role,必填,預設 person=system-owner·org=responsible-organization) / name(必填,編輯時 disabled 自然鍵) / email_address/telephone_number/address(選填)。
  • 9 role(seed SQL scripts/sql/2026-05-22-seed-oscal-ssp-roles.sql:responsible-organization / system-owner / system-security-officer / authorizing-official / information-owner / information-provider / information-receiver / prepared-by / prepared-for。Menu:GET /system/menu/ssp_party_role
  • serializer SspPartyUpsertSchema(party_type OneOf person·organization / name / role / title / email_address / telephone_number / address / matched_user_id / matched_org_unit_id);Response 多 enrich:matched_user_uid / matched_user_name / matched_org_unit_name。
  • 映射:party_type→parties.type、name→parties.name、email_address→email_addresses0、role·title·telephone·address·matched_*→props;party 透過 metadata_id 掛 SSP,無 mapping 表
  • DB oscal.parties:metadata_id / uuid / type / name / short_name / email_addresses(text[]) / telephone_numbers(jsonb) / addresses(jsonb) / props(jsonb: role+title+telephone+address+matched_*)。
  • 碼:GRC_400014(INVALID_PARTY_TYPE) / GRC_400015(PARTY_NAME_REQUIRED) / GRC_400016(PARTY_ROLE_REQUIRED) / GRC_404024(PARTY_NOT_FOUND) / GRC_403051 / GRC_412028。
  • 坑:party_uuid 被 ap_task_participants + ssp_leveraged_authorizations 軟參照(無 FK),刪 party 無保護(follow-up)。
  • 檔:api/oscal/routes/ssp/ssp_party_route.pyapi/oscal/serializers/ssp/ssp_party.pyapp/module_frame/service/module_frame_party_service.py

③ project-ssp-components(元件)

  • endpoint GET/POST /ssp/{uid}/components、PUT/DELETE .../{item_uid}
  • DataTable:類型(Tag)/名稱/描述/狀態/利用授權(Chip)/協定/安全機制。
  • Dialog:title(名稱,必填) / component_type(類型,Dropdown 15 項,預設 system/BE 預設 software) / description(Textarea) / purpose(Textarea) / status(Dropdown 5:operational·under-development·under-major-modification·disposition·other) / leveraged_authorization_uid(Dropdown 來源 GET /leveraged) / protocol·port_ranges·security_auth(InputText→props)。
  • 15 component_type:this-system·system·service·interconnection·hardware·software·network·policy·physical·process-procedure·plan·guidance·standard·validation·other。
  • ⚠️ DB 以 db_schema.json 為準(tbls .md 有 drift,勿用):oscal.ssp_components = system_implementation_id / uuid / type / title / description / purpose / status_state / status_remarks / responsible_roles(jsonb) / protocols(jsonb) / props(jsonb: protocol+port_ranges+security_auth+leveraged-authorization-uid) / links。 leveraged_authorization_uid 欄(在 props)、 tenant_id/is_active。
  • 碼:GRC_404034(SSP_RESOURCE_NOT_FOUND) / GRC_403051。坑:component uuid 被 inventory implemented_components 軟參照。
  • 檔:api/oscal/routes/ssp/ssp_components_route.pyapp/oscal/service/ssp_components_app_service.py、mapper app/module_frame/service/module_frame_components_service.py

④ project-ssp-leveraged(利用授權)

  • endpoint GET/POST /ssp/{uid}/leveraged、PUT/DELETE .../{item_uid};FE service 帶 'ssp' apiBase。
  • DataTable:名稱/提供者/FedRAMP Package ID(⚠️未實現)/影響等級(⚠️未實現)/資料類型(⚠️未實現)/授權日期/關聯元件數。
  • Dialog:title(授權名稱,必填) / provider(提供者) / date_authorized(Calendar,FE null→BE date.today()) / description(Textarea) / purpose(Textarea) / category(Dropdown 4:leveraged-authorization·external-service·interconnection·other,預設 leveraged-authorization) / status(Dropdown 5 同元件)。⚠️ Dialog 無 party_uuid 欄(硬置 null,註「日後 party picker UX」)。
  • props 存 provider/description/purpose/status/category(DTO 攤平到頂層)。
  • DB oscal.ssp_leveraged_authorizations:system_implementation_id / uuid / title / party_uuid(NN,null 時存 NIL-UUID 哨兵 00000000-...,軟參照 parties.uuid) / date_authorized / props / links / remarks。
  • 碼:GRC_404034 / GRC_403051。
  • 已知缺口(寫進 §12):fedramp_package_id / impact_level / data_types 清單顯示但 CRUD response 無回傳(只在 Excel/docx 路徑處理);party_uuid picker 未實作;remarks 無 Dialog 欄。
  • 檔:api/oscal/routes/ssp/ssp_leveraged_route.pyapp/oscal/service/ssp_leveraged_app_service.py、mapper app/module_frame/service/module_frame_leveraged_service.py

寫完 4 頁後的收口

  • project-ssp-edit.md 從「完整頁」改成 hub:§1.1 各子區「詳述」欄改指這 5 個子頁;§6/§9 的詳細內容可精簡成「見各子頁」(保留概覽 + Excel 匯入那條跨子區的留 hub)。
  • NAV_STRUCTURE(scripts/deliverables/render_html.py):把 5 子頁巢狀在 project-ssp-edit.md(現在 project-ssp-edit 已巢狀在 project-planning 下,改成兩層:planning →[ssp-edit →[basic,parties,components,leveraged,inventory]],或平掛 project-management 群,擇一)。
  • build 驗證:57→62 頁全 ✅;每頁新圖 error code 逐一 grep 該頁 md 確認非杜撰;自查敏感/GRC系統=0。

B. 規劃頁 §2 深化(user 拍板:全部第②類 = 功能 1/4/13/15/16 補到 field-level

規劃頁 17 項裡「有真表單、卻只到 UC 流程圖級」的 5 項,要補逐欄 field-level。方法同 A(先 Explore 掃 FE 表單欄位 + BE serializer + db_schema,再親自寫):

功能 現況 要補 主 FE 元件 / endpoint
4 任務檢視與編輯 ← 最大、最像「CRUD 帶過」 UC-PP-02 流程 拆獨立子頁(建議 project-task-edit.md):任務表單逐欄(名稱/描述/指南/類型 general·survey/指派人員/部門/設備/問卷+審核人)+ full-replace 語意 + 關聯四表 ProjectPlanningView AO 面板 / 任務卡;PUT /grc/project/{uid}/job/{jobId}
1 控制項/AO 現況編輯 UC-PP-01 流程 補 field 表:implementation_status(5 種列舉)+ implementation_description + AO 備註 PUT /ssp/{uid}/control-implementation/{cid}.../objective/{stmtId}
13 群組/控制項參與人員 UC-PP-08 流程 補 field 表 + endpoint 逐欄 POST/PUT/DELETE /control-group-participant/project-control-participant
15 專案基本資訊 UC-PP-09 補 field 表(PUT /grc/project 欄位,可參 project-list.md §6.3 已有的 PUT 表) PUT /grc/project/{uid}
16 專案參與人員 UC-PP-09 補 participants 全量覆寫 field 表(role 4 值 / owner 保護) 同上 participants 欄

第③類不動(現有深度剛好):3 樹導覽搜尋、7/8/9/10 Excel 匯出入(wizard 三步流程圖夠)、11 進度卡、12 階段推進、5/6 快速配置/啟動。

C. commit(等 user 明示才做)

本 session 未 commit 量極大(35 md source + 39 新 dot + render_html.py),強烈建議分主題 commit 避免混在一起難 review:

  1. §6 API 格式一致化(30 頁)
  2. UC 全展開(18 頁)+ UC 缺口補圖(4 圖)
  3. project-settings 退役 + UC-PP-09 遷移 + cloud-integrations 修正 + NAV 調序 + §5 tab 表
  4. SSP 5 子頁 + document-pool + project-cloud + project-ssp-edit hub
  5. 規劃頁深化(待辦 B 做完後)

commit 鐵則:顯式 git add <檔名>、禁 -am/add -A;避開別線 WIP(docs/specs/v1.8.0/evidence/assets/img/ 截圖 session、FR-046 tracker、docs/交付文件/*.docxdocs/features/ddd-layer-audit/)。html/ 依規則暫不 commit(等 source 收斂再連 source 一起)。push 永遠等 user 明示。


§5

方法論 / 鐵則(本 session 驗證有效,沿用)

  1. 事實蒐集用 Explore 唯讀 agent、主 session 自寫 md(tracker 教訓 #6 已證;本 session 5 隻欄位級 Explore 產出優)。派 agent 的 prompt 要求:FE 表單每欄 label/型別/列舉/必填/disabled + BE serializer 逐欄 + db_schema jsonb 結構 + error code,標檔:行號,查無就說查無不編。
  2. schema 一律對 db_schema.json(不信 agent 憑元件名猜、不信 tbls .md);endpoint 對 routes.json;error code 開 common/code/grc_error_code.py 逐一 grep 確認真有(本 session 11 個碼全驗過)。
  3. 防杜撰驗證:新圖裡的 error code 逐一 grep 該頁 md 是否真有出處(本 session 靠這抓到縮寫式誤判 + 確認零杜撰)。
  4. 每頁寫完必 buildpython3 scripts/deliverables/render_html.py "docs/specs/v1.8.0"(全 ✅);.dot 先 dot -Tsvg <檔> -o /dev/null 驗編譯;自查 grep -rEn '192\.168\.|password\s*=|Billows@' <檔> = 0、grep 'GRC 系統' = 0。
  5. 13 節模板 + 圖形化慣例:見 writing-feature-specs skill 的 references/page-spec-template.md;配色海軍藍 #13294B / 判斷菱形 #FFF6E5 / 例外 #FDEBD3 / 錯誤 #F8DCDC / 成功 #D9E9DC。
  6. branch main 不切、未 commit 全留 working tree、push 等 user

§6

座標

  • 主 tracker:docs/features/FR-047-2607-feature-spec-handbook/tracker.md
  • 合格範本(field-level 深度):docs/specs/v1.8.0/project-management/project-ssp-inventory.md
  • SSP 編輯器 hub:docs/specs/v1.8.0/project-management/project-ssp-edit.md
  • 規劃頁(含 §5 六 Tab 表 + UC-PP-01~09):docs/specs/v1.8.0/project-management/project-planning.md
  • SOP:writing-feature-specs skill(13 節)、closing-and-handoff skill(本文件)
  • 事實 dump:scripts/deliverables/out/{db_schema,routes}.json
  • NAV_STRUCTURE:scripts/deliverables/render_html.py(約 line 268 專案管理群 / 297 證據管理群)