前言

我製作了一個可自動產生表格定義書與 ER 圖,並能讓 AI 回答資料表結構的工具「dbxray」,因此想在這裡介紹一下。

為了快速掌握業務上不太熟悉的子系統之資料表結構,我改良了先前做過的資料表定義書輸出工具。

這是先前在【PostgreSQL】試著做一個自動產生 Markdown 形式資料表定義書的工具中介紹過、只輸出資料表定義書的工具之改良版。
工具名稱也從 exportTableDefinition 改為 dbxray 1。

除了連接資料庫並輸出資料表定義書之外,還準備了 MCP 伺服器 2,讓 AI 能根據輸出的資料理解資料表結構。
例如,向已註冊 MCP 伺服器的 Claude Code 可以提出以下問題:

  • 幫我找出跟員工相關的資料表
  • 我想從稽核日誌取出部門名稱,要怎麼 JOIN?
  • 如果我修改 employee 資料表,會影響到哪些地方?
  • 有沒有結構跟 employee 相似的資料表?

適合讀者

  • 在大型系統中開發,但沒有完善整理資料表定義書等文件的工程師
  • 使用 Claude Code 等 AI 撰寫程式時,希望也能讓 AI 參照資料表結構的人

關於儲存庫

dbxray 公開在 ebichan88/dbxray 的 GitHub 儲存庫中。

更詳細的設定與輸出規格,請參考 CLI 參考文件 與 MCP 伺服器文件。

本文內容以撰寫時的最新版 v0.4.2 為準。

  • 支援的 DBMS
    • PostgreSQL(建議 PostgreSQL 13 以上)
    • Oracle(建議 Oracle 12c 以上)
  • 執行環境
    • Java 21
    • 發佈用 zip 已內含 Java 執行環境,因此不需要另外安裝 Java。

目錄

dbxray 是什麼

dbxray 是一個可連接資料庫,並以 Markdown 格式輸出資料表清單、資料表定義書、ER 圖等內容的工具。
同時也附帶 MCP 伺服器,讓 AI 可以搜尋輸出的資料。

輸出內容如下:

輸出物內容README輸出所有文件的索引,以及各 Schema 的物件數量統計資料表清單目標資料表清單與各資料表定義書的連結資料表定義書欄位、索引、約束、外鍵、被參照、觸發器等資訊ER 圖以 Mermaid 語法表示外鍵關係的圖。依資料表單位與 Schema 單位,以及各種觀點輸出的頁面以人事管理等業務單位彙整的資料表 ER 圖與清單函式、序列、使用者定義型別的清單與個別頁面函式/程序的定義本體,以及 ENUM 的值等 snapshot 從資料庫取得的 Schema 資訊,轉成機器可讀的 JSON Lines 格式。作為 MCP 伺服器的輸入參考資訊觀點等非 Schema 資訊,但希望提供給 AI 的資料。會連同 snapshot 一起成為 MCP 伺服器的輸入。

使用方法

從 Releases 下載符合作業系統的 zip 並解壓縮。

解壓後,請在 conf/config.yml 中填入連線目標資料庫的資訊。

conf/config.yml(PostgreSQL 範例)

database:
  driver: org.postgresql.Driver
  url: jdbc:postgresql://<IP>:<埠號>/<DB 名稱>
  username: <使用者名稱>

密碼不是寫在 conf/config.yml,而是透過環境變數 DBXRAY_DB_PASSWORD 傳入。
這是為了避免密碼殘留在可能會被 AI Agent 等讀取的設定檔中。

執行方式(Linux/macOS)

export DBXRAY_DB_PASSWORD='密碼'
./run.sh

Windows 的情況下,先在命令提示字元執行 set DBXRAY_DB_PASSWORD=密碼,再啟動 run.bat。

處理完成後,會在 output 資料夾下以以下結構輸出:

輸出位置的結構(節錄)

