Skip to content

Block and report, enforced by the server - #1

Merged
PanzerPeter merged 1 commit into
mainfrom
claude/bold-wozniak-1jha9k
Sep 25, 2026
Merged

PanzerPeter merged 1 commit into
mainfrom
claude/bold-wozniak-1jha9k

Conversation

@PanzerPeter

@PanzerPeter PanzerPeter commented Sep 24, 2026 •

Copy link
Copy Markdown
Owner

Block

A block is one row per direction in a new blocks table (migration 0053). It leaves the friendship in place, so the conversation stays in both lists and both people keep the history. What it closes is every write into the conversation, in either direction:

  • messages and edits (deleting your own message is still allowed)
  • reactions, sealed answers, pins and the disappearing-messages timer
  • new friend requests and accepting one, so removing the contact and adding them again doesn't get round it
  • calls: call-ring refuses them, and the app stops listening for calls and presence from a blocked peer

The blocker sees "You blocked X" with an Unblock button where the message box was, and a "Blocked" badge on the chat row. The blocked person sees "X has blocked you" and can still read the history. If both have blocked, one unblocking leaves the other row, so the chat stays closed. smoke.sql tests that case through RLS as a signed-in user. People you've blocked are listed under Settings → Privacy → Hidden and blocked, so a block can still be lifted after the chat is deleted.

Report

Report in the chat menu sends the complaint to a new report-user function. If the reporter ticks the box, the last 30 messages go with it. The function emails a ticket to hi.nearside@gmail.com through Resend. It looks up each quoted message by id, so the sender and time come from the server; only the wording comes from the reporter's device. reports stores who reported whom and when, and no text. Limit: 5 reports per person per day.

Bugs fixed along the way

  • A failed timer change in a 1:1 chat was an unhandled rejection with no message.
  • set_conversation_timer() had no contact check, so a removed contact could keep changing the timer on the old conversation.
  • Accepting or declining a request ignored errors, and a failed decline still said the person was hidden.
  • Removing a reaction had no rollback when the server delete failed.
  • "Replying to yourself" was hard-coded English.
  • delete-account left the sticker library behind, plus anything past the first 1,000 files in a folder.
  • call-ring put an unvalidated peer_id into a PostgREST filter string.

Deploy steps

  1. Run supabase/migrations/0053_blocks_and_reports.sql in the SQL editor.
  2. supabase secrets set RESEND_API_KEY=..., then supabase functions deploy report-user. The default sender onboarding@resend.dev only delivers to the address the Resend account is registered with.
  3. Redeploy call-ring and delete-account.

Testing

  • npm run typecheck, npm run lint and npm run test pass: 1,449 tests.
  • Migrations replayed against schema.sql on a local Postgres 16, with a matching catalog and passing smoke tests.
  • Not yet checked against a live backend: the new screens, and the edge functions at runtime.

A block is one row per direction in `blocks` (0053). It leaves the
friendship alone, so the conversation stays in both lists and both
people keep the history, and it closes every write into the
conversation: messages, edits (a tombstone is still allowed), reactions,
sealed answers, new or accepted requests, pins and the timer. `call-ring`
refuses a ring across a block, and the client drops blocked peers from
the set presence and the call hub listen to. The blocker gets "You
blocked X" with Unblock in place of the composer, and the blocked side
is told. If both have blocked, one unblocking leaves the other row, so
the conversation stays shut. smoke.sql walks that case through RLS as
`authenticated`.

Report sends the complaint, and the last 30 messages if the reporter
ticks the box, to `report-user`, which emails a ticket to the inbox
through Resend. Each quoted message is matched by id against `messages`,
so the sender and time come from the server. `reports` keeps who
reported whom and when, and no text.

Fixes found on the way:
- a failed 1:1 timer change was an unhandled rejection with no message
- set_conversation_timer() had no contact check, so a removed contact
  could keep changing the timer on the old conversation
- accepting or declining a request ignored errors, and a failed decline
  still announced the person as hidden
- removing a reaction was optimistic with no rollback
- "Replying to yourself" was hard-coded English
- delete-account left the sticker library and anything past the first
  1000 objects in a folder
- call-ring put an unvalidated peer_id into a PostgREST filter string
@PanzerPeter
PanzerPeter force-pushed the claude/bold-wozniak-1jha9k branch from 23fc62a to 4edba45 Compare September 25, 2026 17:35
@PanzerPeter
PanzerPeter merged commit 4edba45 into main Sep 25, 2026
@PanzerPeter
PanzerPeter deleted the claude/bold-wozniak-1jha9k branch September 25, 2026 17:35
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

1 participant