- 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/
6.4 KiB
CLAUDE.md
Cross-repo rules — see
/Users/wen/project/rag/CLAUDE.mdfor full workspace conventions.
- .NET backends share JWT key:
RagJwtSecretKey2026MustBeAtLeast32CharsLong!- 鉴权:本服务用 OIDC Authority(信 SSO 签发的 RS256 JWT,框架自动发现 JWKS),不调 rag-backend gRPC
- 其他仓库:
rag-backend(5211)、im-system(5212)、work-flow、order-service、rag-frontend(5666 Vue)
Build & Run
dotnet build # 全量构建(TreatWarningsAsErrors)
cd src/FileSystem.Api && dotnet run # HTTP :8080, gRPC :9090
cd src/FileSystem.Infrastructure && dotnet ef migrations add <Name> --startup-project ../FileSystem.Api
cd src/FileSystem.Infrastructure && dotnet ef database update --startup-project ../FileSystem.Api
docker compose up -d # PostgreSQL + 服务
Architecture
.NET 10, ABP modular. Four projects: Api → Application → Infrastructure → Domain。
ABP Module Chain
FileSystemApiModule [DependsOn(FileSystemApplicationModule, FileSystemInfrastructureModule)]
→ FileSystemApplicationModule [DependsOn(FileSystemInfrastructureModule)]
→ FileSystemInfrastructureModule [DependsOn(FileSystemDomainModule)]
DI 在 ConfigureServices(),中间件在 OnApplicationInitialization()。Program.cs 经 builder.AddApplicationAsync<FileSystemApiModule>() 引导。
Middleware Order(不可变)
Cors → GlobalExceptionMiddleware → MapGrpcService<FileGrpcService> → ApiResponseMiddleware
→ Authentication → Authorization → FastEndpoints(RoutePrefix="api") → SwaggerGen
MapGrpcService 必须在 ApiResponseMiddleware 之前(否则 MemoryStream 缓冲破坏 gRPC HTTP/2 帧)。
鉴权
OIDC Authority 模式:AddAuthentication("Bearer").AddJwtBearer(Authority = Jwt:Authority, MapInboundClaims=false, ValidateAudience=false, ValidateIssuer=false)。框架自动从 SSO 发现 JWKS 验签 RS256。
全局 fallback policy(RequireAuthenticatedUser):所有未声明 [AllowAnonymous] 的 endpoint 默认要求认证。公开接口(GetShareInfoEndpoint / DownloadShareEndpoint)在 endpoint 类标注 [AllowAnonymous]。
gRPC 鉴权:FileGrpcService 类级 [Authorize],GetShareInfo/DownloadShare 方法级 [AllowAnonymous]。
Tech Stack
- ABP 10.3(模块化)、FastEndpoints 8.1(HTTP REPR)、MediatR 14(CQRS)
- EF Core 10 + Npgsql(PostgreSQL)、FluentValidation 12
- AWSSDK.S3(ForcePathStyle,RustFS/MinIO 兼容)
- Grpc.AspNetCore(原生 proto code-gen)
Code Patterns
Entity(硬删除,不软删)
file-system 的三实体(Folder/FileMeta/ShareLink)实现 IAuditable + IHasOperatorIP,不实现 ISoftDelete——忠实 Go 版硬删除语义,Remove() 走真实物理删除。
public class Folder : BaseEntity, IAuditable, IHasOperatorIP
{
public Guid? ParentId { get; set; }
public string Name { get; set; } = default!;
public string OwnerId { get; set; } = default!;
// IAuditable + IHasOperatorIP 字段(= default!)
}
EF Configuration(snake_case + ValueGeneratedNever)
public class FolderConfiguration : IEntityTypeConfiguration<Folder>
{
public void Configure(EntityTypeBuilder<Folder> builder)
{
builder.ToTable("folders");
builder.HasKey(e => e.Id);
builder.Property(e => e.Id).ValueGeneratedNever();
builder.HasIndex(e => e.OwnerId);
}
}
自动发现(ApplyConfigurationsFromAssembly)。
Command + Handler(同文件,主构造注入)
public record CreateFolderCommand(Guid? ParentId, string Name) : IRequest<FolderDto>;
public class CreateFolderCommandHandler(FileSystemDbContext db, ICurrentUserContext currentUser, IMediator mediator)
: IRequestHandler<CreateFolderCommand, FolderDto> { ... }
ValidationBehavior 管线自动跑 FluentValidation。
Endpoint(FastEndpoints REPR)
public class CreateFolderEndpoint(IMediator mediator) : Endpoint<CreateFolderRequest, FolderDto>
{
public override void Configure() => Post("/folders");
public override async Task HandleAsync(CreateFolderRequest req, CancellationToken ct)
{
var result = await mediator.Send(new CreateFolderCommand(...), ct);
await Send.OkAsync(result, ct);
}
}
- 受保护 endpoint:全局 fallback policy 兜底认证
- 公开 endpoint:endpoint 类
[AllowAnonymous] - 路由前缀
/api/(Module 配置) - 文件上传:
AllowFileUploads()+ Request 的IFormFile File
gRPC(双协议共享 MediatR)
FileGrpcService : FileService.FileServiceBase(proto 生成),24 RPC 全部经 IMediator.Send 复用 Application 层 Command/Query。HTTP endpoint 与 gRPC 共享业务逻辑。proto 见 src/FileSystem.Api/Protos/file.proto。
递归 CTE 删文件夹(DeleteFolderCommand)
PostgreSQL 递归 CTE(EF Core 不原生支持,用原生 SQL):
- 事务外
SqlQuery<S3Ref>查后代 file 的 S3 引用; - 单事务内
ExecuteSqlInterpolated递归删 files + 删 folder 子树; - 事务提交后 best-effort 循环删 S3(单失败只 log);
- 发布
FolderDeletedEvent。
S3 存储(S3StorageService)
AWSSDK.S3,ForcePathStyle=true。CompleteMultipartUpload 内部按 PartNumber 升序排序。NoSuchKey/NotFound → NotFoundException(404)。
Conventions
- file-scoped namespaces、primary constructor DI、
recordfor DTO/Command/Query classfor Entity/Handler/Endpoint/Middleware- NRT 开启 +
= default!、TreatWarningsAsErrorsON - 响应:
{ code: 0, data, message: "ok" }(ApiResponseMiddleware 自动包裹) - 路由前缀
/api/ - 错误码:401/403/400/404/409/410/413(GlobalExceptionMiddleware 映射)
Feature Folder
Application/{Feature}/Commands/ Query+Handler 同文件
Application/{Feature}/Queries/
Application/{Feature}/DTOs/
Application/{Feature}/Validators/
Api/Endpoints/{Feature}/ FastEndpoint<TReq, TRes>
Features:Files、Multipart、Buckets、Folders、Shares。
Port & Config
- HTTP
:8080(Kestrel Http1,前端/file-api代理) - gRPC
:9090(Kestrel Http2) - PostgreSQL 库
file_system Kestrel:Limits:MaxRequestBodySize= 100 MiB;gRPCMaxReceiveMessageSize= 100 MiB