diff --git a/Screenshot from 2025-10-24 10-45-47.png b/Screenshot from 2025-10-24 10-45-47.png new file mode 100644 index 00000000..31cda08e Binary files /dev/null and b/Screenshot from 2025-10-24 10-45-47.png differ diff --git a/TECHNICAL_BRIEF_SUBMISSIONS_500_ERROR.md b/TECHNICAL_BRIEF_SUBMISSIONS_500_ERROR.md new file mode 100644 index 00000000..062cd5f3 --- /dev/null +++ b/TECHNICAL_BRIEF_SUBMISSIONS_500_ERROR.md @@ -0,0 +1,124 @@ +# Technical Brief: Submissions Endpoint 500 Errors + +**Date**: 2025-10-24 +**Severity**: High +**Status**: Unresolved after 1 hour investigation + +## Problem Summary + +Browser reports consistent 500 Internal Server Errors on submissions endpoints: +- `GET /api/submissions?limit=100` → 500 error +- `GET /api/submissions/by-blog-post/{id}` → 500 error + +**Critical Finding**: Server logs show **ZERO** record of these 500 errors. Browser Network tab confirms requests to `http://localhost:9000`, but server stdout/stderr logs have no matching ERROR entries. + +## Evidence + +### Browser Behavior +- Network tab shows: `http://localhost:9000/api/submissions?limit=100` Status: 500 +- Other endpoints work fine: `/api/blog/admin/posts` returns 200 +- User is authenticated (other admin endpoints succeed) + +### Server Behavior +- Server running on port 9000 (PID verified via `lsof -i:9000`) +- Started at 10:40:24 with latest code (commit 28ab839 from 10:31:19) +- Logs show NO 500 errors for submissions endpoints +- Only shows 401 (from curl test with expired token) + +### Code Status +All fixes committed and deployed: +- ✅ Mongoose duplicate index warnings fixed (3 instances in Analytics.model.js) +- ✅ BlogPost `.populate()` calls removed from submissions controller +- ✅ User `.populate()` calls removed from submissions controller +- ✅ Code on disk verified correct (no populate calls present) + +## Root Cause Hypothesis + +**Service Worker Cache Poisoning**: The browser's service worker (`/public/service-worker.js`) may have cached the 500 error responses from earlier failed requests. Even after server restart with fixed code, the service worker serves stale error responses. + +### Supporting Evidence +1. Browser shows errors but server has no log of requests +2. Cache version was bumped to `0.1.1` but service worker may not have updated +3. Service worker intercepts fetch requests before they reach server + +## Immediate Actions Required + +### Option 1: Clear Service Worker (User Action) +1. Open DevTools → Application tab → Service Workers +2. Click "Unregister" for localhost:9000 +3. Hard reload (Ctrl+Shift+R) + +### Option 2: Disable Service Worker (Code Change) +```javascript +// public/service-worker.js - Add at top +self.addEventListener('install', () => { + self.skipWaiting(); +}); + +self.addEventListener('activate', (event) => { + event.waitUntil( + caches.keys().then(cacheNames => { + return Promise.all( + cacheNames.map(cacheName => caches.delete(cacheName)) + ); + }) + ); +}); +``` + +### Option 3: Debug Actual Error (If not cache) +If service worker is not the cause, the 500 errors ARE happening but error handling is swallowing them. Check: + +**src/controllers/submissions.controller.js lines 76-129 (getSubmissions function)**: +```javascript +try { + // Query logic +} catch (error) { + console.error('[Submissions] Get submissions error:', error); // ← Should log + res.status(500).json({ success: false, error: 'Failed to fetch submissions' }); +} +``` + +If logs truly show nothing, then: +- Error occurs BEFORE Morgan logging middleware +- Or try/catch is returning 500 without logging +- Or there's error-handling middleware intercepting + +## Investigation Commands + +```bash +# Check if service worker is active +curl -I http://localhost:9000/service-worker.js + +# Test endpoint with verbose logging +NODE_DEBUG=http node src/server.js 2>&1 | tee /tmp/debug-server.log + +# Monitor in real-time +tail -f /tmp/fresh-server.log | grep -E "(submissions|500|ERROR)" + +# Check all Node processes +ps aux | grep "node.*server.js" +``` + +## Files Modified (Session History) + +1. `src/models/Analytics.model.js` - Removed 3 duplicate index definitions +2. `src/controllers/submissions.controller.js` - Removed BlogPost and User populate calls +3. `src/models/SubmissionTracking.model.js` - Removed BlogPost populate from static methods +4. `public/version.json` - Bumped to 0.1.1 +5. `public/service-worker.js` - Updated CACHE_VERSION to 0.1.1 + +## Next Steps for External Auditor + +1. **Verify service worker status** in browser DevTools +2. **Check MongoDB connection** - submissions controller uses `SubmissionTracking.find()` +3. **Add explicit logging** at top of getSubmissions function to confirm it's being called +4. **Check middleware stack** in `src/routes/submissions.routes.js` - auth middleware may be failing silently +5. **Inspect error-handling middleware** in `src/server.js` - may be catching errors before logging + +## Contact + +- Project: Tractatus Website (tractatus-website) +- Database: MongoDB tractatus_dev (port 27017) +- Server: Node.js/Express (port 9000) +- Session context: Previous work on Mongoose warnings + submissions tracking diff --git a/public/js/admin/blog-curation-enhanced.js b/public/js/admin/blog-curation-enhanced.js index 5643b7df..808907ee 100644 --- a/public/js/admin/blog-curation-enhanced.js +++ b/public/js/admin/blog-curation-enhanced.js @@ -15,6 +15,7 @@ function getAuthToken() { async function apiCall(endpoint, options = {}) { const token = getAuthToken(); const defaultOptions = { + cache: 'no-store', // Force fresh requests - prevent cached 500 errors headers: { 'Content-Type': 'application/json', 'Authorization': `Bearer ${token}` diff --git a/public/js/admin/blog-curation.js b/public/js/admin/blog-curation.js index b2c34c6d..6e8e215f 100644 --- a/public/js/admin/blog-curation.js +++ b/public/js/admin/blog-curation.js @@ -22,6 +22,7 @@ function checkAuth() { async function apiCall(endpoint, options = {}) { const token = getAuthToken(); const defaultOptions = { + cache: 'no-store', // Force fresh requests - prevent cached 500 errors headers: { 'Content-Type': 'application/json', 'Authorization': `Bearer ${token}` diff --git a/public/js/admin/blog-validation.js b/public/js/admin/blog-validation.js index ec258aea..737c1773 100644 --- a/public/js/admin/blog-validation.js +++ b/public/js/admin/blog-validation.js @@ -46,6 +46,7 @@ function getAuthToken() { async function apiCall(endpoint, options = {}) { const token = getAuthToken(); const defaultOptions = { + cache: 'no-store', // Force fresh requests - prevent cached 500 errors headers: { 'Content-Type': 'application/json', 'Authorization': `Bearer ${token}` diff --git a/src/controllers/submissions.controller.js b/src/controllers/submissions.controller.js index 75544092..aef09ba0 100644 --- a/src/controllers/submissions.controller.js +++ b/src/controllers/submissions.controller.js @@ -74,6 +74,7 @@ async function createSubmission(req, res) { * Get all submissions with optional filtering */ async function getSubmissions(req, res) { + console.log('[SUBMISSIONS DEBUG] getSubmissions called, query:', req.query); try { const { status, publicationId, limit = 50, offset = 0 } = req.query;