# FR-065.0 DB 初始化基線——盤點報告（CM-1207 盤點棒）

- **日期**：2026-08-15
- **性質**：唯讀盤點。本文件是「從零建庫需要什麼」的完整清單與方案草案，**不含任何已執行的 DB 異動**。
- **資料源**：DEV DB `192.168.50.188:25432/guidant_ai_dev`（帳號 cmmgr，全程唯讀：`pg_dump --schema-only`、`SELECT`、catalog 查詢）＋ BE repo `scripts/sql/` ＋ jedi-auth 套件源碼。
- **母案**：CM-1189（FR-065 落地版 Installer）；本卡 CM-1207。
- **路徑註記**：派工單寫 `docs/features/FR-065-2608-installer/`，但 `docs/features/README.md` 登記名為 `FR-065-2608-onprem-installer`，依 FR 編號鐵則採 README 登記名。

---

## 1. Schema 全量盤點

### 1.1 總量（DEV 實況，2026-08-15 pg_dump 為準）

| 項目 | 數量 | 備註 |
|---|---|---|
| PostgreSQL 版本 | 16.4 | Debian 套件版 |
| Schema | 5 | `public`(57 表)、`compliance`(45)、`oscal`(58)、`config`(11)、`survey`(15) |
| Table | 186 | 含 2 張分區母表（`public.api_logs`、`public.system_logs`）與其月分區子表 |
| Sequence | 156 | |
| Index | 579 | |
| View | 6 | `v_role_routes`、`v_user_capabilities`、`v_user_routes`、`vw_user_job_queue`、`debug_org_units`、`v_tenant_parent_debug`（後兩支為 debug 用，是否出貨待裁決） |
| Function | 82（去除 extension 後約 40 支自訂） | `app_*` RLS helper 一族、`trg_*` trigger function 一族、`get_user_task_queue`（SP）、`maintain_log_partitions`、`scope_rank`、`set_tenant_path` 等 |
| Trigger | 18 | touch/validate/fill-tenant 類 |
| Event trigger | 1 | `trg_auto_grant_cm_app`（見 §2） |
| RLS 啟用表 | 29 | policy 共 107 條 |
| Extension | `uuid-ossp` 1.1、`pg_trgm` 1.6（+內建 plpgsql） | init 必裝 |
| pg_dump --schema-only | 31,119 行 | 含 400 行 GRANT、18 行 ALTER DEFAULT PRIVILEGES、107 行 CREATE POLICY |

分區維護：`maintain_log_partitions()` 負責 `api_logs` / `system_logs` 月分區滾動；init 時需建立母表＋當月分區＋default 分區（DEV 現況有 2026_05~2026_08 各月子表——歷史月份子表**不屬基線**，init 只需母表＋default＋當期）。

### 1.2 版位追蹤三張表現況

| 表 | 現況 | init 基線角色 |
|---|---|---|
| `public.schema_migrations` | 138 筆（filename / applied_at / note），首筆 `__baseline_pre_2026-05-28__` 是上次基線化的 marker | **基線版位標記主體**——init 完成時應把「已收斂進基線的 migration 檔名」全數登記（或登記一筆新 baseline marker），讓後續增量 migration 判斷起點（方案見 §5） |
| `public.schema_version` | 2 筆（1.4.0 / 1.5.0 semver stamp） | init 收尾補一筆基線版號 |
| `public.alembic_version` | 1 筆 `f20ca741a9bd` | ⚠️ **待裁決**：repo 內無 alembic 目錄，此值來源不明（推測是 legacy 或某 jedi 套件早期 migration 殘留）。需查明是否有任何程式在讀它；若無 → 基線不帶此表 |

### 1.3 對照 scripts/sql/ migration 串

