feat: /v1/role list, get, create, update and delete. Reassign members on delete. Write-time validation (ValidateGrants, duplicates, typed keys against real content types). Name uniqueness (role_name_taken), role_locked, role_has_members, role_conflict on version mismatch. No-escalation: nobody grants a permission they don't hold, and roles.edit_owner_only guards the Owner role. Activity events for role changes. Typed-key exposure in /auth/me. Cleanup of typed rows when a content type is deleted. | Backend only. Will carry the deferred ListGrants decision.

This commit is contained in:
Florian Sylvain committed 2026-10-27 00:45:24 +01:00
1 parent a043f7f41a
commit 094df63a7f
51 files changed
+4822 -115

No files matched your search

+22 -7
View File
@@ -3,6 +3,7 @@ package role
import (
"errors"
"strings"
"time"
)
var (
@@ -14,6 +15,18 @@ var (
ErrDuplicateGrant = errors.New("permission granted more than once")
ErrMissingPermission = errors.New("missing permission")
ErrRoleHasMembers = errors.New("role still has members")
ErrRoleNameTaken = errors.New("role name already used")
ErrRoleLocked = errors.New("role is locked")
ErrBuiltInRole = errors.New("role is built in")
ErrBuiltInName = errors.New("built-in role cannot be renamed")
ErrOwnRole = errors.New("cannot change the role you hold")
ErrInvalidRoleName = errors.New("invalid role name")
ErrUnknownContentType = errors.New("unknown content type")
ErrNotBuiltIn = errors.New("role is not built in")
ErrInvalidReassign = errors.New("invalid reassign target")
ErrEscalation = errors.New("grants more than the caller holds")
)
type Scope string
@@ -30,13 +43,15 @@ type Grant struct {
}
type Role struct {
ID uint32 `json:"id"`
Name string `json:"name"`
Description string `json:"description"`
BuiltIn bool `json:"built_in"`
Locked bool `json:"locked"`
Version uint32 `json:"version"`
Grants []Grant `json:"grants"`
ID uint32 `json:"id"`
Name string `json:"name"`
Description string `json:"description"`
BuiltIn bool `json:"built_in"`
Locked bool `json:"locked"`
Version uint32 `json:"version"`
Grants []Grant `json:"grants"`
UpdatedAt time.Time `json:"-"`
UpdatedBy *uint32 `json:"-"`
}
func resolveGrantKey(key string) (Permission, error) {