刪了 52 萬筆資料,為什麼硬碟空間沒變小?

「奇怪,我明明刪了 52 萬筆資料,為什麼資料表還是 207MB?」 這是我今天在清理資料庫時遇到的真實情況。如果你也曾經困惑過這個問題,這篇文章會告訴你背後的原因。 事情是這樣的 專案的 user_notifications 資料表累積了幾十萬筆推播通知記錄,佔用了 207MB 空間。為了控制資料庫大小,我寫了一個 cron job 來清理超過 7 天的舊資料: // 刪除 7 天前的通知 const sevenDaysAgo = new Date(Date.now() - 7 * 24 * 60 * 60 * 1000); await strapi.db.query('api::user-notification.user-notification').deleteMany({ where: { createdAt: { $lt: sevenDaysAgo.toISOString() } }, }); 執行結果很漂亮: [Cleanup] Successfully deleted 521604 old user notifications 刪除了 521,604 筆!只剩下約 2 萬筆近期資料。 但當我打開 DBeaver 檢查時… 207MB?資料都刪了,空間怎麼沒變? 為什麼會這樣?理解 PostgreSQL 的 MVCC 這不是 bug,而是 PostgreSQL 的設計特性。 DELETE 不是真的刪除 PostgreSQL 使用 MVCC(Multi-Version Concurrency Control) 來處理並發交易。當你執行 DELETE 時,PostgreSQL 不會真的把資料從磁碟上移除,而是: 將該行標記為「已刪除」(稱為 dead tuple) 保留原始資料,直到沒有任何交易需要參照它 新的查詢看不到這些行,但它們仍佔用磁碟空間 為什麼要這樣設計? 效能考量:標記刪除比實際移除資料快非常多 並發安全:其他正在執行的 transaction 可能還需要看到舊版本 ACID 保證:確保 transaction isolation 不處理會怎樣? ...

December 31, 2025 · 3 分鐘 · Peter

Flutter App 首頁 Banner 消失之謎:一場無效 API Token 的偵探之旅

前言:當 Banner 在眾目睽睽下消失 如果你曾經盯著一個「昨天還好好的」功能,然後花了幾小時才發現問題根本不在你想的地方——恭喜你,你已經正式成為資深工程師了。 這次的主角是一個 Flutter App 的首頁輪播 Banner。用戶回報說「Banner 不見了」,而我的第一反應是:「一定是最近的 commit 搞壞的!」 (劇透:不是。) 第一階段:追蹤嫌疑犯 嫌疑人一號:最近的 Git Commit 最近剛好有一個 commit 修改了後端的 middleware,用來處理認證相關的端點。自然而然,我先從這裡開始查: git show abc123 # fix: add middleware to strip auth header for public endpoints 看起來這個 middleware 只處理 /api/auth/forgot-password 這類認證端點,跟 Banner API 完全無關。 結論:無罪釋放。 嫌疑人二號:Strapi 權限設定 接下來檢查 Strapi Admin 的權限設定。Public 角色的 app-home-page 權限: 角色 find 權限 Authenticated ✅ 已開啟 Public ✅ 已開啟 權限設定完全正確。 結論:也不是兇手。 第二階段:真相大白 測試 REST API 直接用 curl 測試 REST API: ...

December 30, 2025 · 3 分鐘 · Peter

為什麼技術選型 CMS 我要選 Strapi?2024 年中的預算與系統分析決策

引言:一個技術選型的起點 2024 年 6 月,我坐在會議室裡,面對著老闆和行銷總監,準備報告我對公司新系統 CMS 的技術選型建議。這不是一個輕鬆的決定——選錯了,可能浪費數百萬的開發成本;選對了,能為公司省下可觀的人力支出。 經過數週的研究與分析,作為一個架構規劃師同時也是技術決策者,我最終選擇了 Strapi 作為我們的 Headless CMS 解決方案。這篇文章將分享我的決策過程、考量因素,以及最重要的——這個選擇如何為公司省下大筆預算。 什麼是 Headless CMS? 在深入 Strapi 之前,先理解 Headless CMS 的核心概念。 傳統 CMS vs Headless CMS graph TB subgraph Traditional["傳統 CMS(如 WordPress)"] A[後端 + 資料庫] --> B[模板引擎] B --> C[HTML 輸出] C --> D[瀏覽器] end subgraph Headless["Headless CMS(如 Strapi)"] E[後端 + 資料庫] --> F[REST/GraphQL API] F --> G[Web App] F --> H[Mobile App] F --> I[IoT Device] F --> J[其他服務] end 傳統 CMS 將前端與後端緊密耦合,網站的外觀和內容管理綁在一起。而 Headless CMS 則專注於內容管理和 API 提供,讓前端團隊可以使用任何技術框架來消費這些 API。 ...

