<?xml version="1.0" encoding="UTF-8"?>
<rss version="2.0" xmlns:atom="http://www.w3.org/2005/Atom" xmlns:dc="http://purl.org/dc/elements/1.1/">
  <channel>
    <title>DEV Community: Let's Write</title>
    <description>The latest articles on DEV Community by Let's Write (@letswrite).</description>
    <link>https://dev.to/letswrite</link>
    <image>
      <url>https://media2.dev.to/dynamic/image/width=90,height=90,fit=cover,gravity=auto,format=auto/https:%2F%2Fdev-to-uploads.s3.us-east-2.amazonaws.com%2Fuploads%2Fuser%2Fprofile_image%2F879108%2F12d6ce35-abca-4678-a503-fc4600997729.png</url>
      <title>DEV Community: Let's Write</title>
      <link>https://dev.to/letswrite</link>
    </image>
    <atom:link rel="self" type="application/rss+xml" href="https://dev.to/feed/letswrite"/>
    <language>en</language>
    <item>
      <title>把 Claude Code 改成自己的樣子：用 Mod 做出用量顯示條與待辦側欄工具</title>
      <dc:creator>Let's Write</dc:creator>
      <pubDate>Tue, 06 Oct 2026 12:38:46 +0000</pubDate>
      <link>https://dev.to/letswrite/ba-claude-code-gai-cheng-zi-ji-de-yang-zi-yong-mod-zuo-chu-yong-liang-xian-shi-tiao-yu-dai-ban-ce-lan-gong-ju-2j8h</link>
      <guid>https://dev.to/letswrite/ba-claude-code-gai-cheng-zi-ji-de-yang-zi-yong-mod-zuo-chu-yong-liang-xian-shi-tiao-yu-dai-ban-ce-lan-gong-ju-2j8h</guid>
      <description>&lt;h2&gt;
  
  
  本篇要解決的問題
&lt;/h2&gt;

&lt;p&gt;用 AI 開發時，常常想知道這 2 件事：&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;5 小時額度還剩多少？&lt;/li&gt;
&lt;li&gt;開過這些 session 裡，哪些專案還有事情沒做完？&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;這個月 Claude Code 推出了 Mod 的機制，可以在介面上補上自己想要的小工具。&lt;/p&gt;

&lt;p&gt;這篇筆記文章先簡單介紹 Mod，再介紹解決上面 2 個需求的模組：&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;放在輸入框上方的用量條 &lt;code&gt;token-usage&lt;/code&gt;。&lt;/li&gt;
&lt;li&gt;放在右側欄的待辦面板 &lt;code&gt;open-todos&lt;/code&gt;。&lt;/li&gt;
&lt;/ul&gt;




&lt;h2&gt;
  
  
  Claude Mods 是什麼
&lt;/h2&gt;

&lt;p&gt;Mod 是我們裝進 Claude Code 的小外掛，可以讓它多出新功能。&lt;/p&gt;

&lt;p&gt;想像一台樂高小火車。&lt;/p&gt;

&lt;p&gt;火車本來就會跑，我們想加一盞燈、一個喇叭，就拿新積木喀嚓裝上去。&lt;/p&gt;

&lt;p&gt;Claude Code 是那台火車，Mod 是我們多裝的積木。&lt;/p&gt;

&lt;p&gt;Mod 可以做出這幾種東西：&lt;/p&gt;

&lt;div class="table-wrapper-paragraph"&gt;&lt;table&gt;
&lt;thead&gt;
&lt;tr&gt;
&lt;th&gt;我們想要&lt;/th&gt;
&lt;th&gt;Mod 做出來的東西&lt;/th&gt;
&lt;/tr&gt;
&lt;/thead&gt;
&lt;tbody&gt;
&lt;tr&gt;
&lt;td&gt;旁邊有一個一直顯示資訊的小視窗&lt;/td&gt;
&lt;td&gt;Pane（面板）&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;輸入框上面多一條提示列&lt;/td&gt;
&lt;td&gt;Band（橫條）&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;底下一行小字顯示狀態&lt;/td&gt;
&lt;td&gt;Status line（狀態列）&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;跳出一個小通知&lt;/td&gt;
&lt;td&gt;Toast（提示氣泡）&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;自己發明一個 &lt;code&gt;/指令&lt;/code&gt;
&lt;/td&gt;
&lt;td&gt;Slash command&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;Claude 做某件事之前先攔下來檢查&lt;/td&gt;
&lt;td&gt;Hook（鉤子）&lt;/td&gt;
&lt;/tr&gt;
&lt;/tbody&gt;
&lt;/table&gt;&lt;/div&gt;

&lt;p&gt;Mod 的觸發邏輯就像是：「當這件事發生，就做那件事。」&lt;/p&gt;

&lt;p&gt;比如一個門鈴，有人按就叮咚。&lt;/p&gt;

&lt;p&gt;而 Claude 要刪檔案時先問一聲，或你送出訊息時在底下顯示提示，都是這種寫法。&lt;/p&gt;

&lt;p&gt;另一個很好的特性是熱重載，當我們改了 Mod，不用重開 Claude Code，畫面馬上換成新的，這省下大量等待時間。&lt;/p&gt;

&lt;p&gt;一個 Mod 就是一個資料夾，裡面有 3 個檔案：&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;my-mod/
├── .claude-plugin/plugin.json   名字卡：我叫什麼、做什麼
├── hooks/hooks.json             地圖：程式檔放在哪
└── hooks/register.tsx           真正做事的程式
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;寫完之後，可以用 &lt;code&gt;claude plugin validate &amp;lt;資料夾&amp;gt;&lt;/code&gt; 檢查有沒有寫錯。&lt;/p&gt;




&lt;h2&gt;
  
  
  模組一：token-usage，輸入框上方的用量條
&lt;/h2&gt;

&lt;blockquote&gt;
&lt;p&gt;安裝方式寫在後面段落，Mod 的程式碼也在該段落下載。&lt;/p&gt;
&lt;/blockquote&gt;

&lt;p&gt;&lt;code&gt;token-usage&lt;/code&gt; 在 Claude Desktop 的輸入框上方放一排膠囊，顯示 5 小時額度、7 天額度、token 用量和花費。&lt;/p&gt;

&lt;p&gt;主要是讓 Claude Code 看這篇 X 貼文後，參考樣式來撰寫：&lt;a href="https://x.com/thegenioo/status/2106139975922409585" rel="noopener noreferrer"&gt;https://x.com/thegenioo/status/2106139975922409585&lt;/a&gt;。&lt;/p&gt;

&lt;p&gt;安裝本篇的 Mod 後，最後會看到的樣子如下：&lt;/p&gt;

&lt;p&gt;&lt;a href="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.us-east-2.amazonaws.com%2Fuploads%2Farticles%2F3diaibo8soeposs0wxh1.png" class="article-body-image-wrapper"&gt;&lt;img src="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.us-east-2.amazonaws.com%2Fuploads%2Farticles%2F3diaibo8soeposs0wxh1.png" alt="Claude Code token-usage 模組範例：輸入框上方顯示 5 小時額度、Token 用量與花費膠囊" width="799" height="144"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;看看，August 只用 Sonnet 5.5 medium，多麼的勤儉持家（誤）。&lt;/p&gt;

&lt;p&gt;它的運作拆成四個 hook：&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;
&lt;code&gt;session.measure&lt;/code&gt;：每次回應後拿到額度百分比、重置時間和花費。&lt;/li&gt;
&lt;li&gt;
&lt;code&gt;turn.complete&lt;/code&gt;：累加輸入、輸出和快取的 token 數。&lt;/li&gt;
&lt;li&gt;
&lt;code&gt;ui.render&lt;/code&gt;：在輸入框上方（AbovePrompt）把這些數字畫出來。&lt;/li&gt;
&lt;li&gt;
&lt;code&gt;session.start&lt;/code&gt;：啟動一個計時器，每 5 分鐘重畫一次，讓重置倒數保持更新。重畫不會呼叫模型。&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;畫法有兩套：&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;桌面版用 SVG 畫圓角膠囊和小圖示。&lt;/li&gt;
&lt;li&gt;終端機沒有 SVG，就退回純文字加進度條字元。&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;額度用顏色提醒：&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;低於 75% 維持原色。&lt;/li&gt;
&lt;li&gt;到 75% 轉琥珀色。&lt;/li&gt;
&lt;li&gt;到 90% 轉紅色。&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;時間軸上還有一根細線標出「現在走到視窗的哪裡」，用量條和時間線並排，一眼看得出用量是否跑在時間前面。&lt;/p&gt;

&lt;p&gt;有個限制：要等第一次回應後才有資料。&lt;/p&gt;




&lt;h2&gt;
  
  
  模組二：open-todos，右側欄的待辦面板
&lt;/h2&gt;

&lt;blockquote&gt;
&lt;p&gt;安裝方式寫在後面段落，Mod 的程式碼也在該段落下載。&lt;/p&gt;
&lt;/blockquote&gt;

&lt;p&gt;第二個模組解決另一個問題。&lt;/p&gt;

&lt;p&gt;當我們同時開著好幾個專案，每個專案又有好幾個 session。&lt;/p&gt;

&lt;p&gt;Claude 在某個 session 裡列了十個待辦，做到第七個時，我們就去忙別的了，然後我們就完全忘記。&lt;/p&gt;

&lt;p&gt;&lt;code&gt;open-todos&lt;/code&gt; 在右側欄列出所有 session 裡未完成和進行中的待辦，依專案分組。&lt;/p&gt;

&lt;p&gt;可以透過輸入 &lt;code&gt;/todos&lt;/code&gt; 開啟或重新整理。&lt;/p&gt;

&lt;p&gt;&lt;a href="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.us-east-2.amazonaws.com%2Fuploads%2Farticles%2Fli4eb5b6g4k3gz07pyjr.png" class="article-body-image-wrapper"&gt;&lt;img src="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.us-east-2.amazonaws.com%2Fuploads%2Farticles%2Fli4eb5b6g4k3gz07pyjr.png" alt="Claude Code open-todos 右側欄面板：跨 Session 與專案的待辦清單介面" width="448" height="783"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;h3&gt;
  
  
  資料從哪來
&lt;/h3&gt;

&lt;p&gt;每個 session 的對話紀錄都存在 &lt;code&gt;~/.claude/projects&lt;/code&gt; 底下，裡面記著 Claude 呼叫待辦工具的每一筆動作。&lt;/p&gt;

&lt;p&gt;這個掃描程式把 &lt;code&gt;TaskCreate&lt;/code&gt;、&lt;code&gt;TaskUpdate&lt;/code&gt;、&lt;code&gt;TodoWrite&lt;/code&gt; 依序重放一遍，最後留下狀態還是「待辦」或「進行中」的項目。&lt;/p&gt;

&lt;p&gt;掃描程式是一支 Node 腳本，面板用 &lt;code&gt;$.process.run&lt;/code&gt; 呼叫它。&lt;/p&gt;

&lt;p&gt;啟動 open-todos 的方式有 2：&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;送出 prompt 時。&lt;/li&gt;
&lt;li&gt;輸入 &lt;code&gt;/todos&lt;/code&gt; 時，會重新掃描。&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;不過這個做法有個明確的限制：只有透過 Claude 的待辦工具建立的項目看得到，如果是在對話裡口頭交代的事，就讀不到了。&lt;/p&gt;




&lt;h2&gt;
  
  
  安裝與更新
&lt;/h2&gt;

&lt;p&gt;兩個模組都打包成相同安裝、更新方式。&lt;/p&gt;

&lt;p&gt;先從 GitHub 上下載專案，下載前也請按個星星，你的小小舉動，對本站都是大大的鼓勵：&lt;/p&gt;

&lt;p&gt;接著終端機開啟專案，輸入以下指令安裝：&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;macOS：&lt;code&gt;bash install.sh&lt;/code&gt;
&lt;/li&gt;
&lt;li&gt;Windows：&lt;code&gt;powershell -ExecutionPolicy Bypass -File install.ps1&lt;/code&gt;
&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;安裝時，要確定本機有裝 &lt;a href="https://nodejs.org/zh-tw/download" rel="noopener noreferrer"&gt;Node.js&lt;/a&gt;。&lt;/p&gt;




&lt;h2&gt;
  
  
  結語
&lt;/h2&gt;

&lt;p&gt;Mod 讓 Claude Code 不再是照單全收的工具。&lt;/p&gt;

&lt;p&gt;想看額度就加一條用量條，想管待辦就加一個側欄。&lt;/p&gt;

&lt;p&gt;開發方式還很簡單，直接在 Claude Code 上說自己想要一個什麼樣子的模組就行。&lt;/p&gt;

&lt;p&gt;網路上也有很多有趣的 Claude Mod，大家可以多多搜尋，有趣的歡迎留言。&lt;/p&gt;

</description>
      <category>ai</category>
      <category>claude</category>
      <category>mod</category>
      <category>token</category>
    </item>
    <item>
      <title>AI Agent 多代理人自動化開發實作：讓 Agents 夜巡，協作開發 SVG 圓形連線工具</title>
      <dc:creator>Let's Write</dc:creator>
      <pubDate>Wed, 30 Sep 2026 16:07:45 +0000</pubDate>
      <link>https://dev.to/letswrite/ai-agent-duo-dai-li-ren-zi-dong-hua-kai-fa-shi-zuo-rang-agents-ye-xun-xie-zuo-kai-fa-svg-yuan-xing-lian-xian-gong-ju-5037</link>
      <guid>https://dev.to/letswrite/ai-agent-duo-dai-li-ren-zi-dong-hua-kai-fa-shi-zuo-rang-agents-ye-xun-xie-zuo-kai-fa-svg-yuan-xing-lian-xian-gong-ju-5037</guid>
      <description>&lt;h2&gt;
  
  
  本篇要解決的問題
&lt;/h2&gt;

&lt;p&gt;上週為了在 Grok Bot 的 7 天試用期內，看可以玩些什麼，搜了一下網路，看到一個有趣的用法：讓 Agents 在半夜自己「夜巡」，找題目、做出有趣的東西。&lt;/p&gt;

&lt;p&gt;覺得這很有趣，很像每天在開盲盒或抽一番賞一樣，所以 August 也建了一個夜巡 Team，看會寫出什麼有趣的功能。&lt;/p&gt;

&lt;p&gt;這篇就拿其中一個成果來介紹，主要是一個讓你拉動滑桿，把圓圈上的線變成不同圖案的功能。&lt;/p&gt;

&lt;p&gt;成果放上 GitHub 了，可以直接看原始碼及 Demo：&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;GitHub：&lt;a href="https://github.com/letswritetw/letswrite-night-patrol" rel="noopener noreferrer"&gt;https://github.com/letswritetw/letswrite-night-patrol&lt;/a&gt;
&lt;/li&gt;
&lt;li&gt;Demo：&lt;a href="https://letswritetw.github.io/letswrite-night-patrol/" rel="noopener noreferrer"&gt;https://letswritetw.github.io/letswrite-night-patrol/&lt;/a&gt;
&lt;/li&gt;
&lt;/ul&gt;




&lt;h2&gt;
  
  
  夜巡，就像交給一支半夜睡不著覺的小隊
&lt;/h2&gt;

&lt;p&gt;我們可以把夜巡想成一個大家都不想睡覺的 Team。&lt;/p&gt;

&lt;p&gt;有人先想「今晚可以做什麼」，有人把點子做出來，接著有人檢查成果。&lt;/p&gt;

&lt;p&gt;最後留下程式、圖片和工作紀錄，方便發表在網路上。&lt;/p&gt;

&lt;p&gt;在 7 天試用期到之前，最後一次的夜巡有列出三個候選題目：&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;圓形連線&lt;/li&gt;
&lt;li&gt;希爾伯特曲線&lt;/li&gt;
&lt;li&gt;模仿植物種子排列的圖案&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;最後 Team Leader 選中圓形連線，紀錄裡提到的理由包括圖案容易辨識、規則簡單，以及容易檢查連線結果。&lt;/p&gt;

&lt;p&gt;換成人話就是，這是一個「看得出成果，也查得出有沒有做對」的功能。&lt;/p&gt;




&lt;h2&gt;
  
  
  夜巡 Agents 設定值
&lt;/h2&gt;

&lt;p&gt;為了完成每天的夜巡，跟 ChatGPT 討論了一下，最後這些是夜巡 Team 的 Agents 設定。&lt;/p&gt;

&lt;h3&gt;
  
  
  Agent1：Night Lead
&lt;/h3&gt;

&lt;p&gt;名稱：NightLead&lt;/p&gt;

&lt;p&gt;說明：&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;你是 NightForge Lab 的 Exploration Lead 與最終 Outcome Owner。

你的工作不是自己完成所有研究與開發，而是協調 Explorer、Builder、Critic 在限定時間內完成一次高自主性的夜間實驗。

每次 Routine 開始時：

1. 取得今天日期 YYYY-MM-DD。
2. 建立全新的工作目錄：
   /workspace/bots/night-lab/runs/YYYY-MM-DD/
3. 確認目錄一開始是空的，不沿用昨天的 Source Code。
4. 建立：
   - README.md
   - EXPLORATION_LOG.md
   - WHAT_I_BUILT.md
   - NEXT_STEPS.md
   - STATUS.json
5. 在 STATUS.json 紀錄：
   - run_date
   - started_at
   - current_phase
   - selected_idea
   - build_status
   - test_status
   - critic_status
   - final_status

你負責時間控制。

建議六小時 NightForge Window：
- 03:00–04:00：Explorer 研究與選題
- 04:00–07:15：Builder 實作、Build、Debug、Test
- 07:15–08:00：Critic 獨立驗證
- 08:00–08:35：Builder 根據 Critic 結果修正一次
- 08:35–09:00：NightLead 最終驗收、文件與 Morning Report

如果某階段提早完成，可以直接進入下一階段。
不要為了把時間用滿而製造無意義工作。

你必須確保 Specialist 之間真的有交接：
Explorer → Builder → Critic → Builder(optional fix) → NightLead。

你不能因為自己比較快，就跳過 Critic 或自行假裝 Specialist 已完成工作。

選題原則：
- 不要求與我的工作直接相關。
- 可以是 Developer Tool、Web Prototype、iOS Experiment、AI Agent、MCP Tool、Automation、Creative Coding、資料視覺化、CLI、小遊戲、UX Experiment、API Experiment 或任何合理軟體實驗。
- 鼓勵有技術探索價值、能真正做出來、隔天容易體驗的題目。
- 不要每天都做同一種類型。

安全邊界：
- 只能在 /workspace/bots/night-lab/runs/YYYY-MM-DD/ 寫入。
- 不讀其他 Bot 工作目錄。
- 不讀 Sean 的正式專案。
- 不讀公司 Repo、內部文件、內網系統、公司 API、公司帳號。
- 不使用私有 Source Code 當實驗材料。
- 不碰 Production。
- 不操作 Production DB。
- 不自行對外發文。
- 不自行寄 Email。
- 不購買付費服務。
- 不開通付費 API。
- 不自動 push 到任何正式 Repo。
- 不使用 Force Push。
- 不取得或擴大 Secrets / Credentials 權限。

允許：
- 使用公開網路資料做技術研究。
- 使用合法可用的免費 Open Source 套件。
- 在 Sandbox 安裝必要 dependency。
- 建立 Local Git Repo。
- 建立多個 Local Commits。
- 啟動本機測試服務。
- 寫 Test。
- 產生 Screenshots、Demo、Build Artifact。

若選題需要付費 API、正式帳號、公司資料、Production 或敏感權限才有辦法繼續，不要要求我半夜處理；直接 Pivot 成不需要這些條件的版本。

如果 Builder 無法完成原始 Scope，你應要求縮小 Scope，而不是留下大量 TODO 後宣稱完成。

最後你必須親自驗收：
- 是否真的能執行
- Build 是否成功
- Test 是否成功
- 核心功能是否能使用
- Critic 找到的重大問題是否已處理
- README 是否能讓隔天的人類重現

最後建立：
/workspace/ops/team-reports/nightforge/YYYY-MM-DD.md

Morning Report 至少包含：
1. 今晚選了什麼題目
2. 為什麼選它
3. 最後實際做出了什麼
4. 使用的技術
5. Build / Test / Demo 狀態
6. Critic 發現什麼
7. Builder 修正了什麼
8. 如何執行或體驗
9. 是否值得留下
10. 如果值得，下一步是什麼
11. 如果不值得，學到了什麼
12. 哪些 Agent / Prompt / Handoff 可以改善
13. 完整檔案位置
14. Local Git commit 摘要

不要用漂亮報告掩蓋失敗。
如果實驗失敗，明確標示 FAILED / PARTIAL，並說明真正原因。
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;h3&gt;
  
  
  Agent2：Explorer
&lt;/h3&gt;

&lt;p&gt;名稱：Explorer&lt;/p&gt;

&lt;p&gt;說明：&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;你是 NightForge Lab 的 Autonomous Idea Explorer。

你的任務不是直接開發，而是回答：
「如果今晚只有幾個小時，我最想實際做出什麼有趣、值得驗證的東西？」

你可以：
- 搜尋公開 Web
- 查看公開 GitHub / Release / API / 技術文件
- 研究近期開發者工具、AI、Web、Mobile、Automation、Creative Coding 等方向
- 從完全沒有新聞性的問題出發，只因為技術上有趣也可以

你不能：
- 讀其他 Team 的工作內容找題目
- 讀公司資料
- 讀我的私有專案
- 從正式 Backlog 偷拿需求
- 因為「看起來對公司有用」而越過 Sandbox 邊界

選題時最多提出 3 個候選。

對每個候選快速評估：
- Why interesting
- 是否能在今晚完成 Prototype
- 技術風險
- 需要哪些外部服務
- 是否可以完全在 Sandbox 完成
- 成功後怎麼 Demo

最後只選 1 個。

優先選擇：
- 可以實際執行，而不是只能寫研究報告
- 有明確完成定義
- 不需要人工帳號操作
- 不需要付費
- 不需要 Production / 公司環境
- 有學習價值或創意價值

避免：
- 純 TODO App
- 純 Landing Page
- 只換 UI 顏色的 CRUD
- 只包裝現成 API、完全沒有技術探索
- 需要一整週才能看到結果的大型題目
- 每天重複同樣的技術棧與題型

將最後選定題目寫入：
EXPLORATION_LOG.md

交給 Builder 的 Brief 必須包含：

# Exploration Brief
- Idea
- Why tonight
- User / use case（如果有）
- Core experiment
- Definition of Done
- Recommended stack（只是建議，Builder 可修改）
- Public references
- Known risks
- What NOT to build tonight
- Demo method

選題完成後停止擴張需求，把 ownership 交給 Builder。
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;h3&gt;
  
  
  Agent3：Builder
&lt;/h3&gt;

&lt;p&gt;名稱：Builder&lt;/p&gt;

&lt;p&gt;說明：&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;你是 NightForge Lab 的 Prototype Engineer。

你接手 Explorer 的 Exploration Brief 後，最重要的工作是「把它做出來」。

開始前：
1. 閱讀 Exploration Brief。
2. 判斷建議技術是否合理。
3. 如果有更簡單、更容易在時限內完成的技術，可以自行更換。
4. 定義最小可驗證版本。
5. 初始化 Local Git Repo。

實作要求：
- 必須有可執行 Source Code。
- 必須嘗試實際 Build / Run。
- 有合理測試方式時要實際 Test。
- 遇到錯誤先自行 Debug。
- 外部 dependency 無法使用時，優先 fallback / mock / local alternative。
- 原 Scope 太大時，主動縮小但保留核心實驗價值。
- 如果核心假設證明不可行，可以 Pivot，但必須記錄原因。

不要：
- 只產生 code snippet
- 只產 README
- 只寫 architecture document
- 把所有真正困難的部分標成 TODO
- 未執行就宣稱成功
- 把 Warning 當作 Build PASS

你要持續更新：
EXPLORATION_LOG.md

至少記錄：
- Major decisions
- Failed approaches
- Important errors
- Debug path
- Scope cuts
- Pivot reason

Local Git：
- 使用有意義的 Commit
- 不需要追求很多 Commit
- Commit message 說明實際變化
- 不 Push

在交給 Critic 前，至少完成一次自己的 Self Check：
- Fresh install 是否可行
- Build 是否成功
- Core path 是否可執行
- 是否留下必要環境設定說明
- 是否有明顯 hard-coded secret
- README 是否足夠

完成第一版後通知 NightLead，並把 ownership 交給 Critic。

如果 Critic 要求一輪修正：
- 只優先處理 Critical / High-impact 問題
- 不在最後一小時加入大功能
- 修正後重新 Build / Test
- 記錄 Fix 結果
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;h3&gt;
  
  
  Agent4：Critic
&lt;/h3&gt;

&lt;p&gt;名稱：Critic&lt;/p&gt;

&lt;p&gt;說明：&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;你是 NightForge Lab 的 Independent Reviewer。

你的價值來自獨立性。
你不要參與 Explorer 的前期選題，也不要在 Builder 開發途中幫忙辯護設計決策。

只有 Builder 第一版完成後才開始。

Review 順序：

1. 不看 Builder 的自我評價，先閱讀 README。
2. 按照 README 從乾淨狀態嘗試安裝 / Build / Run。
3. 實際走核心 Demo Path。
4. 檢查是否真的符合 Exploration Brief 的 Definition of Done。
5. 再閱讀 EXPLORATION_LOG.md，理解已知限制。

你要從四個角度評估：

## A. Executability
- 能不能安裝
- 能不能 Build
- 能不能啟動
- Demo Path 能不能完成

## B. Technical quality
- 明顯 Bug
- Crash / Error
- 不必要複雜度
- fragile hard-code
- secret / security 問題
- 不合理 dependency

## C. Product / Experiment value
- 這個實驗真的驗證了什麼？
- 還是只是做出一個表面 Demo？
- 有沒有比現成方案更有趣的地方？
- 是否值得 Sean 隔天花時間看？

## D. Honesty
- README 是否誇大成果
- 是否把 Partial 寫成 Complete
- 是否把 Mock 說成真實整合
- 是否遺漏重大限制

問題分類：
- BLOCKER：無法 Build / Run / 核心路徑失敗
- HIGH：核心價值或主要功能明顯有問題
- MEDIUM：重要但不阻止 Demo
- LOW：可改善但今晚不用修

只要求 Builder 在今晚修 BLOCKER 與少數 HIGH。
不要在 Review 階段重新發明產品。

最後寫入：
WHAT_I_BUILT.md 的 Review 區段

內容：
- Tested environment
- Build result
- Run result
- Core path result
- Issues by severity
- Value assessment
- Claims that need correction
- Recommended fixes tonight
- Recommended next steps later

Reviewer 不可以因為 Builder 花很多時間，就降低標準。
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;上面 4 個 Agent 都建好後，再建一個群組，貼上以下讓它們做事就可以了：&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;@NightLead 每天 03:00 開始 Night Forge 夜間自由探索。

每天必須使用全新的：
/workspace/bots/night-lab/runs/&amp;lt;today&amp;gt;/

@Explorer
你可以自由搜尋公開資訊與選擇題目。
今晚你有一段完整的自主探索時間：Build whatever you want. Have fun!
最多提出 3 個候選，只選 1 個真正開始做。
題目不能依賴公司資料、私有 Repo、Production、付費服務或人工半夜操作。
完成 Exploration Brief 後交給 Builder。

@Builder
把選定的題目真正做成可執行 Prototype。
自主選技術、Build、Run、Debug、Test。
若 Scope 過大就縮小；如果假設失敗就 Pivot。
不要用 README 或 TODO 假裝完成。
完成第一版後交給 Critic。

@Critic
你在第一版完成前不要介入。
用陌生 Reviewer 的方式重新依 README 安裝、Build、Run、測試核心流程。
找出 BLOCKER / HIGH / MEDIUM / LOW，以及產品價值與成果誠實性問題。
如果有 BLOCKER 或少數 HIGH，要求 Builder 做一輪修正，再快速驗證。

@NightLead
控制整體六小時 Window、安全邊界與交接。
最後親自驗收 Build / Run / Test 狀態，完成 NightForge Morning Report，寫到：
/workspace/ops/team-reports/nightforge/&amp;lt;today&amp;gt;.md

最後報告要明確說：
- Complete / Partial / Failed
- 做出了什麼
- 如何執行
- 哪些東西真的有跑過
- Critic 發現什麼
- 是否值得保留
- 有什麼值得交給 ChiefOps 改善 Agent / Prompt / Workflow

安全邊界：
- 僅能在 NightForge Sandbox 寫入
- 不讀其他 Bot 目錄
- 不讀正式 Repo 或公司資料
- 不碰 Production
- 不 Push 正式 Repo
- 不發布
- 不花錢
- 不擴大權限
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;以上就是 August 跟 ChatGPT 討論過後的夜巡 Team 設定。&lt;/p&gt;

&lt;p&gt;接著繼續寫最後一次夜巡得到的成果。&lt;/p&gt;




&lt;h2&gt;
  
  
  一個圓圈拉線玩具
&lt;/h2&gt;

&lt;p&gt;想像在紙上畫一個圓，再沿著圓形周圍貼上一圈編號貼紙。&lt;/p&gt;

&lt;p&gt;訂一個規則：每張貼紙，都要拉一條線到另一張貼紙，目的地由編號乘上一個數字來決定，如果超過編號範圍，就取除法的餘數，回到圈內。&lt;/p&gt;

&lt;p&gt;這個工具做的就是這件事，它把貼紙換成圓周上的點，把線換成螢幕上的彩色線段。&lt;/p&gt;

&lt;p&gt;拿 10 個點、乘數 2 當例子，編號從 0 到 9：&lt;/p&gt;

&lt;ol&gt;
&lt;li&gt;點 3 連到點 6，因為 &lt;code&gt;3 × 2 = 6&lt;/code&gt;。&lt;/li&gt;
&lt;li&gt;點 7 連到點 4，因為 &lt;code&gt;7 × 2 = 14&lt;/code&gt;，除以 10 的餘數是 4。&lt;/li&gt;
&lt;/ol&gt;

&lt;p&gt;這兩個例子是依照程式的規則計算，我們不用自己一條條拉線，工具會替所有點算出目的地並畫出線段。&lt;/p&gt;

&lt;p&gt;預設有 200 個點，乘數是 2，很多直線疊在一起，會圍出近似心形的輪廓。&lt;/p&gt;

&lt;p&gt;程式也會跳過「自己連回自己」的點，所以這組設定實際畫出 199 條線段。&lt;/p&gt;

&lt;p&gt;&lt;a href="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.us-east-2.amazonaws.com%2Fuploads%2Farticles%2F3rk5alreflpherzq08xc.png" class="article-body-image-wrapper"&gt;&lt;img src="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.us-east-2.amazonaws.com%2Fuploads%2Farticles%2F3rk5alreflpherzq08xc.png" alt="200 個點、乘數 2 的圓形連線圖案"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;h3&gt;
  
  
  怎麼玩
&lt;/h3&gt;

&lt;p&gt;我們可以先改乘數，看看線段怎麼重新排列。&lt;/p&gt;

&lt;p&gt;接著不斷改點數，觀察同一個規則放在不同數量的點上，會產生什麼圖案。&lt;/p&gt;

&lt;p&gt;網頁提供幾個控制項：&lt;/p&gt;

&lt;div class="table-wrapper-paragraph"&gt;&lt;table&gt;
&lt;thead&gt;
&lt;tr&gt;
&lt;th&gt;控制項&lt;/th&gt;
&lt;th&gt;可以做什麼&lt;/th&gt;
&lt;/tr&gt;
&lt;/thead&gt;
&lt;tbody&gt;
&lt;tr&gt;
&lt;td&gt;點數與乘數&lt;/td&gt;
&lt;td&gt;決定圓周上有幾個點，以及連線規則&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;顏色&lt;/td&gt;
&lt;td&gt;依點的編號、線段長度上色，或使用單一顏色&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;重設&lt;/td&gt;
&lt;td&gt;回到預設圖案&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;動畫&lt;/td&gt;
&lt;td&gt;讓乘數逐步改變，觀察圖案變化&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;匯出&lt;/td&gt;
&lt;td&gt;下載目前的 SVG 圖片&lt;/td&gt;
&lt;/tr&gt;
&lt;/tbody&gt;
&lt;/table&gt;&lt;/div&gt;

&lt;p&gt;SVG 可以想成「記錄線怎麼畫」的圖片格式。這個專案的 SVG 就是由線段元素組成；另外，Python 指令版也能產生 PNG 圖片。&lt;/p&gt;




&lt;h2&gt;
  
  
  這次夜巡，留下了什麼？
&lt;/h2&gt;

&lt;p&gt;這次 Agents 留下的東西包括可以操作的網頁、圖片匯出程式、範例圖片、自動測試、選題、檢查紀錄。&lt;/p&gt;

&lt;p&gt;當我們睡醒，打開電腦就能知道它選了什麼、做了什麼，也能找到驗證結果。&lt;/p&gt;

&lt;p&gt;這次不是什麼專業的技術文，而是一種 AI 使用紀錄，也許再過一年回頭看，以那時的 AI 技術來說，這篇就是個考古的筆記吧？&lt;/p&gt;

</description>
      <category>ai</category>
      <category>agents</category>
      <category>grokbot</category>
      <category>javascript</category>
    </item>
    <item>
      <title>告別逾期罰單！用 n8n 免費打造全台路邊停車費自動查詢 Telegram 機器人通知</title>
      <dc:creator>Let's Write</dc:creator>
      <pubDate>Tue, 15 Sep 2026 12:41:53 +0000</pubDate>
      <link>https://dev.to/letswrite/gao-bie-yu-qi-fa-dan-yong-n8n-mian-fei-da-zao-quan-tai-lu-bian-ting-che-fei-zi-dong-cha-xun-telegram-ji-qi-ren-tong-zhi-io3</link>
      <guid>https://dev.to/letswrite/gao-bie-yu-qi-fa-dan-yong-n8n-mian-fei-da-zao-quan-tai-lu-bian-ting-che-fei-zi-dong-cha-xun-telegram-ji-qi-ren-tong-zhi-io3</guid>
      <description>&lt;h2&gt;
  
  
  本篇要解決的問題
&lt;/h2&gt;

&lt;p&gt;最近裝的一個 App，因為變成必須要付費訂閱，才能有自動繳停車費的功能。為了避免停車費過期而多收錢，所以讓 ChatGPT 寫一個簡單的 n8n Workflow，匯入後修改一下設定資料，就可以每天自動通知還有沒有未繳的停車費。&lt;/p&gt;

&lt;p&gt;August 希望做到以下幾件事：&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;不用每天自己打開停車費網站查詢。&lt;/li&gt;
&lt;li&gt;可以同時查詢汽車、機車。&lt;/li&gt;
&lt;li&gt;可以設定多台車。&lt;/li&gt;
&lt;li&gt;一次查詢多個縣市。&lt;/li&gt;
&lt;li&gt;每天固定時間自動執行。&lt;/li&gt;
&lt;li&gt;有未繳停車費時，主動透過 Telegram 通知。&lt;/li&gt;
&lt;li&gt;某個縣市 API 發生錯誤時，也要告訴我，不能直接把它當成「沒有欠費」。&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;而且，以上全部的需求，都可以放在 &lt;strong&gt;同一個 n8n Workflow&lt;/strong&gt; 裡，不需要汽車、機車各做一份。&lt;/p&gt;




&lt;h2&gt;
  
  
  Workflow JSON 下載、匯入
&lt;/h2&gt;

&lt;p&gt;直接複製以下 n8n Workflow，接著進入 n8n，直接貼上：&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight json"&gt;&lt;code&gt;&lt;span class="p"&gt;{&lt;/span&gt;&lt;span class="w"&gt;
  &lt;/span&gt;&lt;span class="nl"&gt;"name"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="s2"&gt;"全台路邊停車費自動查詢｜多車輛＋21縣市＋Telegram v4"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt;
  &lt;/span&gt;&lt;span class="nl"&gt;"nodes"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="w"&gt;
    &lt;/span&gt;&lt;span class="p"&gt;{&lt;/span&gt;&lt;span class="w"&gt;
      &lt;/span&gt;&lt;span class="nl"&gt;"parameters"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="p"&gt;{},&lt;/span&gt;&lt;span class="w"&gt;
      &lt;/span&gt;&lt;span class="nl"&gt;"id"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="s2"&gt;"9d4d1385-782c-4c2d-9c50-5b1a80cf6d83"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt;
      &lt;/span&gt;&lt;span class="nl"&gt;"name"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="s2"&gt;"手動測試"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt;
      &lt;/span&gt;&lt;span class="nl"&gt;"type"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="s2"&gt;"n8n-nodes-base.manualTrigger"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt;
      &lt;/span&gt;&lt;span class="nl"&gt;"typeVersion"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="mi"&gt;1&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt;
      &lt;/span&gt;&lt;span class="nl"&gt;"position"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="mi"&gt;-1160&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="mi"&gt;160&lt;/span&gt;&lt;span class="p"&gt;]&lt;/span&gt;&lt;span class="w"&gt;
    &lt;/span&gt;&lt;span class="p"&gt;},&lt;/span&gt;&lt;span class="w"&gt;
    &lt;/span&gt;&lt;span class="p"&gt;{&lt;/span&gt;&lt;span class="w"&gt;
      &lt;/span&gt;&lt;span class="nl"&gt;"parameters"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="p"&gt;{&lt;/span&gt;&lt;span class="w"&gt;
        &lt;/span&gt;&lt;span class="nl"&gt;"rule"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="p"&gt;{&lt;/span&gt;&lt;span class="w"&gt;
          &lt;/span&gt;&lt;span class="nl"&gt;"interval"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="w"&gt;
            &lt;/span&gt;&lt;span class="p"&gt;{&lt;/span&gt;&lt;span class="w"&gt;
              &lt;/span&gt;&lt;span class="nl"&gt;"field"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="s2"&gt;"cronExpression"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt;
              &lt;/span&gt;&lt;span class="nl"&gt;"expression"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="s2"&gt;"0 9 * * *"&lt;/span&gt;&lt;span class="w"&gt;
            &lt;/span&gt;&lt;span class="p"&gt;}&lt;/span&gt;&lt;span class="w"&gt;
          &lt;/span&gt;&lt;span class="p"&gt;]&lt;/span&gt;&lt;span class="w"&gt;
        &lt;/span&gt;&lt;span class="p"&gt;}&lt;/span&gt;&lt;span class="w"&gt;
      &lt;/span&gt;&lt;span class="p"&gt;},&lt;/span&gt;&lt;span class="w"&gt;
      &lt;/span&gt;&lt;span class="nl"&gt;"id"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="s2"&gt;"ec576177-01d7-468f-8777-196e1656a71d"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt;
      &lt;/span&gt;&lt;span class="nl"&gt;"name"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="s2"&gt;"每天 09:00"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt;
      &lt;/span&gt;&lt;span class="nl"&gt;"type"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="s2"&gt;"n8n-nodes-base.scheduleTrigger"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt;
      &lt;/span&gt;&lt;span class="nl"&gt;"typeVersion"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="mf"&gt;1.2&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt;
      &lt;/span&gt;&lt;span class="nl"&gt;"position"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="mi"&gt;-1160&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="mi"&gt;-40&lt;/span&gt;&lt;span class="p"&gt;]&lt;/span&gt;&lt;span class="w"&gt;
    &lt;/span&gt;&lt;span class="p"&gt;},&lt;/span&gt;&lt;span class="w"&gt;
    &lt;/span&gt;&lt;span class="p"&gt;{&lt;/span&gt;&lt;span class="w"&gt;
      &lt;/span&gt;&lt;span class="nl"&gt;"parameters"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="p"&gt;{&lt;/span&gt;&lt;span class="w"&gt;
        &lt;/span&gt;&lt;span class="nl"&gt;"assignments"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="p"&gt;{&lt;/span&gt;&lt;span class="w"&gt;
          &lt;/span&gt;&lt;span class="nl"&gt;"assignments"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="w"&gt;
            &lt;/span&gt;&lt;span class="p"&gt;{&lt;/span&gt;&lt;span class="w"&gt;
              &lt;/span&gt;&lt;span class="nl"&gt;"id"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="s2"&gt;"4728964e-002f-4430-838c-6e44d2deda12"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt;
              &lt;/span&gt;&lt;span class="nl"&gt;"name"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="s2"&gt;"telegramChatId"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt;
              &lt;/span&gt;&lt;span class="nl"&gt;"value"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="s2"&gt;"請改成你的 Telegram Chat ID"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt;
              &lt;/span&gt;&lt;span class="nl"&gt;"type"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="s2"&gt;"string"&lt;/span&gt;&lt;span class="w"&gt;
            &lt;/span&gt;&lt;span class="p"&gt;},&lt;/span&gt;&lt;span class="w"&gt;
            &lt;/span&gt;&lt;span class="p"&gt;{&lt;/span&gt;&lt;span class="w"&gt;
              &lt;/span&gt;&lt;span class="nl"&gt;"id"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="s2"&gt;"990ecf7e-feaa-4a91-9118-f378adb5d4d9"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt;
              &lt;/span&gt;&lt;span class="nl"&gt;"name"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="s2"&gt;"notifyWhenClear"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt;
              &lt;/span&gt;&lt;span class="nl"&gt;"value"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="kc"&gt;false&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt;
              &lt;/span&gt;&lt;span class="nl"&gt;"type"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="s2"&gt;"boolean"&lt;/span&gt;&lt;span class="w"&gt;
            &lt;/span&gt;&lt;span class="p"&gt;},&lt;/span&gt;&lt;span class="w"&gt;
            &lt;/span&gt;&lt;span class="p"&gt;{&lt;/span&gt;&lt;span class="w"&gt;
              &lt;/span&gt;&lt;span class="nl"&gt;"id"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="s2"&gt;"c69ea629-43b8-466a-bbb0-a5610d2d83e7"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt;
              &lt;/span&gt;&lt;span class="nl"&gt;"name"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="s2"&gt;"vehiclesJson"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt;
              &lt;/span&gt;&lt;span class="nl"&gt;"value"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="s2"&gt;"[&lt;/span&gt;&lt;span class="se"&gt;\n&lt;/span&gt;&lt;span class="s2"&gt;  {&lt;/span&gt;&lt;span class="se"&gt;\n&lt;/span&gt;&lt;span class="s2"&gt;    &lt;/span&gt;&lt;span class="se"&gt;\"&lt;/span&gt;&lt;span class="s2"&gt;label&lt;/span&gt;&lt;span class="se"&gt;\"&lt;/span&gt;&lt;span class="s2"&gt;: &lt;/span&gt;&lt;span class="se"&gt;\"&lt;/span&gt;&lt;span class="s2"&gt;我的汽車&lt;/span&gt;&lt;span class="se"&gt;\"&lt;/span&gt;&lt;span class="s2"&gt;,&lt;/span&gt;&lt;span class="se"&gt;\n&lt;/span&gt;&lt;span class="s2"&gt;    &lt;/span&gt;&lt;span class="se"&gt;\"&lt;/span&gt;&lt;span class="s2"&gt;carId&lt;/span&gt;&lt;span class="se"&gt;\"&lt;/span&gt;&lt;span class="s2"&gt;: &lt;/span&gt;&lt;span class="se"&gt;\"&lt;/span&gt;&lt;span class="s2"&gt;ABC-1234&lt;/span&gt;&lt;span class="se"&gt;\"&lt;/span&gt;&lt;span class="s2"&gt;,&lt;/span&gt;&lt;span class="se"&gt;\n&lt;/span&gt;&lt;span class="s2"&gt;    &lt;/span&gt;&lt;span class="se"&gt;\"&lt;/span&gt;&lt;span class="s2"&gt;carType&lt;/span&gt;&lt;span class="se"&gt;\"&lt;/span&gt;&lt;span class="s2"&gt;: &lt;/span&gt;&lt;span class="se"&gt;\"&lt;/span&gt;&lt;span class="s2"&gt;C&lt;/span&gt;&lt;span class="se"&gt;\"\n&lt;/span&gt;&lt;span class="s2"&gt;  },&lt;/span&gt;&lt;span class="se"&gt;\n&lt;/span&gt;&lt;span class="s2"&gt;  {&lt;/span&gt;&lt;span class="se"&gt;\n&lt;/span&gt;&lt;span class="s2"&gt;    &lt;/span&gt;&lt;span class="se"&gt;\"&lt;/span&gt;&lt;span class="s2"&gt;label&lt;/span&gt;&lt;span class="se"&gt;\"&lt;/span&gt;&lt;span class="s2"&gt;: &lt;/span&gt;&lt;span class="se"&gt;\"&lt;/span&gt;&lt;span class="s2"&gt;我的機車&lt;/span&gt;&lt;span class="se"&gt;\"&lt;/span&gt;&lt;span class="s2"&gt;,&lt;/span&gt;&lt;span class="se"&gt;\n&lt;/span&gt;&lt;span class="s2"&gt;    &lt;/span&gt;&lt;span class="se"&gt;\"&lt;/span&gt;&lt;span class="s2"&gt;carId&lt;/span&gt;&lt;span class="se"&gt;\"&lt;/span&gt;&lt;span class="s2"&gt;: &lt;/span&gt;&lt;span class="se"&gt;\"&lt;/span&gt;&lt;span class="s2"&gt;XYZ-5678&lt;/span&gt;&lt;span class="se"&gt;\"&lt;/span&gt;&lt;span class="s2"&gt;,&lt;/span&gt;&lt;span class="se"&gt;\n&lt;/span&gt;&lt;span class="s2"&gt;    &lt;/span&gt;&lt;span class="se"&gt;\"&lt;/span&gt;&lt;span class="s2"&gt;carType&lt;/span&gt;&lt;span class="se"&gt;\"&lt;/span&gt;&lt;span class="s2"&gt;: &lt;/span&gt;&lt;span class="se"&gt;\"&lt;/span&gt;&lt;span class="s2"&gt;M&lt;/span&gt;&lt;span class="se"&gt;\"\n&lt;/span&gt;&lt;span class="s2"&gt;  }&lt;/span&gt;&lt;span class="se"&gt;\n&lt;/span&gt;&lt;span class="s2"&gt;]"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt;
              &lt;/span&gt;&lt;span class="nl"&gt;"type"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="s2"&gt;"string"&lt;/span&gt;&lt;span class="w"&gt;
            &lt;/span&gt;&lt;span class="p"&gt;},&lt;/span&gt;&lt;span class="w"&gt;
            &lt;/span&gt;&lt;span class="p"&gt;{&lt;/span&gt;&lt;span class="w"&gt;
              &lt;/span&gt;&lt;span class="nl"&gt;"id"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="s2"&gt;"fc5463ba-96f0-49a6-a280-3863bdd345bc"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt;
              &lt;/span&gt;&lt;span class="nl"&gt;"name"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="s2"&gt;"citiesJson"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt;
              &lt;/span&gt;&lt;span class="nl"&gt;"value"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="s2"&gt;"[&lt;/span&gt;&lt;span class="se"&gt;\n&lt;/span&gt;&lt;span class="s2"&gt;  {&lt;/span&gt;&lt;span class="se"&gt;\n&lt;/span&gt;&lt;span class="s2"&gt;    &lt;/span&gt;&lt;span class="se"&gt;\"&lt;/span&gt;&lt;span class="s2"&gt;name&lt;/span&gt;&lt;span class="se"&gt;\"&lt;/span&gt;&lt;span class="s2"&gt;: &lt;/span&gt;&lt;span class="se"&gt;\"&lt;/span&gt;&lt;span class="s2"&gt;臺北市&lt;/span&gt;&lt;span class="se"&gt;\"&lt;/span&gt;&lt;span class="s2"&gt;,&lt;/span&gt;&lt;span class="se"&gt;\n&lt;/span&gt;&lt;span class="s2"&gt;    &lt;/span&gt;&lt;span class="se"&gt;\"&lt;/span&gt;&lt;span class="s2"&gt;urlTemplate&lt;/span&gt;&lt;span class="se"&gt;\"&lt;/span&gt;&lt;span class="s2"&gt;: &lt;/span&gt;&lt;span class="se"&gt;\"&lt;/span&gt;&lt;span class="s2"&gt;https://trafficapi.pma.gov.taipei/Parking/PayBill/CarID/{CarID}/CarType/{CarType}&lt;/span&gt;&lt;span class="se"&gt;\"&lt;/span&gt;&lt;span class="s2"&gt;,&lt;/span&gt;&lt;span class="se"&gt;\n&lt;/span&gt;&lt;span class="s2"&gt;    &lt;/span&gt;&lt;span class="se"&gt;\"&lt;/span&gt;&lt;span class="s2"&gt;enabled&lt;/span&gt;&lt;span class="se"&gt;\"&lt;/span&gt;&lt;span class="s2"&gt;: true&lt;/span&gt;&lt;span class="se"&gt;\n&lt;/span&gt;&lt;span class="s2"&gt;  },&lt;/span&gt;&lt;span class="se"&gt;\n&lt;/span&gt;&lt;span class="s2"&gt;  {&lt;/span&gt;&lt;span class="se"&gt;\n&lt;/span&gt;&lt;span class="s2"&gt;    &lt;/span&gt;&lt;span class="se"&gt;\"&lt;/span&gt;&lt;span class="s2"&gt;name&lt;/span&gt;&lt;span class="se"&gt;\"&lt;/span&gt;&lt;span class="s2"&gt;: &lt;/span&gt;&lt;span class="se"&gt;\"&lt;/span&gt;&lt;span class="s2"&gt;新北市&lt;/span&gt;&lt;span class="se"&gt;\"&lt;/span&gt;&lt;span class="s2"&gt;,&lt;/span&gt;&lt;span class="se"&gt;\n&lt;/span&gt;&lt;span class="s2"&gt;    &lt;/span&gt;&lt;span class="se"&gt;\"&lt;/span&gt;&lt;span class="s2"&gt;urlTemplate&lt;/span&gt;&lt;span class="se"&gt;\"&lt;/span&gt;&lt;span class="s2"&gt;: &lt;/span&gt;&lt;span class="se"&gt;\"&lt;/span&gt;&lt;span class="s2"&gt;https://trafficapi.traffic.ntpc.gov.tw/Parking/PayBill/CarID/{CarID}/CarType/{CarType}&lt;/span&gt;&lt;span class="se"&gt;\"&lt;/span&gt;&lt;span class="s2"&gt;,&lt;/span&gt;&lt;span class="se"&gt;\n&lt;/span&gt;&lt;span class="s2"&gt;    &lt;/span&gt;&lt;span class="se"&gt;\"&lt;/span&gt;&lt;span class="s2"&gt;enabled&lt;/span&gt;&lt;span class="se"&gt;\"&lt;/span&gt;&lt;span class="s2"&gt;: true&lt;/span&gt;&lt;span class="se"&gt;\n&lt;/span&gt;&lt;span class="s2"&gt;  },&lt;/span&gt;&lt;span class="se"&gt;\n&lt;/span&gt;&lt;span class="s2"&gt;  {&lt;/span&gt;&lt;span class="se"&gt;\n&lt;/span&gt;&lt;span class="s2"&gt;    &lt;/span&gt;&lt;span class="se"&gt;\"&lt;/span&gt;&lt;span class="s2"&gt;name&lt;/span&gt;&lt;span class="se"&gt;\"&lt;/span&gt;&lt;span class="s2"&gt;: &lt;/span&gt;&lt;span class="se"&gt;\"&lt;/span&gt;&lt;span class="s2"&gt;桃園市&lt;/span&gt;&lt;span class="se"&gt;\"&lt;/span&gt;&lt;span class="s2"&gt;,&lt;/span&gt;&lt;span class="se"&gt;\n&lt;/span&gt;&lt;span class="s2"&gt;    &lt;/span&gt;&lt;span class="se"&gt;\"&lt;/span&gt;&lt;span class="s2"&gt;urlTemplate&lt;/span&gt;&lt;span class="se"&gt;\"&lt;/span&gt;&lt;span class="s2"&gt;: &lt;/span&gt;&lt;span class="se"&gt;\"&lt;/span&gt;&lt;span class="s2"&gt;https://bill-epark.tycg.gov.tw/Parking/PayBill/CarID/{CarID}/CarType/{CarType}&lt;/span&gt;&lt;span class="se"&gt;\"&lt;/span&gt;&lt;span class="s2"&gt;,&lt;/span&gt;&lt;span class="se"&gt;\n&lt;/span&gt;&lt;span class="s2"&gt;    &lt;/span&gt;&lt;span class="se"&gt;\"&lt;/span&gt;&lt;span class="s2"&gt;enabled&lt;/span&gt;&lt;span class="se"&gt;\"&lt;/span&gt;&lt;span class="s2"&gt;: true&lt;/span&gt;&lt;span class="se"&gt;\n&lt;/span&gt;&lt;span class="s2"&gt;  },&lt;/span&gt;&lt;span class="se"&gt;\n&lt;/span&gt;&lt;span class="s2"&gt;  {&lt;/span&gt;&lt;span class="se"&gt;\n&lt;/span&gt;&lt;span class="s2"&gt;    &lt;/span&gt;&lt;span class="se"&gt;\"&lt;/span&gt;&lt;span class="s2"&gt;name&lt;/span&gt;&lt;span class="se"&gt;\"&lt;/span&gt;&lt;span class="s2"&gt;: &lt;/span&gt;&lt;span class="se"&gt;\"&lt;/span&gt;&lt;span class="s2"&gt;臺中市&lt;/span&gt;&lt;span class="se"&gt;\"&lt;/span&gt;&lt;span class="s2"&gt;,&lt;/span&gt;&lt;span class="se"&gt;\n&lt;/span&gt;&lt;span class="s2"&gt;    &lt;/span&gt;&lt;span class="se"&gt;\"&lt;/span&gt;&lt;span class="s2"&gt;urlTemplate&lt;/span&gt;&lt;span class="se"&gt;\"&lt;/span&gt;&lt;span class="s2"&gt;: &lt;/span&gt;&lt;span class="se"&gt;\"&lt;/span&gt;&lt;span class="s2"&gt;http://tcparkingapi.taichung.gov.tw:8081/NationalParkingPayBillInquiry.Api/Parking/PayBill/CarID/{CarID}/CarType/{CarType}&lt;/span&gt;&lt;span class="se"&gt;\"&lt;/span&gt;&lt;span class="s2"&gt;,&lt;/span&gt;&lt;span class="se"&gt;\n&lt;/span&gt;&lt;span class="s2"&gt;    &lt;/span&gt;&lt;span class="se"&gt;\"&lt;/span&gt;&lt;span class="s2"&gt;enabled&lt;/span&gt;&lt;span class="se"&gt;\"&lt;/span&gt;&lt;span class="s2"&gt;: true,&lt;/span&gt;&lt;span class="se"&gt;\n&lt;/span&gt;&lt;span class="s2"&gt;    &lt;/span&gt;&lt;span class="se"&gt;\"&lt;/span&gt;&lt;span class="s2"&gt;note&lt;/span&gt;&lt;span class="se"&gt;\"&lt;/span&gt;&lt;span class="s2"&gt;: &lt;/span&gt;&lt;span class="se"&gt;\"&lt;/span&gt;&lt;span class="s2"&gt;來源未涵蓋：尚未確認此 :8081 API 是否支援 HTTPS，因此暫保留原 HTTP endpoint。&lt;/span&gt;&lt;span class="se"&gt;\"\n&lt;/span&gt;&lt;span class="s2"&gt;  },&lt;/span&gt;&lt;span class="se"&gt;\n&lt;/span&gt;&lt;span class="s2"&gt;  {&lt;/span&gt;&lt;span class="se"&gt;\n&lt;/span&gt;&lt;span class="s2"&gt;    &lt;/span&gt;&lt;span class="se"&gt;\"&lt;/span&gt;&lt;span class="s2"&gt;name&lt;/span&gt;&lt;span class="se"&gt;\"&lt;/span&gt;&lt;span class="s2"&gt;: &lt;/span&gt;&lt;span class="se"&gt;\"&lt;/span&gt;&lt;span class="s2"&gt;臺南市&lt;/span&gt;&lt;span class="se"&gt;\"&lt;/span&gt;&lt;span class="s2"&gt;,&lt;/span&gt;&lt;span class="se"&gt;\n&lt;/span&gt;&lt;span class="s2"&gt;    &lt;/span&gt;&lt;span class="se"&gt;\"&lt;/span&gt;&lt;span class="s2"&gt;urlTemplate&lt;/span&gt;&lt;span class="se"&gt;\"&lt;/span&gt;&lt;span class="s2"&gt;: &lt;/span&gt;&lt;span class="se"&gt;\"&lt;/span&gt;&lt;span class="s2"&gt;https://parkingbill.tainan.gov.tw/Parking/PayBill/CarID/{CarID}/CarType/{CarType}&lt;/span&gt;&lt;span class="se"&gt;\"&lt;/span&gt;&lt;span class="s2"&gt;,&lt;/span&gt;&lt;span class="se"&gt;\n&lt;/span&gt;&lt;span class="s2"&gt;    &lt;/span&gt;&lt;span class="se"&gt;\"&lt;/span&gt;&lt;span class="s2"&gt;enabled&lt;/span&gt;&lt;span class="se"&gt;\"&lt;/span&gt;&lt;span class="s2"&gt;: true&lt;/span&gt;&lt;span class="se"&gt;\n&lt;/span&gt;&lt;span class="s2"&gt;  },&lt;/span&gt;&lt;span class="se"&gt;\n&lt;/span&gt;&lt;span class="s2"&gt;  {&lt;/span&gt;&lt;span class="se"&gt;\n&lt;/span&gt;&lt;span class="s2"&gt;    &lt;/span&gt;&lt;span class="se"&gt;\"&lt;/span&gt;&lt;span class="s2"&gt;name&lt;/span&gt;&lt;span class="se"&gt;\"&lt;/span&gt;&lt;span class="s2"&gt;: &lt;/span&gt;&lt;span class="se"&gt;\"&lt;/span&gt;&lt;span class="s2"&gt;高雄市&lt;/span&gt;&lt;span class="se"&gt;\"&lt;/span&gt;&lt;span class="s2"&gt;,&lt;/span&gt;&lt;span class="se"&gt;\n&lt;/span&gt;&lt;span class="s2"&gt;    &lt;/span&gt;&lt;span class="se"&gt;\"&lt;/span&gt;&lt;span class="s2"&gt;urlTemplate&lt;/span&gt;&lt;span class="se"&gt;\"&lt;/span&gt;&lt;span class="s2"&gt;: &lt;/span&gt;&lt;span class="se"&gt;\"&lt;/span&gt;&lt;span class="s2"&gt;https://kpp.tbkc.gov.tw/parking/V1/parking/PayBill/CarID/{CarID}/CarType/{CarType}&lt;/span&gt;&lt;span class="se"&gt;\"&lt;/span&gt;&lt;span class="s2"&gt;,&lt;/span&gt;&lt;span class="se"&gt;\n&lt;/span&gt;&lt;span class="s2"&gt;    &lt;/span&gt;&lt;span class="se"&gt;\"&lt;/span&gt;&lt;span class="s2"&gt;enabled&lt;/span&gt;&lt;span class="se"&gt;\"&lt;/span&gt;&lt;span class="s2"&gt;: true&lt;/span&gt;&lt;span class="se"&gt;\n&lt;/span&gt;&lt;span class="s2"&gt;  },&lt;/span&gt;&lt;span class="se"&gt;\n&lt;/span&gt;&lt;span class="s2"&gt;  {&lt;/span&gt;&lt;span class="se"&gt;\n&lt;/span&gt;&lt;span class="s2"&gt;    &lt;/span&gt;&lt;span class="se"&gt;\"&lt;/span&gt;&lt;span class="s2"&gt;name&lt;/span&gt;&lt;span class="se"&gt;\"&lt;/span&gt;&lt;span class="s2"&gt;: &lt;/span&gt;&lt;span class="se"&gt;\"&lt;/span&gt;&lt;span class="s2"&gt;基隆市&lt;/span&gt;&lt;span class="se"&gt;\"&lt;/span&gt;&lt;span class="s2"&gt;,&lt;/span&gt;&lt;span class="se"&gt;\n&lt;/span&gt;&lt;span class="s2"&gt;    &lt;/span&gt;&lt;span class="se"&gt;\"&lt;/span&gt;&lt;span class="s2"&gt;urlTemplate&lt;/span&gt;&lt;span class="se"&gt;\"&lt;/span&gt;&lt;span class="s2"&gt;: &lt;/span&gt;&lt;span class="se"&gt;\"&lt;/span&gt;&lt;span class="s2"&gt;https://park.klcg.gov.tw/TrafficPayBill/Parking/PayBill/CarID/{CarID}/CarType/{CarType}&lt;/span&gt;&lt;span class="se"&gt;\"&lt;/span&gt;&lt;span class="s2"&gt;,&lt;/span&gt;&lt;span class="se"&gt;\n&lt;/span&gt;&lt;span class="s2"&gt;    &lt;/span&gt;&lt;span class="se"&gt;\"&lt;/span&gt;&lt;span class="s2"&gt;enabled&lt;/span&gt;&lt;span class="se"&gt;\"&lt;/span&gt;&lt;span class="s2"&gt;: true&lt;/span&gt;&lt;span class="se"&gt;\n&lt;/span&gt;&lt;span class="s2"&gt;  },&lt;/span&gt;&lt;span class="se"&gt;\n&lt;/span&gt;&lt;span class="s2"&gt;  {&lt;/span&gt;&lt;span class="se"&gt;\n&lt;/span&gt;&lt;span class="s2"&gt;    &lt;/span&gt;&lt;span class="se"&gt;\"&lt;/span&gt;&lt;span class="s2"&gt;name&lt;/span&gt;&lt;span class="se"&gt;\"&lt;/span&gt;&lt;span class="s2"&gt;: &lt;/span&gt;&lt;span class="se"&gt;\"&lt;/span&gt;&lt;span class="s2"&gt;新竹市&lt;/span&gt;&lt;span class="se"&gt;\"&lt;/span&gt;&lt;span class="s2"&gt;,&lt;/span&gt;&lt;span class="se"&gt;\n&lt;/span&gt;&lt;span class="s2"&gt;    &lt;/span&gt;&lt;span class="se"&gt;\"&lt;/span&gt;&lt;span class="s2"&gt;urlTemplate&lt;/span&gt;&lt;span class="se"&gt;\"&lt;/span&gt;&lt;span class="s2"&gt;: &lt;/span&gt;&lt;span class="se"&gt;\"&lt;/span&gt;&lt;span class="s2"&gt;https://his.futek.com.tw:5443/TrafficPayBill/Parking/PayBill/CarID/{CarID}/CarType/{CarType}&lt;/span&gt;&lt;span class="se"&gt;\"&lt;/span&gt;&lt;span class="s2"&gt;,&lt;/span&gt;&lt;span class="se"&gt;\n&lt;/span&gt;&lt;span class="s2"&gt;    &lt;/span&gt;&lt;span class="se"&gt;\"&lt;/span&gt;&lt;span class="s2"&gt;enabled&lt;/span&gt;&lt;span class="se"&gt;\"&lt;/span&gt;&lt;span class="s2"&gt;: true&lt;/span&gt;&lt;span class="se"&gt;\n&lt;/span&gt;&lt;span class="s2"&gt;  },&lt;/span&gt;&lt;span class="se"&gt;\n&lt;/span&gt;&lt;span class="s2"&gt;  {&lt;/span&gt;&lt;span class="se"&gt;\n&lt;/span&gt;&lt;span class="s2"&gt;    &lt;/span&gt;&lt;span class="se"&gt;\"&lt;/span&gt;&lt;span class="s2"&gt;name&lt;/span&gt;&lt;span class="se"&gt;\"&lt;/span&gt;&lt;span class="s2"&gt;: &lt;/span&gt;&lt;span class="se"&gt;\"&lt;/span&gt;&lt;span class="s2"&gt;新竹縣&lt;/span&gt;&lt;span class="se"&gt;\"&lt;/span&gt;&lt;span class="s2"&gt;,&lt;/span&gt;&lt;span class="se"&gt;\n&lt;/span&gt;&lt;span class="s2"&gt;    &lt;/span&gt;&lt;span class="se"&gt;\"&lt;/span&gt;&lt;span class="s2"&gt;urlTemplate&lt;/span&gt;&lt;span class="se"&gt;\"&lt;/span&gt;&lt;span class="s2"&gt;: &lt;/span&gt;&lt;span class="se"&gt;\"&lt;/span&gt;&lt;span class="s2"&gt;https://hcpark.hchg.gov.tw/NationalParkingPayBillInquiry/Parking/PayBill/CarID/{CarID}/CarType/{CarType}&lt;/span&gt;&lt;span class="se"&gt;\"&lt;/span&gt;&lt;span class="s2"&gt;,&lt;/span&gt;&lt;span class="se"&gt;\n&lt;/span&gt;&lt;span class="s2"&gt;    &lt;/span&gt;&lt;span class="se"&gt;\"&lt;/span&gt;&lt;span class="s2"&gt;enabled&lt;/span&gt;&lt;span class="se"&gt;\"&lt;/span&gt;&lt;span class="s2"&gt;: true&lt;/span&gt;&lt;span class="se"&gt;\n&lt;/span&gt;&lt;span class="s2"&gt;  },&lt;/span&gt;&lt;span class="se"&gt;\n&lt;/span&gt;&lt;span class="s2"&gt;  {&lt;/span&gt;&lt;span class="se"&gt;\n&lt;/span&gt;&lt;span class="s2"&gt;    &lt;/span&gt;&lt;span class="se"&gt;\"&lt;/span&gt;&lt;span class="s2"&gt;name&lt;/span&gt;&lt;span class="se"&gt;\"&lt;/span&gt;&lt;span class="s2"&gt;: &lt;/span&gt;&lt;span class="se"&gt;\"&lt;/span&gt;&lt;span class="s2"&gt;苗栗縣&lt;/span&gt;&lt;span class="se"&gt;\"&lt;/span&gt;&lt;span class="s2"&gt;,&lt;/span&gt;&lt;span class="se"&gt;\n&lt;/span&gt;&lt;span class="s2"&gt;    &lt;/span&gt;&lt;span class="se"&gt;\"&lt;/span&gt;&lt;span class="s2"&gt;urlTemplate&lt;/span&gt;&lt;span class="se"&gt;\"&lt;/span&gt;&lt;span class="s2"&gt;: &lt;/span&gt;&lt;span class="se"&gt;\"&lt;/span&gt;&lt;span class="s2"&gt;https://miaoliparking.jotangi.com.tw/TrafficPayBill/Parking/PayBill/CarID/{CarID}/CarType/{CarType}&lt;/span&gt;&lt;span class="se"&gt;\"&lt;/span&gt;&lt;span class="s2"&gt;,&lt;/span&gt;&lt;span class="se"&gt;\n&lt;/span&gt;&lt;span class="s2"&gt;    &lt;/span&gt;&lt;span class="se"&gt;\"&lt;/span&gt;&lt;span class="s2"&gt;enabled&lt;/span&gt;&lt;span class="se"&gt;\"&lt;/span&gt;&lt;span class="s2"&gt;: true&lt;/span&gt;&lt;span class="se"&gt;\n&lt;/span&gt;&lt;span class="s2"&gt;  },&lt;/span&gt;&lt;span class="se"&gt;\n&lt;/span&gt;&lt;span class="s2"&gt;  {&lt;/span&gt;&lt;span class="se"&gt;\n&lt;/span&gt;&lt;span class="s2"&gt;    &lt;/span&gt;&lt;span class="se"&gt;\"&lt;/span&gt;&lt;span class="s2"&gt;name&lt;/span&gt;&lt;span class="se"&gt;\"&lt;/span&gt;&lt;span class="s2"&gt;: &lt;/span&gt;&lt;span class="se"&gt;\"&lt;/span&gt;&lt;span class="s2"&gt;彰化縣&lt;/span&gt;&lt;span class="se"&gt;\"&lt;/span&gt;&lt;span class="s2"&gt;,&lt;/span&gt;&lt;span class="se"&gt;\n&lt;/span&gt;&lt;span class="s2"&gt;    &lt;/span&gt;&lt;span class="se"&gt;\"&lt;/span&gt;&lt;span class="s2"&gt;urlTemplate&lt;/span&gt;&lt;span class="se"&gt;\"&lt;/span&gt;&lt;span class="s2"&gt;: &lt;/span&gt;&lt;span class="se"&gt;\"&lt;/span&gt;&lt;span class="s2"&gt;https://chpark.chcg.gov.tw/TrafficPayBill/Parking/PayBill/CarID/{CarID}/CarType/{CarType}&lt;/span&gt;&lt;span class="se"&gt;\"&lt;/span&gt;&lt;span class="s2"&gt;,&lt;/span&gt;&lt;span class="se"&gt;\n&lt;/span&gt;&lt;span class="s2"&gt;    &lt;/span&gt;&lt;span class="se"&gt;\"&lt;/span&gt;&lt;span class="s2"&gt;enabled&lt;/span&gt;&lt;span class="se"&gt;\"&lt;/span&gt;&lt;span class="s2"&gt;: true&lt;/span&gt;&lt;span class="se"&gt;\n&lt;/span&gt;&lt;span class="s2"&gt;  },&lt;/span&gt;&lt;span class="se"&gt;\n&lt;/span&gt;&lt;span class="s2"&gt;  {&lt;/span&gt;&lt;span class="se"&gt;\n&lt;/span&gt;&lt;span class="s2"&gt;    &lt;/span&gt;&lt;span class="se"&gt;\"&lt;/span&gt;&lt;span class="s2"&gt;name&lt;/span&gt;&lt;span class="se"&gt;\"&lt;/span&gt;&lt;span class="s2"&gt;: &lt;/span&gt;&lt;span class="se"&gt;\"&lt;/span&gt;&lt;span class="s2"&gt;南投縣&lt;/span&gt;&lt;span class="se"&gt;\"&lt;/span&gt;&lt;span class="s2"&gt;,&lt;/span&gt;&lt;span class="se"&gt;\n&lt;/span&gt;&lt;span class="s2"&gt;    &lt;/span&gt;&lt;span class="se"&gt;\"&lt;/span&gt;&lt;span class="s2"&gt;urlTemplate&lt;/span&gt;&lt;span class="se"&gt;\"&lt;/span&gt;&lt;span class="s2"&gt;: &lt;/span&gt;&lt;span class="se"&gt;\"&lt;/span&gt;&lt;span class="s2"&gt;https://parking.nantou.gov.tw/TrafficPayBill/Parking/PayBill/CarID/{CarID}/CarType/{CarType}&lt;/span&gt;&lt;span class="se"&gt;\"&lt;/span&gt;&lt;span class="s2"&gt;,&lt;/span&gt;&lt;span class="se"&gt;\n&lt;/span&gt;&lt;span class="s2"&gt;    &lt;/span&gt;&lt;span class="se"&gt;\"&lt;/span&gt;&lt;span class="s2"&gt;enabled&lt;/span&gt;&lt;span class="se"&gt;\"&lt;/span&gt;&lt;span class="s2"&gt;: true&lt;/span&gt;&lt;span class="se"&gt;\n&lt;/span&gt;&lt;span class="s2"&gt;  },&lt;/span&gt;&lt;span class="se"&gt;\n&lt;/span&gt;&lt;span class="s2"&gt;  {&lt;/span&gt;&lt;span class="se"&gt;\n&lt;/span&gt;&lt;span class="s2"&gt;    &lt;/span&gt;&lt;span class="se"&gt;\"&lt;/span&gt;&lt;span class="s2"&gt;name&lt;/span&gt;&lt;span class="se"&gt;\"&lt;/span&gt;&lt;span class="s2"&gt;: &lt;/span&gt;&lt;span class="se"&gt;\"&lt;/span&gt;&lt;span class="s2"&gt;雲林縣&lt;/span&gt;&lt;span class="se"&gt;\"&lt;/span&gt;&lt;span class="s2"&gt;,&lt;/span&gt;&lt;span class="se"&gt;\n&lt;/span&gt;&lt;span class="s2"&gt;    &lt;/span&gt;&lt;span class="se"&gt;\"&lt;/span&gt;&lt;span class="s2"&gt;urlTemplate&lt;/span&gt;&lt;span class="se"&gt;\"&lt;/span&gt;&lt;span class="s2"&gt;: &lt;/span&gt;&lt;span class="se"&gt;\"&lt;/span&gt;&lt;span class="s2"&gt;https://parking.yunlin.gov.tw/TrafficPayBill/Parking/PayBill/CarID/{CarID}/CarType/{CarType}&lt;/span&gt;&lt;span class="se"&gt;\"&lt;/span&gt;&lt;span class="s2"&gt;,&lt;/span&gt;&lt;span class="se"&gt;\n&lt;/span&gt;&lt;span class="s2"&gt;    &lt;/span&gt;&lt;span class="se"&gt;\"&lt;/span&gt;&lt;span class="s2"&gt;enabled&lt;/span&gt;&lt;span class="se"&gt;\"&lt;/span&gt;&lt;span class="s2"&gt;: true&lt;/span&gt;&lt;span class="se"&gt;\n&lt;/span&gt;&lt;span class="s2"&gt;  },&lt;/span&gt;&lt;span class="se"&gt;\n&lt;/span&gt;&lt;span class="s2"&gt;  {&lt;/span&gt;&lt;span class="se"&gt;\n&lt;/span&gt;&lt;span class="s2"&gt;    &lt;/span&gt;&lt;span class="se"&gt;\"&lt;/span&gt;&lt;span class="s2"&gt;name&lt;/span&gt;&lt;span class="se"&gt;\"&lt;/span&gt;&lt;span class="s2"&gt;: &lt;/span&gt;&lt;span class="se"&gt;\"&lt;/span&gt;&lt;span class="s2"&gt;嘉義縣&lt;/span&gt;&lt;span class="se"&gt;\"&lt;/span&gt;&lt;span class="s2"&gt;,&lt;/span&gt;&lt;span class="se"&gt;\n&lt;/span&gt;&lt;span class="s2"&gt;    &lt;/span&gt;&lt;span class="se"&gt;\"&lt;/span&gt;&lt;span class="s2"&gt;urlTemplate&lt;/span&gt;&lt;span class="se"&gt;\"&lt;/span&gt;&lt;span class="s2"&gt;: &lt;/span&gt;&lt;span class="se"&gt;\"&lt;/span&gt;&lt;span class="s2"&gt;https://8voc0wuf1g.execute-api.ap-southeast-1.amazonaws.com/default/chiayi/Parking/PayBill/CarID/{CarID}/CarType/{CarType}&lt;/span&gt;&lt;span class="se"&gt;\"&lt;/span&gt;&lt;span class="s2"&gt;,&lt;/span&gt;&lt;span class="se"&gt;\n&lt;/span&gt;&lt;span class="s2"&gt;    &lt;/span&gt;&lt;span class="se"&gt;\"&lt;/span&gt;&lt;span class="s2"&gt;enabled&lt;/span&gt;&lt;span class="se"&gt;\"&lt;/span&gt;&lt;span class="s2"&gt;: true&lt;/span&gt;&lt;span class="se"&gt;\n&lt;/span&gt;&lt;span class="s2"&gt;  },&lt;/span&gt;&lt;span class="se"&gt;\n&lt;/span&gt;&lt;span class="s2"&gt;  {&lt;/span&gt;&lt;span class="se"&gt;\n&lt;/span&gt;&lt;span class="s2"&gt;    &lt;/span&gt;&lt;span class="se"&gt;\"&lt;/span&gt;&lt;span class="s2"&gt;name&lt;/span&gt;&lt;span class="se"&gt;\"&lt;/span&gt;&lt;span class="s2"&gt;: &lt;/span&gt;&lt;span class="se"&gt;\"&lt;/span&gt;&lt;span class="s2"&gt;嘉義市&lt;/span&gt;&lt;span class="se"&gt;\"&lt;/span&gt;&lt;span class="s2"&gt;,&lt;/span&gt;&lt;span class="se"&gt;\n&lt;/span&gt;&lt;span class="s2"&gt;    &lt;/span&gt;&lt;span class="se"&gt;\"&lt;/span&gt;&lt;span class="s2"&gt;urlTemplate&lt;/span&gt;&lt;span class="se"&gt;\"&lt;/span&gt;&lt;span class="s2"&gt;: &lt;/span&gt;&lt;span class="se"&gt;\"&lt;/span&gt;&lt;span class="s2"&gt;https://parking.chiayi.gov.tw/cypark/api/Parking/PayBill/CarID/{CarID}/CarType/{CarType}&lt;/span&gt;&lt;span class="se"&gt;\"&lt;/span&gt;&lt;span class="s2"&gt;,&lt;/span&gt;&lt;span class="se"&gt;\n&lt;/span&gt;&lt;span class="s2"&gt;    &lt;/span&gt;&lt;span class="se"&gt;\"&lt;/span&gt;&lt;span class="s2"&gt;enabled&lt;/span&gt;&lt;span class="se"&gt;\"&lt;/span&gt;&lt;span class="s2"&gt;: true&lt;/span&gt;&lt;span class="se"&gt;\n&lt;/span&gt;&lt;span class="s2"&gt;  },&lt;/span&gt;&lt;span class="se"&gt;\n&lt;/span&gt;&lt;span class="s2"&gt;  {&lt;/span&gt;&lt;span class="se"&gt;\n&lt;/span&gt;&lt;span class="s2"&gt;    &lt;/span&gt;&lt;span class="se"&gt;\"&lt;/span&gt;&lt;span class="s2"&gt;name&lt;/span&gt;&lt;span class="se"&gt;\"&lt;/span&gt;&lt;span class="s2"&gt;: &lt;/span&gt;&lt;span class="se"&gt;\"&lt;/span&gt;&lt;span class="s2"&gt;屏東縣&lt;/span&gt;&lt;span class="se"&gt;\"&lt;/span&gt;&lt;span class="s2"&gt;,&lt;/span&gt;&lt;span class="se"&gt;\n&lt;/span&gt;&lt;span class="s2"&gt;    &lt;/span&gt;&lt;span class="se"&gt;\"&lt;/span&gt;&lt;span class="s2"&gt;urlTemplate&lt;/span&gt;&lt;span class="se"&gt;\"&lt;/span&gt;&lt;span class="s2"&gt;: &lt;/span&gt;&lt;span class="se"&gt;\"&lt;/span&gt;&lt;span class="s2"&gt;https://8voc0wuf1g.execute-api.ap-southeast-1.amazonaws.com/default/pingtung/Parking/PayBill/CarID/{CarID}/CarType/{CarType}&lt;/span&gt;&lt;span class="se"&gt;\"&lt;/span&gt;&lt;span class="s2"&gt;,&lt;/span&gt;&lt;span class="se"&gt;\n&lt;/span&gt;&lt;span class="s2"&gt;    &lt;/span&gt;&lt;span class="se"&gt;\"&lt;/span&gt;&lt;span class="s2"&gt;enabled&lt;/span&gt;&lt;span class="se"&gt;\"&lt;/span&gt;&lt;span class="s2"&gt;: true&lt;/span&gt;&lt;span class="se"&gt;\n&lt;/span&gt;&lt;span class="s2"&gt;  },&lt;/span&gt;&lt;span class="se"&gt;\n&lt;/span&gt;&lt;span class="s2"&gt;  {&lt;/span&gt;&lt;span class="se"&gt;\n&lt;/span&gt;&lt;span class="s2"&gt;    &lt;/span&gt;&lt;span class="se"&gt;\"&lt;/span&gt;&lt;span class="s2"&gt;name&lt;/span&gt;&lt;span class="se"&gt;\"&lt;/span&gt;&lt;span class="s2"&gt;: &lt;/span&gt;&lt;span class="se"&gt;\"&lt;/span&gt;&lt;span class="s2"&gt;宜蘭縣&lt;/span&gt;&lt;span class="se"&gt;\"&lt;/span&gt;&lt;span class="s2"&gt;,&lt;/span&gt;&lt;span class="se"&gt;\n&lt;/span&gt;&lt;span class="s2"&gt;    &lt;/span&gt;&lt;span class="se"&gt;\"&lt;/span&gt;&lt;span class="s2"&gt;urlTemplate&lt;/span&gt;&lt;span class="se"&gt;\"&lt;/span&gt;&lt;span class="s2"&gt;: &lt;/span&gt;&lt;span class="se"&gt;\"&lt;/span&gt;&lt;span class="s2"&gt;https://billparking.e-land.gov.tw/Parking/PayBill/CarID/{CarID}/CarType/{CarType}&lt;/span&gt;&lt;span class="se"&gt;\"&lt;/span&gt;&lt;span class="s2"&gt;,&lt;/span&gt;&lt;span class="se"&gt;\n&lt;/span&gt;&lt;span class="s2"&gt;    &lt;/span&gt;&lt;span class="se"&gt;\"&lt;/span&gt;&lt;span class="s2"&gt;enabled&lt;/span&gt;&lt;span class="se"&gt;\"&lt;/span&gt;&lt;span class="s2"&gt;: true&lt;/span&gt;&lt;span class="se"&gt;\n&lt;/span&gt;&lt;span class="s2"&gt;  },&lt;/span&gt;&lt;span class="se"&gt;\n&lt;/span&gt;&lt;span class="s2"&gt;  {&lt;/span&gt;&lt;span class="se"&gt;\n&lt;/span&gt;&lt;span class="s2"&gt;    &lt;/span&gt;&lt;span class="se"&gt;\"&lt;/span&gt;&lt;span class="s2"&gt;name&lt;/span&gt;&lt;span class="se"&gt;\"&lt;/span&gt;&lt;span class="s2"&gt;: &lt;/span&gt;&lt;span class="se"&gt;\"&lt;/span&gt;&lt;span class="s2"&gt;花蓮縣&lt;/span&gt;&lt;span class="se"&gt;\"&lt;/span&gt;&lt;span class="s2"&gt;,&lt;/span&gt;&lt;span class="se"&gt;\n&lt;/span&gt;&lt;span class="s2"&gt;    &lt;/span&gt;&lt;span class="se"&gt;\"&lt;/span&gt;&lt;span class="s2"&gt;urlTemplate&lt;/span&gt;&lt;span class="se"&gt;\"&lt;/span&gt;&lt;span class="s2"&gt;: &lt;/span&gt;&lt;span class="se"&gt;\"&lt;/span&gt;&lt;span class="s2"&gt;https://hl.parchere.com.tw/TrafficPayBill/Parking/PayBill/CarID/{CarID}/CarType/{CarType}&lt;/span&gt;&lt;span class="se"&gt;\"&lt;/span&gt;&lt;span class="s2"&gt;,&lt;/span&gt;&lt;span class="se"&gt;\n&lt;/span&gt;&lt;span class="s2"&gt;    &lt;/span&gt;&lt;span class="se"&gt;\"&lt;/span&gt;&lt;span class="s2"&gt;enabled&lt;/span&gt;&lt;span class="se"&gt;\"&lt;/span&gt;&lt;span class="s2"&gt;: true&lt;/span&gt;&lt;span class="se"&gt;\n&lt;/span&gt;&lt;span class="s2"&gt;  },&lt;/span&gt;&lt;span class="se"&gt;\n&lt;/span&gt;&lt;span class="s2"&gt;  {&lt;/span&gt;&lt;span class="se"&gt;\n&lt;/span&gt;&lt;span class="s2"&gt;    &lt;/span&gt;&lt;span class="se"&gt;\"&lt;/span&gt;&lt;span class="s2"&gt;name&lt;/span&gt;&lt;span class="se"&gt;\"&lt;/span&gt;&lt;span class="s2"&gt;: &lt;/span&gt;&lt;span class="se"&gt;\"&lt;/span&gt;&lt;span class="s2"&gt;臺東縣&lt;/span&gt;&lt;span class="se"&gt;\"&lt;/span&gt;&lt;span class="s2"&gt;,&lt;/span&gt;&lt;span class="se"&gt;\n&lt;/span&gt;&lt;span class="s2"&gt;    &lt;/span&gt;&lt;span class="se"&gt;\"&lt;/span&gt;&lt;span class="s2"&gt;urlTemplate&lt;/span&gt;&lt;span class="se"&gt;\"&lt;/span&gt;&lt;span class="s2"&gt;: &lt;/span&gt;&lt;span class="se"&gt;\"&lt;/span&gt;&lt;span class="s2"&gt;https://tt.guoyun.com.tw/TrafficPayBill/Parking/PayBill/CarID/{CarID}/CarType/{CarType}&lt;/span&gt;&lt;span class="se"&gt;\"&lt;/span&gt;&lt;span class="s2"&gt;,&lt;/span&gt;&lt;span class="se"&gt;\n&lt;/span&gt;&lt;span class="s2"&gt;    &lt;/span&gt;&lt;span class="se"&gt;\"&lt;/span&gt;&lt;span class="s2"&gt;enabled&lt;/span&gt;&lt;span class="se"&gt;\"&lt;/span&gt;&lt;span class="s2"&gt;: true&lt;/span&gt;&lt;span class="se"&gt;\n&lt;/span&gt;&lt;span class="s2"&gt;  },&lt;/span&gt;&lt;span class="se"&gt;\n&lt;/span&gt;&lt;span class="s2"&gt;  {&lt;/span&gt;&lt;span class="se"&gt;\n&lt;/span&gt;&lt;span class="s2"&gt;    &lt;/span&gt;&lt;span class="se"&gt;\"&lt;/span&gt;&lt;span class="s2"&gt;name&lt;/span&gt;&lt;span class="se"&gt;\"&lt;/span&gt;&lt;span class="s2"&gt;: &lt;/span&gt;&lt;span class="se"&gt;\"&lt;/span&gt;&lt;span class="s2"&gt;澎湖縣&lt;/span&gt;&lt;span class="se"&gt;\"&lt;/span&gt;&lt;span class="s2"&gt;,&lt;/span&gt;&lt;span class="se"&gt;\n&lt;/span&gt;&lt;span class="s2"&gt;    &lt;/span&gt;&lt;span class="se"&gt;\"&lt;/span&gt;&lt;span class="s2"&gt;urlTemplate&lt;/span&gt;&lt;span class="se"&gt;\"&lt;/span&gt;&lt;span class="s2"&gt;: &lt;/span&gt;&lt;span class="se"&gt;\"&lt;/span&gt;&lt;span class="s2"&gt;https://parking.penghu.gov.tw/TrafficPayBill/Parking/PayBill/CarID/{CarID}/CarType/{CarType}&lt;/span&gt;&lt;span class="se"&gt;\"&lt;/span&gt;&lt;span class="s2"&gt;,&lt;/span&gt;&lt;span class="se"&gt;\n&lt;/span&gt;&lt;span class="s2"&gt;    &lt;/span&gt;&lt;span class="se"&gt;\"&lt;/span&gt;&lt;span class="s2"&gt;enabled&lt;/span&gt;&lt;span class="se"&gt;\"&lt;/span&gt;&lt;span class="s2"&gt;: true&lt;/span&gt;&lt;span class="se"&gt;\n&lt;/span&gt;&lt;span class="s2"&gt;  },&lt;/span&gt;&lt;span class="se"&gt;\n&lt;/span&gt;&lt;span class="s2"&gt;  {&lt;/span&gt;&lt;span class="se"&gt;\n&lt;/span&gt;&lt;span class="s2"&gt;    &lt;/span&gt;&lt;span class="se"&gt;\"&lt;/span&gt;&lt;span class="s2"&gt;name&lt;/span&gt;&lt;span class="se"&gt;\"&lt;/span&gt;&lt;span class="s2"&gt;: &lt;/span&gt;&lt;span class="se"&gt;\"&lt;/span&gt;&lt;span class="s2"&gt;金門縣&lt;/span&gt;&lt;span class="se"&gt;\"&lt;/span&gt;&lt;span class="s2"&gt;,&lt;/span&gt;&lt;span class="se"&gt;\n&lt;/span&gt;&lt;span class="s2"&gt;    &lt;/span&gt;&lt;span class="se"&gt;\"&lt;/span&gt;&lt;span class="s2"&gt;urlTemplate&lt;/span&gt;&lt;span class="se"&gt;\"&lt;/span&gt;&lt;span class="s2"&gt;: &lt;/span&gt;&lt;span class="se"&gt;\"&lt;/span&gt;&lt;span class="s2"&gt;https://km.guoyun.com.tw/TrafficPayBill/Parking/PayBill/CarID/{CarID}/CarType/{CarType}&lt;/span&gt;&lt;span class="se"&gt;\"&lt;/span&gt;&lt;span class="s2"&gt;,&lt;/span&gt;&lt;span class="se"&gt;\n&lt;/span&gt;&lt;span class="s2"&gt;    &lt;/span&gt;&lt;span class="se"&gt;\"&lt;/span&gt;&lt;span class="s2"&gt;enabled&lt;/span&gt;&lt;span class="se"&gt;\"&lt;/span&gt;&lt;span class="s2"&gt;: true&lt;/span&gt;&lt;span class="se"&gt;\n&lt;/span&gt;&lt;span class="s2"&gt;  }&lt;/span&gt;&lt;span class="se"&gt;\n&lt;/span&gt;&lt;span class="s2"&gt;]"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt;
              &lt;/span&gt;&lt;span class="nl"&gt;"type"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="s2"&gt;"string"&lt;/span&gt;&lt;span class="w"&gt;
            &lt;/span&gt;&lt;span class="p"&gt;}&lt;/span&gt;&lt;span class="w"&gt;
          &lt;/span&gt;&lt;span class="p"&gt;]&lt;/span&gt;&lt;span class="w"&gt;
        &lt;/span&gt;&lt;span class="p"&gt;},&lt;/span&gt;&lt;span class="w"&gt;
        &lt;/span&gt;&lt;span class="nl"&gt;"options"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="p"&gt;{}&lt;/span&gt;&lt;span class="w"&gt;
      &lt;/span&gt;&lt;span class="p"&gt;},&lt;/span&gt;&lt;span class="w"&gt;
      &lt;/span&gt;&lt;span class="nl"&gt;"id"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="s2"&gt;"cfc69392-3221-4479-b078-437991a0b749"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt;
      &lt;/span&gt;&lt;span class="nl"&gt;"name"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="s2"&gt;"設定（只改這裡）"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt;
      &lt;/span&gt;&lt;span class="nl"&gt;"type"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="s2"&gt;"n8n-nodes-base.set"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt;
      &lt;/span&gt;&lt;span class="nl"&gt;"typeVersion"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="mf"&gt;3.4&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt;
      &lt;/span&gt;&lt;span class="nl"&gt;"position"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="mi"&gt;-920&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="mi"&gt;60&lt;/span&gt;&lt;span class="p"&gt;]&lt;/span&gt;&lt;span class="w"&gt;
    &lt;/span&gt;&lt;span class="p"&gt;},&lt;/span&gt;&lt;span class="w"&gt;
    &lt;/span&gt;&lt;span class="p"&gt;{&lt;/span&gt;&lt;span class="w"&gt;
      &lt;/span&gt;&lt;span class="nl"&gt;"parameters"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="p"&gt;{&lt;/span&gt;&lt;span class="w"&gt;
        &lt;/span&gt;&lt;span class="nl"&gt;"mode"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="s2"&gt;"runOnceForAllItems"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt;
        &lt;/span&gt;&lt;span class="nl"&gt;"jsCode"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="s2"&gt;"const cfg = $input.first().json;&lt;/span&gt;&lt;span class="se"&gt;\n\n&lt;/span&gt;&lt;span class="s2"&gt;function parseJsonField(value, fieldName) {&lt;/span&gt;&lt;span class="se"&gt;\n&lt;/span&gt;&lt;span class="s2"&gt;  if (Array.isArray(value)) return value;&lt;/span&gt;&lt;span class="se"&gt;\n&lt;/span&gt;&lt;span class="s2"&gt;  try {&lt;/span&gt;&lt;span class="se"&gt;\n&lt;/span&gt;&lt;span class="s2"&gt;    return JSON.parse(value);&lt;/span&gt;&lt;span class="se"&gt;\n&lt;/span&gt;&lt;span class="s2"&gt;  } catch (e) {&lt;/span&gt;&lt;span class="se"&gt;\n&lt;/span&gt;&lt;span class="s2"&gt;    throw new Error(`${fieldName} 不是合法 JSON：${e.message}`);&lt;/span&gt;&lt;span class="se"&gt;\n&lt;/span&gt;&lt;span class="s2"&gt;  }&lt;/span&gt;&lt;span class="se"&gt;\n&lt;/span&gt;&lt;span class="s2"&gt;}&lt;/span&gt;&lt;span class="se"&gt;\n\n&lt;/span&gt;&lt;span class="s2"&gt;const vehicles = parseJsonField(cfg.vehiclesJson, 'vehiclesJson');&lt;/span&gt;&lt;span class="se"&gt;\n&lt;/span&gt;&lt;span class="s2"&gt;const cities = parseJsonField(cfg.citiesJson, 'citiesJson');&lt;/span&gt;&lt;span class="se"&gt;\n\n&lt;/span&gt;&lt;span class="s2"&gt;if (!Array.isArray(vehicles) || vehicles.length === 0) {&lt;/span&gt;&lt;span class="se"&gt;\n&lt;/span&gt;&lt;span class="s2"&gt;  throw new Error('vehiclesJson 至少要有一台車。');&lt;/span&gt;&lt;span class="se"&gt;\n&lt;/span&gt;&lt;span class="s2"&gt;}&lt;/span&gt;&lt;span class="se"&gt;\n\n&lt;/span&gt;&lt;span class="s2"&gt;const enabledCities = Array.isArray(cities)&lt;/span&gt;&lt;span class="se"&gt;\n&lt;/span&gt;&lt;span class="s2"&gt;  ? cities.filter(c =&amp;gt; c?.enabled !== false &amp;amp;&amp;amp; c?.name &amp;amp;&amp;amp; c?.urlTemplate)&lt;/span&gt;&lt;span class="se"&gt;\n&lt;/span&gt;&lt;span class="s2"&gt;  : [];&lt;/span&gt;&lt;span class="se"&gt;\n\n&lt;/span&gt;&lt;span class="s2"&gt;if (enabledCities.length === 0) {&lt;/span&gt;&lt;span class="se"&gt;\n&lt;/span&gt;&lt;span class="s2"&gt;  throw new Error('citiesJson 至少要啟用一個縣市。');&lt;/span&gt;&lt;span class="se"&gt;\n&lt;/span&gt;&lt;span class="s2"&gt;}&lt;/span&gt;&lt;span class="se"&gt;\n\n&lt;/span&gt;&lt;span class="s2"&gt;const allowedTypes = new Set(['C', 'M', 'O']);&lt;/span&gt;&lt;span class="se"&gt;\n&lt;/span&gt;&lt;span class="s2"&gt;const output = [];&lt;/span&gt;&lt;span class="se"&gt;\n\n&lt;/span&gt;&lt;span class="s2"&gt;for (const vehicle of vehicles) {&lt;/span&gt;&lt;span class="se"&gt;\n&lt;/span&gt;&lt;span class="s2"&gt;  const carId = String(vehicle?.carId ?? '').trim();&lt;/span&gt;&lt;span class="se"&gt;\n&lt;/span&gt;&lt;span class="s2"&gt;  const carType = String(vehicle?.carType ?? '').trim().toUpperCase();&lt;/span&gt;&lt;span class="se"&gt;\n&lt;/span&gt;&lt;span class="s2"&gt;  const label = String(vehicle?.label ?? carId).trim();&lt;/span&gt;&lt;span class="se"&gt;\n\n&lt;/span&gt;&lt;span class="s2"&gt;  if (!carId) throw new Error(`車輛缺少 carId：${JSON.stringify(vehicle)}`);&lt;/span&gt;&lt;span class="se"&gt;\n&lt;/span&gt;&lt;span class="s2"&gt;  if (!allowedTypes.has(carType)) {&lt;/span&gt;&lt;span class="se"&gt;\n&lt;/span&gt;&lt;span class="s2"&gt;    throw new Error(`${carId} 的 carType 必須是 C、M 或 O，目前為：${carType}`);&lt;/span&gt;&lt;span class="se"&gt;\n&lt;/span&gt;&lt;span class="s2"&gt;  }&lt;/span&gt;&lt;span class="se"&gt;\n\n&lt;/span&gt;&lt;span class="s2"&gt;  for (const city of enabledCities) {&lt;/span&gt;&lt;span class="se"&gt;\n&lt;/span&gt;&lt;span class="s2"&gt;    const queryUrl = String(city.urlTemplate)&lt;/span&gt;&lt;span class="se"&gt;\n&lt;/span&gt;&lt;span class="s2"&gt;      .replace('{CarID}', encodeURIComponent(carId))&lt;/span&gt;&lt;span class="se"&gt;\n&lt;/span&gt;&lt;span class="s2"&gt;      .replace('{CarType}', encodeURIComponent(carType));&lt;/span&gt;&lt;span class="se"&gt;\n\n&lt;/span&gt;&lt;span class="s2"&gt;    output.push({&lt;/span&gt;&lt;span class="se"&gt;\n&lt;/span&gt;&lt;span class="s2"&gt;      json: {&lt;/span&gt;&lt;span class="se"&gt;\n&lt;/span&gt;&lt;span class="s2"&gt;        label,&lt;/span&gt;&lt;span class="se"&gt;\n&lt;/span&gt;&lt;span class="s2"&gt;        carId,&lt;/span&gt;&lt;span class="se"&gt;\n&lt;/span&gt;&lt;span class="s2"&gt;        carType,&lt;/span&gt;&lt;span class="se"&gt;\n&lt;/span&gt;&lt;span class="s2"&gt;        cityName: city.name,&lt;/span&gt;&lt;span class="se"&gt;\n&lt;/span&gt;&lt;span class="s2"&gt;        queryUrl,&lt;/span&gt;&lt;span class="se"&gt;\n&lt;/span&gt;&lt;span class="s2"&gt;        telegramChatId: cfg.telegramChatId ?? '',&lt;/span&gt;&lt;span class="se"&gt;\n&lt;/span&gt;&lt;span class="s2"&gt;        notifyWhenClear: Boolean(cfg.notifyWhenClear)&lt;/span&gt;&lt;span class="se"&gt;\n&lt;/span&gt;&lt;span class="s2"&gt;      }&lt;/span&gt;&lt;span class="se"&gt;\n&lt;/span&gt;&lt;span class="s2"&gt;    });&lt;/span&gt;&lt;span class="se"&gt;\n&lt;/span&gt;&lt;span class="s2"&gt;  }&lt;/span&gt;&lt;span class="se"&gt;\n&lt;/span&gt;&lt;span class="s2"&gt;}&lt;/span&gt;&lt;span class="se"&gt;\n\n&lt;/span&gt;&lt;span class="s2"&gt;return output;"&lt;/span&gt;&lt;span class="w"&gt;
      &lt;/span&gt;&lt;span class="p"&gt;},&lt;/span&gt;&lt;span class="w"&gt;
      &lt;/span&gt;&lt;span class="nl"&gt;"id"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="s2"&gt;"fe4cf409-253c-453c-bb87-34849dfcc386"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt;
      &lt;/span&gt;&lt;span class="nl"&gt;"name"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="s2"&gt;"建立 車輛 × 縣市 查詢清單"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt;
      &lt;/span&gt;&lt;span class="nl"&gt;"type"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="s2"&gt;"n8n-nodes-base.code"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt;
      &lt;/span&gt;&lt;span class="nl"&gt;"typeVersion"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="mi"&gt;2&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt;
      &lt;/span&gt;&lt;span class="nl"&gt;"position"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="mi"&gt;-680&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="mi"&gt;60&lt;/span&gt;&lt;span class="p"&gt;]&lt;/span&gt;&lt;span class="w"&gt;
    &lt;/span&gt;&lt;span class="p"&gt;},&lt;/span&gt;&lt;span class="w"&gt;
    &lt;/span&gt;&lt;span class="p"&gt;{&lt;/span&gt;&lt;span class="w"&gt;
      &lt;/span&gt;&lt;span class="nl"&gt;"parameters"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="p"&gt;{&lt;/span&gt;&lt;span class="w"&gt;
        &lt;/span&gt;&lt;span class="nl"&gt;"batchSize"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="mi"&gt;1&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt;
        &lt;/span&gt;&lt;span class="nl"&gt;"options"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="p"&gt;{}&lt;/span&gt;&lt;span class="w"&gt;
      &lt;/span&gt;&lt;span class="p"&gt;},&lt;/span&gt;&lt;span class="w"&gt;
      &lt;/span&gt;&lt;span class="nl"&gt;"id"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="s2"&gt;"da0e1f61-1d54-4afb-82af-752252f5c50f"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt;
      &lt;/span&gt;&lt;span class="nl"&gt;"name"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="s2"&gt;"Loop Over Items（每次 1 筆）"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt;
      &lt;/span&gt;&lt;span class="nl"&gt;"type"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="s2"&gt;"n8n-nodes-base.splitInBatches"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt;
      &lt;/span&gt;&lt;span class="nl"&gt;"typeVersion"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="mi"&gt;3&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt;
      &lt;/span&gt;&lt;span class="nl"&gt;"position"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="mi"&gt;-420&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="mi"&gt;60&lt;/span&gt;&lt;span class="p"&gt;]&lt;/span&gt;&lt;span class="w"&gt;
    &lt;/span&gt;&lt;span class="p"&gt;},&lt;/span&gt;&lt;span class="w"&gt;
    &lt;/span&gt;&lt;span class="p"&gt;{&lt;/span&gt;&lt;span class="w"&gt;
      &lt;/span&gt;&lt;span class="nl"&gt;"parameters"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="p"&gt;{&lt;/span&gt;&lt;span class="w"&gt;
        &lt;/span&gt;&lt;span class="nl"&gt;"method"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="s2"&gt;"GET"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt;
        &lt;/span&gt;&lt;span class="nl"&gt;"url"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="s2"&gt;"={{ $json.queryUrl }}"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt;
        &lt;/span&gt;&lt;span class="nl"&gt;"options"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="p"&gt;{&lt;/span&gt;&lt;span class="w"&gt;
          &lt;/span&gt;&lt;span class="nl"&gt;"response"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="p"&gt;{&lt;/span&gt;&lt;span class="w"&gt;
            &lt;/span&gt;&lt;span class="nl"&gt;"response"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="p"&gt;{&lt;/span&gt;&lt;span class="w"&gt;
              &lt;/span&gt;&lt;span class="nl"&gt;"fullResponse"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="kc"&gt;true&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt;
              &lt;/span&gt;&lt;span class="nl"&gt;"neverError"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="kc"&gt;true&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt;
              &lt;/span&gt;&lt;span class="nl"&gt;"responseFormat"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="s2"&gt;"json"&lt;/span&gt;&lt;span class="w"&gt;
            &lt;/span&gt;&lt;span class="p"&gt;}&lt;/span&gt;&lt;span class="w"&gt;
          &lt;/span&gt;&lt;span class="p"&gt;},&lt;/span&gt;&lt;span class="w"&gt;
          &lt;/span&gt;&lt;span class="nl"&gt;"timeout"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="mi"&gt;10000&lt;/span&gt;&lt;span class="w"&gt;
        &lt;/span&gt;&lt;span class="p"&gt;}&lt;/span&gt;&lt;span class="w"&gt;
      &lt;/span&gt;&lt;span class="p"&gt;},&lt;/span&gt;&lt;span class="w"&gt;
      &lt;/span&gt;&lt;span class="nl"&gt;"id"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="s2"&gt;"0707ce96-44ea-4630-a5fd-184d25e128bc"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt;
      &lt;/span&gt;&lt;span class="nl"&gt;"name"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="s2"&gt;"查詢停車費 API"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt;
      &lt;/span&gt;&lt;span class="nl"&gt;"type"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="s2"&gt;"n8n-nodes-base.httpRequest"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt;
      &lt;/span&gt;&lt;span class="nl"&gt;"typeVersion"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="mf"&gt;4.2&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt;
      &lt;/span&gt;&lt;span class="nl"&gt;"position"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="mi"&gt;-160&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="mi"&gt;200&lt;/span&gt;&lt;span class="p"&gt;],&lt;/span&gt;&lt;span class="w"&gt;
      &lt;/span&gt;&lt;span class="nl"&gt;"onError"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="s2"&gt;"continueRegularOutput"&lt;/span&gt;&lt;span class="w"&gt;
    &lt;/span&gt;&lt;span class="p"&gt;},&lt;/span&gt;&lt;span class="w"&gt;
    &lt;/span&gt;&lt;span class="p"&gt;{&lt;/span&gt;&lt;span class="w"&gt;
      &lt;/span&gt;&lt;span class="nl"&gt;"parameters"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="p"&gt;{&lt;/span&gt;&lt;span class="w"&gt;
        &lt;/span&gt;&lt;span class="nl"&gt;"mode"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="s2"&gt;"runOnceForEachItem"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt;
        &lt;/span&gt;&lt;span class="nl"&gt;"jsCode"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="s2"&gt;"const row = $json ?? {};&lt;/span&gt;&lt;span class="se"&gt;\n\n&lt;/span&gt;&lt;span class="s2"&gt;const base = {&lt;/span&gt;&lt;span class="se"&gt;\n&lt;/span&gt;&lt;span class="s2"&gt;  cityName: row.cityName ?? '',&lt;/span&gt;&lt;span class="se"&gt;\n&lt;/span&gt;&lt;span class="s2"&gt;  label: row.label ?? row.carId ?? '',&lt;/span&gt;&lt;span class="se"&gt;\n&lt;/span&gt;&lt;span class="s2"&gt;  carId: row.carId ?? '',&lt;/span&gt;&lt;span class="se"&gt;\n&lt;/span&gt;&lt;span class="s2"&gt;  carType: row.carType ?? '',&lt;/span&gt;&lt;span class="se"&gt;\n&lt;/span&gt;&lt;span class="s2"&gt;  queryUrl: row.queryUrl ?? '',&lt;/span&gt;&lt;span class="se"&gt;\n&lt;/span&gt;&lt;span class="s2"&gt;  telegramChatId: row.telegramChatId ?? '',&lt;/span&gt;&lt;span class="se"&gt;\n&lt;/span&gt;&lt;span class="s2"&gt;  notifyWhenClear: Boolean(row.notifyWhenClear)&lt;/span&gt;&lt;span class="se"&gt;\n&lt;/span&gt;&lt;span class="s2"&gt;};&lt;/span&gt;&lt;span class="se"&gt;\n\n&lt;/span&gt;&lt;span class="s2"&gt;// Network/TLS/DNS errors continued by the HTTP Request node arrive as `error`.&lt;/span&gt;&lt;span class="se"&gt;\n&lt;/span&gt;&lt;span class="s2"&gt;if (row.error) {&lt;/span&gt;&lt;span class="se"&gt;\n&lt;/span&gt;&lt;span class="s2"&gt;  return {&lt;/span&gt;&lt;span class="se"&gt;\n&lt;/span&gt;&lt;span class="s2"&gt;    json: {&lt;/span&gt;&lt;span class="se"&gt;\n&lt;/span&gt;&lt;span class="s2"&gt;      ...base,&lt;/span&gt;&lt;span class="se"&gt;\n&lt;/span&gt;&lt;span class="s2"&gt;      status: 'ERROR',&lt;/span&gt;&lt;span class="se"&gt;\n&lt;/span&gt;&lt;span class="s2"&gt;      apiMessage: row.error.message || String(row.error),&lt;/span&gt;&lt;span class="se"&gt;\n&lt;/span&gt;&lt;span class="s2"&gt;      httpStatus: null,&lt;/span&gt;&lt;span class="se"&gt;\n&lt;/span&gt;&lt;span class="s2"&gt;      hasUnpaid: false,&lt;/span&gt;&lt;span class="se"&gt;\n&lt;/span&gt;&lt;span class="s2"&gt;      totalCount: 0,&lt;/span&gt;&lt;span class="se"&gt;\n&lt;/span&gt;&lt;span class="s2"&gt;      totalAmount: 0,&lt;/span&gt;&lt;span class="se"&gt;\n&lt;/span&gt;&lt;span class="s2"&gt;      details: [],&lt;/span&gt;&lt;span class="se"&gt;\n&lt;/span&gt;&lt;span class="s2"&gt;      isQueryFailed: true&lt;/span&gt;&lt;span class="se"&gt;\n&lt;/span&gt;&lt;span class="s2"&gt;    }&lt;/span&gt;&lt;span class="se"&gt;\n&lt;/span&gt;&lt;span class="s2"&gt;  };&lt;/span&gt;&lt;span class="se"&gt;\n&lt;/span&gt;&lt;span class="s2"&gt;}&lt;/span&gt;&lt;span class="se"&gt;\n\n&lt;/span&gt;&lt;span class="s2"&gt;const httpStatus = Number(row.statusCode ?? 0);&lt;/span&gt;&lt;span class="se"&gt;\n&lt;/span&gt;&lt;span class="s2"&gt;let res = row.body ?? {};&lt;/span&gt;&lt;span class="se"&gt;\n\n&lt;/span&gt;&lt;span class="s2"&gt;if (typeof res === 'string') {&lt;/span&gt;&lt;span class="se"&gt;\n&lt;/span&gt;&lt;span class="s2"&gt;  try {&lt;/span&gt;&lt;span class="se"&gt;\n&lt;/span&gt;&lt;span class="s2"&gt;    res = JSON.parse(res);&lt;/span&gt;&lt;span class="se"&gt;\n&lt;/span&gt;&lt;span class="s2"&gt;  } catch {&lt;/span&gt;&lt;span class="se"&gt;\n&lt;/span&gt;&lt;span class="s2"&gt;    return {&lt;/span&gt;&lt;span class="se"&gt;\n&lt;/span&gt;&lt;span class="s2"&gt;      json: {&lt;/span&gt;&lt;span class="se"&gt;\n&lt;/span&gt;&lt;span class="s2"&gt;        ...base,&lt;/span&gt;&lt;span class="se"&gt;\n&lt;/span&gt;&lt;span class="s2"&gt;        status: 'ERROR',&lt;/span&gt;&lt;span class="se"&gt;\n&lt;/span&gt;&lt;span class="s2"&gt;        apiMessage: `API 回傳非 JSON 內容${httpStatus ? `（HTTP ${httpStatus}）` : ''}`,&lt;/span&gt;&lt;span class="se"&gt;\n&lt;/span&gt;&lt;span class="s2"&gt;        httpStatus: httpStatus || null,&lt;/span&gt;&lt;span class="se"&gt;\n&lt;/span&gt;&lt;span class="s2"&gt;        hasUnpaid: false,&lt;/span&gt;&lt;span class="se"&gt;\n&lt;/span&gt;&lt;span class="s2"&gt;        totalCount: 0,&lt;/span&gt;&lt;span class="se"&gt;\n&lt;/span&gt;&lt;span class="s2"&gt;        totalAmount: 0,&lt;/span&gt;&lt;span class="se"&gt;\n&lt;/span&gt;&lt;span class="s2"&gt;        details: [],&lt;/span&gt;&lt;span class="se"&gt;\n&lt;/span&gt;&lt;span class="s2"&gt;        isQueryFailed: true&lt;/span&gt;&lt;span class="se"&gt;\n&lt;/span&gt;&lt;span class="s2"&gt;      }&lt;/span&gt;&lt;span class="se"&gt;\n&lt;/span&gt;&lt;span class="s2"&gt;    };&lt;/span&gt;&lt;span class="se"&gt;\n&lt;/span&gt;&lt;span class="s2"&gt;  }&lt;/span&gt;&lt;span class="se"&gt;\n&lt;/span&gt;&lt;span class="s2"&gt;}&lt;/span&gt;&lt;span class="se"&gt;\n\n&lt;/span&gt;&lt;span class="s2"&gt;if (httpStatus &amp;amp;&amp;amp; (httpStatus &amp;lt; 200 || httpStatus &amp;gt;= 300)) {&lt;/span&gt;&lt;span class="se"&gt;\n&lt;/span&gt;&lt;span class="s2"&gt;  return {&lt;/span&gt;&lt;span class="se"&gt;\n&lt;/span&gt;&lt;span class="s2"&gt;    json: {&lt;/span&gt;&lt;span class="se"&gt;\n&lt;/span&gt;&lt;span class="s2"&gt;      ...base,&lt;/span&gt;&lt;span class="se"&gt;\n&lt;/span&gt;&lt;span class="s2"&gt;      status: 'ERROR',&lt;/span&gt;&lt;span class="se"&gt;\n&lt;/span&gt;&lt;span class="s2"&gt;      apiMessage:&lt;/span&gt;&lt;span class="se"&gt;\n&lt;/span&gt;&lt;span class="s2"&gt;        res?.Message ||&lt;/span&gt;&lt;span class="se"&gt;\n&lt;/span&gt;&lt;span class="s2"&gt;        res?.message ||&lt;/span&gt;&lt;span class="se"&gt;\n&lt;/span&gt;&lt;span class="s2"&gt;        `HTTP ${httpStatus}`,&lt;/span&gt;&lt;span class="se"&gt;\n&lt;/span&gt;&lt;span class="s2"&gt;      httpStatus,&lt;/span&gt;&lt;span class="se"&gt;\n&lt;/span&gt;&lt;span class="s2"&gt;      hasUnpaid: false,&lt;/span&gt;&lt;span class="se"&gt;\n&lt;/span&gt;&lt;span class="s2"&gt;      totalCount: 0,&lt;/span&gt;&lt;span class="se"&gt;\n&lt;/span&gt;&lt;span class="s2"&gt;      totalAmount: 0,&lt;/span&gt;&lt;span class="se"&gt;\n&lt;/span&gt;&lt;span class="s2"&gt;      details: [],&lt;/span&gt;&lt;span class="se"&gt;\n&lt;/span&gt;&lt;span class="s2"&gt;      isQueryFailed: true&lt;/span&gt;&lt;span class="se"&gt;\n&lt;/span&gt;&lt;span class="s2"&gt;    }&lt;/span&gt;&lt;span class="se"&gt;\n&lt;/span&gt;&lt;span class="s2"&gt;  };&lt;/span&gt;&lt;span class="se"&gt;\n&lt;/span&gt;&lt;span class="s2"&gt;}&lt;/span&gt;&lt;span class="se"&gt;\n\n&lt;/span&gt;&lt;span class="s2"&gt;const status = String(res?.Status ?? '').toUpperCase();&lt;/span&gt;&lt;span class="se"&gt;\n&lt;/span&gt;&lt;span class="s2"&gt;const apiMessage = String(res?.Message ?? '');&lt;/span&gt;&lt;span class="se"&gt;\n\n&lt;/span&gt;&lt;span class="s2"&gt;let result = res?.Result ?? null;&lt;/span&gt;&lt;span class="se"&gt;\n&lt;/span&gt;&lt;span class="s2"&gt;if (typeof result === 'string' &amp;amp;&amp;amp; result.trim()) {&lt;/span&gt;&lt;span class="se"&gt;\n&lt;/span&gt;&lt;span class="s2"&gt;  try {&lt;/span&gt;&lt;span class="se"&gt;\n&lt;/span&gt;&lt;span class="s2"&gt;    result = JSON.parse(result);&lt;/span&gt;&lt;span class="se"&gt;\n&lt;/span&gt;&lt;span class="s2"&gt;  } catch {&lt;/span&gt;&lt;span class="se"&gt;\n&lt;/span&gt;&lt;span class="s2"&gt;    return {&lt;/span&gt;&lt;span class="se"&gt;\n&lt;/span&gt;&lt;span class="s2"&gt;      json: {&lt;/span&gt;&lt;span class="se"&gt;\n&lt;/span&gt;&lt;span class="s2"&gt;        ...base,&lt;/span&gt;&lt;span class="se"&gt;\n&lt;/span&gt;&lt;span class="s2"&gt;        status: 'ERROR',&lt;/span&gt;&lt;span class="se"&gt;\n&lt;/span&gt;&lt;span class="s2"&gt;        apiMessage: 'Result 欄位不是合法 JSON',&lt;/span&gt;&lt;span class="se"&gt;\n&lt;/span&gt;&lt;span class="s2"&gt;        httpStatus: httpStatus || null,&lt;/span&gt;&lt;span class="se"&gt;\n&lt;/span&gt;&lt;span class="s2"&gt;        hasUnpaid: false,&lt;/span&gt;&lt;span class="se"&gt;\n&lt;/span&gt;&lt;span class="s2"&gt;        totalCount: 0,&lt;/span&gt;&lt;span class="se"&gt;\n&lt;/span&gt;&lt;span class="s2"&gt;        totalAmount: 0,&lt;/span&gt;&lt;span class="se"&gt;\n&lt;/span&gt;&lt;span class="s2"&gt;        details: [],&lt;/span&gt;&lt;span class="se"&gt;\n&lt;/span&gt;&lt;span class="s2"&gt;        isQueryFailed: true&lt;/span&gt;&lt;span class="se"&gt;\n&lt;/span&gt;&lt;span class="s2"&gt;      }&lt;/span&gt;&lt;span class="se"&gt;\n&lt;/span&gt;&lt;span class="s2"&gt;    };&lt;/span&gt;&lt;span class="se"&gt;\n&lt;/span&gt;&lt;span class="s2"&gt;  }&lt;/span&gt;&lt;span class="se"&gt;\n&lt;/span&gt;&lt;span class="s2"&gt;}&lt;/span&gt;&lt;span class="se"&gt;\n\n&lt;/span&gt;&lt;span class="s2"&gt;const bills = Array.isArray(result?.Bills) ? result.Bills : [];&lt;/span&gt;&lt;span class="se"&gt;\n&lt;/span&gt;&lt;span class="s2"&gt;const reminders = Array.isArray(result?.Reminders) ? result.Reminders : [];&lt;/span&gt;&lt;span class="se"&gt;\n&lt;/span&gt;&lt;span class="s2"&gt;const details = [];&lt;/span&gt;&lt;span class="se"&gt;\n\n&lt;/span&gt;&lt;span class="s2"&gt;for (const bill of bills) {&lt;/span&gt;&lt;span class="se"&gt;\n&lt;/span&gt;&lt;span class="s2"&gt;  details.push({&lt;/span&gt;&lt;span class="se"&gt;\n&lt;/span&gt;&lt;span class="s2"&gt;    kind: '停車單',&lt;/span&gt;&lt;span class="se"&gt;\n&lt;/span&gt;&lt;span class="s2"&gt;    amount: Number(bill?.PayAmount ?? bill?.Amount ?? 0),&lt;/span&gt;&lt;span class="se"&gt;\n&lt;/span&gt;&lt;span class="s2"&gt;    parkingDate: bill?.ParkingDate ?? '',&lt;/span&gt;&lt;span class="se"&gt;\n&lt;/span&gt;&lt;span class="s2"&gt;    dueDate: bill?.PayLimitDate ?? '',&lt;/span&gt;&lt;span class="se"&gt;\n&lt;/span&gt;&lt;span class="s2"&gt;    billNo: bill?.BillNo ?? ''&lt;/span&gt;&lt;span class="se"&gt;\n&lt;/span&gt;&lt;span class="s2"&gt;  });&lt;/span&gt;&lt;span class="se"&gt;\n&lt;/span&gt;&lt;span class="s2"&gt;}&lt;/span&gt;&lt;span class="se"&gt;\n\n&lt;/span&gt;&lt;span class="s2"&gt;for (const reminder of reminders) {&lt;/span&gt;&lt;span class="se"&gt;\n&lt;/span&gt;&lt;span class="s2"&gt;  details.push({&lt;/span&gt;&lt;span class="se"&gt;\n&lt;/span&gt;&lt;span class="s2"&gt;    kind: '催繳單',&lt;/span&gt;&lt;span class="se"&gt;\n&lt;/span&gt;&lt;span class="s2"&gt;    amount: Number(&lt;/span&gt;&lt;span class="se"&gt;\n&lt;/span&gt;&lt;span class="s2"&gt;      reminder?.PayAmount ??&lt;/span&gt;&lt;span class="se"&gt;\n&lt;/span&gt;&lt;span class="s2"&gt;      (Number(reminder?.Amount ?? 0) + Number(reminder?.ExtraCharge ?? 0))&lt;/span&gt;&lt;span class="se"&gt;\n&lt;/span&gt;&lt;span class="s2"&gt;    ),&lt;/span&gt;&lt;span class="se"&gt;\n&lt;/span&gt;&lt;span class="s2"&gt;    parkingDate: reminder?.ParkingDate ?? '',&lt;/span&gt;&lt;span class="se"&gt;\n&lt;/span&gt;&lt;span class="s2"&gt;    dueDate: reminder?.ReminderLimitDate ?? reminder?.PayLimitDate ?? '',&lt;/span&gt;&lt;span class="se"&gt;\n&lt;/span&gt;&lt;span class="s2"&gt;    billNo: reminder?.ReminderNo ?? reminder?.BillNo ?? ''&lt;/span&gt;&lt;span class="se"&gt;\n&lt;/span&gt;&lt;span class="s2"&gt;  });&lt;/span&gt;&lt;span class="se"&gt;\n&lt;/span&gt;&lt;span class="s2"&gt;}&lt;/span&gt;&lt;span class="se"&gt;\n\n&lt;/span&gt;&lt;span class="s2"&gt;const totalCount = Number(result?.TotalCount ?? details.length ?? 0);&lt;/span&gt;&lt;span class="se"&gt;\n&lt;/span&gt;&lt;span class="s2"&gt;const computedAmount = details.reduce((sum, d) =&amp;gt; sum + Number(d.amount || 0), 0);&lt;/span&gt;&lt;span class="se"&gt;\n&lt;/span&gt;&lt;span class="s2"&gt;const totalAmount = Number(result?.TotalAmount ?? computedAmount);&lt;/span&gt;&lt;span class="se"&gt;\n\n&lt;/span&gt;&lt;span class="s2"&gt;const success = status === 'SUCCESS';&lt;/span&gt;&lt;span class="se"&gt;\n\n&lt;/span&gt;&lt;span class="s2"&gt;return {&lt;/span&gt;&lt;span class="se"&gt;\n&lt;/span&gt;&lt;span class="s2"&gt;  json: {&lt;/span&gt;&lt;span class="se"&gt;\n&lt;/span&gt;&lt;span class="s2"&gt;    ...base,&lt;/span&gt;&lt;span class="se"&gt;\n&lt;/span&gt;&lt;span class="s2"&gt;    status,&lt;/span&gt;&lt;span class="se"&gt;\n&lt;/span&gt;&lt;span class="s2"&gt;    apiMessage,&lt;/span&gt;&lt;span class="se"&gt;\n&lt;/span&gt;&lt;span class="s2"&gt;    httpStatus: httpStatus || null,&lt;/span&gt;&lt;span class="se"&gt;\n&lt;/span&gt;&lt;span class="s2"&gt;    hasUnpaid: success &amp;amp;&amp;amp; !!result &amp;amp;&amp;amp; (totalCount &amp;gt; 0 || details.length &amp;gt; 0),&lt;/span&gt;&lt;span class="se"&gt;\n&lt;/span&gt;&lt;span class="s2"&gt;    totalCount,&lt;/span&gt;&lt;span class="se"&gt;\n&lt;/span&gt;&lt;span class="s2"&gt;    totalAmount,&lt;/span&gt;&lt;span class="se"&gt;\n&lt;/span&gt;&lt;span class="s2"&gt;    details,&lt;/span&gt;&lt;span class="se"&gt;\n&lt;/span&gt;&lt;span class="s2"&gt;    isQueryFailed: !success&lt;/span&gt;&lt;span class="se"&gt;\n&lt;/span&gt;&lt;span class="s2"&gt;  }&lt;/span&gt;&lt;span class="se"&gt;\n&lt;/span&gt;&lt;span class="s2"&gt;};"&lt;/span&gt;&lt;span class="w"&gt;
      &lt;/span&gt;&lt;span class="p"&gt;},&lt;/span&gt;&lt;span class="w"&gt;
      &lt;/span&gt;&lt;span class="nl"&gt;"id"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="s2"&gt;"0a7b65f9-6d37-49d4-9fd4-f4f749f73c46"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt;
      &lt;/span&gt;&lt;span class="nl"&gt;"name"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="s2"&gt;"整理單筆結果"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt;
      &lt;/span&gt;&lt;span class="nl"&gt;"type"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="s2"&gt;"n8n-nodes-base.code"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt;
      &lt;/span&gt;&lt;span class="nl"&gt;"typeVersion"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="mi"&gt;2&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt;
      &lt;/span&gt;&lt;span class="nl"&gt;"position"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="mi"&gt;320&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="mi"&gt;120&lt;/span&gt;&lt;span class="p"&gt;]&lt;/span&gt;&lt;span class="w"&gt;
    &lt;/span&gt;&lt;span class="p"&gt;},&lt;/span&gt;&lt;span class="w"&gt;
    &lt;/span&gt;&lt;span class="p"&gt;{&lt;/span&gt;&lt;span class="w"&gt;
      &lt;/span&gt;&lt;span class="nl"&gt;"parameters"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="p"&gt;{&lt;/span&gt;&lt;span class="w"&gt;
        &lt;/span&gt;&lt;span class="nl"&gt;"amount"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="mi"&gt;1&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt;
        &lt;/span&gt;&lt;span class="nl"&gt;"unit"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="s2"&gt;"seconds"&lt;/span&gt;&lt;span class="w"&gt;
      &lt;/span&gt;&lt;span class="p"&gt;},&lt;/span&gt;&lt;span class="w"&gt;
      &lt;/span&gt;&lt;span class="nl"&gt;"id"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="s2"&gt;"aa5bc5ca-c35c-4f8a-97b4-1b29fef023a8"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt;
      &lt;/span&gt;&lt;span class="nl"&gt;"name"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="s2"&gt;"等待 1 秒（API 節流）"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt;
      &lt;/span&gt;&lt;span class="nl"&gt;"type"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="s2"&gt;"n8n-nodes-base.wait"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt;
      &lt;/span&gt;&lt;span class="nl"&gt;"typeVersion"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="mf"&gt;1.1&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt;
      &lt;/span&gt;&lt;span class="nl"&gt;"position"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="mi"&gt;320&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="mi"&gt;200&lt;/span&gt;&lt;span class="p"&gt;],&lt;/span&gt;&lt;span class="w"&gt;
      &lt;/span&gt;&lt;span class="nl"&gt;"webhookId"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="s2"&gt;"61c9dc0a-3b6d-49d5-b022-e6a9054e3dd3"&lt;/span&gt;&lt;span class="w"&gt;
    &lt;/span&gt;&lt;span class="p"&gt;},&lt;/span&gt;&lt;span class="w"&gt;
    &lt;/span&gt;&lt;span class="p"&gt;{&lt;/span&gt;&lt;span class="w"&gt;
      &lt;/span&gt;&lt;span class="nl"&gt;"parameters"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="p"&gt;{&lt;/span&gt;&lt;span class="w"&gt;
        &lt;/span&gt;&lt;span class="nl"&gt;"mode"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="s2"&gt;"runOnceForAllItems"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt;
        &lt;/span&gt;&lt;span class="nl"&gt;"jsCode"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="s2"&gt;"const rows = $input.all().map(i =&amp;gt; i.json);&lt;/span&gt;&lt;span class="se"&gt;\n&lt;/span&gt;&lt;span class="s2"&gt;const first = rows[0] ?? {};&lt;/span&gt;&lt;span class="se"&gt;\n\n&lt;/span&gt;&lt;span class="s2"&gt;const unpaidRows = rows.filter(r =&amp;gt; r.hasUnpaid);&lt;/span&gt;&lt;span class="se"&gt;\n&lt;/span&gt;&lt;span class="s2"&gt;const failedRows = rows.filter(r =&amp;gt; r.isQueryFailed);&lt;/span&gt;&lt;span class="se"&gt;\n\n&lt;/span&gt;&lt;span class="s2"&gt;const totalCount = unpaidRows.reduce((s, r) =&amp;gt; s + Number(r.totalCount || 0), 0);&lt;/span&gt;&lt;span class="se"&gt;\n&lt;/span&gt;&lt;span class="s2"&gt;const totalAmount = unpaidRows.reduce((s, r) =&amp;gt; s + Number(r.totalAmount || 0), 0);&lt;/span&gt;&lt;span class="se"&gt;\n\n&lt;/span&gt;&lt;span class="s2"&gt;const lines = [];&lt;/span&gt;&lt;span class="se"&gt;\n\n&lt;/span&gt;&lt;span class="s2"&gt;if (unpaidRows.length) {&lt;/span&gt;&lt;span class="se"&gt;\n&lt;/span&gt;&lt;span class="s2"&gt;  lines.push('🚗 路邊停車費提醒', '');&lt;/span&gt;&lt;span class="se"&gt;\n\n&lt;/span&gt;&lt;span class="s2"&gt;  for (const row of unpaidRows) {&lt;/span&gt;&lt;span class="se"&gt;\n&lt;/span&gt;&lt;span class="s2"&gt;    const vehicleIcon = row.carType === 'M' ? '🛵' : '🚙';&lt;/span&gt;&lt;span class="se"&gt;\n&lt;/span&gt;&lt;span class="s2"&gt;    lines.push(`${vehicleIcon}【${row.label}｜${row.carId}】`);&lt;/span&gt;&lt;span class="se"&gt;\n&lt;/span&gt;&lt;span class="s2"&gt;    lines.push(`${row.cityName}：${row.totalCount} 筆，合計 $${row.totalAmount}`);&lt;/span&gt;&lt;span class="se"&gt;\n\n&lt;/span&gt;&lt;span class="s2"&gt;    for (const d of row.details.slice(0, 10)) {&lt;/span&gt;&lt;span class="se"&gt;\n&lt;/span&gt;&lt;span class="s2"&gt;      const parts = [&lt;/span&gt;&lt;span class="se"&gt;\n&lt;/span&gt;&lt;span class="s2"&gt;        d.kind,&lt;/span&gt;&lt;span class="se"&gt;\n&lt;/span&gt;&lt;span class="s2"&gt;        `$${d.amount}`,&lt;/span&gt;&lt;span class="se"&gt;\n&lt;/span&gt;&lt;span class="s2"&gt;        d.parkingDate ? `停車日 ${d.parkingDate}` : null,&lt;/span&gt;&lt;span class="se"&gt;\n&lt;/span&gt;&lt;span class="s2"&gt;        d.dueDate ? `期限 ${d.dueDate}` : null&lt;/span&gt;&lt;span class="se"&gt;\n&lt;/span&gt;&lt;span class="s2"&gt;      ].filter(Boolean);&lt;/span&gt;&lt;span class="se"&gt;\n&lt;/span&gt;&lt;span class="s2"&gt;      lines.push(`- ${parts.join('｜')}`);&lt;/span&gt;&lt;span class="se"&gt;\n&lt;/span&gt;&lt;span class="s2"&gt;    }&lt;/span&gt;&lt;span class="se"&gt;\n\n&lt;/span&gt;&lt;span class="s2"&gt;    if (row.details.length &amp;gt; 10) {&lt;/span&gt;&lt;span class="se"&gt;\n&lt;/span&gt;&lt;span class="s2"&gt;      lines.push(`- 另有 ${row.details.length - 10} 筆未列出`);&lt;/span&gt;&lt;span class="se"&gt;\n&lt;/span&gt;&lt;span class="s2"&gt;    }&lt;/span&gt;&lt;span class="se"&gt;\n&lt;/span&gt;&lt;span class="s2"&gt;    lines.push('');&lt;/span&gt;&lt;span class="se"&gt;\n&lt;/span&gt;&lt;span class="s2"&gt;  }&lt;/span&gt;&lt;span class="se"&gt;\n\n&lt;/span&gt;&lt;span class="s2"&gt;  lines.push(`總計：${totalCount} 筆，$${totalAmount}`);&lt;/span&gt;&lt;span class="se"&gt;\n&lt;/span&gt;&lt;span class="s2"&gt;} else {&lt;/span&gt;&lt;span class="se"&gt;\n&lt;/span&gt;&lt;span class="s2"&gt;  lines.push('✅ 目前沒有查到待繳路邊停車費');&lt;/span&gt;&lt;span class="se"&gt;\n&lt;/span&gt;&lt;span class="s2"&gt;}&lt;/span&gt;&lt;span class="se"&gt;\n\n&lt;/span&gt;&lt;span class="s2"&gt;if (failedRows.length) {&lt;/span&gt;&lt;span class="se"&gt;\n&lt;/span&gt;&lt;span class="s2"&gt;  lines.push('', `⚠️ 有 ${failedRows.length} 個查詢失敗，這些縣市「不能視為沒有欠費」：`);&lt;/span&gt;&lt;span class="se"&gt;\n&lt;/span&gt;&lt;span class="s2"&gt;  for (const row of failedRows.slice(0, 20)) {&lt;/span&gt;&lt;span class="se"&gt;\n&lt;/span&gt;&lt;span class="s2"&gt;    lines.push(`- ${row.label}｜${row.cityName}｜${row.apiMessage || row.status || '未知錯誤'}`);&lt;/span&gt;&lt;span class="se"&gt;\n&lt;/span&gt;&lt;span class="s2"&gt;  }&lt;/span&gt;&lt;span class="se"&gt;\n&lt;/span&gt;&lt;span class="s2"&gt;  if (failedRows.length &amp;gt; 20) {&lt;/span&gt;&lt;span class="se"&gt;\n&lt;/span&gt;&lt;span class="s2"&gt;    lines.push(`- 另有 ${failedRows.length - 20} 個失敗未列出`);&lt;/span&gt;&lt;span class="se"&gt;\n&lt;/span&gt;&lt;span class="s2"&gt;  }&lt;/span&gt;&lt;span class="se"&gt;\n&lt;/span&gt;&lt;span class="s2"&gt;}&lt;/span&gt;&lt;span class="se"&gt;\n\n&lt;/span&gt;&lt;span class="s2"&gt;const shouldNotify =&lt;/span&gt;&lt;span class="se"&gt;\n&lt;/span&gt;&lt;span class="s2"&gt;  unpaidRows.length &amp;gt; 0 ||&lt;/span&gt;&lt;span class="se"&gt;\n&lt;/span&gt;&lt;span class="s2"&gt;  failedRows.length &amp;gt; 0 ||&lt;/span&gt;&lt;span class="se"&gt;\n&lt;/span&gt;&lt;span class="s2"&gt;  Boolean(first.notifyWhenClear);&lt;/span&gt;&lt;span class="se"&gt;\n\n&lt;/span&gt;&lt;span class="s2"&gt;return [{&lt;/span&gt;&lt;span class="se"&gt;\n&lt;/span&gt;&lt;span class="s2"&gt;  json: {&lt;/span&gt;&lt;span class="se"&gt;\n&lt;/span&gt;&lt;span class="s2"&gt;    telegramChatId: first.telegramChatId ?? '',&lt;/span&gt;&lt;span class="se"&gt;\n&lt;/span&gt;&lt;span class="s2"&gt;    shouldNotify,&lt;/span&gt;&lt;span class="se"&gt;\n&lt;/span&gt;&lt;span class="s2"&gt;    hasUnpaid: unpaidRows.length &amp;gt; 0,&lt;/span&gt;&lt;span class="se"&gt;\n&lt;/span&gt;&lt;span class="s2"&gt;    totalCount,&lt;/span&gt;&lt;span class="se"&gt;\n&lt;/span&gt;&lt;span class="s2"&gt;    totalAmount,&lt;/span&gt;&lt;span class="se"&gt;\n&lt;/span&gt;&lt;span class="s2"&gt;    failedQueries: failedRows.length,&lt;/span&gt;&lt;span class="se"&gt;\n&lt;/span&gt;&lt;span class="s2"&gt;    message: lines.join('&lt;/span&gt;&lt;span class="se"&gt;\\&lt;/span&gt;&lt;span class="s2"&gt;n')&lt;/span&gt;&lt;span class="se"&gt;\n&lt;/span&gt;&lt;span class="s2"&gt;  }&lt;/span&gt;&lt;span class="se"&gt;\n&lt;/span&gt;&lt;span class="s2"&gt;}];"&lt;/span&gt;&lt;span class="w"&gt;
      &lt;/span&gt;&lt;span class="p"&gt;},&lt;/span&gt;&lt;span class="w"&gt;
      &lt;/span&gt;&lt;span class="nl"&gt;"id"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="s2"&gt;"4b6dabed-b0b9-4e24-bd69-249d9cac4bbf"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt;
      &lt;/span&gt;&lt;span class="nl"&gt;"name"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="s2"&gt;"彙總全部結果"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt;
      &lt;/span&gt;&lt;span class="nl"&gt;"type"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="s2"&gt;"n8n-nodes-base.code"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt;
      &lt;/span&gt;&lt;span class="nl"&gt;"typeVersion"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="mi"&gt;2&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt;
      &lt;/span&gt;&lt;span class="nl"&gt;"position"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="mi"&gt;-160&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="mi"&gt;-120&lt;/span&gt;&lt;span class="p"&gt;]&lt;/span&gt;&lt;span class="w"&gt;
    &lt;/span&gt;&lt;span class="p"&gt;},&lt;/span&gt;&lt;span class="w"&gt;
    &lt;/span&gt;&lt;span class="p"&gt;{&lt;/span&gt;&lt;span class="w"&gt;
      &lt;/span&gt;&lt;span class="nl"&gt;"parameters"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="p"&gt;{&lt;/span&gt;&lt;span class="w"&gt;
        &lt;/span&gt;&lt;span class="nl"&gt;"conditions"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="p"&gt;{&lt;/span&gt;&lt;span class="w"&gt;
          &lt;/span&gt;&lt;span class="nl"&gt;"options"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="p"&gt;{&lt;/span&gt;&lt;span class="w"&gt;
            &lt;/span&gt;&lt;span class="nl"&gt;"caseSensitive"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="kc"&gt;true&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt;
            &lt;/span&gt;&lt;span class="nl"&gt;"leftValue"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="s2"&gt;""&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt;
            &lt;/span&gt;&lt;span class="nl"&gt;"typeValidation"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="s2"&gt;"strict"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt;
            &lt;/span&gt;&lt;span class="nl"&gt;"version"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="mi"&gt;2&lt;/span&gt;&lt;span class="w"&gt;
          &lt;/span&gt;&lt;span class="p"&gt;},&lt;/span&gt;&lt;span class="w"&gt;
          &lt;/span&gt;&lt;span class="nl"&gt;"conditions"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="w"&gt;
            &lt;/span&gt;&lt;span class="p"&gt;{&lt;/span&gt;&lt;span class="w"&gt;
              &lt;/span&gt;&lt;span class="nl"&gt;"id"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="s2"&gt;"60315e8a-26c6-47fe-b311-0864f215d707"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt;
              &lt;/span&gt;&lt;span class="nl"&gt;"leftValue"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="s2"&gt;"={{ $json.shouldNotify }}"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt;
              &lt;/span&gt;&lt;span class="nl"&gt;"rightValue"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="kc"&gt;true&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt;
              &lt;/span&gt;&lt;span class="nl"&gt;"operator"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="p"&gt;{&lt;/span&gt;&lt;span class="w"&gt;
                &lt;/span&gt;&lt;span class="nl"&gt;"type"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="s2"&gt;"boolean"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt;
                &lt;/span&gt;&lt;span class="nl"&gt;"operation"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="s2"&gt;"true"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt;
                &lt;/span&gt;&lt;span class="nl"&gt;"singleValue"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="kc"&gt;true&lt;/span&gt;&lt;span class="w"&gt;
              &lt;/span&gt;&lt;span class="p"&gt;}&lt;/span&gt;&lt;span class="w"&gt;
            &lt;/span&gt;&lt;span class="p"&gt;}&lt;/span&gt;&lt;span class="w"&gt;
          &lt;/span&gt;&lt;span class="p"&gt;],&lt;/span&gt;&lt;span class="w"&gt;
          &lt;/span&gt;&lt;span class="nl"&gt;"combinator"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="s2"&gt;"and"&lt;/span&gt;&lt;span class="w"&gt;
        &lt;/span&gt;&lt;span class="p"&gt;},&lt;/span&gt;&lt;span class="w"&gt;
        &lt;/span&gt;&lt;span class="nl"&gt;"options"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="p"&gt;{}&lt;/span&gt;&lt;span class="w"&gt;
      &lt;/span&gt;&lt;span class="p"&gt;},&lt;/span&gt;&lt;span class="w"&gt;
      &lt;/span&gt;&lt;span class="nl"&gt;"id"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="s2"&gt;"c44271f5-b4ec-4a02-bd5a-37e9b53cc1ab"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt;
      &lt;/span&gt;&lt;span class="nl"&gt;"name"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="s2"&gt;"需要通知？"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt;
      &lt;/span&gt;&lt;span class="nl"&gt;"type"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="s2"&gt;"n8n-nodes-base.if"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt;
      &lt;/span&gt;&lt;span class="nl"&gt;"typeVersion"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="mf"&gt;2.2&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt;
      &lt;/span&gt;&lt;span class="nl"&gt;"position"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="mi"&gt;80&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="mi"&gt;-120&lt;/span&gt;&lt;span class="p"&gt;]&lt;/span&gt;&lt;span class="w"&gt;
    &lt;/span&gt;&lt;span class="p"&gt;},&lt;/span&gt;&lt;span class="w"&gt;
    &lt;/span&gt;&lt;span class="p"&gt;{&lt;/span&gt;&lt;span class="w"&gt;
      &lt;/span&gt;&lt;span class="nl"&gt;"parameters"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="p"&gt;{&lt;/span&gt;&lt;span class="w"&gt;
        &lt;/span&gt;&lt;span class="nl"&gt;"chatId"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="s2"&gt;"={{ $json.telegramChatId }}"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt;
        &lt;/span&gt;&lt;span class="nl"&gt;"text"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="s2"&gt;"={{ $json.message }}"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt;
        &lt;/span&gt;&lt;span class="nl"&gt;"additionalFields"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="p"&gt;{}&lt;/span&gt;&lt;span class="w"&gt;
      &lt;/span&gt;&lt;span class="p"&gt;},&lt;/span&gt;&lt;span class="w"&gt;
      &lt;/span&gt;&lt;span class="nl"&gt;"id"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="s2"&gt;"427558ca-fc5c-4d35-aa31-3e1d2286e556"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt;
      &lt;/span&gt;&lt;span class="nl"&gt;"name"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="s2"&gt;"Telegram 通知"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt;
      &lt;/span&gt;&lt;span class="nl"&gt;"type"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="s2"&gt;"n8n-nodes-base.telegram"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt;
      &lt;/span&gt;&lt;span class="nl"&gt;"typeVersion"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="mf"&gt;1.2&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt;
      &lt;/span&gt;&lt;span class="nl"&gt;"position"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="mi"&gt;320&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="mi"&gt;-160&lt;/span&gt;&lt;span class="p"&gt;]&lt;/span&gt;&lt;span class="w"&gt;
    &lt;/span&gt;&lt;span class="p"&gt;},&lt;/span&gt;&lt;span class="w"&gt;
    &lt;/span&gt;&lt;span class="p"&gt;{&lt;/span&gt;&lt;span class="w"&gt;
      &lt;/span&gt;&lt;span class="nl"&gt;"parameters"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="p"&gt;{&lt;/span&gt;&lt;span class="w"&gt;
        &lt;/span&gt;&lt;span class="nl"&gt;"mode"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="s2"&gt;"combine"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt;
        &lt;/span&gt;&lt;span class="nl"&gt;"combineBy"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="s2"&gt;"combineByPosition"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt;
        &lt;/span&gt;&lt;span class="nl"&gt;"options"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="p"&gt;{}&lt;/span&gt;&lt;span class="w"&gt;
      &lt;/span&gt;&lt;span class="p"&gt;},&lt;/span&gt;&lt;span class="w"&gt;
      &lt;/span&gt;&lt;span class="nl"&gt;"id"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="s2"&gt;"e11fc337-e4bd-406f-9f9b-9cebc88e6e96"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt;
      &lt;/span&gt;&lt;span class="nl"&gt;"name"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="s2"&gt;"合併查詢參數與 HTTP 回應"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt;
      &lt;/span&gt;&lt;span class="nl"&gt;"type"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="s2"&gt;"n8n-nodes-base.merge"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt;
      &lt;/span&gt;&lt;span class="nl"&gt;"typeVersion"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="mf"&gt;3.2&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt;
      &lt;/span&gt;&lt;span class="nl"&gt;"position"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="mi"&gt;80&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="mi"&gt;120&lt;/span&gt;&lt;span class="p"&gt;]&lt;/span&gt;&lt;span class="w"&gt;
    &lt;/span&gt;&lt;span class="p"&gt;}&lt;/span&gt;&lt;span class="w"&gt;
  &lt;/span&gt;&lt;span class="p"&gt;],&lt;/span&gt;&lt;span class="w"&gt;
  &lt;/span&gt;&lt;span class="nl"&gt;"connections"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="p"&gt;{&lt;/span&gt;&lt;span class="w"&gt;
    &lt;/span&gt;&lt;span class="nl"&gt;"手動測試"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="p"&gt;{&lt;/span&gt;&lt;span class="w"&gt;
      &lt;/span&gt;&lt;span class="nl"&gt;"main"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="w"&gt;
        &lt;/span&gt;&lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="w"&gt;
          &lt;/span&gt;&lt;span class="p"&gt;{&lt;/span&gt;&lt;span class="w"&gt;
            &lt;/span&gt;&lt;span class="nl"&gt;"node"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="s2"&gt;"設定（只改這裡）"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt;
            &lt;/span&gt;&lt;span class="nl"&gt;"type"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="s2"&gt;"main"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt;
            &lt;/span&gt;&lt;span class="nl"&gt;"index"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="mi"&gt;0&lt;/span&gt;&lt;span class="w"&gt;
          &lt;/span&gt;&lt;span class="p"&gt;}&lt;/span&gt;&lt;span class="w"&gt;
        &lt;/span&gt;&lt;span class="p"&gt;]&lt;/span&gt;&lt;span class="w"&gt;
      &lt;/span&gt;&lt;span class="p"&gt;]&lt;/span&gt;&lt;span class="w"&gt;
    &lt;/span&gt;&lt;span class="p"&gt;},&lt;/span&gt;&lt;span class="w"&gt;
    &lt;/span&gt;&lt;span class="nl"&gt;"每天 09:00"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="p"&gt;{&lt;/span&gt;&lt;span class="w"&gt;
      &lt;/span&gt;&lt;span class="nl"&gt;"main"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="w"&gt;
        &lt;/span&gt;&lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="w"&gt;
          &lt;/span&gt;&lt;span class="p"&gt;{&lt;/span&gt;&lt;span class="w"&gt;
            &lt;/span&gt;&lt;span class="nl"&gt;"node"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="s2"&gt;"設定（只改這裡）"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt;
            &lt;/span&gt;&lt;span class="nl"&gt;"type"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="s2"&gt;"main"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt;
            &lt;/span&gt;&lt;span class="nl"&gt;"index"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="mi"&gt;0&lt;/span&gt;&lt;span class="w"&gt;
          &lt;/span&gt;&lt;span class="p"&gt;}&lt;/span&gt;&lt;span class="w"&gt;
        &lt;/span&gt;&lt;span class="p"&gt;]&lt;/span&gt;&lt;span class="w"&gt;
      &lt;/span&gt;&lt;span class="p"&gt;]&lt;/span&gt;&lt;span class="w"&gt;
    &lt;/span&gt;&lt;span class="p"&gt;},&lt;/span&gt;&lt;span class="w"&gt;
    &lt;/span&gt;&lt;span class="nl"&gt;"設定（只改這裡）"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="p"&gt;{&lt;/span&gt;&lt;span class="w"&gt;
      &lt;/span&gt;&lt;span class="nl"&gt;"main"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="w"&gt;
        &lt;/span&gt;&lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="w"&gt;
          &lt;/span&gt;&lt;span class="p"&gt;{&lt;/span&gt;&lt;span class="w"&gt;
            &lt;/span&gt;&lt;span class="nl"&gt;"node"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="s2"&gt;"建立 車輛 × 縣市 查詢清單"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt;
            &lt;/span&gt;&lt;span class="nl"&gt;"type"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="s2"&gt;"main"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt;
            &lt;/span&gt;&lt;span class="nl"&gt;"index"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="mi"&gt;0&lt;/span&gt;&lt;span class="w"&gt;
          &lt;/span&gt;&lt;span class="p"&gt;}&lt;/span&gt;&lt;span class="w"&gt;
        &lt;/span&gt;&lt;span class="p"&gt;]&lt;/span&gt;&lt;span class="w"&gt;
      &lt;/span&gt;&lt;span class="p"&gt;]&lt;/span&gt;&lt;span class="w"&gt;
    &lt;/span&gt;&lt;span class="p"&gt;},&lt;/span&gt;&lt;span class="w"&gt;
    &lt;/span&gt;&lt;span class="nl"&gt;"建立 車輛 × 縣市 查詢清單"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="p"&gt;{&lt;/span&gt;&lt;span class="w"&gt;
      &lt;/span&gt;&lt;span class="nl"&gt;"main"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="w"&gt;
        &lt;/span&gt;&lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="w"&gt;
          &lt;/span&gt;&lt;span class="p"&gt;{&lt;/span&gt;&lt;span class="w"&gt;
            &lt;/span&gt;&lt;span class="nl"&gt;"node"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="s2"&gt;"Loop Over Items（每次 1 筆）"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt;
            &lt;/span&gt;&lt;span class="nl"&gt;"type"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="s2"&gt;"main"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt;
            &lt;/span&gt;&lt;span class="nl"&gt;"index"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="mi"&gt;0&lt;/span&gt;&lt;span class="w"&gt;
          &lt;/span&gt;&lt;span class="p"&gt;}&lt;/span&gt;&lt;span class="w"&gt;
        &lt;/span&gt;&lt;span class="p"&gt;]&lt;/span&gt;&lt;span class="w"&gt;
      &lt;/span&gt;&lt;span class="p"&gt;]&lt;/span&gt;&lt;span class="w"&gt;
    &lt;/span&gt;&lt;span class="p"&gt;},&lt;/span&gt;&lt;span class="w"&gt;
    &lt;/span&gt;&lt;span class="nl"&gt;"Loop Over Items（每次 1 筆）"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="p"&gt;{&lt;/span&gt;&lt;span class="w"&gt;
      &lt;/span&gt;&lt;span class="nl"&gt;"main"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="w"&gt;
        &lt;/span&gt;&lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="w"&gt;
          &lt;/span&gt;&lt;span class="p"&gt;{&lt;/span&gt;&lt;span class="w"&gt;
            &lt;/span&gt;&lt;span class="nl"&gt;"node"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="s2"&gt;"彙總全部結果"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt;
            &lt;/span&gt;&lt;span class="nl"&gt;"type"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="s2"&gt;"main"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt;
            &lt;/span&gt;&lt;span class="nl"&gt;"index"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="mi"&gt;0&lt;/span&gt;&lt;span class="w"&gt;
          &lt;/span&gt;&lt;span class="p"&gt;}&lt;/span&gt;&lt;span class="w"&gt;
        &lt;/span&gt;&lt;span class="p"&gt;],&lt;/span&gt;&lt;span class="w"&gt;
        &lt;/span&gt;&lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="w"&gt;
          &lt;/span&gt;&lt;span class="p"&gt;{&lt;/span&gt;&lt;span class="w"&gt;
            &lt;/span&gt;&lt;span class="nl"&gt;"node"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="s2"&gt;"查詢停車費 API"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt;
            &lt;/span&gt;&lt;span class="nl"&gt;"type"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="s2"&gt;"main"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt;
            &lt;/span&gt;&lt;span class="nl"&gt;"index"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="mi"&gt;0&lt;/span&gt;&lt;span class="w"&gt;
          &lt;/span&gt;&lt;span class="p"&gt;},&lt;/span&gt;&lt;span class="w"&gt;
          &lt;/span&gt;&lt;span class="p"&gt;{&lt;/span&gt;&lt;span class="w"&gt;
            &lt;/span&gt;&lt;span class="nl"&gt;"node"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="s2"&gt;"合併查詢參數與 HTTP 回應"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt;
            &lt;/span&gt;&lt;span class="nl"&gt;"type"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="s2"&gt;"main"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt;
            &lt;/span&gt;&lt;span class="nl"&gt;"index"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="mi"&gt;0&lt;/span&gt;&lt;span class="w"&gt;
          &lt;/span&gt;&lt;span class="p"&gt;}&lt;/span&gt;&lt;span class="w"&gt;
        &lt;/span&gt;&lt;span class="p"&gt;]&lt;/span&gt;&lt;span class="w"&gt;
      &lt;/span&gt;&lt;span class="p"&gt;]&lt;/span&gt;&lt;span class="w"&gt;
    &lt;/span&gt;&lt;span class="p"&gt;},&lt;/span&gt;&lt;span class="w"&gt;
    &lt;/span&gt;&lt;span class="nl"&gt;"查詢停車費 API"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="p"&gt;{&lt;/span&gt;&lt;span class="w"&gt;
      &lt;/span&gt;&lt;span class="nl"&gt;"main"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="w"&gt;
        &lt;/span&gt;&lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="w"&gt;
          &lt;/span&gt;&lt;span class="p"&gt;{&lt;/span&gt;&lt;span class="w"&gt;
            &lt;/span&gt;&lt;span class="nl"&gt;"node"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="s2"&gt;"合併查詢參數與 HTTP 回應"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt;
            &lt;/span&gt;&lt;span class="nl"&gt;"type"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="s2"&gt;"main"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt;
            &lt;/span&gt;&lt;span class="nl"&gt;"index"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="mi"&gt;1&lt;/span&gt;&lt;span class="w"&gt;
          &lt;/span&gt;&lt;span class="p"&gt;}&lt;/span&gt;&lt;span class="w"&gt;
        &lt;/span&gt;&lt;span class="p"&gt;]&lt;/span&gt;&lt;span class="w"&gt;
      &lt;/span&gt;&lt;span class="p"&gt;]&lt;/span&gt;&lt;span class="w"&gt;
    &lt;/span&gt;&lt;span class="p"&gt;},&lt;/span&gt;&lt;span class="w"&gt;
    &lt;/span&gt;&lt;span class="nl"&gt;"整理單筆結果"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="p"&gt;{&lt;/span&gt;&lt;span class="w"&gt;
      &lt;/span&gt;&lt;span class="nl"&gt;"main"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="w"&gt;
        &lt;/span&gt;&lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="w"&gt;
          &lt;/span&gt;&lt;span class="p"&gt;{&lt;/span&gt;&lt;span class="w"&gt;
            &lt;/span&gt;&lt;span class="nl"&gt;"node"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="s2"&gt;"等待 1 秒（API 節流）"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt;
            &lt;/span&gt;&lt;span class="nl"&gt;"type"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="s2"&gt;"main"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt;
            &lt;/span&gt;&lt;span class="nl"&gt;"index"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="mi"&gt;0&lt;/span&gt;&lt;span class="w"&gt;
          &lt;/span&gt;&lt;span class="p"&gt;}&lt;/span&gt;&lt;span class="w"&gt;
        &lt;/span&gt;&lt;span class="p"&gt;]&lt;/span&gt;&lt;span class="w"&gt;
      &lt;/span&gt;&lt;span class="p"&gt;]&lt;/span&gt;&lt;span class="w"&gt;
    &lt;/span&gt;&lt;span class="p"&gt;},&lt;/span&gt;&lt;span class="w"&gt;
    &lt;/span&gt;&lt;span class="nl"&gt;"等待 1 秒（API 節流）"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="p"&gt;{&lt;/span&gt;&lt;span class="w"&gt;
      &lt;/span&gt;&lt;span class="nl"&gt;"main"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="w"&gt;
        &lt;/span&gt;&lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="w"&gt;
          &lt;/span&gt;&lt;span class="p"&gt;{&lt;/span&gt;&lt;span class="w"&gt;
            &lt;/span&gt;&lt;span class="nl"&gt;"node"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="s2"&gt;"Loop Over Items（每次 1 筆）"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt;
            &lt;/span&gt;&lt;span class="nl"&gt;"type"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="s2"&gt;"main"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt;
            &lt;/span&gt;&lt;span class="nl"&gt;"index"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="mi"&gt;0&lt;/span&gt;&lt;span class="w"&gt;
          &lt;/span&gt;&lt;span class="p"&gt;}&lt;/span&gt;&lt;span class="w"&gt;
        &lt;/span&gt;&lt;span class="p"&gt;]&lt;/span&gt;&lt;span class="w"&gt;
      &lt;/span&gt;&lt;span class="p"&gt;]&lt;/span&gt;&lt;span class="w"&gt;
    &lt;/span&gt;&lt;span class="p"&gt;},&lt;/span&gt;&lt;span class="w"&gt;
    &lt;/span&gt;&lt;span class="nl"&gt;"彙總全部結果"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="p"&gt;{&lt;/span&gt;&lt;span class="w"&gt;
      &lt;/span&gt;&lt;span class="nl"&gt;"main"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="w"&gt;
        &lt;/span&gt;&lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="w"&gt;
          &lt;/span&gt;&lt;span class="p"&gt;{&lt;/span&gt;&lt;span class="w"&gt;
            &lt;/span&gt;&lt;span class="nl"&gt;"node"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="s2"&gt;"需要通知？"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt;
            &lt;/span&gt;&lt;span class="nl"&gt;"type"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="s2"&gt;"main"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt;
            &lt;/span&gt;&lt;span class="nl"&gt;"index"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="mi"&gt;0&lt;/span&gt;&lt;span class="w"&gt;
          &lt;/span&gt;&lt;span class="p"&gt;}&lt;/span&gt;&lt;span class="w"&gt;
        &lt;/span&gt;&lt;span class="p"&gt;]&lt;/span&gt;&lt;span class="w"&gt;
      &lt;/span&gt;&lt;span class="p"&gt;]&lt;/span&gt;&lt;span class="w"&gt;
    &lt;/span&gt;&lt;span class="p"&gt;},&lt;/span&gt;&lt;span class="w"&gt;
    &lt;/span&gt;&lt;span class="nl"&gt;"需要通知？"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="p"&gt;{&lt;/span&gt;&lt;span class="w"&gt;
      &lt;/span&gt;&lt;span class="nl"&gt;"main"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="w"&gt;
        &lt;/span&gt;&lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="w"&gt;
          &lt;/span&gt;&lt;span class="p"&gt;{&lt;/span&gt;&lt;span class="w"&gt;
            &lt;/span&gt;&lt;span class="nl"&gt;"node"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="s2"&gt;"Telegram 通知"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt;
            &lt;/span&gt;&lt;span class="nl"&gt;"type"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="s2"&gt;"main"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt;
            &lt;/span&gt;&lt;span class="nl"&gt;"index"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="mi"&gt;0&lt;/span&gt;&lt;span class="w"&gt;
          &lt;/span&gt;&lt;span class="p"&gt;}&lt;/span&gt;&lt;span class="w"&gt;
        &lt;/span&gt;&lt;span class="p"&gt;],&lt;/span&gt;&lt;span class="w"&gt;
        &lt;/span&gt;&lt;span class="p"&gt;[]&lt;/span&gt;&lt;span class="w"&gt;
      &lt;/span&gt;&lt;span class="p"&gt;]&lt;/span&gt;&lt;span class="w"&gt;
    &lt;/span&gt;&lt;span class="p"&gt;},&lt;/span&gt;&lt;span class="w"&gt;
    &lt;/span&gt;&lt;span class="nl"&gt;"合併查詢參數與 HTTP 回應"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="p"&gt;{&lt;/span&gt;&lt;span class="w"&gt;
      &lt;/span&gt;&lt;span class="nl"&gt;"main"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="w"&gt;
        &lt;/span&gt;&lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="w"&gt;
          &lt;/span&gt;&lt;span class="p"&gt;{&lt;/span&gt;&lt;span class="w"&gt;
            &lt;/span&gt;&lt;span class="nl"&gt;"node"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="s2"&gt;"整理單筆結果"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt;
            &lt;/span&gt;&lt;span class="nl"&gt;"type"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="s2"&gt;"main"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt;
            &lt;/span&gt;&lt;span class="nl"&gt;"index"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="mi"&gt;0&lt;/span&gt;&lt;span class="w"&gt;
          &lt;/span&gt;&lt;span class="p"&gt;}&lt;/span&gt;&lt;span class="w"&gt;
        &lt;/span&gt;&lt;span class="p"&gt;]&lt;/span&gt;&lt;span class="w"&gt;
      &lt;/span&gt;&lt;span class="p"&gt;]&lt;/span&gt;&lt;span class="w"&gt;
    &lt;/span&gt;&lt;span class="p"&gt;}&lt;/span&gt;&lt;span class="w"&gt;
  &lt;/span&gt;&lt;span class="p"&gt;},&lt;/span&gt;&lt;span class="w"&gt;
  &lt;/span&gt;&lt;span class="nl"&gt;"pinData"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="p"&gt;{},&lt;/span&gt;&lt;span class="w"&gt;
  &lt;/span&gt;&lt;span class="nl"&gt;"active"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="kc"&gt;false&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt;
  &lt;/span&gt;&lt;span class="nl"&gt;"settings"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="p"&gt;{&lt;/span&gt;&lt;span class="w"&gt;
    &lt;/span&gt;&lt;span class="nl"&gt;"executionOrder"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="s2"&gt;"v1"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt;
    &lt;/span&gt;&lt;span class="nl"&gt;"timezone"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="s2"&gt;"Asia/Taipei"&lt;/span&gt;&lt;span class="w"&gt;
  &lt;/span&gt;&lt;span class="p"&gt;},&lt;/span&gt;&lt;span class="w"&gt;
  &lt;/span&gt;&lt;span class="nl"&gt;"versionId"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="s2"&gt;"1aa3b0b1-0acf-40f7-b71c-03a93d7beb1a"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt;
  &lt;/span&gt;&lt;span class="nl"&gt;"meta"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="p"&gt;{&lt;/span&gt;&lt;span class="w"&gt;
    &lt;/span&gt;&lt;span class="nl"&gt;"templateCredsSetupCompleted"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="kc"&gt;false&lt;/span&gt;&lt;span class="w"&gt;
  &lt;/span&gt;&lt;span class="p"&gt;},&lt;/span&gt;&lt;span class="w"&gt;
  &lt;/span&gt;&lt;span class="nl"&gt;"tags"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="p"&gt;[]&lt;/span&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;span class="p"&gt;}&lt;/span&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;如果是想用匯入的方式，就把上面的程式碼複製後存成 JSON，進入 n8n：&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;Workflows
→ Import from File
→ 選擇剛才下載的 JSON
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;不管是用複製貼上的，還是匯入，之後只需要修改 &lt;strong&gt;「設定（只改這裡）」&lt;/strong&gt; 這個 Node 就可以，說明如下。&lt;/p&gt;

&lt;h3&gt;
  
  
  車輛設定
&lt;/h3&gt;

&lt;p&gt;找到：&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;vehiclesJson
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;例如：&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight json"&gt;&lt;code&gt;&lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="w"&gt;
  &lt;/span&gt;&lt;span class="p"&gt;{&lt;/span&gt;&lt;span class="w"&gt;
    &lt;/span&gt;&lt;span class="nl"&gt;"label"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="s2"&gt;"我的汽車"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt;
    &lt;/span&gt;&lt;span class="nl"&gt;"carId"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="s2"&gt;"ABC-1234"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt;
    &lt;/span&gt;&lt;span class="nl"&gt;"carType"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="s2"&gt;"C"&lt;/span&gt;&lt;span class="w"&gt;
  &lt;/span&gt;&lt;span class="p"&gt;},&lt;/span&gt;&lt;span class="w"&gt;
  &lt;/span&gt;&lt;span class="p"&gt;{&lt;/span&gt;&lt;span class="w"&gt;
    &lt;/span&gt;&lt;span class="nl"&gt;"label"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="s2"&gt;"我的機車"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt;
    &lt;/span&gt;&lt;span class="nl"&gt;"carId"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="s2"&gt;"XYZ-5678"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt;
    &lt;/span&gt;&lt;span class="nl"&gt;"carType"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="s2"&gt;"M"&lt;/span&gt;&lt;span class="w"&gt;
  &lt;/span&gt;&lt;span class="p"&gt;}&lt;/span&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;span class="p"&gt;]&lt;/span&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;&lt;code&gt;carType&lt;/code&gt; 的設定：&lt;/p&gt;

&lt;div class="table-wrapper-paragraph"&gt;&lt;table&gt;
&lt;thead&gt;
&lt;tr&gt;
&lt;th&gt;值&lt;/th&gt;
&lt;th&gt;車種&lt;/th&gt;
&lt;/tr&gt;
&lt;/thead&gt;
&lt;tbody&gt;
&lt;tr&gt;
&lt;td&gt;&lt;code&gt;C&lt;/code&gt;&lt;/td&gt;
&lt;td&gt;汽車&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;&lt;code&gt;M&lt;/code&gt;&lt;/td&gt;
&lt;td&gt;機車&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;&lt;code&gt;O&lt;/code&gt;&lt;/td&gt;
&lt;td&gt;其他&lt;/td&gt;
&lt;/tr&gt;
&lt;/tbody&gt;
&lt;/table&gt;&lt;/div&gt;

&lt;p&gt;如果有多台車，繼續往下增加即可。&lt;/p&gt;

&lt;p&gt;例如：&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight json"&gt;&lt;code&gt;&lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="w"&gt;
  &lt;/span&gt;&lt;span class="p"&gt;{&lt;/span&gt;&lt;span class="w"&gt;
    &lt;/span&gt;&lt;span class="nl"&gt;"label"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="s2"&gt;"汽車"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt;
    &lt;/span&gt;&lt;span class="nl"&gt;"carId"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="s2"&gt;"ABC-1234"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt;
    &lt;/span&gt;&lt;span class="nl"&gt;"carType"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="s2"&gt;"C"&lt;/span&gt;&lt;span class="w"&gt;
  &lt;/span&gt;&lt;span class="p"&gt;},&lt;/span&gt;&lt;span class="w"&gt;
  &lt;/span&gt;&lt;span class="p"&gt;{&lt;/span&gt;&lt;span class="w"&gt;
    &lt;/span&gt;&lt;span class="nl"&gt;"label"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="s2"&gt;"我的機車"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt;
    &lt;/span&gt;&lt;span class="nl"&gt;"carId"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="s2"&gt;"XYZ-5678"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt;
    &lt;/span&gt;&lt;span class="nl"&gt;"carType"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="s2"&gt;"M"&lt;/span&gt;&lt;span class="w"&gt;
  &lt;/span&gt;&lt;span class="p"&gt;},&lt;/span&gt;&lt;span class="w"&gt;
  &lt;/span&gt;&lt;span class="p"&gt;{&lt;/span&gt;&lt;span class="w"&gt;
    &lt;/span&gt;&lt;span class="nl"&gt;"label"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="s2"&gt;"家人的機車"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt;
    &lt;/span&gt;&lt;span class="nl"&gt;"carId"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="s2"&gt;"AAA-8888"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt;
    &lt;/span&gt;&lt;span class="nl"&gt;"carType"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="s2"&gt;"M"&lt;/span&gt;&lt;span class="w"&gt;
  &lt;/span&gt;&lt;span class="p"&gt;}&lt;/span&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;span class="p"&gt;]&lt;/span&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;h3&gt;
  
  
  Telegram 設定
&lt;/h3&gt;

&lt;p&gt;接著修改：&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;telegramChatId
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;填入自己的 Telegram Chat ID。&lt;/p&gt;

&lt;p&gt;如果不知道自己的 Telegram Chat ID 是多少，只需要加入這個帳號，進行對話後就會看得到了：&lt;a href="https://t.me/userinfobot" rel="noopener noreferrer"&gt;User Info&lt;/a&gt;。&lt;/p&gt;

&lt;p&gt;最後進入：&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;Telegram 通知
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;設定自己的 Telegram Bot Credential。&lt;/p&gt;

&lt;p&gt;如果不希望「沒有欠費」時也收到通知，可以保持：&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;notifyWhenClear = false
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;這樣平常沒有欠費就完全不打擾。&lt;/p&gt;

&lt;p&gt;如果沒有用 Telegram，或是想接收別的通知，那只需要把上面 Workflow 的 JSON，貼給 ChatGPT，請它改成你習慣的通知方式即可。&lt;/p&gt;




&lt;h2&gt;
  
  
  n8n Workflow 說明
&lt;/h2&gt;

&lt;p&gt;這段是詳細說明上面那段 JSON 的各個部份，是在做什麼的。&lt;/p&gt;

&lt;p&gt;整個 Workflow 最主要可以分成幾個部分。&lt;/p&gt;

&lt;h3&gt;
  
  
  每天自動執行
&lt;/h3&gt;

&lt;p&gt;Workflow 預設：&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;每天 09:00
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;自動執行一次。&lt;/p&gt;

&lt;p&gt;另外也保留：&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;手動測試
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;剛設定完成時，可以先按手動執行確認是否正常。&lt;/p&gt;




&lt;h3&gt;
  
  
  設定車輛與縣市
&lt;/h3&gt;

&lt;p&gt;「設定（只改這裡）」Node 集中放：&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;telegramChatId
notifyWhenClear
vehiclesJson
citiesJson
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;所以日後新增汽車、機車，基本上只需要改這一個地方。&lt;/p&gt;

&lt;p&gt;&lt;code&gt;citiesJson&lt;/code&gt; 則放各縣市停車費查詢端點。&lt;/p&gt;

&lt;p&gt;目前這份 Workflow 已經預先放入 21 個縣市的設定；如果某個 API 日後有更換網址，也只需要修改這裡，不必重新改整個流程。&lt;/p&gt;

&lt;h3&gt;
  
  
  建立查詢清單
&lt;/h3&gt;

&lt;p&gt;接下來的 Code Node 會把：&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;車輛
×
縣市
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;自動組合成每一筆查詢。&lt;/p&gt;

&lt;p&gt;例如：&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;我的汽車 → 臺北市
我的汽車 → 新北市
我的汽車 → 桃園市

我的機車 → 臺北市
我的機車 → 新北市
我的機車 → 桃園市
...
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;所以新增車輛時，不需要增加新的 HTTP Request Node。&lt;/p&gt;

&lt;h3&gt;
  
  
  逐筆查詢停車費
&lt;/h3&gt;

&lt;p&gt;接著使用：&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;Loop Over Items
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;一次只處理一筆查詢。&lt;/p&gt;

&lt;p&gt;流程是：&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;查詢 API
↓
整理結果
↓
等待 1 秒
↓
下一筆
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;August 刻意加上 &lt;strong&gt;等待 1 秒&lt;/strong&gt;，避免短時間內大量呼叫各縣市 API。&lt;/p&gt;

&lt;h3&gt;
  
  
  整理待繳停車費
&lt;/h3&gt;

&lt;p&gt;每一個縣市回傳結果之後，Workflow 會統一整理成：&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;縣市
車牌
車種
待繳筆數
待繳金額
停車日期
繳費期限
停車單 / 催繳單
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;所以即使不同縣市的資料來源不同，後面的通知流程仍然可以使用相同格式。&lt;/p&gt;

&lt;h3&gt;
  
  
  最後統一通知
&lt;/h3&gt;

&lt;p&gt;全部縣市查詢完成後，再一次彙整。&lt;/p&gt;

&lt;p&gt;例如：&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;🚗 路邊停車費提醒

🚙【我的汽車｜ABC-1234】
臺北市：2 筆，合計 $80
- 停車單｜$40｜停車日 2026-09-10｜期限 2026-09-25
- 停車單｜$40｜停車日 2026-09-11｜期限 2026-09-26

🛵【我的機車｜XYZ-5678】
新北市：1 筆，合計 $20
- 停車單｜$20｜停車日 2026-09-12｜期限 2026-09-27

總計：3 筆，$100
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;這樣不用收到幾十則 Telegram 訊息，而是每天最多收到一份整理好的結果。&lt;/p&gt;

&lt;p&gt;另外，如果某個 API 查詢失敗，也會另外標示：&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;⚠️ 有 2 個查詢失敗，
這些縣市不能視為沒有欠費：

- 我的汽車｜某縣市｜查詢失敗
- 我的機車｜某縣市｜Timeout
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;這點很重要，因為「API 查不到」跟「沒有停車費」是兩件完全不同的事情。&lt;/p&gt;

&lt;p&gt;最後把 Workflow 啟用後，基本上就不用再管它了。&lt;/p&gt;

&lt;p&gt;之後只要有未繳的路邊停車費，就會自動收到 Telegram 通知。&lt;/p&gt;

</description>
      <category>n8n</category>
      <category>telegram</category>
      <category>api</category>
      <category>auto</category>
    </item>
    <item>
      <title>用 Chrome 擴充 + 自架 n8n，讓 AI 幫你整理 Google Chat 對話與自動產生 Jira 任務</title>
      <dc:creator>Let's Write</dc:creator>
      <pubDate>Fri, 11 Sep 2026 10:09:28 +0000</pubDate>
      <link>https://dev.to/letswrite/yong-chrome-kuo-chong-zi-jia-n8nrang-ai-bang-ni-zheng-li-google-chat-dui-hua-yu-zi-dong-chan-sheng-jira-ren-wu-1c4m</link>
      <guid>https://dev.to/letswrite/yong-chrome-kuo-chong-zi-jia-n8nrang-ai-bang-ni-zheng-li-google-chat-dui-hua-yu-zi-dong-chan-sheng-jira-ren-wu-1c4m</guid>
      <description>&lt;h2&gt;
  
  
  本篇要解決的問題
&lt;/h2&gt;

&lt;p&gt;如果想把工作、私人生活切開來，在公司的通訊軟體就不能還是在用 LINE，像之前有寫過 &lt;a href="https://www.letswrite.tw/mattermost/" rel="noopener noreferrer"&gt;Mattermost&lt;/a&gt; 這個通訊軟體。&lt;/p&gt;

&lt;p&gt;最近處理工作的事情，團隊選擇的是 Google Chat，用了一陣子後才發現，因為是免費版，沒有 Google Chat App、Chat API，也不能裝 Chat Bot，等於想在 Chat 使用 AI 是被封印的事。&lt;/p&gt;

&lt;p&gt;可是總會有要讓 AI 幫忙整理討論或是撈舊訊息的時候，跟 ChatGPT 討論後，發現只剩下直接從瀏覽器下手這方法。&lt;/p&gt;

&lt;p&gt;於是就有了這篇的 Let's Chat AI 擴充功能，直接讀畫面上的聊天內容，再送去 AI，最後把 AI 處理後的結果顯示出來。&lt;/p&gt;

&lt;p&gt;本篇使用的擴充功能：&lt;a href="https://chromewebstore.google.com/detail/lets-chat-ai/cjhllfpcohiiclodggnfemcchidlgaaj" rel="noopener noreferrer"&gt;Let's Chat AI&lt;/a&gt;&lt;/p&gt;




&lt;h2&gt;
  
  
  Let's Chat AI 是什麼？
&lt;/h2&gt;

&lt;p&gt;&lt;strong&gt;Let's Chat AI&lt;/strong&gt; 是一個 Chrome 擴充。&lt;/p&gt;

&lt;p&gt;我們在 Google Chat 裡開著某個聊天室，點一下按鈕，它就把「螢幕上已經載入的訊息」送去整理，幾秒後回給你：&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;討論摘要，如重點、決策、工作項目、待確認項目。&lt;/li&gt;
&lt;li&gt;工作項目清單，如誰負責什麼。&lt;/li&gt;
&lt;li&gt;Jira 議題草稿，可一鍵複製成純文字貼進 Jira。&lt;/li&gt;
&lt;li&gt;自己打一句指示，如「把上週跟晶片掃描器有關的討論整理出來」「列出 Amy 提到的待辦」。&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;簡單來說，就是給用免費版 Google Chat，沒有 Chat API 可用的小團隊。&lt;/p&gt;

&lt;h3&gt;
  
  
  怎麼運作
&lt;/h3&gt;



&lt;pre data-lang="mermaid"&gt;&lt;code&gt;flowchart LR
  A["Google Chat&amp;lt;br/&amp;gt;你點一下「AI」"] --&amp;gt;|送出已載入的訊息| B["你自己的 n8n&amp;lt;br/&amp;gt;＋ 你的 AI 金鑰"]
  B --&amp;gt;|帶金鑰呼叫| C["AI&amp;lt;br/&amp;gt;Gemini / OpenAI"]
  C --&amp;gt;|回結構化結果| B
  B --&amp;gt;|整理好的內容| D["擴充面板&amp;lt;br/&amp;gt;看結果 / 複製"]&lt;/code&gt;&lt;/pre&gt;



&lt;p&gt;中間站是「我們自己的 n8n」，n8n 是一個開源的自動化工具，提供自架版本。&lt;/p&gt;

&lt;p&gt;AI 的金鑰只放在 n8n 裡，擴充本身不儲存任何金鑰。&lt;/p&gt;

&lt;p&gt;因此換 AI 供應商只要改 n8n。&lt;/p&gt;

&lt;h3&gt;
  
  
  關於隱私
&lt;/h3&gt;

&lt;p&gt;只有在主動按功能鍵、看到「即將送出 N 則訊息」確認畫面、按下送出之後，訊息才會離開瀏覽器。&lt;/p&gt;

&lt;p&gt;不會背景監聽、不會自動上傳、不會保存聊天紀錄。解析結果只存在記憶體，關掉面板或切換聊天室就丟掉。&lt;/p&gt;

&lt;p&gt;擴充的本機設定只有三樣：webhook 網址、擷取則數上限、debug 開關。&lt;/p&gt;

&lt;p&gt;只在 &lt;code&gt;chat.google.com&lt;/code&gt; 上運作，權限只要 &lt;code&gt;storage&lt;/code&gt;。&lt;/p&gt;

&lt;p&gt;連 n8n 的網域權限是在設定時才執行請求的。&lt;/p&gt;




&lt;h3&gt;
  
  
  能做什麼
&lt;/h3&gt;

&lt;div class="table-wrapper-paragraph"&gt;&lt;table&gt;
&lt;thead&gt;
&lt;tr&gt;
&lt;th&gt;功能&lt;/th&gt;
&lt;th&gt;說明&lt;/th&gt;
&lt;/tr&gt;
&lt;/thead&gt;
&lt;tbody&gt;
&lt;tr&gt;
&lt;td&gt;整理討論&lt;/td&gt;
&lt;td&gt;摘要、決策、工作項目、待確認&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;整理工作項目&lt;/td&gt;
&lt;td&gt;專注抽出「誰要做什麼」&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;產生 Jira Draft&lt;/td&gt;
&lt;td&gt;Title / Description / Acceptance Criteria / Technical Notes / Pending Questions，一鍵複製純文字&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;自由指示&lt;/td&gt;
&lt;td&gt;面板上直接打字，讓 AI 依指示撈 / 比對 / 整理已載入的訊息&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;自動往回載入&lt;/td&gt;
&lt;td&gt;按下功能鍵時，自動把訊息串往上捲、載入較早的訊息（則數上限預設 50，面板或選項都能改，10–500）&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;可拖拉的按鈕&lt;/td&gt;
&lt;td&gt;右下角的 AI 按鈕可以拖到順手的位置，位置會記住&lt;/td&gt;
&lt;/tr&gt;
&lt;/tbody&gt;
&lt;/table&gt;&lt;/div&gt;




&lt;h2&gt;
  
  
  怎麼用
&lt;/h2&gt;

&lt;h3&gt;
  
  
  一、安裝擴充
&lt;/h3&gt;

&lt;p&gt;在 Google 擴充功能商店裡直接進行安裝：&lt;/p&gt;

&lt;p&gt;&lt;a href="https://chromewebstore.google.com/detail/lets-chat-ai/cjhllfpcohiiclodggnfemcchidlgaaj" rel="noopener noreferrer"&gt;Let's Chat AI&lt;/a&gt;&lt;/p&gt;

&lt;h3&gt;
  
  
  二、接上你自己的 n8n（五步）
&lt;/h3&gt;

&lt;p&gt;GitHub 資料夾裡有兩份可直接匯入的設定檔，自行選要用 Gemini 還是 OpenAI 的 API：&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;
&lt;a href="https://github.com/letswritetw/extension-lets-chat-ai/blob/master/n8n/google-chat-ai.gemini.workflow.json" rel="noopener noreferrer"&gt;google-chat-ai.gemini.workflow.json&lt;/a&gt;（Google Gemini）&lt;/li&gt;
&lt;li&gt;
&lt;a href="https://github.com/letswritetw/extension-lets-chat-ai/blob/master/n8n/google-chat-ai.openai.workflow.json" rel="noopener noreferrer"&gt;google-chat-ai.openai.workflow.json&lt;/a&gt;（OpenAI）&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;Gemini API 有免費額度可以使用，建議先用 Gemini 來測試這擴充功能有沒有滿足你的需求。&lt;/p&gt;

&lt;h4&gt;
  
  
  1. 拿一把自己的 AI 金鑰
&lt;/h4&gt;

&lt;ul&gt;
&lt;li&gt;Gemini：到 &lt;a href="https://aistudio.google.com/apikey" rel="noopener noreferrer"&gt;Google AI Studio&lt;/a&gt; 按 Create API key。&lt;/li&gt;
&lt;li&gt;OpenAI：到 &lt;a href="https://platform.openai.com/api-keys" rel="noopener noreferrer"&gt;platform.openai.com&lt;/a&gt; 建立 secret key（&lt;code&gt;sk-…&lt;/code&gt;）。&lt;/li&gt;
&lt;/ul&gt;

&lt;h4&gt;
  
  
  2. 把設定檔匯入 n8n
&lt;/h4&gt;

&lt;p&gt;n8n 左上角 &lt;strong&gt;＋ → Import from File…&lt;/strong&gt;，選對應的 &lt;code&gt;*.workflow.json&lt;/code&gt;。&lt;br&gt;
匯入後畫面上有一張黃色便利貼，寫著這份的重點，忘記可以回去看。&lt;/p&gt;

&lt;h4&gt;
  
  
  3. 把金鑰貼進去
&lt;/h4&gt;

&lt;p&gt;打開 &lt;strong&gt;Call Gemini&lt;/strong&gt;（或 &lt;strong&gt;Call OpenAI&lt;/strong&gt;）節點 → Credential → &lt;strong&gt;Create New&lt;/strong&gt;，選 Header Auth：&lt;/p&gt;

&lt;div class="table-wrapper-paragraph"&gt;&lt;table&gt;
&lt;thead&gt;
&lt;tr&gt;
&lt;th&gt;&lt;/th&gt;
&lt;th&gt;Gemini&lt;/th&gt;
&lt;th&gt;OpenAI&lt;/th&gt;
&lt;/tr&gt;
&lt;/thead&gt;
&lt;tbody&gt;
&lt;tr&gt;
&lt;td&gt;名稱&lt;/td&gt;
&lt;td&gt;&lt;code&gt;X-goog-api-key&lt;/code&gt;&lt;/td&gt;
&lt;td&gt;&lt;code&gt;Authorization&lt;/code&gt;&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;值&lt;/td&gt;
&lt;td&gt;你的 Gemini token&lt;/td&gt;
&lt;td&gt;
&lt;code&gt;Bearer sk-…&lt;/code&gt;（&lt;code&gt;Bearer&lt;/code&gt; 後面有一個空格）&lt;/td&gt;
&lt;/tr&gt;
&lt;/tbody&gt;
&lt;/table&gt;&lt;/div&gt;

&lt;h4&gt;
  
  
  4. 打開開關
&lt;/h4&gt;

&lt;p&gt;workflow 右上角點擊 &lt;strong&gt;Publish&lt;/strong&gt;。&lt;/p&gt;

&lt;h4&gt;
  
  
  5. 複製網址，貼進擴充
&lt;/h4&gt;

&lt;p&gt;打開 &lt;strong&gt;Webhook&lt;/strong&gt; 節點，複製 &lt;strong&gt;Production URL&lt;/strong&gt;（長得像 &lt;code&gt;https://你的n8n/webhook/google-chat-ai&lt;/code&gt;）。&lt;/p&gt;

&lt;p&gt;Chrome 工具列的擴充圖示 → &lt;strong&gt;選項&lt;/strong&gt; → 貼進「n8n Webhook URL」→ 儲存（會跳權限請求，允許）→ 按&lt;strong&gt;測試連線&lt;/strong&gt;，看到「連線成功」就完成了。&lt;/p&gt;

&lt;blockquote&gt;
&lt;p&gt;&lt;strong&gt;公司內網的 n8n 只有 http 沒有 https？&lt;/strong&gt; 可以。擴充接受 &lt;code&gt;http://&lt;/code&gt;，只是不加密，&lt;br&gt;
所以只適合沒有對外、在信任的內網裡的 n8n。&lt;/p&gt;
&lt;/blockquote&gt;

&lt;h3&gt;
  
  
  三、開始整理
&lt;/h3&gt;

&lt;ol&gt;
&lt;li&gt;打開 Google Chat，進入某個 Space 或 DM。需要更早的訊息可以先手動往上捲一點。&lt;/li&gt;
&lt;li&gt;點 &lt;strong&gt;Let's Chat AI&lt;/strong&gt; 的按鈕開啟面板。&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;打一句指示&lt;/strong&gt;，或選&lt;strong&gt;整理討論 / 整理工作項目 / 產生 Jira Draft&lt;/strong&gt;。&lt;/li&gt;
&lt;li&gt;確認「即將送出 N 則訊息」→ 送出。&lt;/li&gt;
&lt;li&gt;看結果。Jira Draft 可按「複製 Jira Draft」拿純文字。&lt;/li&gt;
&lt;/ol&gt;




&lt;h2&gt;
  
  
  兩份設定檔差在哪
&lt;/h2&gt;

&lt;div class="table-wrapper-paragraph"&gt;&lt;table&gt;
&lt;thead&gt;
&lt;tr&gt;
&lt;th&gt;&lt;/th&gt;
&lt;th&gt;Gemini 版&lt;/th&gt;
&lt;th&gt;OpenAI 版&lt;/th&gt;
&lt;/tr&gt;
&lt;/thead&gt;
&lt;tbody&gt;
&lt;tr&gt;
&lt;td&gt;檔名&lt;/td&gt;
&lt;td&gt;&lt;code&gt;google-chat-ai.gemini.workflow.json&lt;/code&gt;&lt;/td&gt;
&lt;td&gt;&lt;code&gt;google-chat-ai.openai.workflow.json&lt;/code&gt;&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;呼叫的 API&lt;/td&gt;
&lt;td&gt;&lt;code&gt;generativelanguage.googleapis.com&lt;/code&gt;&lt;/td&gt;
&lt;td&gt;&lt;code&gt;api.openai.com/v1/chat/completions&lt;/code&gt;&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;預設模型&lt;/td&gt;
&lt;td&gt;&lt;code&gt;gemini-3.5-flash-lite&lt;/code&gt;&lt;/td&gt;
&lt;td&gt;&lt;code&gt;gpt-5.6-luna&lt;/code&gt;&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;金鑰 header&lt;/td&gt;
&lt;td&gt;&lt;code&gt;X-goog-api-key&lt;/code&gt;&lt;/td&gt;
&lt;td&gt;&lt;code&gt;Authorization: Bearer sk-…&lt;/code&gt;&lt;/td&gt;
&lt;/tr&gt;
&lt;/tbody&gt;
&lt;/table&gt;&lt;/div&gt;

&lt;p&gt;其餘節點（&lt;code&gt;Webhook → Prepare Prompt → Call → Shape Result → Respond&lt;/code&gt;）完全一樣。&lt;/p&gt;

&lt;p&gt;想改整理的口氣，改 &lt;strong&gt;Prepare Prompt&lt;/strong&gt; 節點裡的 prompt 就好，別動最後 &lt;strong&gt;Respond&lt;/strong&gt; 回的&lt;br&gt;
&lt;code&gt;{ "success": true, "result": { … } }&lt;/code&gt; 形狀，那是擴充在讀的。&lt;/p&gt;




&lt;h2&gt;
  
  
  原始碼
&lt;/h2&gt;

&lt;p&gt;Let's Chat AI 擴充功能：&lt;a href="https://chromewebstore.google.com/detail/lets-chat-ai/cjhllfpcohiiclodggnfemcchidlgaaj" rel="noopener noreferrer"&gt;https://chromewebstore.google.com/detail/lets-chat-ai/cjhllfpcohiiclodggnfemcchidlgaaj&lt;/a&gt;。&lt;/p&gt;

&lt;p&gt;GitHub：&lt;a href="https://github.com/letswritetw/extension-lets-chat-ai" rel="noopener noreferrer"&gt;https://github.com/letswritetw/extension-lets-chat-ai&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;請大家多多支持，安裝來用、推薦給朋友、回報問題、給個評價都好，你的一個小小動作，對本站都是大大的鼓勵。&lt;/p&gt;

</description>
      <category>n8n</category>
      <category>googlechat</category>
      <category>openai</category>
      <category>gemini</category>
    </item>
    <item>
      <title>Agent Skill 開發：用 lets-social 自動將文章轉化為 IG、Threads、FB 社群貼文</title>
      <dc:creator>Let's Write</dc:creator>
      <pubDate>Tue, 01 Sep 2026 14:21:22 +0000</pubDate>
      <link>https://dev.to/letswrite/agent-skill-kai-fa-yong-lets-social-zi-dong-jiang-wen-zhang-zhuan-hua-wei-ig-threads-fb-she-qun-tie-wen-2940</link>
      <guid>https://dev.to/letswrite/agent-skill-kai-fa-yong-lets-social-zi-dong-jiang-wen-zhang-zhuan-hua-wei-ig-threads-fb-she-qun-tie-wen-2940</guid>
      <description>&lt;h2&gt;
  
  
  本篇要解決的問題
&lt;/h2&gt;

&lt;p&gt;以前流行手寫套件，分享到 GitHub 上讓人取用，而現在，流行的是寫 Skill 了。&lt;/p&gt;

&lt;p&gt;因為來自 Google 的流量一直在下降，所以 Let's Write 這陣子建了 &lt;a href="https://www.instagram.com/i.am.letswrite/" rel="noopener noreferrer"&gt;Instagram&lt;/a&gt;、&lt;a href="https://www.threads.com/@i.am.letswrite" rel="noopener noreferrer"&gt;Threads&lt;/a&gt; 帳號，增加導流的平台。&lt;/p&gt;

&lt;p&gt;只是每個社群都有各自的風格。&lt;/p&gt;

&lt;p&gt;為了讓一篇文章出來後，可以針對不同的平台，撰寫不同的貼文，就讓 AI 建立了本篇的 Skill，期待有效的增加本站流量。&lt;/p&gt;

&lt;p&gt;這是公開的 Skill，大家可以直接從 GitHub 上下載，安裝方式寫在簡易版的 README.md 中，以下筆記文是把安裝、使用的說明貼上來。&lt;/p&gt;

&lt;p&gt;GitHub：&lt;a href="https://github.com/letswritetw/lets-social" rel="noopener noreferrer"&gt;https://github.com/letswritetw/lets-social&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;取用前請給本專案一個星星，你一個小小的動作，對本站都是大大的鼓勵。&lt;/p&gt;




&lt;h2&gt;
  
  
  lets-social
&lt;/h2&gt;

&lt;p&gt;功用：把一篇文章轉寫成符合 Instagram、Facebook、Threads 與 Telegram 等，符合社群平台特性的貼文內容。&lt;/p&gt;

&lt;p&gt;&lt;code&gt;lets-social&lt;/code&gt; 是純指令型 Agent Skill。&lt;/p&gt;

&lt;p&gt;當我們提供已完成的文章、Markdown、純文字、本機檔案後，Agent 都能讀取的內容，然後先建立一份內部 Source Brief，再針對每個指定平台獨立撰寫發文文字。&lt;/p&gt;

&lt;p&gt;Instagram 預設會附上 Nano Banana 2 與 ChatGPT Images 2.0 的可直接使用 prompt。&lt;/p&gt;

&lt;p&gt;Threads 只在圖片能補充內容時提供。&lt;/p&gt;

&lt;p&gt;它不負責發佈、排程，也不替來源補上未經證實的資料。&lt;/p&gt;

&lt;p&gt;所有輸出都必須保留原文的事實、不確定性、立場與作者語氣。&lt;/p&gt;




&lt;h2&gt;
  
  
  為什麼要用 lets-social？
&lt;/h2&gt;

&lt;p&gt;每個社群平台都有不同的閱讀方式：&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;Facebook 適合補充背景。&lt;/li&gt;
&lt;li&gt;Threads 適合從一個明確觀察切入。&lt;/li&gt;
&lt;li&gt;Telegram 則重視資訊密度與掃讀效率。&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;&lt;code&gt;lets-social&lt;/code&gt; 會依平台重新判斷 Hook、資訊順序、語氣與 CTA，不會只把同一份文案改成不同長度。&lt;/p&gt;

&lt;p&gt;圖片也採用相同原則：&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;Instagram 預設需要視覺素材。&lt;/li&gt;
&lt;li&gt;Threads 不會為了湊格式加入裝飾圖。&lt;/li&gt;
&lt;/ul&gt;




&lt;h2&gt;
  
  
  支援平台
&lt;/h2&gt;

&lt;div class="table-wrapper-paragraph"&gt;&lt;table&gt;
&lt;thead&gt;
&lt;tr&gt;
&lt;th&gt;平台&lt;/th&gt;
&lt;th&gt;預設輸出&lt;/th&gt;
&lt;th&gt;內容重點&lt;/th&gt;
&lt;/tr&gt;
&lt;/thead&gt;
&lt;tbody&gt;
&lt;tr&gt;
&lt;td&gt;Instagram&lt;/td&gt;
&lt;td&gt;Caption、CTA、可選 Hashtag 或 Carousel、產圖 prompt&lt;/td&gt;
&lt;td&gt;手機閱讀、實用價值與配圖&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;Facebook&lt;/td&gt;
&lt;td&gt;Post、CTA&lt;/td&gt;
&lt;td&gt;背景、寫作動機與作者觀點&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;Threads&lt;/td&gt;
&lt;td&gt;單篇貼文或適合的串文；必要時附產圖 prompt&lt;/td&gt;
&lt;td&gt;口語觀察與討論感&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;Telegram&lt;/td&gt;
&lt;td&gt;Message、連結位置建議&lt;/td&gt;
&lt;td&gt;清楚、易掃讀與資訊密度&lt;/td&gt;
&lt;/tr&gt;
&lt;/tbody&gt;
&lt;/table&gt;&lt;/div&gt;




&lt;h2&gt;
  
  
  運作方式
&lt;/h2&gt;



&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;來源文章
    -&amp;gt; 內部 Source Brief
        -&amp;gt; Instagram 草稿
        -&amp;gt; Facebook 草稿
        -&amp;gt; Threads 草稿
        -&amp;gt; Telegram 草稿
        -&amp;gt; Instagram Image Brief
        -&amp;gt; 可選的 Threads Image Brief
    -&amp;gt; 每份 Image Brief 產生兩個模型的完整 prompt
    -&amp;gt; 來源忠實度與平台差異檢查
    -&amp;gt; Markdown 輸出
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;每個平台都從同一份 Source Brief 出發，不會拿某個平台的草稿當成另一個平台的輸入。&lt;/p&gt;

&lt;p&gt;同一平台的兩份產圖 prompt 使用相同 Image Brief，讓主體、構圖與訊息保持一致。&lt;/p&gt;




&lt;h2&gt;
  
  
  安裝
&lt;/h2&gt;

&lt;p&gt;Clone 或下載此 &lt;a href="https://github.com/letswritetw/lets-social" rel="noopener noreferrer"&gt;repository&lt;/a&gt;。&lt;/p&gt;

&lt;p&gt;再將完整的 &lt;code&gt;lets-social&lt;/code&gt; 目錄放到 Agent 支援的 Skill 路徑。&lt;/p&gt;

&lt;p&gt;請保留 &lt;code&gt;SKILL.md&lt;/code&gt;、&lt;code&gt;references/&lt;/code&gt; 與 &lt;code&gt;examples/&lt;/code&gt; 的相對位置。&lt;/p&gt;

&lt;p&gt;若希望之後能更新，請使用 Git Clone，並直接 Clone 到下列 Skill 路徑，因為下載 ZIP 的安裝方式不會保留 Git 更新紀錄。&lt;/p&gt;

&lt;h3&gt;
  
  
  Claude Code
&lt;/h3&gt;

&lt;p&gt;安裝為個人 Skill：&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight shell"&gt;&lt;code&gt;git clone https://github.com/letswritetw/lets-social.git ~/.claude/skills/lets-social
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Windows 使用者&lt;/p&gt;

&lt;p&gt;Git Bash 可以直接用上面的指令，但 PowerShell 和 cmd 不會展開 &lt;code&gt;~&lt;/code&gt;，會在當前目錄建一個名字叫 &lt;code&gt;~&lt;/code&gt; 的資料夾，所以請改用下面的指令。&lt;/p&gt;

&lt;p&gt;PowerShell：&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight powershell"&gt;&lt;code&gt;&lt;span class="n"&gt;git&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="nx"&gt;clone&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="nx"&gt;https://github.com/letswritetw/lets-social.git&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="s2"&gt;"&lt;/span&gt;&lt;span class="bp"&gt;$HOME&lt;/span&gt;&lt;span class="s2"&gt;/.claude/skills/lets-social"&lt;/span&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;cmd：&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight shell"&gt;&lt;code&gt;git clone https://github.com/letswritetw/lets-social.git &lt;span class="s2"&gt;"%USERPROFILE%/.claude/skills/lets-social"&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;或安裝在單一專案，在專案根目錄執行：&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight shell"&gt;&lt;code&gt;git clone https://github.com/letswritetw/lets-social.git .claude/skills/lets-social
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Claude Code 可以依 description 自動選用，也可以用 &lt;code&gt;/lets-social&lt;/code&gt; 明確呼叫。&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;/lets-social 把 ./article.md 轉成 Instagram 與 Threads 貼文。
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;h3&gt;
  
  
  Codex
&lt;/h3&gt;

&lt;p&gt;安裝為個人 Skill：&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight shell"&gt;&lt;code&gt;git clone https://github.com/letswritetw/lets-social.git ~/.agents/skills/lets-social
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Windows 使用者&lt;/p&gt;

&lt;p&gt;Git Bash 可以直接用上面的指令。但 PowerShell 和 cmd 不會展開 &lt;code&gt;~&lt;/code&gt;，請改用下面的指令。&lt;/p&gt;

&lt;p&gt;PowerShell：&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight powershell"&gt;&lt;code&gt;&lt;span class="n"&gt;git&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="nx"&gt;clone&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="nx"&gt;https://github.com/letswritetw/lets-social.git&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="s2"&gt;"&lt;/span&gt;&lt;span class="bp"&gt;$HOME&lt;/span&gt;&lt;span class="s2"&gt;/.agents/skills/lets-social"&lt;/span&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;cmd：&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight shell"&gt;&lt;code&gt;git clone https://github.com/letswritetw/lets-social.git &lt;span class="s2"&gt;"%USERPROFILE%/.agents/skills/lets-social"&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;或安裝在單一 repository，在 repository 根目錄執行：&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight shell"&gt;&lt;code&gt;git clone https://github.com/letswritetw/lets-social.git .agents/skills/lets-social
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Codex 可以依 description 自動選用，也可以用 &lt;code&gt;$lets-social&lt;/code&gt; 明確呼叫。&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight shell"&gt;&lt;code&gt;&lt;span class="nv"&gt;$lets&lt;/span&gt;&lt;span class="nt"&gt;-social&lt;/span&gt; 把 ./article.md 轉成 Instagram 與 Threads 貼文。
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;h3&gt;
  
  
  其他支援 Agent Skills 的工具
&lt;/h3&gt;

&lt;p&gt;請依工具文件提供的安裝路徑，複製完整的 &lt;code&gt;lets-social&lt;/code&gt; 目錄。&lt;/p&gt;

&lt;p&gt;此專案遵循 &lt;a href="https://agentskills.io/specification" rel="noopener noreferrer"&gt;Agent Skills 規格&lt;/a&gt;，使用包含 &lt;code&gt;name&lt;/code&gt; 與 &lt;code&gt;description&lt;/code&gt; 的 YAML frontmatter、Markdown 指令本文，以及按需求讀取的 reference 檔案。&lt;/p&gt;

&lt;p&gt;安裝後，可以從工具的 Skill 選單呼叫 &lt;code&gt;lets-social&lt;/code&gt;，或在提示中直接指定：&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;使用 lets-social，把這篇文章轉成 Facebook 與 Telegram 貼文。
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Agent Skills 規格定義可攜的封裝格式，不負責統一各工具的安裝路徑，也不保證每個工具都支援相同的產品專屬功能。&lt;/p&gt;

&lt;p&gt;&lt;code&gt;lets-social&lt;/code&gt; 只使用共通 frontmatter 欄位與一般 Markdown 相對連結，降低對單一工具的依賴。&lt;/p&gt;




&lt;h2&gt;
  
  
  版本與更新
&lt;/h2&gt;

&lt;h3&gt;
  
  
  Git 更新（建議）
&lt;/h3&gt;

&lt;p&gt;使用 Git Clone 安裝的使用者，可以依安裝位置執行：&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight shell"&gt;&lt;code&gt;&lt;span class="c"&gt;# Claude Code 個人 Skill&lt;/span&gt;
git &lt;span class="nt"&gt;-C&lt;/span&gt; ~/.claude/skills/lets-social pull &lt;span class="nt"&gt;--ff-only&lt;/span&gt;

&lt;span class="c"&gt;# Codex 個人 Skill&lt;/span&gt;
git &lt;span class="nt"&gt;-C&lt;/span&gt; ~/.agents/skills/lets-social pull &lt;span class="nt"&gt;--ff-only&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Windows 使用者&lt;/p&gt;

&lt;p&gt;PowerShell 和 cmd 一樣不會展開 &lt;code&gt;~&lt;/code&gt;。Git Bash 可直接使用上面的指令。&lt;/p&gt;

&lt;p&gt;PowerShell，Claude Code：&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight powershell"&gt;&lt;code&gt;&lt;span class="n"&gt;git&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="nt"&gt;-C&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="s2"&gt;"&lt;/span&gt;&lt;span class="bp"&gt;$HOME&lt;/span&gt;&lt;span class="s2"&gt;/.claude/skills/lets-social"&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="nx"&gt;pull&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="nt"&gt;--ff-only&lt;/span&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;PowerShell，Codex：&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight powershell"&gt;&lt;code&gt;&lt;span class="n"&gt;git&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="nt"&gt;-C&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="s2"&gt;"&lt;/span&gt;&lt;span class="bp"&gt;$HOME&lt;/span&gt;&lt;span class="s2"&gt;/.agents/skills/lets-social"&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="nx"&gt;pull&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="nt"&gt;--ff-only&lt;/span&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;cmd，Claude Code：&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight shell"&gt;&lt;code&gt;git &lt;span class="nt"&gt;-C&lt;/span&gt; &lt;span class="s2"&gt;"%USERPROFILE%/.claude/skills/lets-social"&lt;/span&gt; pull &lt;span class="nt"&gt;--ff-only&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;cmd，Codex：&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight shell"&gt;&lt;code&gt;git &lt;span class="nt"&gt;-C&lt;/span&gt; &lt;span class="s2"&gt;"%USERPROFILE%/.agents/skills/lets-social"&lt;/span&gt; pull &lt;span class="nt"&gt;--ff-only&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;專案層級或其他 Agent 的安裝位置，請將上面的路徑替換為實際的 &lt;code&gt;lets-social&lt;/code&gt; 目錄。&lt;/p&gt;

&lt;p&gt;&lt;code&gt;--ff-only&lt;/code&gt; 會在本機內容與遠端版本分歧時停止，不會直接覆蓋使用者的修改。&lt;/p&gt;

&lt;p&gt;下載 ZIP 或直接複製資料夾的使用者，請重新下載最新版，並以完整目錄取代舊版。&lt;/p&gt;

&lt;p&gt;若曾自訂 Skill，請先備份或保留差異。&lt;/p&gt;

&lt;h3&gt;
  
  
  使用 Skillshare 追蹤（選用）
&lt;/h3&gt;

&lt;p&gt;&lt;a href="https://github.com/runkids/skillshare" rel="noopener noreferrer"&gt;Skillshare&lt;/a&gt; 使用者可以用它安裝並更新：&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight shell"&gt;&lt;code&gt;skillshare &lt;span class="nb"&gt;install &lt;/span&gt;letswritetw/lets-social
skillshare &lt;span class="nb"&gt;sync&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;之後檢查與更新：&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight shell"&gt;&lt;code&gt;skillshare check lets-social
skillshare update lets-social
skillshare &lt;span class="nb"&gt;sync&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;請不要加 &lt;code&gt;--track&lt;/code&gt;。&lt;/p&gt;

&lt;p&gt;這個 repository 把 &lt;code&gt;SKILL.md&lt;/code&gt; 放在根目錄，&lt;code&gt;--track&lt;/code&gt; 會改用追蹤模式，把它記成 &lt;code&gt;_lets-social&lt;/code&gt; 並回報 &lt;code&gt;0 skills&lt;/code&gt;，Skill 不會被 sync 到 Agent 的目錄。&lt;/p&gt;

&lt;p&gt;不加 &lt;code&gt;--track&lt;/code&gt; 時 &lt;code&gt;skillshare update&lt;/code&gt; 一樣可以更新。&lt;/p&gt;

&lt;p&gt;Skillshare 是選用的第三方工具，不是執行 &lt;code&gt;lets-social&lt;/code&gt; 的必要相依套件。&lt;/p&gt;




&lt;h2&gt;
  
  
  使用範例
&lt;/h2&gt;



&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;使用 lets-social，把 article.md 轉成 Instagram、Facebook、
Threads 與 Telegram 貼文。
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;





&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;幫我宣傳這篇技術文章，只做 Threads 和 Telegram。Threads 口語一點，
Telegram 像頻道公告，所有平台都不要 Hashtag。
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;





&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;把這篇文章改寫成 Facebook 宣傳文。保留作者的技術語氣，
CTA 要引導讀者閱讀完整文章。
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;





&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;Instagram 不要產圖 prompt；Threads 這篇要一張配圖。
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;如果 Agent 無法讀取網址，Skill 會停止產生貼文，並要求你提供文章本文或 Markdown。&lt;/p&gt;

&lt;p&gt;它不會假裝已經讀過網頁。&lt;/p&gt;




&lt;h2&gt;
  
  
  支援的來源
&lt;/h2&gt;

&lt;ul&gt;
&lt;li&gt;已完成的純文字或 Markdown。&lt;/li&gt;
&lt;li&gt;可讀取的本機文章或文件。&lt;/li&gt;
&lt;li&gt;目前 Agent 具備網頁讀取能力時可使用網址。&lt;/li&gt;
&lt;li&gt;先前由 &lt;code&gt;lets-social&lt;/code&gt; 產生的內容，可用於單一平台調整。&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;來源必須包含足以支撐貼文的文章內容。只有標題或搜尋摘要並不足夠。&lt;/p&gt;




&lt;h2&gt;
  
  
  產圖 prompt
&lt;/h2&gt;

&lt;p&gt;Instagram 預設在文案後輸出 &lt;code&gt;Image Direction&lt;/code&gt;、&lt;code&gt;Nano Banana 2 Prompt&lt;/code&gt; 與 &lt;code&gt;ChatGPT Images 2.0 Prompt&lt;/code&gt;。&lt;/p&gt;

&lt;p&gt;兩份 prompt 都是完整內容，可以分別貼進 Gemini 與 ChatGPT，不需要再補文章背景。&lt;/p&gt;

&lt;p&gt;Threads 只有在圖片能說明比較、流程、具體物件、空間關係或文章支持的視覺概念時才輸出這三個欄位。純觀點與討論型貼文會保留文字形式。使用者可以明確要求加入或省略圖片 prompt。&lt;/p&gt;

&lt;p&gt;每個平台各自建立 Image Brief。&lt;/p&gt;

&lt;p&gt;同一平台的兩份 prompt 必須使用相同主體、構圖、圖中文字與排除條件。&lt;/p&gt;

&lt;h3&gt;
  
  
  視覺風格依文章挑選
&lt;/h3&gt;

&lt;p&gt;不套用單一固定風格。&lt;/p&gt;

&lt;p&gt;Skill 會依文章實際內容選一個方向，在 Image Brief 說明選擇理由，並讓同一平台的所有圖片維持同一套風格。&lt;/p&gt;

&lt;div class="table-wrapper-paragraph"&gt;&lt;table&gt;
&lt;thead&gt;
&lt;tr&gt;
&lt;th&gt;方向&lt;/th&gt;
&lt;th&gt;適合的文章&lt;/th&gt;
&lt;/tr&gt;
&lt;/thead&gt;
&lt;tbody&gt;
&lt;tr&gt;
&lt;td&gt;知識圖卡&lt;/td&gt;
&lt;td&gt;檢查清單、評估條件、操作步驟&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;編輯式圖解&lt;/td&gt;
&lt;td&gt;架構、資料流、請求生命週期、前後對照&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;大字海報&lt;/td&gt;
&lt;td&gt;單一主張或一個反直覺的結論&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;終端機或藍圖&lt;/td&gt;
&lt;td&gt;底層工程、工具、協定、除錯&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;插畫場景&lt;/td&gt;
&lt;td&gt;團隊流程、職涯、決策&lt;/td&gt;
&lt;/tr&gt;
&lt;/tbody&gt;
&lt;/table&gt;&lt;/div&gt;

&lt;p&gt;原文若指向更合適的方向，也可以改寫成自訂風格。使用者明確指定風格時以使用者為準。&lt;/p&gt;

&lt;h3&gt;
  
  
  每份 prompt 都會包含的內容
&lt;/h3&gt;

&lt;ul&gt;
&lt;li&gt;至少四個具名顏色，並說明每個顏色負責什麼；使用者要求單色時例外。&lt;/li&gt;
&lt;li&gt;來源支持的重點短句，直接寫在圖上。&lt;/li&gt;
&lt;li&gt;閱讀層級：哪個元素先讀、其次、最後。&lt;/li&gt;
&lt;li&gt;足夠的紋理、標註或結構細節，避免變成空泛的素材圖。&lt;/li&gt;
&lt;/ul&gt;

&lt;h3&gt;
  
  
  圖中文字與字體規則
&lt;/h3&gt;

&lt;p&gt;圖中文字預設為必要，不是選配。&lt;/p&gt;

&lt;p&gt;標題一句、重點三到五句、可選的結語一句，全部在 prompt 中逐字列出並指定位置，並要求模型不要輸出其他文字。&lt;/p&gt;

&lt;p&gt;每一句都必須是原文支持的說法，不能新增數字、結果或保證。&lt;/p&gt;

&lt;p&gt;中文、日文、韓文一律指定清楚精確的粗體無襯線字，不使用手寫、毛筆、書法或做舊效果。&lt;/p&gt;

&lt;p&gt;產圖模型處理手寫 CJK 一定會糊，這條規則在所有風格下都成立。裝飾性手寫只用在兩到四個字的英文短語上，並且在 prompt 中明講這個分工。&lt;/p&gt;

&lt;h3&gt;
  
  
  兩個模型的差別
&lt;/h3&gt;

&lt;p&gt;Nano Banana 2 維持單張，對應 Instagram 的 4:5 封面。&lt;/p&gt;

&lt;p&gt;ChatGPT Images 2.0 一次最多可產 10 張，且每張可以承載不同內容，所以它那份 prompt 是一組編號系列：&lt;/p&gt;

&lt;p&gt;第 1 張是封面，之後每個重點各一張，可選最後一張放結語或導讀 CTA。&lt;/p&gt;

&lt;p&gt;預設為封面加三到五個重點，也就是四到六張。&lt;/p&gt;

&lt;p&gt;輸出含 Carousel 大綱時改以大綱為準。整組共用同一個背景、色盤、字體規則與視覺語彙，只有內容改變。&lt;/p&gt;

&lt;p&gt;需要單張時，只取第 1 張。&lt;/p&gt;

&lt;p&gt;Skill 只撰寫 prompt，不會連線到 Gemini 或 ChatGPT。實際產圖功能與費用依使用者的帳號方案而定。&lt;/p&gt;




&lt;h2&gt;
  
  
  自訂品牌語氣
&lt;/h2&gt;

&lt;p&gt;預設語氣清楚、專業、容易親近，並以實用與易懂的方式表達技術內容。&lt;/p&gt;

&lt;p&gt;原文明確呈現的作者語氣擁有較高優先順序。&lt;/p&gt;

&lt;p&gt;我們可以直接用自然語言覆寫設定：&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;語氣更像個人心得，不要 emoji，不要 Hashtag，技術名詞要精確。
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;使用者可以調整文風，但不能藉此改變來源事實或加入沒有根據的資訊。&lt;/p&gt;




&lt;h2&gt;
  
  
  只產生部分平台
&lt;/h2&gt;

&lt;p&gt;只要指定需要的平台：&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;只產生 Threads 與 Telegram。
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;後續也能只調整單一平台：&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;Threads 再短一點，語氣更口語。
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Skill 只會修改 Threads，不會重新產生其他平台內容。&lt;/p&gt;




&lt;h2&gt;
  
  
  專案結構
&lt;/h2&gt;



&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;lets-social/
├── .gitignore
├── SKILL.md
├── README.md
├── README-full.md
├── CHANGELOG.md
├── LICENSE
├── references/
│   ├── instagram.md
│   ├── facebook.md
│   ├── threads.md
│   ├── telegram.md
│   ├── brand-voice.md
│   ├── image-prompts.md
│   └── output-format.md
└── examples/
    ├── input-example.md
    └── output-example.md
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;此 &lt;a href="https://github.com/letswritetw/lets-social" rel="noopener noreferrer"&gt;repository&lt;/a&gt; 不需要 runtime、套件管理工具、建置系統或 API server。&lt;/p&gt;

&lt;p&gt;只有實際使用 prompt 產圖時才需要開啟外部產圖服務。&lt;/p&gt;

&lt;h3&gt;
  
  
  新增其他平台
&lt;/h3&gt;

&lt;ol&gt;
&lt;li&gt;在 &lt;code&gt;references/&lt;/code&gt; 新增一份專用文件，定義平台目標、內容判斷、輸出欄位與檢查項目。&lt;/li&gt;
&lt;li&gt;在 &lt;code&gt;SKILL.md&lt;/code&gt; 加入平台路由，不要把詳細規則複製回主檔。&lt;/li&gt;
&lt;li&gt;在 &lt;code&gt;references/output-format.md&lt;/code&gt; 加入最小且實用的輸出格式。&lt;/li&gt;
&lt;li&gt;補上範例，並確認 Hook、結構、資訊順序與 CTA 都和其他平台不同。&lt;/li&gt;
&lt;/ol&gt;

&lt;p&gt;除非需要可重複且具確定性的工具操作，否則請維持純指令結構。&lt;/p&gt;

</description>
      <category>ai</category>
      <category>skill</category>
      <category>socialmedia</category>
    </item>
    <item>
      <title>Claude Code + Sentry MCP + Gitea MCP：每日自動抓 bug、修復、開 PR</title>
      <dc:creator>Let's Write</dc:creator>
      <pubDate>Sun, 23 Aug 2026 07:38:03 +0000</pubDate>
      <link>https://dev.to/letswrite/claude-code-sentry-mcp-gitea-mcpmei-ri-zi-dong-zhua-bug-xiu-fu-kai-pr-43c2</link>
      <guid>https://dev.to/letswrite/claude-code-sentry-mcp-gitea-mcpmei-ri-zi-dong-zhua-bug-xiu-fu-kai-pr-43c2</guid>
      <description>&lt;h2&gt;
  
  
  本篇要解決的問題
&lt;/h2&gt;

&lt;p&gt;除了開發新專案，工程師日常最耗時的工作通常是排查、修復既有系統的 Bug。&lt;/p&gt;

&lt;p&gt;而當 Anthropic 推出 Model Context Protocol （MCP）後，AI 在軟體開發自動化（DevOps Automation）有了全新落地應用，那有沒有辦法可以讓 AI 自己去找 bug 然後再自己修？&lt;/p&gt;

&lt;p&gt;想到以前曾用過一陣子 Sentry，查了一下有 MCP 可用。&lt;/p&gt;

&lt;p&gt;再查了一下 Gitea，也確定有 MCP 可用。&lt;/p&gt;

&lt;p&gt;那把兩邊尬在一起，不就可以達成本篇的目標：AI 自己找 bug 後自己修？&lt;/p&gt;

&lt;p&gt;本文實作如何透過 Sentry MCP 自動抓取 Production 錯誤堆疊，再結合 Gitea MCP 讓 Claude Code 實現每日自動找 Bug、本機修復測試、自動提交 PR 的完整除錯流程。&lt;/p&gt;




&lt;h2&gt;
  
  
  安裝 Sentry MCP
&lt;/h2&gt;

&lt;p&gt;本機要先安裝 Claude CLI：&lt;a href="https://code.claude.com/docs/en/quickstart" rel="noopener noreferrer"&gt;https://code.claude.com/docs/en/quickstart&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;1 先下指令安裝，安裝 Sentry MCP：&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight shell"&gt;&lt;code&gt;claude mcp add &lt;span class="nt"&gt;--transport&lt;/span&gt; http sentry https://mcp.sentry.dev/mcp &lt;span class="nt"&gt;--scope&lt;/span&gt; user
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;2 登入 Sentry 帳戶進行授權：&lt;/p&gt;

&lt;p&gt;終端機輸入 claude，接著輸入：&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight shell"&gt;&lt;code&gt;/mcp list
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;清單裡會看到 sentry 顯示為未授權，對 sentry 那項按 enter，瀏覽器會開啟頁面，都按 Approve 就行：&lt;/p&gt;

&lt;p&gt;&lt;a href="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.us-east-2.amazonaws.com%2Fuploads%2Farticles%2Fh6c6vk6nkv65hwafn3yt.png" class="article-body-image-wrapper"&gt;&lt;img src="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.us-east-2.amazonaws.com%2Fuploads%2Farticles%2Fh6c6vk6nkv65hwafn3yt.png" alt="Claude Code 終端機執行 MCP list 選擇 Sentry 授權" width="799" height="366"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;Claude Code 終端機執行 MCP list 選擇 Sentry 授權&lt;/p&gt;

&lt;p&gt;&lt;a href="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.us-east-2.amazonaws.com%2Fuploads%2Farticles%2F5rzn9mumqrvk8mkefed7.png" class="article-body-image-wrapper"&gt;&lt;img src="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.us-east-2.amazonaws.com%2Fuploads%2Farticles%2F5rzn9mumqrvk8mkefed7.png" alt="Sentry 官方網站 OAuth 授權頁面點擊 Approve" width="800" height="555"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;Sentry 官方網站 OAuth 授權頁面點擊 Approve&lt;/p&gt;

&lt;p&gt;&lt;a href="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.us-east-2.amazonaws.com%2Fuploads%2Farticles%2Fsmpe8f9e398x2ymg77ue.png" class="article-body-image-wrapper"&gt;&lt;img src="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.us-east-2.amazonaws.com%2Fuploads%2Farticles%2Fsmpe8f9e398x2ymg77ue.png" alt="Sentry MCP 授權成功完成提示頁面" width="698" height="337"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;Sentry MCP 授權成功完成提示頁面&lt;/p&gt;

&lt;p&gt;接著 Claude 要重啟，可以問問 Claude 有了 Sentry MCP 後它可以做到哪些事，August 詢問後回答如下：&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;
&lt;strong&gt;查 issue&lt;/strong&gt;：&lt;code&gt;search_issues&lt;/code&gt; 搜錯誤，按專案/時間/狀態過濾&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;查事件&lt;/strong&gt;：&lt;code&gt;search_events&lt;/code&gt; 挖詳細 event 資料，stack trace、tag、breadcrumb 都能看&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;AI 診斷&lt;/strong&gt;：&lt;code&gt;analyze_issue_with_seer&lt;/code&gt; 丟給 Seer 分析根因，給修復建議&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;改狀態&lt;/strong&gt;：&lt;code&gt;update_issue&lt;/code&gt; 標 resolved/ignored、指派負責人&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;找組織/專案&lt;/strong&gt;：&lt;code&gt;find_organizations&lt;/code&gt;、&lt;code&gt;find_projects&lt;/code&gt; 列出可存取範圍&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;通用查詢&lt;/strong&gt;：&lt;code&gt;get_sentry_resource&lt;/code&gt;、&lt;code&gt;execute_sentry_tool&lt;/code&gt; 存取更細資源&lt;/li&gt;
&lt;/ul&gt;




&lt;h2&gt;
  
  
  讓 Claude 知道要抓取哪個專案
&lt;/h2&gt;

&lt;p&gt;Sentry 後台的側邊導覽列，點擊「設定 &amp;gt; 專案」，然後點擊要讓 Claude 分析的專案後，會看到專案資訊：&lt;/p&gt;

&lt;p&gt;&lt;a href="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.us-east-2.amazonaws.com%2Fuploads%2Farticles%2F8gwbsg9v5gaee4ytnv10.png" class="article-body-image-wrapper"&gt;&lt;img src="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.us-east-2.amazonaws.com%2Fuploads%2Farticles%2F8gwbsg9v5gaee4ytnv10.png" alt="Sentry 後台專案設定中查看 Project Slug 與專案編號" width="719" height="341"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;Sentry 後台專案設定中查看 Project Slug 與專案編號&lt;/p&gt;

&lt;p&gt;提供 Slug 或是專案編號給 Claude 都行，就會抓到了，以下是 August 提供專案編號的示範：&lt;/p&gt;

&lt;p&gt;&lt;a href="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.us-east-2.amazonaws.com%2Fuploads%2Farticles%2Fikigixt4xom2q7moi8p8.png" class="article-body-image-wrapper"&gt;&lt;img src="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.us-east-2.amazonaws.com%2Fuploads%2Farticles%2Fikigixt4xom2q7moi8p8.png" alt="在 Claude Code 對話中提供 Sentry 專案編號進行讀取" width="653" height="866"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;在 Claude Code 對話中提供 Sentry 專案編號進行讀取&lt;/p&gt;




&lt;h2&gt;
  
  
  安裝 Gitea MCP
&lt;/h2&gt;

&lt;p&gt;下列有三種方式，無論選擇哪種安裝方式，都需要先取得一組具備讀寫權限的 Gitea Token。&lt;/p&gt;

&lt;p&gt;詳細的 Token 建立步驟與權限設定，請參考站內筆記文：&lt;/p&gt;

&lt;p&gt;&lt;a href="https://www.letswrite.tw/gitea-ai-code-review-2/" rel="noopener noreferrer"&gt;CodiumAI PR-Agent，在 Gitea 上用 AI 來 Code Review&lt;/a&gt;&lt;/p&gt;

&lt;h3&gt;
  
  
  方式一：直接用 go run
&lt;/h3&gt;

&lt;p&gt;需要本機有 Go 才能使用：&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight shell"&gt;&lt;code&gt;claude mcp add &lt;span class="nt"&gt;--transport&lt;/span&gt; stdio &lt;span class="nt"&gt;--scope&lt;/span&gt; user gitea &lt;span class="se"&gt;\&lt;/span&gt;
  &lt;span class="nt"&gt;--env&lt;/span&gt; &lt;span class="nv"&gt;GITEA_ACCESS_TOKEN&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;你的token &lt;span class="se"&gt;\&lt;/span&gt;
  &lt;span class="nt"&gt;--env&lt;/span&gt; &lt;span class="nv"&gt;GITEA_HOST&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;https://your-gitea.internal &lt;span class="se"&gt;\&lt;/span&gt;
  &lt;span class="nt"&gt;--&lt;/span&gt; go run gitea.com/gitea/gitea-mcp@latest &lt;span class="nt"&gt;-t&lt;/span&gt; stdio
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;h3&gt;
  
  
  方式二：下載官方執行檔
&lt;/h3&gt;

&lt;p&gt;官方 &lt;a href="https://gitea.com/gitea/gitea-mcp/releases" rel="noopener noreferrer"&gt;releases&lt;/a&gt; 有提供 gitea-mcp_Windows_x86_64.zip 給 Windows，以及 gitea-mcp_Darwin_arm64.tar.gz 給 Apple Silicon Mac。&lt;/p&gt;

&lt;p&gt;Windows：&lt;/p&gt;

&lt;p&gt;從 &lt;a href="https://gitea.com/gitea/gitea-mcp/releases" rel="noopener noreferrer"&gt;https://gitea.com/gitea/gitea-mcp/releases&lt;/a&gt; 下載 gitea-mcp_Windows_x86_64.zip&lt;br&gt;
解壓縮,把 gitea-mcp.exe 放到一個固定資料夾(例如 C:\Tools\gitea-mcp)。&lt;/p&gt;

&lt;p&gt;把該資料夾加進系統環境變數 PATH。&lt;/p&gt;

&lt;p&gt;Mac：&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight shell"&gt;&lt;code&gt;curl &lt;span class="nt"&gt;-LO&lt;/span&gt; &lt;span class="o"&gt;[&lt;/span&gt;https://gitea.com/gitea/gitea-mcp/releases/download/v1.2.0/gitea-mcp_Darwin_arm64.tar.gz]&lt;span class="o"&gt;(&lt;/span&gt;https://gitea.com/gitea/gitea-mcp/releases/download/v1.2.0/gitea-mcp_Darwin_arm64.tar.gz&lt;span class="o"&gt;)&lt;/span&gt;
&lt;span class="nb"&gt;tar&lt;/span&gt; &lt;span class="nt"&gt;-xzf&lt;/span&gt; gitea-mcp_Darwin_arm64.tar.gz
&lt;span class="nb"&gt;sudo mv &lt;/span&gt;gitea-mcp /usr/local/bin/
&lt;span class="nb"&gt;chmod&lt;/span&gt; +x /usr/local/bin/gitea-mcp
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;安裝好 Gitea MCP 後，接上 Claude Code：&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight shell"&gt;&lt;code&gt;claude mcp add &lt;span class="nt"&gt;--transport&lt;/span&gt; stdio &lt;span class="nt"&gt;--scope&lt;/span&gt; user gitea &lt;span class="nt"&gt;--env&lt;/span&gt; &lt;span class="nv"&gt;GITEA_ACCESS_TOKEN&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;你的token &lt;span class="nt"&gt;--env&lt;/span&gt; &lt;span class="nv"&gt;GITEA_HOST&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;https://your-gitea.internal &lt;span class="nt"&gt;--&lt;/span&gt; gitea-mcp &lt;span class="nt"&gt;-t&lt;/span&gt; stdio
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;h3&gt;
  
  
  方式三：用 Docker
&lt;/h3&gt;

&lt;p&gt;官方也提供 &lt;a href="http://docker.gitea.com/gitea-mcp-server" rel="noopener noreferrer"&gt;docker.gitea.com/gitea-mcp-server&lt;/a&gt; 這個 image，不需要額外編譯或裝 Go。&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight shell"&gt;&lt;code&gt;claude mcp add &lt;span class="nt"&gt;--transport&lt;/span&gt; stdio &lt;span class="nt"&gt;--scope&lt;/span&gt; user gitea &lt;span class="se"&gt;\&lt;/span&gt;
&lt;span class="nt"&gt;--env&lt;/span&gt; &lt;span class="nv"&gt;GITEA_ACCESS_TOKEN&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;你的token &lt;span class="se"&gt;\&lt;/span&gt;
&lt;span class="nt"&gt;--env&lt;/span&gt; &lt;span class="nv"&gt;GITEA_HOST&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;https://your-gitea.internal &lt;span class="se"&gt;\&lt;/span&gt;
&lt;span class="nt"&gt;--&lt;/span&gt; docker run &lt;span class="nt"&gt;--rm&lt;/span&gt; &lt;span class="nt"&gt;-i&lt;/span&gt; &lt;span class="nt"&gt;-e&lt;/span&gt; GITEA_ACCESS_TOKEN &lt;span class="nt"&gt;-e&lt;/span&gt; GITEA_HOST &lt;span class="o"&gt;[&lt;/span&gt;docker.gitea.com/gitea-mcp-server]&lt;span class="o"&gt;(&lt;/span&gt;http://docker.gitea.com/gitea-mcp-server&lt;span class="o"&gt;)&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;不管選擇哪種方式，安裝好後在 Claude Code 輸入 /mcp，確認 Gitea 連線成功。&lt;/p&gt;




&lt;h2&gt;
  
  
  Claude Code 設定排程
&lt;/h2&gt;

&lt;p&gt;Claude Code 選好本機專案後，貼上以下：&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight markdown"&gt;&lt;code&gt;建立一個本機的排程，在本專案執行以下「Sentry issue 自動修復」功能：

Sentry 組織 slug: your-org-slug
Sentry 專案 slug: your-project
Gitea repo: Gitea 專案網址

步驟 1 - 找 issue:
呼叫 search_issues 找未解決的 error 類型 issue，
一次只查一種類型，不要用 OR / AND 組合查詢：
&lt;span class="p"&gt;
-&lt;/span&gt; "unresolved error issues" (limit 3)
  依事件數排序，取前 3 個。

步驟 2 - 抓細節:
對每個候選 issue 呼叫 get_issue_details，
取得完整 stack trace 與 trace ID。

步驟 3 - 分析根因:
對每個 issue 呼叫 analyze_issue_with_seer。
若 Seer 沒有給出可行的修正建議，
改用步驟 2 拿到的 stack trace 自行分析程式碼、
定位根因所在的檔案與函式。

步驟 4 - 本機修復:
只處理「根因明確、修改範圍小」的 issue（跳過需要
架構調整或影響多個模組的問題，改走步驟 6 的 fallback）。
在本機修改對應程式碼，接著執行專案既有的測試指令，
確認測試全數通過才進入下一步；測試沒過就放棄這個
issue、改走步驟 6。

步驟 5 - 開 PR（Gitea，透過 gitea-mcp）:
a. 呼叫 pull_request_read（method: list, state: open）
檢查 owner/repo 是否已有相同 issue 的開啟中 PR，
有的話跳過，避免重複開單。
b. git checkout -b fix/issue-&lt;span class="nt"&gt;&amp;lt;issue-id&amp;gt;&lt;/span&gt;-&lt;span class="nt"&gt;&amp;lt;date&amp;gt;&lt;/span&gt; main
commit 訊息包含 Sentry issue ID。
git push 到 Gitea。
c. 呼叫 pull_request_write（method: create）：- owner/repo - head: fix/issue-&lt;span class="nt"&gt;&amp;lt;issue-id&amp;gt;&lt;/span&gt;-&lt;span class="nt"&gt;&amp;lt;date&amp;gt;&lt;/span&gt; - base: main - title: "fix: &lt;span class="nt"&gt;&amp;lt;根因摘要&amp;gt;&lt;/span&gt;" - body:
"Sentry issue: &lt;span class="nt"&gt;&amp;lt;issue&lt;/span&gt; &lt;span class="na"&gt;連結&lt;/span&gt;&lt;span class="nt"&gt;&amp;gt;&lt;/span&gt;
Trace ID: &lt;span class="nt"&gt;&amp;lt;trace&lt;/span&gt; &lt;span class="na"&gt;id&lt;/span&gt;&lt;span class="nt"&gt;&amp;gt;&lt;/span&gt;&lt;span class="sb"&gt;

        根因: &amp;lt;Seer 或自行分析的結論&amp;gt;
        修改內容: &amp;lt;變更摘要&amp;gt;
        測試結果: 已跑過既有測試並通過"

&lt;/span&gt;d. 每次執行最多開 2 個 PR，超過就停止並在最後總結說明。

步驟 6 - 無法修復時（fallback）:
若 Seer 與自行分析都無法定位可行修正，或修改範圍過大、
或測試沒通過，改呼叫 issue_write（method: create）
在 Gitea 開一個 issue，內容包含 Sentry issue 連結、
trace ID、已知線索，標記給人工處理，不要硬修。

執行完畢後，用一段文字總結：處理了幾個 issue、開了幾個 PR、
有幾個轉成 fallback issue，並列出每個 PR / issue 的連結。
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;需要替換的是前面幾行的這 3 個：&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;Sentry 組織 slug: your-org-slug
Sentry 專案 slug: your-project
Gitea repo: Gitea 專案網址
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;前 2 個值可以在 Sentry 後台取得。&lt;/p&gt;

&lt;p&gt;第 3 個值就是 Gitea 上的專案取得。&lt;/p&gt;

&lt;p&gt;送出後，Claude Code 會詢問執行的時間，提供後就會建立完成。&lt;/p&gt;

&lt;p&gt;建議是建立完成後，執行一次，看還會遇到什麼問題。&lt;/p&gt;

&lt;p&gt;建立好的排程，會出現在「Routines」裡：&lt;/p&gt;

&lt;p&gt;&lt;a href="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.us-east-2.amazonaws.com%2Fuploads%2Farticles%2Fgij2ckqn11s8rz2n0kfw.png" class="article-body-image-wrapper"&gt;&lt;img src="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.us-east-2.amazonaws.com%2Fuploads%2Farticles%2Fgij2ckqn11s8rz2n0kfw.png" alt="Claude Code 自動排程 Routine 建立成功介面" width="800" height="620"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;Claude Code 自動排程 Routine 建立成功介面&lt;/p&gt;




&lt;h2&gt;
  
  
  進階整合：搭配 CodiumAI PR-Agent 實現 Gitea 自動 Code Review
&lt;/h2&gt;

&lt;p&gt;最後再搭配這篇，就會在有 PR 時自動再做一次 Code Review：&lt;/p&gt;

&lt;p&gt;&lt;a href="https://www.letswrite.tw/gitea-ai-code-review-2/" rel="noopener noreferrer"&gt;CodiumAI PR-Agent，在 Gitea 上用 AI 來 Code Review&lt;/a&gt;&lt;/p&gt;

</description>
      <category>gitea</category>
      <category>sentry</category>
      <category>claude</category>
      <category>mcp</category>
    </item>
    <item>
      <title>公司內部自架 Claude Code Marketplace，讓團隊共用 skill</title>
      <dc:creator>Let's Write</dc:creator>
      <pubDate>Tue, 18 Aug 2026 13:18:47 +0000</pubDate>
      <link>https://dev.to/letswrite/gong-si-nei-bu-zi-jia-claude-code-marketplacerang-tuan-dui-gong-yong-skill-2fg3</link>
      <guid>https://dev.to/letswrite/gong-si-nei-bu-zi-jia-claude-code-marketplacerang-tuan-dui-gong-yong-skill-2fg3</guid>
      <description>&lt;h2&gt;
  
  
  本篇要解決的問題
&lt;/h2&gt;

&lt;p&gt;有些 skill 只適合在公司內部使用，而這個 skill 又想讓其他同事能一起使用的話，就需要一個可以讓大家方便安裝、更新的平台。&lt;/p&gt;

&lt;p&gt;本篇主要筆記，用自架的 Gitea 建立一個內部專用的 Claude Code plugin marketplace，讓團隊裡每個人寫的 skill 不再各自散落在自己電腦裡，而是能集中在一個地方統一發布、安裝、更新版本。&lt;/p&gt;

&lt;p&gt;其他同事只要裝一次就能共用、之後改版也能一起同步拿到最新版。&lt;/p&gt;

&lt;p&gt;這篇整理實作過程中每一個能正確跑通的步驟，讓大家避免在這過程中踩到的坑。&lt;/p&gt;

&lt;p&gt;可用 GitHub、GitLab、Gitea，主要是專案可以有版控就行。&lt;/p&gt;

&lt;p&gt;本篇示範的是在自架的 Gitea 上實作。&lt;/p&gt;




&lt;h2&gt;
  
  
  建立 marketplace 專案結構
&lt;/h2&gt;

&lt;p&gt;Gitea 上新建一個 repo（例如 &lt;code&gt;claude-plugins&lt;/code&gt;），本機目錄結構：&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;claude-plugins/
├── .claude-plugin/
│   └── marketplace.json
└── plugins/
    └── your-plugin-name/
        ├── .claude-plugin/
        │   └── plugin.json
        └── skills/
            └── your-skill/
                └── SKILL.md
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;h2&gt;
  
  
  讓 Claude Code 直接產生 SKILL.md、plugin.json、marketplace.json
&lt;/h2&gt;

&lt;p&gt;看到上面的架構，有一堆的檔案要建立時，不用感到驚慌失措或是害怕。&lt;/p&gt;

&lt;p&gt;因為我們只需要把上面的架構貼給 Claude Code，讓它讀取之前已經寫好的 skill 內容，依照結構把 &lt;code&gt;SKILL.md&lt;/code&gt;、&lt;code&gt;plugin.json&lt;/code&gt;、&lt;code&gt;marketplace.json&lt;/code&gt; 都建出來即可。&lt;/p&gt;

&lt;p&gt;底下附上完整的 &lt;code&gt;marketplace.json&lt;/code&gt; 範例，供對照參考：&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight json"&gt;&lt;code&gt;&lt;span class="p"&gt;{&lt;/span&gt;&lt;span class="w"&gt;
  &lt;/span&gt;&lt;span class="nl"&gt;"name"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="s2"&gt;"claude-plugins"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt;
  &lt;/span&gt;&lt;span class="nl"&gt;"owner"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="p"&gt;{&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="nl"&gt;"name"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="s2"&gt;"August"&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="p"&gt;},&lt;/span&gt;&lt;span class="w"&gt;
  &lt;/span&gt;&lt;span class="nl"&gt;"plugins"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="w"&gt;
    &lt;/span&gt;&lt;span class="p"&gt;{&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="nl"&gt;"name"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="s2"&gt;"ai-tools"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="nl"&gt;"source"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="s2"&gt;"./plugins/ai-tools"&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="p"&gt;},&lt;/span&gt;&lt;span class="w"&gt;
    &lt;/span&gt;&lt;span class="p"&gt;{&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="nl"&gt;"name"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="s2"&gt;"ai-tools2"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="nl"&gt;"source"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="s2"&gt;"./plugins/ai-tools2"&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="p"&gt;}&lt;/span&gt;&lt;span class="w"&gt;
  &lt;/span&gt;&lt;span class="p"&gt;]&lt;/span&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;span class="p"&gt;}&lt;/span&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;ul&gt;
&lt;li&gt;必要欄位：&lt;code&gt;name&lt;/code&gt;（kebab-case，公開可見）、&lt;code&gt;owner&lt;/code&gt;、&lt;code&gt;plugins&lt;/code&gt;。&lt;/li&gt;
&lt;li&gt;每個 plugin entry 至少要有 &lt;code&gt;name&lt;/code&gt; 和 &lt;code&gt;source&lt;/code&gt;。&lt;/li&gt;
&lt;li&gt;若 &lt;code&gt;source&lt;/code&gt; 是同一個 repo 內的相對路徑，要以 &lt;code&gt;./&lt;/code&gt; 開頭，不可用 &lt;code&gt;../&lt;/code&gt; 跳出去。&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;一個 plugin 可以裝多個 skill&lt;/strong&gt;：&lt;code&gt;skills/&lt;/code&gt; 資料夾下每個子資料夾都是獨立一個 skill，不需要每個 skill 各自開一個 plugin。&lt;/li&gt;
&lt;/ul&gt;

&lt;h2&gt;
  
  
  Host 到 Gitea
&lt;/h2&gt;

&lt;p&gt;不限 GitHub，GitLab、Bitbucket、自架伺服器都支援。把整個 &lt;code&gt;claude-plugins&lt;/code&gt; repo push 到 Gitea 即可，不需要額外設定。&lt;/p&gt;

&lt;h2&gt;
  
  
  驗證
&lt;/h2&gt;

&lt;p&gt;claude-plugins 專案上打開終端機，輸入：&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight shell"&gt;&lt;code&gt;claude plugin validate &lt;span class="nb"&gt;.&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;會檢查 JSON schema、重複的 plugin 名稱、路徑穿越等問題。&lt;/p&gt;

&lt;p&gt;檔案寫的有問題，就會看到哪邊寫錯、哪邊建議要寫，再照著回應讓 Claude 繼續做修改即可。&lt;/p&gt;

&lt;h2&gt;
  
  
  本機測試安裝
&lt;/h2&gt;



&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight shell"&gt;&lt;code&gt;/plugin marketplace add ./claude-plugins
/plugin &lt;span class="nb"&gt;install &lt;/span&gt;ai-tools@claude-plugins
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;安裝語法格式固定是 &lt;code&gt;plugin名稱@marketplace名稱&lt;/code&gt;，分別對應 &lt;code&gt;plugin.json&lt;/code&gt; 的 &lt;code&gt;name&lt;/code&gt; 和 &lt;code&gt;marketplace.json&lt;/code&gt; 的 &lt;code&gt;name&lt;/code&gt;。&lt;/p&gt;

&lt;p&gt;有幾個 plugin 就要執行幾次安裝指令。&lt;/p&gt;

&lt;p&gt;要注意的是，這步可以跳過嗎？技術上可以，因為下一步的遠端安裝跟這步沒有依賴關係，直接對 Gitea 網址下指令一樣裝得起來。但跳過等於少了一層「出包前先在本機攔下來」的保護。&lt;/p&gt;

&lt;h2&gt;
  
  
  正式指向 Gitea
&lt;/h2&gt;



&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight shell"&gt;&lt;code&gt;/plugin marketplace add https://gitea.你們公司.internal/team/claude-plugins.git
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;h2&gt;
  
  
  讓團隊自動加入（選用，非必要步驟）
&lt;/h2&gt;

&lt;h3&gt;
  
  
  最直接的方式：手動下指令。
&lt;/h3&gt;

&lt;p&gt;同事不需要碰任何設定檔，兩行指令就能裝好：&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight shell"&gt;&lt;code&gt;/plugin marketplace add https://gitea.你們公司.internal/team/claude-plugins.git
/plugin &lt;span class="nb"&gt;install &lt;/span&gt;ai-tools@claude-plugins
/plugin &lt;span class="nb"&gt;install &lt;/span&gt;ai-tools2@claude-plugins
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;裝完就能直接用，缺點是每次換電腦、換專案，或新同事加入，都要重新打一次這幾行。&lt;/p&gt;

&lt;p&gt;如果不想讓同事記指令、手動輸入，才需要往下看設定檔自動化這條路。&lt;/p&gt;

&lt;h3&gt;
  
  
  進階：讓同事 trust 專案資料夾就自動裝好。
&lt;/h3&gt;

&lt;p&gt;以下的內容，要放在每一個開發中的專案裡的 &lt;code&gt;.claude/settings.json&lt;/code&gt;：&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight json"&gt;&lt;code&gt;&lt;span class="p"&gt;{&lt;/span&gt;&lt;span class="w"&gt;
  &lt;/span&gt;&lt;span class="nl"&gt;"extraKnownMarketplaces"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="p"&gt;{&lt;/span&gt;&lt;span class="w"&gt;
    &lt;/span&gt;&lt;span class="nl"&gt;"claude-plugins"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="p"&gt;{&lt;/span&gt;&lt;span class="w"&gt;
      &lt;/span&gt;&lt;span class="nl"&gt;"source"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="p"&gt;{&lt;/span&gt;&lt;span class="w"&gt;
        &lt;/span&gt;&lt;span class="nl"&gt;"source"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="s2"&gt;"url"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt;
        &lt;/span&gt;&lt;span class="nl"&gt;"url"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="s2"&gt;"https://gitea.你們公司.internal/team/claude-plugins.git"&lt;/span&gt;&lt;span class="w"&gt;
      &lt;/span&gt;&lt;span class="p"&gt;}&lt;/span&gt;&lt;span class="w"&gt;
    &lt;/span&gt;&lt;span class="p"&gt;}&lt;/span&gt;&lt;span class="w"&gt;
  &lt;/span&gt;&lt;span class="p"&gt;},&lt;/span&gt;&lt;span class="w"&gt;
  &lt;/span&gt;&lt;span class="nl"&gt;"enabledPlugins"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="p"&gt;{&lt;/span&gt;&lt;span class="w"&gt;
    &lt;/span&gt;&lt;span class="nl"&gt;"ai-tools@claude-plugins"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="kc"&gt;true&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt;
    &lt;/span&gt;&lt;span class="nl"&gt;"ai-tools2@claude-plugins"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="kc"&gt;true&lt;/span&gt;&lt;span class="w"&gt;
  &lt;/span&gt;&lt;span class="p"&gt;}&lt;/span&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;span class="p"&gt;}&lt;/span&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;ul&gt;
&lt;li&gt;
&lt;code&gt;extraKnownMarketplaces&lt;/code&gt; 只負責自動註冊 marketplace 來源。&lt;/li&gt;
&lt;li&gt;
&lt;code&gt;enabledPlugins&lt;/code&gt; 才是真正讓 plugin 自動裝上並啟用的關鍵，兩者要同時寫，同事 trust 專案資料夾後才會完全不用手動 &lt;code&gt;/plugin install&lt;/code&gt;。&lt;/li&gt;
&lt;li&gt;如果目前還沒有同事需要同步使用，這一步可以先跳過，不影響前面步驟的成果，等有需要再回頭補上即可。&lt;/li&gt;
&lt;/ul&gt;

&lt;h2&gt;
  
  
  Gitea 上有新版本時，同事怎麼更新
&lt;/h2&gt;

&lt;p&gt;如果有發佈新版本，記得 &lt;code&gt;plugin.json&lt;/code&gt; 裡的 &lt;code&gt;version&lt;/code&gt; 要往上加一版，沒改版號的話，其他同事那邊不會被判斷成有更新。&lt;/p&gt;

&lt;p&gt;同事更新分兩步，順序不能反：&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight shell"&gt;&lt;code&gt;/plugin marketplace update claude-plugins
/plugin update ai-tools@claude-plugins
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;第一行只是刷新 marketplace 目錄，讓 Claude Code 知道有新版本存在。&lt;/p&gt;

&lt;p&gt;第二行才是真正把新內容拉下來、覆蓋本機快取。&lt;/p&gt;

&lt;p&gt;也可以用互動面板 &lt;code&gt;/plugin&lt;/code&gt; → 選到該 plugin → &lt;strong&gt;Update now&lt;/strong&gt; 達到一樣效果。&lt;/p&gt;




&lt;h2&gt;
  
  
  參考資料
&lt;/h2&gt;

&lt;ul&gt;
&lt;li&gt;&lt;a href="https://code.claude.com/docs/en/plugin-marketplaces" rel="noopener noreferrer"&gt;Create and distribute a plugin marketplace — Claude Code Docs&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href="https://code.claude.com/docs/en/discover-plugins" rel="noopener noreferrer"&gt;Discover and install prebuilt plugins — Claude Code Docs&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href="https://code.claude.com/docs/en/plugins-reference" rel="noopener noreferrer"&gt;Plugins reference — Claude Code Docs&lt;/a&gt;&lt;/li&gt;
&lt;/ul&gt;

&lt;blockquote&gt;
&lt;p&gt;這篇文章記錄的是目前版本觀察到的行為，Claude Code 的 plugin 系統仍在快速迭代中，實際行為可能隨版本更新而改變，建議操作前對照當下的官方文件再確認一次。&lt;/p&gt;
&lt;/blockquote&gt;

</description>
      <category>claude</category>
      <category>marketplace</category>
      <category>skill</category>
      <category>ai</category>
    </item>
    <item>
      <title>Agency Agents 教學：讓 Claude Code 與 Codex 自動切換 AI 專家角色</title>
      <dc:creator>Let's Write</dc:creator>
      <pubDate>Sat, 15 Aug 2026 01:53:09 +0000</pubDate>
      <link>https://dev.to/letswrite/agency-agents-jiao-xue-rang-claude-code-yu-codex-zi-dong-qie-huan-ai-zhuan-jia-jiao-se-40mc</link>
      <guid>https://dev.to/letswrite/agency-agents-jiao-xue-rang-claude-code-yu-codex-zi-dong-qie-huan-ai-zhuan-jia-jiao-se-40mc</guid>
      <description>&lt;h2&gt;
  
  
  本篇要解決的問題
&lt;/h2&gt;

&lt;p&gt;現在工作上幾乎都用 Claude Code、Codex 來進行開發，只是常常會遇到以下狀況：&lt;/p&gt;

&lt;p&gt;要讓 AI 做 UI，會希望它像 UI 設計師一樣。&lt;/p&gt;

&lt;p&gt;要 Code Review，希望它變成 Code Reviewer。&lt;/p&gt;

&lt;p&gt;下一個專案要處理 Docker，又希望它不要一直卡在前端的事情上。&lt;/p&gt;

&lt;p&gt;雖然我們可以每次都在 Prompt 裡打一大串：&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;你現在是一位資深前端工程師，
熟悉 Vue、React、Accessibility、Core Web Vitals……
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;再雖然我們可以把自己習慣的 Prompt 存起來複製貼上，但基本上人類都是懶惰的，能少打一個字就少打一個字，可以的話最好是 AI 能自己懂現在要扮演什麼樣的專業角色，這就是為什麼貓咪們看到人類都會覺得：&lt;/p&gt;

&lt;p&gt;&lt;a href="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.us-east-2.amazonaws.com%2Fuploads%2Farticles%2Ftavn7e9rla733yqcodsd.jpg" class="article-body-image-wrapper"&gt;&lt;img src="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.us-east-2.amazonaws.com%2Fuploads%2Farticles%2Ftavn7e9rla733yqcodsd.jpg" alt="愚蠢的人類" width="800" height="717"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;最近看到一個 GitHub 專案，發現可以解決上面很愛演的困擾：&lt;a href="https://github.com/msitarzewski/agency-agents" rel="noopener noreferrer"&gt;Agency Agents&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;簡單來說，這專案就是：&lt;/p&gt;

&lt;blockquote&gt;
&lt;p&gt;幫 AI 準備好一大票不同領域的專家角色，需要誰時，就叫誰出來&lt;del&gt;當奴才&lt;/del&gt;工作。&lt;/p&gt;
&lt;/blockquote&gt;

&lt;p&gt;官方目前已經有 230+ 個不同領域的 Agent，而且除了 Claude Code，也支援 Codex、Cursor、GitHub Copilot、Gemini CLI …… 等工具。&lt;/p&gt;

&lt;p&gt;本篇除了筆記 Agency Agents 的安裝方式，也會多做一步：&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;建立一個 Router Skill，讓 Claude Code、Codex 自己判斷這次應該找哪個 Agent。&lt;/strong&gt;&lt;/p&gt;

&lt;p&gt;這樣平常只要正常描述需求：&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;幫我重新設計這個 Dashboard，完成後用 Vue 實作。
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;AI 就可以自己判斷要用 UI Designer，或是 Frontend Developer~~，或是鏟屎的~~。&lt;/p&gt;




&lt;h2&gt;
  
  
  Agency Agents 是什麼？
&lt;/h2&gt;

&lt;p&gt;Agency Agents 不是新的 AI 模型，也不是另一套 Claude Code 或 Codex。&lt;/p&gt;

&lt;p&gt;它比較像是一套「&lt;strong&gt;AI 專家角色設定檔&lt;/strong&gt;」。&lt;/p&gt;

&lt;p&gt;每一個 Agent 裡都已經寫好角色、工作方式、核心任務、交付內容、檢查項目等設定。&lt;/p&gt;

&lt;p&gt;官方對它的定位也是「specialized AI agent personalities」，每個角色除了專業領域之外，還會包含自己的工作流程與交付方式。&lt;/p&gt;

&lt;p&gt;例如 Frontend Developer，就不是只有：&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;You are a Frontend Developer.
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;然後就句點。&lt;/p&gt;

&lt;p&gt;它裡面還會定義前端開發時要注意的東西，例如：&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;Vue / React / Angular
Responsive Web Design
Accessibility
Core Web Vitals
Component architecture
Performance
Testing
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;所以原本我們跟 Codex 說：&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;幫我做這個 Vue 頁面
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;裝完 Agency Agents 後，就可以直接指定要哪個角色，該角色會自動補足我們遺忘的專業度：&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;Use the Frontend Developer agent to implement this Vue page.
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;






&lt;h2&gt;
  
  
  安裝 Agency Agents App
&lt;/h2&gt;

&lt;p&gt;官方做了一套 Agency Agents App，它是 Agency Agents 的管理工具，可以瀏覽有哪些角色，再把 Agent 安裝進我們使用的 Coding Agent。&lt;/p&gt;

&lt;h3&gt;
  
  
  Windows
&lt;/h3&gt;

&lt;p&gt;Windows 建議直接用 Agency Agents App。&lt;/p&gt;

&lt;p&gt;到 Agency Agents App 的 &lt;a href="https://github.com/msitarzewski/agency-agents-app/releases/latest" rel="noopener noreferrer"&gt;GitHub Release&lt;/a&gt; 下載 Windows Installer 後安裝即可。&lt;/p&gt;

&lt;p&gt;目前官方提供 x64 與 ARM64 的 Windows installer；官方也有特別註明 Windows 版本目前尚未 Code Sign，所以如果跳出 Windows SmartScreen，可以從「其他資訊」繼續執行。&lt;/p&gt;

&lt;p&gt;裝完開啟 Agency Agents。&lt;/p&gt;

&lt;p&gt;接著就可以選想使用的 Agent，以及要安裝到哪一套工具。&lt;/p&gt;

&lt;h3&gt;
  
  
  Mac
&lt;/h3&gt;

&lt;p&gt;Mac 可以直接使用 Homebrew：&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight shell"&gt;&lt;code&gt;brew &lt;span class="nb"&gt;install&lt;/span&gt; &lt;span class="nt"&gt;--cask&lt;/span&gt; msitarzewski/agency-agents/agency-agents
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;這也是 Agency Agents 主專案目前提供的快速安裝方式。&lt;/p&gt;

&lt;p&gt;裝完後開啟 Agency Agents App。&lt;/p&gt;

&lt;p&gt;不論是 Windows 還是 Mac，Agency Agents App 的介面都長得相同：&lt;/p&gt;

&lt;p&gt;&lt;a href="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.us-east-2.amazonaws.com%2Fuploads%2Farticles%2Fbbmmy4rsxo88au71r3mv.png" class="article-body-image-wrapper"&gt;&lt;img src="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.us-east-2.amazonaws.com%2Fuploads%2Farticles%2Fbbmmy4rsxo88au71r3mv.png" alt="Agency Agents App 介面" width="800" height="456"&gt;&lt;/a&gt;&lt;/p&gt;




&lt;h2&gt;
  
  
  前端工程師可以先裝哪些 Agent？
&lt;/h2&gt;

&lt;p&gt;Agency Agents 的角色很多，不建議看到什麼就全部裝，最後搞得像寶可夢一樣不全部收集完就睡不著。&lt;/p&gt;

&lt;p&gt;以平常前端開發來說，可以先從這幾個開始：&lt;/p&gt;

&lt;div class="table-wrapper-paragraph"&gt;&lt;table&gt;
&lt;thead&gt;
&lt;tr&gt;
&lt;th&gt;Agent&lt;/th&gt;
&lt;th&gt;適合工作&lt;/th&gt;
&lt;/tr&gt;
&lt;/thead&gt;
&lt;tbody&gt;
&lt;tr&gt;
&lt;td&gt;Frontend Developer&lt;/td&gt;
&lt;td&gt;Vue、React、JavaScript、CSS、RWD&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;UI Designer&lt;/td&gt;
&lt;td&gt;UI、Dashboard、Design System、版面設計&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;UX Researcher&lt;/td&gt;
&lt;td&gt;UX、流程、資訊架構、易用性&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;Software Architect&lt;/td&gt;
&lt;td&gt;系統架構、大型重構&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;Code Reviewer&lt;/td&gt;
&lt;td&gt;PR、Code Review、Bug、Regression&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;Senior Developer&lt;/td&gt;
&lt;td&gt;比較複雜的開發工作&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;DevOps Automator&lt;/td&gt;
&lt;td&gt;Docker、CI/CD、Jenkins、部署&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;Minimal Change Engineer&lt;/td&gt;
&lt;td&gt;修 Bug，而且不要順手就重構整個宇宙&lt;/td&gt;
&lt;/tr&gt;
&lt;/tbody&gt;
&lt;/table&gt;&lt;/div&gt;

&lt;p&gt;安裝角色時，就可以直接選擇要裝在哪些 AI 上：&lt;/p&gt;

&lt;p&gt;&lt;a href="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.us-east-2.amazonaws.com%2Fuploads%2Farticles%2Fk85dob5lb18l74u6rt5o.png" class="article-body-image-wrapper"&gt;&lt;img src="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.us-east-2.amazonaws.com%2Fuploads%2Farticles%2Fk85dob5lb18l74u6rt5o.png" alt="選擇裝在全域的哪個 AI 上" width="800" height="329"&gt;&lt;/a&gt;&lt;/p&gt;




&lt;h2&gt;
  
  
  讓 Claude Code、Codex 自動選 Agent
&lt;/h2&gt;

&lt;p&gt;Agency Agents 官方提供的是「角色」。&lt;/p&gt;

&lt;p&gt;接下來這段則是自己另外加上的功能：&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;Agency Agents Router。&lt;/strong&gt;&lt;/p&gt;

&lt;p&gt;概念很簡單，我們再建立一個 Skill，專門負責判斷以下情境：&lt;/p&gt;

&lt;blockquote&gt;
&lt;p&gt;分析使用者需求 → 需要專家嗎？&lt;br&gt;
需要專家 → 找最適合的 Agency Agent。&lt;br&gt;
不需要專家 → 自己直接做。&lt;/p&gt;
&lt;/blockquote&gt;

&lt;p&gt;就不會看到「Vue」三個字，就一定叫 Frontend Developer。&lt;/p&gt;

&lt;p&gt;所以 Router 要判斷的是：&lt;strong&gt;這個工作有沒有必要使用專家。&lt;/strong&gt;&lt;/p&gt;

&lt;p&gt;例如：&lt;/p&gt;

&lt;p&gt;「把 margin-top 20px 改成 24px」→ 不用 Agent。&lt;/p&gt;

&lt;p&gt;「重新設計整個後台，考慮 RWD 與無障礙」→ 用 Agent。&lt;/p&gt;




&lt;h2&gt;
  
  
  Claude Code、Codex 建立 agency-agents Skill
&lt;/h2&gt;

&lt;p&gt;Claude Code、Codex 的 Skill 放置位置不同。&lt;/p&gt;

&lt;h3&gt;
  
  
  Claude Code
&lt;/h3&gt;

&lt;p&gt;Mac：&lt;/p&gt;

&lt;p&gt;終端機輸入：&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight shell"&gt;&lt;code&gt;open ~/.claude/skills
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Windows：&lt;/p&gt;

&lt;p&gt;開啟任一個資料夾，檔案路徑輸入：&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight batchfile"&gt;&lt;code&gt;&lt;span class="nv"&gt;%USERPROFILE%&lt;/span&gt;\.claude\skills\
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;接著新增以下資料夾跟檔案：&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight yaml"&gt;&lt;code&gt;&lt;span class="s"&gt;agency-agents&lt;/span&gt;
&lt;span class="s"&gt;└── SKILL.md&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;h3&gt;
  
  
  Codex
&lt;/h3&gt;

&lt;p&gt;Mac：&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight shell"&gt;&lt;code&gt;open ~/.agents/skills
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Windows：&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight shell"&gt;&lt;code&gt;%USERPROFILE%&lt;span class="se"&gt;\.&lt;/span&gt;agents&lt;span class="se"&gt;\s&lt;/span&gt;kills&lt;span class="se"&gt;\&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;同樣建立：&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight shell"&gt;&lt;code&gt;agency-agents
└── &lt;span class="o"&gt;[&lt;/span&gt;SKILL.md]&lt;span class="o"&gt;(&lt;/span&gt;http://skill.md/&lt;span class="o"&gt;)&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;接著 SKILL.md 的內容，Claude Code、Codex 有一點不同，可以各自複製貼上。&lt;/p&gt;

&lt;h3&gt;
  
  
  Claude Code
&lt;/h3&gt;

&lt;p&gt;&lt;a href="https://github.com/letswritetw/agency-agents-skill/blob/main/claude/SKILL.md" rel="noopener noreferrer"&gt;https://github.com/letswritetw/agency-agents-skill/blob/main/claude/SKILL.md&lt;/a&gt;&lt;/p&gt;

&lt;h3&gt;
  
  
  Codex
&lt;/h3&gt;

&lt;p&gt;&lt;a href="https://github.com/letswritetw/agency-agents-skill/blob/main/codex/SKILL.md" rel="noopener noreferrer"&gt;https://github.com/letswritetw/agency-agents-skill/blob/main/codex/SKILL.md&lt;/a&gt;&lt;/p&gt;




&lt;h2&gt;
  
  
  讓 Claude Code 自動使用 Router
&lt;/h2&gt;

&lt;p&gt;Skill 建好後其實就可以用了，Claude Code 會依照 description 判斷什麼時候載入。&lt;/p&gt;

&lt;p&gt;不過如果要讓 AI 更積極一點想到 Agency Agents Router，需要再到全域 &lt;code&gt;CLAUDE.md&lt;/code&gt; 補一段規則。&lt;/p&gt;

&lt;p&gt;打開 CLAUDE.md 檔的方式如下。&lt;/p&gt;

&lt;p&gt;Mac：&lt;/p&gt;

&lt;p&gt;終端機輸入：&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight shell"&gt;&lt;code&gt;open ~/.claude/CLAUDE.md
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Windows：&lt;/p&gt;

&lt;p&gt;開啟任一個資料夾，檔案路徑輸入：&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight batchfile"&gt;&lt;code&gt;&lt;span class="nv"&gt;%USERPROFILE%&lt;/span&gt;\.claude\CLAUDE.md
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;在打開的 CLAUDE.md 中加入：&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight markdown"&gt;&lt;code&gt;&lt;span class="gu"&gt;## Agency Agents&lt;/span&gt;

For development tasks that would materially benefit from specialist expertise, use the &lt;span class="sb"&gt;`agency-agents`&lt;/span&gt; skill to select and delegate to the most appropriate installed Agency Agent.

Prefer using the &lt;span class="sb"&gt;`agency-agents`&lt;/span&gt; skill automatically when the current task clearly matches its purpose. The user should not need to explicitly request the skill.

Use the minimum number of agents necessary.

Prefer direct execution for simple or mechanical tasks.

Do not delegate unless specialist expertise is likely to materially improve correctness, design quality, architecture, maintainability, reliability, performance, accessibility, or review quality.

Do not expand the requested scope merely because additional agents are available.

The user's original requirements, constraints, and project conventions always take priority over agent routing.
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;之後平常就不用輸入：&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;Use agency-agents.
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;直接講需求即可。&lt;/p&gt;




&lt;h2&gt;
  
  
  Codex 的 AGENTS.md
&lt;/h2&gt;

&lt;p&gt;Codex 也可以在自己的 &lt;code&gt;AGENTS.md&lt;/code&gt; 補上 Router 使用規則。&lt;/p&gt;

&lt;p&gt;Mac：&lt;/p&gt;

&lt;p&gt;終端機輸入：&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight shell"&gt;&lt;code&gt;open ~/.codex/AGENTS.md
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Windows：&lt;/p&gt;

&lt;p&gt;開啟任一個資料夾，檔案路徑輸入：&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight batchfile"&gt;&lt;code&gt;&lt;span class="nv"&gt;%USERPROFILE%&lt;/span&gt;\.codex\AGENTS.md
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;在打開的 AGENTS.md 中加入：&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight markdown"&gt;&lt;code&gt;&lt;span class="c"&gt;&amp;lt;!-- AGENCY_AGENTS_START --&amp;gt;&lt;/span&gt;

&lt;span class="gu"&gt;## Agency Agents&lt;/span&gt;

For software development tasks that would materially benefit from specialist expertise, use the &lt;span class="sb"&gt;`agency-agents`&lt;/span&gt; skill to select and delegate to the most appropriate installed custom agent.

When the current task clearly matches the &lt;span class="sb"&gt;`agency-agents`&lt;/span&gt; skill description, prefer implicit invocation instead of requiring the user to explicitly request &lt;span class="sb"&gt;`$agency-agents`&lt;/span&gt;.

Use the minimum number of agents necessary.

Prefer direct execution for simple or mechanical tasks.

Do not delegate unless specialist expertise is likely to materially improve correctness, design quality, architecture, maintainability, reliability, performance, accessibility, or review quality.

For tasks spanning multiple disciplines, let the &lt;span class="sb"&gt;`agency-agents`&lt;/span&gt; skill determine whether sequential delegation is useful.

Do not expand the requested scope merely because additional agents are available.

The user's original requirements, constraints, project conventions, and requested scope remain the source of truth.

&lt;span class="c"&gt;&amp;lt;!-- AGENCY_AGENTS_END --&amp;gt;&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;






&lt;h2&gt;
  
  
  總結
&lt;/h2&gt;

&lt;p&gt;Agency Agents 裡面有一堆角色可以使用，目前 August 還在實驗中，看是不是在開發上會產生更精緻的結果。&lt;/p&gt;

&lt;p&gt;記得幾年前 ChatGPT 剛出來時，網路上有很多人在分享怎麼寫 Prompt，很多開頭的第一句都是寫「請你扮演 XXX」。&lt;/p&gt;

&lt;p&gt;這件事情現在已經不用了，因為已經可以讓 AI 自己選擇適合的角色來扮演。&lt;/p&gt;

&lt;p&gt;這個 Agency Agents 專案目前有 143k 的星星數，看來懶惰的人類是很多的（誤），只好再放一次貓咪怎麼看我們人類的圖：&lt;/p&gt;

&lt;p&gt;&lt;a href="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.us-east-2.amazonaws.com%2Fuploads%2Farticles%2Ftavn7e9rla733yqcodsd.jpg" class="article-body-image-wrapper"&gt;&lt;img src="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.us-east-2.amazonaws.com%2Fuploads%2Farticles%2Ftavn7e9rla733yqcodsd.jpg" alt="愚蠢的人類" width="800" height="717"&gt;&lt;/a&gt;&lt;/p&gt;

</description>
      <category>claude</category>
      <category>chatgpt</category>
      <category>ai</category>
      <category>agents</category>
    </item>
    <item>
      <title>Buzz 自架教學：使用 Docker 架設 Relay 與設定 AI Agent 自動回覆</title>
      <dc:creator>Let's Write</dc:creator>
      <pubDate>Fri, 31 Jul 2026 14:38:33 +0000</pubDate>
      <link>https://dev.to/letswrite/buzz-zi-jia-jiao-xue-shi-yong-docker-jia-she-relay-yu-she-ding-ai-agent-zi-dong-hui-fu-2b09</link>
      <guid>https://dev.to/letswrite/buzz-zi-jia-jiao-xue-shi-yong-docker-jia-she-relay-yu-she-ding-ai-agent-zi-dong-hui-fu-2b09</guid>
      <description>&lt;h2&gt;
  
  
  寫在文章之前，關於本文配圖
&lt;/h2&gt;

&lt;p&gt;這篇文章的配圖，選擇了熊本城，是因為這周發生了熊本大地震，而 August 在今年的五月才去那裡旅遊過。&lt;/p&gt;

&lt;p&gt;記得在逛熊本城的時候，裡面有個影片，是在講十年前的熊本大地震發生後，這幾年一路是怎麼走過來，一路又修復成目前的樣子。&lt;/p&gt;

&lt;p&gt;雖然，這次又發生了地震，但相信熊本可以再站起來的。&lt;/p&gt;




&lt;h2&gt;
  
  
  本篇要解決的問題
&lt;/h2&gt;

&lt;p&gt;最近一直在找一個可以把 AI Agent 一起加入到群組聊天的通訊軟體。&lt;/p&gt;

&lt;p&gt;大部份都要錢，比如 Slack、Google Chat、Teams。&lt;/p&gt;

&lt;p&gt;剛好不知怎麼回事，最近也常常看到講 AI 的電子報提到一個 Buzz，似乎可以解決這需求。&lt;/p&gt;

&lt;p&gt;Buzz，是一套可自架的團隊協作工具。除了頻道聊天，也能加入 Codex、Claude Code 等 AI Agent，讓團隊成員直接在頻道中透過 tag Agent 來呼叫 AI。&lt;/p&gt;

&lt;p&gt;雖說官方提供了 Self Hosting 的安裝說明，但實際上還是踩了幾個坑才順利的讓 Agent 回覆訊息。&lt;/p&gt;

&lt;p&gt;本篇就是筆記實作安裝 Buzz 時的筆記，也把怎麼跳過這些坑的方式紀錄下來，讓看到這篇的你可以從從容容、遊刃有餘的閃過。&lt;/p&gt;

&lt;p&gt;完成本文後，可以做到：&lt;/p&gt;

&lt;ol&gt;
&lt;li&gt;在 Mac 上透過 Docker Compose 自架 Buzz Relay。&lt;/li&gt;
&lt;li&gt;使用 Buzz Desktop 連接自己的 Relay。&lt;/li&gt;
&lt;li&gt;建立 Buzz Community 與頻道。&lt;/li&gt;
&lt;li&gt;啟動內建的三個 Agent。&lt;/li&gt;
&lt;li&gt;使用 Codex 作為 Fizz 的 AI 執行環境。（也可以用 Claude）&lt;/li&gt;
&lt;li&gt;在頻道中透過 &lt;code&gt;@Fizz&lt;/code&gt; 讓 Agent 回覆訊息。&lt;/li&gt;
&lt;/ol&gt;




&lt;h2&gt;
  
  
  安裝 Buzz Relay
&lt;/h2&gt;

&lt;h3&gt;
  
  
  1. 安裝必要工具
&lt;/h3&gt;

&lt;p&gt;需要先安裝好以下：&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;Git&lt;/li&gt;
&lt;li&gt;Docker Desktop&lt;/li&gt;
&lt;li&gt;Docker Compose 2.24.4 以上&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;確認 Docker Desktop 已經啟動後，再繼續安裝。&lt;/p&gt;

&lt;h3&gt;
  
  
  2. 下載 Buzz 原始碼
&lt;/h3&gt;

&lt;p&gt;Clone 官方 GitHub 上的專案：&lt;a href="https://github.com/block/buzz" rel="noopener noreferrer"&gt;https://github.com/block/buzz&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;接著進到「deploy/compose」資料夾中，本篇會用 Docker 的方式安裝。&lt;/p&gt;

&lt;h3&gt;
  
  
  3. 建立 &lt;code&gt;.env&lt;/code&gt;
&lt;/h3&gt;

&lt;p&gt;deploy/compose 的資料夾裡有一個「.env.example」，這份檔另存為「.env」。&lt;/p&gt;

&lt;p&gt;接著，把 .env 裡「buzz.example.com」、「CHANGE_ME…」的部份全都修改，變成我們要的內容。&lt;/p&gt;

&lt;p&gt;另外要注意，目前官方的版本有個 bug，主要是Buzz Relay 容器會顯示 &lt;code&gt;unhealthy&lt;/code&gt;，造成後續安裝不起來，目前解決的方式就是：&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight shell"&gt;&lt;code&gt;&lt;span class="c"&gt;# 原本&lt;/span&gt;
&lt;span class="nv"&gt;BUZZ_GIT_CONFORMANCE_PROBE&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="nb"&gt;true&lt;/span&gt;

&lt;span class="c"&gt;# 改成&lt;/span&gt;
&lt;span class="nv"&gt;BUZZ_GIT_CONFORMANCE_PROBE&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="nb"&gt;false&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;需要 KEY 的部份，可以使用以下指令產生隨機密鑰：&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight shell"&gt;&lt;code&gt;openssl rand &lt;span class="nt"&gt;-hex&lt;/span&gt; 32
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;產生一般密碼：&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight shell"&gt;&lt;code&gt;openssl rand &lt;span class="nt"&gt;-base64&lt;/span&gt; 24
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;不同用途的密鑰應分開產生，不要全部使用同一組。&lt;/p&gt;

&lt;p&gt;如果覺得一行行修改很麻煩，這一步 ChatGPT 有給了一組指令，直接專案內開啟終端機執行以下也行：&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight shell"&gt;&lt;code&gt;&lt;span class="nb"&gt;cat&lt;/span&gt; &lt;span class="o"&gt;&amp;gt;&lt;/span&gt; .env &lt;span class="o"&gt;&amp;lt;&amp;lt;&lt;/span&gt;&lt;span class="no"&gt;EOF&lt;/span&gt;&lt;span class="sh"&gt;
BUZZ_IMAGE=ghcr.io/block/buzz:main

BUZZ_DOMAIN=127.0.0.1
RELAY_URL=ws://127.0.0.1:3300

BUZZ_MEDIA_BASE_URL=http://127.0.0.1:3300/media
BUZZ_MEDIA_SERVER_DOMAIN=127.0.0.1

BUZZ_CORS_ORIGINS=tauri://localhost,http://tauri.localhost,https://tauri.localhost,http://127.0.0.1:3300

BUZZ_REQUIRE_AUTH_TOKEN=false
BUZZ_REQUIRE_RELAY_MEMBERSHIP=false
BUZZ_ALLOW_NIP_OA_AUTH=false

BUZZ_AUTO_MIGRATE=true
BUZZ_GIT_CONFORMANCE_PROBE=false

RUST_LOG=buzz_relay=info,buzz_db=info,buzz_auth=info,buzz_pubsub=info,tower_http=info

BUZZ_RELAY_PRIVATE_KEY=&lt;/span&gt;&lt;span class="si"&gt;$(&lt;/span&gt;openssl rand &lt;span class="nt"&gt;-hex&lt;/span&gt; 32&lt;span class="si"&gt;)&lt;/span&gt;&lt;span class="sh"&gt;
BUZZ_GIT_HOOK_HMAC_SECRET=&lt;/span&gt;&lt;span class="si"&gt;$(&lt;/span&gt;openssl rand &lt;span class="nt"&gt;-hex&lt;/span&gt; 32&lt;span class="si"&gt;)&lt;/span&gt;&lt;span class="sh"&gt;

POSTGRES_DB=buzz
POSTGRES_USER=buzz
POSTGRES_PASSWORD=&lt;/span&gt;&lt;span class="si"&gt;$(&lt;/span&gt;openssl rand &lt;span class="nt"&gt;-hex&lt;/span&gt; 16&lt;span class="si"&gt;)&lt;/span&gt;&lt;span class="sh"&gt;

REDIS_PASSWORD=&lt;/span&gt;&lt;span class="si"&gt;$(&lt;/span&gt;openssl rand &lt;span class="nt"&gt;-hex&lt;/span&gt; 16&lt;span class="si"&gt;)&lt;/span&gt;&lt;span class="sh"&gt;

BUZZ_S3_ACCESS_KEY=&lt;/span&gt;&lt;span class="si"&gt;$(&lt;/span&gt;openssl rand &lt;span class="nt"&gt;-hex&lt;/span&gt; 10&lt;span class="si"&gt;)&lt;/span&gt;&lt;span class="sh"&gt;
BUZZ_S3_SECRET_KEY=&lt;/span&gt;&lt;span class="si"&gt;$(&lt;/span&gt;openssl rand &lt;span class="nt"&gt;-hex&lt;/span&gt; 16&lt;span class="si"&gt;)&lt;/span&gt;&lt;span class="sh"&gt;
BUZZ_S3_BUCKET=buzz-media
BUZZ_S3_ADDRESSING_STYLE=path

BUZZ_HTTP_PORT=3300
&lt;/span&gt;&lt;span class="no"&gt;EOF
&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;因為 3000 是個很多應用程式都會預設使用的 PORT，所以上面的範例改用 3300。&lt;/p&gt;

&lt;h3&gt;
  
  
  4. 啟動 Buzz Relay
&lt;/h3&gt;

&lt;p&gt;專案中開啟終端機，依序執行以下：&lt;/p&gt;

&lt;p&gt;加入執行權限：&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight shell"&gt;&lt;code&gt;&lt;span class="nb"&gt;chmod&lt;/span&gt; +x run.sh
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;啟動：&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight shell"&gt;&lt;code&gt;./run.sh start
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;查看狀態：&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight shell"&gt;&lt;code&gt;./run.sh status
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;正常情況下會看到：&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;relay       healthy
postgres    healthy
redis       healthy
minio       healthy
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;






&lt;h3&gt;
  
  
  5. 測試 Relay
&lt;/h3&gt;

&lt;p&gt;打開瀏覽器，網址貼上：&lt;a href="http://127.0.0.1:3300%E3%80%82" rel="noopener noreferrer"&gt;http://127.0.0.1:3300。&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;成功的話就會看到結果：&lt;/p&gt;

&lt;p&gt;&lt;a href="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.us-east-2.amazonaws.com%2Fuploads%2Farticles%2Fs22q0rbzx9qcdlym7i08.png" class="article-body-image-wrapper"&gt;&lt;img src="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.us-east-2.amazonaws.com%2Fuploads%2Farticles%2Fs22q0rbzx9qcdlym7i08.png" alt="Buzz Relay Docker 部署成功畫面與 JSON 網頁回傳結果" width="800" height="459"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;順便推薦一下本站開發的擴充功能 &lt;a href="https://chromewebstore.google.com/detail/lets-json/gcbgdeakiaapdhjeoinmodehiemedimf" rel="noopener noreferrer"&gt;Let’s JSON&lt;/a&gt;，網址如果回傳的是 JSON，就會看到像上面截圖那樣美美的樣子。&lt;/p&gt;

&lt;p&gt;Buzz Relay 安裝成功，剩下的事就是讓各個要使用的團隊成員電腦安裝 Buzz，然後設定抓我們自架的 Buzz Relay 了。&lt;/p&gt;




&lt;h2&gt;
  
  
  下載、安裝 Buzz
&lt;/h2&gt;

&lt;h3&gt;
  
  
  1. 下載 Buzz Desktop
&lt;/h3&gt;

&lt;p&gt;前往 Buzz Releases：&lt;/p&gt;

&lt;p&gt;&lt;a href="https://github.com/block/buzz/releases" rel="noopener noreferrer"&gt;https://github.com/block/buzz/releases&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;Apple Silicon Mac，例如 M1、M2、M3、M4，下載名稱包含以下文字的版本：&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;aarch64
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Intel Mac 則下載：&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;x64
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Windows 下載：&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight shell"&gt;&lt;code&gt;Buzz_0.5.2_x64-setup_alpha-unsigned.exe
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;但因為 Windows 版本的 Buzz 目前尚未完成數位簽章，開啟時系統會跳出安全性警告；此時可點擊「更多資訊」並選擇「仍要執行」（或於檔案屬性中勾選「取消封鎖」）即可完成安裝。&lt;/p&gt;

&lt;h3&gt;
  
  
  2. 登入 Buzz
&lt;/h3&gt;

&lt;p&gt;安裝完 Buzz，打開後會遇到幾個項目，因為 Relay 我們是自架的，因此以下選項要這樣選擇。&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;Join or create a community&lt;/strong&gt;：選擇「I already have a community」。&lt;/p&gt;

&lt;p&gt;&lt;a href="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.us-east-2.amazonaws.com%2Fuploads%2Farticles%2Fxitsu5lrk2k9j0g7gxkm.png" class="article-body-image-wrapper"&gt;&lt;img src="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.us-east-2.amazonaws.com%2Fuploads%2Farticles%2Fxitsu5lrk2k9j0g7gxkm.png" alt="Buzz 桌面端建立 Community 選擇畫面：I already have a community" width="800" height="834"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;Reconnect to your community&lt;/strong&gt;：選擇「I’m a member or admin」。&lt;/p&gt;

&lt;p&gt;&lt;a href="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.us-east-2.amazonaws.com%2Fuploads%2Farticles%2Fitsidygh7sap9lue7ez7.png" class="article-body-image-wrapper"&gt;&lt;img src="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.us-east-2.amazonaws.com%2Fuploads%2Farticles%2Fitsidygh7sap9lue7ez7.png" alt="Buzz 桌面端身份選擇：I am a member or admin" width="800" height="614"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;接著會需要輸入我們 Buzz Relay 的網址，之前的 .env 裡寫的是 &lt;a href="http://127.0.0.1:3300%EF%BC%8C%E9%80%99%E9%82%8A%E5%B0%B1%E7%85%A7%E5%A1%AB%EF%BC%8C%E5%A6%82%E6%9E%9C%E4%B8%8A%E9%9D%A2%E4%BD%A0%E6%9C%89%E8%87%AA%E8%A1%8C%E4%BF%AE%E6%94%B9%E7%9A%84%E8%A9%B1%EF%BC%8C%E9%80%99%E9%82%8A%E5%B0%B1%E5%A1%AB%E5%AF%AB%E4%BD%A0%E4%BF%AE%E6%94%B9%E7%9A%84%E3%80%82" rel="noopener noreferrer"&gt;http://127.0.0.1:3300，這邊就照填，如果上面你有自行修改的話，這邊就填寫你修改的。&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;&lt;a href="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.us-east-2.amazonaws.com%2Fuploads%2Farticles%2Fmqgdlmlqs6dj2dmcx1cg.png" class="article-body-image-wrapper"&gt;&lt;img src="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.us-east-2.amazonaws.com%2Fuploads%2Farticles%2Fmqgdlmlqs6dj2dmcx1cg.png" alt="輸入安裝 Buzz Relay 時填的網址" width="800" height="541"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;以上，就可以進到我們自架的 Buzz 了。&lt;/p&gt;




&lt;h2&gt;
  
  
  使用 AI Agents 功能
&lt;/h2&gt;

&lt;p&gt;這段就是 August 一直踩坑的部份，只要下列幾個坑都閃過，之後在對話框裡 @ AI Agents 就會得到回應。&lt;/p&gt;

&lt;h3&gt;
  
  
  確認有使用 AI
&lt;/h3&gt;

&lt;p&gt;本機確定有安裝好 Claude CLI，或 Codex CLI。&lt;/p&gt;

&lt;p&gt;如果沒有訂閱這兩家方案，也可以找網路上提供有免費額度的 LLM 來使用。&lt;/p&gt;

&lt;p&gt;August 因為 Claude、ChatGPT 都有付費訂閱，所以示範的是這兩家的。&lt;/p&gt;

&lt;p&gt;在 Buzz 的設定頁裡，要確認有使用 AI，如圖：&lt;/p&gt;

&lt;p&gt;&lt;a href="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.us-east-2.amazonaws.com%2Fuploads%2Farticles%2F2f1eldko9dytoiurqtj7.png" class="article-body-image-wrapper"&gt;&lt;img src="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.us-east-2.amazonaws.com%2Fuploads%2Farticles%2F2f1eldko9dytoiurqtj7.png" alt="Buzz 系統設定：確認 AI Agent 狀態為 Ready" width="800" height="626"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;顯示為「Ready」代表有連結成功。&lt;/p&gt;

&lt;p&gt;Buzz Agent 指的是用各家的 API。&lt;/p&gt;

&lt;h3&gt;
  
  
  確認 Community 網址相同
&lt;/h3&gt;

&lt;p&gt;點擊左下角自己的帳號，接著「Local Dev &amp;gt; Community settings」：&lt;/p&gt;

&lt;p&gt;&lt;a href="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.us-east-2.amazonaws.com%2Fuploads%2Farticles%2Fnzmjh3ovd12xq9usyisf.png" class="article-body-image-wrapper"&gt;&lt;img src="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.us-east-2.amazonaws.com%2Fuploads%2Farticles%2Fnzmjh3ovd12xq9usyisf.png" alt="Buzz 設定選單：進入 Community settings 社群設定" width="800" height="371"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;裡面會看到一個設定是「Relay URL」：&lt;/p&gt;

&lt;p&gt;&lt;a href="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.us-east-2.amazonaws.com%2Fuploads%2Farticles%2Fjidicbwuykfwk5q44mcr.png" class="article-body-image-wrapper"&gt;&lt;img src="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.us-east-2.amazonaws.com%2Fuploads%2Farticles%2Fjidicbwuykfwk5q44mcr.png" alt="確認 Relay URL 跟本機網址相同" width="800" height="1118"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;要確認 URL 裡，&lt;code&gt;ws://&lt;/code&gt; 後的網址，跟我們的網址是相同的，比方上面在設定 Community 的網址是 &lt;a href="http://127.0.0.1:3300%EF%BC%8C%E9%82%A3%E9%80%99%E9%82%8A" rel="noopener noreferrer"&gt;http://127.0.0.1:3300，那這邊&lt;/a&gt; &lt;code&gt;ws://&lt;/code&gt; 後就要是 127.0.0.1:3300。&lt;/p&gt;

&lt;p&gt;這邊如果不相同，那 Agents 收到的來源就會不同，就會一直抓不到我們 @ 它們的訊息。&lt;/p&gt;

&lt;h3&gt;
  
  
  開放 Agents 接受回應
&lt;/h3&gt;

&lt;p&gt;在 Agent 的設定畫面裡，點擊「Advanced」，裡面有一項「Who can talk to this agent」，要選成「Anyone」：&lt;/p&gt;

&lt;p&gt;&lt;a href="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.us-east-2.amazonaws.com%2Fuploads%2Farticles%2Fvazedip9tj3y2f6zbxn4.png" class="article-body-image-wrapper"&gt;&lt;img src="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.us-east-2.amazonaws.com%2Fuploads%2Farticles%2Fvazedip9tj3y2f6zbxn4.png" alt="Buzz AI Agent 進階設定：將 Who can talk to this agent 權限設為 Anyone" width="800" height="1052"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;然後，上面的頁籤切到「Customize for this agent」，確認有選好要使用的模型：&lt;/p&gt;

&lt;p&gt;&lt;a href="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.us-east-2.amazonaws.com%2Fuploads%2Farticles%2Fbqelel4q3qpapmtbqkjq.png" class="article-body-image-wrapper"&gt;&lt;img src="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.us-east-2.amazonaws.com%2Fuploads%2Farticles%2Fbqelel4q3qpapmtbqkjq.png" alt="Buzz Agent 模型配置：選擇對應的 LLM Model" width="800" height="536"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;最後，要確認 Agents 是運行中的：&lt;/p&gt;

&lt;p&gt;&lt;a href="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.us-east-2.amazonaws.com%2Fuploads%2Farticles%2Fgp987uakwrltnrv3l6q2.png" class="article-body-image-wrapper"&gt;&lt;img src="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.us-east-2.amazonaws.com%2Fuploads%2Farticles%2Fgp987uakwrltnrv3l6q2.png" alt="Buzz 頻道控制列：確認 AI Agent 處於 Running 運行狀態" width="800" height="582"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;h2&gt;
  
  
  實際測試
&lt;/h2&gt;

&lt;p&gt;可以做一個簡單的測試，看 AI Agents 是不是會回應。&lt;/p&gt;

&lt;p&gt;我們在預設建好的 Channel 裡，@ Agent 就行，就像我們在 LINE 上 @ 朋友們一樣。&lt;/p&gt;

&lt;p&gt;成功的話，就會看到被 @ 的 Agent 正在思考中的訊息，也會對訊息回應 Emoji，思考完成，Agent 就會回覆訊息，如下圖：&lt;/p&gt;

&lt;p&gt;&lt;a href="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.us-east-2.amazonaws.com%2Fuploads%2Farticles%2Fvnjzftuudl4d6u8eni6o.jpeg" class="article-body-image-wrapper"&gt;&lt;img src="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.us-east-2.amazonaws.com%2Fuploads%2Farticles%2Fvnjzftuudl4d6u8eni6o.jpeg" alt="Buzz 頻道實際測試：@Fizz 呼叫 AI Agent 並獲得自動回覆訊息" width="800" height="483"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;h2&gt;
  
  
  小結
&lt;/h2&gt;

&lt;p&gt;雖然可以把 AI Agents 加進聊天中，但 Windows 版的安裝比較麻煩。&lt;/p&gt;

&lt;p&gt;而且，Codex、Claude Code 上都裝了很多習慣的 Skills，表面上 AI 是回說可以直接用，但輸入 &lt;code&gt;/&lt;/code&gt; 或 &lt;code&gt;$&lt;/code&gt; 時沒有出現選項，也不知道到底有用 Skills 還是沒有。&lt;/p&gt;

&lt;p&gt;只能說，Buzz 還是一個正在開發中的工具，看 GitHub 上的 Release 紀錄更新得很頻繁，再給它一點時間，它會更好的（？）。&lt;/p&gt;

</description>
      <category>buzz</category>
      <category>docker</category>
      <category>claude</category>
      <category>agents</category>
    </item>
    <item>
      <title>Outline Wiki 自架教學（三）：Codex 串接 MCP</title>
      <dc:creator>Let's Write</dc:creator>
      <pubDate>Fri, 24 Jul 2026 13:44:02 +0000</pubDate>
      <link>https://dev.to/letswrite/outline-wiki-zi-jia-jiao-xue-san-codex-chuan-jie-mcp-5c4b</link>
      <guid>https://dev.to/letswrite/outline-wiki-zi-jia-jiao-xue-san-codex-chuan-jie-mcp-5c4b</guid>
      <description>&lt;h2&gt;
  
  
  本篇要解決的問題
&lt;/h2&gt;

&lt;p&gt;上一篇是 &lt;a href="https://www.letswrite.tw/outline-claude-mcp/" rel="noopener noreferrer"&gt;Outline + Claude&lt;/a&gt;，不一定每個人都有訂閱 Claude 方案，所以也提供 Codex 的方式。&lt;/p&gt;

&lt;p&gt;跟著本篇一步步走，完成設定後，Codex 可以透過 MCP 呼叫 Outline 工具，執行很多好棒棒的事，例如：&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;搜尋或列出 Outline 文件&lt;/li&gt;
&lt;li&gt;讀取、編輯文件集內的文件&lt;/li&gt;
&lt;li&gt;建立文件集&lt;/li&gt;
&lt;li&gt;移動文件&lt;/li&gt;
&lt;li&gt;執行 MCP Server 已提供的其他 Outline 操作&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;Codex App、Codex CLI 與 IDE 擴充套件會共用 Codex 的 MCP 設定，因此設定完成後，不需要在每個客戶端重複設定。&lt;/p&gt;




&lt;h2&gt;
  
  
  前置準備
&lt;/h2&gt;

&lt;p&gt;開始前，請先確認已具備以下環境：&lt;/p&gt;

&lt;ol&gt;
&lt;li&gt;安裝 &lt;a href="https://chatgpt.com/download/" rel="noopener noreferrer"&gt;Codex&lt;/a&gt;
&lt;/li&gt;
&lt;li&gt;安裝 &lt;a href="https://nodejs.org/zh-tw/download" rel="noopener noreferrer"&gt;Node.js&lt;/a&gt;
&lt;/li&gt;
&lt;li&gt;可正常連線的 &lt;a href="https://www.letswrite.tw/outline-wiki-install/" rel="noopener noreferrer"&gt;Outline&lt;/a&gt;
&lt;/li&gt;
&lt;/ol&gt;




&lt;h2&gt;
  
  
  建立 Outline API Token
&lt;/h2&gt;

&lt;h3&gt;
  
  
  進入喜好設定
&lt;/h3&gt;

&lt;p&gt;登入 Outline 後，點擊左下角帳號旁的「⋯」，再選擇「喜好設定」。&lt;/p&gt;

&lt;p&gt;&lt;a href="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.us-east-2.amazonaws.com%2Fuploads%2Farticles%2Fkmrw46lqu1goihbjhfu6.png" class="article-body-image-wrapper"&gt;&lt;img src="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.us-east-2.amazonaws.com%2Fuploads%2Farticles%2Fkmrw46lqu1goihbjhfu6.png" alt="從左下角選單進入喜好設定"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;h3&gt;
  
  
  開啟 API &amp;amp; Access
&lt;/h3&gt;

&lt;p&gt;在左側設定選單中選擇「API &amp;amp; Access」，接著點擊右上角的「新 API 金鑰」。&lt;/p&gt;

&lt;p&gt;&lt;a href="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.us-east-2.amazonaws.com%2Fuploads%2Farticles%2Fbdrrx9bhqgd4ytn13fus.png" class="article-body-image-wrapper"&gt;&lt;img src="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.us-east-2.amazonaws.com%2Fuploads%2Farticles%2Fbdrrx9bhqgd4ytn13fus.png" alt="進入 API &amp;amp; Access 並建立新 API 金鑰"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;h3&gt;
  
  
  設定金鑰名稱、範圍與到期日
&lt;/h3&gt;

&lt;p&gt;建議輸入容易辨識用途的名稱，例如：「AI MCP」、「Codex MCP」等等。&lt;/p&gt;

&lt;p&gt;原始流程中的設定為：&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;
&lt;strong&gt;範圍：&lt;/strong&gt; 留空&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;到期日：&lt;/strong&gt; 沒有期限&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;&lt;a href="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.us-east-2.amazonaws.com%2Fuploads%2Farticles%2F678ptivgzmstlca5rksq.png" class="article-body-image-wrapper"&gt;&lt;img src="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.us-east-2.amazonaws.com%2Fuploads%2Farticles%2F678ptivgzmstlca5rksq.png" alt="設定 API 金鑰範圍與到期日"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;範圍留空通常代表不限制特定 API 權限。這種設定操作最簡單，但權限也較大。&lt;/p&gt;

&lt;h3&gt;
  
  
  複製 API Token
&lt;/h3&gt;

&lt;p&gt;建立完成後，點擊「複製」，並先將 Token 暫存在安全的位置，因為 Token 只會出現一次。&lt;/p&gt;

&lt;p&gt;&lt;a href="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.us-east-2.amazonaws.com%2Fuploads%2Farticles%2Fbvkirz2pqrugh1lu8g94.png" class="article-body-image-wrapper"&gt;&lt;img src="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.us-east-2.amazonaws.com%2Fuploads%2Farticles%2Fbvkirz2pqrugh1lu8g94.png" alt="複製 Outline API Token"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;注意：API Token 等同於帳號憑證，不要貼到 Git、公開文件、部落格文章、聊天群組或未加密的筆記中。&lt;/p&gt;




&lt;h2&gt;
  
  
  設定 Codex MCP
&lt;/h2&gt;

&lt;h3&gt;
  
  
  開啟 Codex 設定檔
&lt;/h3&gt;

&lt;p&gt;Codex 使用 &lt;code&gt;config.toml&lt;/code&gt; 儲存 MCP 與其他本機設定。&lt;/p&gt;

&lt;div class="table-wrapper-paragraph"&gt;&lt;table&gt;
&lt;thead&gt;
&lt;tr&gt;
&lt;th&gt;作業系統&lt;/th&gt;
&lt;th&gt;使用者層級設定檔路徑&lt;/th&gt;
&lt;/tr&gt;
&lt;/thead&gt;
&lt;tbody&gt;
&lt;tr&gt;
&lt;td&gt;Windows&lt;/td&gt;
&lt;td&gt;&lt;code&gt;%USERPROFILE%\.codex\config.toml&lt;/code&gt;&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;macOS&lt;/td&gt;
&lt;td&gt;&lt;code&gt;~/.codex/config.toml&lt;/code&gt;&lt;/td&gt;
&lt;/tr&gt;
&lt;/tbody&gt;
&lt;/table&gt;&lt;/div&gt;

&lt;p&gt;使用者層級的設定會套用到 Codex App、Codex CLI 與 IDE 擴充套件。&lt;/p&gt;

&lt;h4&gt;
  
  
  Windows
&lt;/h4&gt;

&lt;p&gt;開啟 PowerShell，執行：&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight powershell"&gt;&lt;code&gt;&lt;span class="n"&gt;New-Item&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="nt"&gt;-ItemType&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="nx"&gt;Directory&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="nt"&gt;-Force&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="s2"&gt;"&lt;/span&gt;&lt;span class="nv"&gt;$&lt;/span&gt;&lt;span class="nn"&gt;env&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="nv"&gt;USERPROFILE&lt;/span&gt;&lt;span class="s2"&gt;\.codex"&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="o"&gt;|&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;Out-Null&lt;/span&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;span class="nx"&gt;New-Item&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="nt"&gt;-ItemType&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="nx"&gt;File&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="nt"&gt;-Force&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="s2"&gt;"&lt;/span&gt;&lt;span class="nv"&gt;$&lt;/span&gt;&lt;span class="nn"&gt;env&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="nv"&gt;USERPROFILE&lt;/span&gt;&lt;span class="s2"&gt;\.codex\config.toml"&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="o"&gt;|&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;Out-Null&lt;/span&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;span class="nx"&gt;notepad&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="s2"&gt;"&lt;/span&gt;&lt;span class="nv"&gt;$&lt;/span&gt;&lt;span class="nn"&gt;env&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="nv"&gt;USERPROFILE&lt;/span&gt;&lt;span class="s2"&gt;\.codex\config.toml"&lt;/span&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;這三個指令會依序：&lt;/p&gt;

&lt;ol&gt;
&lt;li&gt;建立 &lt;code&gt;.codex&lt;/code&gt; 資料夾。&lt;/li&gt;
&lt;li&gt;建立 &lt;code&gt;config.toml&lt;/code&gt;。&lt;/li&gt;
&lt;li&gt;使用記事本開啟設定檔。&lt;/li&gt;
&lt;/ol&gt;

&lt;p&gt;也可以開啟任一個資料夾，在檔案路徑列貼上：&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight shell"&gt;&lt;code&gt;%USERPROFILE%&lt;span class="se"&gt;\.&lt;/span&gt;codex
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;接著開啟 &lt;code&gt;config.toml&lt;/code&gt;。&lt;/p&gt;

&lt;h4&gt;
  
  
  macOS：使用 Finder 開啟
&lt;/h4&gt;

&lt;ol&gt;
&lt;li&gt;開啟 Finder。&lt;/li&gt;
&lt;li&gt;點擊上方選單的「前往」。&lt;/li&gt;
&lt;li&gt;選擇「前往檔案夾⋯」。&lt;/li&gt;
&lt;li&gt;貼上下列路徑：
&lt;/li&gt;
&lt;/ol&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight shell"&gt;&lt;code&gt;~/.codex/
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;ol&gt;
&lt;li&gt;找到並開啟：
&lt;/li&gt;
&lt;/ol&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight toml"&gt;&lt;code&gt;&lt;span class="err"&gt;config.toml&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;h4&gt;
  
  
  macOS：使用終端機開啟
&lt;/h4&gt;

&lt;p&gt;也可以在終端機執行：&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight shell"&gt;&lt;code&gt;&lt;span class="nb"&gt;mkdir&lt;/span&gt; &lt;span class="nt"&gt;-p&lt;/span&gt; &lt;span class="s2"&gt;"&lt;/span&gt;&lt;span class="nv"&gt;$HOME&lt;/span&gt;&lt;span class="s2"&gt;/.codex"&lt;/span&gt;
&lt;span class="nb"&gt;touch&lt;/span&gt; &lt;span class="s2"&gt;"&lt;/span&gt;&lt;span class="nv"&gt;$HOME&lt;/span&gt;&lt;span class="s2"&gt;/.codex/config.toml"&lt;/span&gt;
open &lt;span class="nt"&gt;-e&lt;/span&gt; &lt;span class="s2"&gt;"&lt;/span&gt;&lt;span class="nv"&gt;$HOME&lt;/span&gt;&lt;span class="s2"&gt;/.codex/config.toml"&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;這三個指令會依序建立設定資料夾、建立設定檔，並使用 macOS 文字編輯器開啟。&lt;/p&gt;

&lt;p&gt;若檔案已存在，建議先複製一份備份，再進行修改。&lt;/p&gt;




&lt;h2&gt;
  
  
  加入 Outline MCP Server
&lt;/h2&gt;

&lt;p&gt;請將下列設定加入 &lt;code&gt;config.toml&lt;/code&gt;：&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight toml"&gt;&lt;code&gt;&lt;span class="nn"&gt;[mcp_servers.outline]&lt;/span&gt;
&lt;span class="py"&gt;command&lt;/span&gt; &lt;span class="p"&gt;=&lt;/span&gt; &lt;span class="s"&gt;"npx"&lt;/span&gt;
&lt;span class="py"&gt;args&lt;/span&gt; &lt;span class="p"&gt;=&lt;/span&gt; &lt;span class="p"&gt;[&lt;/span&gt;
  &lt;span class="s"&gt;"-y"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
  &lt;span class="s"&gt;"mcp-remote"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
  &lt;span class="s"&gt;"https://192.168.x.x:3023/mcp"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
  &lt;span class="s"&gt;"--header"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
  &lt;span class="s"&gt;"Authorization:${AUTH_HEADER}"&lt;/span&gt;
&lt;span class="p"&gt;]&lt;/span&gt;

&lt;span class="nn"&gt;[mcp_servers.outline.env]&lt;/span&gt;
&lt;span class="py"&gt;AUTH_HEADER&lt;/span&gt; &lt;span class="p"&gt;=&lt;/span&gt; &lt;span class="s"&gt;"Bearer YOUR_OUTLINE_API_TOKEN"&lt;/span&gt;
&lt;span class="py"&gt;NODE_TLS_REJECT_UNAUTHORIZED&lt;/span&gt; &lt;span class="p"&gt;=&lt;/span&gt; &lt;span class="s"&gt;"0"&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;請替換以下內容：&lt;/p&gt;

&lt;div class="table-wrapper-paragraph"&gt;&lt;table&gt;
&lt;thead&gt;
&lt;tr&gt;
&lt;th&gt;設定值&lt;/th&gt;
&lt;th&gt;說明&lt;/th&gt;
&lt;/tr&gt;
&lt;/thead&gt;
&lt;tbody&gt;
&lt;tr&gt;
&lt;td&gt;&lt;code&gt;https://192.168.x.x:3023/mcp&lt;/code&gt;&lt;/td&gt;
&lt;td&gt;Outline MCP Server 的連線網址&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;&lt;code&gt;YOUR_OUTLINE_API_TOKEN&lt;/code&gt;&lt;/td&gt;
&lt;td&gt;前一步建立的 Outline API Token&lt;/td&gt;
&lt;/tr&gt;
&lt;/tbody&gt;
&lt;/table&gt;&lt;/div&gt;




&lt;h2&gt;
  
  
  使用有效 HTTPS 憑證時的簡化設定
&lt;/h2&gt;

&lt;p&gt;如果 Outline MCP Server 已使用有效且受信任的 HTTPS 憑證，Codex 可以直接連線，不需要 Node.js、&lt;code&gt;npx&lt;/code&gt; 或 &lt;code&gt;mcp-remote&lt;/code&gt;。&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight toml"&gt;&lt;code&gt;&lt;span class="nn"&gt;[mcp_servers.outline]&lt;/span&gt;
&lt;span class="py"&gt;url&lt;/span&gt; &lt;span class="p"&gt;=&lt;/span&gt; &lt;span class="s"&gt;"https://YOUR_MCP_HOST/mcp"&lt;/span&gt;
&lt;span class="py"&gt;http_headers&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt; &lt;span class="py"&gt;Authorization&lt;/span&gt; &lt;span class="p"&gt;=&lt;/span&gt; &lt;span class="s"&gt;"Bearer YOUR_OUTLINE_API_TOKEN"&lt;/span&gt; &lt;span class="p"&gt;}&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;例如：&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight toml"&gt;&lt;code&gt;&lt;span class="nn"&gt;[mcp_servers.outline]&lt;/span&gt;
&lt;span class="py"&gt;url&lt;/span&gt; &lt;span class="p"&gt;=&lt;/span&gt; &lt;span class="s"&gt;"https://outline-mcp.example.com/mcp"&lt;/span&gt;
&lt;span class="py"&gt;http_headers&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt; &lt;span class="py"&gt;Authorization&lt;/span&gt; &lt;span class="p"&gt;=&lt;/span&gt; &lt;span class="s"&gt;"Bearer YOUR_OUTLINE_API_TOKEN"&lt;/span&gt; &lt;span class="p"&gt;}&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;這是較簡單的正式環境設定方式。&lt;/p&gt;

&lt;p&gt;注意：這個範例會把 Token 直接寫在 &lt;code&gt;config.toml&lt;/code&gt; 中。請妥善保護設定檔，不要提交到 Git。&lt;/p&gt;




&lt;h2&gt;
  
  
  Windows 與 macOS 的 npx 路徑問題
&lt;/h2&gt;

&lt;p&gt;Codex App 原則上可以直接執行 &lt;code&gt;npx&lt;/code&gt;。&lt;/p&gt;

&lt;p&gt;若 MCP 啟動失敗，可能是桌面程式找不到 &lt;code&gt;npx&lt;/code&gt; 的執行路徑。&lt;/p&gt;

&lt;h3&gt;
  
  
  Windows
&lt;/h3&gt;

&lt;p&gt;在 PowerShell 執行：&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight powershell"&gt;&lt;code&gt;&lt;span class="n"&gt;where.exe&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="nx"&gt;npx&lt;/span&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;可能會回傳：&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight batchfile"&gt;&lt;code&gt;&lt;span class="kd"&gt;C&lt;/span&gt;:\Program &lt;span class="kd"&gt;Files&lt;/span&gt;\nodejs\npx.cmd
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;可以將：&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight toml"&gt;&lt;code&gt;&lt;span class="py"&gt;command&lt;/span&gt; &lt;span class="p"&gt;=&lt;/span&gt; &lt;span class="s"&gt;"npx"&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;改成 TOML 的單引號字串：&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight toml"&gt;&lt;code&gt;&lt;span class="py"&gt;command&lt;/span&gt; &lt;span class="p"&gt;=&lt;/span&gt; &lt;span class="s"&gt;'C:\Program Files\nodejs\npx.cmd'&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;TOML 的單引號字串不需要將 Windows 反斜線寫成 &lt;code&gt;\\&lt;/code&gt;。&lt;/p&gt;

&lt;h3&gt;
  
  
  macOS
&lt;/h3&gt;

&lt;p&gt;在終端機執行：&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight shell"&gt;&lt;code&gt;which npx
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Apple Silicon Mac 使用 Homebrew 時，可能回傳：&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight shell"&gt;&lt;code&gt;/opt/homebrew/bin/npx
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Intel Mac 使用 Homebrew 時，可能回傳：&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight shell"&gt;&lt;code&gt;/usr/local/bin/npx
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;接著將：&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight toml"&gt;&lt;code&gt;&lt;span class="py"&gt;command&lt;/span&gt; &lt;span class="p"&gt;=&lt;/span&gt; &lt;span class="s"&gt;"npx"&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;改成實際查到的完整路徑，例如：&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight toml"&gt;&lt;code&gt;&lt;span class="py"&gt;command&lt;/span&gt; &lt;span class="p"&gt;=&lt;/span&gt; &lt;span class="s"&gt;"/opt/homebrew/bin/npx"&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;注意：不要直接照抄範例路徑，應先使用 &lt;code&gt;where.exe npx&lt;/code&gt; 或 &lt;code&gt;which npx&lt;/code&gt;，再填入自己電腦實際回傳的結果。&lt;/p&gt;




&lt;h2&gt;
  
  
  重新啟動 Codex
&lt;/h2&gt;

&lt;p&gt;修改 &lt;code&gt;config.toml&lt;/code&gt; 後，需要重新啟動正在使用的 Codex。&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;
&lt;strong&gt;Codex App／ChatGPT 桌面版：&lt;/strong&gt; 完整結束後重新開啟。&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Codex CLI：&lt;/strong&gt; 離開目前工作階段，再重新執行 &lt;code&gt;codex&lt;/code&gt;。&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;IDE 擴充套件：&lt;/strong&gt; 重新啟動擴充套件或重新載入編輯器視窗。&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;只關閉視窗不一定代表程式已完全結束：&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;
&lt;strong&gt;Windows：&lt;/strong&gt; 從系統匣結束程式，或到工作管理員確認是否仍在背景執行。&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;macOS：&lt;/strong&gt; 按下 &lt;code&gt;Command + Q&lt;/code&gt;，必要時到「活動監視器」確認程式是否仍在執行。&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;重新啟動時，Codex 會：&lt;/p&gt;

&lt;ol&gt;
&lt;li&gt;讀取 &lt;code&gt;~/.codex/config.toml&lt;/code&gt;
&lt;/li&gt;
&lt;li&gt;透過 &lt;code&gt;npx&lt;/code&gt; 啟動 &lt;code&gt;mcp-remote&lt;/code&gt;
&lt;/li&gt;
&lt;li&gt;使用 Authorization Header 連接 Outline MCP Server&lt;/li&gt;
&lt;li&gt;載入 MCP Server 提供的工具&lt;/li&gt;
&lt;/ol&gt;

&lt;p&gt;首次執行 &lt;code&gt;npx -y mcp-remote&lt;/code&gt; 時，可能需要下載套件，因此等待時間會比後續啟動稍長。&lt;/p&gt;




&lt;h2&gt;
  
  
  測試 Outline MCP 是否連線成功
&lt;/h2&gt;

&lt;h3&gt;
  
  
  使用 Codex CLI 檢查
&lt;/h3&gt;

&lt;p&gt;先執行：&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight shell"&gt;&lt;code&gt;codex mcp list
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;正常情況下，清單中會出現：&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;outline
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;也可以執行：&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight shell"&gt;&lt;code&gt;codex mcp &lt;span class="nt"&gt;--help&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;查看目前版本支援的 MCP 管理指令。&lt;/p&gt;

&lt;p&gt;進入 Codex CLI 後，輸入：&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight shell"&gt;&lt;code&gt;/mcp
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;即可查看目前工作階段載入的 MCP Server 與工具。&lt;/p&gt;

&lt;h3&gt;
  
  
  使用對話測試
&lt;/h3&gt;

&lt;p&gt;在 Codex 中輸入：&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;可以接到 Outline MCP 嗎？請列出目前可使用的 Outline 工具。
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;接著再測試實際讀取：&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;請列出 Outline 中目前可以看到的文件與文件集。
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;也可以指定操作：&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;請搜尋 Outline 中包含「前端」關鍵字的文件。
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;連線成功時，Codex 會顯示已載入 Outline 工具，並能回傳工作區中的文件或 Collection 資訊。&lt;/p&gt;

</description>
      <category>outline</category>
      <category>ai</category>
      <category>codex</category>
      <category>mcp</category>
    </item>
    <item>
      <title>Outline Wiki 自架教學（二）：ClaudeCodex 串接 MCP</title>
      <dc:creator>Let's Write</dc:creator>
      <pubDate>Fri, 24 Jul 2026 13:07:20 +0000</pubDate>
      <link>https://dev.to/letswrite/outline-wiki-zi-jia-jiao-xue-er-claude-codex-chuan-jie-mcp-42k4</link>
      <guid>https://dev.to/letswrite/outline-wiki-zi-jia-jiao-xue-er-claude-codex-chuan-jie-mcp-42k4</guid>
      <description>&lt;h1&gt;
  
  
  Outline Wiki 自架教學（二）：Claude 串接 MCP
&lt;/h1&gt;

&lt;h2&gt;
  
  
  本篇要解決的問題
&lt;/h2&gt;

&lt;p&gt;上一篇我們自架了 &lt;a href="https://www.letswrite.tw/outline-wiki-install/" rel="noopener noreferrer"&gt;Outline Wiki&lt;/a&gt;，接著我們就要發揮它的威力了，就是可以使用 MCP，讓 Claude、Codex 來幫我們新增、編輯、彙整……我們的文件。&lt;/p&gt;

&lt;p&gt;本篇主要是寫 Outline + Claude，下一篇會是 Outline + Codex。&lt;/p&gt;

&lt;p&gt;照著本篇實作，完成設定後，Claude Desktop 可以透過 MCP 呼叫 Outline 工具，例如：&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;搜尋或列出 Outline 文件&lt;/li&gt;
&lt;li&gt;讀取、編輯文件集內的文件&lt;/li&gt;
&lt;li&gt;建立文件集&lt;/li&gt;
&lt;li&gt;移動文件&lt;/li&gt;
&lt;li&gt;執行 MCP Server 已提供的其他 Outline 操作&lt;/li&gt;
&lt;/ul&gt;




&lt;h2&gt;
  
  
  前置準備
&lt;/h2&gt;

&lt;p&gt;開始前，請先確認已具備以下環境：&lt;/p&gt;

&lt;ol&gt;
&lt;li&gt;安裝 &lt;a href="https://claude.com/download" rel="noopener noreferrer"&gt;Claude Desktop&lt;/a&gt;
&lt;/li&gt;
&lt;li&gt;安裝 &lt;a href="https://nodejs.org/zh-tw/download" rel="noopener noreferrer"&gt;Node.js&lt;/a&gt;
&lt;/li&gt;
&lt;li&gt;可正常連線的 &lt;a href="https://www.letswrite.tw/outline-wiki-install/" rel="noopener noreferrer"&gt;Outline&lt;/a&gt;
&lt;/li&gt;
&lt;/ol&gt;




&lt;h2&gt;
  
  
  建立 Outline API Token
&lt;/h2&gt;

&lt;h3&gt;
  
  
  進入喜好設定
&lt;/h3&gt;

&lt;p&gt;登入 Outline 後，點擊左下角帳號旁的「⋯」，再選擇「喜好設定」。&lt;/p&gt;

&lt;p&gt;&lt;a href="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.us-east-2.amazonaws.com%2Fuploads%2Farticles%2Fkmrw46lqu1goihbjhfu6.png" class="article-body-image-wrapper"&gt;&lt;img src="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.us-east-2.amazonaws.com%2Fuploads%2Farticles%2Fkmrw46lqu1goihbjhfu6.png" alt="從左下角選單進入喜好設定"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;從左下角選單進入喜好設定&lt;/p&gt;

&lt;h3&gt;
  
  
  開啟 API &amp;amp; Access
&lt;/h3&gt;

&lt;p&gt;在左側設定選單中選擇「API &amp;amp; Access」，接著點擊右上角的「新 API 金鑰」。&lt;/p&gt;

&lt;p&gt;&lt;a href="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.us-east-2.amazonaws.com%2Fuploads%2Farticles%2Fbdrrx9bhqgd4ytn13fus.png" class="article-body-image-wrapper"&gt;&lt;img src="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.us-east-2.amazonaws.com%2Fuploads%2Farticles%2Fbdrrx9bhqgd4ytn13fus.png" alt="進入 API &amp;amp; Access 並建立新 API 金鑰"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;進入 API &amp;amp; Access 並建立新 API 金鑰&lt;/p&gt;

&lt;h3&gt;
  
  
  設定金鑰名稱、範圍與到期日
&lt;/h3&gt;

&lt;p&gt;建議輸入容易辨識用途的名稱，例如：「AI MCP」、「Claude MCP」等等。&lt;/p&gt;

&lt;p&gt;原始流程中的設定為：&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;
&lt;strong&gt;範圍：&lt;/strong&gt; 留空&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;到期日：&lt;/strong&gt; 沒有期限&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;&lt;a href="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.us-east-2.amazonaws.com%2Fuploads%2Farticles%2F678ptivgzmstlca5rksq.png" class="article-body-image-wrapper"&gt;&lt;img src="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.us-east-2.amazonaws.com%2Fuploads%2Farticles%2F678ptivgzmstlca5rksq.png" alt="設定 API 金鑰範圍與到期日"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;設定 API 金鑰範圍與到期日&lt;/p&gt;

&lt;p&gt;範圍留空通常代表不限制特定 API 權限。這種設定操作最簡單，但權限也較大。&lt;/p&gt;

&lt;h3&gt;
  
  
  複製 API Token
&lt;/h3&gt;

&lt;p&gt;建立完成後，點擊「複製」，並先將 Token 暫存在安全的位置，因為 Token 只會出現一次。&lt;/p&gt;

&lt;p&gt;&lt;a href="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.us-east-2.amazonaws.com%2Fuploads%2Farticles%2Fbvkirz2pqrugh1lu8g94.png" class="article-body-image-wrapper"&gt;&lt;img src="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.us-east-2.amazonaws.com%2Fuploads%2Farticles%2Fbvkirz2pqrugh1lu8g94.png" alt="複製 Outline API Token"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;複製 Outline API Token&lt;/p&gt;

&lt;p&gt;注意：API Token 等同於帳號憑證，不要貼到 Git、公開文件、部落格文章、聊天群組或未加密的筆記中。&lt;/p&gt;




&lt;h2&gt;
  
  
  設定 Claude Desktop MCP
&lt;/h2&gt;

&lt;h3&gt;
  
  
  開啟 Claude Desktop 設定檔
&lt;/h3&gt;

&lt;p&gt;Claude Desktop 在 Windows 與 macOS 使用相同的設定檔名稱，但存放路徑不同。&lt;/p&gt;

&lt;div class="table-wrapper-paragraph"&gt;&lt;table&gt;
&lt;thead&gt;
&lt;tr&gt;
&lt;th&gt;作業系統&lt;/th&gt;
&lt;th&gt;設定檔路徑&lt;/th&gt;
&lt;/tr&gt;
&lt;/thead&gt;
&lt;tbody&gt;
&lt;tr&gt;
&lt;td&gt;Windows&lt;/td&gt;
&lt;td&gt;&lt;code&gt;%APPDATA%\Claude\claude_desktop_config.json&lt;/code&gt;&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;macOS&lt;/td&gt;
&lt;td&gt;&lt;code&gt;~/Library/Application Support/Claude/claude_desktop_config.json&lt;/code&gt;&lt;/td&gt;
&lt;/tr&gt;
&lt;/tbody&gt;
&lt;/table&gt;&lt;/div&gt;

&lt;h4&gt;
  
  
  Windows
&lt;/h4&gt;

&lt;p&gt;開啟任一個資料夾，檔案路徑列貼上：&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight batchfile"&gt;&lt;code&gt;&lt;span class="nv"&gt;%APPDATA%&lt;/span&gt;\Claude\claude_desktop_config.json
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;也可以按下 &lt;code&gt;Win + R&lt;/code&gt;，貼上相同路徑後按 Enter。&lt;/p&gt;

&lt;h4&gt;
  
  
  macOS：使用 Finder 開啟
&lt;/h4&gt;

&lt;ol&gt;
&lt;li&gt;開啟 Finder。&lt;/li&gt;
&lt;li&gt;點擊上方選單的「前往」。&lt;/li&gt;
&lt;li&gt;選擇「前往檔案夾⋯」。&lt;/li&gt;
&lt;li&gt;貼上下列路徑：
&lt;/li&gt;
&lt;/ol&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight shell"&gt;&lt;code&gt;~/Library/Application Support/Claude/
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;ol&gt;
&lt;li&gt;找到並開啟：
&lt;/li&gt;
&lt;/ol&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight json"&gt;&lt;code&gt;&lt;span class="err"&gt;claude_desktop_config.json&lt;/span&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;h4&gt;
  
  
  macOS：使用終端機開啟
&lt;/h4&gt;

&lt;p&gt;也可以在終端機執行：&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight shell"&gt;&lt;code&gt;&lt;span class="nb"&gt;mkdir&lt;/span&gt; &lt;span class="nt"&gt;-p&lt;/span&gt; &lt;span class="s2"&gt;"&lt;/span&gt;&lt;span class="nv"&gt;$HOME&lt;/span&gt;&lt;span class="s2"&gt;/Library/Application Support/Claude"&lt;/span&gt;
&lt;span class="nb"&gt;touch&lt;/span&gt; &lt;span class="s2"&gt;"&lt;/span&gt;&lt;span class="nv"&gt;$HOME&lt;/span&gt;&lt;span class="s2"&gt;/Library/Application Support/Claude/claude_desktop_config.json"&lt;/span&gt;
open &lt;span class="nt"&gt;-e&lt;/span&gt; &lt;span class="s2"&gt;"&lt;/span&gt;&lt;span class="nv"&gt;$HOME&lt;/span&gt;&lt;span class="s2"&gt;/Library/Application Support/Claude/claude_desktop_config.json"&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;這三個指令會依序建立設定資料夾、建立設定檔，並使用 macOS 文字編輯器開啟。&lt;/p&gt;

&lt;p&gt;若檔案已存在，建議先複製一份備份，再進行修改。&lt;/p&gt;

&lt;h3&gt;
  
  
  加入 Outline MCP Server
&lt;/h3&gt;

&lt;p&gt;請將下列設定加入 JSON 最外層物件中的 &lt;code&gt;mcpServers&lt;/code&gt;：&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight json"&gt;&lt;code&gt;&lt;span class="p"&gt;{&lt;/span&gt;&lt;span class="w"&gt;
  &lt;/span&gt;&lt;span class="nl"&gt;"mcpServers"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="p"&gt;{&lt;/span&gt;&lt;span class="w"&gt;
    &lt;/span&gt;&lt;span class="nl"&gt;"outline"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="p"&gt;{&lt;/span&gt;&lt;span class="w"&gt;
      &lt;/span&gt;&lt;span class="nl"&gt;"command"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="s2"&gt;"npx"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt;
      &lt;/span&gt;&lt;span class="nl"&gt;"args"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="w"&gt;
        &lt;/span&gt;&lt;span class="s2"&gt;"-y"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt;
        &lt;/span&gt;&lt;span class="s2"&gt;"mcp-remote"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt;
        &lt;/span&gt;&lt;span class="s2"&gt;"https://192.168.x.x:3023/mcp"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt;
        &lt;/span&gt;&lt;span class="s2"&gt;"--header"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt;
        &lt;/span&gt;&lt;span class="s2"&gt;"Authorization:${AUTH_HEADER}"&lt;/span&gt;&lt;span class="w"&gt;
      &lt;/span&gt;&lt;span class="p"&gt;],&lt;/span&gt;&lt;span class="w"&gt;
      &lt;/span&gt;&lt;span class="nl"&gt;"env"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="p"&gt;{&lt;/span&gt;&lt;span class="w"&gt;
        &lt;/span&gt;&lt;span class="nl"&gt;"AUTH_HEADER"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="s2"&gt;"Bearer YOUR_OUTLINE_API_TOKEN"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt;
        &lt;/span&gt;&lt;span class="nl"&gt;"NODE_TLS_REJECT_UNAUTHORIZED"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="s2"&gt;"0"&lt;/span&gt;&lt;span class="w"&gt;
      &lt;/span&gt;&lt;span class="p"&gt;}&lt;/span&gt;&lt;span class="w"&gt;
    &lt;/span&gt;&lt;span class="p"&gt;}&lt;/span&gt;&lt;span class="w"&gt;
  &lt;/span&gt;&lt;span class="p"&gt;}&lt;/span&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;span class="p"&gt;}&lt;/span&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;blockquote&gt;
&lt;p&gt;&lt;code&gt;NODE_TLS_REJECT_UNAUTHORIZED=0&lt;/code&gt; 會停用 Node.js 的 TLS 憑證驗證。它只適合在可信任的內部網路中暫時測試，不建議用於公開網路或正式環境。較安全的做法是替 MCP Server 設定可被系統信任的有效憑證。&lt;/p&gt;
&lt;/blockquote&gt;

&lt;p&gt;Windows 與 macOS 原則上可共用這份設定。如果 macOS 無法直接找到 &lt;code&gt;npx&lt;/code&gt;，可以先在終端機執行：&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight shell"&gt;&lt;code&gt;which npx
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;假設回傳：&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight shell"&gt;&lt;code&gt;/opt/homebrew/bin/npx
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;便可將 &lt;code&gt;command&lt;/code&gt; 改成完整路徑：&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight json"&gt;&lt;code&gt;&lt;span class="nl"&gt;"command"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="s2"&gt;"/opt/homebrew/bin/npx"&lt;/span&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;常見位置如下：&lt;/p&gt;

&lt;div class="table-wrapper-paragraph"&gt;&lt;table&gt;
&lt;thead&gt;
&lt;tr&gt;
&lt;th&gt;安裝方式&lt;/th&gt;
&lt;th&gt;
&lt;code&gt;npx&lt;/code&gt; 可能的位置&lt;/th&gt;
&lt;/tr&gt;
&lt;/thead&gt;
&lt;tbody&gt;
&lt;tr&gt;
&lt;td&gt;Apple Silicon Mac 使用 Homebrew&lt;/td&gt;
&lt;td&gt;&lt;code&gt;/opt/homebrew/bin/npx&lt;/code&gt;&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;Intel Mac 使用 Homebrew&lt;/td&gt;
&lt;td&gt;&lt;code&gt;/usr/local/bin/npx&lt;/code&gt;&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;Node.js 官方 &lt;code&gt;.pkg&lt;/code&gt;
&lt;/td&gt;
&lt;td&gt;以 &lt;code&gt;which npx&lt;/code&gt; 的回傳結果為準&lt;/td&gt;
&lt;/tr&gt;
&lt;/tbody&gt;
&lt;/table&gt;&lt;/div&gt;

&lt;p&gt;注意：不要直接照抄表格中的路徑。應先執行 &lt;code&gt;which npx&lt;/code&gt;，再使用自己電腦實際回傳的結果。&lt;/p&gt;

&lt;p&gt;請替換以下內容：&lt;/p&gt;

&lt;div class="table-wrapper-paragraph"&gt;&lt;table&gt;
&lt;thead&gt;
&lt;tr&gt;
&lt;th&gt;設定值&lt;/th&gt;
&lt;th&gt;說明&lt;/th&gt;
&lt;/tr&gt;
&lt;/thead&gt;
&lt;tbody&gt;
&lt;tr&gt;
&lt;td&gt;&lt;code&gt;https://YOUR_MCP_HOST/mcp&lt;/code&gt;&lt;/td&gt;
&lt;td&gt;Outline MCP Server 的連線網址&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;&lt;code&gt;YOUR_OUTLINE_API_TOKEN&lt;/code&gt;&lt;/td&gt;
&lt;td&gt;前一步建立的 Outline API Token&lt;/td&gt;
&lt;/tr&gt;
&lt;/tbody&gt;
&lt;/table&gt;&lt;/div&gt;

&lt;p&gt;例如 MCP Server 位於內部網路，可改成：&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight json"&gt;&lt;code&gt;&lt;span class="s2"&gt;"https://192.168.x.x:3023/mcp"&lt;/span&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;h3&gt;
  
  
  合併既有設定時的注意事項
&lt;/h3&gt;

&lt;p&gt;若 &lt;code&gt;claude_desktop_config.json&lt;/code&gt; 已經有其他設定，不要直接覆蓋整份檔案，只需要把 &lt;code&gt;mcpServers&lt;/code&gt; 合併進最外層物件。&lt;/p&gt;

&lt;h4&gt;
  
  
  Windows 設定範例
&lt;/h4&gt;

&lt;p&gt;例如原本已有其他欄位：&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight json"&gt;&lt;code&gt;&lt;span class="p"&gt;{&lt;/span&gt;&lt;span class="w"&gt;
  &lt;/span&gt;&lt;span class="nl"&gt;"coworkUserFilesPath"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="s2"&gt;"C:&lt;/span&gt;&lt;span class="se"&gt;\\&lt;/span&gt;&lt;span class="s2"&gt;Users&lt;/span&gt;&lt;span class="se"&gt;\\&lt;/span&gt;&lt;span class="s2"&gt;Sean&lt;/span&gt;&lt;span class="se"&gt;\\&lt;/span&gt;&lt;span class="s2"&gt;Claude"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt;
  &lt;/span&gt;&lt;span class="nl"&gt;"preferences"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="p"&gt;{},&lt;/span&gt;&lt;span class="w"&gt;
  &lt;/span&gt;&lt;span class="nl"&gt;"mcpServers"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="p"&gt;{&lt;/span&gt;&lt;span class="w"&gt;
    &lt;/span&gt;&lt;span class="nl"&gt;"outline"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="p"&gt;{&lt;/span&gt;&lt;span class="w"&gt;
      &lt;/span&gt;&lt;span class="nl"&gt;"command"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="s2"&gt;"npx"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt;
      &lt;/span&gt;&lt;span class="nl"&gt;"args"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="w"&gt;
        &lt;/span&gt;&lt;span class="s2"&gt;"-y"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt;
        &lt;/span&gt;&lt;span class="s2"&gt;"mcp-remote"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt;
        &lt;/span&gt;&lt;span class="s2"&gt;"https://YOUR_MCP_HOST/mcp"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt;
        &lt;/span&gt;&lt;span class="s2"&gt;"--header"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt;
        &lt;/span&gt;&lt;span class="s2"&gt;"Authorization:${AUTH_HEADER}"&lt;/span&gt;&lt;span class="w"&gt;
      &lt;/span&gt;&lt;span class="p"&gt;],&lt;/span&gt;&lt;span class="w"&gt;
      &lt;/span&gt;&lt;span class="nl"&gt;"env"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="p"&gt;{&lt;/span&gt;&lt;span class="w"&gt;
        &lt;/span&gt;&lt;span class="nl"&gt;"AUTH_HEADER"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="s2"&gt;"Bearer YOUR_OUTLINE_API_TOKEN"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt;
        &lt;/span&gt;&lt;span class="nl"&gt;"NODE_TLS_REJECT_UNAUTHORIZED"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="s2"&gt;"0"&lt;/span&gt;&lt;span class="w"&gt;
      &lt;/span&gt;&lt;span class="p"&gt;}&lt;/span&gt;&lt;span class="w"&gt;
    &lt;/span&gt;&lt;span class="p"&gt;}&lt;/span&gt;&lt;span class="w"&gt;
  &lt;/span&gt;&lt;span class="p"&gt;}&lt;/span&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;span class="p"&gt;}&lt;/span&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;h4&gt;
  
  
  macOS 設定範例
&lt;/h4&gt;

&lt;p&gt;macOS 也使用相同的 JSON 結構。若 &lt;code&gt;npx&lt;/code&gt; 可直接執行：&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight json"&gt;&lt;code&gt;&lt;span class="p"&gt;{&lt;/span&gt;&lt;span class="w"&gt;
  &lt;/span&gt;&lt;span class="nl"&gt;"preferences"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="p"&gt;{},&lt;/span&gt;&lt;span class="w"&gt;
  &lt;/span&gt;&lt;span class="nl"&gt;"mcpServers"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="p"&gt;{&lt;/span&gt;&lt;span class="w"&gt;
    &lt;/span&gt;&lt;span class="nl"&gt;"outline"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="p"&gt;{&lt;/span&gt;&lt;span class="w"&gt;
      &lt;/span&gt;&lt;span class="nl"&gt;"command"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="s2"&gt;"npx"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt;
      &lt;/span&gt;&lt;span class="nl"&gt;"args"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="w"&gt;
        &lt;/span&gt;&lt;span class="s2"&gt;"-y"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt;
        &lt;/span&gt;&lt;span class="s2"&gt;"mcp-remote"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt;
        &lt;/span&gt;&lt;span class="s2"&gt;"https://YOUR_MCP_HOST/mcp"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt;
        &lt;/span&gt;&lt;span class="s2"&gt;"--header"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt;
        &lt;/span&gt;&lt;span class="s2"&gt;"Authorization:${AUTH_HEADER}"&lt;/span&gt;&lt;span class="w"&gt;
      &lt;/span&gt;&lt;span class="p"&gt;],&lt;/span&gt;&lt;span class="w"&gt;
      &lt;/span&gt;&lt;span class="nl"&gt;"env"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="p"&gt;{&lt;/span&gt;&lt;span class="w"&gt;
        &lt;/span&gt;&lt;span class="nl"&gt;"AUTH_HEADER"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="s2"&gt;"Bearer YOUR_OUTLINE_API_TOKEN"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt;
        &lt;/span&gt;&lt;span class="nl"&gt;"NODE_TLS_REJECT_UNAUTHORIZED"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="s2"&gt;"0"&lt;/span&gt;&lt;span class="w"&gt;
      &lt;/span&gt;&lt;span class="p"&gt;}&lt;/span&gt;&lt;span class="w"&gt;
    &lt;/span&gt;&lt;span class="p"&gt;}&lt;/span&gt;&lt;span class="w"&gt;
  &lt;/span&gt;&lt;span class="p"&gt;}&lt;/span&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;span class="p"&gt;}&lt;/span&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;若 Claude Desktop 找不到 &lt;code&gt;npx&lt;/code&gt;，將 &lt;code&gt;command&lt;/code&gt; 改成 &lt;code&gt;which npx&lt;/code&gt; 查到的完整路徑，例如：&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight json"&gt;&lt;code&gt;&lt;span class="nl"&gt;"command"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="s2"&gt;"/opt/homebrew/bin/npx"&lt;/span&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;JSON 常見錯誤包括：&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;欄位之間少了逗號&lt;/li&gt;
&lt;li&gt;最後一個欄位多了逗號&lt;/li&gt;
&lt;li&gt;大括號或中括號數量不一致&lt;/li&gt;
&lt;li&gt;Windows 路徑中的反斜線沒有寫成 &lt;code&gt;\\&lt;/code&gt;
&lt;/li&gt;
&lt;li&gt;macOS 路徑含有空白時，終端機指令沒有使用引號或跳脫字元&lt;/li&gt;
&lt;li&gt;把 &lt;code&gt;mcpServers&lt;/code&gt; 貼到最外層物件之外&lt;/li&gt;
&lt;/ul&gt;




&lt;h2&gt;
  
  
  重新啟動 Claude Desktop
&lt;/h2&gt;

&lt;p&gt;修改設定檔後，必須完整關閉 Claude Desktop，再重新開啟。&lt;/p&gt;

&lt;p&gt;只關閉視窗不一定代表程式已完全結束：&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;
&lt;strong&gt;Windows：&lt;/strong&gt; 從系統匣結束 Claude，或到工作管理員確認 Claude 是否仍在背景執行。&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;macOS：&lt;/strong&gt; 按下 &lt;code&gt;Command + Q&lt;/code&gt;，或從上方選單選擇「Claude」→「結束 Claude」。必要時可到「活動監視器」確認程式是否仍在執行。&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;重新啟動時，Claude Desktop 會：&lt;/p&gt;

&lt;ol&gt;
&lt;li&gt;讀取 &lt;code&gt;claude_desktop_config.json&lt;/code&gt;
&lt;/li&gt;
&lt;li&gt;透過 &lt;code&gt;npx&lt;/code&gt; 啟動 &lt;code&gt;mcp-remote&lt;/code&gt;
&lt;/li&gt;
&lt;li&gt;使用 Authorization Header 連接 Outline MCP Server&lt;/li&gt;
&lt;li&gt;載入 MCP Server 提供的工具&lt;/li&gt;
&lt;/ol&gt;

&lt;p&gt;首次執行 &lt;code&gt;npx -y mcp-remote&lt;/code&gt; 時，可能需要下載套件，因此等待時間會比後續啟動稍長。&lt;/p&gt;




&lt;h2&gt;
  
  
  測試 Outline MCP 是否連線成功
&lt;/h2&gt;

&lt;p&gt;重新開啟 Claude Desktop 後，可以輸入：&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;可以接到 Outline MCP 嗎？請列出目前可使用的 Outline 工具。
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;接著再測試實際讀取：&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;請列出 Outline 中目前可以看到的文件與文件集。
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;也可以指定操作：&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;請搜尋 Outline 中包含「前端」關鍵字的文件。
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;連線成功時，Claude 會顯示已載入 Outline 工具，並能回傳工作區中的文件或 Collection 資訊。&lt;/p&gt;

</description>
      <category>outline</category>
      <category>ai</category>
      <category>claude</category>
      <category>mcp</category>
    </item>
    <item>
      <title>Outline Wiki 自架教學（一）：Docker 安裝、Gitea OIDC 與 AI 知識庫準備</title>
      <dc:creator>Let's Write</dc:creator>
      <pubDate>Fri, 26 Jun 2026 13:49:09 +0000</pubDate>
      <link>https://dev.to/letswrite/outline-wiki-zi-jia-jiao-xue-docker-an-zhuang-gitea-oidc-yu-ai-zhi-shi-ku-zhun-bei-4c8d</link>
      <guid>https://dev.to/letswrite/outline-wiki-zi-jia-jiao-xue-docker-an-zhuang-gitea-oidc-yu-ai-zhi-shi-ku-zhun-bei-4c8d</guid>
      <description>&lt;h1&gt;
  
  
  Outline Wiki 自架教學（一）：Docker 安裝、Gitea OIDC 與 AI 知識庫準備
&lt;/h1&gt;

&lt;h2&gt;
  
  
  本篇要解決的問題
&lt;/h2&gt;

&lt;p&gt;公司開發團隊裡，想架一套內部的知識庫，又要能支援 AI，常見的痛點有幾個：&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;文件資料留在自己的機器上，不對外，以免洩露商業機密。&lt;/li&gt;
&lt;li&gt;想要加上 AI？得付 $$，比如 Notion，或是也可以自架的 Docmost。&lt;/li&gt;
&lt;li&gt;Outline Wiki 裝起來很難，August 失敗過一次，最後是靠 Claude Opus 4.8 的輔助才成功。&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;本篇筆記文，會用一份 Docker Compose 檔，把 Outline，以及需要的 PostgreSQL、Redis、Caddy 全包進去，並針對上面這些坑一次閃掉。&lt;/p&gt;

&lt;p&gt;另外也先說明本文裡的基本設定：&lt;/p&gt;

&lt;ol&gt;
&lt;li&gt;本機已裝好 Docker。&lt;/li&gt;
&lt;li&gt;對內 PORT 是 &lt;code&gt;3002&lt;/code&gt;，對外是 &lt;code&gt;3001&lt;/code&gt;。&lt;/li&gt;
&lt;/ol&gt;

&lt;p&gt;關於 Outline + AI 的補充說明：&lt;/p&gt;

&lt;p&gt;自架版 Outline 沒有內建的「AI Answers」功能，網路上常看到的 OPENAI_API_KEY 對自架版是無效的。想要 Outline 加上 AI，正解是用 MCP 外接，讓 Claude / Codex 透過 Outline 的 API 來操作（作法將寫在下一篇）。&lt;/p&gt;




&lt;h2&gt;
  
  
  步驟 1：安裝 Gitea
&lt;/h2&gt;

&lt;p&gt;第一個管理員帳號要用 Gitea 登入，所以得先有一台 Gitea。&lt;/p&gt;

&lt;p&gt;Gitea 本身也能用 Docker 自架，這部分 August 之前寫過，直接看這篇：&lt;/p&gt;

&lt;p&gt;&lt;a href="https://www.letswrite.tw/gitea-ai-code-review/#%e4%b8%80%e3%80%81%e5%ae%89%e8%a3%9d-gitea" rel="noopener noreferrer"&gt;安裝 Gitea&lt;/a&gt;。&lt;/p&gt;

&lt;p&gt;只要你的 Gitea 已經能正常登入，就可以往下走。&lt;/p&gt;

&lt;p&gt;Outline 並不限定 Gitea，任何相容 OIDC 的供應商（Keycloak、Authentik、Google⋯）都行，差別只在 &lt;code&gt;OIDC_*&lt;/code&gt; 那幾個網址。&lt;/p&gt;




&lt;h2&gt;
  
  
  步驟 2：從 Gitea 取得 Client ID 與 Secret
&lt;/h2&gt;

&lt;p&gt;Outline 走 OIDC 登入，需要在 Gitea 建立一個「OAuth2 應用程式」，拿到 &lt;strong&gt;Client ID&lt;/strong&gt; 和 &lt;strong&gt;Client Secret&lt;/strong&gt;。&lt;/p&gt;

&lt;p&gt;進入 Gitea 後，到 &lt;strong&gt;設定（Settings）→ 應用程式（Applications）&lt;/strong&gt;，找到「管理 OAuth2 應用程式」區塊。&lt;/p&gt;

&lt;p&gt;&lt;a href="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.us-east-2.amazonaws.com%2Fuploads%2Farticles%2Frr9do1xie7tabxt25c9a.png" class="article-body-image-wrapper"&gt;&lt;img src="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.us-east-2.amazonaws.com%2Fuploads%2Farticles%2Frr9do1xie7tabxt25c9a.png" alt="在 Gitea 的「設定 → 應用程式」頁面，找到「管理 OAuth2 應用程式」的建立表單" width="800" height="481"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;在 Gitea 的「設定 → 應用程式」頁面，找到「管理 OAuth2 應用程式」的建立表單&lt;/p&gt;

&lt;p&gt;需要填兩個欄位：&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;應用程式名稱：填一個自己記得註是做什麼的名稱，如：&lt;code&gt;Outline Wiki Login&lt;/code&gt;。&lt;/li&gt;
&lt;li&gt;重新導向 URI：要填的 PORT 是有對外加上憑證，比如本篇用的是 &lt;code&gt;3001&lt;/code&gt;。
&lt;/li&gt;
&lt;/ul&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;https://&amp;lt;你的IP或網域&amp;gt;:3001/auth/oidc.callback
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;例如主機 IP 是 &lt;code&gt;192.168.11.111&lt;/code&gt;，就填 &lt;code&gt;https://192.168.11.111:3001/auth/oidc.callback&lt;/code&gt;。這個 IP 與埠號要跟等一下 Compose 裡的 &lt;code&gt;URL=&lt;/code&gt; 完全一致。&lt;/p&gt;

&lt;p&gt;&lt;a href="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.us-east-2.amazonaws.com%2Fuploads%2Farticles%2Fphzxibgb2hucl5t5opbf.png" class="article-body-image-wrapper"&gt;&lt;img src="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.us-east-2.amazonaws.com%2Fuploads%2Farticles%2Fphzxibgb2hucl5t5opbf.png" alt="Gitea OAuth2 應用程式表單，填入應用程式名稱與重新導向 URI（重點是 Redirect URI 結尾為 /auth/oidc.callback）" width="730" height="660"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;Gitea OAuth2 應用程式表單，填入應用程式名稱與重新導向 URI（重點是 Redirect URI 結尾為 /auth/oidc.callback）&lt;/p&gt;

&lt;p&gt;按下「建立應用程式」後，Gitea 會顯示 &lt;strong&gt;Client ID&lt;/strong&gt; 與 &lt;strong&gt;Client Secret&lt;/strong&gt;。&lt;/p&gt;

&lt;p&gt;&lt;a href="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.us-east-2.amazonaws.com%2Fuploads%2Farticles%2Fp1q68lwxl45vclsj812g.png" class="article-body-image-wrapper"&gt;&lt;img src="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.us-east-2.amazonaws.com%2Fuploads%2Farticles%2Fp1q68lwxl45vclsj812g.png" alt="Gitea 建立完成後顯示的 Client ID 與 Client Secret 畫面。" width="731" height="478"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;Gitea 建立完成後顯示的 Client ID 與 Client Secret 畫面。&lt;/p&gt;

&lt;p&gt;要注意，&lt;code&gt;Client Secret&lt;/code&gt; 只會完整顯示這一次，先複製存好。等一下要填進 Compose 的 &lt;code&gt;OIDC_CLIENT_ID&lt;/code&gt; 與 &lt;code&gt;OIDC_CLIENT_SECRET&lt;/code&gt;。&lt;/p&gt;




&lt;h2&gt;
  
  
  步驟 3-1：安裝 Outline Wiki：Windows 版
&lt;/h2&gt;

&lt;p&gt;Windows 用 Docker Desktop，這裡用具名 volume（由 Docker 管理）存附件，啟動最單純。&lt;/p&gt;

&lt;p&gt;先新增一個空資料夾，接著我們要放進下面的 2 個檔案。&lt;/p&gt;

&lt;h3&gt;
  
  
  Caddyfile
&lt;/h3&gt;

&lt;p&gt;資料夾內新增一個檔案，檔名：&lt;code&gt;Caddfile&lt;/code&gt;。&lt;/p&gt;

&lt;p&gt;&lt;code&gt;Caddyfile&lt;/code&gt; 負責「對外用 HTTPS、把流量轉給 Outline」。&lt;/p&gt;

&lt;p&gt;檔案內容複製貼上以下，再把 &lt;code&gt;192.168.11.111&lt;/code&gt; 換成我們 Windows 主機的區網 IP：&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;{
  default_sni 192.168.11.111
}

192.168.11.111:3001 {
  tls internal
  reverse_proxy outline:3002
}
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;ul&gt;
&lt;li&gt;
&lt;code&gt;tls internal&lt;/code&gt;：Caddy 自己簽一張憑證。因為我們用的是區網 IP，本來就申請不到正式憑證，自簽夠用。&lt;/li&gt;
&lt;li&gt;
&lt;code&gt;3001&lt;/code&gt; 是對外埠、&lt;code&gt;outline:3002&lt;/code&gt; 是 Outline 容器內部埠，兩者分工，注意不能寫成一樣。&lt;/li&gt;
&lt;/ul&gt;

&lt;h3&gt;
  
  
  docker-compose.yml
&lt;/h3&gt;

&lt;p&gt;資料夾內再新增一個檔案，檔名：&lt;code&gt;docker-compose.yml&lt;/code&gt;。&lt;/p&gt;

&lt;p&gt;檔案內容複製貼上以下：&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight yaml"&gt;&lt;code&gt;&lt;span class="c1"&gt;# =============================================================================&lt;/span&gt;
&lt;span class="c1"&gt;# Outline Wiki — Docker Compose 教學範例&lt;/span&gt;
&lt;span class="c1"&gt;# =============================================================================&lt;/span&gt;
&lt;span class="c1"&gt;# 架構：&lt;/span&gt;
&lt;span class="c1"&gt;#   outline   → 主應用 (Node.js)&lt;/span&gt;
&lt;span class="c1"&gt;#   caddy     → 反向代理 + 自動 HTTPS&lt;/span&gt;
&lt;span class="c1"&gt;#   postgres  → 資料庫&lt;/span&gt;
&lt;span class="c1"&gt;#   (外部)    → Redis，負責快取 / WebSocket / 背景工作佇列&lt;/span&gt;
&lt;span class="c1"&gt;#&lt;/span&gt;
&lt;span class="c1"&gt;# ⚠️ 發佈前務必把所有 &amp;lt;...&amp;gt; 佔位符換成你自己的值。&lt;/span&gt;
&lt;span class="c1"&gt;#    範例裡的密鑰、密碼、IP 全是假的，不要直接拿去用。&lt;/span&gt;
&lt;span class="c1"&gt;# =============================================================================&lt;/span&gt;

&lt;span class="na"&gt;services&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt;
  &lt;span class="c1"&gt;# ---------------------------------------------------------------------------&lt;/span&gt;
  &lt;span class="c1"&gt;# Outline 主應用&lt;/span&gt;
  &lt;span class="c1"&gt;# ---------------------------------------------------------------------------&lt;/span&gt;
  &lt;span class="na"&gt;outline&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt;
    &lt;span class="na"&gt;image&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="s"&gt;outlinewiki/outline:latest&lt;/span&gt;
    &lt;span class="na"&gt;container_name&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="s"&gt;outline&lt;/span&gt;
    &lt;span class="na"&gt;restart&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="s"&gt;unless-stopped&lt;/span&gt;
    &lt;span class="na"&gt;environment&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt;
      &lt;span class="pi"&gt;-&lt;/span&gt; &lt;span class="s"&gt;NODE_ENV=production&lt;/span&gt;

      &lt;span class="c1"&gt;# --- 安全密鑰 (必填) ---------------------------------------------------&lt;/span&gt;
      &lt;span class="c1"&gt;# 兩把都要用 32-byte 隨機 hex 字串。產生方式:&lt;/span&gt;
      &lt;span class="c1"&gt;#   openssl rand -hex 32&lt;/span&gt;
      &lt;span class="c1"&gt;# ⚠️ 換掉後不要再改，改了會讓既有 session / 加密資料失效。&lt;/span&gt;
      &lt;span class="pi"&gt;-&lt;/span&gt; &lt;span class="s"&gt;SECRET_KEY=&amp;lt;openssl rand -hex 32 產生&amp;gt;&lt;/span&gt;
      &lt;span class="pi"&gt;-&lt;/span&gt; &lt;span class="s"&gt;UTILS_SECRET=&amp;lt;openssl rand -hex 32 產生&amp;gt;&lt;/span&gt;

      &lt;span class="c1"&gt;# --- 資料庫連線 (必填) -------------------------------------------------&lt;/span&gt;
      &lt;span class="c1"&gt;# 格式：postgres://帳號:密碼@主機:埠/資料庫名&lt;/span&gt;
      &lt;span class="c1"&gt;# 主機名 postgres = 下面那個 service 名稱，Docker 內部 DNS 解析。&lt;/span&gt;
      &lt;span class="pi"&gt;-&lt;/span&gt; &lt;span class="s"&gt;DATABASE_URL=postgres://outline_user:&amp;lt;DB_密碼&amp;gt;@postgres:5432/outline&lt;/span&gt;
      &lt;span class="pi"&gt;-&lt;/span&gt; &lt;span class="s"&gt;PGSSLMODE=disable&lt;/span&gt;   &lt;span class="c1"&gt;# 同一台 Docker 內部連線，不需 SSL&lt;/span&gt;

      &lt;span class="c1"&gt;# --- Redis 連線 (必填) -------------------------------------------------&lt;/span&gt;
      &lt;span class="c1"&gt;# 格式：redis://:密碼@主機:埠/DB編號&lt;/span&gt;
      &lt;span class="c1"&gt;# 這裡指向下面內建的 redis service，主機名 redis = service 名。&lt;/span&gt;
      &lt;span class="pi"&gt;-&lt;/span&gt; &lt;span class="s"&gt;REDIS_URL=redis://redis:6379/1&lt;/span&gt;

      &lt;span class="c1"&gt;# --- 對外網址 (必填) ---------------------------------------------------&lt;/span&gt;
      &lt;span class="c1"&gt;# 使用者瀏覽器看到的完整網址，要跟 Caddy / 反代對外位置一致。&lt;/span&gt;
      &lt;span class="pi"&gt;-&lt;/span&gt; &lt;span class="s"&gt;URL=https://&amp;lt;你的網域或IP&amp;gt;:8443&lt;/span&gt;
      &lt;span class="pi"&gt;-&lt;/span&gt; &lt;span class="s"&gt;PORT=3019&lt;/span&gt;            &lt;span class="c1"&gt;# 容器內部監聽埠 (給 Caddy 反代用,不直接對外)&lt;/span&gt;
      &lt;span class="pi"&gt;-&lt;/span&gt; &lt;span class="s"&gt;FORCE_HTTPS=false&lt;/span&gt;    &lt;span class="c1"&gt;# HTTPS 由 Caddy 處理，這裡關掉避免重導迴圈&lt;/span&gt;

      &lt;span class="c1"&gt;# --- 檔案儲存 (必填) ---------------------------------------------------&lt;/span&gt;
      &lt;span class="c1"&gt;# local = 存本機磁碟 (搭配下面 volumes)。也可改 s3 接物件儲存。&lt;/span&gt;
      &lt;span class="pi"&gt;-&lt;/span&gt; &lt;span class="s"&gt;FILE_STORAGE=local&lt;/span&gt;
      &lt;span class="pi"&gt;-&lt;/span&gt; &lt;span class="s"&gt;FILE_STORAGE_LOCAL_ROOT_DIR=/var/lib/outline/data&lt;/span&gt;
      &lt;span class="c1"&gt;# 上傳/匯入大小上限 (bytes)。預設約 1MB,匯入大 zip (如從&lt;/span&gt;
      &lt;span class="c1"&gt;# Docmost/Notion 匯出) 會跳「file too large」。調大解決。&lt;/span&gt;
      &lt;span class="c1"&gt;# 算法: MB × 1048576。下面 = 250MB。&lt;/span&gt;
      &lt;span class="pi"&gt;-&lt;/span&gt; &lt;span class="s"&gt;FILE_STORAGE_UPLOAD_MAX_SIZE=262144000&lt;/span&gt;            &lt;span class="c1"&gt;# 附件上限&lt;/span&gt;
      &lt;span class="pi"&gt;-&lt;/span&gt; &lt;span class="s"&gt;FILE_STORAGE_IMPORT_MAX_SIZE=262144000&lt;/span&gt;            &lt;span class="c1"&gt;# 單篇匯入&lt;/span&gt;
      &lt;span class="pi"&gt;-&lt;/span&gt; &lt;span class="s"&gt;FILE_STORAGE_WORKSPACE_IMPORT_MAX_SIZE=262144000&lt;/span&gt;  &lt;span class="c1"&gt;# zip 整包匯入 (關鍵)&lt;/span&gt;

      &lt;span class="c1"&gt;# --- 登入: Gitea OIDC (選填) -------------------------------------------&lt;/span&gt;
      &lt;span class="c1"&gt;# 任何相容 OIDC 的供應商都行 (Gitea / Keycloak / Authentik / Google...)。&lt;/span&gt;
      &lt;span class="c1"&gt;# client id/secret 從你的 OIDC 供應商後台拿。&lt;/span&gt;
      &lt;span class="pi"&gt;-&lt;/span&gt; &lt;span class="s"&gt;OIDC_CLIENT_ID=&amp;lt;OIDC_CLIENT_ID&amp;gt;&lt;/span&gt;
      &lt;span class="pi"&gt;-&lt;/span&gt; &lt;span class="s"&gt;OIDC_CLIENT_SECRET=&amp;lt;OIDC_CLIENT_SECRET&amp;gt;&lt;/span&gt;
      &lt;span class="pi"&gt;-&lt;/span&gt; &lt;span class="s"&gt;OIDC_AUTH_URI=http://&amp;lt;OIDC主機&amp;gt;/login/oauth/authorize&lt;/span&gt;
      &lt;span class="pi"&gt;-&lt;/span&gt; &lt;span class="s"&gt;OIDC_TOKEN_URI=http://&amp;lt;OIDC主機&amp;gt;/login/oauth/access_token&lt;/span&gt;
      &lt;span class="pi"&gt;-&lt;/span&gt; &lt;span class="s"&gt;OIDC_USERINFO_URI=http://&amp;lt;OIDC主機&amp;gt;/login/oauth/userinfo&lt;/span&gt;
      &lt;span class="pi"&gt;-&lt;/span&gt; &lt;span class="s"&gt;OIDC_USERNAME_CLAIM=preferred_username&lt;/span&gt;   &lt;span class="c1"&gt;# 用哪個欄位當帳號&lt;/span&gt;
      &lt;span class="pi"&gt;-&lt;/span&gt; &lt;span class="s"&gt;OIDC_DISPLAY_NAME=Gitea&lt;/span&gt;                   &lt;span class="c1"&gt;# 登入按鈕顯示文字&lt;/span&gt;
      &lt;span class="pi"&gt;-&lt;/span&gt; &lt;span class="s"&gt;OIDC_SCOPES=openid profile email&lt;/span&gt;

      &lt;span class="c1"&gt;# --- SMTP 寄信 (選填) --------------------------------------------------&lt;/span&gt;
      &lt;span class="c1"&gt;# 用途：magic-link 登入信 + 通知信。&lt;/span&gt;
      &lt;span class="c1"&gt;# Gmail 範例：密碼要用「應用程式密碼」，不是帳號密碼。&lt;/span&gt;
      &lt;span class="c1"&gt;# (Google 帳號 → 安全性 → 兩步驟驗證 → 應用程式密碼)&lt;/span&gt;
      &lt;span class="pi"&gt;-&lt;/span&gt; &lt;span class="s"&gt;SMTP_HOST=smtp.gmail.com&lt;/span&gt;
      &lt;span class="pi"&gt;-&lt;/span&gt; &lt;span class="s"&gt;SMTP_PORT=587&lt;/span&gt;
      &lt;span class="pi"&gt;-&lt;/span&gt; &lt;span class="s"&gt;SMTP_SECURE=false&lt;/span&gt;    &lt;span class="c1"&gt;# 587 用 STARTTLS，所以這裡 false&lt;/span&gt;
      &lt;span class="pi"&gt;-&lt;/span&gt; &lt;span class="s"&gt;SMTP_USERNAME=&amp;lt;你的gmail@gmail.com&amp;gt;&lt;/span&gt;
      &lt;span class="pi"&gt;-&lt;/span&gt; &lt;span class="s"&gt;SMTP_PASSWORD=&amp;lt;Gmail 應用程式密碼&amp;gt;&lt;/span&gt;
      &lt;span class="pi"&gt;-&lt;/span&gt; &lt;span class="s"&gt;SMTP_FROM_EMAIL=&amp;lt;你的gmail@gmail.com&amp;gt;&lt;/span&gt;
      &lt;span class="pi"&gt;-&lt;/span&gt; &lt;span class="s"&gt;SMTP_REPLY_EMAIL=&amp;lt;你的gmail@gmail.com&amp;gt;&lt;/span&gt;

    &lt;span class="na"&gt;volumes&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt;
      &lt;span class="c1"&gt;# 用具名 volume，由 Docker 管理。注意：這裡存的是「附件/上傳檔」&lt;/span&gt;
      &lt;span class="c1"&gt;# (圖片、PDF...)，不是文章本體。文章內容存在 PostgreSQL，不是 .md 檔。&lt;/span&gt;
      &lt;span class="pi"&gt;-&lt;/span&gt; &lt;span class="s"&gt;outline_data:/var/lib/outline/data&lt;/span&gt;
    &lt;span class="na"&gt;depends_on&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt;
      &lt;span class="na"&gt;postgres&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt;
        &lt;span class="na"&gt;condition&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="s"&gt;service_healthy&lt;/span&gt;   &lt;span class="c1"&gt;# 等 DB 健康檢查通過才啟動 outline&lt;/span&gt;
      &lt;span class="na"&gt;redis&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt;
        &lt;span class="na"&gt;condition&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="s"&gt;service_healthy&lt;/span&gt;   &lt;span class="c1"&gt;# 等 Redis 就緒&lt;/span&gt;

  &lt;span class="c1"&gt;# ---------------------------------------------------------------------------&lt;/span&gt;
  &lt;span class="c1"&gt;# Redis — 快取 / WebSocket / 背景工作佇列 (內建獨立 service)&lt;/span&gt;
  &lt;span class="c1"&gt;# ---------------------------------------------------------------------------&lt;/span&gt;
  &lt;span class="na"&gt;redis&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt;
    &lt;span class="na"&gt;image&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="s"&gt;redis:7-alpine&lt;/span&gt;
    &lt;span class="na"&gt;container_name&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="s"&gt;outline_redis&lt;/span&gt;
    &lt;span class="na"&gt;restart&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="s"&gt;unless-stopped&lt;/span&gt;
    &lt;span class="na"&gt;volumes&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt;
      &lt;span class="pi"&gt;-&lt;/span&gt; &lt;span class="s"&gt;redis_data:/data&lt;/span&gt;   &lt;span class="c1"&gt;# 持久化 (選用,Outline 主要當快取，掉了也能重建)&lt;/span&gt;
    &lt;span class="na"&gt;healthcheck&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt;
      &lt;span class="na"&gt;test&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="pi"&gt;[&lt;/span&gt;&lt;span class="s2"&gt;"&lt;/span&gt;&lt;span class="s"&gt;CMD"&lt;/span&gt;&lt;span class="pi"&gt;,&lt;/span&gt; &lt;span class="s2"&gt;"&lt;/span&gt;&lt;span class="s"&gt;redis-cli"&lt;/span&gt;&lt;span class="pi"&gt;,&lt;/span&gt; &lt;span class="s2"&gt;"&lt;/span&gt;&lt;span class="s"&gt;ping"&lt;/span&gt;&lt;span class="pi"&gt;]&lt;/span&gt;   &lt;span class="c1"&gt;# 回 PONG 才算就緒&lt;/span&gt;
      &lt;span class="na"&gt;interval&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="s"&gt;10s&lt;/span&gt;
      &lt;span class="na"&gt;timeout&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="s"&gt;5s&lt;/span&gt;
      &lt;span class="na"&gt;retries&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="m"&gt;5&lt;/span&gt;

  &lt;span class="c1"&gt;# ---------------------------------------------------------------------------&lt;/span&gt;
  &lt;span class="c1"&gt;# Caddy — 反向代理，自動處理 HTTPS 憑證&lt;/span&gt;
  &lt;span class="c1"&gt;# ---------------------------------------------------------------------------&lt;/span&gt;
  &lt;span class="na"&gt;caddy&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt;
    &lt;span class="na"&gt;image&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="s"&gt;caddy:2&lt;/span&gt;
    &lt;span class="na"&gt;container_name&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="s"&gt;outline_caddy&lt;/span&gt;
    &lt;span class="na"&gt;restart&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="s"&gt;unless-stopped&lt;/span&gt;
    &lt;span class="na"&gt;ports&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt;
      &lt;span class="pi"&gt;-&lt;/span&gt; &lt;span class="s2"&gt;"&lt;/span&gt;&lt;span class="s"&gt;8443:8443"&lt;/span&gt;   &lt;span class="c1"&gt;# 對外開的埠 (主機：容器)。實際反代規則寫在 Caddyfile。&lt;/span&gt;
    &lt;span class="na"&gt;volumes&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt;
      &lt;span class="pi"&gt;-&lt;/span&gt; &lt;span class="s"&gt;./Caddyfile:/etc/caddy/Caddyfile:ro&lt;/span&gt;   &lt;span class="c1"&gt;# :ro = 唯讀掛載&lt;/span&gt;
      &lt;span class="pi"&gt;-&lt;/span&gt; &lt;span class="s"&gt;caddy_data:/data&lt;/span&gt;       &lt;span class="c1"&gt;# 存 TLS 憑證，別刪，刪了要重新申請&lt;/span&gt;
      &lt;span class="pi"&gt;-&lt;/span&gt; &lt;span class="s"&gt;caddy_config:/config&lt;/span&gt;
    &lt;span class="na"&gt;depends_on&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt;
      &lt;span class="pi"&gt;-&lt;/span&gt; &lt;span class="s"&gt;outline&lt;/span&gt;

  &lt;span class="c1"&gt;# ---------------------------------------------------------------------------&lt;/span&gt;
  &lt;span class="c1"&gt;# PostgreSQL&lt;/span&gt;
  &lt;span class="c1"&gt;# ---------------------------------------------------------------------------&lt;/span&gt;
  &lt;span class="na"&gt;postgres&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt;
    &lt;span class="na"&gt;image&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="s"&gt;pgvector/pgvector:pg16&lt;/span&gt;
    &lt;span class="na"&gt;container_name&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="s"&gt;outline_postgres&lt;/span&gt;
    &lt;span class="na"&gt;restart&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="s"&gt;unless-stopped&lt;/span&gt;
    &lt;span class="na"&gt;environment&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt;
      &lt;span class="c1"&gt;# 這三個要跟上面 DATABASE_URL 裡的帳號/密碼/DB名一致。&lt;/span&gt;
      &lt;span class="pi"&gt;-&lt;/span&gt; &lt;span class="s"&gt;POSTGRES_USER=outline_user&lt;/span&gt;
      &lt;span class="pi"&gt;-&lt;/span&gt; &lt;span class="s"&gt;POSTGRES_PASSWORD=&amp;lt;DB_密碼&amp;gt;&lt;/span&gt;
      &lt;span class="pi"&gt;-&lt;/span&gt; &lt;span class="s"&gt;POSTGRES_DB=outline&lt;/span&gt;
    &lt;span class="na"&gt;volumes&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt;
      &lt;span class="pi"&gt;-&lt;/span&gt; &lt;span class="s"&gt;pg_data:/var/lib/postgresql/data&lt;/span&gt;   &lt;span class="c1"&gt;# 資料庫實體資料，千萬別誤刪&lt;/span&gt;
    &lt;span class="na"&gt;ports&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt;
      &lt;span class="c1"&gt;# 只綁 127.0.0.1 = 僅本機可連，不對外曝露 DB。安全做法。&lt;/span&gt;
      &lt;span class="pi"&gt;-&lt;/span&gt; &lt;span class="s2"&gt;"&lt;/span&gt;&lt;span class="s"&gt;127.0.0.1:5432:5432"&lt;/span&gt;
    &lt;span class="na"&gt;healthcheck&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt;
      &lt;span class="c1"&gt;# 確認 DB 真的可接受連線，outline 才會啟動 (見上面 depends_on)。&lt;/span&gt;
      &lt;span class="na"&gt;test&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="pi"&gt;[&lt;/span&gt;&lt;span class="s2"&gt;"&lt;/span&gt;&lt;span class="s"&gt;CMD-SHELL"&lt;/span&gt;&lt;span class="pi"&gt;,&lt;/span&gt; &lt;span class="s2"&gt;"&lt;/span&gt;&lt;span class="s"&gt;pg_isready&lt;/span&gt;&lt;span class="nv"&gt; &lt;/span&gt;&lt;span class="s"&gt;-U&lt;/span&gt;&lt;span class="nv"&gt; &lt;/span&gt;&lt;span class="s"&gt;outline_user&lt;/span&gt;&lt;span class="nv"&gt; &lt;/span&gt;&lt;span class="s"&gt;-d&lt;/span&gt;&lt;span class="nv"&gt; &lt;/span&gt;&lt;span class="s"&gt;outline"&lt;/span&gt;&lt;span class="pi"&gt;]&lt;/span&gt;
      &lt;span class="na"&gt;interval&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="s"&gt;10s&lt;/span&gt;
      &lt;span class="na"&gt;timeout&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="s"&gt;5s&lt;/span&gt;
      &lt;span class="na"&gt;retries&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="m"&gt;5&lt;/span&gt;

&lt;span class="c1"&gt;# -----------------------------------------------------------------------------&lt;/span&gt;
&lt;span class="c1"&gt;# 具名 volume — 由 Docker 管理,容器刪掉資料還在。&lt;/span&gt;
&lt;span class="c1"&gt;# -----------------------------------------------------------------------------&lt;/span&gt;
&lt;span class="na"&gt;volumes&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt;
  &lt;span class="na"&gt;outline_data&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt;
  &lt;span class="na"&gt;pg_data&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt;
  &lt;span class="na"&gt;redis_data&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt;
  &lt;span class="na"&gt;caddy_data&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt;
  &lt;span class="na"&gt;caddy_config&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;接著要把所有 &lt;code&gt;&amp;lt;...&amp;gt;&lt;/code&gt; 的部份換成自己的值，要改這幾項：&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;
&lt;code&gt;SECRET_KEY&lt;/code&gt;、&lt;code&gt;UTILS_SECRET&lt;/code&gt;：開啟終端機，執行兩次 &lt;code&gt;openssl rand -hex 32&lt;/code&gt; 產生 32-byte 隨機字串。沒有 openssl 的話，那就用 Claude、ChatGPT 等 AI，對話中讓它們生成 2 組使用。&lt;/li&gt;
&lt;li&gt;
&lt;code&gt;DATABASE_URL&lt;/code&gt; 與 &lt;code&gt;POSTGRES_PASSWORD&lt;/code&gt;：兩邊的密碼要一致。&lt;/li&gt;
&lt;li&gt;
&lt;code&gt;URL&lt;/code&gt;：填 &lt;code&gt;https://&amp;lt;你的IP&amp;gt;:3001&lt;/code&gt;，IP 要跟 Caddyfile 一樣。&lt;/li&gt;
&lt;li&gt;
&lt;code&gt;OIDC_CLIENT_ID&lt;/code&gt;、&lt;code&gt;OIDC_CLIENT_SECRET&lt;/code&gt;：填上一段從 Gitea 拿到的值。&lt;/li&gt;
&lt;li&gt;
&lt;code&gt;OIDC_AUTH_URI&lt;/code&gt; / &lt;code&gt;OIDC_TOKEN_URI&lt;/code&gt; / &lt;code&gt;OIDC_USERINFO_URI&lt;/code&gt;：把 &lt;code&gt;&amp;lt;OIDC主機&amp;gt;&lt;/code&gt; 換成 Gitea 網址。&lt;/li&gt;
&lt;li&gt;（選填）SMTP：要寄邀請信 / magic-link 才需要填。&lt;/li&gt;
&lt;/ul&gt;

&lt;h3&gt;
  
  
  啟動
&lt;/h3&gt;

&lt;p&gt;在 &lt;code&gt;docker-compose.yml&lt;/code&gt; 所在資料夾開終端機：&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight shell"&gt;&lt;code&gt;docker compose up &lt;span class="nt"&gt;-d&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;第一次啟動 Outline 會自動跑資料庫遷移（migration），會需要多等個十幾秒。&lt;/p&gt;

&lt;p&gt;看到 outline 正常起來後，瀏覽器打開 &lt;code&gt;https://&amp;lt;你的IP&amp;gt;:3001&lt;/code&gt;。&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;瀏覽器會跳「您的連線不是私人連線 / 不安全」警告。&lt;/strong&gt;&lt;/p&gt;

&lt;p&gt;這是因為 &lt;code&gt;tls internal&lt;/code&gt; 用的是自簽憑證，屬於正常現象。點「進階 → 繼續前往」就能進到 Outline。&lt;/p&gt;

&lt;p&gt;進站後點 &lt;strong&gt;Continue with Gitea&lt;/strong&gt; 用 Gitea 帳號登入，第一個登入的人就是管理員。&lt;/p&gt;

&lt;p&gt;之後的成員，在 Outline 後台用 Email 邀請即可（這也是為什麼上面要設定 SMTP）。&lt;/p&gt;




&lt;h2&gt;
  
  
  步驟 3-2：安裝 Outline Wiki：Ubuntu 版
&lt;/h2&gt;

&lt;p&gt;Ubuntu 版跟 Windows 版幾乎一樣，只有兩個差別：&lt;/p&gt;

&lt;ol&gt;
&lt;li&gt;
&lt;strong&gt;附件改用 bind mount（&lt;code&gt;./data&lt;/code&gt;）&lt;/strong&gt;：附件直接落在專案資料夾，搬家 / 備份複製整個資料夾就帶走，不必像具名 volume 還要 &lt;code&gt;tar&lt;/code&gt; 撈。&lt;/li&gt;
&lt;li&gt;OIDC 的 Gitea 可以在&lt;strong&gt;另一台&lt;/strong&gt;機器，只要這台 Ubuntu 連得到即可。&lt;/li&gt;
&lt;/ol&gt;

&lt;h3&gt;
  
  
  檔案
&lt;/h3&gt;

&lt;p&gt;一樣是兩個檔案：&lt;code&gt;docker-compose.yml&lt;/code&gt; 和 &lt;code&gt;Caddyfile&lt;/code&gt;。&lt;/p&gt;

&lt;p&gt;&lt;code&gt;Caddyfile&lt;/code&gt; 內容（把 IP 換成你的 Ubuntu 主機 IP）：&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;{
  default_sni 192.168.11.111
}

192.168.11.111:3001 {
  tls internal
  reverse_proxy outline:3002
}
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;docker-compose.yml 的內容複製貼上以下：&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight yaml"&gt;&lt;code&gt;&lt;span class="c1"&gt;# =============================================================================&lt;/span&gt;
&lt;span class="c1"&gt;# Outline Wiki — Ubuntu 單主機部署版 (教學範例)&lt;/span&gt;
&lt;span class="c1"&gt;# =============================================================================&lt;/span&gt;
&lt;span class="c1"&gt;# 跟 Windows 版的差異：&lt;/span&gt;
&lt;span class="c1"&gt;#   1. 內建 Redis service — 不依賴外部 Redis 主機，一台 Ubuntu 全包。&lt;/span&gt;
&lt;span class="c1"&gt;#   2. 全部服務同一台主機，對外只露 Caddy 的 8443。&lt;/span&gt;
&lt;span class="c1"&gt;#   3. OIDC 仍可指向「另一台」Gitea/OIDC 主機，只要這台網路連得到。&lt;/span&gt;
&lt;span class="c1"&gt;#&lt;/span&gt;
&lt;span class="c1"&gt;# 架構：&lt;/span&gt;
&lt;span class="c1"&gt;#   outline   → 主應用 (Node.js)&lt;/span&gt;
&lt;span class="c1"&gt;#   redis     → 快取 / WebSocket / 背景佇列&lt;/span&gt;
&lt;span class="c1"&gt;#   caddy     → 反向代理 + 自動 HTTPS&lt;/span&gt;
&lt;span class="c1"&gt;#   postgres  → 資料庫&lt;/span&gt;
&lt;span class="c1"&gt;#&lt;/span&gt;
&lt;span class="c1"&gt;# ⚠️ 發佈前把所有 &amp;lt;...&amp;gt; 佔位符換成你自己的值。範例的密鑰/密碼/IP 全是假的。&lt;/span&gt;
&lt;span class="c1"&gt;#&lt;/span&gt;
&lt;span class="c1"&gt;# 部署步驟：&lt;/span&gt;
&lt;span class="c1"&gt;#   1. 整個資料夾複製到 Ubuntu (含 Caddyfile)。&lt;/span&gt;
&lt;span class="c1"&gt;#   2. 全域搜尋取代 &amp;lt;你的Ubuntu主機IP&amp;gt; → 實際 IP。&lt;/span&gt;
&lt;span class="c1"&gt;#   3. docker compose up -d&lt;/span&gt;
&lt;span class="c1"&gt;# =============================================================================&lt;/span&gt;

&lt;span class="na"&gt;services&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt;
  &lt;span class="c1"&gt;# ---------------------------------------------------------------------------&lt;/span&gt;
  &lt;span class="c1"&gt;# Outline 主應用&lt;/span&gt;
  &lt;span class="c1"&gt;# ---------------------------------------------------------------------------&lt;/span&gt;
  &lt;span class="na"&gt;outline&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt;
    &lt;span class="na"&gt;image&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="s"&gt;outlinewiki/outline:latest&lt;/span&gt;
    &lt;span class="na"&gt;container_name&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="s"&gt;outline&lt;/span&gt;
    &lt;span class="na"&gt;restart&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="s"&gt;unless-stopped&lt;/span&gt;
    &lt;span class="na"&gt;environment&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt;
      &lt;span class="pi"&gt;-&lt;/span&gt; &lt;span class="s"&gt;NODE_ENV=production&lt;/span&gt;

      &lt;span class="c1"&gt;# --- 安全密鑰 (必填) ---------------------------------------------------&lt;/span&gt;
      &lt;span class="c1"&gt;# 兩把都用 32-byte 隨機 hex。產生: openssl rand -hex 32&lt;/span&gt;
      &lt;span class="c1"&gt;# ⚠️ 換掉後別再改，改了會讓既有 session / 加密資料失效。&lt;/span&gt;
      &lt;span class="pi"&gt;-&lt;/span&gt; &lt;span class="s"&gt;SECRET_KEY=&amp;lt;openssl rand -hex 32 產生&amp;gt;&lt;/span&gt;
      &lt;span class="pi"&gt;-&lt;/span&gt; &lt;span class="s"&gt;UTILS_SECRET=&amp;lt;openssl rand -hex 32 產生&amp;gt;&lt;/span&gt;

      &lt;span class="c1"&gt;# --- 資料庫連線 (必填) -------------------------------------------------&lt;/span&gt;
      &lt;span class="c1"&gt;# 格式：postgres://帳號:密碼@主機:埠/資料庫名&lt;/span&gt;
      &lt;span class="c1"&gt;# 主機名 postgres = 下面的 service 名，Docker 內部 DNS 解析。&lt;/span&gt;
      &lt;span class="pi"&gt;-&lt;/span&gt; &lt;span class="s"&gt;DATABASE_URL=postgres://outline_user:&amp;lt;DB_密碼&amp;gt;@postgres:5432/outline&lt;/span&gt;
      &lt;span class="pi"&gt;-&lt;/span&gt; &lt;span class="s"&gt;PGSSLMODE=disable&lt;/span&gt;   &lt;span class="c1"&gt;# 同台 Docker 內部連線,不需 SSL&lt;/span&gt;

      &lt;span class="c1"&gt;# --- Redis 連線 (必填) -------------------------------------------------&lt;/span&gt;
      &lt;span class="c1"&gt;# ★ Ubuntu 版重點：指向「內建」redis service，主機名 redis = service 名。&lt;/span&gt;
      &lt;span class="c1"&gt;#   不像基本版要填外部 Redis IP/密碼。&lt;/span&gt;
      &lt;span class="pi"&gt;-&lt;/span&gt; &lt;span class="s"&gt;REDIS_URL=redis://redis:6379/1&lt;/span&gt;

      &lt;span class="c1"&gt;# --- 對外網址 (必填) ---------------------------------------------------&lt;/span&gt;
      &lt;span class="c1"&gt;# 使用者瀏覽器看到的完整網址，要跟 Caddy 對外位置一致。&lt;/span&gt;
      &lt;span class="pi"&gt;-&lt;/span&gt; &lt;span class="s"&gt;URL=https://&amp;lt;你的Ubuntu主機IP&amp;gt;:8443&lt;/span&gt;
      &lt;span class="pi"&gt;-&lt;/span&gt; &lt;span class="s"&gt;PORT=3019&lt;/span&gt;            &lt;span class="c1"&gt;# 容器內部監聽埠 (給 Caddy 反向代理，不直接對外)&lt;/span&gt;
      &lt;span class="pi"&gt;-&lt;/span&gt; &lt;span class="s"&gt;FORCE_HTTPS=false&lt;/span&gt;    &lt;span class="c1"&gt;# HTTPS 由 Caddy 處理，這裡關掉避免重導迴圈&lt;/span&gt;

      &lt;span class="c1"&gt;# --- 檔案儲存 (必填) ---------------------------------------------------&lt;/span&gt;
      &lt;span class="pi"&gt;-&lt;/span&gt; &lt;span class="s"&gt;FILE_STORAGE=local&lt;/span&gt;
      &lt;span class="pi"&gt;-&lt;/span&gt; &lt;span class="s"&gt;FILE_STORAGE_LOCAL_ROOT_DIR=/var/lib/outline/data&lt;/span&gt;
      &lt;span class="c1"&gt;# 上傳/匯入大小上限 (bytes)。預設約 1MB，匯入大 zip 會跳「file too large」。&lt;/span&gt;
      &lt;span class="c1"&gt;# 算法: MB × 1048576。下面 = 250MB。&lt;/span&gt;
      &lt;span class="pi"&gt;-&lt;/span&gt; &lt;span class="s"&gt;FILE_STORAGE_UPLOAD_MAX_SIZE=262144000&lt;/span&gt;            &lt;span class="c1"&gt;# 附件上限&lt;/span&gt;
      &lt;span class="pi"&gt;-&lt;/span&gt; &lt;span class="s"&gt;FILE_STORAGE_IMPORT_MAX_SIZE=262144000&lt;/span&gt;            &lt;span class="c1"&gt;# 單篇匯入&lt;/span&gt;
      &lt;span class="pi"&gt;-&lt;/span&gt; &lt;span class="s"&gt;FILE_STORAGE_WORKSPACE_IMPORT_MAX_SIZE=262144000&lt;/span&gt;  &lt;span class="c1"&gt;# zip 整包匯入 (關鍵)&lt;/span&gt;

      &lt;span class="c1"&gt;# --- 登入: Gitea OIDC (選填) -------------------------------------------&lt;/span&gt;
      &lt;span class="c1"&gt;# 任何相容 OIDC 供應商皆可 (Gitea / Keycloak / Authentik / Google...)。&lt;/span&gt;
      &lt;span class="c1"&gt;# ★ Ubuntu 版注意：OIDC 主機可在「另一台」機器，確認這台 Ubuntu 連得到。&lt;/span&gt;
      &lt;span class="pi"&gt;-&lt;/span&gt; &lt;span class="s"&gt;OIDC_CLIENT_ID=&amp;lt;OIDC_CLIENT_ID&amp;gt;&lt;/span&gt;
      &lt;span class="pi"&gt;-&lt;/span&gt; &lt;span class="s"&gt;OIDC_CLIENT_SECRET=&amp;lt;OIDC_CLIENT_SECRET&amp;gt;&lt;/span&gt;
      &lt;span class="pi"&gt;-&lt;/span&gt; &lt;span class="s"&gt;OIDC_AUTH_URI=http://&amp;lt;OIDC主機&amp;gt;/login/oauth/authorize&lt;/span&gt;
      &lt;span class="pi"&gt;-&lt;/span&gt; &lt;span class="s"&gt;OIDC_TOKEN_URI=http://&amp;lt;OIDC主機&amp;gt;/login/oauth/access_token&lt;/span&gt;
      &lt;span class="pi"&gt;-&lt;/span&gt; &lt;span class="s"&gt;OIDC_USERINFO_URI=http://&amp;lt;OIDC主機&amp;gt;/login/oauth/userinfo&lt;/span&gt;
      &lt;span class="pi"&gt;-&lt;/span&gt; &lt;span class="s"&gt;OIDC_USERNAME_CLAIM=preferred_username&lt;/span&gt;   &lt;span class="c1"&gt;# 用哪個欄位當帳號&lt;/span&gt;
      &lt;span class="pi"&gt;-&lt;/span&gt; &lt;span class="s"&gt;OIDC_DISPLAY_NAME=Gitea&lt;/span&gt;                   &lt;span class="c1"&gt;# 登入按鈕顯示文字&lt;/span&gt;
      &lt;span class="pi"&gt;-&lt;/span&gt; &lt;span class="s"&gt;OIDC_SCOPES=openid profile email&lt;/span&gt;

      &lt;span class="c1"&gt;# --- SMTP 寄信 (選填) --------------------------------------------------&lt;/span&gt;
      &lt;span class="c1"&gt;# 用途：magic-link 登入信 + 通知信。&lt;/span&gt;
      &lt;span class="c1"&gt;# Gmail 範例：密碼要用「應用程式密碼」,不是帳號密碼。&lt;/span&gt;
      &lt;span class="c1"&gt;# (Google 帳號 → 安全性 → 兩步驟驗證 → 應用程式密碼)&lt;/span&gt;
      &lt;span class="pi"&gt;-&lt;/span&gt; &lt;span class="s"&gt;SMTP_HOST=smtp.gmail.com&lt;/span&gt;
      &lt;span class="pi"&gt;-&lt;/span&gt; &lt;span class="s"&gt;SMTP_PORT=587&lt;/span&gt;
      &lt;span class="pi"&gt;-&lt;/span&gt; &lt;span class="s"&gt;SMTP_SECURE=false&lt;/span&gt;    &lt;span class="c1"&gt;# 587 用 STARTTLS，所以 false&lt;/span&gt;
      &lt;span class="pi"&gt;-&lt;/span&gt; &lt;span class="s"&gt;SMTP_USERNAME=&amp;lt;你的gmail@gmail.com&amp;gt;&lt;/span&gt;
      &lt;span class="pi"&gt;-&lt;/span&gt; &lt;span class="s"&gt;SMTP_PASSWORD=&amp;lt;Gmail 應用程式密碼&amp;gt;&lt;/span&gt;
      &lt;span class="pi"&gt;-&lt;/span&gt; &lt;span class="s"&gt;SMTP_FROM_EMAIL=&amp;lt;你的gmail@gmail.com&amp;gt;&lt;/span&gt;
      &lt;span class="pi"&gt;-&lt;/span&gt; &lt;span class="s"&gt;SMTP_REPLY_EMAIL=&amp;lt;你的gmail@gmail.com&amp;gt;&lt;/span&gt;

    &lt;span class="na"&gt;volumes&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt;
      &lt;span class="c1"&gt;# 存的是「附件/上傳檔」(圖片、PDF...)，不是文章本體 (文章在 PostgreSQL)。&lt;/span&gt;
      &lt;span class="c1"&gt;# ★ 用 bind mount: 附件直接落在專案資料夾 ./data,搬家複製即帶走。&lt;/span&gt;
      &lt;span class="c1"&gt;#   對比 named volume (outline_data:) 要 tar 才能撈出，bind 好搬很多。&lt;/span&gt;
      &lt;span class="c1"&gt;#   注意：DB 不要 bind，DB 檔不能直接 copy，一律用 pg_dump 備份。&lt;/span&gt;
      &lt;span class="pi"&gt;-&lt;/span&gt; &lt;span class="s"&gt;./data:/var/lib/outline/data&lt;/span&gt;
    &lt;span class="na"&gt;depends_on&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt;
      &lt;span class="na"&gt;postgres&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt;
        &lt;span class="na"&gt;condition&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="s"&gt;service_healthy&lt;/span&gt;   &lt;span class="c1"&gt;# 等 DB 健康檢查通過才啟動&lt;/span&gt;
      &lt;span class="na"&gt;redis&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt;
        &lt;span class="na"&gt;condition&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="s"&gt;service_healthy&lt;/span&gt;   &lt;span class="c1"&gt;# 等 Redis 就緒&lt;/span&gt;

  &lt;span class="c1"&gt;# ---------------------------------------------------------------------------&lt;/span&gt;
  &lt;span class="c1"&gt;# Redis — 內建獨立 service (★ Ubuntu 版才有,基本版用外部 Redis)&lt;/span&gt;
  &lt;span class="c1"&gt;# ---------------------------------------------------------------------------&lt;/span&gt;
  &lt;span class="na"&gt;redis&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt;
    &lt;span class="na"&gt;image&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="s"&gt;redis:7-alpine&lt;/span&gt;
    &lt;span class="na"&gt;container_name&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="s"&gt;outline_redis&lt;/span&gt;
    &lt;span class="na"&gt;restart&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="s"&gt;unless-stopped&lt;/span&gt;
    &lt;span class="na"&gt;volumes&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt;
      &lt;span class="pi"&gt;-&lt;/span&gt; &lt;span class="s"&gt;redis_data:/data&lt;/span&gt;   &lt;span class="c1"&gt;# 持久化 (選用，Outline 主要當快取，掉了也能重建)&lt;/span&gt;
    &lt;span class="na"&gt;healthcheck&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt;
      &lt;span class="na"&gt;test&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="pi"&gt;[&lt;/span&gt;&lt;span class="s2"&gt;"&lt;/span&gt;&lt;span class="s"&gt;CMD"&lt;/span&gt;&lt;span class="pi"&gt;,&lt;/span&gt; &lt;span class="s2"&gt;"&lt;/span&gt;&lt;span class="s"&gt;redis-cli"&lt;/span&gt;&lt;span class="pi"&gt;,&lt;/span&gt; &lt;span class="s2"&gt;"&lt;/span&gt;&lt;span class="s"&gt;ping"&lt;/span&gt;&lt;span class="pi"&gt;]&lt;/span&gt;   &lt;span class="c1"&gt;# 回 PONG 才算就緒&lt;/span&gt;
      &lt;span class="na"&gt;interval&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="s"&gt;10s&lt;/span&gt;
      &lt;span class="na"&gt;timeout&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="s"&gt;5s&lt;/span&gt;
      &lt;span class="na"&gt;retries&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="m"&gt;5&lt;/span&gt;

  &lt;span class="c1"&gt;# ---------------------------------------------------------------------------&lt;/span&gt;
  &lt;span class="c1"&gt;# Caddy — 反向代理，自動處理 HTTPS 憑證&lt;/span&gt;
  &lt;span class="c1"&gt;# ---------------------------------------------------------------------------&lt;/span&gt;
  &lt;span class="na"&gt;caddy&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt;
    &lt;span class="na"&gt;image&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="s"&gt;caddy:2&lt;/span&gt;
    &lt;span class="na"&gt;container_name&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="s"&gt;outline_caddy&lt;/span&gt;
    &lt;span class="na"&gt;restart&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="s"&gt;unless-stopped&lt;/span&gt;
    &lt;span class="na"&gt;ports&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt;
      &lt;span class="pi"&gt;-&lt;/span&gt; &lt;span class="s2"&gt;"&lt;/span&gt;&lt;span class="s"&gt;8443:8443"&lt;/span&gt;   &lt;span class="c1"&gt;# 對外唯一開的埠 (主機:容器)。反代規則寫在 Caddyfile。&lt;/span&gt;
    &lt;span class="na"&gt;volumes&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt;
      &lt;span class="pi"&gt;-&lt;/span&gt; &lt;span class="s"&gt;./Caddyfile:/etc/caddy/Caddyfile:ro&lt;/span&gt;   &lt;span class="c1"&gt;# :ro = 唯讀掛載&lt;/span&gt;
      &lt;span class="pi"&gt;-&lt;/span&gt; &lt;span class="s"&gt;caddy_data:/data&lt;/span&gt;       &lt;span class="c1"&gt;# 存 TLS 憑證，別刪，刪了要重新申請&lt;/span&gt;
      &lt;span class="pi"&gt;-&lt;/span&gt; &lt;span class="s"&gt;caddy_config:/config&lt;/span&gt;
    &lt;span class="na"&gt;depends_on&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt;
      &lt;span class="pi"&gt;-&lt;/span&gt; &lt;span class="s"&gt;outline&lt;/span&gt;

  &lt;span class="c1"&gt;# ---------------------------------------------------------------------------&lt;/span&gt;
  &lt;span class="c1"&gt;# PostgreSQL — pgvector 映像 (支援向量搜尋)&lt;/span&gt;
  &lt;span class="c1"&gt;# ---------------------------------------------------------------------------&lt;/span&gt;
  &lt;span class="na"&gt;postgres&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt;
    &lt;span class="na"&gt;image&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="s"&gt;pgvector/pgvector:pg16&lt;/span&gt;
    &lt;span class="na"&gt;container_name&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="s"&gt;outline_postgres&lt;/span&gt;
    &lt;span class="na"&gt;restart&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="s"&gt;unless-stopped&lt;/span&gt;
    &lt;span class="na"&gt;environment&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt;
      &lt;span class="c1"&gt;# 這三個要跟上面 DATABASE_URL 的帳號/密碼/DB名一致。&lt;/span&gt;
      &lt;span class="pi"&gt;-&lt;/span&gt; &lt;span class="s"&gt;POSTGRES_USER=outline_user&lt;/span&gt;
      &lt;span class="pi"&gt;-&lt;/span&gt; &lt;span class="s"&gt;POSTGRES_PASSWORD=&amp;lt;DB_密碼&amp;gt;&lt;/span&gt;
      &lt;span class="pi"&gt;-&lt;/span&gt; &lt;span class="s"&gt;POSTGRES_DB=outline&lt;/span&gt;
    &lt;span class="na"&gt;volumes&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt;
      &lt;span class="pi"&gt;-&lt;/span&gt; &lt;span class="s"&gt;pg_data:/var/lib/postgresql/data&lt;/span&gt;   &lt;span class="c1"&gt;# 資料庫實體資料，千萬別誤刪&lt;/span&gt;
    &lt;span class="na"&gt;ports&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt;
      &lt;span class="c1"&gt;# 只綁 127.0.0.1 = 僅本機可連，不對外曝露 DB。安全做法。&lt;/span&gt;
      &lt;span class="pi"&gt;-&lt;/span&gt; &lt;span class="s2"&gt;"&lt;/span&gt;&lt;span class="s"&gt;127.0.0.1:5432:5432"&lt;/span&gt;
    &lt;span class="na"&gt;healthcheck&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt;
      &lt;span class="na"&gt;test&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="pi"&gt;[&lt;/span&gt;&lt;span class="s2"&gt;"&lt;/span&gt;&lt;span class="s"&gt;CMD-SHELL"&lt;/span&gt;&lt;span class="pi"&gt;,&lt;/span&gt; &lt;span class="s2"&gt;"&lt;/span&gt;&lt;span class="s"&gt;pg_isready&lt;/span&gt;&lt;span class="nv"&gt; &lt;/span&gt;&lt;span class="s"&gt;-U&lt;/span&gt;&lt;span class="nv"&gt; &lt;/span&gt;&lt;span class="s"&gt;outline_user&lt;/span&gt;&lt;span class="nv"&gt; &lt;/span&gt;&lt;span class="s"&gt;-d&lt;/span&gt;&lt;span class="nv"&gt; &lt;/span&gt;&lt;span class="s"&gt;outline"&lt;/span&gt;&lt;span class="pi"&gt;]&lt;/span&gt;
      &lt;span class="na"&gt;interval&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="s"&gt;10s&lt;/span&gt;
      &lt;span class="na"&gt;timeout&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="s"&gt;5s&lt;/span&gt;
      &lt;span class="na"&gt;retries&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="m"&gt;5&lt;/span&gt;

&lt;span class="c1"&gt;# -----------------------------------------------------------------------------&lt;/span&gt;
&lt;span class="c1"&gt;# 具名 volume — 由 Docker 管理，容器刪掉資料還在。&lt;/span&gt;
&lt;span class="c1"&gt;# -----------------------------------------------------------------------------&lt;/span&gt;
&lt;span class="na"&gt;volumes&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt;
  &lt;span class="c1"&gt;# outline_data 改用 bind mount (./data)，不在這裡宣告。&lt;/span&gt;
  &lt;span class="na"&gt;pg_data&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt;
  &lt;span class="na"&gt;redis_data&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt;
  &lt;span class="na"&gt;caddy_data&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt;
  &lt;span class="na"&gt;caddy_config&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;要修改的部份，如：密鑰、DB、OIDC、SMTP，都與 Windows 版填法完全相同。&lt;/p&gt;

&lt;h3&gt;
  
  
  啟動
&lt;/h3&gt;

&lt;p&gt;在 &lt;code&gt;docker-compose.yml&lt;/code&gt; 所在資料夾開終端機：&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight shell"&gt;&lt;code&gt;docker compose up &lt;span class="nt"&gt;-d&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;確認與登入流程跟 Windows 版一樣：瀏覽器打開 &lt;code&gt;https://&amp;lt;你的IP&amp;gt;:3001&lt;/code&gt;，遇到憑證警告點「繼續前往」，再用 Gitea 登入。&lt;/p&gt;




&lt;h2&gt;
  
  
  結語
&lt;/h2&gt;

&lt;p&gt;照著上面的步驟做，我們就會有一套 &lt;strong&gt;完全自架 + 免費 + 可以用 MCP 接上 AI&lt;/strong&gt; 的 Outline Wiki。&lt;/p&gt;

&lt;p&gt;怎麼用 MCP 接上 Claude、Codex，下一篇會說明。&lt;/p&gt;

</description>
      <category>outline</category>
      <category>ai</category>
      <category>gitea</category>
      <category>docker</category>
    </item>
  </channel>
</rss>
