更新日誌
GitHub每一項重大變更,逐版記錄。同一份檔案隨儲存庫發布,並已翻譯為全部 19 種語言。
[1.7.0] — 2026-05-03
由 QA r5 驅動的 35-commit 強化 + UX + 功能完成 pass。三層安全性落地(XSS 淨化、CSP、輸入驗證),每個缺失的 CRUD 端點補齊,父專案 bootstrap 現已完全自動化,UI 取得 9 個新頁面 — Activity、改版 Deep Research,以及 7 個 sidebar 分組 mode(project / training / followup / batch / outreach / interview-prep / patterns),完整涵蓋父專案 modes/ 100 %。Pipeline 取得伺服器端 preview pane。Anthropic API 整合讓「Run live」在所有 mode 變成一鍵動作。測試覆蓋從 73 增至 225,跨 25 個測試檔案,加上 23 個 comprehensive Playwright e2e 步驟。GitHub Actions 出貨 CI / AI review / Release / Publish-Package workflow。
🔒 安全性
fix(cv): 淨化 CV markdown 以阻擋 preview 中的 stored XSS(FIX-C10) —PUT /api/cv寫入cv.md前,現在會去除<script>、<iframe>、<object>、<embed>、<style>、<form>、<svg>、on*=事件處理器、以及javascript:/vbscript:/data:text/htmlURI。Body 上限 1 MB(溢出 413)。Client-sideUI.md()重寫,使每個 byte 在任何 markdown 變換執行前都先 escape,所以原始 HTML 永遠到不了innerHTML。Linkhref屬性對安全 scheme 白名單(http/https/mailto/tel/相對 + 僅data:image)驗證。新增 17 個跨 strip helper 與 HTTP round-trip 的測試。fix(server): 加入 CSP 與基線安全標頭(FIX-L2) — 每個 response 現在攜帶X-Content-Type-Options: nosniff、X-Frame-Options: DENY、Referrer-Policy: same-origin。當伺服器繫結超過 loopback(HOST≠127.0.0.1/::1/localhost)時,疊上嚴格Content-Security-Policy:default-src 'self'、script-src 'self'(無unsafe-inline)、Google Fonts 白名單、connect-src 'self'阻擋 XSS 外洩。index.html與router.js中的行內onclick處理器移至addEventListener以保留嚴格 CSP。8 個新測試把關 CSP 跨 5 個不同HOST值。fix(api): 收緊 pipeline URL 驗證器(FIX-M7) —POST /api/pipeline過去接受"not-a-url"並持久化。現在isValidJobUrl()拒絕裸字串、輸入 <10 或 >2000 字元、含空白 URL、非http(s)scheme,以及 loopback 主機名稱(localhost/127.0.0.1/::1)。納入 FIX-M3 + FIX-M6(無效時回 400,成功時帶dedupedflag)。fix(server): 實際載入 .env,讓 HH_USER_AGENT / GEMINI_API_KEY 提示生效— 先前執行期告訴使用者「在 .env 設定 HH_USER_AGENT」,但伺服器從未讀取該檔案,因此照做沒用。新增 35 列零相依 dotenv loader(server/lib/dotenv.mjs)於server/index.mjs頂部接線。命令列上設定的 process-env 值仍優先,既有 CI override 不會被遮蔽。父.env.example現包含記載的HH_USER_AGENT區塊與真實 Chrome User-Agent 範例。6 個新測試。fix(api): prompt 組裝前淨化 JD(FIX-M5) —POST /api/evaluate在呼叫 Gemini 或回送 prompt 前,去除 ANSI escape、控制位元組、行內<script>標籤,並修剪空白。50 KB 長度上限。50 字元最小限制對「淨化後」文字運行,因此看似夠長但多為 escape 的 prompt-injection 嘗試會以 400 快速失敗。fix(health): 當 HOST!=loopback 時遮罩 Node 版本 + 專案 root(FIX-M1) —/api/health不再於 LAN 暴露部署上識別主機。Loopback 回應仍保留值以利本地診斷。
✨ 新功能
feat: 7 個新 sidebar mode + 分組 sidebar(FIX-C8) — 完整涵蓋父專案modes/目錄 100 %,無 UI 空缺。新路由:#/project(portfolio project advisor)、#/training(course / cert evaluation)、#/followup(per-application cadence)、#/batch(parallel URL processor)、#/contacto(LinkedIn outreach drafter)、#/interview-prep(stage-specific prep)、#/patterns(rejection-pattern analyzer)。全部 7 個共用單一 config-driven 視圖工廠(public/js/views/mode-page.js)與單一通用端點POST /api/mode/:slug— 未來新增 mode 是一列 config + 一個 i18n 區塊。Sidebar 重組為 6 群組:Sourcing / Decision / Application / Networking / Analytics / Setup。共 18 個 nav 條目。12 個新測試於tests/modes-endpoints.test.mjs。fix: bootstrap 父專案 deps + russian_portals 預設(FIX-C4 + C9 + C12 + H2) —bin/start.sh現在於 fresh clone 安裝父node_modules(js-yaml、playwright、jsdom)與npx playwright install chromium,讓/api/stream/scan、/pdf與/liveness開箱端對端可用。createApp()每次啟動探測portals.yml— 若缺russian_portals:區塊,附加帶註解的記載預設。冪等:第二次啟動為 no-op。3 個新測試。fix: 在 template + health-check script 停用 9 個失效 portal slug(FIX-C3) —templates/portals.example.yml現在出貨時將 Ada / Factorial / Tinybird / Weights & Biases / Travelperk / Clarity AI / Forto / Vinted / Runway 標為enabled: false(每條附行內原因註解)。新安裝掃描 87 個存活公司而非 96。新web-ui/scripts/portals-health-check.mjsHEAD-probe 每個啟用之careers_url並回報 DEAD 條目並建議 patch 清單(透過--json輸出 JSON)。3 個新測試。feat(activity): 使用者動作日誌 + Activity sidebar 頁面— 每個狀態變更 API 請求皆捕捉至data/activity.jsonl(timestamp、action verb、target、success flag、可選 detail)。新 sidebar 條目 Activity,帶 action-prefix chip 篩選(pipeline / cv / jd / evaluate / scan / stream / script)、動作 ✓/✗ 徽章與刷新按鈕。5 MB 自動 rotate。10 個新測試,涵蓋 middleware、讀取篩選、損壞行容忍、GET /api/activity本身的遞迴防護。feat(deep): 於瀏覽器檢視 Deep Research + 儲存結果存檔— Deep Research 頁面現在(a)當{ run: true }且設定GEMINI_API_KEY時透過 Gemini 即時執行 prompt,並將輸出持久化至interview-prep/{slug}.md;(b)以可點擊卡片列出每個儲存的 deep-research 檔案(帶相對 timestamp);(c)將結果渲染為 Markdown,並提供每結果 📋 Copy / ⬇ Download .md / ↗ Open in tab 動作。新 REST 介面:GET /api/interview-prep、GET /api/interview-prep/:name、DELETE /api/interview-prep/:name。7 個新測試。feat(cv): 於瀏覽器產生 + 下載 PDF,並含 PDF 存檔— CV 頁面新增 📄 Generate PDF 按鈕,於 modal console 串流/api/stream/pdf。發生ERR_MODULE_NOT_FOUND/playwright錯誤時,呈現可複製貼上的 bootstrap 命令。新「Generated PDFs」段落於每次成功執行後自動載入,列出每個output/*.pdf並提供 ↗ Open 與 ⬇ Download 按鈕。新 REST 介面:GET /api/output/pdfs、GET /api/output/pdfs/:name。6 個新測試。feat(api): POST /api/tracker — 從 UI 附加列(FIX-H8) — 從瀏覽器附加規範列至data/applications.md。驗證 company + role、對templates/states.yml正規化 status、自動遞增零填補#、依 company+role(大小寫不敏感)dedup、對 notes pipe-escape 以免 markdown 表格斷裂。檔案為空時 bootstrap 表格。6 個新測試。feat(api): DELETE /api/jds/:name(FIX-H4) — 不再 shell-out 即可移除儲存之 JD。Path-traversal 字元於任何檔案系統觸碰前去除;參數必須以.txt結尾。5 個新測試,包含../../etc/passwd拒絕。feat(api): POST /api/evaluate/test-gemini(FIX-H7) — Smoke 測試端點,透過gemini-eval.mjs跑 50 字元假 JD,讓使用者可在不耗實際 evaluation 時間下驗證 API key 是否有效。回傳{ ok, code, sampleLength, sample }。
🐛 Bug fixes
fix(router): catch-all 404 視圖 + i18n 覆蓋率防護(FIX-C7) — 未知 hash 路由過去無聲後備至 dashboard,遮蔽 typo 與壞掉的書籤。現在#/totally-random-xyz渲染專屬 404 頁面,引用該壞路徑並提供 dashboard 連結。404 視圖在 router IIFE 內註冊,因此不會與任何使用者路由衝突。新tests/i18n-coverage.test.mjs於vm.Context內以 stubwindow執行i18n.js、揭露私有DICT,並斷言 173+ 個 key 跨 8 個 locale 皆已填入且非空。4 個新 router 測試。fix(router): 別名 #/profile → settings(FIX-C2) — 內部路由名為settings(nav.settings渲染為「Profile」)但外部連結與肌肉記憶都會走#/profile。現在兩個位址抵達同一視圖,sidebar nav 條目以任一方式都亮起。2 個新測試。fix(health): 統一 Health/Doctor + 標記模板 profile(FIX-C6 + FIX-H6) — Health 與 Doctor 為兩個不同真實來源。現在/api/health揭露 Doctor 報告之全部(parent-deps、Playwright、目錄、profile-customized、HH_USER_AGENT)。Profile customized檢查偵測佔位名稱(Jane Smith、Alex Doe、John Doe、Your Name、Test User)與明確 YAML 解析錯誤。4 個新測試。fix(scan): 對 RU config 之 query↔negative 衝突發警告(FIX-H3) — 當portals.yml出貨時title_filter.negative含"PHP",而 queries 鎖定 Senior PHP,每個匹配都被篩掉,使用者看到 0 結果。loadConfig()現在計算warnings陣列;runRuScan()在掃描開始前以 SSE stderr 列發出每個警告。2 個新測試驗證出貨預設開箱保持 PHP 友善。fix(scan): HH_USER_AGENT 未設定時發警告(FIX-H1) —/scan頁面探測/api/health,在HH_USER_AGENT為空時於動作列上方顯示黃色警告卡,使用者在點 RU scan 之前即得知 hh.ru 403 之可能。fix(api): 當 POST /api/jds slug 被去除不安全字元時發警告(FIX-M2) — 去除危險字元的 slug 正規化現在回傳warning欄位;純大小寫 / 空白清理保持安靜。淨化後為空時回 400。fix(ui): 路由變更時清除全域搜尋 + 按鈕 spinner(FIX-M4 + FIX-L1) — 全域搜尋輸入於hashchange時清除(對 active 輸入有 guard)。新UI.withSpinner(button, fn)helper 將載入狀態、ARIA、雙擊防護接線進每個 async 按鈕點擊。已採用於 Doctor / Verify / sync-check / Save CV / Normalize / Dedup / Merge 按鈕。fix(ui): 讓 sidebar 可捲動,使 18 個 nav 條目永遠抵達 footer— FIX-C8 之分組 sidebar 在較短 viewport 溢出;底部條目(Activity / Health)被剪掉。.sidebar現有overflow-y: auto與薄客製樣式 scrollbar(WebKit + Firefox)。Footer 透過既有margin-top: auto固定。fix(ui): 空 modal-title 佔位(FIX-H9) —index.html中硬編碼英文"Title"字串已移除,關閉 modal 開啟期間短暫可見的競爭視窗。
🌐 i18n
- 173+ 個翻譯 key × 8 個支援 locale(
en、es、pt-BR、ko、ja、ru、zh-CN、zh-TW)。為 404 頁面、activity 日誌、deep research、PDF 流程、安全警告、tracker 突變、apply 改名加入新 key。覆蓋率現由tests/i18n-coverage.test.mjs強制 — 每個 key 必須於每個支援 locale 有非空值,否則 CI 失敗。
⚙️ DevOps
- 測試數: 73 → 201(+128,跨 23 個測試檔案)。剩餘單一失敗測試(
runEnScan: dry-run end-to-end across multiple sources)為 Greenhouse/Ashby/Lever live API response 之既存 flake。 - Comprehensive Playwright e2e(
tests/e2e-comprehensive.mjs,23 步驟):走訪完整使用者旅程 — CV 儲存 → preview → PDF 產生 → 全部 7 個新 mode → tracker 篩選 → activity 日誌 → 404 → modal ESC → sidebar 捲動 → Ctrl-K focus → search 清除 → profile 別名 → 語言持久化。 - GitHub Actions(
.github/workflows/):ci.yml— Node 18/20/22 矩陣上之單元 + 整合測試,加上 i18n 覆蓋率閘(每個 key × 8 locale 必須非空),加上每個 PR 上的完整 Playwright e2e。ai-review.yml— 每個 PR 上之 Claude Code AI review。維護者保留 merge 權威;Claude 只建議。透過skip-ai-review標籤跳過。release.yml— 當推送v*.*.*tag 時自動發布 GitHub Release;release notes 從CHANGELOG.md切片,讓 8 語言變體保持規範來源。
- CSP 友善 UI:
index.html與router.js中所有行內onclick處理器已移除。嚴格script-src 'self'政策現在可強制執行,且不破壞任何功能。
📦 新 REST 端點
| 方法 | 路徑 | 目的 |
|---|---|---|
GET |
/api/activity |
列出使用者動作事件,最新優先 |
GET |
/api/interview-prep |
列出儲存之 Deep Research 檔案 |
GET |
/api/interview-prep/:name |
讀取單一 Deep Research 檔案 |
DELETE |
/api/interview-prep/:name |
移除 Deep Research 檔案 |
GET |
/api/output/pdfs |
列出產生的 PDF |
GET |
/api/output/pdfs/:name |
以附件方式串流 PDF |
POST |
/api/tracker |
對 applications.md 附加列 |
DELETE |
/api/jds/:name |
移除儲存之 JD |
POST |
/api/evaluate/test-gemini |
Smoke 測試 Gemini API key |
POST |
/api/mode/:slug |
7 個新 mode 之通用 prompt builder(project / training / followup / batch / contacto / interview-prep / patterns) |
[1.6.0] — 2026-05-02
Web UI 首次公開發布。基準功能盤點請參閱 README.md。
career-ops-ui v1.267.1 · page 9/9 · mirror of the project changelog for cvstart.org