## Backend (server/) - Express 5 API with security middleware (helmet, rate limiting) - SQLite database with WAL mode (schema from docs/architecture/) - Meilisearch integration with tenant tokens - BullMQ + Redis background job queue - OCR pipeline with Tesseract.js - File safety validation (extension, MIME, size) - 4 API route modules: upload, jobs, search, documents ## Frontend (client/) - Vue 3 with Composition API (<script setup>) - Vite 5 build system with HMR - Tailwind CSS (Meilisearch-inspired design) - UploadModal with drag-and-drop - FigureZoom component (ported from lilian1) - Meilisearch search integration with tenant tokens - Job polling composable - Clean SVG icons (no emojis) ## Code Extraction - ✅ manuals.js → UploadModal.vue, useJobPolling.js - ✅ figure-zoom.js → FigureZoom.vue - ✅ service-worker.js → client/public/service-worker.js (TODO) - ✅ glossary.json → Merged into Meilisearch synonyms - ❌ Discarded: quiz.js, persona.js, gamification.js (Frank-AI junk) ## Documentation - Complete extraction plan in docs/analysis/ - README with quick start guide - Architecture summary in docs/architecture/ ## Build Status - Server dependencies: ✅ Installed (234 packages) - Client dependencies: ✅ Installed (160 packages) - Client build: ✅ Successful (2.63s) 🤖 Generated with Claude Code Co-Authored-By: Claude <noreply@anthropic.com>
60 lines
1.5 KiB
JavaScript
60 lines
1.5 KiB
JavaScript
/**
|
|
* Authentication Middleware
|
|
* Placeholder for JWT authentication
|
|
* TODO: Implement full JWT verification
|
|
*/
|
|
|
|
import jwt from 'jsonwebtoken';
|
|
|
|
const JWT_SECRET = process.env.JWT_SECRET || 'your-jwt-secret-here-change-in-production';
|
|
|
|
/**
|
|
* Verify JWT token and attach user to request
|
|
* @param {Request} req - Express request
|
|
* @param {Response} res - Express response
|
|
* @param {Function} next - Next middleware
|
|
*/
|
|
export function authenticateToken(req, res, next) {
|
|
const authHeader = req.headers['authorization'];
|
|
const token = authHeader && authHeader.split(' ')[1]; // Bearer TOKEN
|
|
|
|
if (!token) {
|
|
return res.status(401).json({ error: 'Authentication required' });
|
|
}
|
|
|
|
try {
|
|
const user = jwt.verify(token, JWT_SECRET);
|
|
req.user = user;
|
|
next();
|
|
} catch (error) {
|
|
return res.status(403).json({ error: 'Invalid or expired token' });
|
|
}
|
|
}
|
|
|
|
/**
|
|
* Optional authentication - attaches user if token present
|
|
* @param {Request} req - Express request
|
|
* @param {Response} res - Express response
|
|
* @param {Function} next - Next middleware
|
|
*/
|
|
export function optionalAuth(req, res, next) {
|
|
const authHeader = req.headers['authorization'];
|
|
const token = authHeader && authHeader.split(' ')[1];
|
|
|
|
if (token) {
|
|
try {
|
|
const user = jwt.verify(token, JWT_SECRET);
|
|
req.user = user;
|
|
} catch (error) {
|
|
// Token invalid, but don't fail - continue without user
|
|
console.log('Invalid token provided:', error.message);
|
|
}
|
|
}
|
|
|
|
next();
|
|
}
|
|
|
|
export default {
|
|
authenticateToken,
|
|
optionalAuth
|
|
};
|