一句話結論: 這是一個零外部相依的 Node 服務,日常維運只有三件事——看健康、看日誌、備份資料;照本手冊操作,不需要原開發者在場。
web/index.html(App 殼)、app.js(所有互動與 API 呼叫)、styles.css(設計語彙)、admin.html(管理後台,內嵌腳本)。無框架、無建置步驟,改完存檔重新整理即生效。server/index.js(HTTP 路由、靜態檔、驗證、行程排序)、db.js(資料表與查詢)、parser.js(解析引擎)、gazetteer.js(地標辭典與地圖座標投影)、places.js(Google Places 打點 adapter)、logger.js(結構化日誌)。data/mapsync.db/api/health(存活)、/api/version(版本)、/admin(資料與日誌)、/docs/(本套文件)。| 路徑 | 用途 | 常改嗎 |
|---|---|---|
server/index.js | API 路由、行程排序、後台 API、靜態服務 | 少 |
server/db.js | 資料表定義、種子資料、查詢函式 | 少(改 schema 才動) |
server/parser.js | 解析引擎(規則式 + LLM adapter) | 中(想提升解析力時) |
server/gazetteer.js | 地標辭典、地區關鍵字、經緯度→地圖座標投影 | 常(補新地標就加這裡) |
server/places.js | Google Places 打點補強(可插拔) | 少 |
web/app.js | 所有前端互動 | 中 |
web/styles.css | 設計語彙(色彩、字體、元件) | 中(改視覺時) |
web/admin.html | 後台頁面 | 少 |
web/manifest.webmanifest | PWA 安裝資訊與 Web Share Target 宣告 | 少 |
web/sw.js | Service Worker(只快取 App 殼) | 少 |
web/icons/ | PWA 圖示(由 npm run icons 產生) | 少 |
scripts/backup.js | 備份/還原 | 少 |
scripts/backup-remote.js | 遠端備份上傳(Drive API/rclone) | 少 |
scripts/smoke.js | 部署後冒煙測試(16 項) | 少 |
scripts/uptime-monitor.js | 可用性監控與告警 | 少 |
start.bat / deploy/mapsync.service | Windows 啟動/Linux 常駐 | 少 |
scripts/build-docs.js | 由 docs/src/*.md 產生文件 HTML | 少 |
scripts/make-icons.js | 產生 PWA 圖示(自寫 PNG 編碼器) | 少 |
tests/e2e.js | 端到端驗收測試 | 常(加功能就加測試) |
tests/ai-integration.js + tests/stub-services.js | LLM/Places/分享面板整合測試(含降級) | 常 |
deploy/ | Dockerfile、compose、Caddy、systemd 單元 | 少 |
/api/health 確認 200(或跑 npm run monitor 看一段時間的可用率)。/admin,看「錯誤日誌」卡片的數字是否為 0。level=error 的訊息與時間。npm run backup,確認 backups/ 產出新檔案。node scripts/backup.js --list 確認備份數量與時間。npm test(30 項)必須全綠。npm run smoke(16 項)確認運行中的實例正常。/api/version 確認版本一致,並在上線檢查清單的「部署紀錄」補一列。| 症狀 | 可能原因 | 處理方式 |
|---|---|---|
| 網頁打開是白的 | 服務沒起來,或反向代理設定錯 | curl -i /api/health;看服務日誌;確認 Caddy/Nginx 轉發到 8848 |
/api/health 回 503 | 資料庫開啟失敗 | 檢查 MAPSYNC_DATA_DIR 是否存在且可寫;看日誌中 request failed 的 error |
| 後台進不去(401) | 權杖錯或未帶 cookie | 用 data/admin-token.txt 或環境變數的權杖重新登入 |
| 解析都回「讀不到貼文內容」 | 沒填貼文文字 | 匯入時必須貼上貼文說明;或改用「直接手動新增地點」 |
| 解析回「需要你確認」 | 信心度低於門檻 | 從候選清單挑一個,或手動改店名後加入 |
| 圖釘位置不準 | 沒命中地標辭典 | 屬預期行為(geo_confidence=low);可手動校正,或把地標補進 gazetteer.js |
| 圖釘點不到/被面板蓋住 | 前端堆疊順序問題 | 檢查 .fab 與 .sheet 的 z-index 與 bottom 設定(曾發生 BUG-001) |
| 資料庫檔案愈來愈大 | 日誌與事件累積 | 目前量小可忽略;需要時定期 npm run backup 後再清理舊資料 |
| 啟動時冒出 <code>EADDRINUSE</code> | 埠被舊程序占用 | 先停掉舊程序(找 <code>server/index.js</code> 的 node 行程),或用 <code>PORT=其他埠</code> 啟動;服務會以錯誤碼 1 明確退出而不是默默失敗 |
| 某個來源一直收到 429 | 觸發寫入限流(每分鐘 120 次) | 確認是不是爬蟲或前端重複送單;必要時調整 <code>server/index.js</code> 的 <code>RATE_MAX_WRITES</code> |
| Linux 上 Docker 建置找不到 Dockerfile | 檔名大小寫(Windows 不敏感、Linux 敏感) | 確認檔名為 <code>Dockerfile</code>/<code>Caddyfile</code>(曾經發生 BUG-002) |
| 忘記管理權杖 | 環境變數未設時是自動產生的 | 讀 data/admin-token.txt;或改用環境變數固定它 |
| 解析都走規則引擎,沒用到 LLM | 未設 MAPSYNC_LLM_KEY | 設金鑰後重啟,用 /api/version 的 features.llmParser 確認 |
| 圖釘沒有 place_id/經緯度 | 未設 MAPSYNC_PLACES_KEY 或查詢失敗 | 設金鑰後重啟;到後台 parse_jobs.result 看 enriched,日誌搜 placesError |
| Android 分享面板找不到 咻揪趣 | 未加入主畫面,或不是 HTTPS | 先「加入主畫面」,並確認走 https(或 localhost) |
| 改了前端還是舊畫面 | Service Worker 快取舊的 App 殼 | 重新整理兩次,或 DevTools 移除 Service Worker;部署時對 /sw.js 設 no-cache |
| 遠端備份回 <code>missing_token</code> | 未設 MAPSYNC_DRIVE_TOKEN | 設定 Drive 權杖,或改用 --via rclone 模式 |
| 遠端備份回 <code>rclone_not_found</code> | 主機沒裝 rclone | 依 rclone 官網安裝後執行 rclone config 建立 remote |
| 備份上傳成功但 Drive 裡找不到檔案 | 上傳到別的資料夾(或根目錄) | 確認 MAPSYNC_DRIVE_FOLDER_ID,或直接查 Drive 根目錄 |
npm run backup # 產生 backups/mapsync-<時間>.db
node scripts/backup.js --list # 列出所有備份
node scripts/backup.js --restore <檔名> # 還原(會先自動備份現況)
npm run backup,並把 backups/ 同步到外部儲存。npm run backup:remote(預設 Drive API,需 MAPSYNC_DRIVE_TOKEN;或 --via rclone 搭 MAPSYNC_RCLONE_REMOTE)。data/ 同步到雲端硬碟:那是執行中的 SQLite(WAL),同步到寫入一半的檔案會損壞;只同步 backups/ 的一致性快照。| 想改什麼 | 改哪個檔案 | 注意事項 |
|---|---|---|
| 品牌色、字體、圓角 | web/styles.css 的 :root 變數 | 只改變數,元件會自動跟著 |
| 首頁文案、引導文字 | web/index.html、web/app.js 的 maybeOnboard()/openImport() | — |
| 增加可辨識的地標 | server/gazetteer.js 的 PLACES | 需給 x/y(地圖百分比)與 lat/lng |
| 提升解析準確度 | server/parser.js 的 guessName()/TAG_RULES | 改完跑 npm test,別破壞 §B/§C |
| 切換成 LLM 解析 | 設 MAPSYNC_LLM_KEY(+endpoint/model) | 不需改程式,引擎會自動升級 |
| 新增資料表欄位 | server/db.js 的 SCHEMA | 舊資料庫不會自動遷移,需手動 ALTER TABLE 或重建 |
| 行程排序邏輯 | server/index.js 的 buildTrip()/haversineKm() | 目前為最近鄰+步行 4.5 km/h 估算 |
| 部署設定 | deploy/Dockerfile、deploy/docker-compose.yml、deploy/Caddyfile、deploy/mapsync.service、.env | — |
| 測試覆蓋 | tests/e2e.js(驗收)、scripts/smoke.js(部署後)、tests/ai-integration.js(AI 鏈路) | 加功能就加一項 |
| 換 LLM/Places 服務商 | 環境變數 MAPSYNC_LLM_ENDPOINT/MAPSYNC_PLACES_ENDPOINT | 程式不需改 |
| 改分享進來的參數 | web/manifest.webmanifest 的 share_target 與 web/app.js 的 handleShareTarget() | 兩邊必須一致 |
| 換 App 圖示 | 改 scripts/make-icons.js 的 BRAND 後執行 npm run icons | — |
| 調整外部服務逾時 | MAPSYNC_PLACES_TIMEOUT_MS、server/parser.js 的 AbortSignal.timeout | — |
| 換備份目的地 | 環境變數 MAPSYNC_DRIVE_TOKEN/MAPSYNC_DRIVE_FOLDER_ID,或 MAPSYNC_RCLONE_REMOTE | 不必改程式;npm run backup:remote 會自動選模式 |
| 監控頻率 | scripts/uptime-monitor.js 的預設間隔 | — |
npm start 即可,無需安裝任何套件)npm test → tests/LAST-RUN.json)npm run smoke,16 項)打勾者為本次交付已完成;未打勾者是接手後第一件要做的事,已在里程碑看板標為「進行中」。