Shatteredvoid/src/routes/api.js
MegaProxy d41d1e8125 feat: implement complete Phase 2 frontend foundation with React 18
Major milestone: Frontend implementation complete for Shattered Void MMO

FRONTEND IMPLEMENTATION:
- React 18 + TypeScript + Vite development environment
- Tailwind CSS with custom dark theme for sci-fi aesthetic
- Zustand state management with authentication persistence
- Socket.io WebSocket client with auto-reconnection
- Protected routing with authentication guards
- Responsive design with mobile-first approach

AUTHENTICATION SYSTEM:
- Login/register forms with comprehensive validation
- JWT token management with localStorage persistence
- Password strength validation and user feedback
- Protected routes and authentication guards

CORE GAME INTERFACE:
- Colony management dashboard with real-time updates
- Resource display with live production tracking
- WebSocket integration for real-time game events
- Navigation with connection status indicator
- Toast notifications for user feedback

BACKEND ENHANCEMENTS:
- Complete Research System with technology tree (23 technologies)
- Fleet Management System with ship designs and movement
- Enhanced Authentication with email verification and password reset
- Complete game tick integration for all systems
- Advanced WebSocket events for real-time updates

ARCHITECTURE FEATURES:
- Type-safe TypeScript throughout
- Component-based architecture with reusable UI elements
- API client with request/response interceptors
- Error handling and loading states
- Performance optimized builds with code splitting

Phase 2 Status: Frontend foundation complete (Week 1-2 objectives met)
Ready for: Colony management, fleet operations, research interface
Next: Enhanced gameplay features and admin interface

