multi-tenant-golisted
Install: claude install-skill omeyang/Thoth
# Go 多租户模式专家
使用 Go 实现多租户模式:$ARGUMENTS
---
## 1. 租户上下文定义
### Context Key 与基础操作
```go
// 使用 typed key 防止冲突
type contextKey string
const (
keyTenantID = contextKey("tenant_id")
keyTenantName = contextKey("tenant_name")
)
// TenantInfo 租户信息(请求级)
type TenantInfo struct {
TenantID string
TenantName string
}
func (t TenantInfo) IsEmpty() bool { return t.TenantID == "" && t.TenantName == "" }
func (t TenantInfo) Validate() error {
if t.TenantID == "" { return ErrEmptyTenantID }
if t.TenantName == "" { return ErrEmptyTenantName }
return nil
}
var (
ErrEmptyTenantID = errors.New("empty tenant_id")
ErrEmptyTenantName = errors.New("empty tenant_name")
)
```
### Context 注入与提取
```go
// 注入
func WithTenantID(ctx context.Context, id string) context.Context {
return context.WithValue(ctx, keyTenantID, id)
}
func WithTenantInfo(ctx context.Context, info TenantInfo) context.Context {
if info.TenantID != "" { ctx = context.WithValue(ctx, keyTenantID, info.TenantID) }
if info.TenantName != "" { ctx = context.WithValue(ctx, keyTenantName, info.TenantName) }
return ctx
}
// 提取(零值安全)
func TenantID(ctx context.Context) string {
if v, ok := ctx.Value(keyTenantID).(string); ok { return v }
return ""
}
// 强制提取(业务必需场景)
func RequireTenantID(ctx context.Context) (string, error) {
v := TenantID(ctx)
if v == "" { return "", ErrEmptyTenantID }
return v, nil
}
```
> 完整 Context 操作和 Identity 结构体见 [references/examples.md