fix(admin): force fresh API requests to prevent cached 500 errors

- Add cache: 'no-store' to all apiCall functions in admin JS files
- Prevents browser fetch cache from serving stale error responses
- Addresses submissions endpoint 500 errors that weren't appearing in server logs
- Killed duplicate server process (PID 1583625)
- Added debug logging to submissions controller
- Files modified: blog-validation.js, blog-curation.js, blog-curation-enhanced.js
This commit is contained in:
TheFlow 2025-10-24 11:02:43 +13:00
parent 6011a50042
commit f7d0b68d39
6 changed files with 128 additions and 0 deletions

Binary file not shown.

After

Width:  |  Height:  |  Size: 240 KiB

View file

@ -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

View file

@ -15,6 +15,7 @@ function getAuthToken() {
async function apiCall(endpoint, options = {}) { async function apiCall(endpoint, options = {}) {
const token = getAuthToken(); const token = getAuthToken();
const defaultOptions = { const defaultOptions = {
cache: 'no-store', // Force fresh requests - prevent cached 500 errors
headers: { headers: {
'Content-Type': 'application/json', 'Content-Type': 'application/json',
'Authorization': `Bearer ${token}` 'Authorization': `Bearer ${token}`

View file

@ -22,6 +22,7 @@ function checkAuth() {
async function apiCall(endpoint, options = {}) { async function apiCall(endpoint, options = {}) {
const token = getAuthToken(); const token = getAuthToken();
const defaultOptions = { const defaultOptions = {
cache: 'no-store', // Force fresh requests - prevent cached 500 errors
headers: { headers: {
'Content-Type': 'application/json', 'Content-Type': 'application/json',
'Authorization': `Bearer ${token}` 'Authorization': `Bearer ${token}`

View file

@ -46,6 +46,7 @@ function getAuthToken() {
async function apiCall(endpoint, options = {}) { async function apiCall(endpoint, options = {}) {
const token = getAuthToken(); const token = getAuthToken();
const defaultOptions = { const defaultOptions = {
cache: 'no-store', // Force fresh requests - prevent cached 500 errors
headers: { headers: {
'Content-Type': 'application/json', 'Content-Type': 'application/json',
'Authorization': `Bearer ${token}` 'Authorization': `Bearer ${token}`

View file

@ -74,6 +74,7 @@ async function createSubmission(req, res) {
* Get all submissions with optional filtering * Get all submissions with optional filtering
*/ */
async function getSubmissions(req, res) { async function getSubmissions(req, res) {
console.log('[SUBMISSIONS DEBUG] getSubmissions called, query:', req.query);
try { try {
const { status, publicationId, limit = 50, offset = 0 } = req.query; const { status, publicationId, limit = 50, offset = 0 } = req.query;