🤖 Generated with [Claude Code](https://claude.ai/code)

Co-Authored-By: Claude <noreply@anthropic.com>
2025-08-02 18:36:06 +00:00

278 lines
No EOL
8.8 KiB
JavaScript

/**
* Player API Routes
* Defines all player-facing API endpoints with proper middleware and validation
*/
const express = require('express');
const router = express.Router();
// Import middleware
const { authenticatePlayer, optionalPlayerAuth, requireOwnership, injectPlayerId } = require('../middleware/auth.middleware');
const { authenticateToken } = require('../middleware/auth'); // Standardized auth
const { rateLimiters } = require('../middleware/rateLimit.middleware');
const { validators, validateRequest } = require('../middleware/validation.middleware');
const {
accountLockoutProtection,
rateLimiter,
passwordStrengthValidator,
requireEmailVerification,
sanitizeInput
} = require('../middleware/security.middleware');
const {
validateRequest: validateAuthRequest,
validateRegistrationUniqueness,
registerPlayerSchema,
loginPlayerSchema,
verifyEmailSchema,
resendVerificationSchema,
requestPasswordResetSchema,
resetPasswordSchema,
changePasswordSchema
} = require('../validators/auth.validators');
const corsMiddleware = require('../middleware/cors.middleware');
// Use standardized authentication for players
const authenticatePlayerToken = authenticateToken('player');
const optionalPlayerToken = require('../middleware/auth').optionalAuth('player');
// Import controllers
const authController = require('../controllers/api/auth.controller');
const playerController = require('../controllers/api/player.controller');
// Apply CORS to all API routes
router.use(corsMiddleware);
// Apply general API rate limiting
router.use(rateLimiters.player);
/**
* API Status and Information
*/
router.get('/', (req, res) => {
res.json({
name: 'Shattered Void - Player API',
version: process.env.npm_package_version || '0.1.0',
status: 'operational',
timestamp: new Date().toISOString(),
correlationId: req.correlationId,
endpoints: {
authentication: '/api/auth',
player: '/api/player',
game: {
colonies: '/api/colonies',
fleets: '/api/fleets',
research: '/api/research',
galaxy: '/api/galaxy',
combat: '/api/combat'
}
}
});
});
/**
* Authentication Routes
* /api/auth/*
*/
const authRoutes = express.Router();
// Public authentication endpoints (with stricter rate limiting)
authRoutes.post('/register',
rateLimiter({ maxRequests: 3, windowMinutes: 60, action: 'registration' }),
sanitizeInput(['email', 'username']),
validateAuthRequest(registerPlayerSchema),
validateRegistrationUniqueness(),
passwordStrengthValidator('password'),
authController.register
);
authRoutes.post('/login',
rateLimiter({ maxRequests: 5, windowMinutes: 15, action: 'login' }),
accountLockoutProtection,
sanitizeInput(['email']),
validateAuthRequest(loginPlayerSchema),
authController.login
);
// Protected authentication endpoints
authRoutes.post('/logout',
authenticatePlayerToken,
authController.logout
);
authRoutes.post('/refresh',
rateLimiters.auth,
authController.refresh
);
authRoutes.get('/me',
authenticatePlayerToken,
authController.getProfile
);
authRoutes.put('/me',
authenticatePlayerToken,
requireEmailVerification,
rateLimiter({ maxRequests: 5, windowMinutes: 60, action: 'profile_update' }),
sanitizeInput(['username', 'displayName', 'bio']),
validateRequest(require('joi').object({
username: require('joi').string().alphanum().min(3).max(20).optional(),
displayName: require('joi').string().min(1).max(50).optional(),
bio: require('joi').string().max(500).optional()
}), 'body'),
authController.updateProfile
);
authRoutes.get('/verify',
authenticatePlayerToken,
authController.verifyToken
);
authRoutes.post('/change-password',
authenticatePlayerToken,
rateLimiter({ maxRequests: 3, windowMinutes: 60, action: 'password_change' }),
validateAuthRequest(changePasswordSchema),
passwordStrengthValidator('newPassword'),
authController.changePassword
);
// Email verification endpoints
authRoutes.post('/verify-email',
rateLimiter({ maxRequests: 5, windowMinutes: 15, action: 'email_verification' }),
validateAuthRequest(verifyEmailSchema),
authController.verifyEmail
);
authRoutes.post('/resend-verification',
rateLimiter({ maxRequests: 3, windowMinutes: 60, action: 'resend_verification' }),
sanitizeInput(['email']),
validateAuthRequest(resendVerificationSchema),
authController.resendVerification
);
// Password reset endpoints
authRoutes.post('/request-password-reset',
rateLimiter({ maxRequests: 3, windowMinutes: 60, action: 'password_reset_request' }),
sanitizeInput(['email']),
validateAuthRequest(requestPasswordResetSchema),
authController.requestPasswordReset
);
authRoutes.post('/reset-password',
rateLimiter({ maxRequests: 3, windowMinutes: 60, action: 'password_reset' }),
validateAuthRequest(resetPasswordSchema),
passwordStrengthValidator('newPassword'),
authController.resetPassword
);
// Security utility endpoints
authRoutes.post('/check-password-strength',
rateLimiter({ maxRequests: 10, windowMinutes: 5, action: 'password_check' }),
authController.checkPasswordStrength
);
authRoutes.get('/security-status',
authenticatePlayerToken,
authController.getSecurityStatus
);
// Mount authentication routes
router.use('/auth', authRoutes);
/**
* Player Management Routes
* /api/player/*
*/
const playerManagementRoutes = express.Router();
// All player routes require authentication
playerManagementRoutes.use(authenticatePlayerToken);
playerManagementRoutes.get('/dashboard', playerController.getDashboard);
playerManagementRoutes.get('/resources', playerController.getResources);
playerManagementRoutes.get('/stats', playerController.getStats);
playerManagementRoutes.put('/settings',
validateRequest(require('joi').object({
// TODO: Define settings schema
notifications: require('joi').object({
email: require('joi').boolean().optional(),
push: require('joi').boolean().optional(),
battles: require('joi').boolean().optional(),
colonies: require('joi').boolean().optional()
}).optional(),
ui: require('joi').object({
theme: require('joi').string().valid('light', 'dark').optional(),
language: require('joi').string().valid('en', 'es', 'fr', 'de').optional()
}).optional()
}), 'body'),
playerController.updateSettings
);
playerManagementRoutes.get('/activity',
validators.validatePagination,
playerController.getActivity
);
playerManagementRoutes.get('/notifications',
validateRequest(require('joi').object({
unreadOnly: require('joi').boolean().default(false)
}), 'query'),
playerController.getNotifications
);
playerManagementRoutes.put('/notifications/read',
validateRequest(require('joi').object({
notificationIds: require('joi').array().items(
require('joi').number().integer().positive()
).min(1).required()
}), 'body'),
playerController.markNotificationsRead
);
// Mount player management routes (separate from game feature routes)
router.use('/player', playerManagementRoutes);
/**
* Combat Routes
* /api/combat/*
*/
router.use('/combat', require('./api/combat'));
/**
* Game Feature Routes
* Connect to existing working player route modules
*/
// Import existing player route modules for game features
const playerGameRoutes = require('./player');
// Mount player game routes under /player-game prefix to avoid conflicts
// These contain the actual game functionality (colonies, resources, fleets, etc.)
router.use('/player-game', playerGameRoutes);
// Direct mount of specific game features for convenience (these are duplicates of what's in /player/*)
// These provide direct access without the /player prefix for backwards compatibility
router.use('/colonies', authenticatePlayerToken, require('./player/colonies'));
router.use('/resources', authenticatePlayerToken, require('./player/resources'));
router.use('/fleets', authenticatePlayerToken, require('./player/fleets'));
router.use('/research', authenticatePlayerToken, require('./player/research'));
router.use('/galaxy', optionalPlayerToken, require('./player/galaxy'));
router.use('/notifications', authenticatePlayerToken, require('./player/notifications'));
router.use('/events', authenticatePlayerToken, require('./player/events'));
/**
* Error handling for API routes
*/
router.use('*', (req, res) => {
res.status(404).json({
success: false,
error: 'API endpoint not found',
message: `The endpoint ${req.method} ${req.originalUrl} does not exist`,
correlationId: req.correlationId,
timestamp: new Date().toISOString()
});
});
module.exports = router;