feat(permission): add RBAC module with Casbin enforcement and policy reload
- Multi-tenant RBAC: permission catalog, roles, role-permission mapping,
user-role assignment, and external IdP role mapping (zitadel/ldap/scim).
- Casbin enforcer with Redis-backed adapter and Pub/Sub reload for
multi-instance policy sync; HTTP middleware enforces (tenant, role,
path, method) with platform admin bypass.
- /api/v1/permissions routes: catalog, me, policy/reload, roles CRUD,
role permissions, user roles, role mappings.
- New error scope (31) for Permission and biz code descriptions.
- Wire Permission module into ServiceContext, config, mongo-index, and
add cmd/permission-seed CLI plus etc/rbac.conf model.
- Redis client gains lazy PubSubClient helper (go-zero wrapper lacks Subscribe).
- Rewrite internal/model/member/README to cover Tenant/Member/Identity.
Co-authored-by: Cursor <cursoragent@cursor.com>
2026-05-21 08:47:35 +00:00
|
|
|
// Package domain holds the permission module's domain-level definitions
|
|
|
|
|
// (entities, enums, repository/usecase interfaces, errors, redis key
|
|
|
|
|
// helpers, BSON field names). Sub-packages MUST NOT depend on the
|
|
|
|
|
// repository or usecase implementation packages.
|
|
|
|
|
package domain
|
|
|
|
|
|
|
|
|
|
// MongoDB BSON field names used by repositories. Keep in sync with the
|
|
|
|
|
// `bson:` tags on entity structs so usecase / repo code never relies on
|
|
|
|
|
// magic strings.
|
|
|
|
|
const (
|
|
|
|
|
BSONFieldID = "_id"
|
|
|
|
|
BSONFieldTenantID = "tenant_id"
|
|
|
|
|
BSONFieldUID = "uid"
|
|
|
|
|
|
|
|
|
|
// permissions collection
|
|
|
|
|
BSONFieldName = "name"
|
|
|
|
|
BSONFieldParent = "parent"
|
|
|
|
|
BSONFieldHTTPMethods = "http_methods"
|
|
|
|
|
BSONFieldHTTPPath = "http_path"
|
|
|
|
|
BSONFieldStatus = "status"
|
|
|
|
|
BSONFieldType = "type"
|
|
|
|
|
|
|
|
|
|
// roles collection
|
|
|
|
|
BSONFieldKey = "key"
|
|
|
|
|
BSONFieldDisplayName = "display_name"
|
|
|
|
|
BSONFieldCreatorUID = "creator_uid"
|
|
|
|
|
BSONFieldIsSystem = "is_system"
|
|
|
|
|
|
|
|
|
|
// role_permissions
|
|
|
|
|
BSONFieldRoleID = "role_id"
|
|
|
|
|
BSONFieldPermissionID = "permission_id"
|
|
|
|
|
|
|
|
|
|
// user_roles
|
|
|
|
|
BSONFieldSource = "source"
|
|
|
|
|
|
|
|
|
|
// role_mappings
|
|
|
|
|
BSONFieldExternalSource = "external_source"
|
|
|
|
|
BSONFieldExternalKey = "external_key"
|
|
|
|
|
BSONFieldInternalRoleID = "internal_role_id"
|
|
|
|
|
BSONFieldInternalRoleKey = "internal_role_key"
|
|
|
|
|
|
|
|
|
|
BSONFieldCreateAt = "create_at"
|
|
|
|
|
BSONFieldUpdateAt = "update_at"
|
|
|
|
|
)
|
|
|
|
|
|
|
|
|
|
// Casbin policy section markers and reload pubsub channel.
|
|
|
|
|
const (
|
|
|
|
|
CasbinPolicyType = "p"
|
|
|
|
|
|
|
|
|
|
// PolicyReloadChannel is the Redis Pub/Sub channel used to broadcast
|
|
|
|
|
// "tenant policy needs reload" events across pods. Payload is JSON:
|
|
|
|
|
// { "tenant_id": "xxx", "ts": 1716120000000 }
|
|
|
|
|
// tenant_id == "*" means full LoadAllPolicies.
|
|
|
|
|
PolicyReloadChannel = "casbin:reload"
|
|
|
|
|
|
|
|
|
|
// PolicyReloadAllToken is the wildcard for full reload.
|
|
|
|
|
PolicyReloadAllToken = "*"
|
|
|
|
|
)
|
|
|
|
|
|
2026-05-22 09:18:08 +00:00
|
|
|
// Role.Key constraints. See internal/model/permission/SDD.md §3.3 (RBAC Model).
|
feat(permission): add RBAC module with Casbin enforcement and policy reload
- Multi-tenant RBAC: permission catalog, roles, role-permission mapping,
user-role assignment, and external IdP role mapping (zitadel/ldap/scim).
- Casbin enforcer with Redis-backed adapter and Pub/Sub reload for
multi-instance policy sync; HTTP middleware enforces (tenant, role,
path, method) with platform admin bypass.
- /api/v1/permissions routes: catalog, me, policy/reload, roles CRUD,
role permissions, user roles, role mappings.
- New error scope (31) for Permission and biz code descriptions.
- Wire Permission module into ServiceContext, config, mongo-index, and
add cmd/permission-seed CLI plus etc/rbac.conf model.
- Redis client gains lazy PubSubClient helper (go-zero wrapper lacks Subscribe).
- Rewrite internal/model/member/README to cover Tenant/Member/Identity.
Co-authored-by: Cursor <cursoragent@cursor.com>
2026-05-21 08:47:35 +00:00
|
|
|
const (
|
|
|
|
|
RoleKeyMinLength = 2
|
|
|
|
|
RoleKeyMaxLength = 64
|
|
|
|
|
RoleDisplayNameMax = 128
|
|
|
|
|
PermissionNameMax = 128
|
|
|
|
|
HTTPPathMaxLength = 256
|
|
|
|
|
HTTPMethodsMaxLen = 64
|
|
|
|
|
ExternalKeyMaxLen = 256
|
|
|
|
|
RoleMappingPageSize = 50
|
|
|
|
|
)
|
|
|
|
|
|
|
|
|
|
// Reserved Role.Key prefixes that B2B tenants must not register.
|
|
|
|
|
var ReservedRoleKeyPrefixes = []string{"system.", "platform_"}
|