- `scripts/sql/` 有 224 支 `.sql` ＋ `manifest.tsv`（CM-1086 建，四欄：filename/phase/envs/note）。
- manifest 分類：**pre-baseline 83 筆**（永不套，2026-05-28 baseline 之前的歷史）＋ **active 138 筆**。active 中 127 筆 envs=`*`、11 筆是環境限定（dev/stg/poc 專屬——如 DEV cleanup、STG cutover 類，**不屬產品基線**）。
- DEV `schema_migrations` 登記 138 筆與 manifest active 段一致（含 `__baseline_pre_2026-05-28__` marker 與 2 支無日期前綴的 oscal-v2 檔）。
- **結論**：基線收斂的「真相」取 DEV pg_dump 實況；manifest.tsv 已提供哪些 migration 屬環境專屬（不進基線）的判準，收斂時逐支核對 envs 欄即可。
- 隨附資產：`scripts/sql/view/vw_user_job_queue.sql`、`scripts/sql/store_procedure/sp_get_user_task_queue.sql`（view/SP 的 canonical 源，dump 內已含定義）、`scripts/sql/seeds/bpmn/` 4 支內建 BPMN（builtin-full-audit / builtin-full-audit-with-review / builtin-internal-check / builtin-self-assessment，對應 flow_templates 內建流程）。

---

## 2. Table 權限現況 diff（cm_app）

### 2.1 掃描結果：**目前零缺口**

用 `has_table_privilege` / `has_sequence_privilege` / `has_function_privilege` 對 cm_app 全量掃描（5 schema、186 表、156 sequence、6 view、全部 function）：

- 表缺 SELECT/INSERT/UPDATE/DELETE 任一者：**0 張**
- Sequence 缺 USAGE：**0 支**
- View 缺 SELECT：**0 支**；Function 缺 EXECUTE：**0 支**

「歷史 migration 常漏 GRANT」的坑在 DEV 已被兩層機制補平：

1. **ALTER DEFAULT PRIVILEGES**：五個 schema 都設了（grantor=cmmgr）——tables `SELECT,INSERT,UPDATE,DELETE`、sequences `USAGE,SELECT,UPDATE`、functions `EXECUTE` 自動授予 cm_app。之後由 cmmgr 建的新物件天生有權限。
2. **Event trigger `trg_auto_grant_cm_app`**（`auto_grant_cm_app_on_new_schema()`）：CREATE SCHEMA 時自動 `GRANT USAGE` ＋補設該 schema 的 default privileges。

→ **基線 init 的正確做法不是逐表 GRANT 400 行，而是複製這套機制**：建 schema 後先設 default privileges，再建物件；event trigger 一併帶入。逐表 GRANT 僅作為驗收檢查（掃描 SQL 可直接沿用本次盤點語句）。

### 2.2 DB 角色現況與 RLS 關係

| Role | 屬性 | 用途 |
|---|---|---|
| `cmmgr` | LOGIN, **SUPERUSER**, CREATEDB, CREATEROLE, **BYPASSRLS**；DB owner | 管理帳號：套 migration、init。RLS 對它無效 |
| `cm_app` | LOGIN（無任何特權，**受 RLS**）；member of `cm_app_group` | 應用程式連線帳號（`.env` DB_USER） |
| `cm_app_group` | NOLOGIN 群組 | 目前僅 cm_app 一個成員；群組自身未見額外授權（實際授權都直接給 cm_app）——基線可簡化或保留，**待裁決（傾向保留以利未來多 app 帳號）** |
| 其他（`ammgr`/`nicsmgr`/`camunda`/`audit_manager_mgr`） | 同主機他系統/legacy 角色 | **不屬本產品基線**，init 不建 |

RLS 運作方式：107 條 policy 全部掛在 `public`（即對所有非 BYPASSRLS 角色生效），判斷條件不是 DB role 而是 **session GUC**——`app.user_id`、`app.allowed_tenant_paths`、`app.is_super_admin` 等，由 `session_scope()` 每次查詢前注入（helper：`app_tenant_allowed_for_session()` 一族）。因此：

- cm_app 的資料隔離完全靠「應用層注入 GUC ＋ policy」實現，**不依賴 per-tenant DB 帳號**；
- cmmgr 因 BYPASSRLS 可做系統層寫入（seed、migration）；
- **init 對 RLS 的責任＝把 29 張表的 ENABLE ROW LEVEL SECURITY ＋ 107 條 policy ＋ `app_*` helper functions 原樣建齊**（皆已含在 pg_dump 內）。
- 另注意 `pg_db_role_setting` 為空——沒有任何 DB/role 層級的 GUC 預設值，不需搬。

