- Complete PostgreSQL database schema with 21+ tables - Express.js server with dual authentication (player/admin) - WebSocket support for real-time features - Comprehensive middleware (auth, validation, logging, security) - Game systems: colonies, resources, fleets, research, factions - Plugin-based combat architecture - Admin panel foundation - Production-ready logging and error handling - Docker support and CI/CD ready - Complete project structure following CLAUDE.md patterns 🤖 Generated with Claude Code (https://claude.ai/code) Co-Authored-By: Claude <noreply@anthropic.com>
401 lines
No EOL
12 KiB
JavaScript
401 lines
No EOL
12 KiB
JavaScript
/**
|
|
* Admin API Routes
|
|
* Defines all administrative API endpoints with proper authentication and permissions
|
|
*/
|
|
|
|
const express = require('express');
|
|
const router = express.Router();
|
|
|
|
// Import middleware
|
|
const { authenticateAdmin, requirePermissions, requirePlayerAccess, auditAdminAction, ADMIN_PERMISSIONS } = require('../middleware/admin.middleware');
|
|
const { rateLimiters } = require('../middleware/rateLimit.middleware');
|
|
const { validators, validateRequest } = require('../middleware/validation.middleware');
|
|
const corsMiddleware = require('../middleware/cors.middleware');
|
|
|
|
// Import controllers
|
|
const adminAuthController = require('../controllers/admin/auth.controller');
|
|
|
|
// Import services for direct admin operations
|
|
const AdminService = require('../services/user/AdminService');
|
|
const adminService = new AdminService();
|
|
|
|
// Apply CORS to all admin routes
|
|
router.use(corsMiddleware);
|
|
|
|
// Apply admin-specific rate limiting
|
|
router.use(rateLimiters.admin);
|
|
|
|
/**
|
|
* Admin API Status and Information
|
|
*/
|
|
router.get('/', (req, res) => {
|
|
res.json({
|
|
name: 'Shattered Void - Admin API',
|
|
version: process.env.npm_package_version || '0.1.0',
|
|
status: 'operational',
|
|
timestamp: new Date().toISOString(),
|
|
correlationId: req.correlationId,
|
|
endpoints: {
|
|
authentication: '/api/admin/auth',
|
|
players: '/api/admin/players',
|
|
system: '/api/admin/system',
|
|
events: '/api/admin/events',
|
|
analytics: '/api/admin/analytics'
|
|
},
|
|
note: 'Administrative access required for all endpoints'
|
|
});
|
|
});
|
|
|
|
/**
|
|
* Admin Authentication Routes
|
|
* /api/admin/auth/*
|
|
*/
|
|
const authRoutes = express.Router();
|
|
|
|
// Public admin authentication endpoints
|
|
authRoutes.post('/login',
|
|
rateLimiters.auth,
|
|
validators.validateAdminLogin,
|
|
auditAdminAction('admin_login'),
|
|
adminAuthController.login
|
|
);
|
|
|
|
// Protected admin authentication endpoints
|
|
authRoutes.post('/logout',
|
|
authenticateAdmin,
|
|
auditAdminAction('admin_logout'),
|
|
adminAuthController.logout
|
|
);
|
|
|
|
authRoutes.get('/me',
|
|
authenticateAdmin,
|
|
adminAuthController.getProfile
|
|
);
|
|
|
|
authRoutes.get('/verify',
|
|
authenticateAdmin,
|
|
adminAuthController.verifyToken
|
|
);
|
|
|
|
authRoutes.post('/refresh',
|
|
rateLimiters.auth,
|
|
adminAuthController.refresh
|
|
);
|
|
|
|
authRoutes.get('/stats',
|
|
authenticateAdmin,
|
|
requirePermissions([ADMIN_PERMISSIONS.ANALYTICS_READ]),
|
|
auditAdminAction('view_system_stats'),
|
|
adminAuthController.getSystemStats
|
|
);
|
|
|
|
authRoutes.post('/change-password',
|
|
authenticateAdmin,
|
|
rateLimiters.auth,
|
|
validateRequest(require('joi').object({
|
|
currentPassword: require('joi').string().required(),
|
|
newPassword: require('joi').string().min(8).max(128).required()
|
|
}), 'body'),
|
|
auditAdminAction('admin_password_change'),
|
|
adminAuthController.changePassword
|
|
);
|
|
|
|
// Mount admin authentication routes
|
|
router.use('/auth', authRoutes);
|
|
|
|
/**
|
|
* Player Management Routes
|
|
* /api/admin/players/*
|
|
*/
|
|
const playerRoutes = express.Router();
|
|
|
|
// All player management routes require authentication
|
|
playerRoutes.use(authenticateAdmin);
|
|
|
|
// Get players list
|
|
playerRoutes.get('/',
|
|
requirePermissions([ADMIN_PERMISSIONS.PLAYER_DATA_READ]),
|
|
validators.validatePagination,
|
|
validateRequest(require('joi').object({
|
|
search: require('joi').string().max(50).optional(),
|
|
activeOnly: require('joi').boolean().optional(),
|
|
sortBy: require('joi').string().valid('created_at', 'updated_at', 'username', 'email', 'last_login_at').default('created_at'),
|
|
sortOrder: require('joi').string().valid('asc', 'desc').default('desc')
|
|
}), 'query'),
|
|
auditAdminAction('list_players'),
|
|
async (req, res) => {
|
|
try {
|
|
const {
|
|
page = 1,
|
|
limit = 20,
|
|
search = '',
|
|
activeOnly = null,
|
|
sortBy = 'created_at',
|
|
sortOrder = 'desc'
|
|
} = req.query;
|
|
|
|
const result = await adminService.getPlayersList({
|
|
page: parseInt(page),
|
|
limit: parseInt(limit),
|
|
search,
|
|
activeOnly,
|
|
sortBy,
|
|
sortOrder
|
|
}, req.correlationId);
|
|
|
|
res.json({
|
|
success: true,
|
|
message: 'Players list retrieved successfully',
|
|
data: result,
|
|
correlationId: req.correlationId
|
|
});
|
|
|
|
} catch (error) {
|
|
res.status(500).json({
|
|
success: false,
|
|
error: 'Failed to retrieve players list',
|
|
message: error.message,
|
|
correlationId: req.correlationId
|
|
});
|
|
}
|
|
}
|
|
);
|
|
|
|
// Get specific player details
|
|
playerRoutes.get('/:playerId',
|
|
requirePlayerAccess('playerId'),
|
|
validators.validatePlayerId,
|
|
auditAdminAction('view_player_details'),
|
|
async (req, res) => {
|
|
try {
|
|
const playerId = parseInt(req.params.playerId);
|
|
const playerDetails = await adminService.getPlayerDetails(playerId, req.correlationId);
|
|
|
|
res.json({
|
|
success: true,
|
|
message: 'Player details retrieved successfully',
|
|
data: {
|
|
player: playerDetails
|
|
},
|
|
correlationId: req.correlationId
|
|
});
|
|
|
|
} catch (error) {
|
|
const statusCode = error.name === 'NotFoundError' ? 404 : 500;
|
|
res.status(statusCode).json({
|
|
success: false,
|
|
error: error.name === 'NotFoundError' ? 'Player not found' : 'Failed to retrieve player details',
|
|
message: error.message,
|
|
correlationId: req.correlationId
|
|
});
|
|
}
|
|
}
|
|
);
|
|
|
|
// Update player status (activate/deactivate)
|
|
playerRoutes.put('/:playerId/status',
|
|
requirePermissions([ADMIN_PERMISSIONS.PLAYER_MANAGEMENT]),
|
|
validators.validatePlayerId,
|
|
validateRequest(require('joi').object({
|
|
isActive: require('joi').boolean().required(),
|
|
reason: require('joi').string().max(200).optional()
|
|
}), 'body'),
|
|
auditAdminAction('update_player_status'),
|
|
async (req, res) => {
|
|
try {
|
|
const playerId = parseInt(req.params.playerId);
|
|
const { isActive, reason } = req.body;
|
|
|
|
const updatedPlayer = await adminService.updatePlayerStatus(
|
|
playerId,
|
|
isActive,
|
|
req.correlationId
|
|
);
|
|
|
|
res.json({
|
|
success: true,
|
|
message: `Player ${isActive ? 'activated' : 'deactivated'} successfully`,
|
|
data: {
|
|
player: updatedPlayer,
|
|
action: isActive ? 'activated' : 'deactivated',
|
|
reason: reason || null
|
|
},
|
|
correlationId: req.correlationId
|
|
});
|
|
|
|
} catch (error) {
|
|
const statusCode = error.name === 'NotFoundError' ? 404 : 500;
|
|
res.status(statusCode).json({
|
|
success: false,
|
|
error: error.name === 'NotFoundError' ? 'Player not found' : 'Failed to update player status',
|
|
message: error.message,
|
|
correlationId: req.correlationId
|
|
});
|
|
}
|
|
}
|
|
);
|
|
|
|
// Mount player management routes
|
|
router.use('/players', playerRoutes);
|
|
|
|
/**
|
|
* System Management Routes
|
|
* /api/admin/system/*
|
|
*/
|
|
const systemRoutes = express.Router();
|
|
|
|
// All system routes require authentication
|
|
systemRoutes.use(authenticateAdmin);
|
|
|
|
// Get detailed system statistics
|
|
systemRoutes.get('/stats',
|
|
requirePermissions([ADMIN_PERMISSIONS.SYSTEM_MANAGEMENT]),
|
|
auditAdminAction('view_detailed_system_stats'),
|
|
async (req, res) => {
|
|
try {
|
|
const stats = await adminService.getSystemStats(req.correlationId);
|
|
|
|
// Add additional system information
|
|
const systemInfo = {
|
|
...stats,
|
|
server: {
|
|
version: process.env.npm_package_version || '0.1.0',
|
|
environment: process.env.NODE_ENV || 'development',
|
|
uptime: process.uptime(),
|
|
nodeVersion: process.version,
|
|
memory: {
|
|
used: Math.round(process.memoryUsage().heapUsed / 1024 / 1024),
|
|
total: Math.round(process.memoryUsage().heapTotal / 1024 / 1024),
|
|
rss: Math.round(process.memoryUsage().rss / 1024 / 1024)
|
|
}
|
|
}
|
|
};
|
|
|
|
res.json({
|
|
success: true,
|
|
message: 'System statistics retrieved successfully',
|
|
data: systemInfo,
|
|
correlationId: req.correlationId
|
|
});
|
|
|
|
} catch (error) {
|
|
res.status(500).json({
|
|
success: false,
|
|
error: 'Failed to retrieve system statistics',
|
|
message: error.message,
|
|
correlationId: req.correlationId
|
|
});
|
|
}
|
|
}
|
|
);
|
|
|
|
// System health check
|
|
systemRoutes.get('/health',
|
|
requirePermissions([ADMIN_PERMISSIONS.SYSTEM_MANAGEMENT]),
|
|
async (req, res) => {
|
|
try {
|
|
// TODO: Implement comprehensive health checks
|
|
// - Database connectivity
|
|
// - Redis connectivity
|
|
// - WebSocket server status
|
|
// - External service connectivity
|
|
|
|
const healthStatus = {
|
|
status: 'healthy',
|
|
timestamp: new Date().toISOString(),
|
|
services: {
|
|
database: 'healthy',
|
|
redis: 'healthy',
|
|
websocket: 'healthy'
|
|
},
|
|
performance: {
|
|
uptime: process.uptime(),
|
|
memory: process.memoryUsage(),
|
|
cpu: process.cpuUsage()
|
|
}
|
|
};
|
|
|
|
res.json({
|
|
success: true,
|
|
message: 'System health check completed',
|
|
data: healthStatus,
|
|
correlationId: req.correlationId
|
|
});
|
|
|
|
} catch (error) {
|
|
res.status(500).json({
|
|
success: false,
|
|
error: 'Health check failed',
|
|
message: error.message,
|
|
correlationId: req.correlationId
|
|
});
|
|
}
|
|
}
|
|
);
|
|
|
|
// Mount system routes
|
|
router.use('/system', systemRoutes);
|
|
|
|
/**
|
|
* Events Management Routes (placeholder)
|
|
* /api/admin/events/*
|
|
*/
|
|
router.get('/events',
|
|
authenticateAdmin,
|
|
requirePermissions([ADMIN_PERMISSIONS.EVENT_MANAGEMENT]),
|
|
validators.validatePagination,
|
|
auditAdminAction('view_events'),
|
|
(req, res) => {
|
|
res.json({
|
|
success: true,
|
|
message: 'Events endpoint - feature not yet implemented',
|
|
data: {
|
|
events: [],
|
|
pagination: {
|
|
page: 1,
|
|
limit: 20,
|
|
total: 0,
|
|
totalPages: 0
|
|
}
|
|
},
|
|
correlationId: req.correlationId
|
|
});
|
|
}
|
|
);
|
|
|
|
/**
|
|
* Analytics Routes (placeholder)
|
|
* /api/admin/analytics/*
|
|
*/
|
|
router.get('/analytics',
|
|
authenticateAdmin,
|
|
requirePermissions([ADMIN_PERMISSIONS.ANALYTICS_READ]),
|
|
auditAdminAction('view_analytics'),
|
|
(req, res) => {
|
|
res.json({
|
|
success: true,
|
|
message: 'Analytics endpoint - feature not yet implemented',
|
|
data: {
|
|
analytics: {},
|
|
timeRange: 'daily',
|
|
metrics: []
|
|
},
|
|
correlationId: req.correlationId
|
|
});
|
|
}
|
|
);
|
|
|
|
/**
|
|
* Error handling for admin routes
|
|
*/
|
|
router.use('*', (req, res) => {
|
|
res.status(404).json({
|
|
success: false,
|
|
error: 'Admin API endpoint not found',
|
|
message: `The endpoint ${req.method} ${req.originalUrl} does not exist`,
|
|
correlationId: req.correlationId,
|
|
timestamp: new Date().toISOString()
|
|
});
|
|
});
|
|
|
|
module.exports = router; |