Files
youlai-boot/AGENTS.md
tongtongstudio 1829238de6 refactor(storage): 上游上传接口回归原行为,固定目录仅用于新增接口
- system/controller/FileController 恢复为 gitee 上游版本,移除 /api/v1/files/avatar

- FileService#uploadFile(MultipartFile) 与 Aliyun/S3/Local 实现恢复上游 yyyyMMdd 日期目录行为,保留双参数重载供自有接口使用

- AGENTS.md 增加上传规则改动边界:只改我方新增接口,上游已有接口保持原样
2026-10-20 10:15:09 +08:00

12 KiB
Raw Permalink Blame History

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。
  • 存量历史数据(旧本地路径、旧对象目录、旧字段格式)只允许用一次性迁移脚本或管理接口处理,不得在业务代码中长期保留运行时回退分支。