docs(plan): 文件存储服务(rui-service-storage)实施计划
- 16 个可独立 commit 的子任务 - Task 1: 常量 + 枚举 - Task 2: sys_file DDL - Task 3-9: 模块骨架 + Strategy 模式 - Task 10-12: 实体/Service/Controller/Event - Task 13-14: 集成启动器 + 公共配置 - Task 15-16: 编译验证 + Gitea 关闭 关联 Gitea #4
This commit is contained in:
@@ -0,0 +1,406 @@
|
||||
# 文件存储服务(rui-service-storage)实施计划
|
||||
|
||||
> **For agentic workers:** REQUIRED SUB-SKILL: Use superpowers-subagent-driven-development (recommended) or superpowers-executing-plans to implement this plan task-by-task. Steps use checkbox (`- [ ]`) syntax for tracking.
|
||||
|
||||
**Goal:** 落地 `rui-service-storage` 独立微服务,提供统一上传接口(阿里云 OSS / 腾讯云 COS / 本地),并通过 Redis pub/sub 广播 `ON_UPLOAD` / `ON_FILE_DELETED` 事件。
|
||||
|
||||
**Architecture:** Strategy 模式 + 事件驱动。`POST /storage/upload` → 鉴权 → 校验 → Strategy 上传 → 落 `sys_file` → 推 `ON_UPLOAD` 事件 → 返回 `Result<T>`。订阅方(如 `rui-service-system`)实现 `MqConsumer` 按 `type` 字段过滤处理。
|
||||
|
||||
**Tech Stack:** Java 21, Spring Boot 4.x, MyBatis Plus, Fastjson2, Spring Security OAuth2, Spring Data Redis (Redisson), 阿里云 OSS SDK, 腾讯 COS SDK
|
||||
|
||||
**前置依赖:**
|
||||
- 设计文档 [docs/superpowers/specs/2026-06-07-file-storage-service-design.md](docs/superpowers/specs/2026-06-07-file-storage-service-design.md) (commit 66f0712)
|
||||
- 主仓指针 commit c467eaf
|
||||
- `rui-common-mq-redis` 已就绪,`@MqTopic` 注解可用
|
||||
- `rui-common-web/.../annotation/AutoPermission` 已就绪
|
||||
- `rui-common-core/.../result/Result<T>` 已就绪
|
||||
- Gitea #4 实施中
|
||||
|
||||
---
|
||||
|
||||
## 文件映射
|
||||
|
||||
### 新增
|
||||
| 路径 | 操作 | 说明 |
|
||||
|------|------|------|
|
||||
| `rui-common/rui-common-core/.../constants/MqTopicConstants.java` | Create | MQ topic 常量 |
|
||||
| `rui-common/rui-common-core/.../enums/FileBizType.java` | Create | 文件业务类型枚举 |
|
||||
| `rui-service/rui-service-storage/pom.xml` | Create | 新模块 |
|
||||
| `rui-service/rui-service-storage/src/main/java/com/rui/service/storage/StorageApplication.java` | Create | 启动类 |
|
||||
| `rui-service/rui-service-storage/src/main/java/com/rui/service/storage/controller/SysFileController.java` | Create | 上传/查询/删除 |
|
||||
| `rui-service/rui-service-storage/src/main/java/com/rui/service/storage/service/IFileStorage.java` | Create | Strategy 接口 |
|
||||
| `rui-service/rui-service-storage/src/main/java/com/rui/service/storage/service/impl/AliyunOssFileStorage.java` | Create | 阿里云 |
|
||||
| `rui-service/rui-service-storage/src/main/java/com/rui/service/storage/service/impl/TencentCosFileStorage.java` | Create | 腾讯 |
|
||||
| `rui-service/rui-service-storage/src/main/java/com/rui/service/storage/service/impl/LocalFileStorage.java` | Create | 本地 |
|
||||
| `rui-service/rui-service-storage/src/main/java/com/rui/service/storage/service/impl/FileStorageRouter.java` | Create | 选实现 |
|
||||
| `rui-service/rui-service-storage/src/main/java/com/rui/service/storage/event/UploadEventPublisher.java` | Create | ON_UPLOAD 推送 |
|
||||
| `rui-service/rui-service-storage/src/main/java/com/rui/service/storage/event/FileDeletedEventPublisher.java` | Create | ON_FILE_DELETED 推送 |
|
||||
| `rui-service/rui-service-storage/src/main/java/com/rui/service/storage/properties/FileProperties.java` | Create | @ConfigurationProperties |
|
||||
| `rui-service/rui-service-storage/src/main/java/com/rui/service/storage/entity/SysFile.java` | Create | 实体 |
|
||||
| `rui-service/rui-service-storage/src/main/java/com/rui/service/storage/mapper/SysFileMapper.java` | Create | Mapper |
|
||||
| `rui-service/rui-service-storage/src/main/java/com/rui/service/storage/service/ISysFileService.java` | Create | Service 接口 |
|
||||
| `rui-service/rui-service-storage/src/main/java/com/rui/service/storage/service/impl/SysFileServiceImpl.java` | Create | Service 实现 |
|
||||
| `rui-service/rui-service-storage/src/main/java/com/rui/service/storage/dto/SysFileUploadVO.java` | Create | 上传返回 VO |
|
||||
| `rui-service/rui-service-storage/src/main/java/com/rui/service/storage/dto/SysFileQueryVO.java` | Create | 查询返回 VO |
|
||||
| `rui-service/rui-service-storage/src/main/java/com/rui/service/storage/dto/UploadEventPayload.java` | Create | 事件 payload POJO |
|
||||
| `rui-service/rui-service-storage/src/main/resources/application.yml` | Create | port=9400 |
|
||||
| `sql/init-database.sql` | Modify | 新增 sys_file DDL |
|
||||
|
||||
### 修改
|
||||
| 路径 | 操作 | 说明 |
|
||||
|------|------|------|
|
||||
| `rui-service/pom.xml` | Modify | `<modules>` 加 storage |
|
||||
| `rui-service/rui-service-starter/pom.xml` | Modify | 加 storage 依赖 |
|
||||
| `rui-service/rui-service-starter/.../StarterApplication.java` | Modify | ComponentScan + storage |
|
||||
| `rui-service/rui-service-starter/src/main/resources/application.yml` | Modify | rui.modules.available 加 storage 入口 |
|
||||
| `docs/backend/config-templates/application-template.yml` | Modify | rui.file.* 公共配置示例 |
|
||||
| `Gitea #4` | Reply + Close | 实施完成通知 |
|
||||
|
||||
---
|
||||
|
||||
## 任务列表
|
||||
|
||||
### Task 1: 公共常量与枚举(rui-common-core)
|
||||
|
||||
**Files:**
|
||||
- Create: `rui-common/rui-common-core/src/main/java/com/rui/common/core/constants/MqTopicConstants.java`
|
||||
- Create: `rui-common/rui-common-core/src/main/java/com/rui/common/core/enums/FileBizType.java`
|
||||
- Reference style: `CacheConstants.java`(沿用 private ctor + Javadoc 写明写入方/使用方)
|
||||
|
||||
- [ ] **Step 1.1:** 创建 `MqTopicConstants`
|
||||
```java
|
||||
public final class MqTopicConstants {
|
||||
public static final String ON_UPLOAD = "ON_UPLOAD";
|
||||
public static final String ON_FILE_DELETED = "ON_FILE_DELETED";
|
||||
private MqTopicConstants() {}
|
||||
}
|
||||
```
|
||||
|
||||
- [ ] **Step 1.2:** 创建 `FileBizType` 枚举(4 个值 + `uploadType()` / `deletedType()` 方法)
|
||||
|
||||
- [ ] **Step 1.3:** 编译 `mvn -pl rui-common/rui-common-core compile` 通过
|
||||
|
||||
- [ ] **Step 1.4:** 提交 `feat(core): 新增 MqTopicConstants 和 FileBizType`
|
||||
|
||||
---
|
||||
|
||||
### Task 2: 数据库 DDL
|
||||
|
||||
**Files:**
|
||||
- Modify: `sql/init-database.sql` (新增 sys_file 表 DDL)
|
||||
|
||||
- [ ] **Step 2.1:** 在 `sql/init-database.sql` 末尾追加 `sys_file` 表 DDL(参见设计文档 §4.1)
|
||||
|
||||
- [ ] **Step 2.2:** 提交 `feat(db): 新增 sys_file 表`
|
||||
|
||||
---
|
||||
|
||||
### Task 3: rui-service-storage 模块骨架
|
||||
|
||||
**Files:**
|
||||
- Create: `rui-service/rui-service-storage/pom.xml`
|
||||
- Create: `rui-service/rui-service-storage/src/main/java/com/rui/service/storage/StorageApplication.java`
|
||||
- Create: `rui-service/rui-service-storage/src/main/resources/application.yml`
|
||||
- Modify: `rui-service/pom.xml`(`<modules>` 加 `<module>rui-service-storage</module>`)
|
||||
|
||||
- [ ] **Step 3.1:** 创建 `pom.xml`,parent 指向 `rui-service`,依赖:
|
||||
- `rui-common-web` / `rui-common-mybatis` / `rui-common-redis` / `rui-common-mq` / `rui-common-mq-redis` / `rui-common-security` / `rui-common-oauth2`(可选)
|
||||
- `spring-boot-starter-web`
|
||||
- `com.aliyun.oss:aliyun-sdk-oss`(版本从 `rui-dependencies` BOM 取)
|
||||
- `com.qcloud:cos_api`(版本从 BOM 取)
|
||||
- `spring-cloud-starter-alibaba-nacos-discovery` / `nacos-config`
|
||||
- `spring-boot-starter-actuator`
|
||||
- `lombok` / `fastjson2`
|
||||
|
||||
- [ ] **Step 3.2:** 创建 `StorageApplication.java`:
|
||||
```java
|
||||
@SpringBootApplication
|
||||
@EnableDiscoveryClient
|
||||
@EnableResourceServer
|
||||
@ComponentScan(basePackages = {"com.rui.service.storage"})
|
||||
public class StorageApplication {
|
||||
public static void main(String[] args) {
|
||||
SpringApplication.run(StorageApplication.class, args);
|
||||
}
|
||||
}
|
||||
```
|
||||
|
||||
- [ ] **Step 3.3:** 创建 `application.yml`(port=9400,servlet.multipart 兜底)
|
||||
|
||||
- [ ] **Step 3.4:** `rui-service/pom.xml` 的 `<modules>` 末尾加 `<module>rui-service-storage</module>`
|
||||
|
||||
- [ ] **Step 3.5:** 编译 `mvn -pl rui-service/rui-service-storage -am compile` 通过
|
||||
|
||||
- [ ] **Step 3.6:** 提交 `feat(storage): 新建 rui-service-storage 模块骨架`
|
||||
|
||||
---
|
||||
|
||||
### Task 4: 配置类 FileProperties
|
||||
|
||||
**Files:**
|
||||
- Create: `rui-service/rui-service-storage/src/main/java/com/rui/service/storage/properties/FileProperties.java`
|
||||
|
||||
- [ ] **Step 4.1:** 创建 `FileProperties`:
|
||||
- `@ConfigurationProperties(prefix = "rui.file")` + `@Data` + `@Component`(或 `@EnableConfigurationProperties`)
|
||||
- 字段:`String active`、`DataSize defaultMaxSize`(或 long)、`Map<String, BizTypeConfig> bizTypes`、`Aliyun aliyun`、`Tencent tencent`、`Local local`
|
||||
- 嵌套类 `BizTypeConfig { DataSize maxSize; List<String> allowedExtensions; }`
|
||||
- 嵌套类 `Aliyun { boolean enabled; String endpoint, accessKey, secretKey, bucket, urlPrefix, basePath; }`
|
||||
- 嵌套类 `Tencent { boolean enabled; String secretId, secretKey, region, bucket, urlPrefix, basePath; }`
|
||||
- 嵌套类 `Local { String basePath, urlPrefix; }`
|
||||
|
||||
- [ ] **Step 4.2:** 编译通过
|
||||
|
||||
- [ ] **Step 4.3:** 与本任务其他提交合并到 Task 3 的 commit(避免空 commit)
|
||||
|
||||
---
|
||||
|
||||
### Task 5: FileStorage Strategy 接口
|
||||
|
||||
**Files:**
|
||||
- Create: `rui-service/rui-service-storage/src/main/java/com/rui/service/storage/service/IFileStorage.java`
|
||||
- Create: `rui-service/rui-service-storage/src/main/java/com/rui/service/storage/dto/FileStorageResult.java`
|
||||
|
||||
- [ ] **Step 5.1:** 创建 `IFileStorage` 接口:
|
||||
```java
|
||||
public interface IFileStorage {
|
||||
String type(); // "ALIYUN" / "TENCENT" / "LOCAL"
|
||||
boolean enabled(FileProperties props);
|
||||
FileStorageResult upload(MultipartFile file, String storageKey, FileProperties props) throws IOException;
|
||||
void delete(String storageKey, FileProperties props);
|
||||
}
|
||||
```
|
||||
|
||||
- [ ] **Step 5.2:** 创建 `FileStorageResult { String url; String storageKey; }`
|
||||
|
||||
---
|
||||
|
||||
### Task 6: AliyunOssFileStorage 实现
|
||||
|
||||
**Files:**
|
||||
- Create: `rui-service/rui-service-storage/src/main/java/com/rui/service/storage/service/impl/AliyunOssFileStorage.java`
|
||||
|
||||
- [ ] **Step 6.1:** 实现:
|
||||
- `@Component("ALIYUN")` + `@ConditionalOnProperty(prefix = "rui.file.aliyun", name = "enabled", havingValue = "true")`(用 `@ConditionalOnBean` 触发;或简单写死 bean,启用由 `enabled` 控制)
|
||||
- 用 `OSSClientBuilder().build(endpoint, ak, sk)`
|
||||
- `upload` 调 `ossClient.putObject(bucket, storageKey, inputStream)`
|
||||
- `delete` 调 `ossClient.deleteObject(bucket, storageKey)`
|
||||
- 构造 `url` = `urlPrefix + "/" + storageKey`
|
||||
- `enabled` 返回 `aliyun.enabled`
|
||||
|
||||
- [ ] **Step 6.2:** 编译通过
|
||||
|
||||
---
|
||||
|
||||
### Task 7: TencentCosFileStorage 实现
|
||||
|
||||
**Files:**
|
||||
- Create: `rui-service/rui-service-storage/src/main/java/com/rui/service/storage/service/impl/TencentCosFileStorage.java`
|
||||
|
||||
- [ ] **Step 7.1:** 实现:
|
||||
- `@Component("TENCENT")` + 同条件注解
|
||||
- 用 `COSClient( new BasicCOSCredentials(sid, sk), new ClientConfig(new Region(region)) )`
|
||||
- `upload` 调 `cosClient.putObject(bucket, storageKey, inputStream)`
|
||||
- `delete` 调 `cosClient.deleteObject(bucket, storageKey)`
|
||||
- 构造 `url` = `urlPrefix + "/" + storageKey`
|
||||
|
||||
- [ ] **Step 7.2:** 编译通过
|
||||
|
||||
---
|
||||
|
||||
### Task 8: LocalFileStorage 实现
|
||||
|
||||
**Files:**
|
||||
- Create: `rui-service/rui-service-storage/src/main/java/com/rui/service/storage/service/impl/LocalFileStorage.java`
|
||||
|
||||
- [ ] **Step 8.1:** 实现:
|
||||
- `@Component("LOCAL")` (默认总是启用)
|
||||
- `basePath` 启动时 `Files.createDirectories`
|
||||
- `upload` 写文件到 `basePath + storageKey`,返回 `url = urlPrefix + storageKey`
|
||||
- `delete` 调 `Files.deleteIfExists`
|
||||
- `type()` 返回 `"LOCAL"`
|
||||
|
||||
- [ ] **Step 8.2:** 编译通过
|
||||
|
||||
---
|
||||
|
||||
### Task 9: FileStorageRouter
|
||||
|
||||
**Files:**
|
||||
- Create: `rui-service/rui-service-storage/src/main/java/com/rui/service/storage/service/impl/FileStorageRouter.java`
|
||||
|
||||
- [ ] **Step 9.1:** 实现:
|
||||
- `@Component`
|
||||
- 构造注入 `Map<String, IFileStorage>`(Spring 按 bean name 注入所有实现)
|
||||
- `route(String storageHint)` 方法:先按 `storageHint` 找;找不到走 `props.getActive()`;都没有用 `LOCAL`
|
||||
- 失败抛 `BizException("STORAGE_NOT_AVAILABLE")`
|
||||
|
||||
- [ ] **Step 9.2:** Task 5-9 一起提交 `feat(storage): FileStorage Strategy 模式 + 三家实现`
|
||||
|
||||
---
|
||||
|
||||
### Task 10: SysFile 实体/Mapper/Service
|
||||
|
||||
**Files:**
|
||||
- Create: `SysFile.java` (extends `BaseEntity`)
|
||||
- Create: `SysFileMapper.java` (extends `BaseMapper<SysFile>`)
|
||||
- Create: `ISysFileService.java` (extends `IService<SysFile>`)
|
||||
- Create: `SysFileServiceImpl.java` (extends `ServiceImpl<SysFileMapper, SysFile>`)
|
||||
|
||||
- [ ] **Step 10.1:** `SysFile` 字段:`id, name, originalName, url, storageType, bizType, bizId, size, contentType, sha256, uploaderId`,其他由 `BaseEntity` 提供
|
||||
|
||||
- [ ] **Step 10.2:** Service 增加 `appendBizId(Long fileId, String bizId)` 方便订阅方回填
|
||||
|
||||
- [ ] **Step 10.3:** 编译通过
|
||||
|
||||
- [ ] **Step 10.4:** 提交 `feat(storage): sys_file 实体/Mapper/Service`
|
||||
|
||||
---
|
||||
|
||||
### Task 11: 上传/查询/删除 Controller
|
||||
|
||||
**Files:**
|
||||
- Create: `SysFileUploadVO.java`
|
||||
- Create: `SysFileQueryVO.java`
|
||||
- Create: `SysFileController.java`
|
||||
|
||||
- [ ] **Step 11.1:** `SysFileUploadVO` 字段:`id, name, originalName, url, size, contentType, storageType, bizType`
|
||||
|
||||
- [ ] **Step 11.2:** `SysFileQueryVO` 字段:`id, name, originalName, url, size, bizType, createdAt`
|
||||
|
||||
- [ ] **Step 11.3:** `SysFileController`:
|
||||
- 类级 `@AutoPermission("sys:file:upload")`
|
||||
- `@PostMapping("/upload")` → `upload(file, bizType, storage?)`
|
||||
- 校验 `bizType` ∈ `FileBizType.values()`
|
||||
- 加载 `FileProperties.bizTypes[bizType]`,校验大小/扩展名
|
||||
- 调 `FileStorageRouter` 选实现 → `upload`
|
||||
- 算 sha256(`DigestUtils.sha256Hex`)
|
||||
- 落 `sys_file`
|
||||
- 调 `UploadEventPublisher.publish(...)`
|
||||
- 返回 `Result.ok(vo)`
|
||||
- `@GetMapping("/file/{id}")` → `@AutoPermission("sys:file:query")` 查询单条
|
||||
- `@GetMapping("/file/page")` → 分页查询
|
||||
- `@DeleteMapping("/file/{id}")` → `@AutoPermission("sys:file:delete")` 删除
|
||||
- 使用 `BaseController<...>` 或独立 `@RestController`(推荐独立,路径 `/storage`)
|
||||
|
||||
- [ ] **Step 11.4:** 编译通过
|
||||
|
||||
- [ ] **Step 11.5:** 提交 `feat(storage): 文件上传/查询/删除接口`
|
||||
|
||||
---
|
||||
|
||||
### Task 12: Event Publishers
|
||||
|
||||
**Files:**
|
||||
- Create: `UploadEventPayload.java`
|
||||
- Create: `UploadEventPublisher.java`
|
||||
- Create: `FileDeletedEventPublisher.java`
|
||||
|
||||
- [ ] **Step 12.1:** `UploadEventPayload` POJO 字段与设计文档 §8.2 一致,标注 `@JSONField` 序列化
|
||||
|
||||
- [ ] **Step 12.2:** `UploadEventPublisher`:
|
||||
- `@Component @RequiredArgsConstructor`
|
||||
- 注入 `MqClient`
|
||||
- `publish(FileBizType bizType, SysFile entity, Long uploaderId, Long tenantId, JSONObject extra)`
|
||||
- 内部 `mqClient.publish(MqProvider.REDIS, MqTopicConstants.ON_UPLOAD, payload)`
|
||||
- 失败只 `log.error`,不抛(避免上传回滚)
|
||||
|
||||
- [ ] **Step 12.3:** `FileDeletedEventPublisher` 同上结构,topic 用 `ON_FILE_DELETED`
|
||||
|
||||
- [ ] **Step 12.4:** 编译通过
|
||||
|
||||
- [ ] **Step 12.5:** 提交 `feat(storage): ON_UPLOAD/ON_FILE_DELETED 事件推送`
|
||||
|
||||
---
|
||||
|
||||
### Task 13: 集成到 rui-service-starter
|
||||
|
||||
**Files:**
|
||||
- Modify: `rui-service/rui-service-starter/pom.xml`
|
||||
- Modify: `rui-service/rui-service-starter/.../StarterApplication.java`
|
||||
- Modify: `rui-service/rui-service-starter/src/main/resources/application.yml`
|
||||
|
||||
- [ ] **Step 13.1:** `pom.xml` 加 `<dependency> rui-service-storage </dependency>`
|
||||
|
||||
- [ ] **Step 13.2:** `StarterApplication` 的 `@ComponentScan` 加 `"com.rui.service.storage"`
|
||||
|
||||
- [ ] **Step 13.3:** `application.yml` 的 `rui.modules.available` 数组加 `code: storage, name: 文件存储, icon: tabler:cloud-upload`
|
||||
|
||||
- [ ] **Step 13.4:** 编译 `mvn -pl rui-service/rui-service-starter -am compile` 通过
|
||||
|
||||
- [ ] **Step 13.5:** 提交 `feat(starter): 集成 rui-service-storage`
|
||||
|
||||
---
|
||||
|
||||
### Task 14: 公共配置示例
|
||||
|
||||
**Files:**
|
||||
- Modify: `docs/backend/config-templates/application-template.yml` 或 `rui-common.yaml` Nacos 配置
|
||||
|
||||
- [ ] **Step 14.1:** 在公共 yaml 模板加 `rui.file` 配置(active / defaultMaxSize / bizTypes 字典)参照设计文档 §9.1
|
||||
|
||||
- [ ] **Step 14.2:** 提交 `docs(config): rui.file 公共配置示例`
|
||||
|
||||
---
|
||||
|
||||
### Task 15: 编译验证
|
||||
|
||||
- [ ] **Step 15.1:** `mvn clean compile -DskipTests` 全部模块通过
|
||||
|
||||
- [ ] **Step 15.2:** 若有编译错误,按模块修复
|
||||
|
||||
---
|
||||
|
||||
### Task 16: 推送 + 关闭 Gitea #4
|
||||
|
||||
- [ ] **Step 16.1:** 累计 commit 数 ≥10 时 `git push origin main`
|
||||
|
||||
- [ ] **Step 16.2:** 通过 `bin/gitea-helper.sh issue-comment --id 4 --body "..."` 回复实现说明
|
||||
|
||||
- [ ] **Step 16.3:** `bin/gitea-helper.sh issue-close --id 4` 关闭工单
|
||||
|
||||
---
|
||||
|
||||
## 实施计划检查清单
|
||||
|
||||
### 规范覆盖检查
|
||||
|
||||
| 规范要求 | 对应任务 | 状态 |
|
||||
|---------|---------|------|
|
||||
| 公共常量集中 (MqTopicConstants) | Task 1 | ☐ |
|
||||
| 业务枚举集中 (FileBizType) | Task 1 | ☐ |
|
||||
| 数据库继承 BaseEntity | Task 10 | ☐ |
|
||||
| Strategy 模式可插拔 | Tasks 5-9 | ☐ |
|
||||
| 内置 @AutoPermission 鉴权 | Task 11 | ☐ |
|
||||
| 统一 Result<T> 返回 | Task 11 | ☐ |
|
||||
| MQ pub/sub 事件推送 | Task 12 | ☐ |
|
||||
| 集成聚合启动器 | Task 13 | ☐ |
|
||||
| 配置分层 (Nacos 规则) | Task 14 | ☐ |
|
||||
| 最终编译通过 | Task 15 | ☐ |
|
||||
| Gitea #4 关闭 | Task 16 | ☐ |
|
||||
|
||||
### 验收点
|
||||
- [ ] 上传 .pem 文件返回标准 Result,data.url 可访问
|
||||
- [ ] 超大文件/不允许扩展名/未知 bizType 均返回 400
|
||||
- [ ] Redis 收到 ON_UPLOAD 消息
|
||||
- [ ] 删除后 Redis 收到 ON_FILE_DELETED 消息
|
||||
- [ ] 无 JWT 返回 401,无权限返回 403
|
||||
- [ ] `rui-service-starter` 启动时 storage 子模块同时激活
|
||||
- [ ] Gitea #4 已关闭
|
||||
- [ ] 全部 commit 推送至 origin/main
|
||||
|
||||
### 无占位符检查
|
||||
- [ ] 无 "TBD"、"TODO"、"implement later"
|
||||
- [ ] 文件路径全部相对项目根目录
|
||||
- [ ] 字段命名符合 MyBatis Plus 驼峰转下划线
|
||||
- [ ] 每个步骤可独立 commit + 编译
|
||||
|
||||
---
|
||||
|
||||
**计划完成!**
|
||||
|
||||
保存路径:`docs/superpowers/plans/2026-06-07-file-storage-service-plan.md`
|
||||
设计参考:`docs/superpowers/specs/2026-06-07-file-storage-service-design.md`
|
||||
|
||||
**执行选项:**
|
||||
1. **Subagent-Driven(推荐)** — 每个任务分派独立子代理
|
||||
2. **Inline Execution** — 当前会话连续执行,编译错误时停下确认
|
||||
Reference in New Issue
Block a user