Files
DeskcommCRM/hooks/useAdminInboxRealtime.ts
T
Rafael MelgaçoandClaude Opus 4.7 a3d6bcc6bb feat(EPIC-11): admin inbox cross-tenant + realtime fanout [wave 3]
GET /api/v1/admin/inbox/conversations: requirePlatformAdmin, service-role
cross-tenant query joining organizations + contacts + last_message_preview
+ unread_count. Cursor pagination by last_inbound_at desc.

GET /api/v1/admin/inbox/conversations/[id]: detail with last 50 messages.

useAdminInboxRealtime subscribes to postgres_changes on messages INSERT
(no org filter — admin sees all tenants). TanStack invalidation on event.

UI: 3-col layout reusing MessageBubble from EPIC-03. TenantBadge in
every list item + thread header. Composer disabled (read-only) — agent
response only via Impersonate (S-11.07).

Audit: platform_admin.inbox_listed + platform_admin.conversation_viewed
(lightweight, tenant_id only — no PII).

Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
2026-04-29 13:22:44 -03:00

34 lines
1.0 KiB
TypeScript

"use client";
import { useCallback } from "react";
import { useQueryClient } from "@tanstack/react-query";
import { useRealtimeChannel } from "@/hooks/realtime/useRealtimeChannel";
/**
* Subscribes to postgres_changes on `messages` (INSERT) without org_id filter —
* platform admin sees all tenants in real-time.
*
* NOTE: postgres_changes requires Supabase Realtime to be enabled and the
* `messages` table added to the `supabase_realtime` publication.
* If Realtime is not enabled for this table, events will be silently dropped;
* the list will still refresh on focus (staleTime = 10s).
*/
export function useAdminInboxRealtime() {
const qc = useQueryClient();
const onChange = useCallback(() => {
void qc.invalidateQueries({ queryKey: ["admin", "inbox"] });
}, [qc]);
return useRealtimeChannel({
name: "admin-inbox-realtime",
postgresChanges: {
event: "INSERT",
schema: "public",
table: "messages",
// No filter — cross-tenant intentional for platform admin
},
onChange,
enabled: true,
});
}