Painel Administrativo
O painel administrativo do CSGOFlip oferece controle completo sobre a plataforma, com dashboards, gestão de conteúdo, moderação e relatórios.
Visão Geral
Stack do Admin Dashboard
| Tecnologia | Uso |
|---|---|
| Next.js 16 | Framework |
| shadcn/ui | Componentes |
| React Query | Data fetching |
| Zustand | State management |
| Recharts | Gráficos |
| TanStack Table | Tabelas |
Seções
- Dashboard - Estatísticas e métricas
- Gestão de Usuários - Banimentos, ajustes
- Gestão de Caixas - CRUD de caixas e itens
- Transações - Histórico financeiro
- Saques - Fila de aprovação
- Relatórios - Relatórios e exportação
Autenticação Admin
Níveis de Acesso
typescript
enum AdminRole {
SUPER_ADMIN = 'SUPER_ADMIN', // Acesso total
ADMIN = 'ADMIN', // Gestão geral
MODERATOR = 'MODERATOR', // Moderação de usuários
SUPPORT = 'SUPPORT', // Apenas visualização
FINANCIAL = 'FINANCIAL', // Transações e saques
}Permissões por Módulo
| Módulo | Super Admin | Admin | Moderator | Support | Financial |
|---|---|---|---|---|---|
| Dashboard | ✅ | ✅ | ✅ | ✅ | ✅ |
| Usuários (view) | ✅ | ✅ | ✅ | ✅ | ❌ |
| Usuários (edit) | ✅ | ✅ | ✅ | ❌ | ❌ |
| Usuários (ban) | ✅ | ✅ | ✅ | ❌ | ❌ |
| Caixas (CRUD) | ✅ | ✅ | ❌ | ❌ | ❌ |
| Itens (CRUD) | ✅ | ✅ | ❌ | ❌ | ❌ |
| Transações | ✅ | ✅ | ❌ | ❌ | ✅ |
| Saques (aprovar) | ✅ | ✅ | ❌ | ❌ | ✅ |
| Configurações | ✅ | ❌ | ❌ | ❌ | ❌ |
| Logs de Auditoria | ✅ | ✅ | ❌ | ❌ | ❌ |
Guard de Autorização
typescript
// admin-auth.guard.ts
@Injectable()
export class AdminAuthGuard implements CanActivate {
constructor(
private reflector: Reflector,
private sessionService: SessionService,
) {}
async canActivate(context: ExecutionContext): Promise<boolean> {
const request = context.switchToHttp().getRequest();
// 1. Validar sessão
const sessionId = this.extractSessionId(request);
if (!sessionId) {
throw new UnauthorizedException('Session required');
}
const session = await this.sessionService.validate(sessionId);
if (!session) {
throw new UnauthorizedException('Invalid session');
}
// 2. Verificar se é admin
const user = await this.userService.findById(session.userId);
if (!user.isAdmin) {
throw new ForbiddenException('Admin access required');
}
// 3. Verificar permissão específica
const requiredRoles = this.reflector.get<AdminRole[]>(
'adminRoles',
context.getHandler(),
);
if (requiredRoles && !requiredRoles.includes(user.adminRole)) {
throw new ForbiddenException('Insufficient permissions');
}
// 4. Anexar user ao request
request.admin = user;
return true;
}
}Decorator de Roles
typescript
// admin-roles.decorator.ts
export const AdminRoles = (...roles: AdminRole[]) =>
SetMetadata('adminRoles', roles);
// Uso no controller
@Post('users/:id/ban')
@AdminRoles(AdminRole.SUPER_ADMIN, AdminRole.ADMIN, AdminRole.MODERATOR)
async banUser(@Param('id') id: string): Promise<void> {
// ...
}Estrutura do Frontend Admin
next-shadcn-admin-dashboard/
├── app/
│ ├── (auth)/
│ │ └── login/
│ │ └── page.tsx
│ ├── (dashboard)/
│ │ ├── layout.tsx
│ │ ├── page.tsx # Dashboard
│ │ ├── users/
│ │ │ ├── page.tsx # Lista de usuários
│ │ │ └── [id]/
│ │ │ └── page.tsx # Detalhes do usuário
│ │ ├── cases/
│ │ │ ├── page.tsx # Lista de caixas
│ │ │ ├── new/
│ │ │ │ └── page.tsx # Criar caixa
│ │ │ └── [id]/
│ │ │ └── page.tsx # Editar caixa
│ │ ├── items/
│ │ │ └── page.tsx # Lista de itens
│ │ ├── transactions/
│ │ │ └── page.tsx # Transações
│ │ ├── withdrawals/
│ │ │ └── page.tsx # Fila de saques
│ │ ├── deposits/
│ │ │ └── page.tsx # Depósitos
│ │ ├── battles/
│ │ │ └── page.tsx # Batalhas
│ │ └── settings/
│ │ └── page.tsx # Configurações
│ └── api/
│ └── [...proxy]/ # Proxy para backend
├── components/
│ ├── ui/ # shadcn components
│ ├── layout/
│ │ ├── sidebar.tsx
│ │ ├── header.tsx
│ │ └── breadcrumb.tsx
│ ├── dashboard/
│ │ ├── stats-cards.tsx
│ │ ├── revenue-chart.tsx
│ │ └── recent-activity.tsx
│ └── data-tables/
│ ├── users-table.tsx
│ ├── cases-table.tsx
│ └── withdrawals-table.tsx
├── lib/
│ ├── api.ts # API client
│ └── utils.ts
├── hooks/
│ ├── use-admin-auth.ts
│ └── use-data-table.ts
└── stores/
└── admin-store.ts # Zustand storeAPI Admin
Base URL
/api/admin/*Endpoints Principais
| Método | Endpoint | Descrição |
|---|---|---|
| GET | /dashboard | Estatísticas gerais |
| GET | /dashboard/revenue-chart | Dados do gráfico de receita |
| GET | /dashboard/recent-activity | Atividades recentes |
| GET | /users | Listar usuários |
| GET | /users/:id | Detalhes do usuário |
| POST | /users/:id/ban | Banir usuário |
| POST | /users/:id/unban | Desbanir usuário |
| GET | /cases | Listar caixas |
| POST | /cases | Criar caixa |
| PUT | /cases/:id | Atualizar caixa |
| DELETE | /cases/:id | Deletar caixa |
| GET | /items | Listar itens |
| POST | /items | Criar item |
| GET | /transactions | Listar transações |
| GET | /withdrawals | Listar saques |
| POST | /withdrawals/:id/approve | Aprovar saque |
| POST | /withdrawals/:id/reject | Rejeitar saque |
| GET | /deposits | Listar depósitos |
| POST | /deposits/:id/confirm | Confirmar depósito |
| GET | /battles | Listar batalhas |
| POST | /battles/:id/cancel | Cancelar batalha |
Auditoria
Todas as ações administrativas são registradas:
typescript
interface AdminAuditLog {
id: bigint;
adminId: bigint;
action: AdminAction;
resourceType: string;
resourceId: bigint;
previousValue?: Record<string, any>;
newValue?: Record<string, any>;
ipAddress: string;
userAgent: string;
createdAt: Date;
}
enum AdminAction {
USER_BANNED = 'USER_BANNED',
USER_UNBANNED = 'USER_UNBANNED',
USER_BALANCE_ADJUSTED = 'USER_BALANCE_ADJUSTED',
CASE_CREATED = 'CASE_CREATED',
CASE_UPDATED = 'CASE_UPDATED',
CASE_DELETED = 'CASE_DELETED',
ITEM_CREATED = 'ITEM_CREATED',
ITEM_UPDATED = 'ITEM_UPDATED',
ITEM_DELETED = 'ITEM_DELETED',
WITHDRAWAL_APPROVED = 'WITHDRAWAL_APPROVED',
WITHDRAWAL_REJECTED = 'WITHDRAWAL_REJECTED',
DEPOSIT_CONFIRMED = 'DEPOSIT_CONFIRMED',
DEPOSIT_REJECTED = 'DEPOSIT_REJECTED',
BATTLE_CANCELLED = 'BATTLE_CANCELLED',
SETTINGS_UPDATED = 'SETTINGS_UPDATED',
}Segurança
Rate Limiting Admin
typescript
// admin-throttler.config.ts
export const ADMIN_THROTTLE_CONFIG = {
// Limites mais generosos para admin
ttl: 60, // 1 minuto
limit: 100, // 100 requests/min
// Limites específicos por ação
actions: {
ban: { ttl: 60, limit: 10 },
approve_withdrawal: { ttl: 60, limit: 20 },
delete: { ttl: 60, limit: 5 },
},
};2FA Obrigatório
Admins devem ter 2FA ativado:
typescript
// admin-2fa.guard.ts
@Injectable()
export class Admin2FAGuard implements CanActivate {
async canActivate(context: ExecutionContext): Promise<boolean> {
const request = context.switchToHttp().getRequest();
const admin = request.admin;
if (!admin.twoFactorEnabled) {
throw new ForbiddenException(
'Two-factor authentication is required for admin access',
);
}
return true;
}
}IP Whitelist (Opcional)
typescript
// admin-ip.guard.ts
@Injectable()
export class AdminIPGuard implements CanActivate {
private readonly allowedIPs = process.env.ADMIN_ALLOWED_IPS?.split(',') || [];
canActivate(context: ExecutionContext): boolean {
if (this.allowedIPs.length === 0) {
return true; // Whitelist desabilitado
}
const request = context.switchToHttp().getRequest();
const clientIP = getClientIP(request);
if (!this.allowedIPs.includes(clientIP)) {
throw new ForbiddenException('IP not allowed');
}
return true;
}
}