範圍:把 Wave 2A disable 的三組「框架維護」route 重寫接 v2、註冊回舊 URL、對齊舊 shape → FE 零改動。 上游決策:framework CRUD 已用此原則 ship(BE 路由接回
/oscal-frameworks*、/oscal-framework*,FE 未動)。 撰寫日:2026-06-16 branch:feature/oscal-refactor(BE + 套件)
/oscal-framework-versions、/oscal-catalog-group …),主專案 app service 當 adapter 對齊舊 request/response shape。jedi_oscal 進 boot graph(撞 v2 MetaData 直接炸 — FR-038 第一鐵則)。所有重寫只接 jedi_oscal_v2 / v2 repo / raw SQL。EXCLUDE_MODULES 移除 + api/oscal/__init__.py 註冊舊 URL → BOOT + smoke + pytest 不多紅 → 顯式 git add commit。| 階段 | 內容 | FE 頁面 | 風險 | 主要 BE 工 |
|---|---|---|---|---|
| P1 = 2a 版本管理 | 版本 list(樹)/menu/get/create/update/delete | ComplianceFrameworkVersionManage |
低(B1 pattern) | 新 FrameworkVersionAppService;v2 FrameworkService 補 update_version/delete_version/樹過濾 |
| P2 = 2b catalog 編輯 | catalog-tree + group/control/AO 改/刪(draft+無 profile 引用守門) | FrameworkVersionEditView |
中 | 改寫 framework_version_edit_service 接 v2 catalog repos;v2 CatalogService 補 group/control/part update/delete |
| P3 = 兩階段 PDF 匯入 | parse-job:parse→預覽→confirm(decisions/overrides) | FrameworkImportPage |
高 | parse-job service 重寫成 v1-clean;需 v2「parse PDF→dict(不寫入)」能力 |
| URL | method | 用途 |
|---|---|---|
/oscal-framework-versions |
POST | 版本分頁列表,filters:framework_uid / parent_version_uid / is_root |
/oscal-framework-version/<uid> |
GET | 版本詳情 |
/oscal-framework-version |
POST | 新增版本 |
/oscal-framework-version/<uid> |
PUT | 更新版本 |
/oscal-framework-version/<uid> |
DELETE | 刪版本 |
| (版本 menu 若 FE 有用) | GET | 版本樹 menu |
uid, version, release_date, publish_status, framework_uid, framework_name, parent_version_uid, parent_version, catalog{概覽}, is_root, children[], created_user/_name, updated_user/_name, created_at, updated_at
註:v2
framework_versions欄位 = uid/framework_id/parent_id/version/catalog_id/publish_status/published_at;release_datev2 schema 是否有需驗(沒有就回 null 或用 published_at)。
FrameworkService 補(dev path-dep):
update_version(entity)、delete_version(uid)(repo 已有 update/delete_by_uid)list_versions_by(query) 支援 parent_id / is_root(parent_id IS NULL)過濾(query entity 已有 framework_id + parent_id)app/oscal/service/framework_version_app_service.py(@transaction,包 v2 FrameworkService):menu / list+pager(樹過濾 + framework_name enrich)/ get / create / update / delete;對齊舊 shape。oscal_containers.py 加 framework_version_app_service provider。oscal_framework_version_route.py 改 import 新 app service(拔 v1 OscalFrameworkVersionService)。config/di_modules.py 移除 oscal_framework_version_route;api/oscal/__init__.py 註冊舊 URL。framework_versions 有無 release_date 欄位(FE 讀 release_date);無 → adapter 補 null 或對應欄位。catalog 概覽(控制數);需要就 enrich。| URL | method | 守門 |
|---|---|---|
/oscal-framework-version/<uid>/catalog-tree |
GET | — |
/oscal-catalog-group/<uid> |
PUT / DELETE | draft + 無 profile 引用 |
/oscal-catalog-control/<uid> |
PUT / DELETE | 同上(PUT 支援跨 group 搬家) |
/oscal-catalog-control-assessment/<uid> |
PUT / DELETE | draft(PUT 支援跨 control 重綁) |
CatalogService 補(dev path-dep):get_catalog_tree_by_version 或重用既有 get_control_tree;update_group/update_control/update_part、delete_group/delete_control/delete_part(repo 已有 update/delete_by_uid + 級聯需自寫)。app/oscal/service/framework_version_edit_service.py:拔 v1 catalog domain service import,改接 v2 CatalogService / v2 catalog repos;保留雙軌守門(_require_draft + _has_profile_references 改查 v2 profile_imports)。framework_version_edit_route(含 catalog_control_assessment 同檔);註冊舊 URL(/oscal-catalog-group 等)。| URL | method | 用途 |
|---|---|---|
/oscal-framework-parse-jobs |
GET | 列進行中草稿(status filter) |
/oscal-framework-parse-jobs/parse |
POST | Step1 上傳 PDF(multipart)→ 解析存 job |
/oscal-framework-parse-jobs/<uid> |
GET | 取 parsed_result 預覽 |
/oscal-framework-parse-jobs/<uid>/confirm |
POST | Step2 decisions+overrides → 寫 catalog/version |
/oscal-framework-parse-jobs/<uid> |
DELETE | 軟刪 |
{ groups:[{uid,name,description,parent_group_uid,order_no}], controls:[{uid,control_id,control_title,description,guidance,group_uid,order_no}], assessments:[{uid,name,description,control_uid,order_no}] }
OscalImportService.parse_pdf_to_dict + import_from_dict → 不能進 boot graph。CatalogService.import_catalog_from_pdf 是 parse+寫一次完成;兩階段需「只 parse 出 dict 供預覽」。
parse_pdf_to_dict(stream, parser_code) -> dict(把 v1 parser 邏輯搬進 v2,與 import_catalog_from_pdf 共用底層 parser)。add_catalog_from_dict 或用 add_catalog + entity 組裝)。oscal.framework_parse_jobs 表在主專案 infra(已存在);parsed_result/import_summary 是 JSONB,與套件無關,可留。import_catalog_from_pdf 內部 parser,抽出 parse-only)。parse_pdf_to_dict + 「from dict 寫入(含 decisions 後的最終 dict)」。framework_parse_job_service 接 v2(拔光 v1 import)。create_app() BOOT OK + python -m pytest test/ 不多於 baseline 紅(baseline-diff)+ 顯式 git add commit(BE 與套件分開)。pyproject.toml dev path-dep 勿 commit。oscal_profile_route)/ catalog_control_assessment 獨立 route — 視 FE 是否用到再評估。