Feature: feat/portal-ui-redesign to dev - #468
Conversation
Add a "bug_tester" staff role so people can test the admin side without being able to change anything. - isStaffRole is now an allow-list (super_admin, admin, moderator) instead of "anything but volunteer", so a new role can never become full staff by default - isAdmin lets a bug tester through for queries only; any mutation behind it (and isSuperAdmin, built on it) is refused with a read-only message. isScanner does the same, so the scan desks are viewable but nothing can be checked in - callerIsAdmin stays staff-only: bug testers get no widened public responses and cannot act on other leaders' initiatives - resume and bootcamp file routes use isStaffRole, so bug testers cannot download resumes - portal: bug testers see the admin nav (minus the staff-only Staff & Roles and project-lead pages) with a read-only banner; super admins can grant the role from Staff & Roles Every admin query was checked for writes before allowing them; none write. Tests cover queries allowed, mutations refused (full staff, super admin and scanner) and the nav.
The API already refuses every write from a bug tester; the admin UI now says so instead of letting the click fail silently. useReadOnly() is true only for a bug tester, and every control whose purpose is a write (create, save, delete, toggles, check-in, scanning, sending, judging and results controls, membership grants, uploads) renders disabled with a "Read-only access" tooltip. Reads stay usable: tabs, filters, search, pagination, exports, QR viewing and opening detail views. Enter-to-submit on the manual check-in fields is guarded too. The banner copy now says buttons are greyed out.
Read-only bug tester role for QA
There was a problem hiding this comment.
Cursor Bugbot has reviewed your changes using default effort and found 1 potential issue.
❌ Bugbot Autofix is OFF. To automatically fix reported issues with cloud agents, enable autofix in the Cursor dashboard.
Reviewed by Cursor Bugbot for commit 6f12ff8. Configure here.
| // Staff only: this widens public responses and, through isProjectLeader, | ||
| // lets the caller act on other leaders' initiatives. A bug tester gets | ||
| // neither. | ||
| const isStaff = !!admin && isStaffRole(admin.role) && !isExpiredAdmin(admin); |
There was a problem hiding this comment.
Testers miss staff-only edition data
Medium Severity
canViewAdmin lets a bug_tester into admin tools and listAll, but callerIsAdmin still treats them as the public. hackathon.getById then 404s draft editions they just opened, hackathon.list hides draft and hidden editions on Judging, and hackathon.projects strips drafts. Testers cannot actually review those staff-only screens.
Reviewed by Cursor Bugbot for commit 6f12ff8. Configure here.


Automated PR tracking changes from
feat/portal-ui-redesignintodev.Note
Medium Risk
Changes authorization gates and staff role classification across API middleware and many admin UI entry points; incorrect handling could grant writes to QA users or block legitimate staff.
Overview
Introduces a
bug_testeradmin role for read-only QA: they can run staff queries (including scan-desk reads) but every mutation behindisAdmin/isScanneris blocked in middleware with a clear read-only error. Super admins can assign the role via the staff API; the DB admin role enum is extended accordingly.Staff semantics are tightened:
isStaffRoleis now an explicit allow-list (super_admin,admin,moderator), so new roles likebug_testerdo not accidentally gain full staff powers. Portal context exposesisBugTester, andcallerIsAdminonly treats true staff as admins for widened responses.Portal UI lets bug testers open admin surfaces via
canViewAdmin/ nav (minus staff-only routes like/admin/staffand/lead), shows a read-only banner, and disables write controls withuseReadOnlyacross admin pages. Dashboard links to the admin panel for bug testers. API edge tests cover query access, mutation refusal, and super-admin isolation.Reviewed by Cursor Bugbot for commit 6f12ff8. Bugbot is set up for automated code reviews on this repo. Configure here.