---

## 3. Seed 資料逐表分類草案

分類定義：**①產品必備**＝新客戶空庫必 seed；**②環境相依**＝installer 參數化或安裝後由管理介面設定；**③DEV 殘留**＝不隨產品出貨。業務資料表（projects / ssp / 評鑑 / survey 答題 / job 執行 / log 類）在新庫本來就該是空的，不逐一列出——DEV 裡它們有資料屬開發測試產物，全數不出貨。

### 3.1 ①產品必備（字典/系統定義類，值不因客戶而異）

| 表 | DEV 行數 | 判斷理由 |
|---|---|---|
| `public.operations` | 8 | 操作類型字典（VIEW/INSERT/…/VERIFY），程式 enum 對應 |
| `public.system_menus` | 73 | 16 組下拉選單字典（ANS_TYPE/DEVICE_TYPE/STORAGE_TYPE/TASK_TYPE…），UI 依賴 |
| `public.ui_routes` | 53 | 前端選單樹（真選單來源），有 unique(name) 約束 |
| `public.capabilities` | 130 | 權限能力字典（is_platform 24／一般 106），FR-048 授權體系核心 |
| `public.route_capabilities` | 136 | 路由↔capability 綁定 |
| `public.tenants` | 只取 id=1 | root tenant（`Guidant.AI`，path `/1/`）——B-2 模型：系統級資源掛 root，「tenant_id NULL＝壞資料」。**各環境 root 固定 id=1 是硬約定**（migration 直接寫字面值 1），init 必須保證 |
| `public.org_units` | 只取 id=1 | root org unit（同上，id=1 硬約定） |
| `public.roles` ＋ `role_capabilities` | 只取 root 的 `Administrator`（DEV id=2，掛 130 條 capability） | 平台管理員角色。其餘 10 個 role 皆 tenant-scoped（DEV/測試租戶的），不出貨 |
| `public.users` ＋ `user_tenants`/`user_org_units`/`user_roles` | 只取 1 個超管帳號 | 初始 admin（見 §4）；**密碼不出廠寫死，安裝時產生** |
| `public.system_configs` 之 `RUNTIME_CONFIG` 群 | 7 筆（tenant 1） | 登入/密碼/JWT 運行參數（CHANGE_PASSWORD_THRESHOLD_DAYS=90、JWT_*_EXPIRES、LOGIN_* 鎖定、MFA_REQUIRED），FR-063.1g 已有 seed migration `2026-08-14-fr063-1g-runtime-config-seed.sql` 可直接復用 |
| `public.system_configs` 之 `WEB_IDEL_CONFIG` | 1 筆 | 前端閒置逾時預設值 |
| `config.detection_tools` | 8 | 檢測工具定義（openvas/nessus/sonarqube/openscap/zap/inspec(cinc)/nmap/gcb），FR-056~058 一整串 seed migration 的收斂結果 |
| `config.detection_tool_param_schemas` | 14 | 各工具參數 schema |
| `compliance.flow_templates` | 只取 tenant 1 的 4 筆 | 內建稽核流程範本（對應 `scripts/sql/seeds/bpmn/` 4 支 builtin BPMN）；tenant 102 的 9 筆是 DEV 自建測試 |
| `public.schema_migrations` / `schema_version` | — | init 收尾 stamp（§1.2、§5） |

### 3.2 ②環境相依（installer 參數化，或出廠帶「未啟用」空殼）

