ARTICLE DETAIL

资讯详情

深耕郑州网站建设与运营推广的一线实战洞察。

career-ops dashboard:基于 Bubble Tea 的 Go TUI 应用管道看板——从追踪表解析到原子化状态回写

career-ops dashboard:基于 Bubble Tea 的 Go TUI 应用管道看板——从追踪表解析到原子化状态回写 career-ops dashboard基于 Bubble Tea 的 Go TUI 应用管道看板——从追踪表解析到原子化状态回写【免费下载链接】career-opsOpen-source AI job search: scan job portals, evaluate listings into a structured A-H report with a global 1-5 score, tailor your CV, track applications — runs locally in your AI coding CLI (Claude Code, Codex, OpenCode, Antigravity…)项目地址: https://gitcode.com/GitHub_Trending/ca/career-opsdashboard 是 career-ops 中一个完全独立于 Node 核心的 Go 终端界面TUI用于浏览申请追踪表tracker提供筛选标签、多种排序模式、分组/平铺视图、懒加载的评估报告预览以及内联状态选择器。它以只读方式读取applications.md等数据文件仅在用户主动操作改状态、记录丢弃原因时才回写且回写过程带文件锁与整格匹配保护。读完本文你将掌握它的构建与运行方式、数据解析管线、消息路由架构、指标算法以及它如何安全地改写 Markdown 追踪表。一、定位与设计原则dashboard/README.md 开宗明义这是一个Standalone Go TUI for browsing the career-ops pipeline并且It is isolated from the Node core — optional, never required by any other component与 Node 核心隔离——可选从不被其他组件依赖。从源码结构看这个隔离是彻底的双向设计读取侧Go 模块只读取 career-ops 目录下的数据文件applications.md、报告 Markdown、batch/batch-input.tsv、scan-history.tsv等不 import 任何 Node 代码见 dashboard/go.mod依赖全部来自charmbracelet生态与golang.org/x/sys无任何 Node 桥接库写回侧唯一的跨语言调用是生成 PDF时 shell out 到node generate-pdf.mjsdashboard/main.go 中的runGeneratePDF其余状态更新全部由 Go 侧直接完成反向零依赖Node 测试套件只是顺带构建 dashboard见下文测试章节核心管道scan → evaluate → apply → track在任何情况下都不需要它。二、环境要求与运行方式2.1 前置条件README 声明要求 Go 1.24当前 dashboard/go.mod 中实际声明的是go 1.25.0因此以 go.mod 为准准备工具链更稳妥。2.2 从仓库根目录运行/构建package.json 定义了两个 npm 脚本npm run serve:dashboard # 等价于 cd dashboard go run . --path ..在仓库根启动 npm run build:dashboard # 构建独立二进制其中serve:dashboard的--path ..表示以仓库根目录作为 career-ops 目录——因为追踪表applications.md通常位于数据根之下。2.3 为什么需要一个 build 包装脚本go build -o career-dashboard .在 Windows 上会写出一个无扩展名的二进制Go 只有在省略-o时才自动补.exe导致 Windows 上按裸文件名/PATH 查找失败。因此仓库提供了 build-dashboard.mjs 作为跨平台包装const out process.platform win32 ? career-dashboard.exe : career-dashboard; const result spawnSync(go, [build, -o, out, .], { cwd: join(root, dashboard), stdio: inherit, });它在dashboard/目录内执行go build按平台选择输出名Windows 上生成dashboard/career-dashboard.exe其他平台生成dashboard/career-dashboard。若go不在 PATH 中会以ENOENT报错并提示安装 Go 1.24。2.4 二进制参数与数据目录解析二进制接受--path dir参数指向一个 career-ops 目录默认.另有--lang en|tr指定 UI 语言缺省时回退到LANG环境变量自动检测/英文。数据加载器对追踪表位置尝试两种布局以兼容不同安装方式{path}/applications.md与{path}/data/applications.md。在 dashboard/main.go 中--path的默认值并不是简单的.而是一个三级解析链main()中CAREER_OPS_ROOT环境变量绝对路径直接使用相对路径相对仓库根解析——仓库根由是否存在path-resolver.mjs标记文件判定CAREER_OPS_DATA_DIR环境变量规则同上数据目录下的.career-ops-data标记文件内容支持绝对/相对路径。这一设计使 dashboard 可以独立于工作目录启动getRepoRoot()会检查当前目录及其父目录中是否有path-resolver.mjs适合放在终端多路复用器的另一个窗格长期挂起。三、包结构README 给出的包结构与源码一一对应包/文件职责dashboard/main.go入口、flag 解析、顶层 Bubble Tea 模型与视图状态pipeline / report viewer / progress / stats 四态open_darwin.go/open_linux.go/open_windows.go/open_unix_command.go/open_unsupported.go各平台用默认程序打开文件/URL的实现dashboard/open_linux.go 等按 build tag 选择dashboard/internal/data/career.go解析applications.mdParseApplicationsderive.go/stats.go派生聚合指标pdf.go解析生成的 PDFdashboard/internal/model/career.go应用行模型CareerApplication及各类指标结构体dashboard/internal/theme/Catppuccin Mocha暗与 Latte亮主题NewTheme(auto)依据检测到的终端背景色自动选择dashboard/internal/ui/screens/pipeline 列表、report viewer、progress 屏幕及 stats 屏幕dashboard/internal/i18n/UI 双语目录t/T键可全局切换语言外部依赖dashboard/go.modBubble TeaTUI 框架v1.3.10、Lipgloss样式v1.1.0、termenv终端背景色检测v0.16.0以及golang.org/x/sys。模块对 Node 侧零依赖只读取追踪表文件——这与 README 的声明一致。四、数据加载管线从 Markdown 表格到结构化行模型4.1 追踪表定位与表头感知解析ParseApplicationsdashboard/internal/data/career.go先经resolveTrackerPath定位追踪表优先CAREER_OPS_TRACKER环境变量其次{path}/data/applications.md再次{path}/applications.md。解析的关键设计是按表头名映射列而不是按固定位置。detectTrackerColumns扫描表头行用别名表把单元格映射为规范字段名var trackerHeaderAliases map[string]string{ #: num, num: num, date: date, company: company, empresa: company, via: via, role: role, puesto: role, location: location, score: score, status: status, pdf: pdf, report: report, notes: notes, url: url, }只有当num/company/role/score/status五个必备列全部就位时才采用表头映射否则回退到遗留的固定布局num0 … notes8。注释明确说明这与 Node 侧tracker-parse.mjs在 #954 中引入的 header-aware 行为保持一致——即 Go 数据层能容忍与 Node 追踪工具相同的自定义/重排列追踪表例如用户插入了 Location 列也不会错位。行解析兼容两种格式splitTrackerRow| 前缀 制表符分隔的混合格式或纯竖线分隔格式。4.2 每行抽取的字段每行产出一个CareerApplicationdashboard/internal/model/career.goNumber追踪表编号、Date、Company、Role、JobURL、Status、HasPDFPDF 列含 ✅Score从 Score 列用正则(\d\.?\d*)/5抽取 1–5 的评分对应 career-ops 的全局 1–5 打分体系ReportPath/ReportNumber从报告列的N链接中抽取并经resolveReportPath归一化为相对careerOpsPath的路径——报告链接通常相对追踪表自身目录如data/下的../reports/...解析失败时回退到按根目录相对的老式链接Notes并从中派生Location美国城市州、WorkModeRemote/Hybrid/Full、PayRange/PayMax首个$区间、PostedOn、LastContact等字段deriveNoteFields。4.3 五级 Job URL 富化策略对于追踪表没有 URL 列的旧表解析器按优先级回退补全原始职位链接ParseApplications尾部注释即完整清单追踪表 URL 列tier zero直接采用报告头部的**URL:**字段只扫描前 1000 字节保证速度报告中的**Batch ID:**→batch/batch-input.tsv按 ID 查 URLnotes 格式为Title Company | Match% | https://actual-urlreport_num→batch/batch-state.tsv中completed状态的映射scan-history.tsvpipeline 扫描记录按公司职位名匹配同名多条目时用职位词命中数选最优batch-input.tsv的公司名回退匹配公司名会先经normalizeCompany去掉Inc./LLC/Ltd.等后缀并小写化。这套多源回退让 dashboard 对老式追踪表、批量评估产物、扫描历史都能给出可点击的职位 URLpipeline 屏幕的o键用系统默认浏览器打开。4.4 状态规范化NormalizeStatus把自由文本状态归一为规范状态evaluated / applied / responded / interview / offer / hired / rejected / discarded / skip支持英、西、土三种语言拼写并剥离 Markdown 加粗与尾随日期如aplicado 2026-03-12→applied。源码注释要求别名表与templates/states.yml保持同步。StatusPriority给出排序优先级interview(0) offer(1) responded(2) applied(3) evaluated(4) skip(5) rejected(6) discarded(7)即最需要行动的申请排最前。五、顶层状态机与屏幕路由dashboard/main.go 定义了一个四态视图const ( viewPipeline viewState iota viewReport viewProgress viewStats )appModel持有四个屏幕模型PipelineModel/ViewerModel/ProgressModel/StatsModel与当前态Update按消息类型路由屏幕专属消息如ViewerClosedMsg改变state并在下一帧由View()切换渲染其余消息按当前态转发给活动屏幕default分支。程序以tea.WithAltScreen()启动使用备用屏幕缓冲退出后终端恢复原状。关键消息流均在 dashboard/internal/ui/screens/pipeline.go 定义PipelineLoadReportMsg→data.LoadReportSummary懒加载报告摘要archetype、TL;DR、remote、comp 四个字段TL;DR 截断至 120 字符并缓存进 pipeline 模型的报告预览缓存避免每行都实时读盘PipelineOpenReportMsg→ 切入viewReport用报告路径与标题新建ViewerModelPipelineUpdateStatusMsg/PipelineUpdateStatusAndNotesMsg→ 回写追踪表后触发reloadPipelineData()全量重载PipelineOpenProgressMsg/PipelineOpenStatsMsg→ 进入进度/统计屏指标在main启动与每次刷新时预计算ComputeProgressMetrics/ComputeStatsMetricsPipelineGeneratePDFMsg→ 在 goroutinetea.Cmd中调用node generate-pdf.mjs html pdf [--format…] [--reportN]成功后用系统默认程序打开 PDF失败信息被summarizeCmdError压缩成帮助栏一行的长度取输出的最后一个非空行UI 全程保持响应PipelineOpenURLMsg/PipelineOpenPDFMsg→ 统一走平台相关的openWithDefaultAppopen_*.go家族。两个有业务语义的状态流值得注意ViewerUpdateStatusMsg分支hired写库成功后进入StartHiredFlow——庆祝/记录流程会写入匿名data/reported-hires.tsv见SaveAnonymousStatdiscarded/skip进入StartDiscardReasonFlow——丢弃原因选择器原因来自报告的discard_reasons:YAML 块LoadReportDiscardReasons并与规范化原因表salary_too_low、hybrid_required、tech_stack_mismatch、seniority_mismatch、geo_restriction、size_mismatch、company_culture合并展示。另外t/T键全局切换语言但当 pipeline 屏有文本输入框激活时不响应避免打断输入IsTextInputActive()守卫。六、安全回写追踪表锁、整格匹配与原子更新dashboard 会写追踪表这是它与纯只读看板最大的区别也是实现上最讲究的部分dashboard/internal/data/career.go文件锁UpdateApplicationStatusAndNotes写入前先acquireTrackerLock跨平台的 lockfile 机制tracker_lock.go unix/windows/other 变体释放失败会errors.Join到返回值整格匹配绝不子串替换replaceStatusInLine的注释记录了历史缺陷 #1180——旧实现用strings.Replace(line, oldStatus, …, 1)替换行内第一处出现当公司名恰含状态词如Applied Materials时会改写错误单元格。现在statusCellIndex要求整格、大小写不敏感相等规范列校验失败时先找首个值相等的格最后兜底信任规范列当且仅当其当前内容能归一化为已知状态否则返回 -1 让调用方放弃写入空白保真spliceCellValue只替换格内文本、保留两侧空白| Applied |变成| Interview |而不是|Interview|状态备注原子提交#1380 引入的UpdateApplicationStatusAndNotes在同一次文件写入中同时更新 Status 单元格并向 Notes 追加DISCARD: reasonappendNotesInLine只在 Notes 列操作防止两次部分写把追踪表留在半更新状态原子落盘writeFileAtomic替换文件临时文件 rename 语义。定位目标行依赖ReportNumber行内必须含[N]标记找不到目标即报application not found: report N不做猜测性写入。七、指标与统计漏斗、分数桶与周活跃ComputeMetricsdashboard/internal/data/career.go产出头部指标总数、按状态计数、均分/最高分只对Score 0的已评估项求均值、带 PDF 数、Actionable非 skip/rejected/discarded 项。ComputeProgressMetrics支撑 progress 屏幕核心是漏斗与转化率。源码注释明确了口径——与stats.mjs的computeFunnel()这一规范漏斗定义一致每个阶段累计所有到达过该阶段的申请且hired是终局成功证明走完了全部前置阶段因此计入全部四层total : len(apps) applied : counts[applied] counts[responded] counts[interview] counts[offer] counts[hired] counts[rejected] responded : counts[responded] counts[interview] counts[offer] counts[hired] interview : counts[interview] counts[offer] counts[hired] offer : counts[offer] counts[hired]由此计算 ResponseRate / InterviewRate / OfferRate相对 applied。同函数还输出分数分布五桶4.5–5.0 / 4.0–4.4 / 3.5–3.9 / 3.0–3.4 / 3.0、按 ISO 周分组的最近 8 周活动、TotalOffershired 同样计入因为拿到 offer 并入职必然经过 offer、ActiveApps。ComputeStatsMetrics支撑 stats 屏幕的维度分解StatsMetrics见 dashboard/internal/model/career.go按报告派生的 archetype 分组数量/占比/均分、work mode、location、薪酬统计PayMax的均值/中位数/最大值并区分POSTED与est来源、分数档与级别构成、QualityBarPctscore ≥ 4.0 的已评申请占比。八、主题系统dashboard/internal/theme/theme.go 提供ThemeBase/Surface/Overlay/Text/Subtext 8 个强调色与工厂func NewTheme(name string) Theme { switch name { case catppuccin-mocha: return newCatppuccinMocha() case catppuccin-latte: return newCatppuccinLatte() case auto, : if termenv.HasDarkBackground() { return newCatppuccinMocha() } return newCatppuccinLatte() default: return newCatppuccinMocha() } }main()中实际使用theme.NewTheme(auto)通过 termenv 探测终端背景深色终端得到 Catppuccin Mocha浅色终端得到 Latte——即 README 所述picks by detected terminal background。色板定义在 dashboard/internal/theme/catppuccin.go 与 dashboard/internal/theme/catppuccin_latte.go。九、测试策略按 README 约定Go 测试与包同目录*_test.godashboard/internal/data/career_test.go解析、derive_test.go/stats_test.go指标、tracker_lock_test.go/tracker_replace_unix_test系列回写与锁、dashboard/internal/ui/screens/pipeline_test.go、sort_test.go、viewer_test.go、pipeline_width_test.go窗口自适应、timeago_test.go、dashboard/open_command_test.go 与open_windows_test.go平台 open 命令。Node 侧通过 test-all.mjs 把构建 dashboard纳入全量测试流程--quick时跳过保证 Go 模块始终可编译——这是可选组件仍不腐化的机制保障。十、实操要点回顾启动仓库根执行npm run serve:dashboard需要数据根下有applications.md或data/applications.md找不到会以Error: could not find applications.md in …退出产物npm run build:dashboard得到dashboard/career-dashboard(.exe)可脱离 npm/仓库脚本环境使用--path dir指向任意 career-ops 目录CAREER_OPS_ROOT/CAREER_OPS_DATA_DIR/.career-ops-data标记可作为默认值边界它只读追踪表与报告写回仅发生在用户主动改状态/记丢弃原因时且有锁、整格匹配、原子落盘三重保护跨语言交互仅限生成 PDF 时调用node generate-pdf.mjs兼容表头感知列解析与 Node 追踪工具对齐#954可容忍自定义列序状态别名覆盖英/西/土三语。从源码结构看dashboard 是一个典型的薄 UI 强数据契约组件UI 层Bubble Tea 屏幕保持简单复杂度都沉淀在数据层的解析容错、状态归一和写入安全上——这使它既能作为求职流程的独立观察窗长期挂起又不会成为 Node 核心的可用性依赖。【免费下载链接】career-opsOpen-source AI job search: scan job portals, evaluate listings into a structured A-H report with a global 1-5 score, tailor your CV, track applications — runs locally in your AI coding CLI (Claude Code, Codex, OpenCode, Antigravity…)项目地址: https://gitcode.com/GitHub_Trending/ca/career-ops创作声明:本文部分内容由AI辅助生成(AIGC),仅供参考
返回列表