/** * 文档 · /brain/documents * 用途:语言层数据库核心——人格体读写,人类只读(渲染) */ const { Router } = require('express'); const crypto = require('crypto'); const router = Router(); // GET /brain/documents — 列出文档(支持树形查询) router.get('/', (req, res) => { try { let sql = 'SELECT document_id, persona_id, parent_id, path, title, content_type, source, version, created_at, updated_at FROM documents WHERE 1=1'; const params = []; if (req.query.parent_id) { sql += ' AND parent_id = ?'; params.push(req.query.parent_id); } if (req.query.persona_id) { sql += ' AND persona_id = ?'; params.push(req.query.persona_id); } if (req.query.root) { sql += ' AND parent_id IS NULL'; } sql += ' ORDER BY path ASC'; const rows = req.db.prepare(sql).all(...params); res.json({ data: rows, total: rows.length }); } catch (err) { res.status(500).json({ error: true, message: err.message }); } }); // GET /brain/documents/:id — 读取单个文档(含完整内容) router.get('/:id', (req, res) => { try { const row = req.db.prepare('SELECT * FROM documents WHERE document_id = ?').get(req.params.id); if (!row) { return res.status(404).json({ error: true, message: 'Document not found' }); } if (row.tags) { try { row.tags = JSON.parse(row.tags); } catch (_e) {} } res.json({ data: row }); } catch (err) { res.status(500).json({ error: true, message: err.message }); } }); // POST /brain/documents — 创建新文档 router.post('/', (req, res) => { try { const { persona_id, parent_id, path, title, content, content_type, source, tags } = req.body; if (!title) { return res.status(400).json({ error: true, message: 'Missing required field: title' }); } const document_id = `DOC-${Date.now()}-${crypto.randomBytes(4).toString('hex')}`; const docPath = path || (parent_id ? `${parent_id}/${title}` : `/root/${title}`); req.db.prepare(` INSERT INTO documents (document_id, persona_id, parent_id, path, title, content, content_type, source, tags) VALUES (?, ?, ?, ?, ?, ?, ?, ?, ?) `).run( document_id, persona_id || 'SY-001', parent_id || null, docPath, title, content || '', content_type || 'markdown', source || 'api', tags ? JSON.stringify(tags) : null ); const created = req.db.prepare('SELECT * FROM documents WHERE document_id = ?').get(document_id); res.status(201).json({ data: created, message: 'Document created' }); } catch (err) { res.status(500).json({ error: true, message: err.message }); } }); // PUT /brain/documents/:id — 更新文档 router.put('/:id', (req, res) => { try { const existing = req.db.prepare('SELECT * FROM documents WHERE document_id = ?').get(req.params.id); if (!existing) { return res.status(404).json({ error: true, message: 'Document not found' }); } const { title, content, parent_id, path, tags } = req.body; const updates = []; const params = []; if (title !== undefined) { updates.push('title = ?'); params.push(title); } if (content !== undefined) { updates.push('content = ?'); params.push(content); } if (parent_id !== undefined) { updates.push('parent_id = ?'); params.push(parent_id); } if (path !== undefined) { updates.push('path = ?'); params.push(path); } if (tags !== undefined) { updates.push('tags = ?'); params.push(JSON.stringify(tags)); } if (updates.length > 0) { params.push(req.params.id); req.db.prepare(`UPDATE documents SET ${updates.join(', ')}, updated_at = CURRENT_TIMESTAMP WHERE document_id = ?`).run(...params); } const updated = req.db.prepare('SELECT * FROM documents WHERE document_id = ?').get(req.params.id); res.json({ data: updated, message: 'Document updated' }); } catch (err) { res.status(500).json({ error: true, message: err.message }); } }); // DELETE /brain/documents/:id — 软删除 router.delete('/:id', (req, res) => { try { const existing = req.db.prepare('SELECT * FROM documents WHERE document_id = ?').get(req.params.id); if (!existing) { return res.status(404).json({ error: true, message: 'Document not found' }); } const deletedId = `deleted_${req.params.id}`; req.db.prepare('UPDATE documents SET document_id = ?, path = ? WHERE document_id = ?') .run(deletedId, `/trash/${req.params.id}`, req.params.id); res.json({ data: { document_id: deletedId }, message: 'Document moved to trash' }); } catch (err) { res.status(500).json({ error: true, message: err.message }); } }); module.exports = router;