Theme / v0.10.8

Codebase Memory

程式碼記憶與知識圖譜 MCP

實戰範例

實戰範例 001:重構後端 API 時的跨服務圖譜依賴追蹤

實戰演示如何利用 Codebase Memory 知識圖譜,在重構一個核心 Web API 端點時,精確定位並修復所有相依的微服務與前端呼叫點。

實戰背景

在現代的分散式或多模組 Web 系統中,後端 Web API 控制器(Controllers)定義的路由端點(Route Endpoints)常被前端 Single Page App(SPA)、背景排程 Worker 或其他微服務直接調用。

痛點與問題描述: 我們需要重構後端核心的支付介面 POST /api/v1/payments/charge,將其重命名為 POST /api/v2/payments/execute 並修改其請求 Body 格式(移除了 zipCode,改為必填的 billingAddress)。 這項改動一旦發佈,如果前端程式碼或背景排程 Worker 依然使用舊的路徑與參數發送請求,將會引發大面積的生產環境 400 Bad Request 或是 404 Not Found 報錯。傳統的文字搜尋很難穿透跨專案的物理邊界,因此,我們需要利用 Codebase Memory 知識圖譜 的跨服務關聯分析,進行全域的安全變更。


規格定義

本次變更計畫的 ID 為 api-route-refactor。我們在 OpenSpec 增量規格中定義了以下驗收標準:

# 實戰範例 001:openspec/changes/api-route-refactor/specs/api-endpoint/spec.md

## ADDED/MODIFIED Requirements

### Requirement: Upgraded payments execution endpoint
系統必須(SHALL)將原有的 `/api/v1/payments/charge` 路由安全遷移至 `/api/v2/payments/execute`
- 新的 API 控制器必須(SHALL)接收 `PaymentRequestV2` 參數,且包含必填的 `billingAddress` 欄位。

#### Scenario: Verify cross-service endpoint migration
- **WHEN** 執行全域集成測試並模擬前端請求
- **THEN** 所有的前端呼叫點與背景排程 Worker 必須(SHALL)無錯地改呼叫 `/api/v2/payments/execute` 且通過校驗,原有舊端點必須(SHALL)返回 `301 Moved Permanently` 或是安全廢棄。

端到端 8 輪 AI 協作紀錄

以下是 You (開發者) 與 AI 助手在實施此重構時的完整對話歷史。

── 第 1 輪:定位 API 控制器與路徑定義 ──

  • You:
    /opsx:explore "我需要重構支付 API 路由。請幫我用 search_graph 搜尋定義了 payments/charge 路由的類別與位置。"
  • AI:

    好的,已進入探索模式。我將呼叫 codebase-memory 的 search_graph 工具,尋找與 “payments” 或 “charge” 相關的控制器 Class 節點。

    CM 呼叫: search_graph(query: "PaymentController", type: "class")
    CM 回傳:

    [
      {
        "qualifiedName": "ControlSystem.API.Controllers.PaymentController",
        "type": "class",
        "filePath": "/src/API/Controllers/PaymentController.cs",
        "methodsCount": 3
      }
    ]

    分析
    找到了位於 /src/API/Controllers/PaymentController.cs 中的 PaymentController 類別。接下來,我將檢索該類別內部的方法與定義,以確認具體的 Action 路由。


── 第 2 輪:讀取控制器 Action 代碼 ──

  • You:
    請使用 get_code_snippet 讀取 PaymentController 中 charge Action 的 Verbatim 原始碼。
  • AI:

    我將呼叫 get_code_snippet 讀取該類別中對應的 Action 實作。

    CM 呼叫: get_code_snippet(qualifiedName: "ControlSystem.API.Controllers.PaymentController.Charge")
    CM 回傳:

    • 檔案路徑: /src/API/Controllers/PaymentController.cs (第 18 行到第 30 行)
    • 原始碼:
      [HttpPost("v1/charge")]
      public async Task<IActionResult> Charge([FromBody] ChargeRequest request)
      {
          var result = await _paymentService.Process(request.Amount, request.ZipCode);
          return Ok(result);
      }

    分析
    控制器的方法被定義為 HttpPost("v1/charge"),接受 ChargeRequest 物件(內部含有 ZipCode)。 接下來,我們需要找出整個方案中,有哪些前端組件、背景 Worker 或者是單元測試引用了這個 Endpoint。


