Eranaut

FFXIV 玩家社群的潛水艇返航倒數 PWA

Eranaut 讓玩家記錄潛水艇的返航時間,到時間時透過 Discord 私訊、頻道 @ 或瀏覽器推播提醒。目前提供給約百人的社群內部使用。從畫面、API、截圖辨識到部署都由我一人完成,並與 AI 協作開發:需求、設計決策與實機驗證由我負責,每個決定都記錄在決策文件中。

系統架構

Eranaut 系統架構圖瀏覽器經 Cloudflare Tunnel 與 Caddy 連到 Eranaut API 的公開埠;Eranarch bot 只經內部埠;兩個入口共用同一個 service 與 repository 層,底下是 SQLite、OCR 與兩個排程;排程透過 Discord API 與 Web Push 服務發送提醒。自有主機 · Docker Compose瀏覽器 / PWAAngulareranaut-tunnelcloudflarederanaut-webCaddy靜態檔 + /api/*eranarch-botdiscord.js/eran 指令eranaut-api · Fastify公開埠session cookie內部埠共用密鑰 Bearerservice / repository 層業務邏輯與 SQL只放這一層SQLiteOCRPP-OCRv4同程序排程 ×2提醒輪詢資格比對Discord APIWeb Push 服務HTTPSDiscord gatewayWeb PushDM · 頻道 @
主機不開任何 inbound port,對外只經 Cloudflare Tunnel;bot 與 API 在同一個 Docker network,以 service 名稱互相呼叫。虛線框為外部服務。

畫面

Eranaut 桌機版總覽畫面,依返航時間排序的潛水艇列表(展示資料)
Eranaut 手機版總覽畫面(展示資料)

截圖為展示版的假資料。

功能

  • Discord OAuth2 登入與身份組權限(規則可用 AND / OR 組合)
  • 截圖辨識:PP-OCRv4 自架,不連外部服務、辨識完不存檔,支援貼上與擷取畫面
  • 三種提醒:Discord 私訊、頻道 @、瀏覽器推播(Web Push)
  • PWA:手機與桌機介面、介面大小切換、殼層離線載入
  • 管理員與成員指令(透過 Eranarch bot 呼叫內部 API)

技術棧

  • Angular · TypeScript
  • Fastify · Node.js
  • SQLite (better-sqlite3)
  • PP-OCRv4 (onnxruntime-node)
  • Web Push
  • Docker
  • Cloudflare Tunnel + Caddy

設計取捨

  • 登入用伺服器端 session cookie 而不是 JWT:只有單一 API 與 SQLite,可即時撤銷登入。
  • 公開埠與內部埠兩個入口、共用同一套 service 層:bot 只能走內部埠,外網結構上碰不到。
  • OCR 自架於同一程序,不連外部服務、不存圖:隱私與成本都比較好控制。
  • 提醒用 upsert、全系統只有兩個排程:資料量有上限,不需要清理排程。

最有挑戰的部分:OCR 與 Docker 部署

OCR 以 11 張真實截圖加 77 張劣化圖驗證(單艘辨識約 99.5%),並在 Windows x64 與 Linux arm64 兩個平台跑完整測試。Docker 在 arm64 上遇到原生套件(better-sqlite3、onnxruntime-node)的建置問題,逐一排除後在自有主機上線。