| 表 | DEV 行數 | 說明 |
|---|---|---|
| `public.system_configs` 之 `SMTP` | 1 | 寄信主機——安裝時填或裝完後台設定；出廠建議帶 disabled 空殼 |
| `public.system_configs` 之 `STORAGE_CONFIG` | 3（tenant 1/102/131 各一） | MinIO/儲存後端座標——**只出貨 root（tenant 1）一筆**且值參數化（bucket/endpoint 隨客戶環境） |
| `public.system_configs` 之 `THIRD_PARTY_LOGIN`(LDAP) | 2 | 客戶自家 AD/LDAP——不出廠帶值，後台設定 |
| `config.tenant_licenses` / `tenant_license_events` / `public.license_clock_watermark` | 25/29/1 | FR-062 license 導入後 runtime 自建——**init 不 seed**，首次匯入 license 時產生（watermark 亦 runtime 初始化） |
| 初始 admin 密碼 | — | 安裝時隨機產生或安裝者輸入（§4/§5） |

### 3.3 ③DEV 殘留（不出貨）

- **測試租戶整族**：tenants 102(Billows Tech)/131(歐洲航空)/152/153/158(JEDI) 及其 org_units、roles、users（blsadmin/blsit/e2e_* 等 38 個帳號）、module_frames 154 筆、flow_templates 9 筆、surveys、devices、labels 泰半、issues/feedback_issues、drive_* 整族、totp_secrets、tenant_drive_integrations。
- **業務資料**：projects 210、job_executions 1 萬+、workflow_executions、SSP/AP/AR/POA&M 全族、question_answers、upload_files 2668、login_tokens/login_logs、api_logs/system_logs 分區資料。
- **明確垃圾表**：`survey.question_answers_dedup_backup_20260428`、`config.detection_tool_profiles_deprecated_20260803`、`public.system_logs_old`——**基線 schema 不帶這三張**（連結構都不帶）。
- `public.system_configs` 之 `NOTIFY_CONFIG`（tenant 102 的 Discord/Telegram webhook，內含真實 secret）——不出貨。

### 3.4 ⚠️ 待裁決清單（拿不準，留給決策者）

| # | 項目 | 拿不準的點 |
|---|---|---|
| D1 | **CMMC 框架 catalog 整族**（`oscal.frameworks` 1 / `framework_versions` 3 / `catalogs` 79 / `catalog_groups` 296 / `catalog_controls` 980 / `catalog_control_parts` 5651 / `catalog_control_params`，加 `oscal.metadata`/`profiles`/`profile_imports` 中屬框架的部分） | 是產品資產沒錯，但 DEV 的 79 個 catalog 混雜「內建 CMMC」與「開發測試匯入的」，無法從 schema 判斷哪些屬出貨集。且出貨形式有兩路：(a) seed dump 直灌；(b) 出廠帶 OSCAL JSON 檔、首次啟動走既有匯入流程（見 §5 方案 C 註）。**需要 user 指認出貨框架清單** |
| D2 | **內建 workflow_templates**（tenant NULL、provider=`Billows-Official` 的控制項任務範本＋`snapshot` 的凍結快照，共 191 筆；另 tenant 1 有 59 筆） | provider=Billows-Official 看起來是內建 canonical，但 snapshot 類是專案運行產物；且它們與 D1 的框架綁定。需一併裁決出貨範圍 |
| D3 | **樣板 SSP／MF defaults 家族**（`compliance.module_frames` tenant 1/158 各 1 筆、`oscal.system_security_plans` 中 template 性質者；FR-036 已把 defaults 遷進 template SSP） | 新客戶初始該有哪些「內建模組框架＋樣板 SSP」？DEV 現況分不出「產品內建」vs「開發試作」 |
| D4 | **檢測 Profile 庫**（`config.detection_profiles` tenant 1 的 10 筆＋`detection_profile_versions` 11/`_controls` 4841/`_taxonomies` 13） | 資料列看是產品資產（dev-sec 基準＋TWGCB 8 支），但 **profile 版本的檔案實體存在 storage（MinIO）**，DB seed 灌了列、檔案不在就是壞連結——出貨機制需連檔案一起解（隨 installer 帶檔上傳？or 首次啟動重新上傳？） |
| D5 | `public.labels` 35 筆 | 前段（系統回饋/系統操作/選單>專案管理…）像產品字典，後段（textbook-*、resource-*）像特定專案用——需逐筆指認 |
| D6 | `system_configs` 之 `ISSUE_INTEGRATE_CONFIG`（GITHUB/GITLAB，enable=false 空殼） | 功能是否對客戶開放？開放則出廠帶 disabled 空殼，否則不 seed |
| D7 | `public.alembic_version` | 來源不明（repo 無 alembic）；查無 reader 則基線不帶 |
| D8 | root tenant/org/admin 的**出廠命名** | DEV 值是 `Guidant.AI`/`Guidant.AI Manage`/`admin`——正式出貨是否沿用（或 installer 讓客戶命名 root tenant）？ |
| D9 | debug view（`debug_org_units`/`v_tenant_parent_debug`）與 `cm_app_group` 空群組 | 出貨基線帶不帶 |
| D10 | **DB 命名**：新標準 `<系統>_{dev\|stg}`、prod 不帶後綴 → 落地版 DB 名應為 `guidant_ai`？installer 預設值需定案 | 2026-08-08 新制說「guidant_ai_* 舊制沿用不回頭改」，但落地新客戶算新建置，適用新制與否待拍板 |

