diff --git a/persona-brain-db/api/routes/documents.js b/persona-brain-db/api/routes/documents.js new file mode 100644 index 0000000..2482f3a --- /dev/null +++ b/persona-brain-db/api/routes/documents.js @@ -0,0 +1,134 @@ +/** + * 文档 · /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;