Skip to content

feat: push dispatch, file soft/hard-delete, push hygiene & coalescing#282

Merged
codebestia merged 4 commits into
codebestia:mainfrom
Chidimj:feat/push-delivery-file-hygiene
Jun 29, 2026
Merged

feat: push dispatch, file soft/hard-delete, push hygiene & coalescing#282
codebestia merged 4 commits into
codebestia:mainfrom
Chidimj:feat/push-delivery-file-hygiene

Conversation

@Chidimj

@Chidimj Chidimj commented Jun 29, 2026

Copy link
Copy Markdown
Contributor

Summary

Implements four related delivery-pipeline issues in a single cohesive PR.

  • Push dispatch on offline delivery (content-free) #236 – Content-free Web Push dispatched when recipient device has no active socket. Payload carries only { type, conversationId, messageId, count } — no ciphertext, no sender data. Client syncs and decrypts locally on open.
  • Push delivery hygiene: expiry + dead-subscription pruning #237 – Push delivery hygiene: 410/404 responses hard-delete the subscription row; transient failures (5xx) set a 5-minute backoff (disabled_at); last_used_at updated on every successful send; backoffs re-enabled by the background job.
  • Notification coalescing / rate limiting #239 – Notification coalescing: 2-second burst window per (deviceId, conversationId) collapses N messages into one push with accurate count. Per-device rate limit of one push per 30 seconds prevents spam.
  • File deletion: soft-delete + background hard-delete #231 – File soft-delete + background hard-delete: new files table tracks S3 objects; messages.file_id FK added; soft-delete fires on message retraction (REST + socket); background job hard-deletes from S3 when no live message reference remains (ref-counted). Idempotent — hard_deleted_at set only after successful S3 delete.

Changes

Path What
drizzle/0009_push_file_hygiene.sql Migration: files table, messages.file_id, push_subscriptions.last_used_at/disabled_at
src/db/schema.ts files table, fileId on messages, lastUsedAt/disabledAt on pushSubscriptions
src/services/pushNotification.ts New — offline dispatch, coalescing, rate-limit, hygiene (#236 #237 #239)
src/services/fileCleanup.ts New — soft-delete helper + background hard-delete job (#231)
src/services/deviceRevocation.ts isDeviceConnected() exported
src/socket/messaging.ts File record creation + push dispatch after send_message
src/routes/messages.ts softDeleteFile() called on REST message delete
src/index.ts startFileCleanupJob() wired at boot
src/__tests__/pushNotification.test.ts New — 9 tests covering #236 #237 #239
src/__tests__/fileCleanup.test.ts New — 5 tests covering #231
src/__tests__/messages.routes.test.ts Mock added for softDeleteFile

Test plan

  • 142/142 tests pass (pnpm test)
  • TypeScript compiles clean (tsc --noEmit)
  • Push fires only when device offline (connected devices skipped)
  • Payload verified content-free in test assertions
  • 410/404 prunes subscription; 5xx sets disabled_at
  • Burst of 3 messages → single push with count: 3
  • File soft-delete only when no live message refs remain
  • S3 hard-delete skipped on error; hard_deleted_at not set → safe retry

Closes #231
Closes #236
Closes #237
Closes #239

Chidimj and others added 2 commits June 29, 2026 07:13
Closes codebestia#231, codebestia#236, codebestia#237, codebestia#239

codebestia#236: content-free web push to offline devices after send_message
codebestia#237: prune 410/404 subscriptions, backoff on transient failures, lastUsedAt tracking
codebestia#239: 2s coalesce window per device+conversation, 30s per-device rate limit
codebestia#231: files table, soft-delete on retraction, background hard-delete S3 job
@drips-wave

drips-wave Bot commented Jun 29, 2026

Copy link
Copy Markdown

@Chidimj Great news! 🎉 Based on an automated assessment of this PR, the linked Wave issue(s) no longer count against your application limits.

You can now already apply to more issues while waiting for a review of this PR. Keep up the great work! 🚀

Learn more about application limits

@codebestia

Copy link
Copy Markdown
Owner

Hello @Chidimj
Please fix the CI and format the codebase.
Thanks

@codebestia

Copy link
Copy Markdown
Owner

/home/runner/work/clicked/clicked/apps/backend/src/socket/messaging.ts
Error: 188:9 error 'recipientDeviceIds' is assigned a value but never used @typescript-eslint/no-unused-vars

1 Error to fix

@codebestia codebestia left a comment

Copy link
Copy Markdown
Owner

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

LGTM!
Thank you for contribution.

@codebestia codebestia merged commit 0a9321a into codebestia:main Jun 29, 2026
2 checks passed
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

2 participants