mirror of
https://github.com/certd/certd.git
synced 2026-06-10 18:57:33 +08:00
docs: 整理并补充项目开发规则文档
This commit is contained in:
@@ -0,0 +1,35 @@
|
||||
# 后端规则
|
||||
|
||||
主包:`packages/ui/certd-server`。后端使用 Node.js、ESM、TypeScript、MidwayJS 3、Koa、TypeORM,默认 better-sqlite3,同时支持 PostgreSQL 和 MySQL,并通过 `@certd/midway-flyway-js` 使用类似 Flyway 的 SQL 迁移机制。
|
||||
|
||||
详细入口、模块和验证命令见 `.codex/repo-map.md`。
|
||||
|
||||
## 默认开发配置
|
||||
|
||||
- HTTP 端口:`7001`
|
||||
- HTTPS 端口:`7002`
|
||||
- 默认 SQLite 数据库:`./data/db.sqlite`
|
||||
- 默认文件根目录:`./data/files`
|
||||
|
||||
## 数据与迁移
|
||||
|
||||
- 后端使用 TypeORM 实体加 SQL 迁移。
|
||||
- 重点查看 `packages/ui/certd-server/src/modules/**/entity/*.ts` 和 `packages/ui/certd-server/db/migration/*.sql`。
|
||||
- 默认配置中 `synchronize: false`,涉及表结构变更时应添加或更新迁移脚本,不要依赖 TypeORM 自动同步。
|
||||
|
||||
## 文件上传
|
||||
|
||||
使用 `/basic/file/upload` 上传文件后,接口返回的是临时缓存 key。业务保存表单或设置时,后端必须调用 `FileService.saveFile(userId, key, "public" | "private")` 转成永久文件 key 后再入库/入设置;不要直接保存 `tmpfile_key_...`,否则后续回显或下载会失效。
|
||||
|
||||
## Service 与事务
|
||||
|
||||
- 后端方法参数超过 3 个时,尽量改为对象参数传入。
|
||||
- 需要传入 `manager` / `EntityManager` 做事务传播的方法,必须使用对象参数,不要把 `manager` 作为位置参数藏在参数列表末尾。
|
||||
- 后端 service 层只有存在事务链路传播需求时才定义 `ctx`,不要为了将来可能需要而提前给普通方法加 `ctx`。
|
||||
- 事务链路方法统一采用 `method(ctx, req)` 形式,`ctx` 放第一位并承载 `manager?: EntityManager` 等横切上下文,业务参数放在 `req` 对象里,例如 `settleCommission({ manager }, { tradeId, userId, amount })`。
|
||||
- 无事务链路需求的普通查询、纯函数和简单私有方法继续使用明确参数。
|
||||
- service 内部需要根据事务上下文选择 Repository 时,优先使用 `BaseService.getRepo(ctx, EntityClass)`;不要在业务方法里反复写 `ctx.manager?.getRepository(Entity) || this.xxxRepository`。
|
||||
- 拿到 repo 后 save/update/delete/find 都能做,不需要再包一层 `saveEntity` 之类的单一用途方法。
|
||||
- `ctx` 类型统一从 `BaseService` 导出的 `ServiceContext` 复用,不要在每个 service 里重复定义。
|
||||
- 需要“有事务则复用、无事务则开启”时,使用 `BaseService.transactionWithCtx(ctx, callback)`:`ctx.manager` 存在则直接执行 callback,否则自动 `this.transaction()`。不要在业务代码里手写 `if (ctx.manager) { ... } else { await this.transaction(...) }`。
|
||||
- 新增方法注意不要与 `BaseService` 基类方法签名冲突,例如 `delete(id)` vs `BaseService.delete(ids, where?)`,ts-node 下会直接 TS2416 编译报错。冲突时改用具体名称如 `deleteById`。
|
||||
@@ -0,0 +1,24 @@
|
||||
# 代码风格规则
|
||||
|
||||
## 基本原则
|
||||
|
||||
- 中文 README 在部分 PowerShell 环境中可能显示乱码;`README_en.md` 可读性更好,且包含同样的高层项目说明。
|
||||
- 根包管理器是 pnpm,不要引入 npm/yarn lockfile。
|
||||
- 优先沿用现有模块、插件、服务模式,再考虑新增抽象。
|
||||
- 注意本地数据和配置里可能包含凭据、证书材料等敏感信息。
|
||||
|
||||
## 注释
|
||||
|
||||
本仓库代码注释优先使用中文,尤其是解释业务规则、兼容逻辑、协议细节和隐藏风险时;除非文件已有明确英文注释风格或引用外部英文术语,否则不要新增英文说明性注释。
|
||||
|
||||
## 可读性
|
||||
|
||||
代码可读性优先于短写法。遇到包含业务分支的复杂三元表达式、内联对象、链式调用或条件组合时,优先拆成命名清晰的中间变量、独立分支或小函数,让读代码的人能一眼看出业务意图;不要为了少写几行把逻辑压成难读的一坨。
|
||||
|
||||
## DRY
|
||||
|
||||
遵守 DRY 原则:同一业务规则、字段转换、权限判断、Repository 选择、事务传播、金额计算等逻辑不要在多个地方复制粘贴。第二次出现时可以先保持清晰,第三次出现前应优先抽成局部 helper、service 方法或已有公共工具;抽象要服务于减少真实重复和降低修改风险,不要为了形式上的“复用”制造过度设计。
|
||||
|
||||
## 单一职责
|
||||
|
||||
遵守单一职责原则:一个方法只负责一个清晰的业务步骤或技术步骤。流程编排方法可以串联多个步骤,但具体的校验、计算、持久化、状态变更、展示数据组装应尽量拆到命名明确的小方法中;不要让一个方法同时承担查询、校验、计算、写库、格式化返回等过多职责。
|
||||
@@ -0,0 +1,31 @@
|
||||
# 前端规则
|
||||
|
||||
主包:`packages/ui/certd-client`。前端使用 Vue 3、Vite、TypeScript、Ant Design Vue、Fast Crud、Pinia、vue-router、vue-i18n、Tailwind/Windi 相关样式工具。
|
||||
|
||||
详细入口、路由、状态、API、视图、locale 和验证命令见 `.codex/repo-map.md`。
|
||||
|
||||
## 禁跑命令
|
||||
|
||||
- 不要运行前端 `pnpm tsc` / `vue-tsc`:当前依赖组合中 `vue-tsc@1.8.27` 会直接抛内部错误 `Search string not found: "/supportedTSExtensions = .*(?=;)/"`,不是有效的项目类型检查结果。
|
||||
- 前端暂不跑单元测试;当前 `test:unit` 只是占位脚本。
|
||||
|
||||
## 格式化与校验
|
||||
|
||||
前端 TS/Vue/locale 等文件改动后,优先只对本次改动文件运行项目现有自动格式化/修复:
|
||||
|
||||
- Prettier:`packages\ui\certd-client\node_modules\.bin\prettier.cmd --write <files>`
|
||||
- ESLint:`packages\ui\certd-client\node_modules\.bin\eslint.cmd --fix <files>`
|
||||
|
||||
不要为了格式化无关文件而扩大 diff。项目保留了 `tslint` 依赖,但当前主要使用 ESLint + Prettier。
|
||||
|
||||
## Fast Crud 页面
|
||||
|
||||
- 列表管理、后台管理、记录查询、CRUD 表格类页面,默认优先使用 Fast Crud(`@fast-crud/fast-crud`、`fs-crud`、`useFs`、`createCrudOptions`)实现。
|
||||
- 只有轻量只读展示、强交互自定义界面或已有页面模式明确不适合 Fast Crud 时,才手写 `a-table` / 自定义列表,并在回复中说明原因。
|
||||
- 开发或重构这类页面前,先读取 `.trae/skills/fast-crud-page-dev/SKILL.md`,按仓库内 Fast Crud 页面拆分与验证方式实现。
|
||||
- 页面内嵌 Fast Crud 表格时,要显式给外层容器稳定高度或 `flex: 1; min-height: 0` 的撑满链路;Fast Crud 依赖外部元素高度,不能只依赖表格默认高度。
|
||||
- 后台管理列表里展示或筛选用户字段时,优先参考 `packages/ui/certd-client/src/views/sys/suite/user-suite/crud.tsx` 的 `userId` 字段模式:前端使用 `table-select` + `/sys/authority/user/getSimpleUserByIds` 字典回显和搜索;不要为了展示用户名让后端列表接口额外 `fillSimpleUser` / `userDisplay`,除非该接口本身就是用户端业务列表且已有明确模式。
|
||||
|
||||
## 对话框
|
||||
|
||||
前端对话框里只做纯确认时可以使用 `Modal.confirm`;只要对话框里有字段输入、表单校验或提交字段,统一使用 `useFormDialog` / `openFormDialog`,不要在 `Modal.confirm` 的 `content` 里手写输入框。
|
||||
@@ -0,0 +1,42 @@
|
||||
# 流水线与插件规则
|
||||
|
||||
项目最关键的架构概念是证书流水线。核心导出、关键抽象、插件目录和共享 helper 位置见 `.codex/repo-map.md`。
|
||||
|
||||
插件是核心能力,不是边缘功能。新增服务商、DNS 验证、证书部署、通知方式等能力,通常应该放在插件包里,或放在 `packages/ui/certd-server/src/plugins/<plugin-name>/` 下。
|
||||
|
||||
## 改动归属
|
||||
|
||||
修改证书申请、验证、部署或通知行为时,先判断改动属于哪里:
|
||||
|
||||
- ACME client 代码
|
||||
- pipeline 核心抽象
|
||||
- 后端 module/service/entity/controller
|
||||
- 某个具体插件实现
|
||||
- 前端 view/form/schema
|
||||
|
||||
如果只是某个服务商或部署目标的问题,不要轻易修改共享 pipeline/core 行为,除非确实是可复用的公共能力。
|
||||
|
||||
## ACME / EAB
|
||||
|
||||
- 公共 EAB(尤其是 Google EAB)可能只能创建一次 ACME 账号。要跨用户复用公共 EAB,应保存并复用同一个 ACME account private key;`accountUrl` 如果存到 `userContext` 里,只能视为当前用户缓存,因为 `userContext` 跟用户 id 走。
|
||||
- ACME 协议的 `newAccount` 支持 `onlyReturnExisting`。使用同一个 account private key 调用 `newAccount({ onlyReturnExisting: true })` 可以取回已创建账号的 URL,且不会再次消费 EAB。
|
||||
- 修改 EAB 的 `kid` 后,应重新生成绑定该 `kid` 的 account private key;否则应阻止继续申请并提示用户刷新账号私钥。
|
||||
|
||||
## 插件开发技能
|
||||
|
||||
仓库内置了 Certd 插件开发技能,供 Trae 和 Codex 共用:
|
||||
|
||||
- Trae 入口:`.trae/skills`
|
||||
- Codex 入口:`.codex/skills`
|
||||
|
||||
其中 `.codex/skills` 是指向 `.trae/skills` 的目录链接,不要复制出第二份技能内容。更新技能时只维护 `.trae/skills` 下的原始文件,Codex 会通过 `.codex/skills` 读取同一份内容。
|
||||
|
||||
当前技能包括:
|
||||
|
||||
- `access-plugin-dev`:开发 Access 授权插件
|
||||
- `dns-provider-dev`:开发 DNS Provider 插件
|
||||
- `fast-crud-page-dev`:开发或重构前端 Fast Crud 列表管理页面
|
||||
- `task-plugin-dev`:开发 Task 部署任务插件
|
||||
- `plugin-converter`:将插件转换为 YAML 配置
|
||||
|
||||
做插件相关任务时,先读取对应技能目录下的 `SKILL.md`,再进入具体实现。若用户在插件开发中指出更好的做法,应总结并更新对应技能。
|
||||
@@ -0,0 +1,26 @@
|
||||
# 测试与验证规则
|
||||
|
||||
实现新功能或修复行为缺陷前,先补对应单元测试,并先运行测试确认它处于失败状态;再实现功能或修复代码,反复运行聚焦单元测试直到通过。若某项改动确实不适合先写单元测试,应在回复中说明原因和替代验证方式。
|
||||
|
||||
后补单元测试时,应先基于对正确行为的实际预期编写测试,而不是为了迎合现有实现改写预期;如果运行后出现红灯,且通过测试需要修改已有实现,应先向用户确认这是确实的 bug,还是原本需求/既有行为就是如此;确认后再修改原始实现,避免把测试补充变成未经确认的行为改动。
|
||||
|
||||
## 后端单测
|
||||
|
||||
- 后端纯单元测试用例放在 `src` 目录内,并尽量与被测文件相邻,例如 `src/utils/random.test.ts`。
|
||||
- 对应 `test:unit` 只跑 `src/**/*.test.ts`,构建/打包配置应排除这些 `*.test.ts` 文件。
|
||||
- 单元测试需要 mock ESM 静态 import 时,优先使用 `esmock`,不要为了测试把业务代码改成构造函数注入或把逻辑挪到调用方。
|
||||
- 各包 `test:unit` 脚本应显式设置 `NODE_ENV=unittest`。
|
||||
|
||||
## 运行方式
|
||||
|
||||
单个 monorepo 包运行单元测试时,优先使用 `corepack pnpm --dir <包目录> test:unit`,例如:
|
||||
|
||||
- `corepack pnpm --dir packages\ui\certd-server test:unit`
|
||||
- `corepack pnpm --dir packages\core\basic test:unit`
|
||||
- `corepack pnpm --dir packages\plugins\plugin-lib test:unit`
|
||||
|
||||
也可以用包名过滤,例如 `corepack pnpm --filter @certd/ui-server test:unit`。
|
||||
|
||||
前端 `packages\ui\certd-client` 暂时不跑单元测试。前端改动优先使用 Prettier/ESLint 做改动文件验证。
|
||||
|
||||
优先对改动包运行聚焦测试;只有跨包影响明显时再考虑全 monorepo 构建。
|
||||
@@ -0,0 +1,106 @@
|
||||
# Certd 仓库地图
|
||||
|
||||
本文档由 Codex 子智能体只读探索后整理,用于后续开发时快速定位代码。进入仓库仍应先读取根目录 `AGENTS.md`,本文件只作为导航补充。
|
||||
|
||||
## 顶层结构
|
||||
|
||||
Certd 是 pnpm + lerna-lite monorepo。
|
||||
|
||||
- `package.json`:根脚本与 workspace 元信息
|
||||
- `pnpm-workspace.yaml`:workspace 匹配规则,包含 `packages/**`、`packages/ui/**`
|
||||
- `lerna.json`:lerna-lite 配置
|
||||
- `docs`:VitePress 文档站
|
||||
- `docker`:Docker 安装和运行相关文件
|
||||
- `packages/core/acme-client`:ACME 协议客户端
|
||||
- `packages/core/basic`:共享基础工具
|
||||
- `packages/core/pipeline`:流水线核心抽象、插件模型、执行上下文
|
||||
- `packages/libs`:共享集成库
|
||||
- `packages/plugins/plugin-lib`:证书、DNS Provider、格式转换等插件共享能力
|
||||
- `packages/plugins/plugin-cert`:证书插件包入口
|
||||
- `packages/ui/certd-server`:后端 Midway 服务
|
||||
- `packages/ui/certd-client`:前端 Vue/Vite 管理台
|
||||
- `packages/pro`:商业版独立 Git 工作区,需在该目录内单独检查状态
|
||||
|
||||
运行时或生成产物通常包括根目录 `node_modules`、`logs`、`output`、`lerna-debug.log`、`tmp-certd-client-vite*.log`,以及后端 `packages/ui/certd-server/data`、`packages/ui/certd-server/logs`、各包 `dist`、插件 metadata/yaml 导出结果。
|
||||
|
||||
## 常用验证
|
||||
|
||||
- 根目录启动后端生产模式:`pnpm run start:server`
|
||||
- 后端开发服务:`corepack pnpm --dir packages\ui\certd-server dev`
|
||||
- 后端聚焦单测:`corepack pnpm --dir packages\ui\certd-server test:unit`
|
||||
- 后端完整测试:`corepack pnpm --dir packages\ui\certd-server test`
|
||||
- 后端构建:`corepack pnpm --dir packages\ui\certd-server build`
|
||||
- 前端开发服务:`corepack pnpm --dir packages\ui\certd-client dev`
|
||||
- 前端构建:`corepack pnpm --dir packages\ui\certd-client build`
|
||||
- 前端改动文件格式化:`packages\ui\certd-client\node_modules\.bin\prettier.cmd --write <files>`
|
||||
- 前端改动文件 ESLint 修复:`packages\ui\certd-client\node_modules\.bin\eslint.cmd --fix <files>`
|
||||
|
||||
不要主动运行 `pnpm install`。前端不要运行 `pnpm tsc` / `vue-tsc`,当前依赖组合中 `vue-tsc@1.8.27` 会抛无效内部错误;前端 `test:unit` 也只是占位。
|
||||
|
||||
## 后端地图
|
||||
|
||||
主包:`packages/ui/certd-server`。
|
||||
|
||||
- `bootstrap.js`:Midway 启动入口,使用 `@midwayjs/bootstrap`
|
||||
- `src/configuration.ts`:Midway 主配置,注册组件和全局中间件
|
||||
- `src/config/config.default.ts`:端口、HTTPS、静态文件、cron、TypeORM、Flyway、上传、JWT、Swagger 默认配置
|
||||
- `src/config/loader.ts`:读取 `.env`、`.env.<env>.yaml`,支持 `certd_` 前缀环境变量覆盖嵌套配置
|
||||
- `src/modules`:业务模块根目录,例如 `basic`、`cert`、`cname`、`cron`、`login`、`monitor`、`open`、`pipeline`、`plugin`、`suite`、`sys`
|
||||
- `src/controller`:API 入口,按 `basic`、`user`、`sys`、`openapi` 分组
|
||||
- `db/migration`:SQL 迁移目录,TypeORM `synchronize: false`,表结构变更应配套迁移 SQL
|
||||
|
||||
测试使用 Mocha + Node `assert/strict`,纯单测放在 `src/**/*.test.ts`,尽量与被测文件相邻。可参考 `src/utils/random.test.ts`、`src/controller/basic/app-controller.test.ts`、`src/modules/pipeline/service/pipeline-service.test.ts`。
|
||||
|
||||
## 前端地图
|
||||
|
||||
主包:`packages/ui/certd-client`。
|
||||
|
||||
- `vite.config.ts`:Vite 配置,dev 端口 `3008`,`/api`、`/certd/api` 代理到后端 `127.0.0.1:7001`
|
||||
- `src/main.ts`:Vue 启动入口,注册 AntDV、Vben、router、全局组件、插件和偏好设置
|
||||
- `src/App.vue`:根组件,包含 `AConfigProvider`、`FsFormProvider`、`router-view`
|
||||
- `src/router/index.ts`、`src/router/resolve.ts`:路由入口,使用 `createWebHashHistory`
|
||||
- `src/router/source/modules/certd.ts`:Certd 主业务路由
|
||||
- `src/store`:Pinia store,主要有 `user`、`project`、`settings`、`plugin`
|
||||
- `src/api/service.ts`:Axios 封装
|
||||
- `src/api/tools.ts`:错误与响应工具
|
||||
- `src/views/certd`:核心业务视图,例如 `pipeline`、`cert`、`monitor`、`access`、`notification`、`open`、`project`、`suite`、`wallet`
|
||||
- `src/locales`:国际化入口与语言包
|
||||
|
||||
列表管理、后台管理、记录查询、CRUD 表格页面优先使用 Fast Crud。开发前读取 `.trae/skills/fast-crud-page-dev/SKILL.md`。常见拆分是 `api.ts`、`crud.tsx`、`index.vue`。可参考 `src/views/certd/access`、`src/views/sys/suite/user-suite/crud.tsx`、`src/views/certd/wallet/index.vue`。内嵌 `fs-crud` 时要给外层稳定高度或完整 `flex: 1; min-height: 0` 链路。
|
||||
|
||||
## 流水线与插件地图
|
||||
|
||||
核心入口:`packages/core/pipeline/src/index.ts`,导出 `core`、`dt`、`access`、`registry`、`plugin`、`context`、`decorator`、`service`、`notification`。
|
||||
|
||||
- `packages/core/pipeline/src/plugin`:任务插件抽象,例如 `AbstractTaskPlugin`、`IsTaskPlugin`、`TaskInput`、`pluginRegistry`
|
||||
- `packages/core/pipeline/src/access`:授权插件抽象,例如 `BaseAccess`、`IsAccess`、`AccessInput`、`accessRegistry`
|
||||
- `packages/core/pipeline/src/dt/pipeline.ts`:`Pipeline`、`Stage`、`Task`、`RunStrategy` 等流水线数据结构
|
||||
- `packages/core/pipeline/src/core`:执行器、上下文、运行历史、文件存储等
|
||||
- `packages/core/pipeline/src/service`:CNAME、事件、配置、邮件、URL 等 pipeline service 接口
|
||||
- `packages/ui/certd-server/src/plugins`:后端内置服务商、DNS、部署、通知等插件
|
||||
- `packages/ui/certd-server/src/plugins/plugin-cert`:证书申请核心插件
|
||||
- `packages/ui/certd-server/src/plugins/plugin-lib`:后端插件 helper/access
|
||||
- `packages/plugins/plugin-lib/src/cert`:`CertReader`、`CertConverter`、DNS Provider 公共能力
|
||||
- `packages/plugins/plugin-lib/src/cert/dns-provider`:`AbstractDnsProvider`、`dnsProviderRegistry`、`DomainParser`
|
||||
|
||||
插件开发技能入口:
|
||||
|
||||
- `.trae/skills/dns-provider-dev/SKILL.md`:DNS Provider 插件
|
||||
- `.trae/skills/task-plugin-dev/SKILL.md`:Task 部署任务插件
|
||||
- `.trae/skills/access-plugin-dev/SKILL.md`:Access 授权插件
|
||||
- `.trae/skills/plugin-converter/SKILL.md`:插件转 YAML 配置
|
||||
|
||||
改动归属判断:
|
||||
|
||||
- ACME 协议、EAB、账号、订单、挑战流程:优先看 `packages/core/acme-client` 或 `packages/ui/certd-server/src/plugins/plugin-cert/plugin/cert-plugin/acme.ts`
|
||||
- 流水线执行、任务生命周期、输入输出、注册机制:看 `packages/core/pipeline`
|
||||
- 单个云厂商 DNS 验证、证书部署、API 调用失败:改对应 `packages/ui/certd-server/src/plugins/plugin-xxx`
|
||||
- 通用证书读取、DNS Provider 公共能力、格式转换:改 `packages/plugins/plugin-lib`
|
||||
- 后端业务数据、接口、实体、权限、迁移:改 `packages/ui/certd-server/src/modules` 与 `src/controller`
|
||||
- 表单、列表、插件配置 UI:改 `packages/ui/certd-client/src/views/certd` 及对应 `src/api`
|
||||
|
||||
原则:如果只是单个服务商或部署目标的问题,不动共享 pipeline/core;只有可复用的公共语义或跨插件一致行为,才考虑上移到 `packages/core/pipeline` 或 `packages/plugins/plugin-lib`。
|
||||
|
||||
## Git 注意事项
|
||||
|
||||
子智能体探索时根仓库 `git status --short` 为空。`packages/pro` 也是独立仓库且当时未显示未提交改动,但曾出现无法删除 `packages/pro/.git/index.lock` 的警告;后续操作 pro 仓库前应先检查该锁文件或占用状态。
|
||||
@@ -1,245 +1,70 @@
|
||||
# Certd 开发 Agent 上下文
|
||||
# Certd 开发 Agent 上下文
|
||||
|
||||
这个文件是给在本仓库工作的开发 agent 看的常驻项目说明。后续会话进入仓库后,应先读取它,再按任务需要查看具体代码,避免每次都重新全量扫描项目。
|
||||
这个文件是给在本仓库工作的开发 agent 看的常驻项目说明。进入仓库后先读本文,再按任务读取对应导航或规则文件,避免每次重新全量扫描项目。
|
||||
|
||||
## 项目用途
|
||||
仓库代码导航、目录地图、常用入口和参考文件见 `.codex/repo-map.md`。更细的开发规则拆在 `.codex/agent-rules/` 下;本文只保留最高优先级的规则、架构边界和工作方式。
|
||||
|
||||
Certd 是一个支持私有化部署的 SSL/TLS 证书自动化管理平台。它提供 Web 管理台和后端服务,用于证书申请、续期、部署、监控、通知和开放 API 集成。
|
||||
## 项目定位
|
||||
|
||||
它不只是一个简单的 ACME 客户端。项目的核心产品模型是“证书流水线”:
|
||||
Certd 是支持私有化部署的 SSL/TLS 证书自动化管理平台,提供 Web 管理台和后端服务,用于证书申请、续期、部署、监控、通知和开放 API 集成。
|
||||
|
||||
核心产品模型是“证书流水线”:
|
||||
|
||||
- 通过 ACME 申请证书
|
||||
- 支持 DNS-01、HTTP-01、CNAME 代理以及各类服务商集成来完成域名验证
|
||||
- 支持将证书转换或导出为 pem、pfx、der、jks、p7b 等格式
|
||||
- 支持把证书部署到主机、Nginx、Kubernetes、CDN、云厂商、面板等目标
|
||||
- 支持通知用户,并监控站点证书过期时间
|
||||
- 使用 DNS-01、HTTP-01、CNAME 代理或服务商集成完成域名验证
|
||||
- 将证书转换或导出为 pem、pfx、der、jks、p7b 等格式
|
||||
- 部署证书到主机、Nginx、Kubernetes、CDN、云厂商、面板等目标
|
||||
- 通知用户,并监控站点证书过期时间
|
||||
|
||||
由于系统会保存证书、云厂商凭据、SSH 信息、API Key 等敏感数据,产品定位上强烈建议私有化/本地部署。
|
||||
系统会保存证书、云厂商凭据、SSH 信息、API Key 等敏感数据,始终按私有化/本地部署产品处理,避免泄露本地数据和配置。
|
||||
|
||||
## 仓库结构
|
||||
## 必读索引
|
||||
|
||||
这是一个 pnpm + lerna 的 monorepo。
|
||||
- `.codex/repo-map.md`:仓库结构、后端/前端入口、流水线与插件地图、验证命令
|
||||
- `.codex/agent-rules/backend.md`:后端、数据库迁移、文件上传、service/事务约定
|
||||
- `.codex/agent-rules/frontend.md`:前端、Fast Crud、弹窗表单、格式化和禁跑命令
|
||||
- `.codex/agent-rules/plugins.md`:流水线、插件归属、ACME/EAB、插件开发技能
|
||||
- `.codex/agent-rules/testing.md`:测试优先策略、单测位置、ESM mock、聚焦验证
|
||||
- `.codex/agent-rules/coding-style.md`:注释、可读性、DRY、单一职责等通用代码风格
|
||||
|
||||
- `package.json`:根脚本和 workspace 元信息
|
||||
- `pnpm-workspace.yaml`:workspace 包匹配规则
|
||||
- `lerna.json`:lerna-lite 配置
|
||||
- `docs/`:VitePress 文档站
|
||||
- `docker/`:Docker 安装和运行相关文件
|
||||
- `packages/core/acme-client/`:ACME 协议客户端,风格接近 node-acme-client
|
||||
- `packages/core/basic/`:共享基础工具和基础设施
|
||||
- `packages/core/pipeline/`:流水线核心、注册表、装饰器、插件模型、上下文、服务、通知等
|
||||
- `packages/libs/`:共享集成与辅助库,例如 server、Huawei、JDCloud、Kubernetes、iframe
|
||||
- `packages/plugins/plugin-lib/`:通用插件辅助能力和证书相关共享代码
|
||||
- `packages/plugins/plugin-cert/`:证书流水线插件包
|
||||
- `packages/pro/`:商业版/专业版相关包
|
||||
- `packages/ui/certd-server/`:后端服务
|
||||
- `packages/ui/certd-client/`:前端 Web 管理台
|
||||
## 仓库边界
|
||||
|
||||
这是一个 pnpm + lerna 的 monorepo。核心定位:
|
||||
|
||||
- `packages/ui/certd-server`:后端服务
|
||||
- `packages/ui/certd-client`:前端 Web 管理台
|
||||
- `packages/core/pipeline`:流水线核心
|
||||
- `packages/core/acme-client`:ACME 协议客户端
|
||||
- `packages/plugins/plugin-lib`:通用插件辅助能力和证书相关共享代码
|
||||
|
||||
`packages/pro/` 是独立 Git 工作区,使用 `packages/pro/.git` 管理。根仓库的 `git status` / `git diff` 默认看不到这里的实际改动;修改商业版代码后,要在 `packages/pro` 目录内单独执行 `git status` / `git diff` 检查。
|
||||
|
||||
## 后端
|
||||
## 硬性规则
|
||||
|
||||
主要后端包:`packages/ui/certd-server`。
|
||||
|
||||
技术栈:
|
||||
|
||||
- Node.js、ESM、TypeScript
|
||||
- MidwayJS 3
|
||||
- Koa
|
||||
- TypeORM
|
||||
- 默认使用 better-sqlite3,同时支持 PostgreSQL 和 MySQL
|
||||
- 通过 `@certd/midway-flyway-js` 使用类似 Flyway 的 SQL 迁移机制
|
||||
|
||||
重要位置:
|
||||
|
||||
- `packages/ui/certd-server/src/config/config.default.ts`:默认服务、静态文件、数据库、定时任务、认证、上传、Swagger 配置
|
||||
- `packages/ui/certd-server/src/config/`:环境与配置加载逻辑
|
||||
- `packages/ui/certd-server/src/configuration.ts`:Midway 应用配置、中间件注册、组件导入
|
||||
- `packages/ui/certd-server/src/modules/`:业务模块,例如 pipeline、cert、cron、monitor、login、open API、sys、plugin、cname、notification
|
||||
- `packages/ui/certd-server/src/controller/`:按 API 领域划分的控制器
|
||||
- `packages/ui/certd-server/src/plugins/`:后端内置的具体服务商、部署、通知等插件
|
||||
- `packages/ui/certd-server/db/migration/`:数据库迁移 SQL
|
||||
- `packages/ui/certd-server/data/`:本地运行数据,例如 SQLite 数据库和生成文件
|
||||
- `packages/ui/certd-server/logs/`:运行日志
|
||||
|
||||
已观察到的默认开发配置:
|
||||
|
||||
- HTTP 端口:`7001`
|
||||
- HTTPS 端口:`7002`
|
||||
- 默认 SQLite 数据库:`./data/db.sqlite`
|
||||
- 默认文件根目录:`./data/files`
|
||||
|
||||
常用脚本:
|
||||
|
||||
- 根目录 `pnpm run start:server`:以生产模式启动后端包
|
||||
- 后端 `pnpm run dev`:启动 Midway watch/dev 服务
|
||||
- 后端 `pnpm run test`:运行后端 mocha 测试
|
||||
- 后端 `pnpm run build`:构建后端并导出插件元数据
|
||||
|
||||
## 前端
|
||||
|
||||
主要前端包:`packages/ui/certd-client`。
|
||||
|
||||
技术栈:
|
||||
|
||||
- Vue 3
|
||||
- Vite
|
||||
- TypeScript
|
||||
- Ant Design Vue
|
||||
- Fast Crud
|
||||
- Pinia
|
||||
- vue-router
|
||||
- vue-i18n
|
||||
- Tailwind/Windi 相关样式工具
|
||||
|
||||
重要位置:
|
||||
|
||||
- `packages/ui/certd-client/src/main.ts`:前端启动入口
|
||||
- `packages/ui/certd-client/src/App.vue`:根组件
|
||||
- `packages/ui/certd-client/src/api/`:API 调用封装
|
||||
- `packages/ui/certd-client/src/router/`:路由
|
||||
- `packages/ui/certd-client/src/store/`:Pinia store
|
||||
- `packages/ui/certd-client/src/views/certd/`:核心产品页面,例如流水线、证书、授权、监控、通知、开放 API、项目、支付、插件
|
||||
- `packages/ui/certd-client/src/components/`:共享 UI 组件
|
||||
- `packages/ui/certd-client/src/locales/`:国际化
|
||||
|
||||
常用脚本:
|
||||
|
||||
- 前端 `pnpm dev`:启动 Vite 开发服务
|
||||
- 前端 `pnpm build`:生产构建
|
||||
- 不要运行前端 `pnpm tsc` / `vue-tsc`:当前依赖组合中 `vue-tsc@1.8.27` 会直接抛内部错误 `Search string not found: "/supportedTSExtensions = .*(?=;)/"`,不是有效的项目类型检查结果。
|
||||
- 前端暂不跑单元测试;当前 `test:unit` 只是占位脚本
|
||||
|
||||
前端列表管理页面约定:
|
||||
|
||||
- 列表管理、后台管理、记录查询、CRUD 表格类页面,默认优先使用 Fast Crud(`@fast-crud/fast-crud`、`fs-crud`、`useFs`、`createCrudOptions`)实现。
|
||||
- 只有轻量只读展示、强交互自定义界面或已有页面模式明确不适合 Fast Crud 时,才手写 `a-table` / 自定义列表,并在回复中说明原因。
|
||||
- 开发或重构这类页面前,先读取 `.trae/skills/fast-crud-page-dev/SKILL.md`,按仓库内 Fast Crud 页面拆分与验证方式实现。
|
||||
- 前端对话框里只做纯确认时可以使用 `Modal.confirm`;只要对话框里有字段输入、表单校验或提交字段,统一使用 `useFormDialog` / `openFormDialog`,不要在 `Modal.confirm` 的 `content` 里手写输入框。
|
||||
- 页面内嵌 Fast Crud 表格时,要显式给外层容器稳定高度或 `flex: 1; min-height: 0` 的撑满链路;Fast Crud 依赖外部元素高度,不能只依赖表格默认高度。
|
||||
- 后台管理列表里展示或筛选用户字段时,优先参考 `packages/ui/certd-client/src/views/sys/suite/user-suite/crud.tsx` 的 `userId` 字段模式:前端使用 `table-select` + `/sys/authority/user/getSimpleUserByIds` 字典回显和搜索;不要为了展示用户名让后端列表接口额外 `fillSimpleUser` / `userDisplay`,除非该接口本身就是用户端业务列表且已有明确模式。
|
||||
|
||||
## 流水线与插件模型
|
||||
|
||||
项目最关键的架构概念是证书流水线。
|
||||
|
||||
可以从 `packages/core/pipeline/src/index.ts` 入手,它导出:
|
||||
|
||||
- `core`
|
||||
- `dt`
|
||||
- `access`
|
||||
- `registry`
|
||||
- `plugin`
|
||||
- `context`
|
||||
- `decorator`
|
||||
- `service`
|
||||
- `notification`
|
||||
|
||||
插件是核心能力,不是边缘功能。新增服务商、DNS 验证、证书部署、通知方式等能力,通常应该放在插件包里,或放在 `packages/ui/certd-server/src/plugins/<plugin-name>/` 下。
|
||||
|
||||
后端已看到的插件类型包括:
|
||||
|
||||
- DNS 和注册商服务商:Aliyun、Tencent、Cloudflare、Huawei、JDCloud、AWS、Azure、Google、GoDaddy、Namesilo、Xinnet、West、UCloud、Qiniu、Upyun、Volcengine 等
|
||||
- 部署目标:host、Kubernetes、Nginx Proxy Manager、APISIX、Proxmox、QNAP、Dokploy、GoEdge、各类 CDN、各类面板
|
||||
- 系统/产品插件:notification、captcha、oauth、admin、plus/pro、demo/template
|
||||
|
||||
当修改证书申请、验证、部署或通知行为时,先判断改动属于哪里:
|
||||
|
||||
- ACME client 代码
|
||||
- pipeline 核心抽象
|
||||
- 后端 module/service/entity/controller
|
||||
- 某个具体插件实现
|
||||
- 前端 view/form/schema
|
||||
|
||||
如果只是某个服务商或部署目标的问题,不要轻易修改共享 pipeline/core 行为,除非确实是可复用的公共能力。
|
||||
|
||||
### ACME / EAB 注意事项
|
||||
|
||||
- 公共 EAB(尤其是 Google EAB)可能只能创建一次 ACME 账号。要跨用户复用公共 EAB,应保存并复用同一个 ACME account private key;`accountUrl` 如果存到 `userContext` 里,只能视为当前用户缓存,因为 `userContext` 跟用户 id 走。
|
||||
- ACME 协议的 `newAccount` 支持 `onlyReturnExisting`。使用同一个 account private key 调用 `newAccount({ onlyReturnExisting: true })` 可以取回已创建账号的 URL,且不会再次消费 EAB。
|
||||
- 修改 EAB 的 `kid` 后,应重新生成绑定该 `kid` 的 account private key;否则应阻止继续申请并提示用户刷新账号私钥。
|
||||
|
||||
## 数据与迁移
|
||||
|
||||
后端使用 TypeORM 实体加 SQL 迁移。
|
||||
|
||||
重点查看:
|
||||
|
||||
- `packages/ui/certd-server/src/modules/**/entity/*.ts`
|
||||
- `packages/ui/certd-server/db/migration/*.sql`
|
||||
|
||||
默认配置中 `synchronize: false`,所以涉及表结构变更时,通常应该添加或更新迁移脚本,而不是依赖 TypeORM 自动同步。
|
||||
|
||||
## 开发注意事项
|
||||
|
||||
- 中文 README 在部分 PowerShell 环境中可能显示乱码;`README_en.md` 可读性更好,且包含同样的高层项目说明。
|
||||
- 初次整理时观察到当前分支为 `v2-dev`。
|
||||
- 根包管理器是 pnpm,不要引入 npm/yarn lockfile。
|
||||
- 优先沿用现有模块、插件、服务模式,再考虑新增抽象。
|
||||
- `packages/ui/certd-server/data/`、`logs/`、生成的 metadata/dist 等通常视为运行时或构建产物,除非任务明确要求处理它们。
|
||||
- 注意本地数据和配置里可能包含凭据、证书材料等敏感信息。
|
||||
- 使用 `/basic/file/upload` 上传文件后,接口返回的是临时缓存 key。业务保存表单或设置时,后端必须调用 `FileService.saveFile(userId, key, "public" | "private")` 转成永久文件 key 后再入库/入设置;不要直接保存 `tmpfile_key_...`,否则后续回显或下载会失效。
|
||||
- 本仓库代码注释优先使用中文,尤其是解释业务规则、兼容逻辑、协议细节和隐藏风险时;除非文件已有明确英文注释风格或引用外部英文术语,否则不要新增英文说明性注释。
|
||||
- 代码可读性优先于短写法。遇到包含业务分支的复杂三元表达式、内联对象、链式调用或条件组合时,优先拆成命名清晰的中间变量、独立分支或小函数,让读代码的人能一眼看出业务意图;不要为了少写几行把逻辑压成难读的一坨。
|
||||
- 遵守 DRY 原则:同一业务规则、字段转换、权限判断、Repository 选择、事务传播、金额计算等逻辑不要在多个地方复制粘贴。第二次出现时可以先保持清晰,第三次出现前应优先抽成局部 helper、service 方法或已有公共工具;抽象要服务于减少真实重复和降低修改风险,不要为了形式上的“复用”制造过度设计。
|
||||
- 遵守单一职责原则:一个方法只负责一个清晰的业务步骤或技术步骤。流程编排方法可以串联多个步骤,但具体的校验、计算、持久化、状态变更、展示数据组装应尽量拆到命名明确的小方法中;不要让一个方法同时承担查询、校验、计算、写库、格式化返回等过多职责。
|
||||
- 后端方法参数超过 3 个时,尽量改为对象参数传入;需要传入 `manager` / `EntityManager` 做事务传播的方法,必须使用对象参数,不要把 `manager` 作为位置参数藏在参数列表末尾。
|
||||
- 后端 service 层只有存在事务链路传播需求时才定义 `ctx`,不要为了将来可能需要而提前给普通方法加 `ctx`。事务链路方法统一采用 `method(ctx, req)` 形式,`ctx` 放第一位并承载 `manager?: EntityManager` 等横切上下文,业务参数放在 `req` 对象里,例如 `settleCommission({ manager }, { tradeId, userId, amount })`。无事务链路需求的普通查询、纯函数和简单私有方法继续使用明确参数。
|
||||
- service 内部需要根据事务上下文选择 Repository 时,优先使用 `BaseService.getRepo(ctx, EntityClass)`;不要在业务方法里反复写 `ctx.manager?.getRepository(Entity) || this.xxxRepository`。拿到 repo 后 save/update/delete/find 都能做,不需要再包一层 `saveEntity` 之类的单一用途方法。`ctx` 类型统一从 `BaseService` 导出的 `ServiceContext` 复用,不要在每个 service 里重复定义。
|
||||
- 不要主动运行 `pnpm install`;用户会事先准备好 `node_modules`。如果 `pnpm install` 或测试因缺少依赖、TTY、网络问题失败,停止尝试并告知用户环境问题。
|
||||
- 前端不要运行 `pnpm tsc` / `vue-tsc`;当前依赖组合中 `vue-tsc@1.8.27` 会抛无效内部错误。前端 `test:unit` 只是占位脚本。
|
||||
- 不要把 `packages/ui/certd-server/data/`、`logs/`、生成的 metadata/dist 等运行时或构建产物纳入改动,除非任务明确要求。
|
||||
- 做数据库结构变更时,添加或更新迁移脚本,不要依赖 TypeORM 自动同步。
|
||||
- 做插件相关任务时,先读取对应 `.trae/skills/<skill>/SKILL.md`,再进入具体实现。
|
||||
|
||||
- 需要"有事务则复用、无事务则开启"时,使用 `BaseService.transactionWithCtx(ctx, callback)`:ctx.manager 存在则直接执行 callback,否则自动 `this.transaction()`。不要在业务代码里手写 `if (ctx.manager) { ... } else { await this.transaction(...) }`。
|
||||
## 工作方式
|
||||
|
||||
- 新增方法注意不要与 `BaseService` 基类方法签名冲突(如 `delete(id)` vs `BaseService.delete(ids, where?)`),ts-node 下会直接 TS2416 编译报错。冲突时改用具体名称如 `deleteById`。
|
||||
|
||||
## 插件开发技能
|
||||
|
||||
仓库内置了 Certd 插件开发技能,供 Trae 和 Codex 共用:
|
||||
|
||||
- Trae 入口:`.trae/skills`
|
||||
- Codex 入口:`.codex/skills`
|
||||
|
||||
其中 `.codex/skills` 是指向 `.trae/skills` 的目录链接,不要复制出第二份技能内容。更新技能时只维护 `.trae/skills` 下的原始文件,Codex 会通过 `.codex/skills` 读取同一份内容。
|
||||
|
||||
当前技能包括:
|
||||
|
||||
- `access-plugin-dev`:开发 Access 授权插件
|
||||
- `dns-provider-dev`:开发 DNS Provider 插件
|
||||
- `fast-crud-page-dev`:开发或重构前端 Fast Crud 列表管理页面
|
||||
- `task-plugin-dev`:开发 Task 部署任务插件
|
||||
- `plugin-converter`:将插件转换为 YAML 配置
|
||||
|
||||
做插件相关任务时,先读取对应技能目录下的 `SKILL.md`,再进入具体实现。若用户在插件开发中指出更好的做法,应总结并更新对应技能。
|
||||
|
||||
## 快速定向命令
|
||||
|
||||
进入项目后,优先使用这些有目标的读取命令,而不是立刻全仓库扫描:
|
||||
|
||||
```powershell
|
||||
Get-Content -Encoding utf8 package.json
|
||||
Get-Content -Encoding utf8 pnpm-workspace.yaml
|
||||
Get-Content -Encoding utf8 lerna.json
|
||||
Get-Content -Encoding utf8 README_en.md -TotalCount 180
|
||||
Get-Content -Encoding utf8 packages\ui\certd-server\package.json
|
||||
Get-Content -Encoding utf8 packages\ui\certd-client\package.json
|
||||
Get-ChildItem packages\ui\certd-server\src\modules
|
||||
Get-ChildItem packages\ui\certd-server\src\plugins
|
||||
Get-ChildItem packages\ui\certd-client\src\views\certd
|
||||
```
|
||||
|
||||
## 本仓库 Agent 工作方式
|
||||
|
||||
- 先读本文件,再按用户任务查看相关 package/module。
|
||||
- 在 PowerShell 中读取中文、Markdown、locale、文档类文件时,显式使用 `Get-Content -Encoding utf8`;如果仍然显示乱码,再先执行 `[Console]::OutputEncoding = [System.Text.UTF8Encoding]::new()` 后重试。
|
||||
- 先读本文;需要代码导航、目录入口、参考文件或验证命令时读 `.codex/repo-map.md`。
|
||||
- 任务涉及后端、前端、插件、测试或代码风格时,先读取 `.codex/agent-rules/` 下对应规则文件,再查看具体代码。
|
||||
- 在 PowerShell 中读取中文、Markdown、locale、文档类文件时,显式使用 `Get-Content -Encoding utf8`;如果仍乱码,再执行 `[Console]::OutputEncoding = [System.Text.UTF8Encoding]::new()` 后重试。
|
||||
- 做后端任务时,先定位 `packages/ui/certd-server/src/modules` 下的模块,以及相关 entity/service/controller。
|
||||
- 做前端任务时,先定位 `packages/ui/certd-client/src/views/certd` 下的页面,再找对应 `src/api`。
|
||||
- 做服务商、DNS、部署、通知相关任务时,先看 `packages/ui/certd-server/src/plugins`,再看 `packages/plugins/plugin-lib` 里的共享辅助能力。
|
||||
- 做数据库结构变更时,添加或更新迁移脚本,不要依赖 TypeORM 自动同步。
|
||||
- 实现新功能或修复行为缺陷前,先补对应单元测试,并先运行测试确认它处于失败状态;再实现功能或修复代码,反复运行聚焦单元测试直到通过。若某项改动确实不适合先写单元测试,应在回复中说明原因和替代验证方式。
|
||||
- 后补单元测试时,应先基于对正确行为的实际预期编写测试,而不是为了迎合现有实现改写预期;如果运行后出现红灯,且通过测试需要修改已有实现,应先向用户确认这是确实的 bug,还是原本需求/既有行为就是如此;确认后再修改原始实现,避免把测试补充变成未经确认的行为改动。
|
||||
- 后端纯单元测试用例放在 `src` 目录内,并尽量与被测文件相邻,例如 `src/utils/random.test.ts`;对应 `test:unit` 只跑 `src/**/*.test.ts`,构建/打包配置应排除这些 `*.test.ts` 文件。
|
||||
- 单元测试需要 mock ESM 静态 import 时,优先使用 `esmock`,不要为了测试把业务代码改成构造函数注入或把逻辑挪到调用方;各包 `test:unit` 脚本应显式设置 `NODE_ENV=unittest`。
|
||||
- 单个 monorepo 包运行单元测试时,优先使用 `corepack pnpm --dir <包目录> test:unit`,例如 `corepack pnpm --dir packages\ui\certd-server test:unit`、`corepack pnpm --dir packages\core\basic test:unit`、`corepack pnpm --dir packages\plugins\plugin-lib test:unit`;也可以用包名过滤,例如 `corepack pnpm --filter @certd/ui-server test:unit`。前端 `packages\ui\certd-client` 暂时不跑单元测试。
|
||||
- 前端 TS/Vue/locale 等文件改动后,优先只对本次改动文件运行项目现有自动格式化/修复;Windows/PowerShell 下 Prettier 已验证可用命令为 `packages\ui\certd-client\node_modules\.bin\prettier.cmd --write <files>`,ESLint 可用命令为 `packages\ui\certd-client\node_modules\.bin\eslint.cmd --fix <files>`;不要运行 `vue-tsc` / `pnpm tsc`;不要为了格式化无关文件而扩大 diff。项目保留了 `tslint` 依赖,但当前主要使用 ESLint + Prettier。
|
||||
- 优先对改动包运行聚焦的测试;后端可按包运行单元测试,前端优先使用 Prettier/ESLint 做改动文件验证。只有跨包影响明显时再考虑全 monorepo 构建。
|
||||
- 优先沿用现有模块、插件、服务模式,再考虑新增抽象;避免为了形式上的“复用”制造过度设计。
|
||||
- 实现新功能或修复行为缺陷前,优先补对应单元测试并确认红灯,再实现代码并跑聚焦验证。确实不适合先写测试时,在回复中说明原因和替代验证方式。
|
||||
- 后补单元测试时,先按正确行为写预期;如果红灯需要修改既有实现,先向用户确认这是 bug 还是既有需求,避免未经确认改变行为。
|
||||
- 优先对改动包运行聚焦测试或格式化/ESLint;只有跨包影响明显时再考虑更大范围构建。
|
||||
|
||||
- 不要主动运行 `pnpm install` 安装依赖:用户会事先准备好 `node_modules`。如果 `pnpm install` 或 `test:unit` 因缺少依赖、TTY 或网络问题失败,立即停止尝试,告知用户解决环境问题。
|
||||
## 架构边界
|
||||
|
||||
插件是核心能力,不是边缘功能。新增服务商、DNS 验证、证书部署、通知方式等能力,通常应该放在插件包里,或放在 `packages/ui/certd-server/src/plugins/<plugin-name>/` 下。
|
||||
|
||||
修改证书申请、验证、部署或通知行为时,先判断改动属于 ACME client、pipeline 核心抽象、后端 module/service/entity/controller、具体插件实现,还是前端 view/form/schema。
|
||||
|
||||
如果只是某个服务商或部署目标的问题,不要轻易修改共享 pipeline/core 行为,除非确实是可复用的公共能力。
|
||||
|
||||
Reference in New Issue
Block a user