fix(rbac): sales/operational roles see deal alerts; quiet admin-only onboarding probe
UAT findings from the Sales-role functional walkthrough: F1 — The deal-alert feed (stale interest, hot-lead-silent, EOI unsigned, signer overdue, reservation-needs-agreement, berth stalled, expense dupes) was gated on admin.view_audit_log, so salespeople got a 403 on the Alerts inbox. None of the 9 alert rules are audit/security signals — they're all operational — so re-gate the list route to interests.view (sales, director, viewer get it; external residential partners don't) and hide the Alerts section in the inbox for users without it instead of letting the query 403. F2 — Non-admins triggered /api/v1/admin/onboarding/status (admin-only) and ate a 403 in the console. Make useOnboardingStatus strictly opt-in (enabled: opts.enabled === true) so a transient/stale isSuperAdmin during permission hydration can't fire the privileged request. 1664 vitest pass; tsc + eslint clean. Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
This commit is contained in:
@@ -5,11 +5,13 @@ import { listAlertsForPort } from '@/lib/services/alerts.service';
|
||||
|
||||
type AlertStatus = 'open' | 'dismissed' | 'resolved';
|
||||
|
||||
// Tier-4 (authz-auditor): alerts include permission_denied + audit-adjacent
|
||||
// signals. Gated on admin.view_audit_log - same permission the audit log
|
||||
// page uses.
|
||||
// The alert feed is entirely operational/deal signals (stale interest, hot lead
|
||||
// silent, EOI unsigned, signer overdue, reservation needs agreement, berth
|
||||
// stalled, duplicate/unscanned expense) — there are no audit/security alert
|
||||
// rules. Gated on interests.view so the operational roles that act on these
|
||||
// (sales, director, viewer) see them; external residential partners don't.
|
||||
export const GET = withAuth(
|
||||
withPermission('admin', 'view_audit_log', async (req: NextRequest, ctx) => {
|
||||
withPermission('interests', 'view', async (req: NextRequest, ctx) => {
|
||||
const url = new URL(req.url);
|
||||
const status = (url.searchParams.get('status') ?? 'open') as AlertStatus;
|
||||
|
||||
|
||||
Reference in New Issue
Block a user