feat: add RBAC permission system to admin cabinet frontend

- Permission store (Zustand) with wildcard matching and role level checks
- PermissionRoute guard for route-level access control
- PermissionGate component for element-level visibility
- Admin Roles page: CRUD, permission editor, role assignment
- Admin Policies page: ABAC policy management (time/IP conditions)
- Admin Audit Log page: filterable log viewer with CSV export
- AdminPanel sidebar navigation gated by permissions
- 4 locale files updated (en, ru, zh, fa) with RBAC translations
- API client module for all RBAC endpoints
This commit is contained in:
Fringg
2026-02-25 03:02:52 +03:00
parent 48be067d1b
commit 874ee2682e
15 changed files with 5320 additions and 121 deletions

View File

@@ -835,7 +835,8 @@
"marketing": "Marketing",
"system": "System",
"tariffs": "Tariffs & Sales",
"users": "Users"
"users": "Users",
"security": "Security"
},
"nav": {
"title": "Admin",
@@ -862,7 +863,11 @@
"pinnedMessages": "Pinned Messages",
"partners": "Partners",
"withdrawals": "Withdrawals",
"channelSubscriptions": "Required Channels"
"channelSubscriptions": "Required Channels",
"roles": "Roles",
"roleAssign": "Role Assignment",
"policies": "Access Policies",
"auditLog": "Audit Log"
},
"panel": {
"title": "Admin Panel",
@@ -890,7 +895,11 @@
"pinnedMessagesDesc": "Manage pinned messages for users",
"partnersDesc": "Manage partner applications and commissions",
"withdrawalsDesc": "Review and process withdrawal requests",
"channelSubscriptionsDesc": "Manage required channel subscriptions"
"channelSubscriptionsDesc": "Manage required channel subscriptions",
"rolesDesc": "Manage admin roles and permissions",
"roleAssignDesc": "Assign and revoke user roles",
"policiesDesc": "Configure ABAC access policies",
"auditLogDesc": "Review system activity and access history"
},
"trafficUsage": {
"title": "Traffic Usage",
@@ -2920,6 +2929,274 @@
"unhealthy": "Unhealthy",
"components": "Components",
"uptime": "Uptime"
},
"roles": {
"title": "Roles & Permissions",
"subtitle": "Manage admin roles and their permissions",
"createRole": "Create Role",
"noRoles": "No roles found",
"systemBadge": "System",
"inactiveBadge": "Inactive",
"levelLabel": "Level",
"usersCount_one": "{{count}} user",
"usersCount_other": "{{count}} users",
"permissionsCount_one": "{{count}} permission",
"permissionsCount_other": "{{count}} permissions",
"stats": {
"totalRoles": "Total roles",
"active": "Active",
"system": "System"
},
"actions": {
"edit": "Edit",
"delete": "Delete"
},
"modal": {
"createTitle": "Create Role",
"editTitle": "Edit Role",
"close": "Close"
},
"form": {
"name": "Role name",
"namePlaceholder": "e.g. Moderator",
"description": "Description",
"descriptionPlaceholder": "What this role is for...",
"level": "Priority level",
"levelValue": "Level value",
"levelHint": "Higher level = more authority. Users can only manage roles with a lower level than their own.",
"color": "Color",
"presets": "Permission presets",
"permissions": "Permissions",
"toggleSection": "Toggle all {{section}} permissions",
"selectedPermissions_one": "{{count}} permission selected",
"selectedPermissions_other": "{{count}} permissions selected",
"cancel": "Cancel",
"saving": "Saving...",
"save": "Save"
},
"presets": {
"moderator": "Moderator",
"marketer": "Marketer",
"support": "Support"
},
"confirm": {
"title": "Delete role?",
"text": "This role will be permanently deleted. Users with this role will lose its permissions.",
"cancel": "Cancel",
"delete": "Delete",
"deleting": "Deleting..."
},
"errors": {
"loadFailed": "Failed to load roles",
"createFailed": "Failed to create role",
"updateFailed": "Failed to update role",
"nameRequired": "Role name is required"
}
},
"roleAssign": {
"title": "Role Assignment",
"subtitle": "Assign and manage user roles",
"assignSection": "Assign Role",
"userLabel": "User",
"searchPlaceholder": "Search by name, username, Telegram ID, or email...",
"clearUser": "Clear selected user",
"noUsersFound": "No users found",
"roleLabel": "Role",
"selectRole": "Select a role...",
"expiresLabel": "Expires at (optional)",
"expiresHint": "Leave empty for permanent assignment",
"assignButton": "Assign",
"assigning": "Assigning...",
"assignSuccess": "Role assigned successfully",
"currentAssignments": "Current Assignments",
"totalAssignments_one": "{{count}} assignment total",
"totalAssignments_other": "{{count}} assignments total",
"noAssignments": "No role assignments found",
"unknownUser": "Unknown user",
"system": "System",
"permanent": "Permanent",
"expired": "expired",
"revoke": "Revoke",
"revokeAriaLabel": "Revoke role {{role}} from {{user}}",
"table": {
"user": "User",
"role": "Role",
"assignedBy": "Assigned by",
"assignedAt": "Assigned at",
"expires": "Expires",
"actions": "Actions"
},
"pagination": {
"showing": "{{from}}-{{to}} of {{total}}",
"prev": "Previous page",
"next": "Next page"
},
"confirm": {
"title": "Revoke role?",
"text": "This user will immediately lose all permissions associated with this role.",
"cancel": "Cancel",
"revoke": "Revoke",
"revoking": "Revoking..."
},
"errors": {
"userRequired": "Please select a user",
"roleRequired": "Please select a role",
"assignFailed": "Failed to assign role"
}
},
"policies": {
"title": "Access Policies",
"subtitle": "Manage ABAC access control policies",
"createPolicy": "Create Policy",
"noPolicies": "No policies found",
"inactiveBadge": "Inactive",
"effectAllow": "Allow",
"effectDeny": "Deny",
"global": "Global",
"unknownRole": "Unknown role",
"roleLabel": "Role",
"priorityLabel": "Priority",
"stats": {
"total": "Total policies",
"allow": "Allow",
"deny": "Deny",
"active": "Active"
},
"actions": {
"edit": "Edit",
"delete": "Delete"
},
"modal": {
"createTitle": "Create Policy",
"editTitle": "Edit Policy",
"close": "Close"
},
"form": {
"name": "Policy name",
"namePlaceholder": "e.g. Block night access",
"description": "Description",
"descriptionPlaceholder": "What this policy does...",
"effect": "Effect",
"resource": "Resource",
"selectResource": "Select a resource...",
"actions": "Actions",
"role": "Role (optional)",
"globalOption": "Global (all roles)",
"roleHint": "Leave as Global to apply the policy to all roles.",
"priority": "Priority",
"priorityHint": "Higher priority policies are evaluated first. Deny overrides Allow at equal priority.",
"conditions": "Conditions",
"cancel": "Cancel",
"saving": "Saving...",
"save": "Save"
},
"conditions": {
"timeRange": "Time range",
"timeStart": "Start time",
"timeEnd": "End time",
"ipWhitelist": "IP whitelist",
"ipPlaceholder": "Enter IP and press Enter...",
"removeIp": "Remove {{ip}}",
"ipCount_one": "{{count}} IP",
"ipCount_other": "{{count}} IPs",
"rateLimit": "Rate limit",
"rateLimitValue": "Rate limit value",
"rateValue": "{{count}}/hr",
"perHour": "actions per hour"
},
"confirm": {
"title": "Delete policy?",
"text": "This policy will be permanently deleted. Access control rules will be recalculated.",
"cancel": "Cancel",
"delete": "Delete",
"deleting": "Deleting..."
},
"errors": {
"loadFailed": "Failed to load policies",
"createFailed": "Failed to create policy",
"updateFailed": "Failed to update policy",
"nameRequired": "Policy name is required",
"resourceRequired": "Please select a resource",
"actionsRequired": "Please select at least one action"
}
},
"auditLog": {
"title": "Audit Log",
"subtitle": "Review system activity and access history",
"back": "Back",
"exportCsv": "Export CSV",
"exporting": "Exporting...",
"refresh": "Refresh",
"unknownUser": "Unknown user",
"noEntries": "No audit log entries found",
"totalEntries_one": "{{count}} entry",
"totalEntries_other": "{{count}} entries",
"autoRefresh": {
"label": "Auto-refresh",
"tooltip": "Auto-refresh every 30 seconds"
},
"filters": {
"title": "Filters",
"active": "Active",
"action": "Action",
"actionPlaceholder": "Search by action...",
"resource": "Resource type",
"allResources": "All resources",
"status": "Status",
"allStatuses": "All statuses",
"dateFrom": "Date from",
"dateTo": "Date to",
"apply": "Apply",
"clear": "Clear"
},
"status": {
"success": "Success",
"denied": "Denied",
"error": "Error"
},
"resourceTypes": {
"users": "Users",
"tickets": "Tickets",
"roles": "Roles",
"policies": "Policies",
"settings": "Settings",
"broadcasts": "Broadcasts",
"tariffs": "Tariffs",
"servers": "Servers",
"payments": "Payments",
"campaigns": "Campaigns",
"promocodes": "Promo Codes"
},
"details": {
"userAgent": "User Agent",
"requestPath": "Request Path",
"ipAddress": "IP Address",
"timestamp": "Timestamp",
"before": "Before",
"after": "After",
"fullDetails": "Full Details"
},
"time": {
"justNow": "Just now",
"minutesAgo_one": "{{count}} min ago",
"minutesAgo_other": "{{count}} min ago",
"hoursAgo_one": "{{count}} hr ago",
"hoursAgo_other": "{{count}} hrs ago",
"daysAgo_one": "{{count}} day ago",
"daysAgo_other": "{{count}} days ago"
},
"pagination": {
"pageSize": "Per page:",
"pageOf": "{{current}} / {{total}}",
"first": "First page",
"previous": "Previous page",
"next": "Next page",
"last": "Last page"
},
"errors": {
"loadFailed": "Failed to load audit log",
"retry": "Try again"
}
}
},
"profile": {