output
├─testdb                          ・・・ Markdown 文件(每個 DB 一份)
│  ├─README.md
│  ├─tableList_testdb.md
│  ├─erDiagram_testdb_sample.md
│  ├─viewpoint_testdb_personnel.md
│  └─sample
│     ├─table
│     │  └─employee.md
│     └─function
├─snapshot                        ・・・ 快照(MCP 伺服器的輸入)
│  └─testdb
│     ├─database.json
│     └─sample
│        ├─tables.jsonl
│        └─functions.jsonl
└─insights                        ・・・ 參考資訊(MCP 伺服器的輸入)
   └─testdb
      └─viewpoints.json

輸出的文件

本章將介紹從範例資料庫輸出的文件。
輸出的 Markdown 可以直接在 GitHub 等網站上閱讀。

完整的輸出範例可從 範例資料庫的 README 參考。

本文中的輸出範例、截圖與執行畫面,全部都是從隨附於儲存庫中的範例資料庫產生的虛構資訊,不包含任何真實個人資料或業務資料。

README

會依每個 DB 輸出一份 README,作為所有輸出文件的索引。
其中也會列出各 Schema 的物件數、以及已記載邏輯名稱的資料表與欄位數量等統計。

README 的輸出範例

資料表清單

輸出目標資料表的清單,以及各資料表定義書的連結。

資料表清單的輸出範例

資料表定義書

會針對每個資料表輸出資料表資訊、欄位資訊、索引、約束、外鍵、被參照、觸發器等資訊。
以下截圖是 employee 資料表的定義書。

資料表定義書的輸出範例

被參照資訊中會列出參照這個資料表的其他資料表。
由於外鍵只會定義在參照方資料表,因此會從被參照方也能追查到關聯。

資料表定義書中的外鍵資訊與被參照資訊

ER 圖

ER 圖會以 Mermaid 語法輸出,方便直接在 GitHub 等平台以圖形顯示。
下圖是 employee 資料表定義書中的 ER 圖。

自家資料表會顯示所有欄位,周邊資料表則只顯示圖中關聯所需的欄位。
如果周邊資料表也全部顯示欄位,方框會變得太大。

ER 圖會依下列粒度輸出。

輸出位置內容各資料表定義書的「ER 圖」區段自家資料表與直接的參照先/參照來源資料表。繪製層數可從 1~3 調整依 Schema 的 ER 圖整個 Schema 的 ER 圖依群組的 ER 圖當 Schema 很大時,會依相連資料表的群組切分輸出的 ER 圖依觀點的頁面後述觀點中的所屬資料表彼此之間的 ER 圖

多重度判定

關聯線的多重度,會根據參照來源資料表的外鍵欄位所設定的約束自動判定。
由於外鍵本身只表示是否有關聯,因此會結合欄位唯一性與 NOT NULL 約束一起判斷。

外鍵欄位的情況、唯一外鍵的所有欄位是否為 NOT NULL、多重度、Mermaid 表記如下:

