Add activity monitor, family workspace, per-user rate limiting
- Activity monitor API: phone usage tracking with report/summary/daily/ai-analysis endpoints - Family workspace: shared task groups with member management - Per-user API rate limiting: JWT-based key generator with IP fallback - Also includes previously uncommitted spaced-repetition and admin routes Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
This commit is contained in:
67
api/src/routes/admin.js
Normal file
67
api/src/routes/admin.js
Normal file
@@ -0,0 +1,67 @@
|
||||
// Task Team — Admin Dashboard — 2026-03-30
|
||||
async function adminRoutes(app) {
|
||||
// User management
|
||||
app.get("/admin/users", async (req) => {
|
||||
const { rows } = await app.db.query(
|
||||
`SELECT u.id, u.email, u.name, u.phone, u.language, u.auth_provider, u.created_at,
|
||||
(SELECT count(*) FROM tasks WHERE user_id=u.id) as task_count,
|
||||
(SELECT count(*) FROM goals WHERE user_id=u.id) as goal_count
|
||||
FROM users u ORDER BY u.created_at DESC`
|
||||
);
|
||||
return { data: rows };
|
||||
});
|
||||
|
||||
app.delete("/admin/users/:id", async (req) => {
|
||||
await app.db.query("DELETE FROM users WHERE id = $1", [req.params.id]);
|
||||
return { status: "deleted" };
|
||||
});
|
||||
|
||||
// System analytics
|
||||
app.get("/admin/analytics", async (req) => {
|
||||
const { rows: overview } = await app.db.query(`
|
||||
SELECT
|
||||
(SELECT count(*) FROM users) as total_users,
|
||||
(SELECT count(*) FROM users WHERE created_at > NOW() - INTERVAL '7 days') as new_users_7d,
|
||||
(SELECT count(*) FROM tasks) as total_tasks,
|
||||
(SELECT count(*) FROM tasks WHERE status='completed' OR status='done') as completed_tasks,
|
||||
(SELECT count(*) FROM tasks WHERE created_at > NOW() - INTERVAL '24 hours') as tasks_today,
|
||||
(SELECT count(*) FROM goals) as total_goals,
|
||||
(SELECT count(*) FROM invitations WHERE status='accepted') as accepted_invites,
|
||||
(SELECT count(*) FROM task_comments WHERE is_ai=true) as ai_messages,
|
||||
(SELECT count(*) FROM error_logs WHERE created_at > NOW() - INTERVAL '24 hours') as errors_24h,
|
||||
(SELECT count(*) FROM projects) as total_projects
|
||||
`);
|
||||
|
||||
// Daily activity (last 7 days)
|
||||
const { rows: daily } = await app.db.query(`
|
||||
SELECT date_trunc('day', created_at)::date as day, count(*) as tasks_created
|
||||
FROM tasks WHERE created_at > NOW() - INTERVAL '7 days'
|
||||
GROUP BY 1 ORDER BY 1
|
||||
`);
|
||||
|
||||
return { data: { overview: overview[0], daily } };
|
||||
});
|
||||
|
||||
// Recent activity feed
|
||||
app.get("/admin/activity", async (req) => {
|
||||
const { rows } = await app.db.query(`
|
||||
(SELECT 'task_created' as type, title as detail, created_at FROM tasks ORDER BY created_at DESC LIMIT 5)
|
||||
UNION ALL
|
||||
(SELECT 'user_registered', email, created_at FROM users ORDER BY created_at DESC LIMIT 5)
|
||||
UNION ALL
|
||||
(SELECT 'goal_created', title, created_at FROM goals ORDER BY created_at DESC LIMIT 5)
|
||||
UNION ALL
|
||||
(SELECT 'invite_sent', invitee_email, created_at FROM invitations ORDER BY created_at DESC LIMIT 5)
|
||||
ORDER BY created_at DESC LIMIT 20
|
||||
`);
|
||||
return { data: rows };
|
||||
});
|
||||
|
||||
// Error log management
|
||||
app.delete("/admin/errors/clear", async (req) => {
|
||||
const { rowCount } = await app.db.query("DELETE FROM error_logs WHERE created_at < NOW() - INTERVAL '7 days'");
|
||||
return { status: "cleared", deleted: rowCount };
|
||||
});
|
||||
}
|
||||
|
||||
module.exports = adminRoutes;
|
||||
Reference in New Issue
Block a user