fix(sidebar): gate outbox+webhook badge polls on INTERNAL scope (no more 403 spam)

This commit is contained in:
Александр Зимин
2026-05-14 22:41:28 +00:00
parent 55a1171ac4
commit ac74a8fbd9
3 changed files with 68 additions and 8 deletions
@@ -17,6 +17,7 @@ import { useCanMutate } from '@/auth/useCanMutate'
import {
useCanReviewRecord,
useCanReviewSchema,
useHasInternalScope,
} from '@/auth/usePermissions'
import {
useDictionaries,
@@ -84,10 +85,13 @@ export function Sidebar() {
// Reviews badge — суммирует record-reviews + schema-reviews pending queues
// через size=1 paged запросы. Gated на authenticated.
const reviews = useReviewsBadgeCount(auth.isAuthenticated)
// Outbox/Webhooks badges — light periodic poll. Backend гейтит, поэтому
// anonymous safe (просто 401 проигнорируется).
const outboxStats = useOutboxStats()
const webhooks = useWebhookSubscriptions()
// Outbox/Webhooks badges — light periodic poll. Backend гейтит INTERNAL
// scope: пользователь без нужной роли получает 403 на каждый poll. Гейтим
// на frontend через useHasInternalScope чтобы не спамить console 403'ами
// на каждой странице. Для PUBLIC users badge остаётся пустым (не false-zero).
const hasInternal = useHasInternalScope()
const outboxStats = useOutboxStats(hasInternal)
const webhooks = useWebhookSubscriptions(hasInternal)
const dictsCount = dictsQuery.data?.length ?? 0
const myDraftsCount =
@@ -453,8 +457,10 @@ export function MobileSidebar({ open, onClose }: { open: boolean; onClose: () =>
const myDrafts = useMyDrafts(0, 1)
const mySchemaDrafts = useMySchemaDrafts(0, 1)
const reviews = useReviewsBadgeCount(auth.isAuthenticated)
const outboxStats = useOutboxStats()
const webhooks = useWebhookSubscriptions()
// Same INTERNAL-scope gate as desktop Sidebar (см. line ~92).
const hasInternal = useHasInternalScope()
const outboxStats = useOutboxStats(hasInternal)
const webhooks = useWebhookSubscriptions(hasInternal)
const dictsCount = dictsQuery.data?.length ?? 0
const myDraftsCount =