feat(api): user management and audit log for admins (M1)
- /admin/users: list with search, role filter and cursor pages; create with a one-time temporary password; rename, change role, block; reset password; delete - every change is checked against the role policy, a forbidden field rejects the whole patch; the last active admin is locked in the transaction and cannot be demoted, blocked or deleted - role change and blocking revoke access tokens at once; blocking and password reset also end all sessions - /admin/audit: newest-first journal with actor names - path and query parameter errors are problem+json now Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
This commit is contained in:
1 parent
ed4a492dba
commit
f075863f15
13 files changed
+2578
-70
No files matched your search
@@ -21,6 +21,22 @@ type ProfileUpdate struct {
|
||||
UIPrefs *UIPrefs
|
||||
}
|
||||
|
||||
// UserFilter — параметры списка пользователей.
|
||||
type UserFilter struct {
|
||||
Query string // подстрока логина или имени
|
||||
Role *Role
|
||||
After string // логин последнего элемента предыдущей страницы
|
||||
Limit int
|
||||
}
|
||||
|
||||
// UserUpdate — изменения из админки. nil — не менять.
|
||||
type UserUpdate struct {
|
||||
DisplayName **string
|
||||
Role *Role
|
||||
IsBlocked *bool
|
||||
RevokeTokens bool
|
||||
}
|
||||
|
||||
// Store — доступ к users, refresh_tokens, audit_log и app_settings.
|
||||
type Store interface {
|
||||
// WithTx выполняет fn в транзакции; Store внутри fn работает в ней же.
|
||||
@@ -49,7 +65,20 @@ type Store interface {
|
||||
// ListSessions — активные семьи пользователя: есть неиспользованный, неотозванный, не истёкший токен.
|
||||
ListSessions(ctx context.Context, userID uuid.UUID, now time.Time) ([]Session, error)
|
||||
|
||||
// ListUsers — страница пользователей по возрастанию логина, после логина f.After.
|
||||
ListUsers(ctx context.Context, f UserFilter) ([]User, error)
|
||||
// LockActiveAdmins блокирует строки активных админов до конца транзакции и возвращает их число:
|
||||
// два параллельных понижения не оставят систему без админа.
|
||||
LockActiveAdmins(ctx context.Context) (int, error)
|
||||
// UpdateUser применяет изменения админки; RevokeTokens увеличивает token_version.
|
||||
UpdateUser(ctx context.Context, id uuid.UUID, upd UserUpdate) (User, error)
|
||||
// ResetPassword ставит временный пароль: must_change_password, сброс блокировки входа, token_version + 1.
|
||||
ResetPassword(ctx context.Context, id uuid.UUID, hash string) error
|
||||
DeleteUser(ctx context.Context, id uuid.UUID) error
|
||||
|
||||
InsertAudit(ctx context.Context, id uuid.UUID, e AuditEntry) error
|
||||
// ListAudit — записи журнала новее-первыми, с id меньше before (uuid.Nil — с начала).
|
||||
ListAudit(ctx context.Context, before uuid.UUID, limit int) ([]AuditRecord, error)
|
||||
GetSettingBool(ctx context.Context, key string) (bool, error)
|
||||
SetSetting(ctx context.Context, key string, value any) error
|
||||
}
|
||||
|
||||
Reference in new issue
Block a user