- system/controller/FileController 恢复为 gitee 上游版本,移除 /api/v1/files/avatar - FileService#uploadFile(MultipartFile) 与 Aliyun/S3/Local 实现恢复上游 yyyyMMdd 日期目录行为,保留双参数重载供自有接口使用 - AGENTS.md 增加上传规则改动边界:只改我方新增接口,上游已有接口保持原样
12 KiB
12 KiB
AGENTS.md
本仓库是 youlai-boot 的 TTSTD 定制分支,用于老年平板设备管理:设备端(sn)、家属端(client)、运营后台(device / app)。
1. 与 Gitee 上游的关系(最高优先级)
远程仓库:
| remote | 地址 | 用途 |
|---|---|---|
gitee |
git@gitee.com:youlaiorg/youlai-boot.git |
上游只读(push 已禁用),只用于比对/同步 |
origin |
ssh://git@gitea.ttstd.com:2222/tt/youlai-boot.git |
我方仓库 |
只有以下目录是我方新增的业务代码,可自由新增/修改:
| 目录 | 职责 |
|---|---|
src/main/java/com/youlai/boot/app/ |
客户端应用管理:应用分类、应用包(APK/XAPK/APKM 解析、上传、Mongo 存储) |
src/main/java/com/youlai/boot/client/ |
家属端:App 用户、通讯录、设备操作、文件 |
src/main/java/com/youlai/boot/device/ |
设备管理:sn 设备、截图、壁纸、策略、告警、APK 安装、硬件/网络/安全/系统信息 |
src/main/java/com/youlai/boot/open/ |
家属端开放认证:短信登录、密码登录、注册、重置密码 |
src/main/java/com/youlai/boot/common/config/ |
FilePath(本地存储路径)、WebMvcConfig(静态资源映射) |
其余所有目录(auth/、system/、framework/、support/、config/、module/、codegen/ 等)都来自上游,尽量保持不动。
修改前必做检查
git fetch gitee
git ls-tree -r --name-only gitee/master -- src/main/java/com/youlai/boot/xxx # 上游是否存在该文件
git log --oneline gitee/master -- src/main/java/com/youlai/boot/xxx # 上游是否有近期改动
- 上游存在该文件 → 尽量不改。优先在五个自有目录内新增类/扩展点(继承、实现接口、新增 Controller)来满足需求。
- 确实必须改上游文件时:只做最小必要改动,不做格式化/重命名/顺带重构,提交信息注明原因,例如
chore(upstream): 安全配置放行 /api/v1/xxx 以支持新模块。 - 上游不存在该文件 → 可新增,但应落在上述五个目录内。
已登记的例外清单
以下改动位于上游目录,属结构性必要或历史遗留。请勿删除、重构或格式化,修改前先确认调用方。
A. 上游目录中新增的文件(上游不存在,因框架结构必须留在原包)
| 位置 | 说明 |
|---|---|
common/constant/ClientTypeConstants.java |
端标识(admin / client) |
common/util/{HashUtils, FileUtils, RedisSafeOps, CodeGeneratorUtil}.java |
校验值、文件、Redis 安全操作、编码生成工具 |
config/{DataSourceConfig, RedissonConfig, MqttConfig, RedisHealthConfig}.java、config/property/MqttProperties.java |
多数据源、分布式锁、MQTT、Redis 健康检查 |
framework/security/filter/{MobileApiSignatureFilter, CachedBodyRequestWrapper}.java |
设备端 ECDSA 验签过滤器与请求体缓存 |
framework/security/signature/DeviceSignatureVerifier.java |
设备签名校验 |
framework/security/authorization/ClientAccessAuthorizationManager.java |
家属端令牌隔离 |
support/mqtt/{MqttController, MqttMessageHandler, MqttProducer}.java |
MQTT 上报/推送 |
support/webrtc/** |
WebRTC 信令(/ws/signal) |
support/sms/SmsResult.java |
短信发送结果 |
resources/mapper/system/DeviceMapper.xml |
设备分页查询 |
test/java/com/youlai/boot/app/packages/component/ApkMetaParserTest.java |
安装包解析测试 |
B. 被修改的上游文件(只允许最小增补,不做重构/格式化)
| 文件 | 允许的改动范围 |
|---|---|
config/SecurityConfig.java |
放行 /api/v1/sn/**、/api/v1/open/**、/ws/signal;/api/v1/client/** 走 ClientAccessAuthorizationManager |
config/JacksonConfig.java |
保持上游原样(不得添加未使用的 import / 注释代码) |
config/RedisConfig.java |
仅 @Lazy 延迟初始化;序列化方式必须与上游一致 |
framework/security/config/SecurityProperties.java |
client 端令牌 TTL 两个字段 |
framework/security/model/{SecurityUser, SecurityUserDetails}.java |
clientType 字段 |
framework/security/token/JwtTokenManager.java |
client 端 TTL 解析、clientType claim、校验失败日志 |
common/constant/JwtClaimConstants.java、common/constant/RedisConstants.java |
clientType claim、设备在线 key、短信验证码 key |
common/enums/{ActionTypeEnum, LogModuleEnum}.java、common/result/ResultCode.java |
仅追加新枚举值/错误码 |
framework/web/advice/GlobalExceptionHandler.java |
Redis 相关异常、SSE 超时、静态资源 404 |
framework/web/log/OperationLogAspect.java |
设备无登录会话时的操作人兜底;error_msg 上限 2000 |
system/service/impl/ConfigServiceImpl.java |
缓存预热失败不阻断启动 |
support/file/model/FileInfo.java、support/file/service/impl/LocalFileServiceImpl.java |
md5/sha1/sha256 校验值 |
support/file/service/FileService.java、support/file/service/impl/{AliyunFileServiceImpl, S3FileServiceImpl, LocalFileServiceImpl}.java |
仅新增 uploadFile(MultipartFile, String directory) 重载(供我方新增接口使用);阿里云 domain 配置及 deleteFile 的 key 解析适配(兼容自定义域名)。uploadFile(MultipartFile) 保持上游日期目录行为;system/controller/FileController.java 保持上游原样 |
support/sms/{SmsTypeEnum, service/SmsService, service/impl/AliyunSmsServiceImpl}.java |
sendWithResult,按响应码判定成败 |
support/sse/{SseService, SseSessionManager, constant/SseEventConstants}.java |
设备事件主题 |
pom.xml |
新增依赖(websocket、mongodb、mqtt、apk-parser、apkanalyzer、redisson 等) |
.gitignore |
目前仅新增 /uploadFile/ |
resources/application-dev.yml、resources/application-prod.yml |
数据源(mysql/tdengine)、redis、mongodb、oss、sms、mqtt、安全白名单、令牌 TTL |
sql/youlai-admin.sql |
sys_log.error_msg 由 1000 调整为 2000 |
C. 数据与运维脚本(非 Java 代码,允许新增)
sql/*.sql、docs/sql/*.sql、docker/*。
D. 禁止事项
- 上游文件里做格式化、重命名、import 重排、注释掉代码等无关改动。
- 配置文件提交真实凭证:密码/AccessKey 一律用环境变量或本地 profile 覆盖,不写入版本库。
- 在上游目录新增 Java 类(应放到自有目录,例如
ByteArrayMultipartFile放在app/packages/component/)。 - 为适配我方上传规则去改 gitee 上游已有的上传接口(
POST /api/v1/files、system/controller/FileController):上游已有的不管,规则只加在我方新增接口上。
2. 技术栈
Java 17 · Spring Boot 4.0.5 · Spring Security · MyBatis-Plus 3.5.15 · MySQL · Redis + Redisson · MongoDB(spring-boot-starter-data-mongodb) · WebSocket · knife4j/springdoc · MapStruct + Lombok · Hutool · apk-parser / apkanalyzer
3. 构建与运行
mvn -DskipTests clean package # 打包,产物 target/youlai-boot-4.12.0.jar
mvn test # 测试
java -jar target/youlai-boot-4.12.0.jar --spring.profiles.active=dev
- 默认 profile 为
dev(application.yml),配置见application-dev.yml/application-prod.yml;代码生成配置在codegen.yml。 - 数据库连接请使用本地
/ 环境变量覆盖,不要提交真实账号密码。 - Windows 上 shell 为 PowerShell,勿使用
head/tail/cd /d等 cmd/Unix 语法。
4. 代码约定
包结构(自有模块统一遵循):
xxx/
├── controller/ # @RestController,路径 /api/v1/...
├── service/ # 接口
│ └── impl/ # 实现,继承 MyBatis-Plus ServiceImpl<Mapper, Entity>
├── converter/ # MapStruct 转换器
├── mapper/ # MyBatis-Plus Mapper(自有模块一般不写 XML)
├── repository/ # Mongo 仓储(接口 + impl,用 MongoTemplate)
└── model/
├── entity/ # MySQL 实体(设备相关以 Sn 前缀命名,如 SnDeviceInfo)
├── document/ # Mongo 文档(如 AppPackageDocument)
├── form/ req/ query/ # 入参
└── vo/ dto/ # 出参
- 统一返回
Result<T>/PageResult<T>,分页参数用PageQuery,分页结果用IPage。 - 构造器注入:类加
@RequiredArgsConstructor,字段private final。 - 接口文档:
@Tag(name = "序号.名称")+@Operation(summary = ...)。 - 操作日志:
@Log(module = LogModuleEnum.X, value = ActionTypeEnum.Y)。 - 鉴权分区:
/api/v1/sn/**:设备端,MobileApiSignatureFilter做 ECDSA 设备签名校验(非 JWT)/api/v1/client/**:家属端,仅接受clientType=client的令牌/api/v1/open/**:免登录(登录/注册/找回密码)- 后台接口(
/api/v1/device、/api/v1/app/**、/api/v1/developers等):走 Spring Security,按需@PreAuthorize
- 我方新增接口的业务文件统一通过
FileService#uploadFile(MultipartFile, String directory)存到StorageDir定义的固定目录(app/icon、app/package-icon、app/package、app/screenshot、app/avatar、app/wallpaper、app/category-icon、app/file),实际存储由storage.type(s3 / aliyun / local)决定;不按上传日期分目录。 - 上游
FileService#uploadFile(MultipartFile)及其Aliyun/S3/Local三个实现保持 gitee 行为(yyyyMMdd/日期目录,本地实现不算哈希),只由上游POST /api/v1/files使用,不得修改其语义。 - 头像:家属端走
POST /api/v1/client/files/avatar,落app/avatar。管理端头像继续用上游POST /api/v1/files,system/controller/FileController保持 gitee 原样(不再提供/api/v1/files/avatar)。 - 文件上传规则的改动边界:涉及存储目录、对象命名、扩展名校验、URL 生成等上传规则调整时,只允许改我方新增的接口与实现(
/api/v1/client/files/**、/api/v1/sn/**等);gitee 上游已有的上传接口(POST /api/v1/files、system/controller/FileController及其调用的FileService原方法)保持上游原样,不因我方需求改其入参、出参、校验与行为。 FilePath+/static/{子目录}/**仅用于设备截图等纯本地资源,以及存量历史文件的访问。- 新增后台菜单/表结构请补充
sql/脚本,保持与代码同步。
5. 提交约定
采用 Conventional Commits(feat(device): ...、fix(client): ...、refactor(config): ...、chore: ...)。涉及上游文件的改动需在正文说明原因。
6. 不做兼容(强制)
变更直接定案,不写向后兼容代码:
- 接口入参/出参、字段语义、存储路径变更时,直接改成目标形态;禁止可选参数、双分支、"不传则走旧逻辑"、"新老格式都支持"之类的兜底写法。
- 禁止为旧前端/旧设备端保留旧接口、旧字段或旧 URL 前缀;需要它们同步修改时,在提交说明中列明改动点。
- 存储位置由业务语义决定:一类资源对应
StorageDir中的一个固定常量,使用专用接口落盘(如POST /api/v1/client/files/avatar),不得让调用方通过directory之类的参数决定目录。该约定仅约束我方新增接口,不改动上游POST /api/v1/files。 - 存量历史数据(旧本地路径、旧对象目录、旧字段格式)只允许用一次性迁移脚本或管理接口处理,不得在业务代码中长期保留运行时回退分支。