docs: 完善 AGENTS 仓库指引

This commit is contained in:
liumangmang
2026-03-24 13:52:24 +08:00
parent c8fa3de679
commit b236386273

348
AGENTS.md
View File

@@ -1,214 +1,152 @@
# AGENTS 指南(ssh-manager
本文件面向在本仓库工作的自动化 coding agents
目标:快速、安全、风格一致地完成改动。
## 1) 仓库概览
- Monorepo`backend`Spring Boot 2.7 + Java 8+ `frontend`Vue 3 + TS + Vite
- 默认后端端口:`48080`(见 `backend/src/main/resources/application.yml`
- 前端开发端口:`5173`,通过 Vite 代理 `/api``/ws`
- 数据库:H2 文件库(`./data/sshmanager`
- 认证JWTHTTP Header Bearer + WebSocket query token
## 2) 环境与依赖
- JDK8+
- Maven3.6+
- Node.js18+
- npm`frontend/package-lock.json` 配套
## 3) 常用命令(构建 / 检查 / 测试)
### 3.1 后端(在 `backend/` 目录)
# `ssh-manager` AGENTS 指南
本文件用于指导在本仓库中执行任务的 agentic coding assistants。
目标是在保证安全、可验证和风格统一的前提下,以尽量小的意外完成聚焦改动
## 1. 仓库结构
- Monorepo包含
- `backend/`Spring Boot 2.7、Java 8、Maven、H2、WebSocket、JWT
- `frontend/`Vue 3、TypeScript、Vite、Pinia、Tailwind、Axios
- 后端默认端口:`48080`
- 前端开发服务端口:`5173`
- 前端开发时会将 `/api``/ws` 代理到后端
- 数据库:文件型 H2路径为 `./data/sshmanager`
- 认证方式HTTP 使用 Bearer JWT终端相关 WebSocket 流程在 query 中携带 token
## 2. 需优先检查的规则文件
- 主要仓库规范来源:本 `AGENTS.md`
- Cursor 规则:未发现 `.cursor/rules/` 目录,也未发现 `.cursorrules`
- Copilot 规则:未发现 `.github/copilot-instructions.md`
- 如果未来新增这些文件,编辑前应先读取,并将其视为高优先级约束
## 3. 工具链
- JDK`8+`
- Maven`3.6+`
- Node.js`18+`
- npm使用与 `frontend/package-lock.json` 兼容的版本
- Docker Compose通过 `docker compose` 使用
## 4. 构建 / 运行 / 测试命令
### 后端(`backend/`
- 启动开发服务:`mvn spring-boot:run`
- 打包:`mvn package`
- 仅运行测试:`mvn test`
- 打包应用`mvn package`
- 跳过测试打包:`mvn -DskipTests package`
- 运行全部测试:`mvn test`
- 运行单个测试类:`mvn -Dtest=ConnectionServiceTest test`
- 运行单个测试方法:`mvn -Dtest=ConnectionServiceTest#shouldCreateConnection test`
说明:
- 当前仓库可能暂无 `src/test` 用例;上述命令是 Maven 标准入口。
- 新增测试时优先使用 Surefire 默认命名约定(`*Test``*Tests`)。
### 3.2 前端(在 `frontend/` 目录)
- 运行同一类中的多个方法:`mvn -Dtest=ConnectionServiceTest#testA,testB test`
### 前端(`frontend/`
- 安装依赖:`npm install`
- 启动开发服务:`npm run dev`
- 生产构建:`npm run build`
- 本地预览构建产物:`npm run preview`
说明:
- 当前 `package.json` 未配置独立 lint/test script。
- `npm run build` 会先执行 `vue-tsc -b`,可视为类型检查关卡。
### 3.3 Docker在仓库根目录
- 预览构建产物:`npm run preview`
- 当前没有独立的 `lint` script
- 当前没有独立的前端测试 script
- `npm run build` 会先执行 `vue-tsc -b`,因此它也是主要的前端类型检查入口
### Docker / 根目录(`./`
- 构建镜像:`docker compose -f docker/docker-compose.yml build`
- 前台运行`docker compose -f docker/docker-compose.yml up`
- 后台运行`docker compose -f docker/docker-compose.yml up -d`
## 4) 单测执行策略(重点)
- 后端单测首选:`mvn -Dtest=类名#方法名 test`
- 多方法可用逗号:`mvn -Dtest=ClassTest#testA,testB test`
- 若测试依赖 Spring 上下文,优先在类级隔离,避免全量启动过慢
- 修改 Service/Controller 后,至少补一条对应单元或集成测试(若仓库开始建设测试)
- 前端若后续引入 Vitest建议约定
- 全量:`npm run test`
- 单文件:`npm run test -- src/views/ConnectionsView.test.ts`
- 单用例:`npm run test -- -t "case name"`
## 5) 代码风格总则
- 小步提交:改动聚焦,避免“顺手重构”无关文件
- 保持现有技术栈,不随意引入新框架/重依赖
- 默认不修改对外 API 语义;若必须修改,同步更新调用侧
- 安全优先严禁提交真实密钥、密码、token、私钥
- 可观测性:失败路径要返回可诊断信息(但不能泄露敏感数据)
## 6) 后端风格Java / Spring
### 6.1 导入与结构
- 包名固定前缀:`com.sshmanager`
- import 分组遵循现有习惯:
- 先项目内 `com.sshmanager...`
- 再第三方/框架 `org...` / `javax...`
- 最后 `java...`
- 避免通配符 import`*`
### 6.2 格式与命名
- 4 空格缩进,左花括号同行
- 类名 `PascalCase`,方法/变量 `camelCase`
- Controller 以 `*Controller`Service 以 `*Service`Repository 以 `*Repository`
- DTO 放 `dto`,实体放 `entity`
- 前台启动`docker compose -f docker/docker-compose.yml up`
- 后台启动`docker compose -f docker/docker-compose.yml up -d`
- Make 快捷命令:
- `make build`
- `make up`
- `make down`
- `make restart`
- `make logs`
- `make ps`
## 5. 测试策略
- 优先选择能覆盖改动的最小测试命令
- 对后端改动,先运行受影响的单个测试,再按需要扩大范围
- 现有后端测试位于 `backend/src/test/java`
- 当前后端测试类包括控制器和服务测试,如 `ConnectionControllerTest``SftpControllerTest``ConnectionServiceTest``SftpServiceTest`
- 如果改动涉及 Spring MVC、安全、WebSocket、SSH 或 SFTP 流程,优先补充或运行定向回归测试,而不只是编译通过
- 前端当前没有提交测试套件;对前端改动,至少运行 `npm run build`
## 6. 改动范围规则
- 保持改动小且聚焦任务本身
- 实现需求时不要顺手重构无关文件
- 除非任务明确要求,否则不要静默改变 API 语义
- 如果后端契约发生变化,需要在同一改动中同步更新前端 API / 类型
- 严禁提交 secrets、密码、token、私钥或带环境属性的敏感凭据
## 7. Git 与提交规范
- 开始修改前先查看工作区状态,识别是否存在与当前任务无关的脏变更
- 不要回退、覆盖或格式化并非由当前任务引入的用户改动
- 除非用户明确要求,否则不要主动创建 commit、tag、分支或 PR
- 避免使用 `git reset --hard``git checkout --`、强制推送等破坏性命令
- 若需要提交,提交内容应仅包含与当前任务直接相关的文件
- 提交说明建议简洁描述“为什么改”,而不只是罗列“改了什么”
- 若因 hooks 或生成步骤导致文件变动,应先确认内容合理,再决定是否纳入同一提交
## 8. 后端约定(`backend/`
### import 与文件结构
- 包名前缀固定为 `com.sshmanager`
- 保持显式 import不使用通配符 import
- 遵循仓库现有 import 分组风格:
- 先项目内 import`com.sshmanager...`
- 再框架 / 第三方:`org...``javax...`
- 最后 JDK`java...`
- 控制器放在 `controller`,服务放在 `service`,仓库层放在 `repository`DTO 放 `dto`,实体放 `entity`,安全相关代码放在 `security`
### 格式与命名
- 使用 4 空格缩进
- 左花括号与声明同行
- 类名使用 `PascalCase`
- 方法名和字段名使用 `camelCase`
- 常量使用 `UPPER_SNAKE_CASE`
### 6.3 类型与注解
- Java 8 语法兼容(不要引入更高版本语法特性)
- 优先构造器注入(本仓库已有统一做法)
- 合理使用 Lombok当前主要在 Entity 使用)
- 对外接口返回 `ResponseEntity<...>` 保持一致
### 6.4 异常与错误处理
- 与现有代码一致:业务错误返回 JSON`message``error` 字段)
- 鉴权失败返回 401参数错误返回 400服务异常返回 500
- 记录日志时避免输出明文凭据password/privateKey/passphrase/token
- SFTP 相关改动需考虑并发安全:`ChannelSftp` 非线程安全
### 6.5 安全相关
- JWT 校验逻辑位于过滤器与握手流程,改动需覆盖 HTTP + WS 场景
- 允许跨域来源在 `SecurityConfig` 中集中维护
- 加密逻辑统一走 `EncryptionService`,禁止绕过直接落库明文
## 7) 前端风格Vue 3 / TS / Tailwind
### 7.1 导入与模块组织
- 使用 `<script setup lang="ts">`
- import 优先级参考现有文件
- Vue 核心
- 路由 / store
- 本地 API / type / 组件
- 图标或其他第三方
- 相对路径保持简洁,避免无必要跨层引用
### 7.2 格式与命名
- 2 空格缩进
- TypeScript 与 Vue 脚本保持“无分号 + 单引号”风格
- 组件文件名 `PascalCase.vue`
- store 命名:`useXxxStore`
- 方法变量 `camelCase`,常量 `UPPER_SNAKE_CASE`
### 7.3 类型与状态
- API 类型定义集中在 `frontend/src/api/*.ts`
-可空值显式标注(如 `Connection | null`
- Pinia store 负责状态与数据同步,视图层尽量避免重复请求逻辑
- 新增接口先补类型,再写调用
### 7.4 UI 与交互
- 延续 Tailwind 工具类写法,不引入额外 CSS 框架
- 保持现有深色主题语言(`slate/cyan`)与可访问性属性(如 `aria-label`
- 交互失败要有可感知反馈(至少日志或错误提示)
- 注意终端/SFTP页面的响应性能避免不必要重渲染
## 8) 提交前自检清单
- 后端改动:至少运行 `mvn test`(若存在测试)或最小可行编译验证
- 前端改动:运行 `npm run build`(包含 `vue-tsc`
- 手工验证登录流程、连接列表、终端或 SFTP 关键路径(按改动范围)
- 检查未提交敏感信息与本地配置
- 仅提交与需求直接相关的文件
## 9) Makefile 快捷命令(仓库根目录)
- `make build`:构建 Docker 镜像
- `make up`:构建并后台启动服务
- `make down`:停止并移除服务
- `make restart`:重启服务
- `make logs`:查看服务日志
- `make ps`:查看服务状态
## 10) 文档与规则文件检查结果
- `AGENTS.md`:本文件(仓库根目录)
- Cursor 规则:未发现 `.cursor/rules/``.cursorrules`
- Copilot 规则:未发现 `.github/copilot-instructions.md`
若未来新增上述规则文件agents 必须先读取并将其视为高优先级约束。
## 11) 近期修复记录
### 11.1 Docker 启动失败修复
**问题现象**
```text
Could not resolve placeholder 'SSHMANAGER_JWT_SECRET'
Encryption key must be 32 bytes (256 bits)
No qualifying bean of type 'ExecutorService' available: expected single matching bean but found 2
```
**修复措施**
1. **`application.yml`** - 为安全配置添加空字符串默认值
```yaml
sshmanager:
encryption-key: ${SSHMANAGER_ENCRYPTION_KEY ""}
jwt-secret: ${SSHMANAGER_JWT_SECRET ""}
```
2. **`docker-compose.yml`** - 提供有效的默认密钥(仅用于开发/测试)
```yaml
environment:
- SSHMANAGER_JWT_SECRET=ssh-manager-prod-jwt-secret-20240311
- SSHMANAGER_ENCRYPTION_KEY=MLVt7pE35KULIppEiit0doUMvSjozZJ037oNGeXjhVA=
```
> 注:`MLVt7pE35KULIppEiit0doUMvSjozZJ037oNGeXjhVA=` 是通过 `openssl rand -base64 32` 生成的有效 32 字节 AES-256 密钥
3. **`TerminalWebSocketHandler.java`** - 解决依赖注入歧义
```java
import org.springframework.beans.factory.annotation.Qualifier;
public TerminalWebSocketHandler(
// ... 其他参数
@Qualifier("terminalWebSocketExecutor") ExecutorService executor) {
}
```
**验证结果**
```
Started SshManagerApplication in 3.469 seconds (JVM running for 3.836)
```
**注意事项**
- **生产环境部署时必须修改** `SSHMANAGER_JWT_SECRET` 和 `SSHMANAGER_ENCRYPTION_KEY`
- 建议取消 `docker-compose.yml` 中 `volumes` 注释以持久化 H2 数据库文件
- Spring 类型命名后缀保持一致:`*Controller``*Service``*Repository`
### 类型与 Spring 用法
- 保持 Java 8 兼容,不要引入更高版本语言特性
- 优先使用构造器注入
- 控制器返回 `ResponseEntity<?>``ResponseEntity<T>`,与现有代码保持一致
- 请求 / 响应边界优先使用 DTO除非某文件本来就是如此否则不要直接从控制器暴露实体
- 持久化操作应保留在 service / repository 边界内,不要堆进 controller
- 对需要原子性的写操作使用 `@Transactional`
### 错误处理与安全
- 维持现有 JSON 错误格式,使用 `message``error` 字段
- HTTP 状态码保持一致:
- `400`:参数或输入错误
- `401`:认证 / 授权失败
- `500`:未预期的服务端异常
- 不要在日志中输出明文密码、私钥、口令、JWT 或解密后的凭据
- 加解密逻辑统一集中在 `EncryptionService`
- 修改认证逻辑时,要同时验证 HTTP 与 WebSocket token 处理
- 注意 `ChannelSftp` 不是线程安全的,不要在并发场景共享实例
## 9. 前端约定(`frontend/`
### Vue 与 TypeScript 结构
- Vue 单文件组件使用 `<script setup lang="ts">`
- 新增前端逻辑时优先使用 TypeScript
- ref、路由参数、API payload 尽量强类型化,不要随手使用 `any`
- 先新增或更新 API 层类型,再接入 UI 行为
- 有状态的数据流应保留在 Pinia store 或 API 模块中,不要在多个视图里重复维护
### import 与命名
- 遵循当前观察到的 import 顺序
- Vue 核心
- router / store
- 本地 API / 类型 / 组件
- 未与核心库归组时的第三方 UI / 图标库
- 组件文件名使用 `PascalCase.vue`
- Store 命名使用 `useXxxStore`
- 变量 / 函数名使用 `camelCase`
- 常量使用 `UPPER_SNAKE_CASE`
### 格式与界面模式
- 使用 2 空格缩进
- TS / Vue script 块保持现有的无分号、单引号风格
- 优先使用 Tailwind 工具类,不引入新的样式体系
- 除非任务明确要求改版,否则保留当前 `slate` / `cyan` 视觉语言
- 保持基础可访问性:表单标签、按钮状态、必要的 `aria-*` 属性,以及键盘可操作性
### 错误处理与性能
- 重要操作失败时要给用户可见反馈,不要静默失败
- 除非明确要改认证流程,否则保留当前 Axios 拦截器中的登录失效处理逻辑
-终端和 SFTP 视图要特别注意,避免不必要重渲染和高成本响应式循环
- 对可选后端数据优先做空值安全处理,如 `string | null` 与可选响应字段
## 10. 完成前验证
- 仅后端改动:至少运行最相关的 `mvn -Dtest=... test``mvn test`
- 仅前端改动:运行 `npm run build`
- 全栈改动:运行最窄范围的后端测试,再运行 `npm run build`
- 如果运行时行为发生变化,在可能时手工检查受影响流程,如登录、连接 CRUD、终端或 SFTP
- 最终说明中应明确写出已验证内容与未验证内容
## 11. 仓库特定说明
- 后端配置文件位于 `backend/src/main/resources/application.yml`
- 与安全相关的环境变量包括 `SSHMANAGER_JWT_SECRET``SSHMANAGER_ENCRYPTION_KEY`
- 生产部署必须提供真实有效的这些密钥
- 前端认证 token 当前存储在 `localStorage`
- `frontend/src/api/client.ts` 在收到 `401` 响应时会跳转到 `/login`
## 12. 在本仓库中的良好 agent 行为
- 先阅读现有代码,再决定采用什么模式
- 匹配周边代码风格,不要强行套用新偏好
- 优先做手术式修改,而不是大范围重写
- 当改动会让相邻文档或类型失真时,一并更新它们
- 只在任务范围内把工作区变得更整洁
- 输出结果时优先说明实际改动、验证情况以及仍未覆盖的风险点