SteamSaleChecker
Live自建的 Steam 特價追蹤站:後端定時抓 Steam 官方端點與 GamerPower、自建價格歷史(算「本站追蹤以來史低」)烤成靜態 JSON,前端 Astro 以深色電競風呈現;支援 Discord 登入、跨裝置願望清單與降價/目標價的 Discord 通知。
專案概述
一套自建的 Steam 特價追蹤站,定位在「SteamDB 風的特價榜 + 自建價格歷史 + Discord 通知」。後端 worker(Node + TypeScript、cron 約每 30 分)在 server 端呼叫 Steam 官方商店端點(featuredcategories / appdetails / 特價搜尋,免金鑰、台灣區 cc=tw)與 GamerPower(永久入庫的免費遊戲/DLC),把每輪台幣價寫進 SQLite 累積成「本站追蹤以來」的價格走勢與史低(observed low),再烤成 deals / free / meta 三份靜態 JSON;可選配 IsThereAnyDeal API 以真實台幣史低校正冷啟動初值。前端是 Astro 靜態站(深色電競風、繁中/英 i18n、深淺主題、PWA),提供可排序列表與卡片雙檢視、列內價格走勢 sparkline、Steam 評價、特價即時倒數、即將結束與免費領取專區,以及每款的商品詳細頁(自建歷史走勢圖)。登入子系統採 Discord OAuth:收藏跨裝置同步(未登入用 localStorage、登入後合併)、每款可設目標價,創本站新低或跌破目標時由 Discord bot 在你的頻道 @你或私訊提醒,並有 per-user 通知偏好(降價/免費/每日每週摘要/只收特定類型/頻道 vs DM)。所有第三方呼叫都在 server 端完成,公開瀏覽永遠只吃靜態 JSON,不暴露任何金鑰。
關鍵亮點
- 自建價格歷史而非串接第三方:worker 每輪把抓到的台幣價寫進 SQLite,累積成「本站追蹤以來」的走勢與史低(observed low),並誠實標示為『追蹤以來最低』而非冒充 SteamDB/ITAD runtime;另可選配 ITAD API Key 以真實台幣史低校正冷啟動初值,只改 game_stats、不污染累積曲線。
- 「server 端抓取、前端純靜態 JSON」的架構:對 Steam / GamerPower / ITAD 的呼叫全在 worker 完成,烤成 deals / free / meta 給前端 fetch,公開瀏覽零金鑰外洩、免重 build;npm-workspaces monorepo 切成 shared 純函式+型別 / worker / Astro web / api,純邏輯以 vitest TDD(全專案 160+ 測試)。
- 可登入的通知子系統:Discord OAuth 登入後願望清單跨裝置同步(未登入 localStorage、登入即合併)、每款可設目標價;worker 偵測「收藏且創本站新低/跌破目標」時,由 Discord bot 依 per-user 偏好以頻道 @你或私訊 DM 發送,含個人免費遊戲通知與每日/每週特價摘要;另可一鍵從公開 Steam 願望單(貼 SteamID64 或個人檔網址、免金鑰)匯入收藏。
- 完整自架部署:api(Fastify + better-sqlite3 + secure-session)與 worker 以 Docker Compose 跑在 Oracle ARM 主機,Caddy 同站代理 /api、/auth 並服務 Astro 靜態檔,外接 Cloudflare Tunnel 上線到 steam.terrychou.com;push 到 main 由 GitHub Actions 經 SSH 自動 git reset + compose 重建 + health check,祕密放主機 .env 不進 CI,與既有 soulshard 子站共存。
技術棧
挑戰與取捨
最大的取捨是「要不要自建價格歷史」:直接串第三方(SteamDB/ITAD runtime)最省事,但有授權與穩定性風險,因此選擇自抓自存、誠實標示「追蹤以來最低」,代價是冷啟動時史低不準——再以選配 ITAD API Key 校正初值、且只寫 game_stats 不污染累積曲線來折衷。架構上堅持「server 端抓取、前端純靜態 JSON」以杜絕金鑰外洩並免重 build,代價是犧牲即時性,於是用 cron(約 30 分)加上資料新鮮度標示換取簡單與安全。通知子系統最難的是「可靠送達且不重複、不遺失」:目標價必須看現價跌破即發(不能只在創新低時觸發),個人免費通知改用 per-user 基線加完整清單 feed,避免被全域上限永久略過——這些都以多代理對抗式 review(每筆 refute-by-default 驗證)與整合測試守住。部署則完全貼合既有 soulshard 架構(Cloudflare Tunnel → Caddy → Docker),避開已佔用的 8787 埠、cookie 依環境切換 secure,確保兩個子站互不干擾。