---

## 4. 帳號與密碼機制現況

### 4.1 DB 帳號（cmmgr / cm_app）

- **建立紀錄不在 repo 內**：`scripts/sql/` 與 docs 全量 grep 無 `CREATE ROLE cmmgr/cm_app`——推測（標註：推測）是當年 DB server 手動建立，屬 cluster-level 操作本來就不進單庫 migration。**→ init 機制必須自己補上這塊**（首次在客戶主機建 cluster 帳號）。
- 現況屬性見 §2.2。關鍵設計事實：cmmgr=superuser+BYPASSRLS 的管理帳號、cm_app=受 RLS 的應用帳號，**兩帳號同密碼是 DEV 慣例，出貨不應沿用**（installer 應分別產生）。
- RLS 不依賴帳號屬性以外的東西：只要應用連線帳號**非** BYPASSRLS/superuser，policy 就生效；GUC 注入由應用層負責。
- ⚠️ 出貨層面注意：cmmgr 目前是 SUPERUSER——若客戶端 DB 是客戶自管（RDS 類），SUPERUSER 拿不到。基線最低需求其實是「DB owner + CREATEROLE + BYPASSRLS」，init 設計時建議降規（列入 §5 考量，實作棒驗證）。

### 4.2 應用層帳號（users 表）

- **密碼儲存**：bcrypt `$2b$12$`（cost 12），**per-user salt** 存 `users.salt` 欄（`bcrypt.gensalt()`），hash 60 字元存 `users.password`。DEV 39 個帳號全部同一格式，無 legacy 雜湊。實作在 jedi-auth `user_domain_service.add_user()`。
- **DEV 超管現況**：`admin`（tenant 1，`is_super_admin=true`，DEV id=16）＋`blsadmin`（tenant 102 的租戶超管）。`admin` 的建立同樣**查無 seed SQL**（推測 legacy 手動/早期工具建立）；後續由 `2026-06-29-b2-admin-root-tenant.sql` 把它掛進 root tenant（users.tenant_id→1 ＋ user_tenants ＋ user_org_units 三筆，B-2 模型）。**init 建初始 admin 時這三件事要一次做齊**，否則重演「super admin 寫入 tenant_id=NULL 孤兒」bug。
- **is_super_admin 語意**：RLS policy 以 GUC `app.is_super_admin='t'` 放行全庫，值由登入時從 users.is_super_admin 帶出。

### 4.3 首登改密／密碼治理（機制已存在，init 可直接復用）

jedi-auth 已內建完整機制，init 不必新造：

