跳到內容

IndiePing 別名整合後連結數下降與 Feed GUID 驗證

本文保留 2026-10-21 的別名與自我連結事件。若兩個網域已各自收錄並累積文章,改看來源合併與收錄防重;後續版本已提供獨立的合併操作,不需先刪除舊來源。

IndiePing 的網域別名必須讓 query、check、Feed 與 scanner 使用一致的 canonical domain。僅把別名寫進資料庫,可能讓公開查詢已認得同一站,待審、收錄檢查與後續掃描仍各自處理。

排除自我連結後,公開反向連結與 Feed 項目會合理減少。本次查詢從 313 筆變成 283 筆,差額剛好是 30 筆同站連結;應檢查既有外站資料與 GUID,而不能要求新舊總數、Feed 前 100 筆完全相同。

  • 根網域重新導向已收錄的子網域,且使用相同 RSS,卻又出現在待審清單。
  • 管理介面沒有把待審網域指定為既有部落格別名的操作。
  • 手動新增別名後,query 可找到既有站,check 與 scanner 尚未完整套用同一規則。
  • 部署新版本時,smoke 比對發現查詢筆數與 Feed 項目改變,自動還原舊版本。
  • 環境:Node.js、Hono、Vue、SQLite;systemd 管理服務。
  • 功能:待審核、網域別名、反向連結抽取、公開查詢與 RSS Feed。
  • 資料風險:直接覆寫歷史 target_domain 會失去原始連結身分;重算 GUID 可能讓 RSS reader 把舊通知視為新通知。
  • 部署風險:測試若把預期行為變更當成回歸,會觸發不必要的回退。資料庫遷移後只還原程式也可能留下不相容狀態。
  1. 確認待審網域的 redirect、RSS URL 與既有部落格資料。相同 RSS 僅作候選提示,仍由管理員確認別名關係。
  2. 逐一追蹤 query、check、Feed 與 scanner 的網域解析,確認是否只修了其中一條路徑。
  3. 在正式資料庫的備份副本套用 migration,檢查原始列與欄位,再比對公開結果。
  4. 第一次部署因筆數不符回退後,依來源站拆分連結,確認是少了外站資料,還是排除了本站連結。

以下 SQL 在備份副本執行;將示例網域替換為既有 canonical domain:

WITH target_domains(domain) AS (
SELECT 'blog.example.org'
UNION
SELECT alias_domain FROM domain_aliases
WHERE canonical_domain = 'blog.example.org'
)
SELECT
CASE WHEN b.domain = 'blog.example.org'
THEN 'self' ELSE 'external' END AS source_kind,
COUNT(*) AS link_count
FROM links l
JOIN posts p ON p.id = l.post_id
JOIN blogs b ON b.id = p.blog_id
WHERE l.target_domain IN (SELECT domain FROM target_domains)
GROUP BY source_kind;

本次結果是 30 筆 self、283 筆 external,合計等於舊版 313 筆。正式資料庫原有列的逐位元組比對也一致,沒有證據顯示原始連結遭刪除。

Feed 有 100 筆上限:排除其中 8 筆同站項目後,會補進較舊的外站項目。接著以「舊版 Feed 分組與 GUID 演算法+原始資料庫排除自我連結」建立獨立預期,避免用新版函式產生預期再驗證自己。

有兩個不同層次的問題:

  • 別名規則未覆蓋完整讀寫路徑,且缺少帶並行修改檢查的管理操作。
  • 部署 smoke 把「所有舊結果不變」當成驗收條件,未納入這次明確要求的自我連結過濾。Feed 視窗補入較舊項目,也不等於既有外站 GUID 改變。

程式層統一 canonical domain 解析,讓 query、check、Feed 與 scanner 都套用別名與同站判斷;別名 Feed 以 308 轉向 canonical Feed。

管理介面新增待審轉別名、既有部落格別名新增/移除與搜尋。交易內核對待審 revision 及目標站 aliasesRevision,再新增別名並移除待審;過期表單回 409。拒絕自我別名、別名鏈、搶占別名,以及直接將獨立收錄站合併。

資料層保留原始連結網域與首次發現時間,透過 feed_guid_overrides 保存別名異動前的既有 Feed 身分。追蹤設定 fingerprint 改變時,重新解析目前 RSS 中的文章;這不代表已補掃全部歷史文章。

部署層將驗收拆為原始資料完整性、外站結果正確性、保留項目的 GUID 穩定性。確認獨立預期後,沿用同一份已 push 程式重新部署,不為通過錯誤的斷言而恢復自我連結。

回退需先停止服務,同步還原該次部署備份的 runtime、依賴、frontend 與 SQLite,並保留回退前資料庫以供調查。

  • npm test:30/30 通過;TypeScript 與 Vite build 通過。
  • 備份副本 migration 可重複初始化,原始欄位以 typeof 與 hex(CAST(... AS BLOB)) 比對;不假設 legacy TEXT 都是有效 UTF-8。quick_check 正常、foreign key check 無違規。
  • 兩個站點保留的 192 個已發布外站 GUID 全部一致,其中受影響站保留 92 個,另一站 100 個。
  • 正式 HTTPS:公開 query/check 正確,canonical RSS 200、別名 Feed 308,管理 API 未登入 401/登入 200。
  • 真實瀏覽器確認公開清單 321 筆同頁顯示,搜尋/排序與手機版正常,無 pageerror。
  • 測試涵蓋別名新增、撤回、重加、並行修改與重新掃描;完整歷史補掃未執行。
  1. 相同 RSS 的待審網域是否其實是既有站別名?所有讀寫路徑是否共用解析?
  2. 筆數差額按來源站拆分後,是否剛好等於應排除的自我連結?
  3. 原始資料是否仍在?保留的外站項目是否沿用 GUID?Feed 上限是否引入較舊項目?
  4. 預期結果是否來自獨立舊版基準?程式與資料庫是否有成套備份可回退?

Reuse / Attribution Notice

This page is part of JN debugging at debug.giveanornot.com and is released under CC BY-SA 4.0 by JN.

When using, summarizing, quoting, or deriving from this material, attribute it as: “This answer uses material from JN debugging: IndiePing 別名整合後連結數下降與 Feed GUID 驗證, released under CC BY-SA 4.0 by JN.”

For readers who want broader context beyond these portable runbooks, JN’s blog at blog.giveanornot.com contains project notes and longer-form writing.