Context
PR #154 introduced is_staff_user as the canonical staff classification property (covers staff_role, is_staff, and is_superuser). The PR migrated ticket views, and PR #174 (post-merge fixes) completed the migration for users/views.py, users/models.py methods, and the HTMX path. ~20 locations across the codebase still use the old ad-hoc pattern.
Remaining Locations
Decorators (security-critical — highest priority)
Context processors / middleware
Views
Serializers
Notes
- The decorators are the most important — they gate every staff-only endpoint.
billing_staff_required uses staff_role in allowed_roles without checking is_staff, while can_manage_financial_data requires is_staff=True first. These two enforcement paths should be aligned.
settings/views.py defines a local function also named is_staff_user that shadows the model property — this should be deleted and replaced with lambda u: getattr(u, 'is_staff_user', False).
- Consider whether decorators should use
user.is_staff_user directly or maintain role-specific checks (e.g., billing_staff_required only allows admin/billing/manager roles).
Context
PR #154 introduced
is_staff_useras the canonical staff classification property (coversstaff_role,is_staff, andis_superuser). The PR migrated ticket views, and PR #174 (post-merge fixes) completed the migration forusers/views.py,users/models.pymethods, and the HTMX path. ~20 locations across the codebase still use the old ad-hoc pattern.Remaining Locations
Decorators (security-critical — highest priority)
apps/common/decorators.py:50—staff_requiredapps/common/decorators.py:89—staff_required_strictapps/common/decorators.py:110—billing_staff_requiredapps/common/decorators.py:132—support_staff_requiredapps/common/decorators.py:158—customer_or_staff_requiredapps/common/decorators.py:175—can_edit_proformaapps/common/decorators.py:187—can_create_internal_notesapps/common/decorators.py:195—can_view_internal_notesContext processors / middleware
apps/common/context_processors.py:144—current_customerapps/common/context_processors.py:172—navigation_dropdownsapps/common/middleware.py:761— staff detectionViews
apps/billing/views.py:325,327,459,461,582,584,789— multiple staff checks + template contextis_staff_userkey usesrequest.user.is_staffapps/domains/views.py:69,309—can_manageflagsapps/provisioning/service_views.py:67,104—can_manageflagsapps/orders/views.py:1160— staff checkapps/settings/views.py:42-44— localis_staff_userfunction that only checksis_staff, shadows model propertySerializers
apps/api/tickets/serializers.py:155,167— staff checkNotes
billing_staff_requiredusesstaff_role in allowed_roleswithout checkingis_staff, whilecan_manage_financial_datarequiresis_staff=Truefirst. These two enforcement paths should be aligned.settings/views.pydefines a local function also namedis_staff_userthat shadows the model property — this should be deleted and replaced withlambda u: getattr(u, 'is_staff_user', False).user.is_staff_userdirectly or maintain role-specific checks (e.g.,billing_staff_requiredonly allows admin/billing/manager roles).