diff --git a/CRITICAL_FIXES_PROMPT.md b/CRITICAL_FIXES_PROMPT.md new file mode 100644 index 0000000..9208267 --- /dev/null +++ b/CRITICAL_FIXES_PROMPT.md @@ -0,0 +1,243 @@ +# NaviDocs CRITICAL Security & UX Fixes - 8 Haiku Agents + +**GitHub Repository:** https://github.com/dannystocker/navidocs +**Base Branch:** `claude/install-run-ssh-01RZPPuRFwrveZKec62363vu` (latest build) +**New Branch:** `fix/critical-security-ux` + +--- + +## Mission: Fix 8 Critical Issues Found in Code Reviews + +**Context:** Codex and Gemini reviews found 8 CRITICAL blockers that must be fixed before production. The app is functionally complete but has security holes and UX issues for marine environment. + +--- + +## CRITICAL ISSUES (Must Fix) + +### 🔴 Security (Agents 1-4) + +**AGENT 1: JWT Secret Enforcement** +- **File:** `server/services/auth.service.js` +- **Issue:** Line 13: `const JWT_SECRET = process.env.JWT_SECRET || 'your-jwt-secret-here-change-in-production'` +- **Risk:** If JWT_SECRET not set, attackers can forge tokens +- **Fix:** + ```javascript + // BEFORE + const JWT_SECRET = process.env.JWT_SECRET || 'your-jwt-secret-here-change-in-production'; + + // AFTER + const JWT_SECRET = process.env.JWT_SECRET; + if (!JWT_SECRET || JWT_SECRET.length < 32) { + throw new Error('JWT_SECRET environment variable is required and must be at least 32 chars'); + } + ``` +- **Test:** Start server without JWT_SECRET → should throw error + +**AGENT 2: Document Routes Auth Gaps** +- **Files:** `server/routes/documents.js`, `server/routes/images.js` +- **Issue:** Routes use `req.user?.id || 'test-user-id'` instead of enforcing auth +- **Risk:** Synthetic user ID bypasses tenant isolation +- **Fix Pattern:** + ```javascript + // BEFORE + router.get('/:id', async (req, res) => { + const userId = req.user?.id || 'test-user-id'; + // ... + }); + + // AFTER + import { authenticateToken } from '../middleware/auth.middleware.js'; + + router.get('/:id', authenticateToken, async (req, res) => { + const userId = req.user.userId; // Always defined after middleware + // ... + }); + ``` +- **Apply to:** All routes in `documents.js` and `images.js` +- **Test:** Unauthenticated request → 401 + +**AGENT 3: Search/Upload Route Auth** +- **Files:** `server/routes/search.js`, `server/routes/upload.js` +- **Issue:** Same `test-user-id` pattern +- **Fix:** Add `authenticateToken` middleware to all endpoints +- **Test:** Upload without token → 401 + +**AGENT 4: Stats Route Protection** +- **File:** `server/routes/stats.js` +- **Issue:** Global stats endpoint has no auth (reveals business metrics) +- **Fix:** + ```javascript + import { authenticateToken, requireSystemAdmin } from '../middleware/auth.middleware.js'; + + router.get('/', authenticateToken, requireSystemAdmin, async (req, res) => { + // Only admins can see global stats + }); + ``` +- **Test:** Non-admin request → 403 + +### 🎨 UX Marine Environment (Agents 5-8) + +**AGENT 5: Touch Targets (60px Minimum)** +- **Issue:** Buttons as small as 12×12px found in `client/src/components/` +- **Pattern:** + ```vue + + + + + + ``` +- **Files to Fix:** + - `client/src/components/TocSidebar.vue` (40px → 60px) + - `client/src/components/SearchResultsSidebar.vue` (20px → 60px) + - `client/src/components/TocEntry.vue` (32px → 60px) +- **Test:** All interactive elements ≥60×60px + +**AGENT 6: Font Sizes (16px Minimum)** +- **Issue:** Fonts as small as 10px found (unreadable in sunlight) +- **Pattern:** + ```vue + +
Last updated
+ + +Last updated
+ ``` +- **Files to Fix:** + - `client/src/views/SearchView.vue` (10px, 11px, 12px → 16px) + - `client/src/components/TocSidebar.vue` (11px → 16px) + - `client/src/components/SearchResultsSidebar.vue` (11px → 16px) +- **Test:** No fonts <16px in codebase + +**AGENT 7: ARIA Labels (29 Icon Buttons)** +- **Issue:** Icon-only buttons lack screen reader labels +- **Pattern:** + ```vue + + + + + + ``` +- **Scan:** `grep -r "