× / ○、1 對多:A ||--o{ B
× / ×、0..1 對多:A |o--o{ B
○ / ○、1 對 1:A ||--o| B
○ / ×、0..1 對 1:A |o--o| B

前述 ER 圖中,以下列方式判定:

  • employee.department_id:NOT NULL 且不唯一 → 1 對多
  • employee.manager_id:可為 NULL 且不唯一 → 0..1 對多
  • employee.parking_spot_id:UNIQUE 且可為 NULL → 0..1 對 1
  • employee_profile.employee_id:因為是主鍵,所以唯一且 NOT NULL → 1 對 1

唯一性的判定不是看欄位名稱是否相同,而是看包含關係。

以包含關係判定唯一性的例子

-- 外鍵是 NOT NULL 的 a、b 兩個欄位
ALTER TABLE child ADD FOREIGN KEY (a, b) REFERENCES parent (a, b);
-- 如果只要 a 就是唯一,那 (a, b) 的組合也一定唯一,因此判定為 1 對 1
ALTER TABLE child ADD UNIQUE (a);

反過來,就算有 UNIQUE (a, b),只要外鍵只有 (a),也不會判定為 1 對 1。

此外,除了唯一約束之外,透過 CREATE UNIQUE INDEX 建立的唯一索引也會納入判定,但 PostgreSQL 的部分索引則排除在外。

不納入判定的部分索引範例

-- 只保證未刪除資料中的唯一性,因此不作為多重度判定依據
CREATE UNIQUE INDEX ON child (parent_id) WHERE deleted_at IS NULL;

為了在未整理好的資料庫中使用的功能

到目前為止的輸出範例,都以有設定外鍵約束與註解的資料表為主來介紹。
但在實際現場的資料庫中,外鍵約束或註解可能根本沒整理好,或是資料表數量太多,以致一次輸出 ER 圖也難以閱讀,這種情況其實很常見。

dbxray 也準備了能在這種環境下使用的功能。

補充外鍵約束或註解以外的資訊

範例資料庫中,department 資料表沒有註解,audit_log 資料表也沒有外鍵約束。

像這樣資料庫中缺少的資訊,可以寫在sidecar YAML 中並合併到輸出裡。

annotations.sample.yml(節錄自範例)

tables:
  sample.department:
    description: |
      管理公司內部組織單位的主檔資料表。
      員工(employee)一定隸屬於其中一個部門。
    remarks: 組織調整時請勿變更 department_code,只更新 department_name
    columns:
      department_code: 部門代碼。作為與其他系統串接時的鍵值使用
      department_name: 部門名稱

relations:
  - table: sample.audit_log            # 參照來源(子)
    columns: [record_id]
    parentTable: sample.employee       # 參照對象(父)
    parentColumns: [employee_id]
    cardinality: 0..1對多              # 因為 DB 沒有約束,所以在這裡明確指定多重度

tables 中記載的說明與備註,會反映到資料表定義書的資料表說明與備註欄位。

反映 sidecar YAML 內容的 department 資料表定義書

relations 中記載的關聯會被視為邏輯關聯。
在資料表定義書中會與外鍵資訊分開顯示,而在 ER 圖中為了和實體外鍵區分,會用虛線表示。
前面 employee 的 ER 圖中,與 audit_log 之間的線為虛線,就是邏輯關聯。

audit_log 資料表定義書中的邏輯關聯資訊

補充了多少資訊,可以從 README 的統計中確認。

將大型 Schema 的 ER 圖切分

若 Schema 的資料表數量很多,把全部內容畫在同一張 ER 圖上,線條會交錯混亂而難以閱讀。
因此我為單張圖可包含的資料表數量設了上限,超過上限時會像以下方式拆分輸出。

把小群組放在同一組,是為了避免產生大量只有兩個資料表的小型 ER 圖。
因為被合併在同一組的資料表之間不會畫線,所以不會誤讀它們的關聯。

依業務單位整理資料表

Schema 單位或連結單位的 ER 圖屬於機械式切分,因此若想依業務單位理解資料表,就不太適合。

所以我讓使用者可以透過 sidecar YAML 宣告像人事管理、訂單管理這樣的觀點,以業務單位整理資料表。

annotations.sample.yml(節錄自範例)

viewpoints:
  - id: personnel
    name: 人事管理
    description: |
      處理員工及其所屬資訊、附帶資訊的資料表群。
      與專案分派相關的部分請參考「專案管理」觀點。
    tables:
      - sample.employee*
      - "!sample.employee_directory_view"
      - sample.department
      - sample.parking_spot

宣告觀點後,系統會輸出一個包含該觀點 ER 圖與所屬資料表清單的頁面。

觀點「人事管理」頁面

偵測文件更新遺漏

即使輸出了文件,如果無法跟上資料庫變更,很快也會過時。

加上 --check 執行時,會比較已提交的 snapshot 與目前資料庫生成的 snapshot。
這是為了在 CI 中偵測是否漏掉了資料庫 migration 後的文件重輸出。

例如,對範例資料庫的 employee 資料表新增 nickname 欄位後再執行,就會像下面這樣以 unified diff 格式顯示差異。

--check 的輸出(節錄)

Content differs:
 - table sample.employee
--- committed/testdb/sample/tables.jsonl (table sample.employee)
+++ generated/testdb/sample/tables.jsonl (table sample.employee)
@@ -15,6 +15,7 @@
     {"name":"profile","logicalName":"個人資料(JSON)","type":"jsonb","primaryKey":false,"notNull":true,"defaultValue":"'{}'::jsonb"}
     {"name":"hired_date","logicalName":"到職日","type":"date","primaryKey":false,"notNull":true,"defaultValue":"CURRENT_DATE"}
     {"name":"updated_at","logicalName":"更新時間","type":"timestamp without time zone","primaryKey":false,"notNull":true,"defaultValue":"now()"}
+    {"name":"nickname","logicalName":"暱稱","type":"text","primaryKey":false,"notNull":false}
   ]
   "indexes": [
     {"name":"employee_employee_code_key","method":"btree","unique":true,"primary":false,"definition":"CREATE UNIQUE INDEX employee_employee_code_key ON sample.employee USING btree (employee_code)"}

如果有差異,就可以讓 CI 的 job 失敗,進而發現文件更新遺漏。

透過 MCP 伺服器讓 AI 回答資料表結構

本章介紹 MCP 伺服器。

一開始我沒有打算做 MCP 伺服器,但在開發途中突然想到:如果 AI 能直接回答資料表結構,應該會很有趣吧,於是向 AI 提案後,意外地把這件事一路做下去了。
目前這個 MCP 伺服器已經提供 19 個工具。

整體架構

整體架構如下。

重點是,MCP 伺服器本身不會連接資料庫。
它只會讀取 dbxray 輸出的 snapshot 與參考資訊,因此不需要把資料庫連線資訊放在 AI 的執行環境中,也不會把資料庫的實際資料傳給 AI。

另外,給人看的資料表定義書與供 AI 參照的資訊,都是從同一份取得結果輸出,因此兩者不會有不一致的問題。

不過,另一方面,只要資料庫有變更,除非重新執行 dbxray 更新 snapshot,否則 AI 就無法參照到變更內容 3。

設定方法

MCP 伺服器本體是發佈用 zip 內的 mcp/dbxray-mcp.jar。
因為可以透過內含的 Java 執行環境運作,所以在 Claude Code 中可用以下指令註冊。

Claude Code 註冊方式(Linux/macOS 範例)

claude mcp add dbxray -- /opt/dbxray-linux/runtime/bin/java -jar /opt/dbxray-linux/mcp/dbxray-mcp.jar --snapshot=/work/schema-docs/output/snapshot

MCP 伺服器會從與 --snapshot 指定目錄同層的 insights 讀取參考資訊。
如果只共享 snapshot,就無法參照觀點與函式使用資料表等資訊,因此 snapshot 與 insights 兩者都要一起提交。

另外,不只這一點,業務資料庫的輸出內容可能包含內部資訊,因此請務必注意公開範圍,例如放在有存取控制的儲存庫中管理。

如果要在團隊中共享,可以把 .mcp.json 提交到應用程式的儲存庫,並以環境變數指定不同環境各自不同的路徑。

.mcp.json

{
  "mcpServers": {
    "dbxray": {
      "command": "${DBXRAY_HOME}/runtime/bin/java",
      "args": ["-jar", "${DBXRAY_HOME}/mcp/dbxray-mcp.jar", "--snapshot=${SCHEMA_SNAPSHOT_DIR}"]
    }
  }
}

可以問 AI 什麼

這裡會搭配在範例資料庫上執行工具的結果,介紹可以問 AI 的內容。

用業務用語搜尋資料表

即使資料表名稱是英文,也可以針對邏輯名稱、說明、欄位名稱用日文搜尋。
以下是用 search_tables 搜尋「従業員」的結果。

search_tables(query: 従業員)的結果(節錄)

{
  "total": 3,
  "tables": [
    {
      "name": "employee",
      "logicalName": "従業員",
      "matchedIn": ["logicalName", "column:employee_id", "column:employee_code", "column:employee_name", "column:manager_id"]
    },
    {
      "name": "employee_history",
      "logicalName": "従業員履歴",
      "matchedIn": ["logicalName"]
    },
    {
      "name": "department",
      "description": "管理公司內部組織單位的主檔資料表。\n員工(employee)一定隸屬於其中一個部門。\n",
      "matchedIn": ["description"]
    }
  ]
}

department 資料表在 DB 中沒有註解,但因為 sidecar YAML 裡記載的說明包含「従業員」,所以也被包含在搜尋結果中。
由於人手補上的資訊也會成為搜尋對象,補得越多,AI 就越容易找到資料表。

也可以從欄位名稱反查資料表。

「請幫我查有多少欄位的物理名稱包含 id」的詢問結果

查詢 JOIN 路徑

假設要從稽核日誌 audit_log 取得被修改員工的部門名稱。

雖然 audit_log 沒有外鍵約束,但因為在 sidecar YAML 中宣告了到 employee 的邏輯關聯,所以可以透過 find_join_path 找出 JOIN 路徑。

find_join_path(from: audit_log、to: department)的結果(節錄)

{
  "paths": [
    {
      "tables": ["sample.audit_log", "sample.employee", "sample.department"],
      "joins": [
        {
          "from": "sample.audit_log",
          "fromColumns": ["record_id"],
          "to": "sample.employee",
          "toColumns": ["employee_id"],
          "kind": "logicalRelation",
          "cardinality": "OPTIONAL_ONE_TO_MANY"
        },
        {
          "from": "sample.employee",
          "fromColumns": ["department_id"],
          "to": "sample.department",
          "toColumns": ["department_id"],
          "kind": "foreignKey",
          "cardinality": "ONE_TO_MANY"
        }
      ]
    }
  ]
}

除了 JOIN 的欄位組合之外,結果也包含這個關聯是來自外鍵還是邏輯關聯,以及多重度。

根據這個結果組 SQL,會像下面這樣:

根據返回路徑組出的 SQL 範例

SELECT a.changed_at, a.action, e.employee_name, d.department_name
FROM sample.audit_log a
-- record_id 允許 NULL,且是 0..1 對多的關聯,因此先用外連接
LEFT JOIN sample.employee e ON e.employee_id = a.record_id
LEFT JOIN sample.department d ON d.department_id = e.department_id
-- record_id 也可能是其他資料表的主鍵值,因此只限制為 employee 的變更
WHERE a.table_name = 'employee';

在沒有外鍵約束的資料庫中,AI 只能根據欄位名稱推測關聯來寫 JOIN;但使用 dbxray 就能根據人手宣告的關聯來回答。

分析變更的影響範圍

使用 get_impact,只要呼叫一次,就能查出修改或刪除某個資料表時的影響範圍。
將 employee 資料表的調查結果整理如下:

種類受影響的對象透過外鍵參照的資料表attendance、employee 自我參照、employee_history、employee_profile、project_assignment透過邏輯關聯參照的資料表audit_log間接參照的資料表attendance_note。經由 attendance 參照的檢視表employee_directory_view,以及參照它的 attendance_monthly_view觸發器trg_employee_audit、trg_employee_set_updated_at使用的函式/程序raise_salary、close_project、department_headcount 等 4 個,以及候補的 count_rows 函式/程序

關於 count_rows 函式/程序,會在 operations 中以 C / R / U / D 回傳它對目標資料表是用在新增、查詢、更新還是刪除。
此外,像是經由檢視表的觸發器呼叫、進而寫入 employee 的函式,也可以透過 calledByTriggers 確認。

get_impact(table: employee)的結果中函式部分(節錄)

"usages": [
  {
    "function": "sample.raise_salary",
    "kind": "PROCEDURE",
    "overloads": ["IN p_employee_id integer, IN p_amount numeric"],
    "operations": "U"
  },
  {
    "function": "sample.employee_directory_insert",
    "kind": "FUNCTION",
    "overloads": ["()"],
    "operations": "C",
    "calledByTriggers": ["sample.employee_directory_view.trg_employee_directory_insert"]
  }
]

候補的 count_rows 因為參照了沒有 Schema 修飾的 employee,在執行時會因 search_path 不同而有可能指向別的資料表。
這類函式不會當作確定結果,而是用 match: possible 來區分。

函式所使用的資料表,是從函式定義本體機械式抽出的結果,只有在加上 --preview 執行時才會啟用,屬於預覽功能 4。

尋找結構相似的資料表

其中我個人最喜歡的是用來找結構相似資料表的 find_similar_tables。
它不只是直接回傳快照資料,還加入了類似度計算等巧思。

「有沒有結構跟 employee 類似的資料表?」的詢問結果

此時 MCP 伺服器回傳給 AI 的 JSON 如下。

find_similar_tables(table: employee)的結果

{
  "base": "sample.employee",
  "total": 1,
  "tables": [
    {
      "database": "testdb",
      "name": "sample.employee_history",
      "logicalName": "従業員履歴",
      "similarity": 77,
      "kind": "superset",
      "sharedColumns": 11,
      "onlyInOther": ["history_id", "valid_from", "valid_to"],
      "typeMismatches": [
        {
          "column": "employee_name",
          "base": "character varying(50)",
          "other": "character varying(100)",
          "difference": "size"
        }
      ],
      "relatedToBase": true
    }
  ]
}

它會把 employee 的 11 個欄位全部包含,並且額外加上 history_id、valid_from、valid_to 的 employee_history 判定為歷史表。
此外,也能看出只有 employee_name 的字數長度與本體不同。

這個功能預計用於:在建立新資料表之前,先確認是否已經存在用途相同的資料表,或是找出歷史表、備份用資料表。

取得 ER 圖

可以用與資料表定義書相同的 Mermaid 語法,回傳資料表周邊或觀點單位的 ER 圖。

「請把員工資料表周邊的 ER 圖畫出來並用圖片展示」的詢問結果

尋找結構相似資料表的機制

find_similar_tables 會以加權 Jaccard 係數比較欄位名稱集合。
比較前會先統一欄位名稱的大小寫與全形/半形。

一般的 Jaccard 係數,是用共同欄位數除以兩個資料表欄位的聯集數來計算:

\text{Jaccard 係數} = \frac{\text{共同欄位數}}{\text{兩者欄位聯集數}}

加權 Jaccard 係數則不是用欄位數,而是用各欄位權重的總和來計算:

\text{相似度} = \frac{\sum_{c \in \text{共同欄位}} w(c)}{\sum_{c \in \text{兩者欄位聯集}} w(c)}
,\qquad
w(c) = \ln \frac{N + 1}{\text{擁有該欄位名稱的資料表數}}

其中 $N$ 是 DB 中的資料表數量。
$N$ 與擁有該欄位名稱的資料表數量,都會排除檢視表與基準資料表本身後再計算。

權重 $w(c)$ 會隨著擁有該欄位名稱的資料表越多而越小。
這是為了避免只因為共享了像 id、created_at 這種多數資料表都通用的欄位,就誤判為相似。

SimilarTableFinder.java(一部份節錄)

    double weightOf(String name) {
      return Math.log((tables + 1.0) / Math.max(counts.getOrDefault(name, 0), 1));
    }

結果除了相似度之外,也包含以下資訊:

  • kind:與對方的關係類型
    • identical:欄位完全相同
    • superset:對方包含基準資料表的所有欄位
    • subset:對方只包含基準資料表的一部分欄位
    • overlap:其他情況
  • typeMismatches:同名但型別不同的欄位
    • 會區分是型別本身不同,還是只有長度不同
  • relatedToBase:是否與基準資料表透過外鍵或邏輯關聯直接相連

不把與基準資料表相連的資料表排除,而是另外標記,是因為歷史表或擴充表常常會參照基準資料表。

另外,相似度所表示的是欄位名稱結構的接近程度,不代表一定是同一個用途的資料表。
是否為相同用途的資料表,則交由呼叫的 AI 透過 get_table 查看說明與定義後自行判斷 5。

工具清單

截至 v0.4.2,提供以下 19 個工具。

目的工具內容掌握整體架構list_schemasDB 與 Schema,以及各種類物件數量list_viewpoints觀點清單list_table_clusters根據關聯連結推測的資料表群組尋找search_tables以關鍵字搜尋資料表。也會包含邏輯名稱、說明與欄位名稱list_tables資料表清單與各自的關聯數find_columns從欄位名稱反查擁有該欄位的資料表find_similar_tables尋找欄位結構相似的資料表查看定義get_table資料表與檢視表的定義追蹤關聯get_related_tables透過外鍵與邏輯關聯連結的資料表find_join_path連接兩個資料表的最短 JOIN 路徑get_er_diagramMermaid 語法的 ER 圖分析影響get_impact修改或刪除資料表時的影響範圍其他list_functions、get_function等其他函式、序列、使用者定義型別、觸發器的清單與定義除了工具之外,也提供可讓使用者用 @ 在對話中附加資料表定義的資源。
在終端版 Claude Code 中,於輸入欄輸入像 @受注明細 這樣的邏輯名稱或物理名稱,就會顯示候選項目。

開發時遇到的困難

這次改版的大部分是由 Claude Code 實作的,但最辛苦的是理解 AI 寫出來的原始碼。

原本這是自己從零做出來的工具,所以應該很熟悉原始碼才對;但不知不覺間,實作的進度已經快到自己的理解跟不上了。

因此,我一邊逐項檢視可讀性、責任切分、命名、例外設計、作為 DDD 的架構等,一邊進行重構,最後也整理了原始碼閱讀指南。

閱讀指南把前置知識、處理流程,以及各個原始碼的職責與關係用圖整理起來,並公開在 GitHub Pages 上。

此外,為了維持 AI 實作程式碼的品質,也導入了以下機制:

  • 使用 Spotless 檢查程式碼格式
  • 使用 JaCoCo 檢查最低覆蓋率
  • 使用 ArchUnit 檢查分層架構與編碼規範
  • 使用 SpotBugs 與 CodeQL 進行靜態分析
  • 對 Docker 上的 PostgreSQL 與 Oracle 進行整合測試,並與整體輸出基準比對
  • 驗證 MCP 伺服器工具規格與實作是否一致的契約測試
  • 針對來自 DB 的字串設計路徑穿越與 HTML 注入測試
  • 整理給 AI Agent 的規則文件 AGENTS.md 與程式撰寫指南

各機制的詳細內容,請參考儲存庫中的 CONTRIBUTING.md 與 程式撰寫指南。

結語

在強化功能的過程中,我更加明確地將這個工具的概念語言化為讀懂既有系統。

如果你是在大型系統中開發,而那個環境又沒有整理好資料表定義書等文件,我非常推薦你試試看。

  1. 舊名稱比較偏向資料表定義書專用,因此我想換成更通用的名稱。原本打算比照 GitLens 命名為「dblens」,但似乎已經有同名儲存庫存在,所以改成不重複的名稱。 ↩
  2. MCP(Model Context Protocol)是讓 AI 使用外部工具與資料的標準規格。詳細資訊請參考官方網站。 ↩
  3. 這個資料新鮮度問題,預計會透過在 CI 中執行前述 --check,檢測 snapshot 與 DB 是否脫節來處理。 ↩
  4. 不包含動態 SQL,以及在被呼叫函式內部的查詢。這類可能漏判的函式會另外顯示在結果中。 ↩
  5. 如果 DB 的資料表數量很少,通用欄位的權重可能無法充分降低,這也是一項限制。 ↩

原文出處:https://qiita.com/ebichan_88/items/f7c44c74e437875b1399


精選技術文章翻譯,幫助開發者持續吸收新知。

共有 0 則留言


精選技術文章翻譯,幫助開發者持續吸收新知。
🏆 本月排行榜
🥇
站長阿川
📝11   💬1  
340
🥈
mike
1
評分標準:發文×10 + 留言×3 + 獲讚×5 + 點讚×1 + 瀏覽數÷10
本數據每小時更新一次
📢 贊助商廣告 · 我要刊登