本卡屬 FR-091(母卡 CM-1690)第二批。中量:有 DB 表(bulletins)、2 支 migration、3 條 route、2 個 entity 檔。範例是 jedi-asset(含
tests/integration/test_service_behaviour.py的 testcontainers 整合測試),照它做。主專案側接線已由 CM-1689 收進core/plugins/bulletin.py,本卡不動主專案。
jedi-bulletin(公告)是抽出時的舊形狀:plugin.py 一檔 407 行塞 6 個 dataclass,api/init.py 157 行裝守門與 ctx() 13 處,logger 用 "app"(會與主專案撞名)和 name 兩種,41 處施工日誌型註解(棒號、CM 號、「等發版」)。tests/integration/ 只有 conftest 與 initdb、0 支測試——有 DB 表卻沒有真資料庫的行為測試。本卡整成 jedi-asset 那個樣子。
首腦核對(2026-09-12):plugin.py 407 行 6 dataclass;api/init.py 157 行;route 3;entity 檔 2(0 dataclass);表 bulletins;migration 2 支(001 tables、002 rls-grants);tests 77 支(unittest+architecture);tests/integration/ 空骨架;harness 有 compose、無 --smoke;施工日誌 41 處;ctx() 13 處;logger "app"/name;有吐 created_user_name(17 處)但已走 D8 identity 欄位,不必再開新 port。主專案 venv 裡 jedi_bulletin.__file__ 指工作樹(path override 生效)。
套件:/Users/chouraymond/Projects/Jedicogy/module/jedi-python-package/jedi-bulletin/
範例:jedi-asset/(plugin/ 五檔、api/guards.py+routing.py、tests/unittest/test_plugin_layout.py、tests/integration/test_service_behaviour.py、harness/dev_app.py --smoke)
SOP:docs/features/FR-069-2608-jedi-module-extraction/extraction-sop.md §4.3(分檔)、§3.4(logger)、§6.1(harness)、§8(收工檢查表)
說明:docs/features/FR-089-2609-package-shape-unification/plugin-anatomy.md
主專案 import 面:grep -rn "from jedi_bulletin\|import jedi_bulletin" compliance-manager-be --include='*.py' --exclude-dir=.venv(3 檔,含 core/plugins/bulletin.py)
plugin.py → plugin/ 五檔(init/contract/runtime/assembly/migrations;有 migration 所以 migrations.py 要建,MIGRATIONS_DIR 記得 parent.parent);api/__init__.py → guards.py(runtime()+lazy decorator)+routing.py(URL 對照表)。對外 import 路徑一字不改:from jedi_bulletin.plugin import X、from jedi_bulletin.api import Y 照舊;__all__ 列齊。Blueprint(name, "jedi_bulletin.plugin") 第二參數寫死。rt);logger 全改 logging.getLogger("common.jedi_bulletin")("app" 那處是撞名,必改);route class 命名 <Type><動作>Route、domain service 屬性 self._repo。@dataclass,改前先 inspect.signature 把每個欄位的預設值抄下來、改後逐欄比對,不能漏預設值。tests/integration/ 不是刪,是填——見「要寫測試」。tests/unittest/test_plugin_layout.py(含突變);harness 補 --smoke(用 test client 打一輪就結束,不綁 port,照 jedi-system-core 或 jedi-asset 的寫法);pyproject.toml [tool.pytest.ini_options] 加 addopts = "--import-mode=importlib";README 補新結構與接線路徑。__all__ 符號 → 紅;contract.py 加一行 flask import → 紅)。tests/integration/test_service_behaviour.py:起真 postgres、套自己的 001/002 migration、對 app service 走一輪建立→列表→更新→刪除,斷言 RLS grant 下 cm_app 角色讀得到自己租戶、讀不到別人的。照 jedi-asset 那支的骨架抄,數量不求多,求「壞了會紅」。test_plugin_contract.py 的 URL/能力點/error code 凍結集合整理前後同綠。cd compliance-manager-be && .venv/bin/python -c "import jedi_bulletin;print(jedi_bulletin.__file__)"。指到 site-packages 就所有主專案側驗證加 PYTHONPATH=<套件目錄>,否則驗的是舊 wheel、假綠。pytest tests/ --import-mode=importlib(含整合測試,需 docker);python harness/dev_app.py --smoke;主專案 pytest test/test_module_boundaries.py;主專案 3 處 import 逐一 python -c 實跑。