Imported from lastsunday/job-hunting (
AGENTS.md). Install upstream withnpx skills add lastsunday/job-hunting. Copyright stays with the author.
AGENTS.md
索引
1. 技术栈
Rust (apps/server)
- Edition 2024 - 使用 RPIT 生命周期捕获规则等新语法
- Web: Axum 0.8 + tower-http + utoipa-axum (Scalar OpenAPI)
- ORM: Sea-ORM (sqlx-postgres, sqlx-sqlite, with-chrono, with-rust_decimal)
- Auth: jsonwebtoken (HS256, access + refresh token) + bcrypt
- Config: config crate (YAML)
- ID: xid (XID format)
- DB: PostgreSQL (sea-orm-migration)
- Error: 自定义
#[error]proc-macro (framework-macros) - Testing: cucumber (BDD) + testcontainers
- Other: chrono, strum, utoipa-scalar
- 开发环境: Nix (Lix) + flake + direnv(可复现开发环境)
TypeScript
管理后台 (apps/server-ui):
- React 19 + Mantine v9 + @mantine/core + @mantine/hooks
- TanStack Router (file-based routing, auto code-splitting)
- TanStack Query (React Query)
- Axios +
postJson<T>()/getJson<T>()/putJson<T>()/deleteJson<T>() - i18next + react-i18next (命名空间翻译)
- UnoCSS + CSS Modules (.module.css)
- zod (runtime validation)
- 环境变量:
import.meta.env.VITE_* - Prettier:
{ singleQuote: true }
浏览器扩展 (apps/extension):
- WXT framework (Chrome MV3)
- React 19 + Ant Design v5 + @ant-design/icons
- react-router 7 (页面路由)
- zustand (状态管理)
- fetch (API 调用)
- @electric-sql/pglite (嵌入式 WASM PostgreSQL)
- @mlc-ai/web-llm (浏览器内 LLM 推理)
- UnoCSS
- 测试: Vitest + Playwright BDD (playwright-bdd)
2. 项目结构与命名
目录结构
├── docs/ mdBook 项目文档
├── flake.nix Nix flake 配置
├── flake.lock Nix flake lock
├── .envrc direnv 自动激活(use flake)
├── rust-toolchain.toml Rust 版本(由 flake 自动读取)
├── .node-version Node.js 版本(由 flake 自动读取)
├── packages/ workspace 占位
├── libs/
│ └── analysis/ Lit Web Components 分析组件库
├── apps/
│ ├── server/ Rust 后端
│ │ ├── src/ 应用入口 (main.rs, clap, logging, runtime 等)
│ │ ├── api/src/ API 路由层 (每个模块一个 .rs 文件)
│ │ ├── service/src/ 业务逻辑层
│ │ ├── entity/src/ Sea-ORM Entity (自动生成 + 手动补充)
│ │ ├── migration/src/ 数据库迁移
│ │ ├── web/src/ Web 层 (静态文件服务)
│ │ ├── framework/ 框架层 (error, auth, config, data, middleware 等)
│ │ ├── macros/ proc-macro crate
│ │ └── build-metadata/ 构建元数据 crate
│ ├── server-ui/src/ React 管理后台
│ ├── server-ui-e2e/ 管理后台 E2E 测试 (Playwright)
│ │ ├── components/ UI 组件
│ │ ├── hooks/ 自定义 Hooks
│ │ ├── routes/ TanStack Router 路由文件
│ │ ├── api/ API 调用层
│ │ ├── config/ 配置
│ │ ├── data/ 数据类型定义
│ │ ├── i18n/ 国际化
│ │ ├── store/ 状态管理
│ │ ├── widget/ 微件组件
│ │ ├── assets/ 静态资源
│ │ └── utils/ 工具函数
│ └── extension/ 浏览器扩展
│ ├── entrypoints/ 入口 (background, content, offscreen, admin 等)
│ ├── common/ 共享代码 (api, data/domain/bo/dto, extension)
│ └── lib/ 第三方库
新建文件请严格遵循对应的目录位置。
命名风格
| 语言/层 | 命名风格 | 示例 |
|---|---|---|
| Rust 变量/函数 | snake_case | create_routes, get_job_by_id |
| Rust 类型/Trait | PascalCase | ApiResult<T>, Principal |
| Rust 错误码枚举 | *ErrorCode (PascalCase) |
UserErrorCode, JobErrorCode |
| Rust 模块名 | snake_case | job.rs, user.rs |
| TS 变量/函数 | camelCase | loadJobs, handleSubmit |
| TS 组件/类 | PascalCase | RouteComponent, JobFormData |
| TS 组件文件 | PascalCase + .tsx | ExcelPreview.tsx, LocationMap.tsx |
| TS 非组件文件 | camelCase + .ts | taskDataPlan.ts, http.ts |
| DB 表/字段 | snake_case | company_tag, first_scan_datetime |
| URI | snake_case | /api/job/search、/api/auth/access_token |
| 扩展 API 方法 | className + methodName | dataSourceMetadataSearch |
3. 核心禁忌
绝对不能做的
- 不要手动编辑
routeTree.gen.ts(TanStack Router 自动生成和覆盖) - 不要修改 Moon workspace 结构 (
.moon/workspace.yml,.moon/toolchains.yml) 及各项目moon.yml配置 - 不要引入新依赖前未检查现有依赖是否已满足需求
- 不要使用非 Edition 2024 的 Rust 语法(如
'_生命周期 elision 规则、impl<T>旧式 trait bound 等) - 不要手动编辑
flake.lock(使用nix flake update更新)
必须遵守的
-
提交信息: 必须使用 Conventional Commits 格式(
feat:/fix:/perf:/remove:/deprecate:/security:)。Lefthook commit-msg hook 自动校验格式,不满足会被拒绝。如需跳过用git commit --no-verify。如需在 changelog 中展示详细说明,在 footer 中写入CHANGELOG: <description>。破坏性变更使用feat!:或BREAKING CHANGE:footer -
CHANGELOG 更新: 发布前运行
moon run <project>:bump自动版本升级、生成 CHANGELOG、commit 并 tag。底层调用scripts/bump.sh,接受 3 参数:TAG_PREFIX、MANIFEST、INCLUDE_PATHS。首次发布(无 tag)直接标记当前版本;后续发布通过git-cliff --bump自动检测版本,commit 使用--no-verify绕过 lefthook -
Rust: 必须使用
#[error]宏定义错误码(6 位数字),不要手动实现 Error trait -
Rust: 必须使用
err!宏产生 ApiError,不要直接Err(ApiError::...) -
Rust: 不要遗漏
use framework::prelude::* -
Rust: 路由必须在
create_routes中通过OpenApiRouter组织 -
Rust: 提交前运行
cargo fmt && cargo clippy保持代码风格 -
server-ui: 不要修改 TanStack Router 路由配置之外的自动生成文件
-
extension: 扩展 API 必须用
fillBridgeApi()注册,不要直接跨 context 调用函数
4. 开发工作流
开发环境设置(Lix)
项目使用 Lix(Nix 的社区 fork)管理可复现的开发环境。
首次设置:
# 1. 安装 Lix
# Linux
curl -sSf -L https://install.lix.systems/lix | sh -s -- install
# macOS (Intel) — 同上命令即可
# macOS (Apple Silicon) — 同上
# 注意:不要使用 Determinate Systems 安装器(已停止支持 Intel Mac)
# 2. 安装 direnv(推荐,自动激活环境)
nix profile install nixpkgs#direnv nixpkgs#nix-direnv
# 在 ~/.zshrc 或 ~/.bashrc 添加: eval "$(direnv hook zsh)"
# 3. 进入项目(direnv 自动激活,或手动 nix develop)
cd job-hunting
direnv allow
devShell 选择:
nix develop .#server # 仅 Rust 后端(rustToolchain + openssl + sqlite + postgresql)
nix develop .#frontend # 仅前端(nodejs + pnpm)
nix develop # 默认完整环境(含 moon、just、mdbook、pkg-config 等)
版本来源(自动同步,无需手动维护):
- Rust 版本 →
rust-toolchain.toml - Node.js 版本 →
.node-version
注意事项:
- macOS Intel (x86_64-darwin):Lix 官方仍支持(tier 2),如有问题联系维护者
- 系统依赖(openssl, sqlite, postgresql 等)由 Lix 统一管理,无需 brew/apt
- CI 中 Lix 提供环境:
nix develop --command moon ci --base=origin/dev
Git Hook & 模板自动安装
.envrc 中已配置 lefthook install + git config commit.template,进入目录时自动生效:
- lefthook:
commit-msghook 校验 Conventional Commits v1.0.0 格式(summary + footer),通过--no-verify跳过 - 模板:
.git-commit-template.txt作为提交模板,git commit(编辑器)时自动填入提示
新增业务逻辑时 (Rust)
migration/src/: 创建 SQL 迁移entity/src/: 更新 Sea-ORM 实体,手动补充部分注意不要被自动生成覆盖api/src/: 定义模块专用的*ErrorCode(或在framework/error/中定义通用错误码)service/src/: 实现具体业务逻辑api/src/: 使用create_routes导出路由并接入api_setup- 运行
cargo check && cargo test验证类型与测试(API 集成测试使用 cucumber BDD,见apps/server/api/tests/)
新增前端页面时 (server-ui)
routes/: 按 TanStack Router 文件路由约定新建.tsx文件api/: 添加对应的 API 调用函数components/+.module.css: 组件与样式文件- 翻译文本添加到
public/locales/{lang}/{namespace}.json - 运行
moon run server-ui:typecheck验证类型 - 开发调试:
cd apps/server-ui && pnpm run dev
新增扩展功能时 (extension)
common/data/domain/或common/data/dto/: 数据模型common/api/: API 层,fillBridgeApi()注册entrypoints/offscreen/或entrypoints/background/: Service 实现- 涉及表结构变更时,在
entrypoints/offscreen/worker/changeLog/添加changeLogV{version}.js - 运行
npm run compile验证类型
最佳实践
- 涉及项目模块细节问题时,优先查阅
docs/src/下对应模块的文档 - 涉及扩展 DB 事务或密集计算时,优先在 Offscreen Document 中处理
- 涉及第三方库的特定版本兼容性问题、已知 bug 或不熟悉的 API 时,先搜索官方文档和已知解决方案,再动手处理
- 生成 React 组件时,默认配套同名的
.module.css(仅限 server-ui 管理后台,使用 Mantine v9;扩展使用 Ant Design v5) - 启动扩展开发用
cd apps/extension && pnpm run dev,加载.output/chrome-mv3-dev - Rust 路由改动后运行
cargo check验证类型,不用cargo run全量编译;新增业务逻辑记得同时运行cargo test - 发布时运行
moon run <project>:bump,自动升版本、生成 changelog、commit 并 tag
5. 构建与 CI 调试
构建工具
- Monorepo: Moon (@moonrepo/cli 2.3.2)
- 配置:
.moon/workspace.yml,.moon/toolchains.yml - JS/TS 任务: Moon 自动从
package.jsonscripts 推断(script 名中的:自动转为-) - Rust 任务: 在
moon.yml中显式定义 - 常用命令:
moon run <project>:<task>— 运行某项目的特定任务moon run :<task>— 所有项目运行某任务moon run <tag>:<task>— 某 tag 的所有项目运行某任务moon ci --affected— CI 中运行受影响项目的 pipelinemoon query projects— 列出所有项目moon query tasks— 列出所有任务moon check— 验证配置
- 工具链: 由 Nix flake 统一管理(Node.js →
.node-version,Rust →rust-toolchain.toml,moon CLI 内置于flake.nix) - 注意: 升级 moon 版本时同步更新
flake.nix中的moonVersion和moonSha256 - 注意:
.moon/toolchains.yml必须是复数(Moon v2.3 bug 导致moon init生成单数toolchain.yml但实际不加载)
CI 调试指南
快速定位 moon ci 失败:
moon ci 报 Failed
├─ 有任务输出(含 Error / error[E...])→ 看具体编译/运行错误
├─ 无任务输出,但有 moon 引擎 Error 行(如 task_runner::missing_outputs)
│ → 检查 moon.yml 的 outputs 路径是否匹配实际产物
└─ 无任务输出,无 moon Error 行,任务静默失败
→ 可能是 OOM(exit 137),单独跑 moon run <task> 验证
关键认知:
- moon 中 task 输出(cargo/stdout)和 moon 引擎日志是两条独立通道
buffer-only-failure仅显示任务非 0 退出时的输出。任务 exit 0 但后置校验失败(如 missing_outputs),buffer 会被丢弃- moon 引擎 Error 行不会被
MOON_LOG级别过滤,始终可见 missing_outputs表示moon.yml中outputs声明的路径不存在,修正路径即可
调试命令:
moon run <project>:<task> # 隔离跑单个任务,看完整输出
moon run <project>:<task> --log trace # 带 moon 内部日志(会输出大量信息)
MOON_DEBUG_PROCESS_INPUT=true moon run <project>:<task> # 显示传给子进程的 stdin
moon debug config # 查看 moon 内部配置加载状态
附录 框架约定与扩展机制
框架约定
framework::prelude::*→err!,ApiResult,ApiError,AppErrorCode,#[error]宏,IntoStaticStr- 错误码导入: 框架级用
use framework::error::xxx::XxxErrorCode,模块级用#[error]宏定义在api/src/*.rs中 - 每个业务子 crate 实现
pub fn create_routes(state: AppState) -> OpenApiRouter(index模块除外,其不需要 state) - 所有路由嵌套在
/api下,通过api_setup函数组装(在api/src/lib.rs中调用) - handler 使用
#[debug_handler]attribute 辅助编译期错误提示 ValidJson<T>验证 JSON body,ValidQuery<T>验证 query 参数Extension<Principal>提取 JWT 身份- 条件查询:
query.apply_if(value, |q, v| q.filter(condition)) - 分页:
Entity::find().order_by_xxx().paginate(&conn, page_size)
扩展内部机制
- 内部 API 注册:
fillBridgeApi({ api })+mergeServiceMethod(map, ServiceClass) - 方法名 =
className + methodName(小驼峰) - 通信链: ContentScript ↔ Background ↔ Offscreen ↔ WebWorker
- 自定义 ORM: BaseService → database.js (PGlite 操作, JSON ↔ SQL, 小驼峰↔下划线)
- Schema 变更:
changeLogV{version}.js+ version 表 (事务执行) - 支持的招聘平台详见
docs/src/README.md