high priority medium complexity frontend pending frontend specialist Tier 5

Acceptance Criteria

UserListFilter model contains: selectedRole (nullable RoleEnum), selectedChapterId (nullable String), searchQuery (String, default empty)
ActivityListFilter model contains: dateRange (nullable DateTimeRange), activityType (nullable ActivityTypeEnum), chapterId (nullable String)
Both filter models are stored in AdminPortalState and survive tab switches (StatefulShellRoute navigation) without resetting
Changing the org hierarchy scope (OrgScopeChanged event) resets both filter models to their default/empty values
UpdateUserListFilter and UpdateActivityListFilter events partially update only the changed filter field using copyWith, preserving other filter fields
Pagination state (currentPage, pageSize, totalCount) is tracked per list and resets to page 1 whenever a filter field changes
A ClearUserListFilter and ClearActivityListFilter event resets the respective filter to defaults without affecting the other
Filter state drives the parameters passed to the underlying data-fetch service calls — no client-side filtering of a full list
Empty search query triggers fetch of the unfiltered list, not an empty result
All filter state fields have type-safe defaults and never hold null where a default value is semantically appropriate

Technical Requirements

frameworks
Flutter
BLoC (flutter_bloc)
Dart
apis
AdminUserService (internal)
AdminActivityService (internal)
Supabase REST/RPC for filtered queries
data models
UserListFilter
ActivityListFilter
PaginationState
AdminPortalState
RoleEnum
ActivityTypeEnum
performance requirements
Filter updates must debounce search query changes by 300ms before triggering a service call
Pagination must use cursor-based or offset pagination matching the Supabase query pattern
BLoC must cancel in-flight fetch requests when a new filter event arrives (use CancelableOperation or stream switchMap)
security requirements
All filter parameters must be sanitised before being passed to Supabase queries to prevent injection
Chapter filter must be validated against the admin's permitted scope before the query is issued
Search query must be length-limited (max 200 chars) in the filter model constructor

Execution Context

Execution Tier
Tier 5

Tier 5 - 253 tasks

Can start after Tier 4 completes

Implementation Notes

Define UserListFilter and ActivityListFilter as immutable Dart classes with copyWith and equality (equatable or manual ==). Store both inside AdminPortalState alongside their respective PaginationState objects. Use a transformer on UpdateUserListFilter events (e.g., restartable or droppable from bloc_concurrency) to cancel in-flight queries when filters change rapidly. Implement the 300ms debounce using EventTransformer.debounce from the bloc library.

The scope-reset logic should be a single handler for OrgScopeChanged that emits a new state with filter models replaced by their const defaults — do not duplicate this logic per filter event. This pattern mirrors good practices for large admin BLoCs where many orthogonal state slices need to coexist without interfering.

Testing Requirements

Unit test with bloc_test: (1) UpdateUserListFilter with only searchQuery updates that field and resets pagination to page 1; (2) UpdateActivityListFilter with dateRange preserves other filter fields; (3) OrgScopeChanged resets both filter models to defaults; (4) tab navigation does not reset filter state (verify state identity before and after a tab-switch event); (5) ClearUserListFilter resets user filters without touching activity filters; (6) search query debounce prevents immediate service call. Use mock services returning fixed paginated results to verify correct filter parameters are forwarded.

Component
Admin Portal BLoC
data high
Epic Risks (3)
high impact medium prob technical

If org node selection in AdminStateBLoC does not correctly propagate to all dependent data streams (statistics, activity log, user list, certification panel), some panels may show data from the previously selected org scope, creating a confusing and potentially dangerous mixed-scope view.

Mitigation & Contingency

Mitigation: Model org node selection as a single source of truth in AdminStateBLoC. All downstream providers derive their query parameters from this single stream via Riverpod's watch pattern. Write integration tests that verify every data stream emits a reload event when the selected node changes.

Contingency: If scope propagation bugs are detected in QA, add an explicit full-state reset on org node change (clear all cached data and refetch from scratch) as a safe but less efficient fallback until the targeted propagation is fixed.

medium impact medium prob technical

The Admin Dashboard Screen must adapt its layout for Flutter Web (wider viewports, mouse interaction, larger grid) and mobile embedding. Flutter Web responsive layout support has historically required non-trivial workarounds, and the adaptive grid may introduce significant additional development time.

Mitigation & Contingency

Mitigation: Define breakpoints and grid behaviour in the design system before implementation. Use LayoutBuilder with explicit breakpoint constants rather than MediaQuery scattered across widgets. Prototype the web layout with a skeleton screen before implementing live data binding.

Contingency: If web layout proves intractable within sprint, deliver a mobile-first layout for all platforms initially and track a dedicated web-optimisation task for the next sprint.

high impact low prob security

A bug in the Role Assignment Panel's permission scope validation could allow an org_admin to assign roles beyond their authority (e.g., assigning super_admin to a user), representing a serious privilege escalation vulnerability.

Mitigation & Contingency

Mitigation: Enforce role assignment scope on both the client (disable unavailable roles in the panel UI) and the server (UserManagementService validates the target role is within the admin's permitted scope before persisting). Write security-focused tests that attempt out-of-scope role assignments and assert rejection.

Contingency: If an escalation vulnerability is discovered, immediately disable the role assignment panel via feature flag, revoke any incorrectly assigned roles, and deploy a server-side fix before re-enabling.