tractatus/src/routes/documents.routes.js
TheFlow 2298d36bed fix(submissions): restructure Economist package and fix article display
- Create Economist SubmissionTracking package correctly:
  * mainArticle = full blog post content
  * coverLetter = 216-word SIR— letter
  * Links to blog post via blogPostId
- Archive 'Letter to The Economist' from blog posts (it's the cover letter)
- Fix date display on article cards (use published_at)
- Target publication already displaying via blue badge

Database changes:
- Make blogPostId optional in SubmissionTracking model
- Economist package ID: 68fa85ae49d4900e7f2ecd83
- Le Monde package ID: 68fa2abd2e6acd5691932150

Next: Enhanced modal with tabs, validation, export

🤖 Generated with [Claude Code](https://claude.com/claude-code)

Co-Authored-By: Claude <noreply@anthropic.com>
2025-10-24 08:47:42 +13:00

100 lines
2.5 KiB
JavaScript

/**
* Documents Routes
* Framework documentation endpoints
*/
const express = require('express');
const router = express.Router();
const documentsController = require('../controllers/documents.controller');
const { authenticateToken, requireRole } = 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
router.get('/archived',
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 (ID or slug)
router.get('/:identifier',
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)
);
module.exports = router;