Chat moderation: Report message + Block user (App Store guideline 1.2)

Apple requires user-generated-content apps to offer a way to report
objectionable content and block abusive users. The chat had neither, which is
the #1 rejection cause for messaging apps. Added both, server-enforced.

Server:
- schema: message_reports + user_blocks tables.
- repos: reports {add,listForTeam,setStatus}, blocks {add,remove,has,listFor},
  users.adminsOf(); thread + threadByConversation now exclude blocked senders in
  SQL (like message_hidden) so the LIMIT counts only visible rows (no pagination
  stall).
- routes: POST /api/messages/report, /api/users/block|unblock, GET
  /api/users/blocked, GET /api/reports + POST /api/reports/resolve (admin only).
- enforcement: a blocked sender's DM/group messages are persisted but not
  delivered (no live push, no background notification) to anyone who blocked
  them; blocked users can't ring you (/api/calls/dm/start + /api/calls/invite);
  admins can delete reported content (delete route now allows role=admin).

Client (home.html, all platforms via the web UI — no rebuild):
- message menu gains Report (canned-reason picker) + Block/Unblock.
- profile menu: "Blocked users" manager (list + unblock) for everyone;
  "Reported messages" review (delete / block / resolve) for admins.
- blocked DMs hidden from the sidebar; block list loaded on boot.
- reports route to the workspace's OWN admins (org-internal moderation).

Verified: db-smoke 22/22 + a new moderation suite 12/12 (report+admin-list,
non-admin 403, block hides post-block history but sender still sees sent,
blocked call 403, unblock restores history + calling). New flag/ban icons added.

Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
This commit is contained in:
2026-08-19 19:46:22 +05:30
parent 7e3a94b04c
commit e4d361f298
5 changed files with 236 additions and 11 deletions
+25
View File
@@ -163,6 +163,31 @@ CREATE TABLE IF NOT EXISTS message_reactions (
PRIMARY KEY (message_id, user_id, emoji)
);
-- UGC moderation (App Store Review guideline 1.2): report a message + block a user.
-- Reports are workspace-internal — surfaced to the tenant's admins, who can delete the message / act.
CREATE TABLE IF NOT EXISTS message_reports (
id TEXT PRIMARY KEY,
team_id TEXT NOT NULL,
message_id TEXT NOT NULL,
reporter_id TEXT NOT NULL,
reported_id TEXT NOT NULL,
reason TEXT,
snippet TEXT,
created_at BIGINT NOT NULL,
status TEXT NOT NULL DEFAULT 'open'
);
CREATE INDEX IF NOT EXISTS idx_reports_team ON message_reports(team_id, created_at);
-- A one-directional block: blocker no longer receives the blocked user's messages or calls.
CREATE TABLE IF NOT EXISTS user_blocks (
blocker_id TEXT NOT NULL,
blocked_id TEXT NOT NULL,
team_id TEXT NOT NULL,
created_at BIGINT NOT NULL,
PRIMARY KEY (blocker_id, blocked_id)
);
CREATE INDEX IF NOT EXISTS idx_blocks_blocker ON user_blocks(blocker_id);
CREATE TABLE IF NOT EXISTS attachments (
id TEXT PRIMARY KEY,
team_id TEXT NOT NULL,