diff --git a/api/src/routes/auth.js b/api/src/routes/auth.js index a4f3e19..8dec02a 100644 --- a/api/src/routes/auth.js +++ b/api/src/routes/auth.js @@ -101,16 +101,36 @@ async function authRoutes(app) { return { status: 'not_implemented', message: 'WebAuthn biometric auth coming soon.' }; }); - // Delete account - app.delete('/auth/account', { preHandler: [async (req) => { await req.jwtVerify(); }] }, async (req, reply) => { + // Delete account (GDPR + Google Play requirement) + app.delete("/auth/account", { preHandler: [async (req) => { await req.jwtVerify(); }] }, async (req, reply) => { const uid = req.user.id; - await app.db.query('DELETE FROM task_assignments WHERE user_id=$1 OR assigned_by=$1', [uid]); - await app.db.query('DELETE FROM tasks WHERE user_id=$1', [uid]); - await app.db.query('DELETE FROM task_groups WHERE user_id=$1', [uid]); - await app.db.query('DELETE FROM goals WHERE user_id=$1', [uid]); - await app.db.query('DELETE FROM sessions WHERE user_id=$1', [uid]); - await app.db.query('DELETE FROM users WHERE id=$1', [uid]); - return reply.send({ data: { deleted: true } }); + await app.db.query("DELETE FROM task_comments WHERE user_id=$1", [uid]); + await app.db.query("DELETE FROM subtasks WHERE assigned_to=$1", [uid]); + await app.db.query("DELETE FROM task_collaboration WHERE from_user_id=$1 OR to_user_id=$1", [uid]); + await app.db.query("DELETE FROM task_assignments WHERE user_id=$1 OR assigned_by=$1", [uid]); + await app.db.query("DELETE FROM push_subscriptions WHERE user_id=$1", [uid]); + await app.db.query("DELETE FROM goals WHERE user_id=$1", [uid]); + await app.db.query("DELETE FROM connectors WHERE user_id=$1", [uid]); + await app.db.query("DELETE FROM tasks WHERE user_id=$1", [uid]); + await app.db.query("DELETE FROM task_groups WHERE user_id=$1", [uid]); + await app.db.query("DELETE FROM users WHERE id=$1", [uid]); + return reply.send({ data: { deleted: true, message: "Account and all data permanently deleted" } }); + }); + + // Alias: /auth/delete-account (backward compat) + app.delete("/auth/delete-account", { preHandler: [async (req) => { await req.jwtVerify(); }] }, async (req, reply) => { + const uid = req.user.id; + await app.db.query("DELETE FROM task_comments WHERE user_id=$1", [uid]); + await app.db.query("DELETE FROM subtasks WHERE assigned_to=$1", [uid]); + await app.db.query("DELETE FROM task_collaboration WHERE from_user_id=$1 OR to_user_id=$1", [uid]); + await app.db.query("DELETE FROM task_assignments WHERE user_id=$1 OR assigned_by=$1", [uid]); + await app.db.query("DELETE FROM push_subscriptions WHERE user_id=$1", [uid]); + await app.db.query("DELETE FROM goals WHERE user_id=$1", [uid]); + await app.db.query("DELETE FROM connectors WHERE user_id=$1", [uid]); + await app.db.query("DELETE FROM tasks WHERE user_id=$1", [uid]); + await app.db.query("DELETE FROM task_groups WHERE user_id=$1", [uid]); + await app.db.query("DELETE FROM users WHERE id=$1", [uid]); + return reply.send({ data: { deleted: true, message: "Account and all data permanently deleted" } }); }); // OAuth initiate routes moved to ./oauth.js diff --git a/api/src/routes/errors.js b/api/src/routes/errors.js index 8bcb919..a88cef4 100644 --- a/api/src/routes/errors.js +++ b/api/src/routes/errors.js @@ -1,6 +1,17 @@ // Task Team — Error Tracking — 2026-03-29 async function errorRoutes(app) { + await app.db.query(` + CREATE TABLE IF NOT EXISTS error_logs ( + id SERIAL PRIMARY KEY, + level VARCHAR(20) DEFAULT 'error', + message TEXT, + stack TEXT, + url TEXT, + method VARCHAR(10), + metadata JSONB DEFAULT '{}', + created_at TIMESTAMP DEFAULT NOW() + ); CREATE INDEX IF NOT EXISTS idx_errors_created ON error_logs(created_at DESC); `);