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

@@ -6,6 +6,7 @@ import { apiClient } from '../api/client';
import { captureCampaignFromUrl, consumeCampaignSlug } from '../utils/campaign';
import { captureReferralFromUrl, consumeReferralCode } from '../utils/referral';
import { tokenStorage, isTokenValid, tokenRefreshManager } from '../utils/token';
import { usePermissionStore } from './permissions';
export interface TelegramWidgetData {
id: number;
@@ -93,6 +94,7 @@ export const useAuthStore = create<AuthState>()(
});
}
tokenStorage.clearTokens();
usePermissionStore.getState().reset();
set({
accessToken: null,
refreshToken: null,
@@ -107,13 +109,20 @@ export const useAuthStore = create<AuthState>()(
const token = tokenStorage.getAccessToken();
if (!token || !isTokenValid(token)) {
set({ isAdmin: false });
usePermissionStore.getState().reset();
return;
}
// Используем apiClient для единообразной обработки ошибок
const response = await apiClient.get<{ is_admin: boolean }>('/cabinet/auth/me/is-admin');
set({ isAdmin: response.data.is_admin });
if (response.data.is_admin) {
await usePermissionStore.getState().fetchPermissions();
} else {
usePermissionStore.getState().reset();
}
} catch {
set({ isAdmin: false });
usePermissionStore.getState().reset();
}
},