feat: implement comprehensive startup system and fix authentication
Major improvements: - Created startup orchestration system with health monitoring and graceful shutdown - Fixed user registration and login with simplified authentication flow - Rebuilt authentication forms from scratch with direct API integration - Implemented comprehensive debugging and error handling - Added Redis fallback functionality for disabled environments - Fixed CORS configuration for cross-origin frontend requests - Simplified password validation to 6+ characters (removed complexity requirements) - Added toast notifications at app level for better UX feedback - Created comprehensive startup/shutdown scripts with OODA methodology - Fixed database validation and connection issues - Implemented TokenService memory fallback when Redis is disabled Technical details: - New SimpleLoginForm.tsx and SimpleRegisterForm.tsx components - Enhanced CORS middleware with additional allowed origins - Simplified auth validators and removed strict password requirements - Added extensive logging and diagnostic capabilities - Fixed authentication middleware token validation - Implemented graceful Redis error handling throughout the stack - Created modular startup system with configurable health checks 🤖 Generated with [Claude Code](https://claude.ai/code) Co-Authored-By: Claude <noreply@anthropic.com>
This commit is contained in:
parent
d41d1e8125
commit
e681c446b6
36 changed files with 7719 additions and 183 deletions
244
test_registration.html
Normal file
244
test_registration.html
Normal file
|
|
@ -0,0 +1,244 @@
|
|||
<!DOCTYPE html>
|
||||
<html lang="en">
|
||||
<head>
|
||||
<meta charset="UTF-8">
|
||||
<meta name="viewport" content="width=device-width, initial-scale=1.0">
|
||||
<title>Test Registration - Shattered Void MMO</title>
|
||||
<style>
|
||||
body { font-family: Arial, sans-serif; max-width: 600px; margin: 50px auto; padding: 20px; }
|
||||
.form-group { margin-bottom: 15px; }
|
||||
label { display: block; margin-bottom: 5px; font-weight: bold; }
|
||||
input { width: 100%; padding: 8px; font-size: 14px; border: 1px solid #ccc; border-radius: 4px; }
|
||||
button { background: #007bff; color: white; padding: 10px 20px; border: none; border-radius: 4px; cursor: pointer; }
|
||||
button:hover { background: #0056b3; }
|
||||
button:disabled { background: #ccc; cursor: not-allowed; }
|
||||
.result { margin-top: 20px; padding: 10px; border-radius: 4px; }
|
||||
.success { background: #d4edda; color: #155724; border: 1px solid #c3e6cb; }
|
||||
.error { background: #f8d7da; color: #721c24; border: 1px solid #f5c6cb; }
|
||||
.info { background: #d1ecf1; color: #0c5460; border: 1px solid #bee5eb; }
|
||||
pre { background: #f8f9fa; padding: 10px; border-radius: 4px; overflow-x: auto; }
|
||||
</style>
|
||||
</head>
|
||||
<body>
|
||||
<h1>🎮 Shattered Void MMO - Registration Test</h1>
|
||||
|
||||
<form id="registrationForm">
|
||||
<div class="form-group">
|
||||
<label for="email">Email:</label>
|
||||
<input type="email" id="email" required>
|
||||
</div>
|
||||
|
||||
<div class="form-group">
|
||||
<label for="username">Username:</label>
|
||||
<input type="text" id="username" required minlength="3" maxlength="20">
|
||||
</div>
|
||||
|
||||
<div class="form-group">
|
||||
<label for="password">Password:</label>
|
||||
<input type="password" id="password" required minlength="8">
|
||||
<small>Must contain uppercase, lowercase, number, and special character</small>
|
||||
</div>
|
||||
|
||||
<div class="form-group">
|
||||
<label for="confirmPassword">Confirm Password:</label>
|
||||
<input type="password" id="confirmPassword" required>
|
||||
</div>
|
||||
|
||||
<button type="submit" id="registerBtn">Register</button>
|
||||
</form>
|
||||
|
||||
<div id="result"></div>
|
||||
|
||||
<hr style="margin: 40px 0;">
|
||||
|
||||
<h2>Login Test</h2>
|
||||
<form id="loginForm">
|
||||
<div class="form-group">
|
||||
<label for="loginEmail">Email:</label>
|
||||
<input type="email" id="loginEmail" required>
|
||||
</div>
|
||||
|
||||
<div class="form-group">
|
||||
<label for="loginPassword">Password:</label>
|
||||
<input type="password" id="loginPassword" required>
|
||||
</div>
|
||||
|
||||
<button type="submit" id="loginBtn">Login</button>
|
||||
</form>
|
||||
|
||||
<div id="loginResult"></div>
|
||||
|
||||
<script>
|
||||
const API_BASE = 'http://0.0.0.0:3000/api';
|
||||
|
||||
// Registration form handler
|
||||
document.getElementById('registrationForm').addEventListener('submit', async (e) => {
|
||||
e.preventDefault();
|
||||
|
||||
const registerBtn = document.getElementById('registerBtn');
|
||||
const resultDiv = document.getElementById('result');
|
||||
|
||||
registerBtn.disabled = true;
|
||||
registerBtn.textContent = 'Registering...';
|
||||
|
||||
const email = document.getElementById('email').value;
|
||||
const username = document.getElementById('username').value;
|
||||
const password = document.getElementById('password').value;
|
||||
const confirmPassword = document.getElementById('confirmPassword').value;
|
||||
|
||||
// Basic validation
|
||||
if (password !== confirmPassword) {
|
||||
resultDiv.innerHTML = '<div class="error">Passwords do not match!</div>';
|
||||
registerBtn.disabled = false;
|
||||
registerBtn.textContent = 'Register';
|
||||
return;
|
||||
}
|
||||
|
||||
try {
|
||||
const response = await fetch(`${API_BASE}/auth/register`, {
|
||||
method: 'POST',
|
||||
headers: {
|
||||
'Content-Type': 'application/json',
|
||||
},
|
||||
body: JSON.stringify({
|
||||
email,
|
||||
username,
|
||||
password
|
||||
})
|
||||
});
|
||||
|
||||
const data = await response.json();
|
||||
|
||||
if (response.ok && data.success) {
|
||||
resultDiv.innerHTML = `
|
||||
<div class="success">
|
||||
<h3>✅ Registration Successful!</h3>
|
||||
<p><strong>User ID:</strong> ${data.data.user.id}</p>
|
||||
<p><strong>Username:</strong> ${data.data.user.username}</p>
|
||||
<p><strong>Email:</strong> ${data.data.user.email}</p>
|
||||
<p><strong>Token received:</strong> ${data.data.token ? 'Yes' : 'No'}</p>
|
||||
${data.data.token ? '<p><strong>Token:</strong> ' + data.data.token.substring(0, 50) + '...</p>' : ''}
|
||||
<details>
|
||||
<summary>Full Response</summary>
|
||||
<pre>${JSON.stringify(data, null, 2)}</pre>
|
||||
</details>
|
||||
</div>
|
||||
`;
|
||||
|
||||
// Store token for login test
|
||||
if (data.data.token) {
|
||||
localStorage.setItem('auth_token', data.data.token);
|
||||
}
|
||||
|
||||
// Auto-fill login form
|
||||
document.getElementById('loginEmail').value = email;
|
||||
document.getElementById('loginPassword').value = password;
|
||||
|
||||
} else {
|
||||
resultDiv.innerHTML = `
|
||||
<div class="error">
|
||||
<h3>❌ Registration Failed</h3>
|
||||
<p><strong>Error:</strong> ${data.message || 'Unknown error'}</p>
|
||||
<details>
|
||||
<summary>Full Response</summary>
|
||||
<pre>${JSON.stringify(data, null, 2)}</pre>
|
||||
</details>
|
||||
</div>
|
||||
`;
|
||||
}
|
||||
} catch (error) {
|
||||
resultDiv.innerHTML = `
|
||||
<div class="error">
|
||||
<h3>❌ Network Error</h3>
|
||||
<p><strong>Error:</strong> ${error.message}</p>
|
||||
<p>Make sure the server is running on ${API_BASE}</p>
|
||||
</div>
|
||||
`;
|
||||
}
|
||||
|
||||
registerBtn.disabled = false;
|
||||
registerBtn.textContent = 'Register';
|
||||
});
|
||||
|
||||
// Login form handler
|
||||
document.getElementById('loginForm').addEventListener('submit', async (e) => {
|
||||
e.preventDefault();
|
||||
|
||||
const loginBtn = document.getElementById('loginBtn');
|
||||
const resultDiv = document.getElementById('loginResult');
|
||||
|
||||
loginBtn.disabled = true;
|
||||
loginBtn.textContent = 'Logging in...';
|
||||
|
||||
const email = document.getElementById('loginEmail').value;
|
||||
const password = document.getElementById('loginPassword').value;
|
||||
|
||||
try {
|
||||
const response = await fetch(`${API_BASE}/auth/login`, {
|
||||
method: 'POST',
|
||||
headers: {
|
||||
'Content-Type': 'application/json',
|
||||
},
|
||||
body: JSON.stringify({
|
||||
email,
|
||||
password
|
||||
})
|
||||
});
|
||||
|
||||
const data = await response.json();
|
||||
|
||||
if (response.ok && data.success) {
|
||||
resultDiv.innerHTML = `
|
||||
<div class="success">
|
||||
<h3>✅ Login Successful!</h3>
|
||||
<p><strong>User ID:</strong> ${data.data.user.id}</p>
|
||||
<p><strong>Username:</strong> ${data.data.user.username}</p>
|
||||
<p><strong>Email:</strong> ${data.data.user.email}</p>
|
||||
<p><strong>Token received:</strong> ${data.data.token ? 'Yes' : 'No'}</p>
|
||||
${data.data.token ? '<p><strong>Token:</strong> ' + data.data.token.substring(0, 50) + '...</p>' : ''}
|
||||
<details>
|
||||
<summary>Full Response</summary>
|
||||
<pre>${JSON.stringify(data, null, 2)}</pre>
|
||||
</details>
|
||||
</div>
|
||||
`;
|
||||
|
||||
// Store token
|
||||
if (data.data.token) {
|
||||
localStorage.setItem('auth_token', data.data.token);
|
||||
}
|
||||
|
||||
} else {
|
||||
resultDiv.innerHTML = `
|
||||
<div class="error">
|
||||
<h3>❌ Login Failed</h3>
|
||||
<p><strong>Error:</strong> ${data.message || 'Unknown error'}</p>
|
||||
<details>
|
||||
<summary>Full Response</summary>
|
||||
<pre>${JSON.stringify(data, null, 2)}</pre>
|
||||
</details>
|
||||
</div>
|
||||
`;
|
||||
}
|
||||
} catch (error) {
|
||||
resultDiv.innerHTML = `
|
||||
<div class="error">
|
||||
<h3>❌ Network Error</h3>
|
||||
<p><strong>Error:</strong> ${error.message}</p>
|
||||
<p>Make sure the server is running on ${API_BASE}</p>
|
||||
</div>
|
||||
`;
|
||||
}
|
||||
|
||||
loginBtn.disabled = false;
|
||||
loginBtn.textContent = 'Login';
|
||||
});
|
||||
|
||||
// Auto-fill test data
|
||||
document.getElementById('email').value = 'test' + Date.now() + '@example.com';
|
||||
document.getElementById('username').value = 'testuser' + Date.now().toString().slice(-4);
|
||||
document.getElementById('password').value = 'TestPass1@';
|
||||
document.getElementById('confirmPassword').value = 'TestPass1@';
|
||||
</script>
|
||||
</body>
|
||||
</html>
|
||||
Loading…
Add table
Add a link
Reference in a new issue