// Task Team — Tasks CRUD — 2026-03-29 async function taskRoutes(app) { // List tasks app.get('/tasks', async (req, reply) => { const { status, group_id, limit = 50, offset = 0 } = req.query; let query = 'SELECT t.*, tg.name as group_name, tg.color as group_color, tg.icon as group_icon FROM tasks t LEFT JOIN task_groups tg ON t.group_id = tg.id WHERE 1=1'; const params = []; if (status) { params.push(status); query += ` AND t.status = $${params.length}`; } if (group_id) { params.push(group_id); query += ` AND t.group_id = $${params.length}`; } query += ' ORDER BY t.scheduled_at ASC NULLS LAST, t.priority DESC, t.created_at DESC'; params.push(limit); query += ` LIMIT $${params.length}`; params.push(offset); query += ` OFFSET $${params.length}`; const { rows } = await app.db.query(query, params); return { data: rows, total: rows.length }; }); // Get single task app.get('/tasks/:id', async (req) => { const { rows } = await app.db.query( 'SELECT t.*, tg.name as group_name, tg.color as group_color FROM tasks t LEFT JOIN task_groups tg ON t.group_id = tg.id WHERE t.id = $1', [req.params.id] ); if (!rows.length) throw { statusCode: 404, message: 'Task not found' }; return { data: rows[0] }; }); // Create task app.post('/tasks', async (req) => { const { title, description, status, group_id, priority, scheduled_at, due_at, assigned_to } = req.body; const { rows } = await app.db.query( `INSERT INTO tasks (title, description, status, group_id, priority, scheduled_at, due_at, assigned_to) VALUES ($1, $2, $3, $4, $5, $6, $7, $8) RETURNING *`, [title, description || '', status || 'pending', group_id, priority || 'medium', scheduled_at, due_at, assigned_to || []] ); return { data: rows[0] }; }); // Update task app.put('/tasks/:id', async (req) => { const fields = req.body; const sets = []; const params = []; let i = 1; for (const [key, value] of Object.entries(fields)) { if (['title','description','status','group_id','priority','scheduled_at','due_at','assigned_to','completed_at'].includes(key)) { sets.push(`${key} = $${i}`); params.push(value); i++; } } if (fields.status === 'completed' && !fields.completed_at) { sets.push(`completed_at = NOW()`); } sets.push(`updated_at = NOW()`); params.push(req.params.id); const { rows } = await app.db.query( `UPDATE tasks SET ${sets.join(', ')} WHERE id = $${i} RETURNING *`, params ); if (!rows.length) throw { statusCode: 404, message: 'Task not found' }; return { data: rows[0] }; }); // Delete task app.delete('/tasks/:id', async (req) => { const { rowCount } = await app.db.query('DELETE FROM tasks WHERE id = $1', [req.params.id]); if (!rowCount) throw { statusCode: 404, message: 'Task not found' }; return { status: 'deleted' }; }); // Task comments app.get('/tasks/:id/comments', async (req) => { const { rows } = await app.db.query( 'SELECT * FROM task_comments WHERE task_id = $1 ORDER BY created_at ASC', [req.params.id] ); return { data: rows }; }); app.post('/tasks/:id/comments', async (req) => { const { content, is_ai } = req.body; const { rows } = await app.db.query( 'INSERT INTO task_comments (task_id, content, is_ai) VALUES ($1, $2, $3) RETURNING *', [req.params.id, content, is_ai || false] ); return { data: rows[0] }; }); } module.exports = taskRoutes;