feat: add admin dashboard, audit logs, token expiry check and test suite
Frontend Features: - Add ProtectedRoute component with token expiry validation - Create AdminDashboardPage with system statistics and user management - Create AuditLogsPage with filtering and pagination - Add admin-only navigation (Shield icon) for ymirliu@panjit.com.tw - Add admin API methods to apiV2 service - Add admin type definitions (SystemStats, AuditLog, etc.) Token Management: - Auto-redirect to login on token expiry - Check authentication on route change - Show loading state during auth check - Admin privilege verification Backend Testing: - Add pytest configuration (pytest.ini) - Create test fixtures (conftest.py) - Add unit tests for auth, tasks, and admin endpoints - Add integration tests for complete workflows - Test user isolation and admin access control Documentation: - Add TESTING.md with comprehensive testing guide - Include test running instructions - Document fixtures and best practices Routes: - /admin - Admin dashboard (admin only) - /admin/audit-logs - Audit logs viewer (admin only) 🤖 Generated with [Claude Code](https://claude.com/claude-code) Co-Authored-By: Claude <noreply@anthropic.com>
This commit is contained in:
@@ -24,6 +24,12 @@ import type {
|
||||
TaskListResponse,
|
||||
TaskStats,
|
||||
SessionInfo,
|
||||
SystemStats,
|
||||
UserWithStats,
|
||||
TopUser,
|
||||
AuditLog,
|
||||
AuditLogListResponse,
|
||||
UserActivitySummary,
|
||||
} from '@/types/apiV2'
|
||||
|
||||
/**
|
||||
@@ -426,6 +432,66 @@ class ApiClientV2 {
|
||||
link.click()
|
||||
window.URL.revokeObjectURL(link.href)
|
||||
}
|
||||
|
||||
// ==================== Admin APIs ====================
|
||||
|
||||
/**
|
||||
* Get system statistics (admin only)
|
||||
*/
|
||||
async getSystemStats(): Promise<SystemStats> {
|
||||
const response = await this.client.get<SystemStats>('/admin/stats')
|
||||
return response.data
|
||||
}
|
||||
|
||||
/**
|
||||
* Get user list with statistics (admin only)
|
||||
*/
|
||||
async listUsers(params: {
|
||||
page?: number
|
||||
page_size?: number
|
||||
} = {}): Promise<{ users: UserWithStats[]; total: number; page: number; page_size: number }> {
|
||||
const response = await this.client.get('/admin/users', { params })
|
||||
return response.data
|
||||
}
|
||||
|
||||
/**
|
||||
* Get top users by metric (admin only)
|
||||
*/
|
||||
async getTopUsers(params: {
|
||||
metric?: 'tasks' | 'completed_tasks'
|
||||
limit?: number
|
||||
} = {}): Promise<TopUser[]> {
|
||||
const response = await this.client.get<TopUser[]>('/admin/users/top', { params })
|
||||
return response.data
|
||||
}
|
||||
|
||||
/**
|
||||
* Get audit logs (admin only)
|
||||
*/
|
||||
async getAuditLogs(params: {
|
||||
user_id?: number
|
||||
category?: string
|
||||
action?: string
|
||||
success?: boolean
|
||||
date_from?: string
|
||||
date_to?: string
|
||||
page?: number
|
||||
page_size?: number
|
||||
} = {}): Promise<AuditLogListResponse> {
|
||||
const response = await this.client.get<AuditLogListResponse>('/admin/audit-logs', { params })
|
||||
return response.data
|
||||
}
|
||||
|
||||
/**
|
||||
* Get user activity summary (admin only)
|
||||
*/
|
||||
async getUserActivitySummary(userId: number, days: number = 30): Promise<UserActivitySummary> {
|
||||
const response = await this.client.get<UserActivitySummary>(
|
||||
`/admin/audit-logs/user/${userId}/summary`,
|
||||
{ params: { days } }
|
||||
)
|
||||
return response.data
|
||||
}
|
||||
}
|
||||
|
||||
// Export singleton instance
|
||||
|
||||
Reference in New Issue
Block a user