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>
This commit is contained in:
MegaProxy 2025-08-02 18:36:06 +00:00
parent 8d9ef427be
commit d41d1e8125
130 changed files with 33588 additions and 14817 deletions

View file

@ -8,10 +8,33 @@ 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');
@ -54,20 +77,25 @@ const authRoutes = express.Router();
// Public authentication endpoints (with stricter rate limiting)
authRoutes.post('/register',
rateLimiters.auth,
validators.validatePlayerRegistration,
rateLimiter({ maxRequests: 3, windowMinutes: 60, action: 'registration' }),
sanitizeInput(['email', 'username']),
validateAuthRequest(registerPlayerSchema),
validateRegistrationUniqueness(),
passwordStrengthValidator('password'),
authController.register
);
authRoutes.post('/login',
rateLimiters.auth,
validators.validatePlayerLogin,
rateLimiter({ maxRequests: 5, windowMinutes: 15, action: 'login' }),
accountLockoutProtection,
sanitizeInput(['email']),
validateAuthRequest(loginPlayerSchema),
authController.login
);
// Protected authentication endpoints
authRoutes.post('/logout',
authenticatePlayer,
authenticatePlayerToken,
authController.logout
);
@ -77,33 +105,76 @@ authRoutes.post('/refresh',
);
authRoutes.get('/me',
authenticatePlayer,
authenticatePlayerToken,
authController.getProfile
);
authRoutes.put('/me',
authenticatePlayer,
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()
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',
authenticatePlayer,
authenticatePlayerToken,
authController.verifyToken
);
authRoutes.post('/change-password',
authenticatePlayer,
rateLimiters.auth,
validateRequest(require('joi').object({
currentPassword: require('joi').string().required(),
newPassword: require('joi').string().min(8).max(128).required()
}), 'body'),
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);
@ -111,18 +182,18 @@ router.use('/auth', authRoutes);
* Player Management Routes
* /api/player/*
*/
const playerRoutes = express.Router();
const playerManagementRoutes = express.Router();
// All player routes require authentication
playerRoutes.use(authenticatePlayer);
playerManagementRoutes.use(authenticatePlayerToken);
playerRoutes.get('/dashboard', playerController.getDashboard);
playerManagementRoutes.get('/dashboard', playerController.getDashboard);
playerRoutes.get('/resources', playerController.getResources);
playerManagementRoutes.get('/resources', playerController.getResources);
playerRoutes.get('/stats', playerController.getStats);
playerManagementRoutes.get('/stats', playerController.getStats);
playerRoutes.put('/settings',
playerManagementRoutes.put('/settings',
validateRequest(require('joi').object({
// TODO: Define settings schema
notifications: require('joi').object({
@ -139,19 +210,19 @@ playerRoutes.put('/settings',
playerController.updateSettings
);
playerRoutes.get('/activity',
playerManagementRoutes.get('/activity',
validators.validatePagination,
playerController.getActivity
);
playerRoutes.get('/notifications',
playerManagementRoutes.get('/notifications',
validateRequest(require('joi').object({
unreadOnly: require('joi').boolean().default(false)
}), 'query'),
playerController.getNotifications
);
playerRoutes.put('/notifications/read',
playerManagementRoutes.put('/notifications/read',
validateRequest(require('joi').object({
notificationIds: require('joi').array().items(
require('joi').number().integer().positive()
@ -160,8 +231,8 @@ playerRoutes.put('/notifications/read',
playerController.markNotificationsRead
);
// Mount player routes
router.use('/player', playerRoutes);
// Mount player management routes (separate from game feature routes)
router.use('/player', playerManagementRoutes);
/**
* Combat Routes
@ -171,169 +242,25 @@ router.use('/combat', require('./api/combat'));
/**
* Game Feature Routes
* These will be expanded with actual game functionality
* Connect to existing working player route modules
*/
// Colonies Routes (placeholder)
router.get('/colonies',
authenticatePlayer,
validators.validatePagination,
(req, res) => {
res.json({
success: true,
message: 'Colonies endpoint - feature not yet implemented',
data: {
colonies: [],
pagination: {
page: 1,
limit: 20,
total: 0,
totalPages: 0
}
},
correlationId: req.correlationId
});
}
);
// Import existing player route modules for game features
const playerGameRoutes = require('./player');
router.post('/colonies',
authenticatePlayer,
rateLimiters.gameAction,
validators.validateColonyCreation,
(req, res) => {
res.status(501).json({
success: false,
message: 'Colony creation feature not yet implemented',
correlationId: req.correlationId
});
}
);
// 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);
// Fleets Routes (placeholder)
router.get('/fleets',
authenticatePlayer,
validators.validatePagination,
(req, res) => {
res.json({
success: true,
message: 'Fleets endpoint - feature not yet implemented',
data: {
fleets: [],
pagination: {
page: 1,
limit: 20,
total: 0,
totalPages: 0
}
},
correlationId: req.correlationId
});
}
);
router.post('/fleets',
authenticatePlayer,
rateLimiters.gameAction,
validators.validateFleetCreation,
(req, res) => {
res.status(501).json({
success: false,
message: 'Fleet creation feature not yet implemented',
correlationId: req.correlationId
});
}
);
// Research Routes (placeholder)
router.get('/research',
authenticatePlayer,
(req, res) => {
res.json({
success: true,
message: 'Research endpoint - feature not yet implemented',
data: {
currentResearch: null,
availableResearch: [],
completedResearch: []
},
correlationId: req.correlationId
});
}
);
router.post('/research',
authenticatePlayer,
rateLimiters.gameAction,
validators.validateResearchInitiation,
(req, res) => {
res.status(501).json({
success: false,
message: 'Research initiation feature not yet implemented',
correlationId: req.correlationId
});
}
);
// Galaxy Routes (placeholder)
router.get('/galaxy',
authenticatePlayer,
validateRequest(require('joi').object({
sector: require('joi').string().pattern(/^[A-Z]\d+$/).optional(),
coordinates: require('joi').string().pattern(/^[A-Z]\d+-\d+-[A-Z]$/).optional()
}), 'query'),
(req, res) => {
const { sector, coordinates } = req.query;
res.json({
success: true,
message: 'Galaxy endpoint - feature not yet implemented',
data: {
sector: sector || null,
coordinates: coordinates || null,
systems: [],
playerColonies: [],
playerFleets: []
},
correlationId: req.correlationId
});
}
);
// Messages Routes (placeholder)
router.get('/messages',
authenticatePlayer,
validators.validatePagination,
(req, res) => {
res.json({
success: true,
message: 'Messages endpoint - feature not yet implemented',
data: {
messages: [],
unreadCount: 0,
pagination: {
page: 1,
limit: 20,
total: 0,
totalPages: 0
}
},
correlationId: req.correlationId
});
}
);
router.post('/messages',
authenticatePlayer,
rateLimiters.messaging,
validators.validateMessageSend,
(req, res) => {
res.status(501).json({
success: false,
message: 'Message sending feature not yet implemented',
correlationId: req.correlationId
});
}
);
// 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