- **FIRST_REGISTER 變更請求**：`add_user()` 流程會自動產 12 碼複雜密碼（`generate_complex_password(12)`）＋建立 `user_change_password_request`（type=FIRST_REGISTER，7 天效期）＋寄密碼信。登入時有 pending request 會被導去改密頁；`change_password_by_request()` 走密碼政策驗證（≥12 碼+大小寫+數字，CM-683）。
- **密碼過期**：`RUNTIME_CONFIG.CHANGE_PASSWORD_THRESHOLD_DAYS`（預設 90）+ type=PASSWORD_EXPIRE 請求。
- **MFA**：`RUNTIME_CONFIG.MFA_REQUIRED` + `totp_secrets` 表。
- → **初始 admin 的「隨機產生＋強制首登改密」拼圖現成**：init 只需以 bcrypt 正確格式寫入 users＋一筆 FIRST_REGISTER change request（效期建議放寬），或最簡單——密碼由 installer 產生後印給安裝者、同時 stamp 一筆過期的 threshold 逼首登改密。細節屬實作棒設計。

---

## 5. Init 機制方案建議（只提案不實作）

### 5.0 共同前提（不管選哪案都成立）

- **基線真相=DEV pg_dump**，不是 224 支 migration 重放。歷史串重放不可行：早期檔互相覆蓋、部分含 DEV 專屬資料修補、環境限定檔混雜。
- **權限不逐表 GRANT**：按 §2.1，建 schema →設 default privileges →建物件的順序天生全對，再帶 event trigger 保未來。
- **層次切分**：cluster 層（roles、database、extension）與 database 層（schema/物件/seed）必須分開——前者需要連 `postgres` 庫的權限，後者連目標庫。
- **冪等性**：所有 seed 用自然鍵 `ON CONFLICT DO NOTHING` / `INSERT ... WHERE NOT EXISTS`；schema 段以「`schema_migrations` 有無 baseline marker」判斷跳過整段。root tenant/org **id=1 硬約定**需在空庫 seed 時顯式指定 id 並 setval sequence。
- **收尾 stamp**：init 完成時往 `schema_migrations` 登記（建議登記一筆 `__init_baseline_v<版號>__` marker ＋ 把已收斂的 active migration 檔名全數補登），讓日後增量 migration 與三環境 diff 工具無縫接軌；`schema_version` 補基線版號。這與既有 sql-migration 慣例（檔頭 Date、--single-transaction、cmmgr 執行）完全相容——**基線之後的新 migration 照舊制走，不受影響**。

### 5.1 方案 A：單一 init.sql（大一統檔）

pg_dump schema 段＋seed 段＋stamp 段串成一支，installer 用 `psql --single-transaction -v ON_ERROR_STOP=1` 一發套完。

- ✅ 最簡單、單一交易原子性、與現行 migration 套法零學習成本。
- ❌ 3 萬行大檔難維護難 review；參數注入（admin 密碼、storage 座標）得靠 psql `-v` 變數穿插在巨檔裡，易錯；cluster 層（CREATE ROLE/DATABASE 不能在交易內、要連不同庫）根本塞不進同一支——實務上一定會裂成「殼腳本＋大 SQL」，那不如直接選 B。

### 5.2 方案 B：分段腳本組（建議傾向）★

```
scripts/init/
  00-cluster.sql        # CREATE ROLE cmmgr(降規版)/cm_app/cm_app_group、CREATE DATABASE（連 postgres 庫，殼腳本執行）
  01-extensions.sql     # uuid-ossp、pg_trgm
  02-schema.sql         # 由 pg_dump --schema-only 產出後整理（去 DEV 殘留表、去歷史月分區）
  03-grants.sql         # default privileges ×5 schema + event trigger +（驗收用逐項掃描）
  04-seed-core.sql      # §3.1 字典/權限/選單/root tenant+org/內建流程範本
  05-seed-catalog.sql   # D1~D4 裁決後的框架/profile 資產（可能改走匯入流程，見下）
  06-admin.sql          # 初始 admin（bcrypt hash 由外部算好以 -v 傳入）+ B-2 三件套
  99-stamp.sql          # schema_migrations baseline marker + schema_version
  init.sh               # 依序執行、參數注入（env vars）、冪等判斷、失敗即停
```

