changed the navbar to work.
All checks were successful
Build Frontend / Build Frontend (push) Successful in 35s
All checks were successful
Build Frontend / Build Frontend (push) Successful in 35s
This commit is contained in:
225
DEPLOY_NAVBAR_FIX.md
Normal file
225
DEPLOY_NAVBAR_FIX.md
Normal file
@@ -0,0 +1,225 @@
|
|||||||
|
# Deploy Navbar Login Fix - Quick Checklist
|
||||||
|
|
||||||
|
## 🎯 What This Fixes
|
||||||
|
|
||||||
|
**Problem:** After logging in via Steam, the navbar doesn't update to show the logged-in state (avatar, username, balance).
|
||||||
|
|
||||||
|
**Solution:** WebSocket now triggers auth state refresh when connection is established.
|
||||||
|
|
||||||
|
---
|
||||||
|
|
||||||
|
## ✅ Pre-Deployment Checklist
|
||||||
|
|
||||||
|
- [x] Source code changes committed
|
||||||
|
- [x] Frontend build successful
|
||||||
|
- [x] Verification script passed
|
||||||
|
- [ ] Backend is running
|
||||||
|
- [ ] Ready to deploy
|
||||||
|
|
||||||
|
---
|
||||||
|
|
||||||
|
## 🚀 Quick Deploy (Production)
|
||||||
|
|
||||||
|
### On Your Server
|
||||||
|
|
||||||
|
```bash
|
||||||
|
# 1. Navigate to project
|
||||||
|
cd /path/to/TurboTrades
|
||||||
|
|
||||||
|
# 2. Pull latest changes
|
||||||
|
git pull origin main
|
||||||
|
|
||||||
|
# 3. Build frontend
|
||||||
|
cd frontend
|
||||||
|
npm install # only if package.json changed
|
||||||
|
npm run build
|
||||||
|
|
||||||
|
# 4. Deploy to web root
|
||||||
|
sudo cp -r dist/* /var/www/html/turbotrades/
|
||||||
|
|
||||||
|
# 5. Verify deployment
|
||||||
|
curl -I https://turbotrades.dev # Should return 200
|
||||||
|
|
||||||
|
# Done! 🎉
|
||||||
|
```
|
||||||
|
|
||||||
|
---
|
||||||
|
|
||||||
|
## 🧪 Testing After Deployment
|
||||||
|
|
||||||
|
### 1. Clear Browser Cache
|
||||||
|
|
||||||
|
- **Chrome/Edge:** `Ctrl + Shift + R` (Windows/Linux) or `Cmd + Shift + R` (Mac)
|
||||||
|
- **Firefox:** `Ctrl + Shift + R` (Windows/Linux) or `Cmd + Shift + R` (Mac)
|
||||||
|
- **Or use Incognito/Private mode**
|
||||||
|
|
||||||
|
### 2. Open Browser Console
|
||||||
|
|
||||||
|
Press `F12` → **Console** tab
|
||||||
|
|
||||||
|
### 3. Clear All Site Data
|
||||||
|
|
||||||
|
In DevTools:
|
||||||
|
- **Application** tab → **Clear storage** → **Clear site data**
|
||||||
|
|
||||||
|
### 4. Test Login Flow
|
||||||
|
|
||||||
|
1. Click "Login to Steam" button
|
||||||
|
2. Complete Steam authentication
|
||||||
|
3. Watch console for these logs:
|
||||||
|
|
||||||
|
```
|
||||||
|
🔵 Auth store initialize called - isInitialized: false
|
||||||
|
🔵 fetchUser called - fetching user from /api/auth/me
|
||||||
|
✅ fetchUser response: { success: true, user: {...} }
|
||||||
|
✅ Setting user in auth store: { steamId: "...", ... }
|
||||||
|
🔵 fetchUser complete - isAuthenticated: true
|
||||||
|
|
||||||
|
Connecting to WebSocket: wss://api.turbotrades.dev/ws
|
||||||
|
WebSocket connected
|
||||||
|
🟢 WebSocket received 'connected' message: { ... }
|
||||||
|
🔵 Calling authStore.fetchUser() from WebSocket connected handler
|
||||||
|
🔵 fetchUser called - fetching user from /api/auth/me
|
||||||
|
✅ fetchUser response: { success: true, user: {...} }
|
||||||
|
```
|
||||||
|
|
||||||
|
### 5. Verify Navbar
|
||||||
|
|
||||||
|
Should now show:
|
||||||
|
- ✅ Your Steam avatar
|
||||||
|
- ✅ Your username
|
||||||
|
- ✅ Your balance with deposit button
|
||||||
|
- ✅ User dropdown menu (Profile, Inventory, etc.)
|
||||||
|
|
||||||
|
---
|
||||||
|
|
||||||
|
## 🔧 If It Doesn't Work
|
||||||
|
|
||||||
|
### Common Issues
|
||||||
|
|
||||||
|
#### Navbar Still Not Updating
|
||||||
|
|
||||||
|
```bash
|
||||||
|
# 1. Hard refresh browser (clear all cache)
|
||||||
|
Ctrl + Shift + Delete → Clear all browsing data
|
||||||
|
|
||||||
|
# 2. Check if build was actually deployed
|
||||||
|
curl -I https://turbotrades.dev/assets/index-*.js
|
||||||
|
|
||||||
|
# 3. Check console for errors
|
||||||
|
# Look for CORS errors, 404s, or auth failures
|
||||||
|
```
|
||||||
|
|
||||||
|
#### WebSocket Not Connecting
|
||||||
|
|
||||||
|
```bash
|
||||||
|
# Check Nginx config has WebSocket proxy
|
||||||
|
sudo cat /etc/nginx/sites-available/turbotrades-api
|
||||||
|
|
||||||
|
# Should have:
|
||||||
|
location /ws {
|
||||||
|
proxy_set_header Upgrade $http_upgrade;
|
||||||
|
proxy_set_header Connection "upgrade";
|
||||||
|
proxy_pass http://127.0.0.1:3000/ws;
|
||||||
|
}
|
||||||
|
|
||||||
|
# Reload Nginx if changed
|
||||||
|
sudo nginx -t
|
||||||
|
sudo systemctl reload nginx
|
||||||
|
```
|
||||||
|
|
||||||
|
#### Backend Issues
|
||||||
|
|
||||||
|
```bash
|
||||||
|
# Check backend is running
|
||||||
|
pm2 status
|
||||||
|
|
||||||
|
# Check logs
|
||||||
|
pm2 logs turbotrades-backend --lines 50
|
||||||
|
|
||||||
|
# Restart if needed
|
||||||
|
pm2 restart turbotrades-backend
|
||||||
|
```
|
||||||
|
|
||||||
|
---
|
||||||
|
|
||||||
|
## 📊 Verification Script
|
||||||
|
|
||||||
|
Run this to check everything is ready:
|
||||||
|
|
||||||
|
```bash
|
||||||
|
node scripts/verify-login-fix.cjs
|
||||||
|
```
|
||||||
|
|
||||||
|
**Expected output:**
|
||||||
|
```
|
||||||
|
✅ WebSocket store has the navbar login fix
|
||||||
|
✅ Frontend build exists and looks valid
|
||||||
|
✅ API Health Endpoint: Reachable
|
||||||
|
✅ WebSocket: Connection successful
|
||||||
|
All checks passed! ✨
|
||||||
|
```
|
||||||
|
|
||||||
|
---
|
||||||
|
|
||||||
|
## 🔄 Rollback (If Needed)
|
||||||
|
|
||||||
|
```bash
|
||||||
|
# Revert commits
|
||||||
|
git revert HEAD~2..HEAD
|
||||||
|
git push origin main
|
||||||
|
|
||||||
|
# Rebuild and redeploy
|
||||||
|
cd frontend
|
||||||
|
npm run build
|
||||||
|
sudo cp -r dist/* /var/www/html/turbotrades/
|
||||||
|
```
|
||||||
|
|
||||||
|
---
|
||||||
|
|
||||||
|
## 📝 Files Changed
|
||||||
|
|
||||||
|
- `frontend/src/stores/websocket.js` - Added `authStore.fetchUser()` call on WebSocket connected
|
||||||
|
- `frontend/src/stores/auth.js` - Added debug logging for troubleshooting
|
||||||
|
|
||||||
|
---
|
||||||
|
|
||||||
|
## 🎓 How It Works
|
||||||
|
|
||||||
|
1. **User logs in** → Steam OAuth → Backend sets session cookie
|
||||||
|
2. **Frontend loads** → `App.vue` calls `authStore.initialize()`
|
||||||
|
3. **WebSocket connects** → Server sends `{ type: "connected", data: {...} }`
|
||||||
|
4. **NEW:** WebSocket handler calls `authStore.fetchUser()`
|
||||||
|
5. **Auth store updates** → `isAuthenticated = true`
|
||||||
|
6. **Navbar reactively updates** → Shows logged-in UI
|
||||||
|
|
||||||
|
---
|
||||||
|
|
||||||
|
## ✨ Success Criteria
|
||||||
|
|
||||||
|
- [x] Source code has the fix
|
||||||
|
- [x] Frontend build is recent
|
||||||
|
- [x] API endpoints reachable
|
||||||
|
- [x] WebSocket connection works
|
||||||
|
- [ ] **User can login and see navbar update**
|
||||||
|
|
||||||
|
---
|
||||||
|
|
||||||
|
**Status:** Ready to Deploy
|
||||||
|
**Build Date:** 2025-01-10
|
||||||
|
**Estimated Deploy Time:** 5 minutes
|
||||||
|
**Risk Level:** Low (only frontend changes)
|
||||||
|
|
||||||
|
---
|
||||||
|
|
||||||
|
## 🆘 Need Help?
|
||||||
|
|
||||||
|
Check these docs:
|
||||||
|
- Full details: `NAVBAR_LOGIN_FIX.md`
|
||||||
|
- Troubleshooting: `DEPLOYMENT_FIXES.md`
|
||||||
|
- Environment setup: `ENV_SETUP.md`
|
||||||
|
|
||||||
|
Or check the logs:
|
||||||
|
```bash
|
||||||
|
pm2 logs turbotrades-backend
|
||||||
|
```
|
||||||
337
NAVBAR_LOGIN_FIX.md
Normal file
337
NAVBAR_LOGIN_FIX.md
Normal file
@@ -0,0 +1,337 @@
|
|||||||
|
# Navbar Login Fix - WebSocket Authentication State Update
|
||||||
|
|
||||||
|
## Problem Description
|
||||||
|
|
||||||
|
After successfully logging in via Steam, the WebSocket would connect and receive user data from the server, but the navbar would not update to show the logged-in state.
|
||||||
|
|
||||||
|
### Root Cause
|
||||||
|
|
||||||
|
The WebSocket `connected` message handler was receiving user data (steamId, username, userId) but was only logging it to the console. It was **not updating the auth store**, which the navbar component relies on to display authentication state.
|
||||||
|
|
||||||
|
**Console logs showed:**
|
||||||
|
```
|
||||||
|
🔵 AnnouncementBanner mounted - loading announcements...
|
||||||
|
WebSocket connected
|
||||||
|
WebSocket message received: { type: "connected", data: {...} }
|
||||||
|
Server confirmed connection: { steamId: "...", username: "...", userId: "..." }
|
||||||
|
```
|
||||||
|
|
||||||
|
But the navbar remained in logged-out state because `authStore.isAuthenticated` was still `false`.
|
||||||
|
|
||||||
|
---
|
||||||
|
|
||||||
|
## Solution
|
||||||
|
|
||||||
|
### Changes Made
|
||||||
|
|
||||||
|
#### 1. WebSocket Store (`frontend/src/stores/websocket.js`)
|
||||||
|
- **Modified the `"connected"` message handler** to call `authStore.fetchUser()` when the WebSocket connection is confirmed
|
||||||
|
- **Fixed duplicate `authStore` declarations** by declaring it once at the top of `handleMessage` function
|
||||||
|
- **Added debug logging** to trace the authentication flow
|
||||||
|
|
||||||
|
**Before:**
|
||||||
|
```javascript
|
||||||
|
case "connected":
|
||||||
|
console.log("Server confirmed connection:", payload);
|
||||||
|
break;
|
||||||
|
```
|
||||||
|
|
||||||
|
**After:**
|
||||||
|
```javascript
|
||||||
|
const handleMessage = (data) => {
|
||||||
|
const { type, data: payload, timestamp } = data;
|
||||||
|
const authStore = useAuthStore(); // Declared once at top
|
||||||
|
|
||||||
|
switch (type) {
|
||||||
|
case "connected":
|
||||||
|
console.log("🟢 WebSocket received 'connected' message:", payload);
|
||||||
|
// Fetch updated user data from the auth endpoint
|
||||||
|
console.log("🔵 Calling authStore.fetchUser() from WebSocket connected handler");
|
||||||
|
authStore.fetchUser();
|
||||||
|
break;
|
||||||
|
|
||||||
|
case "balance_update":
|
||||||
|
// Now uses authStore declared at top
|
||||||
|
if (payload?.balance !== undefined) {
|
||||||
|
authStore.updateBalance(payload.balance);
|
||||||
|
}
|
||||||
|
break;
|
||||||
|
// ... rest of cases
|
||||||
|
}
|
||||||
|
};
|
||||||
|
```
|
||||||
|
|
||||||
|
#### 2. Auth Store (`frontend/src/stores/auth.js`)
|
||||||
|
- **Added debug logging** to trace authentication initialization and user fetch operations
|
||||||
|
|
||||||
|
**Added logs:**
|
||||||
|
```javascript
|
||||||
|
console.log("🔵 fetchUser called - fetching user from /api/auth/me");
|
||||||
|
console.log("✅ fetchUser response:", response.data);
|
||||||
|
console.log("✅ Setting user in auth store:", response.data.user);
|
||||||
|
console.log("🔵 fetchUser complete - isAuthenticated:", isAuthenticated.value);
|
||||||
|
console.log("🔵 Auth store initialize called - isInitialized:", isInitialized.value);
|
||||||
|
```
|
||||||
|
|
||||||
|
---
|
||||||
|
|
||||||
|
## How It Works Now
|
||||||
|
|
||||||
|
### Authentication Flow After Steam Login
|
||||||
|
|
||||||
|
1. **User clicks "Login to Steam"** button
|
||||||
|
- Frontend redirects to: `${VITE_API_URL}/api/auth/steam`
|
||||||
|
|
||||||
|
2. **Steam OAuth flow completes**
|
||||||
|
- Backend receives callback from Steam
|
||||||
|
- Backend creates session and sets HTTP-only cookie
|
||||||
|
- Backend redirects user back to frontend
|
||||||
|
|
||||||
|
3. **Frontend loads** (`App.vue` `onMounted`)
|
||||||
|
- `authStore.initialize()` → calls `fetchUser()` → requests `/api/auth/me`
|
||||||
|
- `wsStore.connect()` → establishes WebSocket connection
|
||||||
|
|
||||||
|
4. **WebSocket connects successfully**
|
||||||
|
- Backend sends `{ type: "connected", data: { steamId, username, userId } }`
|
||||||
|
|
||||||
|
5. **WebSocket receives "connected" message** ✨ **NEW**
|
||||||
|
- Handler calls `authStore.fetchUser()`
|
||||||
|
- Fetches user data from `/api/auth/me` with credentials
|
||||||
|
- Updates `authStore.user` and sets `isAuthenticated = true`
|
||||||
|
|
||||||
|
6. **Navbar reactively updates** 🎉
|
||||||
|
- `authStore.isAuthenticated` changes from `false` → `true`
|
||||||
|
- Vue's reactivity triggers navbar to show user menu, avatar, balance, etc.
|
||||||
|
|
||||||
|
---
|
||||||
|
|
||||||
|
## Deployment Instructions
|
||||||
|
|
||||||
|
### 1. Build the Frontend
|
||||||
|
|
||||||
|
```bash
|
||||||
|
cd frontend
|
||||||
|
npm run build
|
||||||
|
```
|
||||||
|
|
||||||
|
**Expected output:**
|
||||||
|
```
|
||||||
|
✓ 1588 modules transformed.
|
||||||
|
✓ built in 2.80s
|
||||||
|
```
|
||||||
|
|
||||||
|
### 2. Deploy to Production
|
||||||
|
|
||||||
|
**Option A: Manual deployment on server**
|
||||||
|
```bash
|
||||||
|
# SSH into your server
|
||||||
|
ssh user@your-server
|
||||||
|
|
||||||
|
# Navigate to project
|
||||||
|
cd /path/to/TurboTrades/frontend
|
||||||
|
|
||||||
|
# Pull latest changes
|
||||||
|
git pull origin main
|
||||||
|
|
||||||
|
# Build
|
||||||
|
npm install # if dependencies changed
|
||||||
|
npm run build
|
||||||
|
|
||||||
|
# Copy to web root
|
||||||
|
sudo cp -r dist/* /var/www/html/turbotrades/
|
||||||
|
```
|
||||||
|
|
||||||
|
**Option B: CI/CD Pipeline**
|
||||||
|
```bash
|
||||||
|
# Commit and push changes
|
||||||
|
git add frontend/src/stores/websocket.js frontend/src/stores/auth.js
|
||||||
|
git commit -m "Fix navbar not updating after Steam login - WebSocket auth state sync"
|
||||||
|
git push origin main
|
||||||
|
|
||||||
|
# Your CI/CD pipeline will automatically:
|
||||||
|
# 1. Pull changes
|
||||||
|
# 2. Build frontend
|
||||||
|
# 3. Deploy to production
|
||||||
|
```
|
||||||
|
|
||||||
|
### 3. Clear Browser Cache
|
||||||
|
|
||||||
|
After deployment, users need to hard-refresh to get the new JavaScript bundle:
|
||||||
|
|
||||||
|
- **Windows/Linux:** `Ctrl + Shift + R` or `Ctrl + F5`
|
||||||
|
- **Mac:** `Cmd + Shift + R`
|
||||||
|
- **Or use Incognito/Private mode** for testing
|
||||||
|
|
||||||
|
---
|
||||||
|
|
||||||
|
## Testing the Fix
|
||||||
|
|
||||||
|
### 1. Open Browser Console
|
||||||
|
|
||||||
|
Press `F12` to open DevTools and go to Console tab.
|
||||||
|
|
||||||
|
### 2. Clear Cookies and Storage
|
||||||
|
|
||||||
|
In DevTools:
|
||||||
|
- Go to **Application** tab
|
||||||
|
- Click **Clear storage** → **Clear site data**
|
||||||
|
|
||||||
|
### 3. Attempt Login
|
||||||
|
|
||||||
|
Click "Login to Steam" button and complete authentication.
|
||||||
|
|
||||||
|
### 4. Watch Console Logs
|
||||||
|
|
||||||
|
You should see this sequence:
|
||||||
|
|
||||||
|
```
|
||||||
|
🔵 Auth store initialize called - isInitialized: false
|
||||||
|
🔵 fetchUser called - fetching user from /api/auth/me
|
||||||
|
✅ fetchUser response: { success: true, user: {...} }
|
||||||
|
✅ Setting user in auth store: { steamId: "...", username: "...", ... }
|
||||||
|
🔵 fetchUser complete - isAuthenticated: true
|
||||||
|
|
||||||
|
Connecting to WebSocket: wss://api.turbotrades.dev/ws
|
||||||
|
WebSocket connected
|
||||||
|
🟢 WebSocket received 'connected' message: { steamId: "...", username: "...", userId: "..." }
|
||||||
|
🔵 Calling authStore.fetchUser() from WebSocket connected handler
|
||||||
|
🔵 fetchUser called - fetching user from /api/auth/me
|
||||||
|
✅ fetchUser response: { success: true, user: {...} }
|
||||||
|
✅ Setting user in auth store: { steamId: "...", username: "...", ... }
|
||||||
|
🔵 fetchUser complete - isAuthenticated: true
|
||||||
|
```
|
||||||
|
|
||||||
|
### 5. Verify Navbar Updates
|
||||||
|
|
||||||
|
The navbar should now show:
|
||||||
|
- ✅ Your Steam avatar
|
||||||
|
- ✅ Your username
|
||||||
|
- ✅ Your balance with deposit button
|
||||||
|
- ✅ User dropdown menu with Profile, Inventory, etc.
|
||||||
|
|
||||||
|
---
|
||||||
|
|
||||||
|
## Rollback Plan
|
||||||
|
|
||||||
|
If issues occur after deployment:
|
||||||
|
|
||||||
|
### Quick Rollback
|
||||||
|
```bash
|
||||||
|
# Revert the commits
|
||||||
|
git revert HEAD~2..HEAD
|
||||||
|
|
||||||
|
# Rebuild and redeploy
|
||||||
|
cd frontend
|
||||||
|
npm run build
|
||||||
|
sudo cp -r dist/* /var/www/html/turbotrades/
|
||||||
|
```
|
||||||
|
|
||||||
|
### Remove Debug Logs (Production Cleanup)
|
||||||
|
|
||||||
|
Once confirmed working, you may want to remove the verbose debug logs:
|
||||||
|
|
||||||
|
**In `frontend/src/stores/auth.js`** - remove all `console.log` statements added
|
||||||
|
|
||||||
|
**In `frontend/src/stores/websocket.js`** - remove or reduce debug logs:
|
||||||
|
```javascript
|
||||||
|
case "connected":
|
||||||
|
// Keep minimal logging
|
||||||
|
console.log("WebSocket connected");
|
||||||
|
authStore.fetchUser();
|
||||||
|
break;
|
||||||
|
```
|
||||||
|
|
||||||
|
Then rebuild and redeploy.
|
||||||
|
|
||||||
|
---
|
||||||
|
|
||||||
|
## Additional Notes
|
||||||
|
|
||||||
|
### Why Two `fetchUser()` Calls?
|
||||||
|
|
||||||
|
You might notice `fetchUser()` is called twice:
|
||||||
|
|
||||||
|
1. **On App Mount** (`App.vue` → `authStore.initialize()`)
|
||||||
|
- Handles the case where user already has a valid session
|
||||||
|
- Runs immediately when page loads
|
||||||
|
|
||||||
|
2. **On WebSocket Connected** (new addition)
|
||||||
|
- Handles the case where user just logged in via Steam
|
||||||
|
- Ensures auth state is fresh after Steam OAuth redirect
|
||||||
|
- Provides a fallback if the initial fetch happened before the session cookie was set
|
||||||
|
|
||||||
|
This redundancy is intentional and ensures authentication works reliably in all scenarios.
|
||||||
|
|
||||||
|
### Session Persistence
|
||||||
|
|
||||||
|
The authentication uses HTTP-only cookies set by the backend. These persist across:
|
||||||
|
- Page refreshes
|
||||||
|
- Browser restarts (unless expired)
|
||||||
|
- Tab closures
|
||||||
|
|
||||||
|
The WebSocket connection authenticates using the same session cookie.
|
||||||
|
|
||||||
|
---
|
||||||
|
|
||||||
|
## Related Files
|
||||||
|
|
||||||
|
- `frontend/src/stores/websocket.js` - WebSocket message handling
|
||||||
|
- `frontend/src/stores/auth.js` - Authentication state management
|
||||||
|
- `frontend/src/components/NavBar.vue` - Navbar component (reactive to auth state)
|
||||||
|
- `frontend/src/App.vue` - App initialization flow
|
||||||
|
- `backend/routes/auth.js` - Steam OAuth and session management
|
||||||
|
|
||||||
|
---
|
||||||
|
|
||||||
|
## Troubleshooting
|
||||||
|
|
||||||
|
### Navbar Still Not Updating
|
||||||
|
|
||||||
|
1. **Clear browser cache completely** (not just refresh)
|
||||||
|
2. **Check browser console for errors**
|
||||||
|
3. **Verify `/api/auth/me` returns user data:**
|
||||||
|
```bash
|
||||||
|
curl -s https://api.turbotrades.dev/api/auth/me -b cookies.txt | jq
|
||||||
|
```
|
||||||
|
4. **Check WebSocket connection:**
|
||||||
|
- Look for "WebSocket connected" in console
|
||||||
|
- Verify no CORS errors
|
||||||
|
|
||||||
|
### "fetchUser called" But No Response
|
||||||
|
|
||||||
|
- **Backend issue:** Check PM2 logs
|
||||||
|
```bash
|
||||||
|
pm2 logs turbotrades-backend --lines 50
|
||||||
|
```
|
||||||
|
- **CORS issue:** Check for CORS errors in browser console
|
||||||
|
- **Session cookie not set:** Check backend logs for Steam OAuth errors
|
||||||
|
|
||||||
|
### WebSocket Doesn't Receive "connected" Message
|
||||||
|
|
||||||
|
- **Backend WebSocket handler issue:** Check `backend/services/websocket.js`
|
||||||
|
- **Nginx not proxying WS correctly:** Verify Nginx config has:
|
||||||
|
```nginx
|
||||||
|
location /ws {
|
||||||
|
proxy_set_header Upgrade $http_upgrade;
|
||||||
|
proxy_set_header Connection "upgrade";
|
||||||
|
proxy_pass http://127.0.0.1:3000/ws;
|
||||||
|
}
|
||||||
|
```
|
||||||
|
|
||||||
|
---
|
||||||
|
|
||||||
|
## Success Criteria
|
||||||
|
|
||||||
|
✅ User can click "Login to Steam" and complete OAuth flow
|
||||||
|
✅ Upon redirect back to site, navbar shows logged-in state
|
||||||
|
✅ User's avatar, username, and balance are displayed
|
||||||
|
✅ WebSocket connects and shows user data in console
|
||||||
|
✅ User can access protected routes (Inventory, Profile, etc.)
|
||||||
|
✅ No console errors related to authentication or WebSocket
|
||||||
|
|
||||||
|
---
|
||||||
|
|
||||||
|
**Status:** Ready for deployment
|
||||||
|
**Last Updated:** 2025-01-10
|
||||||
|
**Build Tested:** ✅ Success
|
||||||
|
**Files Modified:** 2 (websocket.js, auth.js)
|
||||||
@@ -44,26 +44,35 @@ export const useAuthStore = defineStore("auth", () => {
|
|||||||
const fetchUser = async () => {
|
const fetchUser = async () => {
|
||||||
if (isLoading.value) return;
|
if (isLoading.value) return;
|
||||||
|
|
||||||
|
console.log("🔵 fetchUser called - fetching user from /api/auth/me");
|
||||||
isLoading.value = true;
|
isLoading.value = true;
|
||||||
try {
|
try {
|
||||||
const response = await axios.get("/api/auth/me", {
|
const response = await axios.get("/api/auth/me", {
|
||||||
withCredentials: true,
|
withCredentials: true,
|
||||||
});
|
});
|
||||||
|
|
||||||
|
console.log("✅ fetchUser response:", response.data);
|
||||||
|
|
||||||
if (response.data.success && response.data.user) {
|
if (response.data.success && response.data.user) {
|
||||||
|
console.log("✅ Setting user in auth store:", response.data.user);
|
||||||
setUser(response.data.user);
|
setUser(response.data.user);
|
||||||
return response.data.user;
|
return response.data.user;
|
||||||
} else {
|
} else {
|
||||||
|
console.log("❌ No user in response, clearing auth");
|
||||||
clearUser();
|
clearUser();
|
||||||
return null;
|
return null;
|
||||||
}
|
}
|
||||||
} catch (error) {
|
} catch (error) {
|
||||||
console.error("Failed to fetch user:", error);
|
console.error("❌ Failed to fetch user:", error);
|
||||||
clearUser();
|
clearUser();
|
||||||
return null;
|
return null;
|
||||||
} finally {
|
} finally {
|
||||||
isLoading.value = false;
|
isLoading.value = false;
|
||||||
isInitialized.value = true;
|
isInitialized.value = true;
|
||||||
|
console.log(
|
||||||
|
"🔵 fetchUser complete - isAuthenticated:",
|
||||||
|
isAuthenticated.value
|
||||||
|
);
|
||||||
}
|
}
|
||||||
};
|
};
|
||||||
|
|
||||||
@@ -229,6 +238,10 @@ export const useAuthStore = defineStore("auth", () => {
|
|||||||
|
|
||||||
// Initialize on store creation
|
// Initialize on store creation
|
||||||
const initialize = async () => {
|
const initialize = async () => {
|
||||||
|
console.log(
|
||||||
|
"🔵 Auth store initialize called - isInitialized:",
|
||||||
|
isInitialized.value
|
||||||
|
);
|
||||||
if (!isInitialized.value) {
|
if (!isInitialized.value) {
|
||||||
await fetchUser();
|
await fetchUser();
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -208,10 +208,16 @@ export const useWebSocketStore = defineStore("websocket", () => {
|
|||||||
|
|
||||||
const handleMessage = (data) => {
|
const handleMessage = (data) => {
|
||||||
const { type, data: payload, timestamp } = data;
|
const { type, data: payload, timestamp } = data;
|
||||||
|
const authStore = useAuthStore();
|
||||||
|
|
||||||
switch (type) {
|
switch (type) {
|
||||||
case "connected":
|
case "connected":
|
||||||
console.log("Server confirmed connection:", payload);
|
console.log("🟢 WebSocket received 'connected' message:", payload);
|
||||||
|
// Fetch updated user data from the auth endpoint
|
||||||
|
console.log(
|
||||||
|
"🔵 Calling authStore.fetchUser() from WebSocket connected handler"
|
||||||
|
);
|
||||||
|
authStore.fetchUser();
|
||||||
break;
|
break;
|
||||||
|
|
||||||
case "pong":
|
case "pong":
|
||||||
@@ -226,7 +232,6 @@ export const useWebSocketStore = defineStore("websocket", () => {
|
|||||||
|
|
||||||
case "balance_update":
|
case "balance_update":
|
||||||
// Update user balance
|
// Update user balance
|
||||||
const authStore = useAuthStore();
|
|
||||||
if (payload?.balance !== undefined) {
|
if (payload?.balance !== undefined) {
|
||||||
authStore.updateBalance(payload.balance);
|
authStore.updateBalance(payload.balance);
|
||||||
}
|
}
|
||||||
|
|||||||
314
scripts/verify-login-fix.cjs
Normal file
314
scripts/verify-login-fix.cjs
Normal file
@@ -0,0 +1,314 @@
|
|||||||
|
#!/usr/bin/env node
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Verification Script for Navbar Login Fix
|
||||||
|
*
|
||||||
|
* This script verifies that the WebSocket authentication state synchronization
|
||||||
|
* is working correctly after the navbar login fix deployment.
|
||||||
|
*
|
||||||
|
* Usage:
|
||||||
|
* node scripts/verify-login-fix.js
|
||||||
|
*/
|
||||||
|
|
||||||
|
const https = require('https');
|
||||||
|
const http = require('http');
|
||||||
|
|
||||||
|
const API_URL = process.env.VITE_API_URL || 'https://api.turbotrades.dev';
|
||||||
|
const WS_URL = process.env.VITE_WS_URL || 'wss://api.turbotrades.dev/ws';
|
||||||
|
|
||||||
|
const colors = {
|
||||||
|
reset: '\x1b[0m',
|
||||||
|
bright: '\x1b[1m',
|
||||||
|
green: '\x1b[32m',
|
||||||
|
red: '\x1b[31m',
|
||||||
|
yellow: '\x1b[33m',
|
||||||
|
blue: '\x1b[34m',
|
||||||
|
cyan: '\x1b[36m',
|
||||||
|
};
|
||||||
|
|
||||||
|
function log(message, color = colors.reset) {
|
||||||
|
console.log(`${color}${message}${colors.reset}`);
|
||||||
|
}
|
||||||
|
|
||||||
|
function success(message) {
|
||||||
|
log(`✅ ${message}`, colors.green);
|
||||||
|
}
|
||||||
|
|
||||||
|
function error(message) {
|
||||||
|
log(`❌ ${message}`, colors.red);
|
||||||
|
}
|
||||||
|
|
||||||
|
function warning(message) {
|
||||||
|
log(`⚠️ ${message}`, colors.yellow);
|
||||||
|
}
|
||||||
|
|
||||||
|
function info(message) {
|
||||||
|
log(`ℹ️ ${message}`, colors.cyan);
|
||||||
|
}
|
||||||
|
|
||||||
|
function section(message) {
|
||||||
|
log(`\n${colors.bright}${message}${colors.reset}`);
|
||||||
|
log('='.repeat(60));
|
||||||
|
}
|
||||||
|
|
||||||
|
// Check if endpoint is reachable
|
||||||
|
function checkEndpoint(url, description) {
|
||||||
|
return new Promise((resolve) => {
|
||||||
|
const urlObj = new URL(url);
|
||||||
|
const client = urlObj.protocol === 'https:' ? https : http;
|
||||||
|
|
||||||
|
const options = {
|
||||||
|
hostname: urlObj.hostname,
|
||||||
|
port: urlObj.port || (urlObj.protocol === 'https:' ? 443 : 80),
|
||||||
|
path: urlObj.pathname,
|
||||||
|
method: 'GET',
|
||||||
|
timeout: 5000,
|
||||||
|
};
|
||||||
|
|
||||||
|
const req = client.request(options, (res) => {
|
||||||
|
if (res.statusCode >= 200 && res.statusCode < 400) {
|
||||||
|
success(`${description}: Reachable (Status: ${res.statusCode})`);
|
||||||
|
resolve(true);
|
||||||
|
} else {
|
||||||
|
warning(`${description}: Returned status ${res.statusCode}`);
|
||||||
|
resolve(false);
|
||||||
|
}
|
||||||
|
});
|
||||||
|
|
||||||
|
req.on('error', (err) => {
|
||||||
|
error(`${description}: ${err.message}`);
|
||||||
|
resolve(false);
|
||||||
|
});
|
||||||
|
|
||||||
|
req.on('timeout', () => {
|
||||||
|
error(`${description}: Request timed out`);
|
||||||
|
req.destroy();
|
||||||
|
resolve(false);
|
||||||
|
});
|
||||||
|
|
||||||
|
req.end();
|
||||||
|
});
|
||||||
|
}
|
||||||
|
|
||||||
|
// Check WebSocket endpoint
|
||||||
|
function checkWebSocket(url) {
|
||||||
|
return new Promise((resolve) => {
|
||||||
|
try {
|
||||||
|
const WebSocket = require('ws');
|
||||||
|
const ws = new WebSocket(url);
|
||||||
|
|
||||||
|
const timeout = setTimeout(() => {
|
||||||
|
ws.close();
|
||||||
|
error('WebSocket: Connection timeout');
|
||||||
|
resolve(false);
|
||||||
|
}, 5000);
|
||||||
|
|
||||||
|
ws.on('open', () => {
|
||||||
|
clearTimeout(timeout);
|
||||||
|
success('WebSocket: Connection successful');
|
||||||
|
ws.close();
|
||||||
|
resolve(true);
|
||||||
|
});
|
||||||
|
|
||||||
|
ws.on('error', (err) => {
|
||||||
|
clearTimeout(timeout);
|
||||||
|
error(`WebSocket: ${err.message}`);
|
||||||
|
resolve(false);
|
||||||
|
});
|
||||||
|
|
||||||
|
} catch (err) {
|
||||||
|
error(`WebSocket: ws module not available (${err.message})`);
|
||||||
|
warning('Install with: npm install ws');
|
||||||
|
resolve(false);
|
||||||
|
}
|
||||||
|
});
|
||||||
|
}
|
||||||
|
|
||||||
|
// Read and verify frontend build files
|
||||||
|
function checkFrontendBuild() {
|
||||||
|
const fs = require('fs');
|
||||||
|
const path = require('path');
|
||||||
|
|
||||||
|
const distPath = path.join(__dirname, '..', 'frontend', 'dist');
|
||||||
|
const indexPath = path.join(distPath, 'index.html');
|
||||||
|
|
||||||
|
if (!fs.existsSync(distPath)) {
|
||||||
|
error('Frontend dist directory not found');
|
||||||
|
warning('Run: cd frontend && npm run build');
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (!fs.existsSync(indexPath)) {
|
||||||
|
error('Frontend index.html not found in dist/');
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
|
const indexContent = fs.readFileSync(indexPath, 'utf8');
|
||||||
|
|
||||||
|
// Check for recent build by looking for assets
|
||||||
|
const hasAssets = indexContent.includes('/assets/');
|
||||||
|
const hasModernJS = indexContent.includes('type="module"');
|
||||||
|
|
||||||
|
if (hasAssets && hasModernJS) {
|
||||||
|
success('Frontend build exists and looks valid');
|
||||||
|
|
||||||
|
// Get build timestamp from file modification time
|
||||||
|
const stats = fs.statSync(indexPath);
|
||||||
|
const buildTime = stats.mtime;
|
||||||
|
const now = new Date();
|
||||||
|
const ageMinutes = Math.floor((now - buildTime) / 1000 / 60);
|
||||||
|
|
||||||
|
if (ageMinutes < 60) {
|
||||||
|
success(`Build age: ${ageMinutes} minutes (recent)`);
|
||||||
|
} else if (ageMinutes < 1440) {
|
||||||
|
info(`Build age: ${Math.floor(ageMinutes / 60)} hours`);
|
||||||
|
} else {
|
||||||
|
warning(`Build age: ${Math.floor(ageMinutes / 1440)} days (consider rebuilding)`);
|
||||||
|
}
|
||||||
|
|
||||||
|
return true;
|
||||||
|
} else {
|
||||||
|
error('Frontend build appears invalid');
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// Check source files for the fix
|
||||||
|
function checkSourceCode() {
|
||||||
|
const fs = require('fs');
|
||||||
|
const path = require('path');
|
||||||
|
|
||||||
|
const websocketStorePath = path.join(__dirname, '..', 'frontend', 'src', 'stores', 'websocket.js');
|
||||||
|
const authStorePath = path.join(__dirname, '..', 'frontend', 'src', 'stores', 'auth.js');
|
||||||
|
|
||||||
|
if (!fs.existsSync(websocketStorePath)) {
|
||||||
|
error('WebSocket store not found');
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (!fs.existsSync(authStorePath)) {
|
||||||
|
error('Auth store not found');
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
|
const websocketCode = fs.readFileSync(websocketStorePath, 'utf8');
|
||||||
|
const authCode = fs.readFileSync(authStorePath, 'utf8');
|
||||||
|
|
||||||
|
// Check for the fix in websocket store
|
||||||
|
const hasConnectedHandler = websocketCode.includes('case "connected":');
|
||||||
|
const callsFetchUser = websocketCode.includes('authStore.fetchUser()');
|
||||||
|
const declaresAuthStore = websocketCode.includes('const authStore = useAuthStore()');
|
||||||
|
|
||||||
|
if (hasConnectedHandler && callsFetchUser && declaresAuthStore) {
|
||||||
|
success('WebSocket store has the navbar login fix');
|
||||||
|
} else {
|
||||||
|
error('WebSocket store missing the fix');
|
||||||
|
if (!hasConnectedHandler) warning(' - Missing "connected" case handler');
|
||||||
|
if (!callsFetchUser) warning(' - Not calling authStore.fetchUser()');
|
||||||
|
if (!declaresAuthStore) warning(' - Not declaring authStore');
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
|
// Check for debug logging (optional)
|
||||||
|
const hasDebugLogs = websocketCode.includes('🟢 WebSocket received') ||
|
||||||
|
authCode.includes('🔵 fetchUser called');
|
||||||
|
|
||||||
|
if (hasDebugLogs) {
|
||||||
|
info('Debug logging is present (helpful for troubleshooting)');
|
||||||
|
} else {
|
||||||
|
info('Debug logging not present (clean for production)');
|
||||||
|
}
|
||||||
|
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
|
||||||
|
// Main verification flow
|
||||||
|
async function main() {
|
||||||
|
log('\n' + '='.repeat(60), colors.bright);
|
||||||
|
log(' NAVBAR LOGIN FIX - VERIFICATION SCRIPT', colors.bright);
|
||||||
|
log('='.repeat(60) + '\n', colors.bright);
|
||||||
|
|
||||||
|
let allChecks = true;
|
||||||
|
|
||||||
|
// 1. Check source code
|
||||||
|
section('1. Checking Source Code');
|
||||||
|
const sourceCheck = checkSourceCode();
|
||||||
|
allChecks = allChecks && sourceCheck;
|
||||||
|
|
||||||
|
// 2. Check frontend build
|
||||||
|
section('2. Checking Frontend Build');
|
||||||
|
const buildCheck = checkFrontendBuild();
|
||||||
|
allChecks = allChecks && buildCheck;
|
||||||
|
|
||||||
|
// 3. Check API endpoints
|
||||||
|
section('3. Checking API Endpoints');
|
||||||
|
|
||||||
|
const apiHealthCheck = await checkEndpoint(
|
||||||
|
`${API_URL}/api/health`,
|
||||||
|
'API Health Endpoint'
|
||||||
|
);
|
||||||
|
|
||||||
|
const apiAuthCheck = await checkEndpoint(
|
||||||
|
`${API_URL}/api/auth/me`,
|
||||||
|
'Auth Endpoint (/api/auth/me)'
|
||||||
|
);
|
||||||
|
|
||||||
|
const publicConfigCheck = await checkEndpoint(
|
||||||
|
`${API_URL}/api/config/public`,
|
||||||
|
'Public Config Endpoint'
|
||||||
|
);
|
||||||
|
|
||||||
|
allChecks = allChecks && apiHealthCheck && apiAuthCheck && publicConfigCheck;
|
||||||
|
|
||||||
|
// 4. Check WebSocket
|
||||||
|
section('4. Checking WebSocket Connection');
|
||||||
|
const wsCheck = await checkWebSocket(WS_URL);
|
||||||
|
allChecks = allChecks && wsCheck;
|
||||||
|
|
||||||
|
// Summary
|
||||||
|
section('Verification Summary');
|
||||||
|
|
||||||
|
if (allChecks) {
|
||||||
|
success('All checks passed! ✨');
|
||||||
|
log('\n📋 Next Steps:', colors.bright);
|
||||||
|
log(' 1. Deploy the frontend build to production');
|
||||||
|
log(' 2. Clear browser cache (Ctrl+Shift+R)');
|
||||||
|
log(' 3. Test Steam login in browser');
|
||||||
|
log(' 4. Verify navbar updates after login\n');
|
||||||
|
} else {
|
||||||
|
error('Some checks failed!');
|
||||||
|
log('\n📋 Recommended Actions:', colors.bright);
|
||||||
|
|
||||||
|
if (!sourceCheck) {
|
||||||
|
log(' • Verify the code changes are committed');
|
||||||
|
log(' • Pull latest changes: git pull origin main');
|
||||||
|
}
|
||||||
|
|
||||||
|
if (!buildCheck) {
|
||||||
|
log(' • Rebuild frontend: cd frontend && npm run build');
|
||||||
|
}
|
||||||
|
|
||||||
|
if (!apiHealthCheck || !apiAuthCheck || !publicConfigCheck) {
|
||||||
|
log(' • Check backend is running: pm2 status');
|
||||||
|
log(' • Check backend logs: pm2 logs turbotrades-backend');
|
||||||
|
log(' • Verify Nginx configuration');
|
||||||
|
}
|
||||||
|
|
||||||
|
if (!wsCheck) {
|
||||||
|
log(' • Check WebSocket endpoint in Nginx config');
|
||||||
|
log(' • Verify backend WebSocket service is running');
|
||||||
|
log(' • Check firewall rules for WebSocket connections');
|
||||||
|
}
|
||||||
|
|
||||||
|
log('');
|
||||||
|
}
|
||||||
|
|
||||||
|
process.exit(allChecks ? 0 : 1);
|
||||||
|
}
|
||||||
|
|
||||||
|
// Run the script
|
||||||
|
main().catch((err) => {
|
||||||
|
error(`Unexpected error: ${err.message}`);
|
||||||
|
console.error(err);
|
||||||
|
process.exit(1);
|
||||||
|
});
|
||||||
Reference in New Issue
Block a user