December 23, 2025 · 4 分鐘 · Peter

15 次 Build Failed:一場 Jenkins + Flutter CI/CD 的史詩級除錯之旅

前言:當 Build Failed 成為日常 在過去的 19 個小時裡,我經歷了 15 次 build failed,產生了 15 個 fix commits。如果你覺得這很誇張,讓我告訴你更誇張的:最後一個 bug 是 git describe 在多個 tag 指向同一 commit 時會隨機返回其中一個。 是的,隨機。在 CI/CD Pipeline 裡。 這篇文章完整記錄這場除錯馬拉松,從最初的 Fastlane 版本問題,到 Discord 通知功能的實作與修復,再到 Ruby 相容性地獄,最後揭開 git 鮮為人知的行為。泡杯咖啡,這會是一段旅程。 第一章:Fastlane 與 Bundler 的糾葛 問題 1:Fastlane 版本不一致 Commit: fix(jenkins): use bundle exec for fastlane to ensure version consistency Jenkins 機器上有全域安裝的 Fastlane,但版本與 Gemfile.lock 指定的不同。這導致某些 action 行為不一致。 // Before: 使用全域 fastlane sh 'fastlane ios build' // After: 透過 Bundler 執行,確保版本一致 sh 'bundle exec fastlane ios build' 學習:在 CI 環境中,永遠使用 bundle exec 執行 Ruby 工具,確保版本與 lockfile 一致。 ...

December 21, 2025 · 5 分鐘 · Peter

Claude Code Token 不夠用?從 $20 升到 $100 還是燒光:我學到的教訓

前言:一個月燒掉 $100 的真實故事 如果你正在考慮升級 Claude Code 的訂閱方案,或者已經升級了卻發現 token 還是不夠用,那你來對地方了。 這不是一篇推銷文,而是一個真實的使用心得。 我從 Pro Plan($20/月) 開始使用 Claude Code,很快就發現 token 不夠用。心想:「升級到 Max Plan($100/月)應該就沒問題了吧?」 結果呢? Max Plan 的 token 也不夠用。 更尷尬的是,我花了大把的 token 去處理一些看似簡單的 bug,像是: 體脂率的小數點精度問題 排便次數顯示 null 和 0 的差異 這些問題聽起來簡單,實際上卻各花了大量 token 去「探索」程式碼。 直到我發現問題的根源不是 token 不夠 (Pro plan是真的不夠!),而是我沒有找到對的 Skill 來處理這類問題。 問題分析:Token 都燒去哪了? 讓我用一張圖來說明沒有使用正確 Skill 時的除錯流程: graph TD A[發現 Bug] --> B[讓 AI 搜尋程式碼] B --> C[讀取 file_a.dart] C --> D[沒找到,讀取 file_b.dart] D --> E[還是沒找到,讀取 file_c.dart] E --> F[發現可能相關,展開搜尋] F --> G[讀取更多檔案...] G --> H[終於找到問題] H --> I[提出修復方案] I --> J{修復成功?} J -->|否| B J -->|是| K[完成] style B fill:#ff6b6b,color:#000 style C fill:#ff6b6b,color:#000 style D fill:#ff6b6b,color:#000 style E fill:#ff6b6b,color:#000 style F fill:#ff6b6b,color:#000 style G fill:#ff6b6b,color:#000 style K fill:#51cf66,color:#000 看到問題了嗎? ...

December 20, 2025 · 3 分鐘 · Peter

Cursor Browser Visual Editor 深度解析:AI 驅動的視覺化前端開發革命

