feat(gateway): 多租户地基·增量1 —— 租户身份/成员/上下文(T4.A/SaaS P1)

按 SAAS_DESIGN.md P1 第一刀(真·多租户 + 桌面端为主):先立租户身份,不动查询。
- store.Tenant / TenantMember 表 + AutoMigrate
- store: CreateTenant / AddMember(幂等) / DefaultTenantForUser / EnsureDefaultTenant(幂等) /
  BackfillDefaultTenants / GetTenant / MemberRole
- 注册即建单人默认租户(owner);启动回填给存量用户补建(幂等)
- middleware.TenantContext(挂 Auth 后)解析当前租户→注入 tenant_id;handler.tenantID(c) 助手
- GET /api/v1/tenants/current 验证端点(租户上下文 + 角色)
- live:存量用户(回填 7 租户)/tenants/current 返回默认租户+owner;新注册自动建租户

下一步(增量2):核心表加 tenant_id + 统一 gorm scope 强制隔离 + 存量行回填 + 重写查询。

Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
This commit is contained in:
Blizzard
2026-07-06 17:31:09 +08:00
parent 2f19e322e3
commit 693a8f09e9
8 changed files with 250 additions and 4 deletions
+5 -3
View File
@@ -25,9 +25,10 @@ func New(db *store.Postgres, cache *store.Redis, bus *nats.Bus, blobStore *blob.
r.Use(middleware.RequestID()) // 生成/透传 X-Request-ID(日志关联)
r.Use(middleware.Observe()) // Prometheus 指标 + 结构化访问日志(替代 gin 默认文本日志)
r.Use(cors()) // 桌面端/浏览器跨源访问
r.Use(middleware.Auth()) // 解析 Bearer JWT,注入已验证 userID(非阻断)——须在限流前,供按用户限流
r.Use(middleware.RateLimit(cache)) // 已认证按用户限流,否则按 IP(企业网多人共享 IP 不再互相拖累
r.Use(middleware.Guardrail(db)) // Harness: Input Guardrail(命中落库 guardrail_event
r.Use(middleware.Auth()) // 解析 Bearer JWT,注入已验证 userID(非阻断)——须在限流前,供按用户限流
r.Use(middleware.TenantContext(db)) // 多租户:注入当前 tenant_id(已登录才解析;须在 Auth 之后
r.Use(middleware.RateLimit(cache)) // 已认证按用户限流,否则按 IP(企业网多人共享 IP 不再互相拖累
r.Use(middleware.Guardrail(db)) // Harness: Input Guardrail(命中落库 guardrail_event
h := handler.New(db, cache, bus, blobStore)
@@ -55,6 +56,7 @@ func New(db *store.Postgres, cache *store.Redis, bus *nats.Bus, blobStore *blob.
p.POST("/tasks", h.SubmitTask) // 解析 DSL 并 Publish 到 NATS(带已验证 uid
p.GET("/tasks/:id", h.TaskStatus) // 任务生命周期状态(UI 轮询 submitted/running/done/failed/timeout/waiting/rejected
p.POST("/tasks/:id/approve", middleware.Audit(db), h.ApproveTask) // HITL 人工审批决定(批准/拒绝,审计)
p.GET("/tenants/current", h.TenantCurrent) // 当前租户上下文 + 角色(多租户)
p.GET("/tasks/:id/eval", h.TaskEval) // 自动化评测结果(综合/质量/忠实度/分级)
p.PUT("/memory", h.SetMemory) // 偏好记忆登记(→ mcp-go memory_upsert
p.GET("/memory", h.ListMemory) // 列出当前用户偏好(记忆面板)