595ca06a57
## Socket.IO broadcasts (core task): - POST /users/:id/roles: uses .returning() to emit apps_changed only when row inserted - DELETE /users/:id/roles/:roleName: uses .returning() to emit only when row deleted - Added emitAppsChangedToRoleHolders(roleId) helper to realtime.ts - New role-permission endpoints in roles.ts, emit only on effective changes: - GET /roles/:id/permissions — list permissions for a role - POST /roles/:id/permissions — assign; emits to role holders on actual insert - DELETE /roles/:id/permissions/:permId — remove; emits only if row was deleted ## Bug fix: admin panel not showing disabled apps - Added GET /api/admin/apps (requireAdmin) returning ALL apps from DB - Updated admin.tsx: useQuery → /api/admin/apps with ADMIN_APPS_KEY constant - All admin.tsx mutation handlers invalidate ADMIN_APPS_KEY ## UI fix: disabled app cards nearly invisible (opacity-60 on glass) - Gray background + grayscale icon + muted text + stronger Disabled badge Replit-Task-Id: f439ec75-bcd5-4030-8ee1-83a5d976f1a1 ## DB: removed 11 duplicate rows from app_permissions table