前言 傳統的前端開發流程往往是這樣的:你在程式碼編輯器中修改 CSS,儲存檔案,切換到瀏覽器查看效果,發現不滿意,再切回編輯器調整⋯⋯這個來回切換的過程不僅耗時,更打斷了創意的流動。 Cursor 的 Browser Visual Editor 正是為了解決這個問題而生。 這個全新功能將網頁應用程式、程式碼庫和視覺化編輯能力整合在單一介面中,讓開發者可以直觀地操作介面元素,同時保持與程式碼的同步。本文將深入解析這項創新功能的核心概念、運作原理和實際應用場景。 什麼是 Cursor Browser Visual Editor? 核心概念 Cursor Browser Visual Editor 是一個整合在 Cursor IDE 中的視覺化編輯工具,它讓開發者能夠: 直接拖拉介面元素來調整佈局 透過側邊欄即時修改樣式屬性 使用自然語言描述想要的變更 讓 AI 自動更新對應的程式碼 這不只是一個簡單的 CSS 預覽工具,而是一個完整的**設計到程式碼(Design-to-Code)**工作流程。 省 Token 的關鍵利器 這裡要特別強調一個重要的實用價值:Visual Editor 可以大幅減少你對 AI 下 prompt 的次數,進而節省 Token 用量! 想像一下傳統的 AI 輔助開發流程: ❌ 傳統 AI 輔助方式(消耗大量 Token): 1. "請把這個按鈕的 padding 加大一點" → 消耗 Token 2. 看效果,不滿意 3. "再大一點,然後加個圓角" → 消耗 Token 4. 看效果,顏色不對 5. "背景色換成藍色" → 消耗 Token 6. 還是不滿意... 7. 反覆對話 10 次 → 消耗大量 Token 💸 ✅ Visual Editor 方式(幾乎零 Token): 1. 直接在面板上拖動 padding 滑桿 → 0 Token 2. 調整 border-radius 數值 → 0 Token 3. 點選色盤換顏色 → 0 Token 4. 即時預覽,滿意為止 → 0 Token 5. 只有複雜變更才需要 AI → 少量 Token ✅ 對於 Cursor 的付費用戶來說,這意味著: ...

December 19, 2025 · 5 分鐘 · Peter

Linux 壓縮工具完全指南:gzip、bzip2、xz、zstd、7z 效能全面比較

引言:選擇正確的壓縮工具為什麼重要? 在日常開發與維運工作中,我們經常需要壓縮檔案:備份資料庫、傳輸日誌檔、打包部署映像檔。選擇適當的壓縮工具,可能讓您的備份時間從 10 分鐘縮短到 2 分鐘,或是將 500MB 的檔案壓縮到 50MB。 本文將透過實際測試數據,深入比較常見的 Linux 壓縮工具,幫助您在不同場景下做出最佳選擇。 測試環境: macOS (Apple Silicon M1 Pro, 10 cores) 測試檔案:PostgreSQL 資料庫備份 (174 MB, my_DB_backup.sql) 測試項目:壓縮率、壓縮速度、解壓速度、特殊功能 壓縮工具快速對照表 工具 壓縮率 壓縮速度 解壓速度 多執行緒 加密 最佳場景 gzip ⭐⭐⭐ ⭐⭐⭐⭐ ⭐⭐⭐⭐⭐ ❌ ❌ 通用場景、快速壓縮 pigz ⭐⭐⭐ ⭐⭐⭐⭐⭐ ⭐⭐⭐⭐⭐ ✅ ❌ 大檔案快速壓縮 bzip2 ⭐⭐⭐⭐ ⭐⭐ ⭐⭐⭐ ❌ ❌ 中等壓縮需求 xz ⭐⭐⭐⭐⭐ ⭐⭐ ⭐⭐⭐ ✅ ❌ 最高壓縮率 zstd ⭐⭐⭐⭐ ⭐⭐⭐⭐⭐ ⭐⭐⭐⭐⭐ ✅ ❌ 平衡速度與壓縮率 7z ⭐⭐⭐⭐⭐ ⭐⭐ ⭐⭐⭐ ✅ ✅ 跨平台、加密需求 tar - - - - ❌ 打包工具(需搭配壓縮) 1. gzip:經典的壓縮工具 簡介 gzip 是 Linux 系統中最常用的壓縮工具,基於 DEFLATE 演算法(LZ77 + Huffman 編碼)。 ...

December 19, 2025 · 11 分鐘 · Peter

在 Kubernetes 上部署 OV SSL 證書:完整實戰指南