- ✅ 每段可獨立 review/重跑；參數注入面窄（只有 00/04/06 吃參數）；cluster/database 層天然分離；與 manifest.tsv 的維護思路一致；**基線升版時只 regenerate 02/03，seed 段不動**。
- ❌ 段間非單一交易（02~99 可各自包交易，但整體失敗需 DROP DATABASE 重來——init 場景可接受，殼腳本做好「失敗即整庫重建」語意即可）。
- 觸發者：**installer 觸發（呼叫 init.sh）**，理由見 5.3。

### 5.3 方案 C：entrypoint 自動 init（容器啟動偵測空庫自動建）

服務容器 entrypoint 起 binary 前檢測 DB，空庫就跑 init。

- ✅ 客戶體驗最滑：`docker run` 即全好。
- ❌ **服務容器必須持有 cmmgr 級憑證**——違反最小權限（runtime 只該有 cm_app）；FR-063 產物是 Nuitka binary，entrypoint 塞 psql/初始化工具鏈會撐大 image；空庫誤判（DB 連錯台）時風險是「在錯的庫建整套 schema」。
- 折衷變體：**獨立 init job 容器**（同 image family 另一個 one-shot container，或 installer 內嵌 psql client），只有 init 當下拿 superuser 憑證，跑完即棄。若未來要「升級也自動套 migration」，這個 job 容器形態可沿用。

### 5.4 取捨建議

**B（installer 觸發的分段腳本）為主，C 的 init-job 容器作為執行載體**：installer 負責產參數（兩組 DB 密碼、admin 初始密碼）→ 起 one-shot init 容器（或直接在主機跑 psql）執行 init.sh → 成功後才起服務容器（只給 cm_app 憑證）。A 不建議單獨採用。

**D1 框架資產的特別註記**：若裁決結果是「出廠帶 OSCAL JSON、首次啟動匯入」，則 05-seed-catalog.sql 整段換成應用層匯入指令（既有框架匯入 pipeline），DB init 只管空殼——這會顯著縮小 seed dump 的維護面，但拉長首次安裝時間且依賴應用已能啟動。兩路成本留給實作棒對照裁決結果細算。

### 5.5 參數注入接口（留給 FR-065 installer 的契約草案）

| 參數 | 用途 | 預設 |
|---|---|---|
| `INIT_DB_HOST` / `INIT_DB_PORT` | 目標 DB | —（必填） |
| `INIT_DB_NAME` | 資料庫名 | `guidant_ai`（D10 待裁決） |
| `INIT_CMMGR_PASSWORD` / `INIT_CMAPP_PASSWORD` | 兩組帳號密碼 | installer 隨機產生 |
| `INIT_ADMIN_LOGIN` / `INIT_ADMIN_PASSWORD` | 初始 admin | `admin`／隨機產生+首登改密（D8） |
| `INIT_ROOT_TENANT_NAME` | root tenant 顯示名 | D8 待裁決 |
| `INIT_STORAGE_*` | STORAGE_CONFIG 座標 | 安裝時填或裝後後台設 |

---

## 附錄：本次盤點使用的唯讀查核語句（實作棒驗收可複用）

```sql
-- 缺 GRANT 的表（應回 0 列）
SELECT n.nspname||'.'||c.relname FROM pg_class c JOIN pg_namespace n ON n.oid=c.relnamespace
WHERE c.relkind IN ('r','p') AND n.nspname IN ('public','compliance','config','oscal','survey')
AND NOT (has_table_privilege('cm_app',c.oid,'SELECT') AND has_table_privilege('cm_app',c.oid,'INSERT')
     AND has_table_privilege('cm_app',c.oid,'UPDATE') AND has_table_privilege('cm_app',c.oid,'DELETE'));
-- 缺 USAGE 的 sequence（應回 0 列）
SELECT schemaname||'.'||sequencename FROM pg_sequences
WHERE NOT has_sequence_privilege('cm_app', quote_ident(schemaname)||'.'||quote_ident(sequencename),'USAGE');
-- RLS 啟用表清單／policy 數
SELECT n.nspname||'.'||c.relname FROM pg_class c JOIN pg_namespace n ON n.oid=c.relnamespace WHERE c.relrowsecurity;
SELECT count(*) FROM pg_policies;
```