── 第 3 輪:跨服務依賴檢索 ──

  • You:
    使用 trace_path 追蹤對 Charge 方法的入站依賴,確認有哪些外部呼叫端。
  • AI:

    好的,我將呼叫 trace_path 工具,沿著圖譜的關係鏈追蹤所有引用了 PaymentController.Charge 的位置。

    CM 呼叫: trace_path(symbolName: "ControlSystem.API.Controllers.PaymentController.Charge", direction: "inbound")
    CM 回傳:

    [
      {
        "caller": "ControlSystem.API.Controllers.PaymentController.Charge",
        "calledBy": [
          {
            "caller": "ControlSystem.Workers.SubscriptionBillingJob.Execute",
            "location": "/src/Workers/SubscriptionBillingJob.cs#L72",
            "type": "BackendWorkerCall"
          },
          {
            "caller": "src/frontend/api/payments.ts",
            "location": "/src/frontend/api/payments.ts#L12",
            "type": "HTTPRouteDependency"
          }
        ]
      }
    ]

    分析
    圖譜精確抓取到了跨專案的兩個重要呼叫源:

    1. 後端背景 WorkerSubscriptionBillingJob.cs 的第 72 行調用了此 API。
    2. 前端 TypeScript API 封裝src/frontend/api/payments.ts 的第 12 行向此路由發送了請求。

    我們必須同步修改這兩個地方。我現在退出探索模式,並為您建立變更計畫。


── 第 4 輪:建立提案 ──

  • You:
    /opsx:propose "將支付 API 升級至 v2,重構控制器、背景 Worker 與前端呼叫點,補齊 billingAddress 參數並移除 zipCode"
  • AI:

    好的,提案 api-route-refactor 已建立!

    • proposal.md: 說明升級支付 API 的必要性與防禦性修改前端/背景 Worker 的步驟。
    • specs/api-endpoint/spec.md: 定義 v2 API 的驗收 Scenario。
    • tasks.md: 任務拆解如下:
      • 1.1 修改 PaymentController.cs 路由為 v2/execute 並改用 PaymentRequestV2
      • 1.2 修改背景 Worker SubscriptionBillingJob.cs
      • 1.3 修改前端 payments.ts
      • 1.4 執行建置與測試。

    請輸入 /opsx:apply 來開始實作。


── 第 5 輪:重構控制器 (Task 1.1) ──

  • You:
    /opsx:apply
  • AI:

    Implementing: api-route-refactor (schema: spec-driven)

    正在處理任務 1.1:重構後端控制器與 Data Model。

    我已在 src/API/Controllers/PaymentController.cs 中建立了全新的 V2 Action,並廢棄了 V1(改為回傳 301):

    [HttpPost("v2/execute")]
    public async Task<IActionResult> Execute([FromBody] PaymentRequestV2 request)
    {
        var result = await _paymentService.ProcessV2(request.Amount, request.BillingAddress);
        return Ok(result);
    }

    ✓ 任務 1.1 完成!已更新 tasks.md 狀態。


── 第 6 輪:重構背景 Worker (Task 1.2) ──

  • You:
    繼續任務 1.2,重構 SubscriptionBillingJob.cs。
  • AI:

    Implementing: api-route-refactor

    正在處理任務 1.2:修改背景 Worker 調用。

    我已修改了 src/Workers/SubscriptionBillingJob.cs 的第 72 行,將原有的 JSON 請求體修改為傳送 BillingAddress

    var payload = new {
        amount = subscription.Price,
        billingAddress = subscription.UserAddress // 替代了舊的 zipCode
    };
    var response = await _client.PostAsJsonAsync("api/v2/payments/execute", payload);

    ✓ 任務 1.2 實作完成。


── 第 7 輪:重構前端 API 封裝與驗證 ──

  • You:
    繼續實作任務 1.3 前端 API 修改,並執行建置驗證。
  • AI:

    Implementing: api-route-refactor

    正在處理任務 1.3 & 1.4:前端 API 修改與建置驗證。

    • 前端修改:已在 src/frontend/api/payments.ts 中將請求網址更改為 /api/v2/payments/execute 並更新 TypeScript 介面定義。
    • 編譯建置:執行 pnpm run build 通過。後端編譯 dotnet build 成功。
    • 集成測試:模擬發送支付請求,後端順利解析 billingAddress 且成功完成刷卡,返回 transactionId

    已將變更同步至主規格並歸檔計畫。

    Archive Complete

    變更計畫已成功歸檔!


── 第 8 輪:重構效益總結 ──

  • You:
    總結本次利用圖譜進行 API 重構的價值。
  • AI:

    本次重構中,codebase-memory 顯示出其無與倫比的跨服務關聯價值:

    1. 消除盲區:前端 TypeScript 檔案與後端 C# 檔案屬於完全不同的專案目錄。傳統的 C# IDE 只能追蹤 C# 內部的呼叫,對前端 payments.ts 中的字串調用完全是瞎子。圖譜成功把「HTTP 路由」作為邊關係串聯起來。
    2. 零漏網之魚:背景 Worker SubscriptionBillingJob 如果這次沒有被同步修改,會導致排程扣款在深夜執行時全部爆錯。圖譜精確定位了它,防範了潛在的線上大事故。