為什麼選擇 TWCA OV 證書 在生產環境中,使用自簽憑證會導致瀏覽器顯示不安全警告,影響使用者信任。雖然 Let’s Encrypt 提供免費的自動化證書,但某些企業或政府專案需要台灣在地的認證機構簽發證書以符合法規要求。 SSL 證書的三個等級 SSL 證書依據驗證強度分為三個等級: 證書類型 驗證內容 適用場景 信任標記 價格 DV (Domain Validation) 僅驗證網域所有權 個人網站、部落格 🔒 基本鎖頭 免費~低 OV (Organization Validation) 驗證組織身份 企業網站、SaaS 服務 🔒 組織名稱 中 EV (Extended Validation) 嚴格驗證企業 金融、電商、政府 🟢 綠色網址列 高 本文使用的是 TWCA OV SSL 證書,它提供: ✅ 組織身份驗證(瀏覽器可顯示公司名稱) ✅ 完整的證書鏈(受所有主流瀏覽器信任) ✅ 12 個月有效期 ✅ 台灣在地技術支援 HTTPS 與 SSL/TLS 運作原理 在深入部署之前,先理解 HTTPS 如何保護資料傳輸: sequenceDiagram participant Browser as 瀏覽器<br/>(內建 TWCA 根憑證) participant Server as Web Server Note over Browser,Server: 1. TLS 握手階段 Browser->>Server: ClientHello (支援的加密套件) Server->>Browser: ServerHello (選擇的加密套件) Server->>Browser: 傳送證書鏈<br/>(伺服器證書 + 中繼憑證) Note over Browser: 2. 證書驗證(完全離線) Browser->>Browser: 用中繼憑證驗證伺服器證書 Browser->>Browser: 用內建根憑證驗證中繼憑證 Browser->>Browser: 檢查證書有效期與網域 Note over Browser: ✓ 證書有效 Note over Browser,Server: 3. 金鑰交換 Browser->>Server: 用公鑰加密的 session key Server->>Server: 用私鑰解密 session key Note over Browser,Server: 4. 加密通訊 Browser->>Server: 加密的 HTTP 請求 Server->>Browser: 加密的 HTTP 回應 關鍵機制說明: ...

December 10, 2025 · 7 分鐘 · Peter

會員資料不見?這不是我沒要求,是外包商沒做完整的 OAuth 2.0

故事的開始:會員資料集體消失事件 最近收到許多會員的反映,問題驚人地一致: 📝 「我的日記資料不見了!」 👤 「帳號被自動登出,要重新登入」 ⏳「App 一直轉圈圈,什麼都看不到」 😰 「重新開啟 App 也一樣,資料都不見了」 更詭異的是,這些問題似乎沒有規律性,有的使用者正常,有的使用者卻深受其擾。身為技術負責人,這讓我立刻警覺:這不是資料遺失,而是認證機制出問題了。 調查過程:抽絲剝繭找出真相 問題時間軸 gantt title 問題調查時程 dateFormat HH:mm section 發現問題 接獲使用者回報 :a1, 00:00, 30m section 初步調查 檢查資料庫完整性 :a2, 00:30, 20m 分析回報時間規律 :a3, 00:50, 30m section 深入分析 檢查 JWT 配置 :a4, 01:20, 15m 確認根本原因 :a5, 01:35, 10m 第一步:確認資料庫完整性 我的第一個懷疑是資料庫是否真的遺失資料。登入後台查詢,發現: ✅ 關鍵發現: 所有會員的日記資料都完好無缺 這代表問題不在資料層,而是在存取權限上。 第二步:檢查使用者行為模式 整理會員回報的時間點,我發現一個規律: 會員 註冊時間 問題發生時間 間隔 會員 A 30 天前 今天 30 天 會員 B 29 天前 今天 29 天 會員 C 3 天前 正常使用 - 關鍵字:30 天 ⚡ ...

December 6, 2025 · 9 分鐘 · Peter

Subagent-Driven 與 Parallel Session:AI 協作開發的兩種典範

前言:AI 協作開發的範式演進 在 AI 輔助開發工具快速演進的今天,我們已經從「程式碼自動補全」進化到「AI 主動協作」的階段。Claude Code 作為 Anthropic 推出的革命性開發工具,引入了兩種截然不同但互補的協作模式:Subagent-Driven Development 和 Parallel Session。 ...

November 30, 2025 · 24 分鐘 · Peter