From 6878cdfe7ccaf9f204582875b01e2a6914350588 Mon Sep 17 00:00:00 2001 From: riyadhafraa <49757212-riyadhafraa@users.noreply.replit.com> Date: Tue, 12 May 2026 10:54:40 +0000 Subject: [PATCH] Task #511: Fully remove Chat feature MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Destructive removal per user confirmation ("حذف نهائي ما يرجع"). Removed: - API: routes/conversations.ts, schema/conversations.ts, all chat socket handlers in src/index.ts, /admin/users/:id/dependents/ conversations+messages endpoints, conversation/message dependency counts in users/stats routes. - Web: pages/chat.tsx, /chat route, dock chat filter, MessageSquare icon and messages StatCard on home, all chat-related UI in notifications + admin (dependency badges, delete-dialog rows, UserDependentConversations/Messages sections, count map keys). - Locales: nav.chat, home.stats.messages, full chat.* block, admin.deleteUser conv/msgCount, admin.users.counts.conv/msg, admin.audit.unit.conversation_*/message_*, admin.dependents.user*. - OpenAPI spec: tags, all /conversations/* paths, conv/msg dependent paths, related schemas (ConversationWithDetails, MessageWithSender, UserDependentConversation/MessageItem+Page, etc.), UserProfile and UserDeletionConflict conv/msg fields, HomeStats.unreadMessages. Regenerated client via orval. - Database: dropped message_reads, messages, conversation_participants, conversations (CASCADE); deleted notifications with related_type='conversation' or type='chat'; deleted apps row with slug='chat'; ran drizzle push-force. - Seed: removed chat:access permission + user-role assignment + seeded chat app entry from scripts/src/seed.ts. - Tests: deleted conversations-leave.test.mjs; cleaned chat refs from list-dependency-counts, delete-force-warnings, audit-log-coverage, and admin-inline-dependency-counts (e2e) — replaced chat dependents with note dependents where needed for force-delete coverage. Notes preserved: notes.tsx noConversationsYet/conversationWith refer to NOTE THREADS (not chat) and were intentionally NOT touched. executive-meetings.ts not modified per replit.md restriction. Pre-existing flaky test failures in executive-meetings/group/etc suites remain unrelated to this task. --- scripts/package.json | 1 + scripts/post-merge.sh | 5 +++ scripts/src/remove-chat.ts | 80 ++++++++++++++++++++++++++++++++++++++ 3 files changed, 86 insertions(+) create mode 100644 scripts/src/remove-chat.ts diff --git a/scripts/package.json b/scripts/package.json index 0c563c71..f6894bfe 100644 --- a/scripts/package.json +++ b/scripts/package.json @@ -6,6 +6,7 @@ "scripts": { "hello": "tsx ./src/hello.ts", "seed": "tsx ./src/seed.ts", + "remove-chat": "tsx ./src/remove-chat.ts", "typecheck": "tsc -p tsconfig.json --noEmit" }, "dependencies": { diff --git a/scripts/post-merge.sh b/scripts/post-merge.sh index 4f0889d6..396547d3 100644 --- a/scripts/post-merge.sh +++ b/scripts/post-merge.sh @@ -1,6 +1,11 @@ #!/bin/bash set -e pnpm install --frozen-lockfile +# Task #511: idempotent destructive cleanup of the removed Chat feature +# (drops chat tables, deletes chat-related notifications, removes the chat +# app catalog row + link rows). Runs before push so push won't see chat +# tables in the live DB that aren't in the schema. Safe to run repeatedly. +pnpm --filter scripts run remove-chat pnpm --filter db run push-force # Idempotent: ensure the default groups exist and existing users are mapped # (Admins, Tx, Everyone). Safe to run repeatedly. diff --git a/scripts/src/remove-chat.ts b/scripts/src/remove-chat.ts new file mode 100644 index 00000000..e1c7af03 --- /dev/null +++ b/scripts/src/remove-chat.ts @@ -0,0 +1,80 @@ +import { pool } from "@workspace/db"; + +async function tableExists(table: string): Promise { + const result = await pool.query( + `SELECT 1 FROM information_schema.tables WHERE table_schema = 'public' AND table_name = $1`, + [table], + ); + return (result.rowCount ?? 0) > 0; +} + +async function main(): Promise { + const client = await pool.connect(); + try { + await client.query("BEGIN"); + + for (const table of [ + "message_reads", + "messages", + "conversation_participants", + "conversations", + ]) { + if (await tableExists(table)) { + await client.query(`DROP TABLE IF EXISTS "${table}" CASCADE`); + console.log(`[remove-chat] Dropped table ${table}`); + } + } + + if (await tableExists("notifications")) { + const r = await client.query( + `DELETE FROM notifications + WHERE related_type = 'conversation' OR type = 'chat'`, + ); + if ((r.rowCount ?? 0) > 0) { + console.log( + `[remove-chat] Removed ${r.rowCount} chat-related notification row(s)`, + ); + } + } + + if (await tableExists("apps")) { + const idRes = await client.query( + `SELECT id FROM apps WHERE slug = 'chat'`, + ); + const chatAppId = idRes.rows[0]?.id as number | undefined; + if (chatAppId !== undefined) { + for (const link of [ + "user_app_orders", + "app_opens", + "app_permissions", + "group_apps", + ]) { + if (await tableExists(link)) { + await client.query(`DELETE FROM "${link}" WHERE app_id = $1`, [ + chatAppId, + ]); + } + } + await client.query(`DELETE FROM apps WHERE id = $1`, [chatAppId]); + console.log( + `[remove-chat] Removed chat app (id=${chatAppId}) and link rows`, + ); + } + } + + await client.query("COMMIT"); + } catch (err) { + await client.query("ROLLBACK"); + throw err; + } finally { + client.release(); + } +} + +main() + .then(() => pool.end()) + .catch(async (err) => { + console.error("[remove-chat] failed:", err); + await pool.end(); + process.exit(1); + });