4.9 KiB
4.9 KiB
CLAUDE.md
Cross-repo rules — see
/Users/wen/project/rag/CLAUDE.mdfor full workspace conventions.
- .NET backends share JWT key:
RagJwtSecretKey2026MustBeAtLeast32CharsLong!- gRPC auth: call
rag-backend:50051for token validation + permission checks- Other repos:
rag-backend(5211),im-system(5212),work-flow,rag-frontend(5666 Vue)
Build & Run
go run ./cmd/server -conf configs/config.yaml # HTTP :8080, gRPC :9000
make api # Regenerate proto code
make wire # Regenerate Wire DI
go test ./... # All tests
buf generate # Regenerate proto
docker compose up -d # Via local build
Architecture
Go 1.25 microservice. Kratos framework + DDD four-layer + Watermill CQRS.
cmd/server/main.go → Entry point, load config
cmd/server/wire.go → Wire DI declarations
cmd/server/wire_gen.go → Wire generated code
api/file/v1/ → Proto definitions (HTTP+gRPC dual protocol)
internal/conf/ → Config structs (proto-defined)
internal/biz/ → Business logic layer (repo interface definitions + usecases)
internal/data/ → Data access layer (GORM + S3, implements biz repo interfaces)
internal/service/ → Service implementation (implements proto Service interface)
internal/server/ → HTTP/gRPC server creation and middleware
internal/watermark/ → Watermill CQRS (CommandBus + EventBus)
internal/pkg/sanitize/ → Input sanitization utilities
internal/pkg/s3errors/ → S3 error mapping
configs/config.yaml → Local dev config
Layered Call Chain
service (DTO conversion) → biz (business logic) → data (data access)
↕
watermark (CQRS commands/events)
Tech Stack
- Kratos — HTTP + gRPC framework, proto-first API definition
- Wire — Compile-time dependency injection
- Watermill — CQRS (CommandBus + EventBus), PGSQL as message store
- GORM — Business data ORM (folders, files, share_links)
- AWS SDK v2 — S3 interface to RustFS/MinIO
- PostgreSQL — Business data + Watermill message queue
Code Patterns
Wire ProviderSet Pattern
Each layer defines a ProviderSet:
// internal/data/data.go
var ProviderSet = wire.NewSet(NewData, NewFileRepo, NewFolderRepo, NewFileMetaRepo, NewShareRepo)
// internal/biz/biz.go
var ProviderSet = wire.NewSet(NewFileUsecase, NewBucketUsecase, NewFolderUsecase, NewShareUsecase)
// internal/service/service.go
var ProviderSet = wire.NewSet(NewFileService)
// internal/server/server.go
var ProviderSet = wire.NewSet(NewHTTPServer, NewGRPCServer)
Wire bindings (in cmd/server/wire.go):
biz.FileRepo→*data.FileRepobiz.FolderRepo→*data.FolderRepobiz.FileMetaRepo→*data.FileMetaRepobiz.ShareRepo→*data.ShareRepo
GORM Transaction Management
// biz layer defines interface
type Transaction interface { InTx(ctx context.Context, fn func(ctx context.Context) error) error }
// data layer implements
func (d *Data) DB(ctx context.Context) *gorm.DB {
tx, ok := ctx.Value(contextTxKey{}).(*gorm.DB)
if ok { return tx }
return d.db.WithContext(ctx)
}
Proto Error Definition
Errors defined in api/file/v1/error_reason.proto:
enum ErrorReason {
FILE_NOT_FOUND = 0 [(errors.code) = 404];
INVALID_PARAMETER = 1 [(errors.code) = 400];
}
Usage: return nil, api.file.v1.ErrorFileNotFound("file %s not found", key)
GORM Model Naming
- Models suffixed with
PO:FolderPO,FileMetaPO,ShareLinkPO - Table names via
TableName()method with snake_case
Service → Biz → Data Pattern
// service: proto request → usecase call → proto response
func (s *FileService) UploadFile(ctx context.Context, req *pb.UploadFileRequest) (*pb.UploadFileResponse, error) {
err := s.fileUC.UploadFile(ctx, req.BucketName, req.ObjectKey, bytes.NewReader(req.Data))
return &pb.UploadFileResponse{Message: "uploaded"}, err
}
// biz: business logic, repo interface calls
func (uc *FileUsecase) UploadFile(ctx context.Context, bucket, key string, data io.Reader) error {
return uc.repo.UploadFile(ctx, bucket, key, data)
}
// data: concrete implementation
func (r *FileRepo) UploadFile(ctx context.Context, bucket, key string, data io.Reader) error {
_, err := r.client.PutObject(ctx, &s3.PutObjectInput{...})
return s3errors.Wrap(err)
}
Configuration
configs/config.yaml for local development. Environment variables via ${ENV_VAR} placeholders.
Loaded via Kratos config component with file source.
Middleware Chain (Kratos)
HTTP and gRPC share the same middleware:
recovery → tracing → logging
Configured in internal/server/http.go and internal/server/grpc.go.