/** * Documents Routes * Framework documentation endpoints */ const express = require('express'); const router = express.Router(); const documentsController = require('../controllers/documents.controller'); const { authenticateToken, requireRole, optionalAuth } = require('../middleware/auth.middleware'); const { validateRequired, validateObjectId, validateSlug } = require('../middleware/validation.middleware'); const { asyncHandler } = require('../middleware/error.middleware'); /** * Public routes (read-only) */ // GET /api/documents/search?q=query router.get('/search', asyncHandler(documentsController.searchDocuments) ); // GET /api/documents/archived (admin only) router.get('/archived', authenticateToken, requireRole('admin'), asyncHandler(documentsController.listArchivedDocuments) ); // GET /api/documents/drafts (admin only) router.get('/drafts', authenticateToken, requireRole('admin'), asyncHandler(documentsController.listDraftDocuments) ); // GET /api/documents router.get('/', (req, res, next) => { // Redirect browser requests to API documentation const acceptsHtml = req.accepts('html'); const acceptsJson = req.accepts('json'); if (acceptsHtml && !acceptsJson) { return res.redirect(302, '/api-reference.html#documents'); } next(); }, asyncHandler(documentsController.listDocuments)); // GET /api/documents/:identifier/translations (public, visibility-filtered) router.get('/:identifier/translations', optionalAuth, asyncHandler(documentsController.getTranslations) ); // GET /api/documents/:identifier (ID or slug, visibility-filtered) router.get('/:identifier', optionalAuth, asyncHandler(documentsController.getDocument) ); /** * Admin routes (protected) */ // POST /api/documents router.post('/', authenticateToken, requireRole('admin'), validateRequired(['title', 'slug', 'quadrant', 'content_markdown']), validateSlug, asyncHandler(documentsController.createDocument) ); // PUT /api/documents/:id router.put('/:id', authenticateToken, requireRole('admin'), validateObjectId('id'), asyncHandler(documentsController.updateDocument) ); // DELETE /api/documents/:id router.delete('/:id', authenticateToken, requireRole('admin'), validateObjectId('id'), asyncHandler(documentsController.deleteDocument) ); // POST /api/documents/:id/publish (admin only) // SECURITY: Explicit publish workflow with validation router.post('/:id/publish', authenticateToken, requireRole('admin'), validateObjectId('id'), validateRequired(['category']), asyncHandler(documentsController.publishDocument) ); // POST /api/documents/:id/unpublish (admin only) router.post('/:id/unpublish', authenticateToken, requireRole('admin'), validateObjectId('id'), asyncHandler(documentsController.unpublishDocument) ); // POST /api/documents/:id/translate (admin only) // Translate document to target language using DeepL router.post('/:id/translate', authenticateToken, requireRole('admin'), validateObjectId('id'), validateRequired(['targetLang']), asyncHandler(documentsController.translateDocument) ); // DELETE /api/documents/:id/translations/:lang (admin only) // Delete a translation router.delete('/:id/translations/:lang', authenticateToken, requireRole('admin'), validateObjectId('id'), asyncHandler(documentsController.deleteTranslation) ); module.exports = router;