file-system/README.md
向宁 df8f1e4cb7 refactor: rewrite file-system from Go to .NET 10 / ABP modular
- Replace Go (Kratos/Wire/Watermill) implementation with .NET 10 solution
- Add FileSystem.slnx, Directory.Build.props and ABP module structure
- Keep Docker/Jenkins/docker-compose deployment artifacts
- This drops all Go sources (cmd/, internal/, api/proto) in favor of src/
2026-06-14 15:02:59 +08:00

133 lines
5.8 KiB
Markdown
Raw Permalink Blame History

This file contains ambiguous Unicode characters

This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.

# file-system
基于 **.NET 10 + ABP + FastEndpoints + MediatR + EF Core** 的文件存储微服务,提供文件上传/下载、分片上传、存储桶管理、文件夹/文件元数据管理与分享等能力。底层使用 S3 兼容存储RustFS/MinIO与 PostgreSQL。提供 **HTTP + gRPC 双协议**
由原 Go/Kratos 版重写而来,功能 1:1 对齐。
## 功能特性
-**文件操作**上传、下载、删除、列表、预签名预览24h、文本内容预览10MB
-**分片上传**大文件分片上传init / part / complete / abort服务端按 PartNumber 排序)
-**存储桶管理**:创建、列表、删除
-**文件夹与元数据**:树形文件夹、文件元数据、移动、**递归 CTE 事务删除 + best-effort S3 清理**
-**分享链接**bcrypt 密码保护、过期时间、下载次数限制
-**JWT 鉴权**OIDC/JWKS信 SSO 签发的 RS256 JWT
-**所有权隔离**:受保护接口以 JWT `sub` 为权威所有者,忽略请求体 `owner_id`
-**双协议**HTTPFastEndpoints+ gRPC原生 proto共享同一套 MediatR CQRS
## 技术栈
| 类别 | 技术 |
|------|------|
| 框架 | .NET 10、ABP 10.3模块化、FastEndpoints 8.1REPR、MediatR 14CQRS |
| 数据 | EF Core 10 + PostgreSQLNpgsql |
| 存储 | AWSSDK.S3ForcePathStyle兼容 RustFS/MinIO |
| 鉴权 | OIDC AuthorityJWKS 自动发现) |
| 校验 | FluentValidation 12管线自动校验 |
| 协议 | HTTPFastEndpoints+ gRPC原生 proto |
## 架构分层
```
FileSystem.Api → FastEndpoints + Middleware + ABP 模块装配 + gRPC 服务
FileSystem.Application → MediatR CQRS handlers + DTOs + Validators + 领域事件
FileSystem.Infrastructure → EF Core + DbContext + Configurations + AuditInterceptor + S3 存储
FileSystem.Domain → Entities + Interfaces + Exceptions零外部依赖
```
依赖:`Api → Application → Infrastructure → Domain`。ABP 模块 `[DependsOn]` 链同构 rag-backend。
## 快速开始
### 环境要求
- .NET 10 SDK
- PostgreSQL含库 `file_system`
- S3 兼容存储RustFS / MinIO
- 可访问的 SSO 服务(用于 JWKS
### 构建运行
```bash
dotnet build
cd src/FileSystem.Infrastructure && dotnet ef migrations add Init --startup-project ../FileSystem.Api
cd src/FileSystem.Api && dotnet run # HTTP :8080, gRPC :9090
```
或 Docker
```bash
docker compose up -d
```
服务监听:
- HTTP: `http://localhost:8080`
- gRPC: `localhost:9090`
- Swagger: `http://localhost:8080/swagger`
## 配置
运行配置在 `src/FileSystem.Api/appsettings.json`,环境变量用 `__` 分隔节覆盖(如 `S3__Endpoint``S3:Endpoint`)。
| 配置项 | 说明 |
|------|------|
| `Kestrel:Endpoints:Http/Grpc` | HTTP8080, Http1/ gRPC9090, Http2监听地址 |
| `Kestrel:Limits:MaxRequestBodySize` | 请求体上限100 MiB |
| `ConnectionStrings:Default` | PostgreSQL 连接串 |
| `S3:*` | S3 兼容端点与凭证 |
| `Jwt:Authority` | SSO 地址,框架自动发现 JWKS |
| `Jwt:RequireHttps` | 是否要求 HTTPS开发期 false |
## 鉴权
- 受保护接口要求请求头携带 SSO 下发的 `Authorization: Bearer <token>`RS256
- 服务从 JWT 的 `sub` claim 取用户 ID 作为资源所有者;请求体的 `owner_id`/`created_by` 字段**仅 proto 兼容保留,不作为鉴权依据**。
- 公开接口(无需鉴权):`GetShareInfo``DownloadShare`
- 分享下载在设置了密码时,必须通过 `password` 字段并经 bcrypt 校验。
## API 端点24 个)
| HTTP | 路径 | 鉴权 | 说明 |
|------|------|------|------|
| POST | `/api/files/upload` | 登录 | 上传文件multipart≤100MiB |
| GET | `/api/files/download` | 登录 | 下载对象 |
| GET | `/api/files/list` | 登录 | 分页列对象默认100/上限1000 |
| GET | `/api/files/preview` | 登录 | 24h 预签名预览 URL |
| GET | `/api/files/content` | 登录 | 文本内容≤10MB |
| DELETE | `/api/files/delete` | 登录 | 删除对象 |
| POST | `/api/files/multipart/init` | 登录 | 开启分片会话 |
| PUT | `/api/files/multipart/part` | 登录 | 上传单片 |
| POST | `/api/files/multipart/complete` | 登录 | 合并分片 |
| POST | `/api/files/multipart/abort` | 登录 | 取消会话 |
| POST | `/api/buckets` | 登录 | 建桶 |
| GET | `/api/buckets` | 登录 | 列桶 |
| DELETE | `/api/buckets` | 登录 | 删桶 |
| POST | `/api/folders` | 登录+sub | 建文件夹parent_id 空=根) |
| GET | `/api/folders/tree` | 登录+sub | 该用户所有文件夹 |
| GET | `/api/folders/{id}` | 登录+sub | 文件夹+子项 |
| PUT | `/api/folders/{id}` | 登录+sub | 重命名 |
| DELETE | `/api/folders/{id}` | 登录+sub | 递归删 DB 子树 + best-effort 删 S3 |
| POST | `/api/folders/{folder_id}/files` | 登录+sub | UUID key 上传到 files 桶 + 元数据 |
| POST | `/api/files/{id}/move` | 登录+sub | 移动文件target 空=根) |
| POST | `/api/share` | 登录+sub | 建分享bcrypt 密码/过期/次数) |
| DELETE | `/api/share/{id}` | 登录+sub | 按 id+owner 删 |
| GET | `/api/share/{token}` | **公开** | 查分享信息 |
| POST | `/api/share/{token}/download` | **公开** | 校验密码/过期/次数 → 15min 预签名 URL |
gRPC 方法同上,契约见 `src/FileSystem.Api/Protos/file.proto`
## 错误码
| 错误 | HTTP | 含义 |
|------|------|------|
| Unauthorized | 401 | 缺少/无效 JWT |
| Forbidden | 403 | 无权访问他人资源 |
| InvalidParameter | 400 | 参数校验失败 |
| NotFound | 404 | 资源不存在 |
| AlreadyExists | 409 | 资源已存在 |
| ShareExpired | 410 | 分享已过期 |
| ShareExhausted | 410 | 分享下载次数耗尽 |
| SharePassword | 401 | 分享密码缺失或错误 |
| TooLarge | 413 | 超过单文件大小上限100MiB |